Hydra is a rendering architecture part of USD, designed to abstract the host application from the renderer. A renderer implementing a Hydra render delegate can run in any host application supporting Hydra, which now includes Blender. For external renderers this means less code to be written, and improved performance due to a using a C++ API instead of a Python API. Add-ons need to subclass bpy.types.HydraRenderEngine. See the example in the Python API docs for details. An add-on for Hydra Storm will be included as well. This is USD's rasterizing renderer, used in other applications like usdview. For users it can provide a preview of USD file export, and for developers it serves a reference. There are still limitations and missing features, especially around materials. The remaining to do items are tracked in #110765. This feature was contributed by AMD. Ref #110765 Co-authored-by: Georgiy Markelov <georgiy.m.markelov@gmail.com> Co-authored-by: Vasyl-Pidhirskyi <vpidhirskyi@gmail.com> Co-authored-by: Brian Savery <brian.savery@gmail.com> Co-authored-by: Brecht Van Lommel <brecht@blender.org> Pull Request: https://projects.blender.org/blender/blender/pulls/104712
125 lines
4.1 KiB
C++
125 lines
4.1 KiB
C++
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* SPDX-FileCopyrightText: 2011-2022 Blender Foundation */
|
|
|
|
#include "engine.h"
|
|
|
|
#include <pxr/base/plug/plugin.h>
|
|
#include <pxr/base/plug/registry.h>
|
|
#include <pxr/imaging/hd/rendererPluginRegistry.h>
|
|
#include <pxr/imaging/hdSt/renderDelegate.h>
|
|
#include <pxr/imaging/hgi/tokens.h>
|
|
#include <pxr/usd/usdGeom/tokens.h>
|
|
|
|
#include "BLI_path_util.h"
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "GPU_context.h"
|
|
|
|
#include "DEG_depsgraph_query.h"
|
|
|
|
#include "RE_engine.h"
|
|
|
|
#include "CLG_log.h"
|
|
|
|
namespace blender::render::hydra {
|
|
|
|
CLG_LOGREF_DECLARE_GLOBAL(LOG_HYDRA_RENDER, "hydra.render");
|
|
|
|
Engine::Engine(RenderEngine *bl_engine, const std::string &render_delegate_name)
|
|
: render_delegate_name_(render_delegate_name), bl_engine_(bl_engine)
|
|
{
|
|
pxr::HdRendererPluginRegistry ®istry = pxr::HdRendererPluginRegistry::GetInstance();
|
|
|
|
pxr::TF_PY_ALLOW_THREADS_IN_SCOPE();
|
|
|
|
if (GPU_backend_get_type() == GPU_BACKEND_VULKAN) {
|
|
BLI_setenv("HGI_ENABLE_VULKAN", "1");
|
|
}
|
|
|
|
pxr::HdDriverVector hd_drivers;
|
|
if (bl_engine->type->flag & RE_USE_GPU_CONTEXT) {
|
|
hgi_ = pxr::Hgi::CreatePlatformDefaultHgi();
|
|
hgi_driver_.name = pxr::HgiTokens->renderDriver;
|
|
hgi_driver_.driver = pxr::VtValue(hgi_.get());
|
|
|
|
hd_drivers.push_back(&hgi_driver_);
|
|
}
|
|
render_delegate_ = registry.CreateRenderDelegate(pxr::TfToken(render_delegate_name_));
|
|
|
|
if (!render_delegate_) {
|
|
throw std::runtime_error("Cannot create render delegate: " + 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 && GPU_backend_get_type() == GPU_BACKEND_OPENGL) {
|
|
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>();
|
|
}
|
|
|
|
void Engine::sync(Depsgraph *depsgraph, bContext *context)
|
|
{
|
|
depsgraph_ = depsgraph;
|
|
context_ = context;
|
|
scene_ = DEG_get_evaluated_scene(depsgraph);
|
|
|
|
if (!hydra_scene_delegate_) {
|
|
pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene");
|
|
hydra_scene_delegate_ = std::make_unique<io::hydra::HydraSceneDelegate>(render_index_.get(),
|
|
scene_path);
|
|
}
|
|
hydra_scene_delegate_->populate(depsgraph, context ? CTX_wm_view3d(context) : nullptr);
|
|
}
|
|
|
|
void Engine::set_render_setting(const std::string &key, const pxr::VtValue &val)
|
|
{
|
|
render_delegate_->SetRenderSetting(pxr::TfToken(key), val);
|
|
}
|
|
|
|
float Engine::renderer_percent_done()
|
|
{
|
|
pxr::VtDictionary render_stats = render_delegate_->GetRenderStats();
|
|
auto it = render_stats.find("percentDone");
|
|
if (it == render_stats.end()) {
|
|
return 0.0f;
|
|
}
|
|
return (float)it->second.UncheckedGet<double>();
|
|
}
|
|
|
|
pxr::HdTaskSharedPtrVector Engine::tasks()
|
|
{
|
|
pxr::HdTaskSharedPtrVector res;
|
|
if (light_tasks_delegate_) {
|
|
if (scene_->r.alphamode != R_ALPHAPREMUL) {
|
|
#ifndef __APPLE__
|
|
/* TODO: Temporary disable skydome task for MacOS due to crash with error:
|
|
* Failed to created pipeline state, error depthAttachmentPixelFormat is not valid
|
|
* and shader writes to depth */
|
|
res.push_back(light_tasks_delegate_->skydome_task());
|
|
#endif
|
|
}
|
|
res.push_back(light_tasks_delegate_->simple_task());
|
|
}
|
|
res.push_back(render_task_delegate_->task());
|
|
return res;
|
|
}
|
|
|
|
} // namespace blender::render::hydra
|