Hydra render engine #104712

Closed
Bogdan Nagirniak wants to merge 142 commits from BogdanNagirniak/blender:hydra-render into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
10 changed files with 154 additions and 14 deletions
Showing only changes of commit 1a8674f175 - Show all commits

View File

@ -50,6 +50,8 @@ set(SRC
engine.cpp
finalEngine.h
finalEngine.cpp
finalEngineGL.h
finalEngineGL.cpp
viewportEngine.h
viewportEngine.cpp

View File

@ -37,12 +37,14 @@ class HydraRenderEngine(bpy.types.RenderEngine):
engine_type = 'PREVIEW' if self.is_preview else 'FINAL'
log("update", self, engine_type)
def render(self, depsgraph):
engine_type = 'PREVIEW' if self.is_preview else 'FINAL'
log("render", self, engine_type)
self.engine_ptr = _usdhydra.engine.create(self.as_pointer(), engine_type, self.delegate_id)
delegate_settings = self.get_delegate_settings(engine_type)
_usdhydra.engine.sync(self.engine_ptr, depsgraph.as_pointer(), bpy.context.as_pointer(), delegate_settings)
def render(self, depsgraph):
log("render", self)
_usdhydra.engine.sync(self.engine_ptr, depsgraph.as_pointer(), bpy.context.as_pointer(), delegate_settings)
_usdhydra.engine.render(self.engine_ptr, depsgraph.as_pointer())
# viewport render

View File

@ -12,6 +12,7 @@
#include "engine.h"
#include "finalEngine.h"
#include "finalEngineGL.h"
#include "viewportEngine.h"
using namespace pxr;
@ -41,6 +42,8 @@ Engine::Engine(BL::RenderEngine &b_engine, const std::string &delegateId)
renderIndex.get(), SdfPath::AbsoluteRootPath().AppendElementString("freeCamera"));
renderTaskDelegate = std::make_unique<RenderTaskDelegate>(
renderIndex.get(), SdfPath::AbsoluteRootPath().AppendElementString("renderTask"));
engine = std::make_unique<HdEngine>();
}
Engine::~Engine()
@ -50,6 +53,8 @@ Engine::~Engine()
freeCameraDelegate = nullptr;
renderIndex = nullptr;
renderDelegate = nullptr;
engine = nullptr;
hgi = nullptr;
}
float Engine::getRendererPercentDone()
@ -85,7 +90,12 @@ static PyObject *create_func(PyObject * /*self*/, PyObject *args)
engine = new ViewportEngine(b_engine, delegateId);
}
else {
engine = new FinalEngine(b_engine, delegateId);
if (b_engine.bl_use_gpu_context()) {
engine = new FinalEngineGL(b_engine, delegateId);
}
else {
engine = new FinalEngine(b_engine, delegateId);
}
}
return PyLong_FromVoidPtr(engine);

View File

@ -39,7 +39,7 @@ protected:
std::unique_ptr<BlenderSceneDelegate> sceneDelegate;
std::unique_ptr<RenderTaskDelegate> renderTaskDelegate;
std::unique_ptr<HdxFreeCameraSceneDelegate> freeCameraDelegate;
HdEngine engine;
std::unique_ptr<HdEngine> engine;
HgiUniquePtr hgi;
// Similar for HdDriver.

View File

@ -22,7 +22,7 @@ namespace usdhydra {
void FinalEngine::sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, pxr::HdRenderSettingsMap &renderSettings)
{
sceneDelegate = std::make_unique<BlenderSceneDelegate>(renderIndex.get(),
SdfPath::AbsoluteRootPath().AppendElementString("blenderScene"), b_depsgraph);
SdfPath::AbsoluteRootPath().AppendElementString("scene"), b_depsgraph);
sceneDelegate->Populate();
for (auto const& setting : renderSettings) {
@ -55,7 +55,7 @@ void FinalEngine::render(BL::Depsgraph &b_depsgraph)
{
// Release the GIL before calling into hydra, in case any hydra plugins call into python.
TF_PY_ALLOW_THREADS_IN_SCOPE();
engine.Execute(renderIndex.get(), &tasks);
engine->Execute(renderIndex.get(), &tasks);
}
while (true) {

View File

@ -13,12 +13,15 @@ class FinalEngine : public Engine {
public:
using Engine::Engine;
void sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, pxr::HdRenderSettingsMap &renderSettings) override;
void render(BL::Depsgraph &b_depsgraph);
virtual void render(BL::Depsgraph &b_depsgraph);
private:
protected:
void getResolution(BL::RenderSettings b_render, int &width, int &height);
void updateRenderResult(std::map<std::string, std::vector<float>> &render_images, const std::string &layerName, int width, int height);
void notifyStatus(float progress, const std::string &title, const std::string &info);
protected:
HdRenderSettingsMap renderSettings;
};
} // namespace usdhydra

99
extern/usdhydra/finalEngineGL.cpp vendored Normal file
View File

@ -0,0 +1,99 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#include <memory>
#include <pxr/imaging/hd/engine.h>
#include <pxr/imaging/hdx/freeCameraSceneDelegate.h>
#include <pxr/imaging/glf/drawTarget.h>
#include <pxr/usdImaging/usdAppUtils/camera.h>
#include "glog/logging.h"
#include "finalEngineGL.h"
#include "utils.h"
#include "sceneDelegate/scene.h"
using namespace std;
using namespace pxr;
namespace usdhydra {
void FinalEngineGL::render(BL::Depsgraph& b_depsgraph)
{
SceneExport sceneExport(b_depsgraph);
auto resolution = sceneExport.resolution();
int width = resolution.first, height = resolution.second;
GfCamera gfCamera = sceneExport.gfCamera();
freeCameraDelegate->SetCamera(gfCamera);
renderTaskDelegate->SetCameraAndViewport(freeCameraDelegate->GetCameraId(), GfVec4d(0, 0, width, height));
HdTaskSharedPtrVector tasks = renderTaskDelegate->GetTasks();
chrono::time_point<chrono::steady_clock> timeBegin = chrono::steady_clock::now(), timeCurrent;
chrono::milliseconds elapsedTime;
float percentDone = 0.0;
string sceneName = sceneExport.sceneName(), layerName = sceneExport.layerName();
map<string, vector<float>> renderImages{{"Combined", vector<float>(width * height * 4)}}; // 4 - number of channels
vector<float> &pixels = renderImages["Combined"];
GLuint FramebufferName = 0;
glGenFramebuffers(1, &FramebufferName);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferName);
// The texture we're going to render to
GLuint renderedTexture;
glGenTextures(1, &renderedTexture);
// "Bind" the newly created texture : all future texture functions will modify this texture
glBindTexture(GL_TEXTURE_2D, renderedTexture);
// Give an empty image to OpenGL ( the last "0" )
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, 0);
// Poor filtering. Needed !
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// Set "renderedTexture" as our colour attachement #0
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, renderedTexture, 0);
// Generate vertex array
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
{
// Release the GIL before calling into hydra, in case any hydra plugins call into python.
TF_PY_ALLOW_THREADS_IN_SCOPE();
engine->Execute(renderIndex.get(), &tasks);
}
while (true) {
if (b_engine.test_break()) {
break;
}
percentDone = getRendererPercentDone();
timeCurrent = chrono::steady_clock::now();
elapsedTime = chrono::duration_cast<chrono::milliseconds>(timeCurrent - timeBegin);
notifyStatus(percentDone / 100.0, sceneName + ": " + layerName,
"Render Time: " + formatDuration(elapsedTime) + " | Done: " + to_string(int(percentDone)) + "%");
if (renderTaskDelegate->IsConverged()) {
break;
}
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixels.data());
updateRenderResult(renderImages, layerName, width, height);
}
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, pixels.data());
updateRenderResult(renderImages, layerName, width, height);
}
} // namespace usdhydra

17
extern/usdhydra/finalEngineGL.h vendored Normal file
View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: Apache-2.0
* Copyright 2011-2022 Blender Foundation */
#pragma once
#include "finalEngine.h"
#include "finalEngineGL.h"
namespace usdhydra {
class FinalEngineGL : public FinalEngine {
public:
using FinalEngine::FinalEngine;
void render(BL::Depsgraph& b_depsgraph) override;
};
} // namespace usdhydra

View File

@ -39,14 +39,21 @@ std::string MaterialExport::name()
SdfAssetPath MaterialExport::exportMX()
{
PyObject *module, *dict, *func, *params, *result;
module = PyImport_Import(PyUnicode_FromString("usdhydra.matx"));
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
module = PyImport_ImportModule("usdhydra.matx");
dict = PyModule_GetDict(module);
func = PyDict_GetItemString(dict, "export");
params = Py_BuildValue("(s)", name().c_str());
result = PyObject_CallObject(func, params);
std::string path = PyUnicode_AsUTF8(result);
return SdfAssetPath(path, path);
PyGILState_Release(gstate);
return SdfAssetPath(path, path);
}
} // namespace usdhydra

View File

@ -544,7 +544,7 @@ void ViewportEngine::sync(BL::Depsgraph &b_depsgraph, BL::Context &b_context, px
sceneDelegate = std::make_unique<BlenderSceneDelegate>(renderIndex.get(),
SdfPath::AbsoluteRootPath().AppendElementString("scene"), b_depsgraph);
}
sceneDelegate->Populate();
for (auto const& setting : renderSettings) {
renderDelegate->SetRenderSetting(setting.first, setting.second);
@ -580,14 +580,14 @@ void ViewportEngine::viewDraw(BL::Depsgraph &b_depsgraph, BL::Context &b_context
{
// Release the GIL before calling into hydra, in case any hydra plugins call into python.
TF_PY_ALLOW_THREADS_IN_SCOPE();
engine.Execute(renderIndex.get(), &tasks);
engine->Execute(renderIndex.get(), &tasks);
if (!b_engine.bl_use_gpu_context()) {
texture.setBuffer(renderTaskDelegate->GetRendererAov(HdAovTokens->color));
texture.draw((GLfloat)viewSettings.border[0][0], (GLfloat)viewSettings.border[0][1]);
}
}
b_engine.unbind_display_space_shader();
chrono::time_point<chrono::steady_clock> timeCurrent = chrono::steady_clock::now();