diff --git a/scripts/modules/bpy_hydra.py b/scripts/modules/bpy_hydra.py index 828c568d919e..07eaa455912e 100644 --- a/scripts/modules/bpy_hydra.py +++ b/scripts/modules/bpy_hydra.py @@ -19,7 +19,7 @@ class CustomHydraRenderEngine(HydraRenderEngine): def register(cls): super().register() - bpy_hydra.register_plugins(["/path/to/plugin")], ["/additional/system/path")]) + bpy_hydra.register_plugins(["/path/to/plugin")]) def get_delegate_settings(self, engine_type): return { @@ -59,6 +59,7 @@ class HydraRenderEngine(bpy.types.RenderEngine): return _bpy_hydra.engine_free(self.engine_ptr) + del self.engine_ptr @classmethod def register(cls): @@ -75,16 +76,14 @@ class HydraRenderEngine(bpy.types.RenderEngine): # final render def update(self, data, depsgraph): - pass - - def render(self, depsgraph): engine_type = 'PREVIEW' if self.is_preview else 'FINAL' - self.engine_ptr = _bpy_hydra.engine_create(self.as_pointer(), engine_type, self.delegate_id) delegate_settings = self.get_delegate_settings(engine_type) - _bpy_hydra.engine_sync(self.engine_ptr, depsgraph.as_pointer(), bpy.context.as_pointer(), delegate_settings) - _bpy_hydra.engine_render(self.engine_ptr, depsgraph.as_pointer()) + + def render(self, depsgraph): + if self.engine_ptr: + _bpy_hydra.engine_render(self.engine_ptr, depsgraph.as_pointer()) # viewport render def view_update(self, context, depsgraph): diff --git a/source/blender/render/hydra/preview_engine.cc b/source/blender/render/hydra/preview_engine.cc index d135da4ce785..ffb9891952e2 100644 --- a/source/blender/render/hydra/preview_engine.cc +++ b/source/blender/render/hydra/preview_engine.cc @@ -5,17 +5,64 @@ #include "camera.h" #include "preview_engine.h" +#include "BLI_timer.h" namespace blender::render::hydra { +const double LIFETIME = 180.0; + +std::unique_ptr PreviewEngine::instance; + +void PreviewEngine::schedule_free() +{ + instance->render_delegate->Stop(); + + /* Register timer for schedule free PreviewEngine instance */ + BLI_timer_register((uintptr_t)instance.get(), + free_instance, + nullptr, + nullptr, + LIFETIME, + true); +} + +PreviewEngine *PreviewEngine::get_instance(RenderEngine *bl_engine, const std::string &render_delegate_id) +{ + if (!instance) { + instance = std::make_unique(bl_engine, render_delegate_id); + } + if (BLI_timer_is_registered((uintptr_t)instance.get())) { + /* Unregister timer while PreviewEngine is working */ + BLI_timer_unregister((uintptr_t)instance.get()); + } + instance->update(bl_engine, render_delegate_id); + + return instance.get(); +} + +double PreviewEngine::free_instance(uintptr_t uuid, void *user_data) +{ + if (!instance->render_task_delegate->is_converged()) { + /* Restart timer if render isn't completed */ + return LIFETIME; + } + + CLOG_INFO(LOG_EN, 2, ""); + instance = nullptr; + return -1; +} + void PreviewEngine::sync(Depsgraph *depsgraph, bContext *context, pxr::HdRenderSettingsMap &render_settings) { - scene_delegate = std::make_unique( - render_index.get(), - pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene"), - BlenderSceneDelegate::EngineType::PREVIEW); + if (!scene_delegate) { + scene_delegate = std::make_unique( + render_index.get(), + pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene"), + BlenderSceneDelegate::EngineType::PREVIEW); + } + scene_delegate->clear(); scene_delegate->populate(depsgraph, context); for (auto const &setting : render_settings) { @@ -70,6 +117,12 @@ void PreviewEngine::render(Depsgraph *depsgraph) update_render_result(layer_name, res[0], res[1], pixels); } +void PreviewEngine::update(RenderEngine *bl_engine, const std::string &render_delegate_id) +{ + this->bl_engine = bl_engine; + /* TODO: recreate render_delegate when render_delegate_id is changed */ +} + void PreviewEngine::update_render_result(const std::string &layer_name, int width, int height, diff --git a/source/blender/render/hydra/preview_engine.h b/source/blender/render/hydra/preview_engine.h index a0b38b1d0653..97ee9da93a3e 100644 --- a/source/blender/render/hydra/preview_engine.h +++ b/source/blender/render/hydra/preview_engine.h @@ -8,21 +8,28 @@ namespace blender::render::hydra { class PreviewEngine : public FinalEngine { + private: + /* Singleton class instance */ + static std::unique_ptr instance; + static double free_instance(uintptr_t uuid, void *user_data); + public: + static PreviewEngine *get_instance(RenderEngine *bl_engine, const std::string &render_delegate_id); + static void schedule_free(); + using FinalEngine::FinalEngine; void sync(Depsgraph *depsgraph, bContext *context, pxr::HdRenderSettingsMap &render_settings) override; void render(Depsgraph *depsgraph) override; - protected: + private: + void update(RenderEngine *bl_engine, const std::string &render_delegate_id); void update_render_result(const std::string &layer_name, int width, int height, std::vector &pixels); - protected: - pxr::HdRenderSettingsMap render_settings; }; } // namespace blender::render::hydra diff --git a/source/blender/render/hydra/python.cc b/source/blender/render/hydra/python.cc index 858e00b3ba3b..b97a31b15555 100644 --- a/source/blender/render/hydra/python.cc +++ b/source/blender/render/hydra/python.cc @@ -16,6 +16,8 @@ #include "utils.h" #include "viewport_engine.h" +#include "BLI_timer.h" + namespace blender::render::hydra { static PyObject *init_func(PyObject * /*self*/, PyObject *args) @@ -112,7 +114,7 @@ static PyObject *engine_create_func(PyObject * /*self*/, PyObject *args) engine = new ViewportEngine(bl_engine, render_delegate_id); } else if (STREQ(engine_type, "PREVIEW")) { - engine = new PreviewEngine(bl_engine, render_delegate_id); + engine = PreviewEngine::get_instance(bl_engine, render_delegate_id); } else { if (bl_engine->type->flag & RE_USE_GPU_CONTEXT) { @@ -136,7 +138,13 @@ static PyObject *engine_free_func(PyObject * /*self*/, PyObject *args) } Engine *engine = (Engine *)PyLong_AsVoidPtr(pyengine); - delete engine; + PreviewEngine *preview_engine = dynamic_cast(engine); + if (preview_engine) { + PreviewEngine::schedule_free(); + } + else { + delete engine; + } CLOG_INFO(LOG_EN, 2, "Engine %016llx", engine); Py_RETURN_NONE; diff --git a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc index 772275228dd6..38346736b41e 100644 --- a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc +++ b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.cc @@ -434,4 +434,18 @@ pxr::VtValue BlenderSceneDelegate::GetLightParamValue(pxr::SdfPath const &id, return pxr::VtValue(); } +void BlenderSceneDelegate::clear() +{ + for (auto &it : materials) { + it.second->remove(); + } + + for (auto &it : objects) { + it.second->remove(); + } + + materials.clear(); + objects.clear(); +} + } // namespace blender::render::hydra diff --git a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h index 04dd2f684120..0ee8bb3d0f21 100644 --- a/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h +++ b/source/blender/render/hydra/scene_delegate/blender_scene_delegate.h @@ -33,6 +33,7 @@ class BlenderSceneDelegate : public pxr::HdSceneDelegate { ~BlenderSceneDelegate() override = default; void populate(Depsgraph *depsgraph, bContext *context); + void clear(); // delegate methods pxr::HdMeshTopology GetMeshTopology(pxr::SdfPath const &id) override; diff --git a/source/blender/render/hydra/scene_delegate/light.cc b/source/blender/render/hydra/scene_delegate/light.cc index 9d95abb1b218..3b104e7f11e1 100644 --- a/source/blender/render/hydra/scene_delegate/light.cc +++ b/source/blender/render/hydra/scene_delegate/light.cc @@ -7,7 +7,6 @@ #include #include -#include "BKE_light.h" #include "DNA_light_types.h" #include "blender_scene_delegate.h" @@ -80,13 +79,14 @@ void LightData::init() break; } + p_type = prim_type(light); + /* TODO: temporary value, it should be delivered through Python UI */ data[pxr::HdLightTokens->exposure] = 1.0f; } -pxr::TfToken LightData::prim_type() +pxr::TfToken LightData::prim_type(Light *light) { - Light *light = (Light *)((Object *)id)->data; pxr::TfToken ret; switch (light->type) { case LA_LOCAL: @@ -155,21 +155,27 @@ bool LightData::update_visibility(View3D *view3d) void LightData::insert() { CLOG_INFO(LOG_BSD, 2, "%s", id->name); - scene_delegate->GetRenderIndex().InsertSprim(prim_type(), scene_delegate, p_id); + scene_delegate->GetRenderIndex().InsertSprim(p_type, scene_delegate, p_id); } void LightData::remove() { CLOG_INFO(LOG_BSD, 2, "%s", id->name); - scene_delegate->GetRenderIndex().RemoveSprim(prim_type(), p_id); + scene_delegate->GetRenderIndex().RemoveSprim(p_type, p_id); } void LightData::update() { - /* TODO: prim_type was changed we have to do remove..add light */ - CLOG_INFO(LOG_BSD, 2, "%s", id->name); + Light *light = (Light *)((Object *)id)->data; + if (prim_type(light) != p_type) { + remove(); + init(); + insert(); + return; + } + pxr::HdDirtyBits bits = pxr::HdLight::Clean; if (id->recalc & ID_RECALC_GEOMETRY) { init(); diff --git a/source/blender/render/hydra/scene_delegate/light.h b/source/blender/render/hydra/scene_delegate/light.h index 12d1988e80ed..f351450c084b 100644 --- a/source/blender/render/hydra/scene_delegate/light.h +++ b/source/blender/render/hydra/scene_delegate/light.h @@ -7,6 +7,8 @@ #include #include +#include "BKE_light.h" + #include "object.h" namespace blender::render::hydra { @@ -24,7 +26,8 @@ class LightData : public ObjectData { private: std::map data; - pxr::TfToken prim_type(); + pxr::TfToken p_type; + pxr::TfToken prim_type(Light *light); }; } // namespace blender::render::hydra