Add Chromium-only Blender WebEngine parity work
This commit is contained in:
104
blender-5.2.0/source/blender/render/hydra/CMakeLists.txt
Normal file
104
blender-5.2.0/source/blender/render/hydra/CMakeLists.txt
Normal file
@@ -0,0 +1,104 @@
|
||||
# SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# This suppresses the warning "This file includes at least one deprecated or antiquated
|
||||
# header which may be removed without further notice at a future date", which is caused
|
||||
# by the USD library including <ext/hash_set> on Linux. This has been reported at:
|
||||
# https://github.com/PixarAnimationStudios/USD/issues/1057.
|
||||
if(UNIX AND NOT APPLE)
|
||||
add_definitions(-D_GLIBCXX_PERMIT_BACKWARD_HASH)
|
||||
endif()
|
||||
if(WIN32)
|
||||
# We need to keep BOOST_DEBUG_PYTHON for the vendored copy of boost inside USD.
|
||||
add_definitions(-DBOOST_DEBUG_PYTHON)
|
||||
endif()
|
||||
|
||||
# Pre-compiled Linux libraries are made with GCC, and USD uses some extensions
|
||||
# which lead to an incompatible ABI for Clang. Using those extensions with
|
||||
# Clang as well works around the issue.
|
||||
if(UNIX AND NOT APPLE)
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
if(DEFINED LIBDIR)
|
||||
add_definitions(-DARCH_HAS_GNU_STL_EXTENSIONS)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# USD headers use deprecated TBB headers, silence warning.
|
||||
add_definitions(-DTBB_SUPPRESS_DEPRECATED_MESSAGES=1)
|
||||
|
||||
if(WIN32)
|
||||
# Some USD library headers trigger the "unreferenced formal parameter"
|
||||
# warning alert.
|
||||
# Silence them by restore warn C4100 back to w4
|
||||
remove_c_and_cxx_flag("/w34100")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
# USD currently does not support the new preprocessor,
|
||||
# so we remove it here and disable sse2neon
|
||||
remove_c_and_cxx_flag("/Zc:preprocessor")
|
||||
add_definitions(-DDISABLE_SSE2NEON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_OPENGL_BACKEND)
|
||||
add_definitions(-DWITH_OPENGL_BACKEND)
|
||||
endif()
|
||||
|
||||
set(INC
|
||||
../../../../intern/guardedalloc
|
||||
../../blenlib
|
||||
../../makesdna
|
||||
../../makesrna
|
||||
../../io/usd
|
||||
../../gpu/intern
|
||||
../../python/intern
|
||||
# RNA_prototypes.hh
|
||||
${CMAKE_BINARY_DIR}/source/blender/makesrna
|
||||
..
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
)
|
||||
|
||||
set(LIB
|
||||
PRIVATE bf::blenkernel
|
||||
PRIVATE bf::blenlib
|
||||
PRIVATE bf::depsgraph
|
||||
PRIVATE bf::gpu
|
||||
PRIVATE bf::imbuf
|
||||
PRIVATE bf::intern::clog
|
||||
bf_io_usd
|
||||
PRIVATE bf::nodes
|
||||
PRIVATE bf::dependencies::optional::python
|
||||
PRIVATE bf::dependencies::optional::usd
|
||||
PRIVATE bf::dependencies::optional::tbb
|
||||
PRIVATE bf::dependencies::epoxy
|
||||
PRIVATE bf::dependencies::gflags
|
||||
PRIVATE bf::dependencies::eigen
|
||||
)
|
||||
|
||||
set(SRC
|
||||
camera.cc
|
||||
engine.cc
|
||||
final_engine.cc
|
||||
light_tasks_delegate.cc
|
||||
preview_engine.cc
|
||||
python.cc
|
||||
render_task_delegate.cc
|
||||
viewport_engine.cc
|
||||
|
||||
camera.hh
|
||||
engine.hh
|
||||
final_engine.hh
|
||||
light_tasks_delegate.hh
|
||||
preview_engine.hh
|
||||
render_task_delegate.hh
|
||||
settings.hh
|
||||
viewport_engine.hh
|
||||
)
|
||||
|
||||
blender_add_lib(bf_render_hydra "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
|
||||
|
||||
# RNA_prototypes.hh
|
||||
add_dependencies(bf_render_hydra bf_rna)
|
||||
137
blender-5.2.0/source/blender/render/hydra/camera.cc
Normal file
137
blender-5.2.0/source/blender/render/hydra/camera.cc
Normal file
@@ -0,0 +1,137 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "camera.hh"
|
||||
|
||||
#include "BKE_camera.h"
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
static pxr::GfMatrix4d gf_matrix_from_transform(const float m[4][4])
|
||||
{
|
||||
pxr::GfMatrix4d ret;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ret[i][j] = m[i][j];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void gf_camera_fill_dof_data(const Object *camera_obj, pxr::GfCamera *gf_camera)
|
||||
{
|
||||
if (camera_obj == nullptr || camera_obj->type != OB_CAMERA) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Camera *camera = id_cast<Camera *>(camera_obj->data);
|
||||
if (!(camera->dof.flag & CAM_DOF_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* World units. Handles DoF object and value. Object takes precedence. */
|
||||
const float focus_distance = BKE_camera_object_dof_distance(camera_obj);
|
||||
gf_camera->SetFocusDistance(focus_distance);
|
||||
|
||||
/*
|
||||
* F-stop is unit-less, however it's a ratio between focal length and aperture diameter.
|
||||
* The aperture must be in the same unit for correctness.
|
||||
* Focal length in GfCamera is defined in tenths of a world unit.
|
||||
*
|
||||
* Following the logic of USD camera data writer:
|
||||
* tenth_unit_to_meters = 1 / 10
|
||||
* tenth_unit_to_millimeters = 1000 * tenth_unit_to_meters = 100
|
||||
* Scene's units scale is not used for camera's focal length.
|
||||
*/
|
||||
gf_camera->SetFStop(camera->dof.aperture_fstop * 100.0);
|
||||
}
|
||||
|
||||
static pxr::GfCamera gf_camera(const CameraParams ¶ms,
|
||||
const pxr::GfVec2i &res,
|
||||
const pxr::GfVec4f &border)
|
||||
{
|
||||
pxr::GfCamera camera;
|
||||
|
||||
camera.SetProjection(params.is_ortho ? pxr::GfCamera::Projection::Orthographic :
|
||||
pxr::GfCamera::Projection::Perspective);
|
||||
camera.SetClippingRange(pxr::GfRange1f(params.clip_start, params.clip_end));
|
||||
camera.SetFocalLength(params.lens);
|
||||
|
||||
pxr::GfVec2f b_pos(border[0], border[1]), b_size(border[2], border[3]);
|
||||
float sensor_size = BKE_camera_sensor_size(params.sensor_fit, params.sensor_x, params.sensor_y);
|
||||
pxr::GfVec2f sensor_scale = (BKE_camera_sensor_fit(params.sensor_fit, res[0], res[1]) ==
|
||||
CAMERA_SENSOR_FIT_HOR) ?
|
||||
pxr::GfVec2f(1.0f, float(res[1]) / res[0]) :
|
||||
pxr::GfVec2f(float(res[0]) / res[1], 1.0f);
|
||||
pxr::GfVec2f aperture = pxr::GfVec2f((params.is_ortho) ? params.ortho_scale : sensor_size);
|
||||
aperture = pxr::GfCompMult(aperture, sensor_scale);
|
||||
aperture = pxr::GfCompMult(aperture, b_size);
|
||||
aperture *= params.zoom;
|
||||
if (params.is_ortho) {
|
||||
/* Use tenths of a world unit according to USD docs
|
||||
* https://graphics.pixar.com/usd/docs/api/class_gf_camera.html */
|
||||
aperture *= 10.0f;
|
||||
}
|
||||
camera.SetHorizontalAperture(aperture[0]);
|
||||
camera.SetVerticalAperture(aperture[1]);
|
||||
|
||||
pxr::GfVec2f lens_shift = pxr::GfVec2f(params.shiftx, params.shifty);
|
||||
lens_shift = pxr::GfCompDiv(lens_shift, sensor_scale);
|
||||
lens_shift += pxr::GfVec2f(params.offsetx, params.offsety);
|
||||
lens_shift += b_pos + b_size * 0.5f - pxr::GfVec2f(0.5f);
|
||||
lens_shift = pxr::GfCompDiv(lens_shift, b_size);
|
||||
camera.SetHorizontalApertureOffset(lens_shift[0] * aperture[0]);
|
||||
camera.SetVerticalApertureOffset(lens_shift[1] * aperture[1]);
|
||||
|
||||
return camera;
|
||||
}
|
||||
|
||||
pxr::GfCamera gf_camera(const Depsgraph *depsgraph,
|
||||
const View3D *v3d,
|
||||
const ARegion *region,
|
||||
const pxr::GfVec4f &border)
|
||||
{
|
||||
const RegionView3D *region_data = static_cast<const RegionView3D *>(region->regiondata);
|
||||
const Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
|
||||
CameraParams params;
|
||||
BKE_camera_params_init(¶ms);
|
||||
BKE_camera_params_from_view3d(¶ms, depsgraph, v3d, region_data);
|
||||
|
||||
pxr::GfCamera camera = gf_camera(params, pxr::GfVec2i(region->winx, region->winy), border);
|
||||
camera.SetTransform(gf_matrix_from_transform(region_data->viewmat).GetInverse());
|
||||
|
||||
/* Ensure viewport is in active camera view mode. */
|
||||
if (region_data->persp == RV3D_CAMOB) {
|
||||
gf_camera_fill_dof_data(scene->camera, &camera);
|
||||
}
|
||||
|
||||
return camera;
|
||||
}
|
||||
|
||||
pxr::GfCamera gf_camera(const Object *camera_obj,
|
||||
const pxr::GfVec2i &res,
|
||||
const pxr::GfVec4f &border)
|
||||
{
|
||||
CameraParams params;
|
||||
BKE_camera_params_init(¶ms);
|
||||
BKE_camera_params_from_object(¶ms, camera_obj);
|
||||
|
||||
pxr::GfCamera camera = gf_camera(params, res, border);
|
||||
camera.SetTransform(gf_matrix_from_transform(camera_obj->object_to_world().ptr()));
|
||||
|
||||
gf_camera_fill_dof_data(camera_obj, &camera);
|
||||
|
||||
return camera;
|
||||
}
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
28
blender-5.2.0/source/blender/render/hydra/camera.hh
Normal file
28
blender-5.2.0/source/blender/render/hydra/camera.hh
Normal file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pxr/base/gf/camera.h>
|
||||
#include <pxr/base/gf/vec2f.h>
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct ARegion;
|
||||
struct Depsgraph;
|
||||
struct Object;
|
||||
struct View3D;
|
||||
namespace render::hydra {
|
||||
|
||||
pxr::GfCamera gf_camera(const Depsgraph *depsgraph,
|
||||
const View3D *v3d,
|
||||
const ARegion *region,
|
||||
const pxr::GfVec4f &border);
|
||||
|
||||
pxr::GfCamera gf_camera(const Object *camera_obj,
|
||||
const pxr::GfVec2i &res,
|
||||
const pxr::GfVec4f &border);
|
||||
|
||||
} // namespace render::hydra
|
||||
} // namespace blender
|
||||
180
blender-5.2.0/source/blender/render/hydra/engine.cc
Normal file
180
blender-5.2.0/source/blender/render/hydra/engine.cc
Normal file
@@ -0,0 +1,180 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "engine.hh"
|
||||
|
||||
#include <pxr/base/plug/plugin.h>
|
||||
#include <pxr/base/plug/registry.h>
|
||||
#include <pxr/imaging/hd/flatteningSceneIndex.h>
|
||||
#include <pxr/imaging/hd/rendererPluginRegistry.h>
|
||||
#include <pxr/imaging/hdSt/renderDelegate.h>
|
||||
#include <pxr/imaging/hdsi/extComputationPrimvarPruningSceneIndex.h>
|
||||
#include <pxr/imaging/hgi/tokens.h>
|
||||
#include <pxr/usd/usdGeom/tokens.h>
|
||||
#include <pxr/usdImaging/usdImaging/flattenedDataSourceProviders.h>
|
||||
#include <pxr/usdImaging/usdImaging/materialBindingsResolvingSceneIndex.h>
|
||||
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "GPU_context.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#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();
|
||||
|
||||
pxr::HdDriverVector hd_drivers;
|
||||
if (bl_engine->type->flag & RE_USE_GPU_CONTEXT) {
|
||||
pxr::TfToken hgi_token;
|
||||
switch (GPU_backend_get_type()) {
|
||||
case GPU_BACKEND_METAL:
|
||||
hgi_token = pxr::TfToken("Metal");
|
||||
break;
|
||||
case GPU_BACKEND_OPENGL:
|
||||
hgi_token = pxr::TfToken("OpenGL");
|
||||
break;
|
||||
case GPU_BACKEND_VULKAN:
|
||||
hgi_token = pxr::TfToken("Vulkan");
|
||||
break;
|
||||
case GPU_BACKEND_NONE:
|
||||
case GPU_BACKEND_ANY:
|
||||
/* When pxr::Hgi::CreateNamedHgi is called with an empty token it will select the default
|
||||
* platform Hgi. */
|
||||
break;
|
||||
}
|
||||
hgi_ = pxr::Hgi::CreateNamedHgi(hgi_token);
|
||||
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<io::hydra::CameraDelegate>(
|
||||
render_index_.get(), pxr::SdfPath::AbsoluteRootPath().AppendElementString("freeCamera"));
|
||||
|
||||
/* Tasks are exposed as task prims through a retained scene index. */
|
||||
const bool needs_prefixing = false;
|
||||
task_scene_index_ = pxr::HdRetainedSceneIndex::New();
|
||||
render_index_->InsertSceneIndex(
|
||||
task_scene_index_, pxr::SdfPath::AbsoluteRootPath(), needs_prefixing);
|
||||
|
||||
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(),
|
||||
task_scene_index_,
|
||||
pxr::SdfPath::AbsoluteRootPath().AppendElementString("renderTask"));
|
||||
}
|
||||
else {
|
||||
render_task_delegate_ = std::make_unique<RenderTaskDelegate>(
|
||||
render_index_.get(),
|
||||
task_scene_index_,
|
||||
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(),
|
||||
task_scene_index_,
|
||||
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);
|
||||
|
||||
const bool use_materialx = bl_engine_->type->flag & RE_USE_MATERIALX;
|
||||
|
||||
if (scene_->hydra.export_method == SCE_HYDRA_EXPORT_HYDRA) {
|
||||
/* Fast path. */
|
||||
usd_scene_delegate_.reset();
|
||||
|
||||
if (!hydra_scene_index_) {
|
||||
hydra_scene_index_path_ = pxr::SdfPath::AbsoluteRootPath().AppendElementString("scene");
|
||||
hydra_scene_index_ = std::make_unique<io::hydra::HydraSceneIndex>(
|
||||
hydra_scene_index_path_, render_delegate_.Get(), use_materialx);
|
||||
const bool needs_prefixing = false;
|
||||
pxr::HdSceneIndexBaseRefPtr filtered = hydra_scene_index_->retained();
|
||||
filtered = pxr::HdSiExtComputationPrimvarPruningSceneIndex::New(filtered);
|
||||
filtered = pxr::HdFlatteningSceneIndex::New(filtered,
|
||||
pxr::UsdImagingFlattenedDataSourceProviders());
|
||||
filtered = pxr::UsdImagingMaterialBindingsResolvingSceneIndex::New(filtered, nullptr);
|
||||
render_index_->InsertSceneIndex(filtered, hydra_scene_index_path_, needs_prefixing);
|
||||
}
|
||||
hydra_scene_index_->populate(depsgraph, context ? CTX_wm_view3d(context) : nullptr);
|
||||
}
|
||||
else {
|
||||
/* Slow USD export for reference. */
|
||||
if (hydra_scene_index_) {
|
||||
hydra_scene_index_->clear();
|
||||
}
|
||||
|
||||
if (!usd_scene_delegate_) {
|
||||
pxr::SdfPath scene_path = pxr::SdfPath::AbsoluteRootPath().AppendElementString("usd_scene");
|
||||
usd_scene_delegate_ = std::make_unique<io::hydra::USDSceneIndex>(
|
||||
render_index_.get(), scene_path, use_materialx);
|
||||
}
|
||||
usd_scene_delegate_->populate(depsgraph);
|
||||
}
|
||||
free_camera_delegate_->sync(scene_);
|
||||
}
|
||||
|
||||
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 create 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
|
||||
79
blender-5.2.0/source/blender/render/hydra/engine.hh
Normal file
79
blender-5.2.0/source/blender/render/hydra/engine.hh
Normal file
@@ -0,0 +1,79 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <pxr/imaging/hd/driver.h>
|
||||
#include <pxr/imaging/hd/engine.h>
|
||||
#include <pxr/imaging/hd/pluginRenderDelegateUniqueHandle.h>
|
||||
#include <pxr/imaging/hd/retainedSceneIndex.h>
|
||||
#include <pxr/imaging/hgi/hgi.h>
|
||||
#include <pxr/usd/usd/stage.h>
|
||||
#include <pxr/usdImaging/usdImaging/delegate.h>
|
||||
|
||||
#include "hydra/camera_delegate.hh"
|
||||
#include "hydra/scene_index.hh"
|
||||
#include "hydra/settings.hh"
|
||||
#include "hydra/usd_scene_index.hh"
|
||||
|
||||
#include "light_tasks_delegate.hh"
|
||||
#include "render_task_delegate.hh"
|
||||
|
||||
struct CLG_LogRef;
|
||||
|
||||
namespace blender {
|
||||
|
||||
struct bContext;
|
||||
struct RenderEngine;
|
||||
|
||||
namespace render::hydra {
|
||||
|
||||
extern CLG_LogRef *LOG_HYDRA_RENDER;
|
||||
|
||||
class Engine {
|
||||
protected:
|
||||
std::string render_delegate_name_;
|
||||
RenderEngine *bl_engine_ = nullptr;
|
||||
Depsgraph *depsgraph_ = nullptr;
|
||||
bContext *context_ = nullptr;
|
||||
Scene *scene_ = nullptr;
|
||||
|
||||
/* The order is important due to deletion order */
|
||||
pxr::HgiUniquePtr hgi_;
|
||||
pxr::HdDriver hgi_driver_;
|
||||
pxr::HdPluginRenderDelegateUniqueHandle render_delegate_;
|
||||
std::unique_ptr<pxr::HdRenderIndex> render_index_;
|
||||
|
||||
std::unique_ptr<io::hydra::CameraDelegate> free_camera_delegate_;
|
||||
std::unique_ptr<io::hydra::HydraSceneIndex> hydra_scene_index_;
|
||||
pxr::SdfPath hydra_scene_index_path_;
|
||||
std::unique_ptr<io::hydra::USDSceneIndex> usd_scene_delegate_;
|
||||
|
||||
pxr::HdRetainedSceneIndexRefPtr task_scene_index_;
|
||||
std::unique_ptr<RenderTaskDelegate> render_task_delegate_;
|
||||
std::unique_ptr<LightTasksDelegate> light_tasks_delegate_;
|
||||
std::unique_ptr<pxr::HdEngine> engine_;
|
||||
|
||||
public:
|
||||
Engine(RenderEngine *bl_engine, const std::string &render_delegate_name);
|
||||
virtual ~Engine() = default;
|
||||
|
||||
void sync(Depsgraph *depsgraph, bContext *context);
|
||||
virtual void render() = 0;
|
||||
|
||||
virtual void set_render_setting(const std::string &key, const pxr::VtValue &val);
|
||||
|
||||
protected:
|
||||
float renderer_percent_done();
|
||||
pxr::HdTaskSharedPtrVector tasks();
|
||||
virtual void notify_status(float progress,
|
||||
const std::string &title,
|
||||
const std::string &info) = 0;
|
||||
};
|
||||
|
||||
} // namespace render::hydra
|
||||
} // namespace blender
|
||||
140
blender-5.2.0/source/blender/render/hydra/final_engine.cc
Normal file
140
blender-5.2.0/source/blender/render/hydra/final_engine.cc
Normal file
@@ -0,0 +1,140 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "final_engine.hh"
|
||||
#include "camera.hh"
|
||||
|
||||
#include <pxr/imaging/hd/light.h>
|
||||
#include <pxr/imaging/hd/renderBuffer.h>
|
||||
|
||||
#include "DNA_layer_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_time.h"
|
||||
#include "BLI_timecode.h"
|
||||
|
||||
#include "BKE_lib_id.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "IMB_imbuf_types.hh"
|
||||
|
||||
#include "RE_engine.h"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
void FinalEngine::render()
|
||||
{
|
||||
const ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph_);
|
||||
|
||||
char scene_name[MAX_ID_FULL_NAME];
|
||||
BKE_id_full_name_get(scene_name, &scene_->id, 0);
|
||||
|
||||
const RenderData &r = scene_->r;
|
||||
pxr::GfVec4f border(0, 0, 1, 1);
|
||||
if (r.mode & R_BORDER) {
|
||||
border.Set(r.border.xmin,
|
||||
r.border.ymin,
|
||||
r.border.xmax - r.border.xmin,
|
||||
r.border.ymax - r.border.ymin);
|
||||
}
|
||||
pxr::GfVec2i image_res(r.xsch * r.size / 100, r.ysch * r.size / 100);
|
||||
int width = image_res[0] * border[2];
|
||||
int height = image_res[1] * border[3];
|
||||
|
||||
pxr::GfCamera camera = gf_camera(scene_->camera, image_res, border);
|
||||
|
||||
free_camera_delegate_->SetCamera(camera);
|
||||
render_task_delegate_->set_viewport(pxr::GfVec4d(0, 0, width, height));
|
||||
if (light_tasks_delegate_) {
|
||||
light_tasks_delegate_->set_viewport(pxr::GfVec4d(0, 0, width, height));
|
||||
}
|
||||
|
||||
RenderResult *rr = RE_engine_get_result(bl_engine_);
|
||||
RenderLayer *rlayer = static_cast<RenderLayer *>(rr->layers.first);
|
||||
for (RenderPass &rpass : rlayer->passes) {
|
||||
pxr::TfToken *aov_token = aov_tokens_.lookup_ptr(rpass.name);
|
||||
if (!aov_token) {
|
||||
CLOG_WARN(LOG_HYDRA_RENDER, "Couldn't find AOV token for render pass: %s", rpass.name);
|
||||
continue;
|
||||
}
|
||||
render_task_delegate_->add_aov(*aov_token);
|
||||
}
|
||||
if (bl_engine_->type->flag & RE_USE_GPU_CONTEXT) {
|
||||
/* For GPU context engine color and depth AOVs has to be added anyway */
|
||||
render_task_delegate_->add_aov(pxr::HdAovTokens->color);
|
||||
render_task_delegate_->add_aov(pxr::HdAovTokens->depth);
|
||||
}
|
||||
|
||||
render_task_delegate_->bind();
|
||||
|
||||
auto t = tasks();
|
||||
|
||||
char elapsed_time[32];
|
||||
double time_begin = BLI_time_now_seconds();
|
||||
float percent_done = 0.0;
|
||||
|
||||
while (true) {
|
||||
engine_->Execute(render_index_.get(), &t);
|
||||
|
||||
if (RE_engine_test_break(bl_engine_)) {
|
||||
break;
|
||||
}
|
||||
|
||||
percent_done = renderer_percent_done();
|
||||
BLI_timecode_string_from_time_simple(
|
||||
elapsed_time, sizeof(elapsed_time), BLI_time_now_seconds() - time_begin);
|
||||
notify_status(percent_done / 100.0,
|
||||
std::string(scene_name) + ": " + view_layer->name,
|
||||
std::string("Render Time: ") + elapsed_time +
|
||||
" | Done: " + std::to_string(int(percent_done)) + "%");
|
||||
|
||||
if (render_task_delegate_->is_converged()) {
|
||||
break;
|
||||
}
|
||||
|
||||
update_render_result(width, height, view_layer->name);
|
||||
}
|
||||
|
||||
update_render_result(width, height, view_layer->name);
|
||||
render_task_delegate_->unbind();
|
||||
}
|
||||
|
||||
void FinalEngine::set_render_setting(const std::string &key, const pxr::VtValue &val)
|
||||
{
|
||||
if (STRPREFIX(key.c_str(), "aovToken:")) {
|
||||
aov_tokens_.add_overwrite(key.substr(key.find(":") + 1),
|
||||
pxr::TfToken(val.UncheckedGet<std::string>()));
|
||||
return;
|
||||
}
|
||||
Engine::set_render_setting(key, val);
|
||||
}
|
||||
|
||||
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(int width, int height, const char *layer_name)
|
||||
{
|
||||
RenderResult *rr = RE_engine_begin_result(bl_engine_, 0, 0, width, height, layer_name, nullptr);
|
||||
|
||||
RenderLayer *rlayer = static_cast<RenderLayer *>(
|
||||
BLI_findstring(&rr->layers, layer_name, offsetof(RenderLayer, name)));
|
||||
|
||||
if (rlayer) {
|
||||
for (RenderPass &rpass : rlayer->passes) {
|
||||
pxr::TfToken *aov_token = aov_tokens_.lookup_ptr(rpass.name);
|
||||
if (aov_token) {
|
||||
render_task_delegate_->read_aov(*aov_token, rpass.ibuf->float_data_for_write());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RE_engine_end_result(bl_engine_, rr, false, false, false);
|
||||
}
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
28
blender-5.2.0/source/blender/render/hydra/final_engine.hh
Normal file
28
blender-5.2.0/source/blender/render/hydra/final_engine.hh
Normal file
@@ -0,0 +1,28 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "engine.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
class FinalEngine : public Engine {
|
||||
private:
|
||||
Map<std::string, pxr::TfToken> aov_tokens_;
|
||||
|
||||
public:
|
||||
using Engine::Engine;
|
||||
|
||||
void render() override;
|
||||
void set_render_setting(const std::string &key, const pxr::VtValue &val) override;
|
||||
|
||||
protected:
|
||||
void notify_status(float progress, const std::string &title, const std::string &info) override;
|
||||
|
||||
private:
|
||||
void update_render_result(int width, int height, const char *layer_name);
|
||||
};
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
@@ -0,0 +1,106 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "light_tasks_delegate.hh"
|
||||
#include "engine.hh"
|
||||
|
||||
#include <pxr/imaging/hd/legacyTaskFactory.h>
|
||||
#include <pxr/imaging/hd/legacyTaskSchema.h>
|
||||
#include <pxr/imaging/hd/retainedDataSource.h>
|
||||
#include <pxr/imaging/hd/sceneIndexObserver.h>
|
||||
#include <pxr/imaging/hd/tokens.h>
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
LightTasksDelegate::LightTasksDelegate(pxr::HdRenderIndex *render_index,
|
||||
pxr::HdRetainedSceneIndexRefPtr task_scene_index,
|
||||
pxr::SdfPath const &base_id)
|
||||
: render_index_(render_index),
|
||||
task_scene_index_(std::move(task_scene_index)),
|
||||
simple_task_id_(base_id.AppendElementString("simpleTask")),
|
||||
skydome_task_id_(base_id.AppendElementString("skydomeTask"))
|
||||
{
|
||||
publish_simple_task();
|
||||
publish_skydome_task();
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", simple_task_id_.GetText());
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", skydome_task_id_.GetText());
|
||||
}
|
||||
|
||||
void LightTasksDelegate::publish_simple_task()
|
||||
{
|
||||
pxr::HdContainerDataSourceHandle task_ds =
|
||||
pxr::HdLegacyTaskSchema::Builder()
|
||||
.SetFactory(
|
||||
pxr::HdRetainedTypedSampledDataSource<pxr::HdLegacyTaskFactorySharedPtr>::New(
|
||||
pxr::HdMakeLegacyTaskFactory<pxr::HdxSimpleLightTask>()))
|
||||
.SetParameters(simple_task_params_ds_)
|
||||
.Build();
|
||||
|
||||
task_scene_index_->AddPrims({{simple_task_id_,
|
||||
pxr::HdPrimTypeTokens->task,
|
||||
pxr::HdRetainedContainerDataSource::New(
|
||||
pxr::HdLegacyTaskSchema::GetSchemaToken(), task_ds)}});
|
||||
}
|
||||
|
||||
void LightTasksDelegate::publish_skydome_task()
|
||||
{
|
||||
const pxr::HdRprimCollection collection(pxr::HdTokens->geometry,
|
||||
pxr::HdReprSelector(pxr::HdReprTokens->smoothHull));
|
||||
const pxr::TfTokenVector render_tags = {pxr::HdRenderTagTokens->geometry};
|
||||
|
||||
pxr::HdContainerDataSourceHandle task_ds =
|
||||
pxr::HdLegacyTaskSchema::Builder()
|
||||
.SetFactory(
|
||||
pxr::HdRetainedTypedSampledDataSource<pxr::HdLegacyTaskFactorySharedPtr>::New(
|
||||
pxr::HdMakeLegacyTaskFactory<pxr::HdxSkydomeTask>()))
|
||||
.SetParameters(skydome_task_params_ds_)
|
||||
.SetCollection(
|
||||
pxr::HdRetainedTypedSampledDataSource<pxr::HdRprimCollection>::New(collection))
|
||||
.SetRenderTags(
|
||||
pxr::HdRetainedTypedSampledDataSource<pxr::TfTokenVector>::New(render_tags))
|
||||
.Build();
|
||||
|
||||
task_scene_index_->AddPrims({{skydome_task_id_,
|
||||
pxr::HdPrimTypeTokens->task,
|
||||
pxr::HdRetainedContainerDataSource::New(
|
||||
pxr::HdLegacyTaskSchema::GetSchemaToken(), task_ds)}});
|
||||
}
|
||||
|
||||
pxr::HdTaskSharedPtr LightTasksDelegate::simple_task()
|
||||
{
|
||||
return render_index_->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 render_index_->GetTask(skydome_task_id_);
|
||||
}
|
||||
|
||||
void LightTasksDelegate::set_camera(pxr::SdfPath const &camera_id)
|
||||
{
|
||||
if (simple_task_params_.cameraPath == camera_id && skydome_task_params_.camera == camera_id) {
|
||||
return;
|
||||
}
|
||||
simple_task_params_.cameraPath = camera_id;
|
||||
skydome_task_params_.camera = camera_id;
|
||||
task_scene_index_->DirtyPrims(
|
||||
{{simple_task_id_, pxr::HdLegacyTaskSchema::GetParametersLocator()},
|
||||
{skydome_task_id_, pxr::HdLegacyTaskSchema::GetParametersLocator()}});
|
||||
}
|
||||
|
||||
void LightTasksDelegate::set_viewport(pxr::GfVec4d const &viewport)
|
||||
{
|
||||
if (skydome_task_params_.viewport == viewport) {
|
||||
return;
|
||||
}
|
||||
skydome_task_params_.viewport = viewport;
|
||||
task_scene_index_->DirtyPrims(
|
||||
{{skydome_task_id_, pxr::HdLegacyTaskSchema::GetParametersLocator()}});
|
||||
}
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
@@ -0,0 +1,69 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pxr/imaging/hd/dataSource.h>
|
||||
#include <pxr/imaging/hd/renderIndex.h>
|
||||
#include <pxr/imaging/hd/retainedSceneIndex.h>
|
||||
#include <pxr/imaging/hd/task.h>
|
||||
#include <pxr/imaging/hdx/simpleLightTask.h>
|
||||
#include <pxr/imaging/hdx/skydomeTask.h>
|
||||
|
||||
#include "render_task_delegate.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
/* Registers a HdxSimpleLightTask and HdxSkydomeTask with the render index. */
|
||||
|
||||
class SimpleLightTaskParamsDataSource final
|
||||
: public pxr::HdTypedSampledDataSource<pxr::HdxSimpleLightTaskParams> {
|
||||
public:
|
||||
HD_DECLARE_DATASOURCE(SimpleLightTaskParamsDataSource);
|
||||
|
||||
pxr::HdxSimpleLightTaskParams params;
|
||||
|
||||
pxr::VtValue GetValue(Time /*t*/) override
|
||||
{
|
||||
return pxr::VtValue(params);
|
||||
}
|
||||
pxr::HdxSimpleLightTaskParams GetTypedValue(Time /*t*/) override
|
||||
{
|
||||
return params;
|
||||
}
|
||||
bool GetContributingSampleTimesForInterval(Time /*start*/,
|
||||
Time /*end*/,
|
||||
std::vector<Time> * /*sampleTimes*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class LightTasksDelegate {
|
||||
public:
|
||||
LightTasksDelegate(pxr::HdRenderIndex *render_index,
|
||||
pxr::HdRetainedSceneIndexRefPtr task_scene_index,
|
||||
pxr::SdfPath const &base_id);
|
||||
|
||||
pxr::HdTaskSharedPtr simple_task();
|
||||
pxr::HdTaskSharedPtr skydome_task();
|
||||
void set_camera(pxr::SdfPath const &camera_id);
|
||||
void set_viewport(pxr::GfVec4d const &viewport);
|
||||
|
||||
private:
|
||||
void publish_simple_task();
|
||||
void publish_skydome_task();
|
||||
|
||||
pxr::HdRenderIndex *render_index_ = nullptr;
|
||||
pxr::HdRetainedSceneIndexRefPtr task_scene_index_;
|
||||
pxr::SdfPath simple_task_id_;
|
||||
pxr::SdfPath skydome_task_id_;
|
||||
SimpleLightTaskParamsDataSource::Handle simple_task_params_ds_ =
|
||||
SimpleLightTaskParamsDataSource::New();
|
||||
RenderTaskParamsDataSource::Handle skydome_task_params_ds_ = RenderTaskParamsDataSource::New();
|
||||
pxr::HdxSimpleLightTaskParams &simple_task_params_ = simple_task_params_ds_->params;
|
||||
pxr::HdxRenderTaskParams &skydome_task_params_ = skydome_task_params_ds_->params;
|
||||
};
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
16
blender-5.2.0/source/blender/render/hydra/preview_engine.cc
Normal file
16
blender-5.2.0/source/blender/render/hydra/preview_engine.cc
Normal file
@@ -0,0 +1,16 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "preview_engine.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
void PreviewEngine::notify_status(float /*progress*/,
|
||||
const std::string & /*title*/,
|
||||
const std::string & /*info*/)
|
||||
{
|
||||
/* Empty function. */
|
||||
}
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
19
blender-5.2.0/source/blender/render/hydra/preview_engine.hh
Normal file
19
blender-5.2.0/source/blender/render/hydra/preview_engine.hh
Normal file
@@ -0,0 +1,19 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "final_engine.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
class PreviewEngine : public FinalEngine {
|
||||
public:
|
||||
using FinalEngine::FinalEngine;
|
||||
|
||||
protected:
|
||||
void notify_status(float progress, const std::string &title, const std::string &info) override;
|
||||
};
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
217
blender-5.2.0/source/blender/render/hydra/python.cc
Normal file
217
blender-5.2.0/source/blender/render/hydra/python.cc
Normal file
@@ -0,0 +1,217 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "final_engine.hh"
|
||||
#include "preview_engine.hh"
|
||||
#include "viewport_engine.hh"
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "RE_engine.h"
|
||||
|
||||
#include "../generic/py_capi_utils.hh"
|
||||
#include "bpy_rna.hh"
|
||||
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "RNA_prototypes.hh"
|
||||
|
||||
#include "hydra/image.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
namespace render::hydra {
|
||||
|
||||
template<typename T> T *pyrna_to_pointer(PyObject *pyobject, const StructRNA *rnatype)
|
||||
{
|
||||
const PointerRNA *ptr = pyrna_struct_as_ptr_or_null(pyobject, rnatype);
|
||||
return (ptr) ? static_cast<T *>(ptr->data) : nullptr;
|
||||
}
|
||||
|
||||
static PyObject *engine_create_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pyengine;
|
||||
char *engine_type, *render_delegate_id;
|
||||
if (!PyArg_ParseTuple(args, "Oss", &pyengine, &engine_type, &render_delegate_id)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RenderEngine *bl_engine = pyrna_to_pointer<RenderEngine>(pyengine, RNA_RenderEngine);
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %s", engine_type);
|
||||
Engine *engine = nullptr;
|
||||
try {
|
||||
if (STREQ(engine_type, "VIEWPORT")) {
|
||||
engine = new ViewportEngine(bl_engine, render_delegate_id);
|
||||
}
|
||||
else if (STREQ(engine_type, "PREVIEW")) {
|
||||
engine = new PreviewEngine(bl_engine, render_delegate_id);
|
||||
}
|
||||
else {
|
||||
engine = new FinalEngine(bl_engine, render_delegate_id);
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error &e) {
|
||||
CLOG_ERROR(LOG_HYDRA_RENDER, "%s", e.what());
|
||||
}
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine);
|
||||
return PyLong_FromVoidPtr(engine);
|
||||
}
|
||||
|
||||
static PyObject *engine_free_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pyengine;
|
||||
if (!PyArg_ParseTuple(args, "O", &pyengine)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Engine *engine = static_cast<Engine *>(PyLong_AsVoidPtr(pyengine));
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine);
|
||||
delete engine;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *engine_update_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pyengine, *pydepsgraph, *pycontext;
|
||||
if (!PyArg_ParseTuple(args, "OOO", &pyengine, &pydepsgraph, &pycontext)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Engine *engine = static_cast<Engine *>(PyLong_AsVoidPtr(pyengine));
|
||||
Depsgraph *depsgraph = pyrna_to_pointer<Depsgraph>(pydepsgraph, RNA_Depsgraph);
|
||||
bContext *context = pyrna_to_pointer<bContext>(pycontext, RNA_Context);
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine);
|
||||
engine->sync(depsgraph, context);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *engine_render_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pyengine;
|
||||
if (!PyArg_ParseTuple(args, "O", &pyengine)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Engine *engine = static_cast<Engine *>(PyLong_AsVoidPtr(pyengine));
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine);
|
||||
|
||||
/* Allow Blender to execute other Python scripts. */
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
engine->render();
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *engine_view_draw_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pyengine, *pycontext;
|
||||
if (!PyArg_ParseTuple(args, "OO", &pyengine, &pycontext)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ViewportEngine *engine = static_cast<ViewportEngine *>(PyLong_AsVoidPtr(pyengine));
|
||||
bContext *context = pyrna_to_pointer<bContext>(pycontext, RNA_Context);
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p", engine);
|
||||
|
||||
/* Allow Blender to execute other Python scripts. */
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
engine->render(context);
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static pxr::VtValue get_setting_val(PyObject *pyval)
|
||||
{
|
||||
pxr::VtValue val;
|
||||
if (PyBool_Check(pyval)) {
|
||||
val = Py_IsTrue(pyval);
|
||||
}
|
||||
else if (PyLong_Check(pyval)) {
|
||||
val = PyLong_AsLong(pyval);
|
||||
}
|
||||
else if (PyFloat_Check(pyval)) {
|
||||
val = PyFloat_AsDouble(pyval);
|
||||
}
|
||||
else if (PyUnicode_Check(pyval)) {
|
||||
val = std::string(PyUnicode_AsUTF8(pyval));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static PyObject *engine_set_render_setting_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pyengine, *pyval;
|
||||
char *key;
|
||||
if (!PyArg_ParseTuple(args, "OsO", &pyengine, &key, &pyval)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Engine *engine = static_cast<Engine *>(PyLong_AsVoidPtr(pyengine));
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "Engine %p: %s", engine, key);
|
||||
engine->set_render_setting(key, get_setting_val(pyval));
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *cache_or_get_image_file_func(PyObject * /*self*/, PyObject *args)
|
||||
{
|
||||
PyObject *pycontext, *pyimage;
|
||||
if (!PyArg_ParseTuple(args, "OO", &pycontext, &pyimage)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bContext *context = static_cast<bContext *>(PyLong_AsVoidPtr(pycontext));
|
||||
Image *image = static_cast<Image *>(PyLong_AsVoidPtr(pyimage));
|
||||
|
||||
std::string image_path = io::hydra::cache_or_get_image_file(
|
||||
CTX_data_main(context), CTX_data_scene(context), image, nullptr);
|
||||
return PyC_UnicodeFromStdStr(image_path);
|
||||
}
|
||||
|
||||
static PyMethodDef methods[] = {
|
||||
{"engine_create", engine_create_func, METH_VARARGS, ""},
|
||||
{"engine_free", engine_free_func, METH_VARARGS, ""},
|
||||
{"engine_update", engine_update_func, METH_VARARGS, ""},
|
||||
{"engine_render", engine_render_func, METH_VARARGS, ""},
|
||||
{"engine_view_draw", engine_view_draw_func, METH_VARARGS, ""},
|
||||
{"engine_set_render_setting", engine_set_render_setting_func, METH_VARARGS, ""},
|
||||
|
||||
{"cache_or_get_image_file", cache_or_get_image_file_func, METH_VARARGS, ""},
|
||||
|
||||
{nullptr, nullptr, 0, nullptr},
|
||||
};
|
||||
|
||||
static PyModuleDef module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_bpy_hydra",
|
||||
"Hydra render API",
|
||||
-1,
|
||||
methods,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
};
|
||||
|
||||
} // namespace render::hydra
|
||||
|
||||
PyObject *BPyInit_hydra();
|
||||
|
||||
PyObject *BPyInit_hydra()
|
||||
{
|
||||
PyObject *mod = PyModule_Create(&render::hydra::module);
|
||||
return mod;
|
||||
}
|
||||
|
||||
} // namespace blender
|
||||
@@ -0,0 +1,352 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "render_task_delegate.hh"
|
||||
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
# include "GPU_context.hh"
|
||||
# include <epoxy/gl.h>
|
||||
#endif
|
||||
|
||||
#include <pxr/imaging/hd/legacyTaskFactory.h>
|
||||
#include <pxr/imaging/hd/legacyTaskSchema.h>
|
||||
#include <pxr/imaging/hd/renderBuffer.h>
|
||||
#include <pxr/imaging/hd/renderBufferSchema.h>
|
||||
#include <pxr/imaging/hd/renderDelegate.h>
|
||||
#include <pxr/imaging/hd/retainedDataSource.h>
|
||||
#include <pxr/imaging/hd/sceneIndexObserver.h>
|
||||
#include <pxr/imaging/hd/tokens.h>
|
||||
#include <pxr/imaging/hdx/renderTask.h>
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
|
||||
#include "engine.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
RenderTaskDelegate::RenderTaskDelegate(pxr::HdRenderIndex *render_index,
|
||||
pxr::HdRetainedSceneIndexRefPtr task_scene_index,
|
||||
pxr::SdfPath const &base_id)
|
||||
: render_index_(render_index),
|
||||
task_scene_index_(std::move(task_scene_index)),
|
||||
base_id_(base_id),
|
||||
task_id_(base_id.AppendElementString("task"))
|
||||
{
|
||||
task_params_.enableLighting = true;
|
||||
task_params_.alphaThreshold = 0.1f;
|
||||
|
||||
/* Disable this so Metal and OpenGL match in Storm render tests, only
|
||||
* the former seems to use multisample. */
|
||||
task_params_.useAovMultiSample = false;
|
||||
|
||||
publish_task();
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", task_id_.GetText());
|
||||
}
|
||||
|
||||
void RenderTaskDelegate::publish_task()
|
||||
{
|
||||
const pxr::HdRprimCollection collection(pxr::HdTokens->geometry,
|
||||
pxr::HdReprSelector(pxr::HdReprTokens->smoothHull));
|
||||
const pxr::TfTokenVector render_tags = {pxr::HdRenderTagTokens->geometry};
|
||||
|
||||
pxr::HdContainerDataSourceHandle task_ds =
|
||||
pxr::HdLegacyTaskSchema::Builder()
|
||||
.SetFactory(
|
||||
pxr::HdRetainedTypedSampledDataSource<pxr::HdLegacyTaskFactorySharedPtr>::New(
|
||||
pxr::HdMakeLegacyTaskFactory<pxr::HdxRenderTask>()))
|
||||
.SetParameters(task_params_ds_)
|
||||
.SetCollection(
|
||||
pxr::HdRetainedTypedSampledDataSource<pxr::HdRprimCollection>::New(collection))
|
||||
.SetRenderTags(
|
||||
pxr::HdRetainedTypedSampledDataSource<pxr::TfTokenVector>::New(render_tags))
|
||||
.Build();
|
||||
|
||||
task_scene_index_->AddPrims({{task_id_,
|
||||
pxr::HdPrimTypeTokens->task,
|
||||
pxr::HdRetainedContainerDataSource::New(
|
||||
pxr::HdLegacyTaskSchema::GetSchemaToken(), task_ds)}});
|
||||
}
|
||||
|
||||
void RenderTaskDelegate::dirty_task_params()
|
||||
{
|
||||
task_scene_index_->DirtyPrims({{task_id_, pxr::HdLegacyTaskSchema::GetParametersLocator()}});
|
||||
}
|
||||
|
||||
void RenderTaskDelegate::publish_buffer(pxr::SdfPath const &buf_id,
|
||||
pxr::HdRenderBufferDescriptor const &desc)
|
||||
{
|
||||
pxr::HdContainerDataSourceHandle buffer_ds =
|
||||
pxr::HdRenderBufferSchema::Builder()
|
||||
.SetDimensions(pxr::HdRetainedTypedSampledDataSource<pxr::GfVec3i>::New(desc.dimensions))
|
||||
.SetFormat(pxr::HdRetainedTypedSampledDataSource<pxr::HdFormat>::New(desc.format))
|
||||
.SetMultiSampled(pxr::HdRetainedTypedSampledDataSource<bool>::New(desc.multiSampled))
|
||||
.Build();
|
||||
|
||||
task_scene_index_->AddPrims({{buf_id,
|
||||
pxr::HdPrimTypeTokens->renderBuffer,
|
||||
pxr::HdRetainedContainerDataSource::New(
|
||||
pxr::HdRenderBufferSchema::GetSchemaToken(), buffer_ds)}});
|
||||
}
|
||||
|
||||
pxr::HdTaskSharedPtr RenderTaskDelegate::task()
|
||||
{
|
||||
return render_index_->GetTask(task_id_);
|
||||
}
|
||||
|
||||
void RenderTaskDelegate::set_camera(pxr::SdfPath const &camera_id)
|
||||
{
|
||||
if (task_params_.camera == camera_id) {
|
||||
return;
|
||||
}
|
||||
task_params_.camera = camera_id;
|
||||
dirty_task_params();
|
||||
}
|
||||
|
||||
bool RenderTaskDelegate::is_converged()
|
||||
{
|
||||
return static_cast<pxr::HdxRenderTask *>(task().get())->IsConverged();
|
||||
}
|
||||
|
||||
void RenderTaskDelegate::set_viewport(pxr::GfVec4d const &viewport)
|
||||
{
|
||||
if (task_params_.viewport == viewport) {
|
||||
return;
|
||||
}
|
||||
task_params_.viewport = viewport;
|
||||
dirty_task_params();
|
||||
|
||||
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);
|
||||
publish_buffer(it.first, it.second);
|
||||
task_scene_index_->DirtyPrims({{it.first, pxr::HdRenderBufferSchema::GetDimensionsLocator()}});
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
pxr::HdAovDescriptor aov_desc = render_index_->GetRenderDelegate()->GetDefaultAovDescriptor(
|
||||
aov_key);
|
||||
|
||||
if (aov_desc.format == pxr::HdFormatInvalid) {
|
||||
CLOG_ERROR(LOG_HYDRA_RENDER, "Invalid AOV: %s", aov_key.GetText());
|
||||
return;
|
||||
}
|
||||
if (!ELEM(
|
||||
pxr::HdGetComponentFormat(aov_desc.format), pxr::HdFormatFloat32, pxr::HdFormatFloat16))
|
||||
{
|
||||
CLOG_WARN(LOG_HYDRA_RENDER,
|
||||
"Unsupported data format %s for AOV %s",
|
||||
pxr::TfEnum::GetName(aov_desc.format).c_str(),
|
||||
aov_key.GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
int w = task_params_.viewport[2] - task_params_.viewport[0];
|
||||
int h = task_params_.viewport[3] - task_params_.viewport[1];
|
||||
pxr::HdRenderBufferDescriptor desc(
|
||||
pxr::GfVec3i(w, h, 1), aov_desc.format, aov_desc.multiSampled);
|
||||
buffer_descriptors_[buf_id] = desc;
|
||||
publish_buffer(buf_id, desc);
|
||||
|
||||
pxr::HdRenderPassAovBinding binding;
|
||||
binding.aovName = aov_key;
|
||||
binding.renderBufferId = buf_id;
|
||||
binding.aovSettings = aov_desc.aovSettings;
|
||||
binding.clearValue = aov_desc.clearValue;
|
||||
task_params_.aovBindings.push_back(binding);
|
||||
dirty_task_params();
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", aov_key.GetText());
|
||||
}
|
||||
|
||||
void RenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, void *data)
|
||||
{
|
||||
pxr::HdRenderBuffer *buffer = static_cast<pxr::HdRenderBuffer *>(
|
||||
render_index_->GetBprim(pxr::HdPrimTypeTokens->renderBuffer, buffer_id(aov_key)));
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
pxr::HdFormat format = buffer->GetFormat();
|
||||
size_t len = buffer->GetWidth() * buffer->GetHeight() * pxr::HdGetComponentCount(format);
|
||||
if (pxr::HdGetComponentFormat(format) == pxr::HdFormatFloat32) {
|
||||
void *buf_data = buffer->Map();
|
||||
memcpy(data, buf_data, len * sizeof(float));
|
||||
buffer->Unmap();
|
||||
}
|
||||
else if (pxr::HdGetComponentFormat(format) == pxr::HdFormatFloat16) {
|
||||
Eigen::half *buf_data = (Eigen::half *)buffer->Map();
|
||||
float *fdata = static_cast<float *>(data);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
fdata[i] = buf_data[i];
|
||||
}
|
||||
buffer->Unmap();
|
||||
}
|
||||
else {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
pxr::HdRenderBuffer *RenderTaskDelegate::get_aov_buffer(pxr::TfToken const &aov_key)
|
||||
{
|
||||
return (pxr::HdRenderBuffer *)render_index_->GetBprim(pxr::HdPrimTypeTokens->renderBuffer,
|
||||
buffer_id(aov_key));
|
||||
}
|
||||
|
||||
void RenderTaskDelegate::bind() {}
|
||||
|
||||
void RenderTaskDelegate::unbind() {}
|
||||
|
||||
pxr::SdfPath RenderTaskDelegate::buffer_id(pxr::TfToken const &aov_key) const
|
||||
{
|
||||
return base_id_.AppendElementString("aov_" + aov_key.GetString());
|
||||
}
|
||||
|
||||
GPURenderTaskDelegate::~GPURenderTaskDelegate()
|
||||
{
|
||||
unbind();
|
||||
if (tex_color_) {
|
||||
GPU_texture_free(tex_color_);
|
||||
}
|
||||
if (tex_depth_) {
|
||||
GPU_texture_free(tex_depth_);
|
||||
}
|
||||
}
|
||||
|
||||
void GPURenderTaskDelegate::set_viewport(pxr::GfVec4d const &viewport)
|
||||
{
|
||||
if (task_params_.viewport == viewport) {
|
||||
return;
|
||||
}
|
||||
task_params_.viewport = viewport;
|
||||
dirty_task_params();
|
||||
|
||||
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)
|
||||
{
|
||||
gpu::TextureFormat format;
|
||||
gpu::Texture **tex;
|
||||
if (aov_key == pxr::HdAovTokens->color) {
|
||||
format = gpu::TextureFormat::SFLOAT_32_32_32_32;
|
||||
tex = &tex_color_;
|
||||
}
|
||||
else if (aov_key == pxr::HdAovTokens->depth) {
|
||||
format = gpu::TextureFormat::SFLOAT_32_DEPTH;
|
||||
tex = &tex_depth_;
|
||||
}
|
||||
else {
|
||||
CLOG_ERROR(LOG_HYDRA_RENDER, "Invalid AOV: %s", aov_key.GetText());
|
||||
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);
|
||||
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", aov_key.GetText());
|
||||
}
|
||||
|
||||
void GPURenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, void *data)
|
||||
{
|
||||
gpu::Texture *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_delete_void(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_);
|
||||
|
||||
GPU_framebuffer_clear_color_depth(framebuffer_, {0.0, 0.0, 0.0, 0.0}, 1.0f);
|
||||
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
/* Workaround missing/buggy VAOs in hgiGL and hdSt. For OpenGL compatibility
|
||||
* profile this is not a problem, but for core profile it is. */
|
||||
if (VAO_ == 0 && GPU_backend_get_type() == GPU_BACKEND_OPENGL) {
|
||||
glGenVertexArrays(1, &VAO_);
|
||||
glBindVertexArray(VAO_);
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(VAO_);
|
||||
#endif
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "bind");
|
||||
}
|
||||
|
||||
void GPURenderTaskDelegate::unbind()
|
||||
{
|
||||
#ifdef WITH_OPENGL_BACKEND
|
||||
if (VAO_) {
|
||||
glDeleteVertexArrays(1, &VAO_);
|
||||
VAO_ = 0;
|
||||
}
|
||||
#endif
|
||||
if (framebuffer_) {
|
||||
GPU_framebuffer_free(framebuffer_);
|
||||
framebuffer_ = nullptr;
|
||||
}
|
||||
CLOG_DEBUG(LOG_HYDRA_RENDER, "unbind");
|
||||
}
|
||||
|
||||
gpu::Texture *GPURenderTaskDelegate::get_aov_texture(pxr::TfToken const &aov_key)
|
||||
{
|
||||
if (aov_key == pxr::HdAovTokens->color) {
|
||||
return tex_color_;
|
||||
}
|
||||
if (aov_key == pxr::HdAovTokens->depth) {
|
||||
return tex_depth_;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
@@ -0,0 +1,97 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pxr/imaging/hd/dataSource.h>
|
||||
#include <pxr/imaging/hd/renderIndex.h>
|
||||
#include <pxr/imaging/hd/retainedSceneIndex.h>
|
||||
#include <pxr/imaging/hd/task.h>
|
||||
#include <pxr/imaging/hdx/renderSetupTask.h>
|
||||
|
||||
#include "GPU_framebuffer.hh"
|
||||
#include "GPU_texture.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
/* Registers a HdxRenderTask with the render index as a task prim. */
|
||||
|
||||
class RenderTaskParamsDataSource final
|
||||
: public pxr::HdTypedSampledDataSource<pxr::HdxRenderTaskParams> {
|
||||
public:
|
||||
HD_DECLARE_DATASOURCE(RenderTaskParamsDataSource);
|
||||
|
||||
pxr::HdxRenderTaskParams params;
|
||||
|
||||
pxr::VtValue GetValue(Time /*shutterOffset*/) override
|
||||
{
|
||||
return pxr::VtValue(params);
|
||||
}
|
||||
pxr::HdxRenderTaskParams GetTypedValue(Time /*shutterOffset*/) override
|
||||
{
|
||||
return params;
|
||||
}
|
||||
bool GetContributingSampleTimesForInterval(Time /*start*/,
|
||||
Time /*end*/,
|
||||
std::vector<Time> * /*sampleTimes*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class RenderTaskDelegate {
|
||||
protected:
|
||||
pxr::HdRenderIndex *render_index_ = nullptr;
|
||||
pxr::HdRetainedSceneIndexRefPtr task_scene_index_;
|
||||
pxr::SdfPath base_id_;
|
||||
pxr::SdfPath task_id_;
|
||||
RenderTaskParamsDataSource::Handle task_params_ds_ = RenderTaskParamsDataSource::New();
|
||||
pxr::HdxRenderTaskParams &task_params_ = task_params_ds_->params;
|
||||
pxr::TfHashMap<pxr::SdfPath, pxr::HdRenderBufferDescriptor, pxr::SdfPath::Hash>
|
||||
buffer_descriptors_;
|
||||
|
||||
public:
|
||||
RenderTaskDelegate(pxr::HdRenderIndex *render_index,
|
||||
pxr::HdRetainedSceneIndexRefPtr task_scene_index,
|
||||
pxr::SdfPath const &base_id);
|
||||
virtual ~RenderTaskDelegate() = default;
|
||||
|
||||
pxr::HdTaskSharedPtr task();
|
||||
void set_camera(pxr::SdfPath const &camera_id);
|
||||
bool is_converged();
|
||||
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);
|
||||
pxr::HdRenderBuffer *get_aov_buffer(pxr::TfToken const &aov_key);
|
||||
virtual void bind();
|
||||
virtual void unbind();
|
||||
|
||||
protected:
|
||||
pxr::SdfPath buffer_id(pxr::TfToken const &aov_key) const;
|
||||
|
||||
void publish_task();
|
||||
void dirty_task_params();
|
||||
void publish_buffer(pxr::SdfPath const &buf_id, pxr::HdRenderBufferDescriptor const &desc);
|
||||
};
|
||||
|
||||
class GPURenderTaskDelegate : public RenderTaskDelegate {
|
||||
private:
|
||||
gpu::FrameBuffer *framebuffer_ = nullptr;
|
||||
gpu::Texture *tex_color_ = nullptr;
|
||||
gpu::Texture *tex_depth_ = nullptr;
|
||||
unsigned int VAO_ = 0;
|
||||
|
||||
public:
|
||||
using RenderTaskDelegate::RenderTaskDelegate;
|
||||
~GPURenderTaskDelegate() override;
|
||||
|
||||
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 bind() override;
|
||||
void unbind() override;
|
||||
gpu::Texture *get_aov_texture(pxr::TfToken const &aov_key);
|
||||
};
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
306
blender-5.2.0/source/blender/render/hydra/viewport_engine.cc
Normal file
306
blender-5.2.0/source/blender/render/hydra/viewport_engine.cc
Normal file
@@ -0,0 +1,306 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "viewport_engine.hh"
|
||||
#include "camera.hh"
|
||||
|
||||
#include <pxr/base/gf/camera.h>
|
||||
#include <pxr/imaging/glf/drawTarget.h>
|
||||
#include <pxr/usd/usdGeom/camera.h>
|
||||
|
||||
#include "DNA_camera_types.h"
|
||||
#include "DNA_scene_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 "DNA_view3d_types.h"
|
||||
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_time.h"
|
||||
#include "BLI_timecode.h"
|
||||
|
||||
#include "BKE_camera.h"
|
||||
#include "BKE_context.hh"
|
||||
|
||||
#include "GPU_matrix.hh"
|
||||
#include "GPU_texture.hh"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "RE_engine.h"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
struct ViewSettings {
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
pxr::GfVec4i border;
|
||||
pxr::GfCamera camera;
|
||||
|
||||
ViewSettings(bContext *context);
|
||||
|
||||
int width();
|
||||
int height();
|
||||
};
|
||||
|
||||
ViewSettings::ViewSettings(bContext *context)
|
||||
{
|
||||
View3D *view3d = CTX_wm_view3d(context);
|
||||
RegionView3D *region_data = static_cast<RegionView3D *>(CTX_wm_region_data(context));
|
||||
ARegion *region = CTX_wm_region(context);
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(context);
|
||||
Scene *scene = DEG_get_evaluated_scene(depsgraph);
|
||||
|
||||
screen_width = region->winx;
|
||||
screen_height = region->winy;
|
||||
|
||||
/* Getting render border. */
|
||||
int x1 = 0, y1 = 0;
|
||||
int x2 = screen_width, y2 = screen_height;
|
||||
|
||||
if (region_data->persp == RV3D_CAMOB) {
|
||||
Object *camera_obj = scene->camera;
|
||||
if ((scene->r.mode & R_BORDER) && camera_obj && camera_obj->type == OB_CAMERA) {
|
||||
float camera_points[4][3];
|
||||
BKE_camera_view_frame(scene, id_cast<Camera *>(camera_obj->data), camera_points);
|
||||
|
||||
float screen_points[4][2];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
float world_location[] = {
|
||||
camera_points[i][0], camera_points[i][1], camera_points[i][2], 1.0f};
|
||||
mul_m4_v4(camera_obj->object_to_world().ptr(), world_location);
|
||||
mul_m4_v4(region_data->persmat, world_location);
|
||||
|
||||
if (world_location[3] > 0.0) {
|
||||
screen_points[i][0] = screen_width * 0.5f +
|
||||
screen_width * 0.5f * (world_location[0] / world_location[3]);
|
||||
screen_points[i][1] = screen_height * 0.5f +
|
||||
screen_height * 0.5f * (world_location[1] / world_location[3]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Getting camera view region. */
|
||||
float x1_f = std::min(
|
||||
{screen_points[0][0], screen_points[1][0], screen_points[2][0], screen_points[3][0]});
|
||||
float x2_f = std::max(
|
||||
{screen_points[0][0], screen_points[1][0], screen_points[2][0], screen_points[3][0]});
|
||||
float y1_f = std::min(
|
||||
{screen_points[0][1], screen_points[1][1], screen_points[2][1], screen_points[3][1]});
|
||||
float y2_f = std::max(
|
||||
{screen_points[0][1], screen_points[1][1], screen_points[2][1], screen_points[3][1]});
|
||||
|
||||
/* Adjusting region to border. */
|
||||
float x = x1_f, y = y1_f;
|
||||
float dx = x2_f - x1_f, dy = y2_f - y1_f;
|
||||
|
||||
x1 = x + scene->r.border.xmin * dx;
|
||||
x2 = x + scene->r.border.xmax * dx;
|
||||
y1 = y + scene->r.border.ymin * dy;
|
||||
y2 = y + scene->r.border.ymax * dy;
|
||||
|
||||
/* Adjusting to region screen resolution. */
|
||||
x1 = std::max(std::min(x1, screen_width), 0);
|
||||
x2 = std::max(std::min(x2, screen_width), 0);
|
||||
y1 = std::max(std::min(y1, screen_height), 0);
|
||||
y2 = std::max(std::min(y2, screen_height), 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (view3d->flag2 & V3D_RENDER_BORDER) {
|
||||
x1 = view3d->render_border.xmin * screen_width;
|
||||
x2 = view3d->render_border.xmax * screen_width;
|
||||
y1 = view3d->render_border.ymin * screen_height;
|
||||
y2 = view3d->render_border.ymax * screen_height;
|
||||
}
|
||||
}
|
||||
|
||||
border = pxr::GfVec4i(x1, y1, x2, y2);
|
||||
|
||||
camera = gf_camera(depsgraph,
|
||||
view3d,
|
||||
region,
|
||||
pxr::GfVec4f(float(border[0]) / screen_width,
|
||||
float(border[1]) / screen_height,
|
||||
float(width()) / screen_width,
|
||||
float(height()) / screen_height));
|
||||
}
|
||||
|
||||
int ViewSettings::width()
|
||||
{
|
||||
return border[2] - border[0];
|
||||
}
|
||||
|
||||
int ViewSettings::height()
|
||||
{
|
||||
return border[3] - border[1];
|
||||
}
|
||||
|
||||
DrawTexture::DrawTexture()
|
||||
{
|
||||
float coords[8] = {0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0};
|
||||
|
||||
GPUVertFormat format = {0};
|
||||
GPU_vertformat_attr_add(&format, "pos", gpu::VertAttrType::SFLOAT_32_32);
|
||||
GPU_vertformat_attr_add(&format, "texCoord", gpu::VertAttrType::SFLOAT_32_32);
|
||||
gpu::VertBuf *vbo = GPU_vertbuf_create_with_format(format);
|
||||
GPU_vertbuf_data_alloc(*vbo, 4);
|
||||
GPU_vertbuf_attr_fill(vbo, 0, coords);
|
||||
GPU_vertbuf_attr_fill(vbo, 1, coords);
|
||||
|
||||
batch_ = GPU_batch_create_ex(GPU_PRIM_TRI_FAN, vbo, nullptr, GPU_BATCH_OWNS_VBO);
|
||||
}
|
||||
|
||||
DrawTexture::~DrawTexture()
|
||||
{
|
||||
if (texture_) {
|
||||
GPU_texture_free(texture_);
|
||||
}
|
||||
GPU_batch_discard(batch_);
|
||||
}
|
||||
|
||||
void DrawTexture::create_from_buffer(pxr::HdRenderBuffer *buffer)
|
||||
{
|
||||
if (buffer == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::TextureFormat texture_format;
|
||||
eGPUDataFormat data_format;
|
||||
|
||||
if (buffer->GetFormat() == pxr::HdFormat::HdFormatFloat16Vec4) {
|
||||
texture_format = gpu::TextureFormat::SFLOAT_16_16_16_16;
|
||||
data_format = GPU_DATA_HALF_FLOAT;
|
||||
}
|
||||
else {
|
||||
texture_format = gpu::TextureFormat::SFLOAT_32_32_32_32;
|
||||
data_format = GPU_DATA_FLOAT;
|
||||
}
|
||||
|
||||
if (texture_ && (GPU_texture_width(texture_) != buffer->GetWidth() ||
|
||||
GPU_texture_height(texture_) != buffer->GetHeight() ||
|
||||
GPU_texture_format(texture_) != texture_format))
|
||||
{
|
||||
GPU_texture_free(texture_);
|
||||
texture_ = nullptr;
|
||||
}
|
||||
|
||||
if (texture_ == nullptr) {
|
||||
texture_ = GPU_texture_create_2d("tex_hydra_render_viewport",
|
||||
buffer->GetWidth(),
|
||||
buffer->GetHeight(),
|
||||
1,
|
||||
texture_format,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void *data = buffer->Map();
|
||||
GPU_texture_update(texture_, data_format, data);
|
||||
buffer->Unmap();
|
||||
}
|
||||
|
||||
void DrawTexture::draw(gpu::Shader *shader, const pxr::GfVec4d &viewport, gpu::Texture *tex)
|
||||
{
|
||||
if (!tex) {
|
||||
tex = texture_;
|
||||
}
|
||||
int slot = GPU_shader_get_sampler_binding(shader, "image");
|
||||
GPU_texture_bind(tex, slot);
|
||||
GPU_shader_uniform_1i(shader, "image", slot);
|
||||
|
||||
GPU_matrix_push();
|
||||
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();
|
||||
}
|
||||
|
||||
gpu::Texture *DrawTexture::texture() const
|
||||
{
|
||||
return texture_;
|
||||
}
|
||||
|
||||
void ViewportEngine::render()
|
||||
{
|
||||
ViewSettings view_settings(context_);
|
||||
if (view_settings.width() * view_settings.height() == 0) {
|
||||
return;
|
||||
};
|
||||
|
||||
free_camera_delegate_->SetCamera(view_settings.camera);
|
||||
|
||||
pxr::GfVec4d viewport(0.0, 0.0, view_settings.width(), view_settings.height());
|
||||
render_task_delegate_->set_viewport(viewport);
|
||||
if (light_tasks_delegate_) {
|
||||
light_tasks_delegate_->set_viewport(viewport);
|
||||
}
|
||||
|
||||
render_task_delegate_->add_aov(pxr::HdAovTokens->color);
|
||||
render_task_delegate_->add_aov(pxr::HdAovTokens->depth);
|
||||
|
||||
gpu::FrameBuffer *view_framebuffer = GPU_framebuffer_active_get();
|
||||
render_task_delegate_->bind();
|
||||
|
||||
auto t = tasks();
|
||||
engine_->Execute(render_index_.get(), &t);
|
||||
|
||||
render_task_delegate_->unbind();
|
||||
|
||||
GPU_framebuffer_bind(view_framebuffer);
|
||||
gpu::Shader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_IMAGE);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
pxr::GfVec4d draw_viewport(view_settings.border[0],
|
||||
view_settings.border[1],
|
||||
view_settings.border[2],
|
||||
view_settings.border[3]);
|
||||
GPURenderTaskDelegate *gpu_task = dynamic_cast<GPURenderTaskDelegate *>(
|
||||
render_task_delegate_.get());
|
||||
if (gpu_task) {
|
||||
draw_texture_.draw(shader, draw_viewport, gpu_task->get_aov_texture(pxr::HdAovTokens->color));
|
||||
}
|
||||
else {
|
||||
draw_texture_.create_from_buffer(
|
||||
render_task_delegate_->get_aov_buffer(pxr::HdAovTokens->color));
|
||||
draw_texture_.draw(shader, draw_viewport);
|
||||
}
|
||||
|
||||
GPU_shader_unbind();
|
||||
|
||||
if (renderer_percent_done() == 0.0f) {
|
||||
time_begin_ = BLI_time_now_seconds();
|
||||
}
|
||||
|
||||
char elapsed_time[32];
|
||||
|
||||
BLI_timecode_string_from_time_simple(
|
||||
elapsed_time, sizeof(elapsed_time), BLI_time_now_seconds() - time_begin_);
|
||||
|
||||
float percent_done = renderer_percent_done();
|
||||
if (!render_task_delegate_->is_converged()) {
|
||||
notify_status(percent_done / 100.0,
|
||||
std ::string("Time: ") + elapsed_time +
|
||||
" | Done: " + std::to_string(int(percent_done)) + "%",
|
||||
"Render");
|
||||
bl_engine_->flag |= RE_ENGINE_DO_DRAW;
|
||||
}
|
||||
else {
|
||||
notify_status(percent_done / 100.0, std::string("Time: ") + elapsed_time, "Rendering Done");
|
||||
}
|
||||
}
|
||||
|
||||
void ViewportEngine::render(bContext *context)
|
||||
{
|
||||
context_ = context;
|
||||
render();
|
||||
}
|
||||
|
||||
void ViewportEngine::notify_status(float /*progress*/,
|
||||
const std::string &info,
|
||||
const std::string &status)
|
||||
{
|
||||
RE_engine_update_stats(bl_engine_, status.c_str(), info.c_str());
|
||||
}
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
48
blender-5.2.0/source/blender/render/hydra/viewport_engine.hh
Normal file
48
blender-5.2.0/source/blender/render/hydra/viewport_engine.hh
Normal file
@@ -0,0 +1,48 @@
|
||||
/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <pxr/imaging/hd/renderBuffer.h>
|
||||
|
||||
#include "GPU_batch.hh"
|
||||
#include "GPU_shader.hh"
|
||||
#include "GPU_texture.hh"
|
||||
|
||||
#include "engine.hh"
|
||||
|
||||
namespace blender::render::hydra {
|
||||
|
||||
class DrawTexture {
|
||||
private:
|
||||
gpu::Texture *texture_ = nullptr;
|
||||
gpu::Batch *batch_;
|
||||
|
||||
public:
|
||||
DrawTexture();
|
||||
~DrawTexture();
|
||||
|
||||
void create_from_buffer(pxr::HdRenderBuffer *buffer);
|
||||
void draw(gpu::Shader *shader, const pxr::GfVec4d &viewport, gpu::Texture *tex = nullptr);
|
||||
gpu::Texture *texture() const;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class ViewportEngine : public Engine {
|
||||
private:
|
||||
double time_begin_;
|
||||
DrawTexture draw_texture_;
|
||||
|
||||
public:
|
||||
using Engine::Engine;
|
||||
|
||||
void render() override;
|
||||
void render(bContext *context);
|
||||
|
||||
protected:
|
||||
void notify_status(float progress, const std::string &info, const std::string &status) override;
|
||||
};
|
||||
|
||||
} // namespace blender::render::hydra
|
||||
Reference in New Issue
Block a user