diff --git a/source/blender/render/hydra/engine.cc b/source/blender/render/hydra/engine.cc index 7be85fb22430..dfe39edee02c 100644 --- a/source/blender/render/hydra/engine.cc +++ b/source/blender/render/hydra/engine.cc @@ -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( render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("freeCamera")); - render_task_delegate_ = std::make_unique( - render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("renderTask")); + + if (bl_engine->type->flag & RE_USE_GPU_CONTEXT) { + render_task_delegate_ = std::make_unique( + render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("renderTask")); + } + else { + render_task_delegate_ = std::make_unique( + 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( render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("lightTasks")); + light_tasks_delegate_->set_camera(free_camera_delegate_->GetCameraId()); } engine_ = std::make_unique(); diff --git a/source/blender/render/hydra/final_engine.cc b/source/blender/render/hydra/final_engine.cc index 88a4d451402c..68e763736afc 100644 --- a/source/blender/render/hydra/final_engine.cc +++ b/source/blender/render/hydra/final_engine.cc @@ -1,15 +1,12 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#include - #include +#include #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 &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(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 &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 diff --git a/source/blender/render/hydra/final_engine.h b/source/blender/render/hydra/final_engine.h index 2ab44bbadaa5..81155629a010 100644 --- a/source/blender/render/hydra/final_engine.h +++ b/source/blender/render/hydra/final_engine.h @@ -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> render_images_; pxr::GfVec2i resolution_; }; -class FinalEngineGPU : public FinalEngine { - public: - using FinalEngine::FinalEngine; - - void render(Depsgraph *depsgraph) override; -}; - } // namespace blender::render::hydra diff --git a/source/blender/render/hydra/light_tasks_delegate.cc b/source/blender/render/hydra/light_tasks_delegate.cc index dc817d17ce2a..82730c042da5 100644 --- a/source/blender/render/hydra/light_tasks_delegate.cc +++ b/source/blender/render/hydra/light_tasks_delegate.cc @@ -1,9 +1,6 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#include -#include - #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(this, skydome_task_id_); + simple_task_id_ = GetDelegateID().AppendElementString("simpleTask"); GetRenderIndex().InsertTask(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(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 diff --git a/source/blender/render/hydra/light_tasks_delegate.h b/source/blender/render/hydra/light_tasks_delegate.h index ea1db5adba43..6b350469bb72 100644 --- a/source/blender/render/hydra/light_tasks_delegate.h +++ b/source/blender/render/hydra/light_tasks_delegate.h @@ -4,8 +4,8 @@ #pragma once #include -#include #include +#include 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_; diff --git a/source/blender/render/hydra/preview_engine.cc b/source/blender/render/hydra/preview_engine.cc index a0d7205287c8..c0086fe2e0b0 100644 --- a/source/blender/render/hydra/preview_engine.cc +++ b/source/blender/render/hydra/preview_engine.cc @@ -1,123 +1,15 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#include - -#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 &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 &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 &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 diff --git a/source/blender/render/hydra/preview_engine.h b/source/blender/render/hydra/preview_engine.h index a3fa9e045603..07c3947c3eca 100644 --- a/source/blender/render/hydra/preview_engine.h +++ b/source/blender/render/hydra/preview_engine.h @@ -11,17 +11,8 @@ class PreviewEngine : public FinalEngine { public: using FinalEngine::FinalEngine; - void render(Depsgraph *depsgraph) override; - - private: - void update_render_result(std::vector &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 diff --git a/source/blender/render/hydra/python.cc b/source/blender/render/hydra/python.cc index da8b5b96dce4..cc4ab4bbe00d 100644 --- a/source/blender/render/hydra/python.cc +++ b/source/blender/render/hydra/python.cc @@ -71,20 +71,10 @@ 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); - } + 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); - } + engine = new FinalEngine(bl_engine, render_delegate_id); } } catch (std::runtime_error &e) { diff --git a/source/blender/render/hydra/render_task_delegate.cc b/source/blender/render/hydra/render_task_delegate.cc index 5351be086ca2..278f6e99a203 100644 --- a/source/blender/render/hydra/render_task_delegate.cc +++ b/source/blender/render/hydra/render_task_delegate.cc @@ -1,12 +1,14 @@ /* SPDX-License-Identifier: Apache-2.0 * Copyright 2011-2022 Blender Foundation */ -#include +#include #include #include #include +#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(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(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 diff --git a/source/blender/render/hydra/render_task_delegate.h b/source/blender/render/hydra/render_task_delegate.h index f8a1a956816c..548fec3a02c5 100644 --- a/source/blender/render/hydra/render_task_delegate.h +++ b/source/blender/render/hydra/render_task_delegate.h @@ -6,6 +6,9 @@ #include #include +#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 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 diff --git a/source/blender/render/hydra/viewport_engine.cc b/source/blender/render/hydra/viewport_engine.cc index 1d02441fcea5..229ec9fff309 100644 --- a/source/blender/render/hydra/viewport_engine.cc +++ b/source/blender/render/hydra/viewport_engine.cc @@ -5,19 +5,15 @@ #include #include -#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); + if (texture_ && width == GPU_texture_width(texture_) && height == GPU_texture_height(texture_)) { + if (data) { + GPU_texture_update(texture_, GPU_DATA_FLOAT, data); + } return; } - if (width_ != buffer->GetWidth() || height_ != buffer->GetHeight()) { - free(); - create(buffer); - return; + if (texture_) { + GPU_texture_free(texture_); } - void *data = buffer->Map(); - GPU_texture_update(texture_, GPU_DATA_FLOAT, data); - buffer->Unmap(); + 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])); + pxr::GfVec4d viewport(view_settings.border[0], + view_settings.border[1], + view_settings.border[2], + view_settings.border[3]); + render_task_delegate_->set_viewport(viewport); if (light_tasks_delegate_) { - light_tasks_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])); + 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(light_tasks_delegate_->simple_task()); } - tasks.push_back(render_task_delegate_->get_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(); diff --git a/source/blender/render/hydra/viewport_engine.h b/source/blender/render/hydra/viewport_engine.h index a21ccda581e8..b9ec215ea068 100644 --- a/source/blender/render/hydra/viewport_engine.h +++ b/source/blender/render/hydra/viewport_engine.h @@ -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 {