Support instancing for other objects: curves and volumes #74

Merged
Bogdan Nagirniak merged 4 commits from BLEN-449 into hydra-render 2023-07-26 10:27:51 +02:00
12 changed files with 427 additions and 495 deletions
Showing only changes of commit 7c82061813 - Show all commits

View File

@ -50,11 +50,21 @@ Engine::Engine(RenderEngine *bl_engine, const std::string &render_delegate_name)
render_index_.reset(pxr::HdRenderIndex::New(render_delegate_.Get(), hd_drivers));
free_camera_delegate_ = std::make_unique<pxr::HdxFreeCameraSceneDelegate>(
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("freeCamera"));
if (bl_engine->type->flag & RE_USE_GPU_CONTEXT) {
render_task_delegate_ = std::make_unique<GPURenderTaskDelegate>(
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("renderTask"));
}
else {
render_task_delegate_ = std::make_unique<RenderTaskDelegate>(
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("renderTask"));
}
render_task_delegate_->set_camera(free_camera_delegate_->GetCameraId());
if (render_delegate_name == "HdStormRendererPlugin") {
light_tasks_delegate_ = std::make_unique<LightTasksDelegate>(
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("lightTasks"));
light_tasks_delegate_->set_camera(free_camera_delegate_->GetCameraId());
}
engine_ = std::make_unique<pxr::HdEngine>();

View File

@ -1,15 +1,12 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <epoxy/gl.h>
#include <pxr/imaging/hd/light.h>
#include <pxr/imaging/hd/renderBuffer.h>
#include "BKE_lib_id.h"
#include "BLI_timecode.h"
#include "DEG_depsgraph_query.h"
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
#include "PIL_time.h"
#include "IMB_imbuf_types.h"
@ -19,75 +16,16 @@
namespace blender::render::hydra {
/* FinalEngine implementation */
void FinalEngine::render(Depsgraph *depsgraph)
{
prepare_for_render(depsgraph);
render_task_delegate_->set_renderer_aov(pxr::HdAovTokens->color);
engine_->Execute(render_index_.get(), &tasks_);
std::vector<float> &pixels = render_images_["Combined"];
char elapsed_time[32];
double time_begin = PIL_check_seconds_timer();
float percent_done = 0.0;
while (true) {
if (RE_engine_test_break(bl_engine_)) {
break;
}
percent_done = renderer_percent_done();
BLI_timecode_string_from_time_simple(
elapsed_time, sizeof(elapsed_time), PIL_check_seconds_timer() - time_begin);
notify_status(percent_done / 100.0,
scene_name_ + ": " + layer_name_,
std::string("Render Time: ") + elapsed_time +
" | Done: " + std::to_string(int(percent_done)) + "%");
if (render_task_delegate_->is_converged()) {
break;
}
render_task_delegate_->get_renderer_aov_data(pxr::HdAovTokens->color, pixels.data());
update_render_result();
}
render_task_delegate_->get_renderer_aov_data(pxr::HdAovTokens->color, pixels.data());
update_render_result();
}
void FinalEngine::update_render_result()
{
RenderResult *result = RE_engine_begin_result(
bl_engine_, 0, 0, resolution_[0], resolution_[1], layer_name_.c_str(), nullptr);
/* TODO: only for the first render layer */
RenderLayer *layer = (RenderLayer *)result->layers.first;
for (RenderPass *pass = (RenderPass *)layer->passes.first; pass != nullptr; pass = pass->next) {
auto it_image = render_images_.find(pass->name);
if (it_image == render_images_.end()) {
continue;
}
memcpy(pass->ibuf->float_buffer.data,
it_image->second.data(),
sizeof(float) * pass->rectx * pass->recty * pass->channels);
}
RE_engine_end_result(bl_engine_, result, false, false, false);
}
void FinalEngine::notify_status(float progress, const std::string &title, const std::string &info)
{
RE_engine_update_progress(bl_engine_, progress);
RE_engine_update_stats(bl_engine_, title.c_str(), info.c_str());
}
void FinalEngine::prepare_for_render(Depsgraph *depsgraph)
{
const Scene *scene = DEG_get_evaluated_scene(depsgraph);
const ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
BKE_id_full_name_get(scene_name_.data(), (ID *)scene, 0);
char scene_name[MAX_NAME];
BKE_id_full_name_get(scene_name, (ID *)scene, 0);
scene_name_ = scene_name;
layer_name_ = view_layer->name;
const RenderData &r = scene->r;
@ -104,62 +42,26 @@ void FinalEngine::prepare_for_render(Depsgraph *depsgraph)
CameraData(scene->camera, image_res, pxr::GfVec4f(0, 0, 1, 1)).gf_camera(border);
free_camera_delegate_->SetCamera(camera);
render_task_delegate_->set_camera_and_viewport(
free_camera_delegate_->GetCameraId(), pxr::GfVec4d(0, 0, resolution_[0], resolution_[1]));
render_task_delegate_->set_viewport(pxr::GfVec4d(0, 0, resolution_[0], resolution_[1]));
if (light_tasks_delegate_) {
light_tasks_delegate_->set_camera_and_viewport(
free_camera_delegate_->GetCameraId(), pxr::GfVec4d(0, 0, resolution_[0], resolution_[1]));
tasks_ = light_tasks_delegate_->get_tasks(scene->r.alphamode == R_ALPHAPREMUL);
light_tasks_delegate_->set_viewport(pxr::GfVec4d(0, 0, resolution_[0], resolution_[1]));
}
tasks_.push_back(render_task_delegate_->get_task());
render_images_.emplace(
"Combined",
std::vector<float>(resolution_[0] * resolution_[1] * 4)); /* 4 - number of channels. */
}
render_task_delegate_->add_aov(pxr::HdAovTokens->color);
render_task_delegate_->add_aov(pxr::HdAovTokens->depth);
void FinalEngineGPU::render(Depsgraph *depsgraph)
{
prepare_for_render(depsgraph);
render_task_delegate_->bind();
GPUFrameBuffer *framebuffer = GPU_framebuffer_create("fb_render_hydra");
GPUTexture *tex_color = GPU_texture_create_2d("tex_render_hydra_color",
resolution_[0],
resolution_[1],
1,
GPU_RGBA32F,
GPU_TEXTURE_USAGE_GENERAL,
nullptr);
GPUTexture *tex_depth = GPU_texture_create_2d("tex_render_hydra_depth",
resolution_[0],
resolution_[1],
1,
GPU_DEPTH32F_STENCIL8,
GPU_TEXTURE_USAGE_GENERAL,
nullptr);
GPU_texture_filter_mode(tex_color, true);
GPU_texture_mipmap_mode(tex_color, true, true);
GPU_texture_filter_mode(tex_depth, true);
GPU_texture_mipmap_mode(tex_depth, true, true);
pxr::HdTaskSharedPtrVector tasks;
if (light_tasks_delegate_) {
if (scene->r.alphamode != R_ALPHAPREMUL) {
tasks.push_back(light_tasks_delegate_->skydome_task());
}
tasks.push_back(light_tasks_delegate_->simple_task());
}
tasks.push_back(render_task_delegate_->task());
engine_->Execute(render_index_.get(), &tasks);
GPU_framebuffer_ensure_config(
&framebuffer, {GPU_ATTACHMENT_TEXTURE(tex_depth), GPU_ATTACHMENT_TEXTURE(tex_color)});
GPU_framebuffer_bind(framebuffer);
float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color_depth(framebuffer, clear_color, 1.0f);
/* Important: we have to create and bind at least one Vertex Array Object (VAO) before render
execution: More info at https://open.gl/drawing */
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
engine_->Execute(render_index_.get(), &tasks_);
std::vector<float> &pixels = render_images_["Combined"];
char elapsed_time[32];
double time_begin = PIL_check_seconds_timer();
float percent_done = 0.0;
@ -170,10 +72,8 @@ void FinalEngineGPU::render(Depsgraph *depsgraph)
}
percent_done = renderer_percent_done();
BLI_timecode_string_from_time_simple(
elapsed_time, sizeof(elapsed_time), PIL_check_seconds_timer() - time_begin);
notify_status(percent_done / 100.0,
scene_name_ + ": " + layer_name_,
std::string("Render Time: ") + elapsed_time +
@ -183,21 +83,38 @@ void FinalEngineGPU::render(Depsgraph *depsgraph)
break;
}
void *data = GPU_texture_read(tex_color, GPU_DATA_FLOAT, 0);
memcpy(pixels.data(), data, pixels.size() * sizeof(float));
MEM_freeN(data);
update_render_result();
}
void *data = GPU_texture_read(tex_color, GPU_DATA_FLOAT, 0);
memcpy(pixels.data(), data, pixels.size() * sizeof(float));
MEM_freeN(data);
update_render_result();
render_task_delegate_->unbind();
}
glDeleteVertexArrays(1, &VAO);
GPU_framebuffer_free(framebuffer);
GPU_texture_free(tex_color);
GPU_texture_free(tex_depth);
void FinalEngine::notify_status(float progress, const std::string &title, const std::string &info)
{
RE_engine_update_progress(bl_engine_, progress);
RE_engine_update_stats(bl_engine_, title.c_str(), info.c_str());
}
void FinalEngine::update_render_result()
{
RenderResult *result = RE_engine_begin_result(
bl_engine_, 0, 0, resolution_[0], resolution_[1], layer_name_.c_str(), nullptr);
/* TODO: only for the first render layer */
RenderLayer *layer = (RenderLayer *)result->layers.first;
for (RenderPass *pass = (RenderPass *)layer->passes.first; pass != nullptr; pass = pass->next) {
pxr::TfToken aov_key;
if (STREQ(pass->name, "Combined")) {
aov_key = pxr::HdAovTokens->color;
}
else if (STREQ(pass->name, "Depth")) {
aov_key = pxr::HdAovTokens->depth;
}
render_task_delegate_->read_aov(aov_key, pass->ibuf->float_buffer.data);
}
RE_engine_end_result(bl_engine_, result, false, false, false);
}
} // namespace blender::render::hydra

View File

@ -11,26 +11,15 @@ class FinalEngine : public Engine {
public:
using Engine::Engine;
void render(Depsgraph *b_depsgraph) override;
void render(Depsgraph *depsgraph) override;
protected:
virtual void notify_status(float progress, const std::string &title, const std::string &info);
void update_render_result();
void notify_status(float progress, const std::string &title, const std::string &info);
void prepare_for_render(Depsgraph *depsgraph);
pxr::HdRenderSettingsMap render_settings_;
pxr::HdTaskSharedPtrVector tasks_;
std::string scene_name_;
std::string layer_name_;
std::map<std::string, std::vector<float>> render_images_;
pxr::GfVec2i resolution_;
};
class FinalEngineGPU : public FinalEngine {
public:
using FinalEngine::FinalEngine;
void render(Depsgraph *depsgraph) override;
};
} // namespace blender::render::hydra

View File

@ -1,9 +1,6 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <pxr/imaging/hdx/simpleLightTask.h>
#include <pxr/imaging/hdx/skydomeTask.h>
#include "light_tasks_delegate.h"
namespace blender::render::hydra {
@ -12,39 +9,10 @@ LightTasksDelegate::LightTasksDelegate(pxr::HdRenderIndex *parent_index,
pxr::SdfPath const &delegate_id)
: pxr::HdSceneDelegate(parent_index, delegate_id)
{
skydome_task_id_ = GetDelegateID().AppendElementString("simpleLightTask");
simple_task_id_ = GetDelegateID().AppendElementString("skydomeTask");
GetRenderIndex().InsertTask<pxr::HdxSkydomeTask>(this, skydome_task_id_);
simple_task_id_ = GetDelegateID().AppendElementString("simpleTask");
GetRenderIndex().InsertTask<pxr::HdxSimpleLightTask>(this, simple_task_id_);
}
pxr::HdTaskSharedPtrVector LightTasksDelegate::get_tasks(const bool isTransparent)
{
/*Note that this task is intended to be the first "Render Task",
so that the AOV's are properly cleared, however it
does not spawn a HdRenderPass.*/
pxr::HdTaskSharedPtrVector tasks;
if (!isTransparent) {
tasks.push_back(GetRenderIndex().GetTask(skydome_task_id_));
}
tasks.push_back(GetRenderIndex().GetTask(simple_task_id_));
return tasks;
}
void LightTasksDelegate::set_camera_and_viewport(pxr::SdfPath const &camera_id,
pxr::GfVec4d const &viewport)
{
if (simple_task_params_.cameraPath != camera_id) {
simple_task_params_.cameraPath = camera_id;
GetRenderIndex().GetChangeTracker().MarkTaskDirty(simple_task_id_,
pxr::HdChangeTracker::DirtyParams);
}
if (skydome_task_params_.viewport != viewport || skydome_task_params_.camera != camera_id) {
skydome_task_params_.viewport = viewport;
skydome_task_params_.camera = camera_id;
GetRenderIndex().GetChangeTracker().MarkTaskDirty(skydome_task_id_,
pxr::HdChangeTracker::DirtyParams);
}
skydome_task_id_ = GetDelegateID().AppendElementString("skydomeTask");
GetRenderIndex().InsertTask<pxr::HdxSkydomeTask>(this, skydome_task_id_);
}
pxr::VtValue LightTasksDelegate::Get(pxr::SdfPath const &id, pxr::TfToken const &key)
@ -60,4 +28,40 @@ pxr::VtValue LightTasksDelegate::Get(pxr::SdfPath const &id, pxr::TfToken const
return pxr::VtValue();
}
pxr::HdTaskSharedPtr LightTasksDelegate::simple_task()
{
return GetRenderIndex().GetTask(simple_task_id_);
}
pxr::HdTaskSharedPtr LightTasksDelegate::skydome_task()
{
/* Note that this task is intended to be the first "Render Task",
so that the AOV's are properly cleared, however it
does not spawn a HdRenderPass. */
return GetRenderIndex().GetTask(skydome_task_id_);
}
void LightTasksDelegate::set_camera(pxr::SdfPath const &camera_id)
{
if (simple_task_params_.cameraPath == camera_id) {
return;
}
simple_task_params_.cameraPath = camera_id;
GetRenderIndex().GetChangeTracker().MarkTaskDirty(simple_task_id_,
pxr::HdChangeTracker::DirtyParams);
skydome_task_params_.camera = camera_id;
GetRenderIndex().GetChangeTracker().MarkTaskDirty(skydome_task_id_,
pxr::HdChangeTracker::DirtyParams);
}
void LightTasksDelegate::set_viewport(pxr::GfVec4d const &viewport)
{
if (skydome_task_params_.viewport == viewport) {
return;
}
skydome_task_params_.viewport = viewport;
GetRenderIndex().GetChangeTracker().MarkTaskDirty(skydome_task_id_,
pxr::HdChangeTracker::DirtyParams);
}
} // namespace blender::render::hydra

View File

@ -4,8 +4,8 @@
#pragma once
#include <pxr/imaging/hd/sceneDelegate.h>
#include <pxr/imaging/hdx/renderSetupTask.h>
#include <pxr/imaging/hdx/simpleLightTask.h>
#include <pxr/imaging/hdx/skydomeTask.h>
namespace blender::render::hydra {
@ -14,12 +14,14 @@ class LightTasksDelegate : public pxr::HdSceneDelegate {
LightTasksDelegate(pxr::HdRenderIndex *parentIndex, pxr::SdfPath const &delegate_id);
~LightTasksDelegate() override = default;
pxr::HdTaskSharedPtrVector get_tasks(const bool isTransparent);
void set_camera_and_viewport(pxr::SdfPath const &camera_id, pxr::GfVec4d const &viewport);
/* Delegate methods */
pxr::VtValue Get(pxr::SdfPath const &id, pxr::TfToken const &key) override;
pxr::HdTaskSharedPtr simple_task();
pxr::HdTaskSharedPtr skydome_task();
void set_camera(pxr::SdfPath const &camera_id);
void set_viewport(pxr::GfVec4d const &viewport);
private:
pxr::SdfPath simple_task_id_;
pxr::SdfPath skydome_task_id_;

View File

@ -1,123 +1,15 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <epoxy/gl.h>
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
#include "IMB_imbuf_types.h"
#include "preview_engine.h"
namespace blender::render::hydra {
void PreviewEngine::render(Depsgraph *depsgraph)
void PreviewEngine::notify_status(float progress,
const std::string &title,
const std::string &info)
{
prepare_for_render(depsgraph);
render_task_delegate_->set_renderer_aov(pxr::HdAovTokens->color);
engine_->Execute(render_index_.get(), &tasks_);
std::vector<float> &pixels = render_images_["Combined"];
while (true) {
if (RE_engine_test_break(bl_engine_)) {
break;
}
if (render_task_delegate_->is_converged()) {
break;
}
render_task_delegate_->get_renderer_aov_data(pxr::HdAovTokens->color, pixels.data());
update_render_result(pixels);
}
render_task_delegate_->get_renderer_aov_data(pxr::HdAovTokens->color, pixels.data());
update_render_result(pixels);
}
void PreviewEngineGPU::render(Depsgraph *depsgraph)
{
prepare_for_render(depsgraph);
GPUFrameBuffer *framebuffer = GPU_framebuffer_create("fb_render_mat_prev_hydra");
GPUTexture *tex_color = GPU_texture_create_2d("tex_render_mat_prev_hydra_color",
resolution_[0],
resolution_[1],
1,
GPU_RGBA32F,
GPU_TEXTURE_USAGE_GENERAL,
nullptr);
GPUTexture *tex_depth = GPU_texture_create_2d("tex_render_mat_prev_hydra_depth",
resolution_[0],
resolution_[1],
1,
GPU_DEPTH32F_STENCIL8,
GPU_TEXTURE_USAGE_GENERAL,
nullptr);
GPU_texture_filter_mode(tex_color, true);
GPU_texture_mipmap_mode(tex_color, true, true);
GPU_texture_filter_mode(tex_depth, true);
GPU_texture_mipmap_mode(tex_depth, true, true);
GPU_framebuffer_ensure_config(
&framebuffer, {GPU_ATTACHMENT_TEXTURE(tex_depth), GPU_ATTACHMENT_TEXTURE(tex_color)});
GPU_framebuffer_bind(framebuffer);
float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
GPU_framebuffer_clear_color_depth(framebuffer, clear_color, 1.0f);
/* Important: we have to create and bind at least one Vertex Array Object (VAO) before render
execution: More info at https://open.gl/drawing */
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
engine_->Execute(render_index_.get(), &tasks_);
std::vector<float> &pixels = render_images_["Combined"];
while (true) {
if (RE_engine_test_break(bl_engine_)) {
break;
}
if (render_task_delegate_->is_converged()) {
break;
}
void *data = GPU_texture_read(tex_color, GPU_DATA_FLOAT, 0);
memcpy(pixels.data(), data, pixels.size() * sizeof(float));
MEM_freeN(data);
update_render_result();
}
void *data = GPU_texture_read(tex_color, GPU_DATA_FLOAT, 0);
memcpy(pixels.data(), data, pixels.size() * sizeof(float));
MEM_freeN(data);
update_render_result();
glDeleteVertexArrays(1, &VAO);
GPU_framebuffer_free(framebuffer);
GPU_texture_free(tex_color);
GPU_texture_free(tex_depth);
}
void PreviewEngine::update_render_result(std::vector<float> &pixels)
{
RenderResult *result = RE_engine_begin_result(
bl_engine_, 0, 0, resolution_[0], resolution_[1], layer_name_.c_str(), nullptr);
RenderLayer *layer = (RenderLayer *)result->layers.first;
RenderPass *pass = (RenderPass *)layer->passes.first;
memcpy(pass->ibuf->float_buffer.data,
pixels.data(),
sizeof(float) * pass->rectx * pass->recty * pass->channels);
RE_engine_end_result(bl_engine_, result, false, false, false);
/* Empty fucntion */
}
} // namespace blender::render::hydra

View File

@ -11,17 +11,8 @@ class PreviewEngine : public FinalEngine {
public:
using FinalEngine::FinalEngine;
void render(Depsgraph *depsgraph) override;
private:
void update_render_result(std::vector<float> &pixels);
};
class PreviewEngineGPU : public FinalEngineGPU {
public:
using FinalEngineGPU::FinalEngineGPU;
void render(Depsgraph *depsgraph) override;
protected:
void notify_status(float progress, const std::string &title, const std::string &info) override;
};
} // namespace blender::render::hydra

View File

@ -71,22 +71,12 @@ static PyObject *engine_create_func(PyObject * /*self*/, PyObject *args)
engine = new ViewportEngine(bl_engine, render_delegate_id);
}
else if (STREQ(engine_type, "PREVIEW")) {
if (bl_engine->type->flag & RE_USE_GPU_CONTEXT) {
engine = new PreviewEngineGPU(bl_engine, render_delegate_id);
}
else {
engine = new PreviewEngine(bl_engine, render_delegate_id);
}
}
else {
if (bl_engine->type->flag & RE_USE_GPU_CONTEXT) {
engine = new FinalEngineGPU(bl_engine, render_delegate_id);
}
else {
engine = new FinalEngine(bl_engine, render_delegate_id);
}
}
}
catch (std::runtime_error &e) {
CLOG_ERROR(LOG_RENDER_HYDRA, "%s", e.what());
}

View File

@ -1,12 +1,14 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <iostream>
#include <epoxy/gl.h>
#include <pxr/imaging/hd/renderBuffer.h>
#include <pxr/imaging/hd/renderDelegate.h>
#include <pxr/imaging/hdx/renderTask.h>
#include "MEM_guardedalloc.h"
#include "render_task_delegate.h"
namespace blender::render::hydra {
@ -15,121 +17,250 @@ RenderTaskDelegate::RenderTaskDelegate(pxr::HdRenderIndex *parent_index,
pxr::SdfPath const &delegate_id)
: pxr::HdSceneDelegate(parent_index, delegate_id)
{
pxr::SdfPath render_task_id = get_task_id();
GetRenderIndex().InsertTask<pxr::HdxRenderTask>(this, render_task_id);
GetRenderIndex().GetChangeTracker().MarkTaskDirty(render_task_id,
pxr::HdChangeTracker::DirtyCollection);
GetRenderIndex().GetChangeTracker().MarkTaskDirty(render_task_id,
pxr::HdChangeTracker::DirtyRenderTags);
task_id_ = GetDelegateID().AppendElementString("task");
GetRenderIndex().InsertTask<pxr::HdxRenderTask>(this, task_id_);
task_params_.enableLighting = true;
task_params_.alphaThreshold = 0.1f;
}
pxr::SdfPath RenderTaskDelegate::get_task_id() const
{
return GetDelegateID().AppendElementString("task");
}
pxr::SdfPath RenderTaskDelegate::get_aov_id(pxr::TfToken const &aov) const
{
return GetDelegateID().AppendElementString("aov_" + aov.GetString());
}
bool RenderTaskDelegate::is_converged()
{
pxr::HdTaskSharedPtr renderTask = GetRenderIndex().GetTask(get_task_id());
return ((pxr::HdxRenderTask &)*renderTask).IsConverged();
}
void RenderTaskDelegate::set_renderer_aov(pxr::TfToken const &aov)
{
pxr::HdAovDescriptor aov_desc = GetRenderIndex().GetRenderDelegate()->GetDefaultAovDescriptor(
aov);
pxr::HdRenderBufferDescriptor desc(
pxr::GfVec3i(task_params_.viewport[2], task_params_.viewport[3], 1),
aov_desc.format,
aov_desc.multiSampled);
pxr::SdfPath buffer_id = get_aov_id(aov);
if (buffer_descriptors_.find(buffer_id) == buffer_descriptors_.end()) {
GetRenderIndex().InsertBprim(pxr::HdPrimTypeTokens->renderBuffer, this, buffer_id);
buffer_descriptors_[buffer_id] = desc;
GetRenderIndex().GetChangeTracker().MarkBprimDirty(buffer_id,
pxr::HdRenderBuffer::DirtyDescription);
pxr::HdRenderPassAovBinding binding;
binding.aovName = aov;
binding.renderBufferId = buffer_id;
binding.aovSettings = aov_desc.aovSettings;
task_params_.aovBindings.push_back(binding);
GetRenderIndex().GetChangeTracker().MarkTaskDirty(get_task_id(),
pxr::HdChangeTracker::DirtyParams);
}
else if (buffer_descriptors_[buffer_id] != desc) {
buffer_descriptors_[buffer_id] = desc;
GetRenderIndex().GetChangeTracker().MarkBprimDirty(buffer_id,
pxr::HdRenderBuffer::DirtyDescription);
}
}
pxr::HdRenderBuffer *RenderTaskDelegate::get_renderer_aov(pxr::TfToken const &aov)
{
return (pxr::HdRenderBuffer *)(GetRenderIndex().GetBprim(pxr::HdPrimTypeTokens->renderBuffer,
get_aov_id(aov)));
}
void RenderTaskDelegate::get_renderer_aov_data(pxr::TfToken const &aov, void *data)
{
pxr::HdRenderBuffer *buffer = get_renderer_aov(aov);
void *buf_data = buffer->Map();
memcpy(data,
buf_data,
buffer->GetWidth() * buffer->GetHeight() * pxr::HdDataSizeOfFormat(buffer->GetFormat()));
buffer->Unmap();
}
pxr::HdTaskSharedPtr RenderTaskDelegate::get_task()
{
return GetRenderIndex().GetTask(get_task_id());
}
void RenderTaskDelegate::set_camera_and_viewport(pxr::SdfPath const &camera_id,
pxr::GfVec4d const &viewport)
{
if (task_params_.viewport != viewport || task_params_.camera != camera_id) {
task_params_.viewport = viewport;
task_params_.camera = camera_id;
GetRenderIndex().GetChangeTracker().MarkTaskDirty(get_task_id(),
pxr::HdChangeTracker::DirtyParams);
}
}
pxr::VtValue RenderTaskDelegate::Get(pxr::SdfPath const & /*id*/, pxr::TfToken const &key)
{
if (key == pxr::HdTokens->params) {
return pxr::VtValue(task_params_);
}
if (key == pxr::HdTokens->collection) {
pxr::HdRprimCollection rprim_collection(pxr::HdTokens->geometry,
pxr::HdReprSelector(pxr::HdReprTokens->smoothHull),
false,
pxr::TfToken());
rprim_collection.SetRootPath(pxr::SdfPath::AbsoluteRootPath());
return pxr::VtValue(rprim_collection);
return pxr::VtValue(pxr::HdRprimCollection(
pxr::HdTokens->geometry, pxr::HdReprSelector(pxr::HdReprTokens->smoothHull)));
}
return pxr::VtValue();
}
pxr::TfTokenVector RenderTaskDelegate::GetTaskRenderTags(pxr::SdfPath const & /*id*/)
{
return {pxr::HdRenderTagTokens->geometry};
}
pxr::HdRenderBufferDescriptor RenderTaskDelegate::GetRenderBufferDescriptor(pxr::SdfPath const &id)
{
return buffer_descriptors_[id];
}
pxr::TfTokenVector RenderTaskDelegate::GetTaskRenderTags(pxr::SdfPath const & /*task_id*/)
pxr::HdTaskSharedPtr RenderTaskDelegate::task()
{
return {pxr::HdRenderTagTokens->geometry};
return GetRenderIndex().GetTask(task_id_);
}
void RenderTaskDelegate::set_camera(pxr::SdfPath const &camera_id)
{
if (task_params_.camera == camera_id) {
return;
}
task_params_.camera = camera_id;
GetRenderIndex().GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
}
bool RenderTaskDelegate::is_converged()
{
return ((pxr::HdxRenderTask *)task().get())->IsConverged();
}
void RenderTaskDelegate::set_viewport(pxr::GfVec4d const &viewport)
{
if (task_params_.viewport == viewport) {
return;
}
auto &render_index = GetRenderIndex();
task_params_.viewport = viewport;
render_index.GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
int w = viewport[2] - viewport[0];
int h = viewport[3] - viewport[1];
for (auto &it : buffer_descriptors_) {
it.second.dimensions = pxr::GfVec3i(w, h, 1);
render_index.GetChangeTracker().MarkBprimDirty(it.first,
pxr::HdRenderBuffer::DirtyDescription);
}
}
void RenderTaskDelegate::add_aov(pxr::TfToken const &aov_key)
{
pxr::SdfPath buf_id = buffer_id(aov_key);
if (buffer_descriptors_.find(buf_id) != buffer_descriptors_.end()) {
return;
}
auto &render_index = GetRenderIndex();
pxr::HdAovDescriptor aov_desc = render_index.GetRenderDelegate()->GetDefaultAovDescriptor(
aov_key);
int w = task_params_.viewport[2] - task_params_.viewport[0];
int h = task_params_.viewport[3] - task_params_.viewport[1];
render_index.InsertBprim(pxr::HdPrimTypeTokens->renderBuffer, this, buf_id);
buffer_descriptors_[buf_id] = pxr::HdRenderBufferDescriptor(
pxr::GfVec3i(w, h, 1), aov_desc.format, aov_desc.multiSampled);
pxr::HdRenderPassAovBinding binding;
binding.aovName = aov_key;
binding.renderBufferId = buf_id;
binding.aovSettings = aov_desc.aovSettings;
task_params_.aovBindings.push_back(binding);
render_index.GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
}
void RenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, void *data)
{
pxr::HdRenderBuffer *buffer = (pxr::HdRenderBuffer *)GetRenderIndex().GetBprim(
pxr::HdPrimTypeTokens->renderBuffer, buffer_id(aov_key));
if (!buffer) {
return;
}
void *buf_data = buffer->Map();
memcpy(data,
buf_data,
buffer->GetWidth() * buffer->GetHeight() * pxr::HdDataSizeOfFormat(buffer->GetFormat()));
buffer->Unmap();
}
void RenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, GPUTexture *texture)
{
pxr::HdRenderBuffer *buffer = (pxr::HdRenderBuffer *)GetRenderIndex().GetBprim(
pxr::HdPrimTypeTokens->renderBuffer, buffer_id(aov_key));
if (!buffer) {
return;
}
void *buf_data = buffer->Map();
GPU_texture_update(texture, GPU_DATA_FLOAT, buf_data);
buffer->Unmap();
}
void RenderTaskDelegate::bind() {}
void RenderTaskDelegate::unbind() {}
pxr::SdfPath RenderTaskDelegate::buffer_id(pxr::TfToken const &aov_key) const
{
return GetDelegateID().AppendElementString("aov_" + aov_key.GetString());
}
void GPURenderTaskDelegate::set_viewport(pxr::GfVec4d const &viewport)
{
if (task_params_.viewport == viewport) {
return;
}
auto &render_index = GetRenderIndex();
task_params_.viewport = viewport;
render_index.GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
if (tex_color_) {
GPU_texture_free(tex_color_);
tex_color_ = nullptr;
add_aov(pxr::HdAovTokens->color);
}
if (tex_depth_) {
GPU_texture_free(tex_depth_);
tex_depth_ = nullptr;
add_aov(pxr::HdAovTokens->depth);
}
}
void GPURenderTaskDelegate::add_aov(pxr::TfToken const &aov_key)
{
eGPUTextureFormat format;
GPUTexture **tex;
if (aov_key == pxr::HdAovTokens->color) {
format = GPU_RGBA32F;
tex = &tex_color_;
}
else if (aov_key == pxr::HdAovTokens->depth) {
format = GPU_DEPTH32F_STENCIL8;
tex = &tex_depth_;
}
else {
return;
}
if (*tex) {
return;
}
*tex = GPU_texture_create_2d(("tex_render_hydra_" + aov_key.GetString()).c_str(),
task_params_.viewport[2] - task_params_.viewport[0],
task_params_.viewport[3] - task_params_.viewport[1],
1,
format,
GPU_TEXTURE_USAGE_GENERAL,
nullptr);
}
void GPURenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, void *data)
{
GPUTexture *tex = nullptr;
int c;
if (aov_key == pxr::HdAovTokens->color) {
tex = tex_color_;
c = 4;
}
else if (aov_key == pxr::HdAovTokens->depth) {
tex = tex_depth_;
c = 1;
}
if (!tex) {
return;
}
int w = GPU_texture_width(tex), h = GPU_texture_height(tex);
void *tex_data = GPU_texture_read(tex, GPU_DATA_FLOAT, 0);
memcpy(data, tex_data, sizeof(float) * w * h * c);
MEM_freeN(tex_data);
}
void GPURenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, GPUTexture *texture)
{
GPUTexture *tex = nullptr;
int c;
if (aov_key == pxr::HdAovTokens->color) {
tex = tex_color_;
c = 4;
}
else if (aov_key == pxr::HdAovTokens->depth) {
tex = tex_depth_;
c = 1;
}
if (!tex) {
return;
}
void *tex_data = GPU_texture_read(tex, GPU_DATA_FLOAT, 0);
GPU_texture_update(texture, GPU_DATA_FLOAT, tex_data);
MEM_freeN(tex_data);
}
void GPURenderTaskDelegate::bind()
{
if (!framebuffer_) {
framebuffer_ = GPU_framebuffer_create("fb_render_hydra");
}
GPU_framebuffer_ensure_config(
&framebuffer_, {GPU_ATTACHMENT_TEXTURE(tex_depth_), GPU_ATTACHMENT_TEXTURE(tex_color_)});
GPU_framebuffer_bind(framebuffer_);
float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color_depth(framebuffer_, clear_color, 1.0f);
/* Important: we have to create and bind at least one Vertex Array Object (VAO) before render
execution: More info at https://open.gl/drawing */
if (VAO_ == 0) {
glGenVertexArrays(1, &VAO_);
}
glBindVertexArray(VAO_);
}
void GPURenderTaskDelegate::unbind()
{
glDeleteVertexArrays(1, &VAO_);
GPU_framebuffer_free(framebuffer_);
GPU_texture_free(tex_color_);
GPU_texture_free(tex_depth_);
}
} // namespace blender::render::hydra

View File

@ -6,6 +6,9 @@
#include <pxr/imaging/hd/sceneDelegate.h>
#include <pxr/imaging/hdx/renderSetupTask.h>
#include "GPU_framebuffer.h"
#include "GPU_texture.h"
namespace blender::render::hydra {
class RenderTaskDelegate : public pxr::HdSceneDelegate {
@ -13,26 +16,46 @@ class RenderTaskDelegate : public pxr::HdSceneDelegate {
RenderTaskDelegate(pxr::HdRenderIndex *parent_index, pxr::SdfPath const &delegate_id);
~RenderTaskDelegate() override = default;
pxr::SdfPath get_task_id() const;
pxr::SdfPath get_aov_id(pxr::TfToken const &aov) const;
bool is_converged();
void set_renderer_aov(pxr::TfToken const &aovId);
pxr::HdRenderBuffer *get_renderer_aov(pxr::TfToken const &id);
void get_renderer_aov_data(pxr::TfToken const &id, void *buf);
pxr::HdTaskSharedPtr get_task();
void set_camera_and_viewport(pxr::SdfPath const &cameraId, pxr::GfVec4d const &viewport);
/* Delegate methods */
pxr::VtValue Get(pxr::SdfPath const &id, pxr::TfToken const &key) override;
pxr::TfTokenVector GetTaskRenderTags(pxr::SdfPath const &id) override;
pxr::HdRenderBufferDescriptor GetRenderBufferDescriptor(pxr::SdfPath const &id) override;
pxr::TfTokenVector GetTaskRenderTags(pxr::SdfPath const &taskId) override;
private:
pxr::HdTaskSharedPtr task();
bool is_converged();
void set_camera(pxr::SdfPath const &camera_id);
virtual void set_viewport(pxr::GfVec4d const &viewport);
virtual void add_aov(pxr::TfToken const &aov_key);
virtual void read_aov(pxr::TfToken const &aov_key, void *data);
virtual void read_aov(pxr::TfToken const &aov_key, GPUTexture *texture);
virtual void bind();
virtual void unbind();
protected:
pxr::SdfPath buffer_id(pxr::TfToken const &aov_key) const;
pxr::SdfPath task_id_;
pxr::HdxRenderTaskParams task_params_;
pxr::TfHashMap<pxr::SdfPath, pxr::HdRenderBufferDescriptor, pxr::SdfPath::Hash>
buffer_descriptors_;
};
class GPURenderTaskDelegate : public RenderTaskDelegate {
public:
using RenderTaskDelegate::RenderTaskDelegate;
void set_viewport(pxr::GfVec4d const &viewport) override;
void add_aov(pxr::TfToken const &aov_key) override;
void read_aov(pxr::TfToken const &aov_key, void *data) override;
void read_aov(pxr::TfToken const &aov_key, GPUTexture *texture) override;
void bind() override;
void unbind() override;
private:
GPUFrameBuffer *framebuffer_ = nullptr;
GPUTexture *tex_color_ = nullptr;
GPUTexture *tex_depth_ = nullptr;
unsigned int VAO_ = 0;
};
} // namespace blender::render::hydra

View File

@ -5,19 +5,15 @@
#include <pxr/imaging/glf/drawTarget.h>
#include <pxr/usd/usdGeom/camera.h>
#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
#include "DNA_vec_types.h" /* this include must be before BKE_camera.h due to "rctf" type */
#include "BKE_camera.h"
#include "BLI_math_matrix.h"
#include "BLI_timecode.h"
#include "DEG_depsgraph_query.h"
#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
#include "GPU_matrix.h"
#include "PIL_time.h"
#include "camera.h"
@ -136,7 +132,7 @@ pxr::GfCamera ViewSettings::gf_camera()
(float)border[3] / screen_height));
}
DrawTexture::DrawTexture() : texture_(nullptr), width_(0), height_(0), channels_(4)
DrawTexture::DrawTexture()
{
float coords[8] = {0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0};
@ -154,67 +150,57 @@ DrawTexture::DrawTexture() : texture_(nullptr), width_(0), height_(0), channels_
DrawTexture::~DrawTexture()
{
if (texture_) {
free();
GPU_texture_free(texture_);
}
GPU_batch_discard(batch_);
}
void DrawTexture::set_buffer(pxr::HdRenderBuffer *buffer)
void DrawTexture::write_data(int width, int height, const void *data)
{
if (!texture_) {
create(buffer);
return;
}
if (width_ != buffer->GetWidth() || height_ != buffer->GetHeight()) {
free();
create(buffer);
return;
}
void *data = buffer->Map();
if (texture_ && width == GPU_texture_width(texture_) && height == GPU_texture_height(texture_)) {
if (data) {
GPU_texture_update(texture_, GPU_DATA_FLOAT, data);
buffer->Unmap();
}
return;
}
if (texture_) {
GPU_texture_free(texture_);
}
texture_ = GPU_texture_create_2d("tex_hydra_render_viewport",
width,
height,
1,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_GENERAL,
(float *)data);
GPU_texture_filter_mode(texture_, true);
GPU_texture_mipmap_mode(texture_, true, true);
}
void DrawTexture::draw(GPUShader *shader, float x, float y)
void DrawTexture::draw(GPUShader *shader, const pxr::GfVec4d &viewport)
{
draw(shader, texture_, viewport);
}
void DrawTexture::draw(GPUShader *shader, GPUTexture *tex, const pxr::GfVec4d &viewport)
{
int slot = GPU_shader_get_sampler_binding(shader, "image");
GPU_texture_bind(texture_, slot);
GPU_texture_bind(tex, slot);
GPU_shader_uniform_1i(shader, "image", slot);
GPU_matrix_push();
GPU_matrix_translate_2f(x, y);
GPU_matrix_scale_2f(width_, height_);
GPU_matrix_translate_2f(viewport[0], viewport[1]);
GPU_matrix_scale_2f(viewport[2] - viewport[0], viewport[3] - viewport[1]);
GPU_batch_set_shader(batch_, shader);
GPU_batch_draw(batch_);
GPU_matrix_pop();
}
void DrawTexture::create(pxr::HdRenderBuffer *buffer)
GPUTexture *DrawTexture::texture() const
{
width_ = buffer->GetWidth();
height_ = buffer->GetHeight();
channels_ = pxr::HdGetComponentCount(buffer->GetFormat());
void *data = buffer->Map();
texture_ = GPU_texture_create_2d("tex_hydra_render_viewport",
width_,
height_,
1,
GPU_RGBA16F,
GPU_TEXTURE_USAGE_GENERAL,
(float *)data);
buffer->Unmap();
GPU_texture_filter_mode(texture_, true);
GPU_texture_mipmap_mode(texture_, true, true);
}
void DrawTexture::free()
{
GPU_texture_free(texture_);
texture_ = nullptr;
return texture_;
}
void ViewportEngine::render(Depsgraph * /* depsgraph */)
@ -232,22 +218,18 @@ void ViewportEngine::render(Depsgraph *depsgraph, bContext *context)
pxr::GfCamera gf_camera = view_settings.gf_camera();
free_camera_delegate_->SetCamera(gf_camera);
render_task_delegate_->set_camera_and_viewport(free_camera_delegate_->GetCameraId(),
pxr::GfVec4d(view_settings.border[0],
view_settings.border[1],
view_settings.border[2],
view_settings.border[3]));
if (light_tasks_delegate_) {
light_tasks_delegate_->set_camera_and_viewport(free_camera_delegate_->GetCameraId(),
pxr::GfVec4d(view_settings.border[0],
pxr::GfVec4d viewport(view_settings.border[0],
view_settings.border[1],
view_settings.border[2],
view_settings.border[3]));
view_settings.border[3]);
render_task_delegate_->set_viewport(viewport);
if (light_tasks_delegate_) {
light_tasks_delegate_->set_viewport(viewport);
}
if ((bl_engine_->type->flag & RE_USE_GPU_CONTEXT) == 0) {
render_task_delegate_->set_renderer_aov(pxr::HdAovTokens->color);
render_task_delegate_->add_aov(pxr::HdAovTokens->color);
}
GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_IMAGE);
@ -255,15 +237,18 @@ void ViewportEngine::render(Depsgraph *depsgraph, bContext *context)
pxr::HdTaskSharedPtrVector tasks;
if (light_tasks_delegate_) {
tasks = light_tasks_delegate_->get_tasks(scene->r.alphamode == R_ALPHAPREMUL);
if (scene->r.alphamode != R_ALPHAPREMUL) {
tasks.push_back(light_tasks_delegate_->skydome_task());
}
tasks.push_back(render_task_delegate_->get_task());
tasks.push_back(light_tasks_delegate_->simple_task());
}
tasks.push_back(render_task_delegate_->task());
engine_->Execute(render_index_.get(), &tasks);
if ((bl_engine_->type->flag & RE_USE_GPU_CONTEXT) == 0) {
draw_texture_.set_buffer(render_task_delegate_->get_renderer_aov(pxr::HdAovTokens->color));
draw_texture_.draw(shader, view_settings.border[0], view_settings.border[1]);
draw_texture_.write_data(view_settings.width(), view_settings.height(), nullptr);
render_task_delegate_->read_aov(pxr::HdAovTokens->color, draw_texture_.texture());
draw_texture_.draw(shader, viewport);
}
GPU_shader_unbind();

View File

@ -18,16 +18,14 @@ class DrawTexture {
DrawTexture();
~DrawTexture();
void set_buffer(pxr::HdRenderBuffer *buffer);
void draw(GPUShader *shader, float x, float y);
void write_data(int width, int height, const void *data);
void draw(GPUShader *shader, const pxr::GfVec4d &viewport);
void draw(GPUShader *shader, GPUTexture *tex, const pxr::GfVec4d &viewport);
GPUTexture *texture() const;
private:
void create(pxr::HdRenderBuffer *buffer);
void free();
GPUTexture *texture_;
GPUTexture *texture_ = nullptr;
GPUBatch *batch_;
int width_, height_, channels_;
};
class ViewportEngine : public Engine {