Blender V5.0
render_task_delegate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include <epoxy/gl.h>
8
9#include "GPU_context.hh"
10
11#include <pxr/imaging/hd/renderBuffer.h>
12#include <pxr/imaging/hd/renderDelegate.h>
13#include <pxr/imaging/hdx/renderTask.h>
14
15#include "MEM_guardedalloc.h"
16
17#include <Eigen/Core>
18
19#include "engine.hh"
20
21namespace blender::render::hydra {
22
23RenderTaskDelegate::RenderTaskDelegate(pxr::HdRenderIndex *parent_index,
24 pxr::SdfPath const &delegate_id)
25 : pxr::HdSceneDelegate(parent_index, delegate_id)
26{
27 task_id_ = GetDelegateID().AppendElementString("task");
28 GetRenderIndex().InsertTask<pxr::HdxRenderTask>(this, task_id_);
29
30 task_params_.enableLighting = true;
31 task_params_.alphaThreshold = 0.1f;
32
33 /* Disable this so Metal and OpenGL match in Storm render tests, only
34 * the former seems to use multisample. */
35 task_params_.useAovMultiSample = false;
36
37 CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", task_id_.GetText());
38}
39
40pxr::VtValue RenderTaskDelegate::Get(pxr::SdfPath const &id, pxr::TfToken const &key)
41{
42 CLOG_DEBUG(LOG_HYDRA_RENDER, "%s, %s", id.GetText(), key.GetText());
43
44 if (key == pxr::HdTokens->params) {
45 return pxr::VtValue(task_params_);
46 }
47 if (key == pxr::HdTokens->collection) {
48 return pxr::VtValue(pxr::HdRprimCollection(
49 pxr::HdTokens->geometry, pxr::HdReprSelector(pxr::HdReprTokens->smoothHull)));
50 }
51 return pxr::VtValue();
52}
53
54pxr::TfTokenVector RenderTaskDelegate::GetTaskRenderTags(pxr::SdfPath const &id)
55{
56 CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", id.GetText());
57
58 return {pxr::HdRenderTagTokens->geometry};
59}
60
61pxr::HdRenderBufferDescriptor RenderTaskDelegate::GetRenderBufferDescriptor(pxr::SdfPath const &id)
62{
63 CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", id.GetText());
64
65 return buffer_descriptors_[id];
66}
67
68pxr::HdTaskSharedPtr RenderTaskDelegate::task()
69{
70 return GetRenderIndex().GetTask(task_id_);
71}
72
73void RenderTaskDelegate::set_camera(pxr::SdfPath const &camera_id)
74{
75 if (task_params_.camera == camera_id) {
76 return;
77 }
78 task_params_.camera = camera_id;
79 GetRenderIndex().GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
80}
81
83{
84 return static_cast<pxr::HdxRenderTask *>(task().get())->IsConverged();
85}
86
87void RenderTaskDelegate::set_viewport(pxr::GfVec4d const &viewport)
88{
89 if (task_params_.viewport == viewport) {
90 return;
91 }
92 auto &render_index = GetRenderIndex();
93 task_params_.viewport = viewport;
94 render_index.GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
95
96 int w = viewport[2] - viewport[0];
97 int h = viewport[3] - viewport[1];
98 for (auto &it : buffer_descriptors_) {
99 it.second.dimensions = pxr::GfVec3i(w, h, 1);
100 render_index.GetChangeTracker().MarkBprimDirty(it.first,
101 pxr::HdRenderBuffer::DirtyDescription);
102 }
103}
104
105void RenderTaskDelegate::add_aov(pxr::TfToken const &aov_key)
106{
107 pxr::SdfPath buf_id = buffer_id(aov_key);
108 if (buffer_descriptors_.find(buf_id) != buffer_descriptors_.end()) {
109 return;
110 }
111 auto &render_index = GetRenderIndex();
112 pxr::HdAovDescriptor aov_desc = render_index.GetRenderDelegate()->GetDefaultAovDescriptor(
113 aov_key);
114
115 if (aov_desc.format == pxr::HdFormatInvalid) {
116 CLOG_ERROR(LOG_HYDRA_RENDER, "Invalid AOV: %s", aov_key.GetText());
117 return;
118 }
119 if (!ELEM(
120 pxr::HdGetComponentFormat(aov_desc.format), pxr::HdFormatFloat32, pxr::HdFormatFloat16))
121 {
123 "Unsupported data format %s for AOV %s",
124 pxr::TfEnum::GetName(aov_desc.format).c_str(),
125 aov_key.GetText());
126 return;
127 }
128
129 int w = task_params_.viewport[2] - task_params_.viewport[0];
130 int h = task_params_.viewport[3] - task_params_.viewport[1];
131 render_index.InsertBprim(pxr::HdPrimTypeTokens->renderBuffer, this, buf_id);
132 buffer_descriptors_[buf_id] = pxr::HdRenderBufferDescriptor(
133 pxr::GfVec3i(w, h, 1), aov_desc.format, aov_desc.multiSampled);
134
135 pxr::HdRenderPassAovBinding binding;
136 binding.aovName = aov_key;
137 binding.renderBufferId = buf_id;
138 binding.aovSettings = aov_desc.aovSettings;
139 binding.clearValue = aov_desc.clearValue;
140 task_params_.aovBindings.push_back(binding);
141 render_index.GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
142
143 CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", aov_key.GetText());
144}
145
146void RenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, void *data)
147{
148 pxr::HdRenderBuffer *buffer = static_cast<pxr::HdRenderBuffer *>(
149 GetRenderIndex().GetBprim(pxr::HdPrimTypeTokens->renderBuffer, buffer_id(aov_key)));
150 if (!buffer) {
151 return;
152 }
153
154 pxr::HdFormat format = buffer->GetFormat();
155 size_t len = buffer->GetWidth() * buffer->GetHeight() * pxr::HdGetComponentCount(format);
156 if (pxr::HdGetComponentFormat(format) == pxr::HdFormatFloat32) {
157 void *buf_data = buffer->Map();
158 memcpy(data, buf_data, len * sizeof(float));
159 buffer->Unmap();
160 }
161 else if (pxr::HdGetComponentFormat(format) == pxr::HdFormatFloat16) {
162 Eigen::half *buf_data = (Eigen::half *)buffer->Map();
163 float *fdata = (float *)data;
164 for (size_t i = 0; i < len; ++i) {
165 fdata[i] = buf_data[i];
166 }
167 buffer->Unmap();
168 }
169 else {
171 }
172}
173
174pxr::HdRenderBuffer *RenderTaskDelegate::get_aov_buffer(pxr::TfToken const &aov_key)
175{
176 return (pxr::HdRenderBuffer *)GetRenderIndex().GetBprim(pxr::HdPrimTypeTokens->renderBuffer,
177 buffer_id(aov_key));
178}
179
181
183
184pxr::SdfPath RenderTaskDelegate::buffer_id(pxr::TfToken const &aov_key) const
185{
186 return GetDelegateID().AppendElementString("aov_" + aov_key.GetString());
187}
188
190{
191 unbind();
192 if (tex_color_) {
193 GPU_texture_free(tex_color_);
194 }
195 if (tex_depth_) {
196 GPU_texture_free(tex_depth_);
197 }
198}
199
200void GPURenderTaskDelegate::set_viewport(pxr::GfVec4d const &viewport)
201{
202 if (task_params_.viewport == viewport) {
203 return;
204 }
205 auto &render_index = GetRenderIndex();
206 task_params_.viewport = viewport;
207 render_index.GetChangeTracker().MarkTaskDirty(task_id_, pxr::HdChangeTracker::DirtyParams);
208
209 if (tex_color_) {
210 GPU_texture_free(tex_color_);
211 tex_color_ = nullptr;
212 add_aov(pxr::HdAovTokens->color);
213 }
214 if (tex_depth_) {
215 GPU_texture_free(tex_depth_);
216 tex_depth_ = nullptr;
217 add_aov(pxr::HdAovTokens->depth);
218 }
219}
220
221void GPURenderTaskDelegate::add_aov(pxr::TfToken const &aov_key)
222{
225 if (aov_key == pxr::HdAovTokens->color) {
226 format = blender::gpu::TextureFormat::SFLOAT_32_32_32_32;
227 tex = &tex_color_;
228 }
229 else if (aov_key == pxr::HdAovTokens->depth) {
230 format = blender::gpu::TextureFormat::SFLOAT_32_DEPTH;
231 tex = &tex_depth_;
232 }
233 else {
234 CLOG_ERROR(LOG_HYDRA_RENDER, "Invalid AOV: %s", aov_key.GetText());
235 return;
236 }
237
238 if (*tex) {
239 return;
240 }
241
242 *tex = GPU_texture_create_2d(("tex_render_hydra_" + aov_key.GetString()).c_str(),
243 task_params_.viewport[2] - task_params_.viewport[0],
244 task_params_.viewport[3] - task_params_.viewport[1],
245 1,
246 format,
248 nullptr);
249
250 CLOG_DEBUG(LOG_HYDRA_RENDER, "%s", aov_key.GetText());
251}
252
253void GPURenderTaskDelegate::read_aov(pxr::TfToken const &aov_key, void *data)
254{
255 blender::gpu::Texture *tex = nullptr;
256 int c;
257 if (aov_key == pxr::HdAovTokens->color) {
258 tex = tex_color_;
259 c = 4;
260 }
261 else if (aov_key == pxr::HdAovTokens->depth) {
262 tex = tex_depth_;
263 c = 1;
264 }
265 if (!tex) {
266 return;
267 }
268
269 int w = GPU_texture_width(tex), h = GPU_texture_height(tex);
270 void *tex_data = GPU_texture_read(tex, GPU_DATA_FLOAT, 0);
271 memcpy(data, tex_data, sizeof(float) * w * h * c);
272 MEM_freeN(tex_data);
273}
274
276{
277 if (!framebuffer_) {
278 framebuffer_ = GPU_framebuffer_create("fb_render_hydra");
279 }
281 &framebuffer_, {GPU_ATTACHMENT_TEXTURE(tex_depth_), GPU_ATTACHMENT_TEXTURE(tex_color_)});
282 GPU_framebuffer_bind(framebuffer_);
283
284 float clear_color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
285 GPU_framebuffer_clear_color_depth(framebuffer_, clear_color, 1.0f);
286
287 /* Workaround missing/buggy VAOs in hgiGL and hdSt. For OpenGL compatibility
288 * profile this is not a problem, but for core profile it is. */
289 if (VAO_ == 0 && GPU_backend_get_type() == GPU_BACKEND_OPENGL) {
290 glGenVertexArrays(1, &VAO_);
291 glBindVertexArray(VAO_);
292 }
294}
295
297{
298 if (VAO_) {
299 glDeleteVertexArrays(1, &VAO_);
300 VAO_ = 0;
301 }
302 if (framebuffer_) {
303 GPU_framebuffer_free(framebuffer_);
304 framebuffer_ = nullptr;
305 }
306 CLOG_DEBUG(LOG_HYDRA_RENDER, "unbind");
307}
308
310{
311 if (aov_key == pxr::HdAovTokens->color) {
312 return tex_color_;
313 }
314 if (aov_key == pxr::HdAovTokens->depth) {
315 return tex_depth_;
316 }
317 return nullptr;
318}
319
320} // namespace blender::render::hydra
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define ELEM(...)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:188
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
GPUBackendType GPU_backend_get_type()
blender::gpu::FrameBuffer * GPU_framebuffer_create(const char *name)
#define GPU_ATTACHMENT_TEXTURE(_texture)
void GPU_framebuffer_free(blender::gpu::FrameBuffer *fb)
#define GPU_framebuffer_ensure_config(_fb,...)
void GPU_framebuffer_clear_color_depth(blender::gpu::FrameBuffer *fb, const float clear_col[4], float clear_depth)
void GPU_framebuffer_bind(blender::gpu::FrameBuffer *fb)
int GPU_texture_height(const blender::gpu::Texture *texture)
int GPU_texture_width(const blender::gpu::Texture *texture)
@ GPU_DATA_FLOAT
@ GPU_TEXTURE_USAGE_GENERAL
void * GPU_texture_read(blender::gpu::Texture *texture, eGPUDataFormat data_format, int mip_level)
blender::gpu::Texture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(blender::gpu::Texture *texture)
Read Guarded memory(de)allocation.
BMesh const char void * data
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
void add_aov(pxr::TfToken const &aov_key) override
void set_viewport(pxr::GfVec4d const &viewport) override
blender::gpu::Texture * get_aov_texture(pxr::TfToken const &aov_key)
void read_aov(pxr::TfToken const &aov_key, void *data) override
pxr::HdRenderBuffer * get_aov_buffer(pxr::TfToken const &aov_key)
pxr::TfTokenVector GetTaskRenderTags(pxr::SdfPath const &id) override
RenderTaskDelegate(pxr::HdRenderIndex *parent_index, pxr::SdfPath const &delegate_id)
virtual void set_viewport(pxr::GfVec4d const &viewport)
pxr::VtValue Get(pxr::SdfPath const &id, pxr::TfToken const &key) override
virtual void add_aov(pxr::TfToken const &aov_key)
pxr::SdfPath buffer_id(pxr::TfToken const &aov_key) const
void set_camera(pxr::SdfPath const &camera_id)
virtual void read_aov(pxr::TfToken const &aov_key, void *data)
pxr::HdRenderBufferDescriptor GetRenderBufferDescriptor(pxr::SdfPath const &id) override
pxr::TfHashMap< pxr::SdfPath, pxr::HdRenderBufferDescriptor, pxr::SdfPath::Hash > buffer_descriptors_
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
format
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
struct CLG_LogRef * LOG_HYDRA_RENDER
i
Definition text_draw.cc:230
uint len