Blender V5.0
buffers.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <cstdlib>
6
7#include "device/device.h"
8
9#include "session/buffers.h"
10
11#include "util/log.h"
12
14
15/* --------------------------------------------------------------------
16 * Convert part information to an index of `BufferParams::pass_offset_`.
17 */
18
19static int pass_type_mode_to_index(PassType pass_type, PassMode mode)
20{
21 int index = static_cast<int>(pass_type) * 2;
22
23 if (mode == PassMode::DENOISED) {
24 ++index;
25 }
26
27 return index;
28}
29
30static int pass_to_index(const BufferPass &pass)
31{
32 return pass_type_mode_to_index(pass.type, pass.mode);
33}
34
35/* --------------------------------------------------------------------
36 * Buffer pass.
37 */
38
40{
41 NodeType *type = NodeType::add("buffer_pass", create);
42
43 const NodeEnum *pass_type_enum = Pass::get_type_enum();
44 const NodeEnum *pass_mode_enum = Pass::get_mode_enum();
45
46 SOCKET_ENUM(type, "Type", *pass_type_enum, PASS_COMBINED);
47 SOCKET_ENUM(mode, "Mode", *pass_mode_enum, static_cast<int>(PassMode::DENOISED));
48 SOCKET_STRING(name, "Name", ustring());
49 SOCKET_BOOLEAN(include_albedo, "Include Albedo", false);
50 SOCKET_STRING(lightgroup, "Light Group", ustring());
51
52 SOCKET_INT(offset, "Offset", -1);
53
54 return type;
55}
56
57BufferPass::BufferPass() : Node(get_node_type()) {}
58
59BufferPass::BufferPass(const Pass *scene_pass)
60 : Node(get_node_type()),
61 type(scene_pass->get_type()),
62 mode(scene_pass->get_mode()),
63 name(scene_pass->get_name()),
64 include_albedo(scene_pass->get_include_albedo()),
65 lightgroup(scene_pass->get_lightgroup())
66{
67}
68
73
74/* --------------------------------------------------------------------
75 * Buffer Parameters.
76 */
77
79{
80 NodeType *type = NodeType::add("buffer_params", create);
81
82 SOCKET_INT(width, "Width", 0);
83 SOCKET_INT(height, "Height", 0);
84
85 SOCKET_INT(window_x, "Window X", 0);
86 SOCKET_INT(window_y, "Window Y", 0);
87 SOCKET_INT(window_width, "Window Width", 0);
88 SOCKET_INT(window_height, "Window Height", 0);
89
90 SOCKET_INT(full_x, "Full X", 0);
91 SOCKET_INT(full_y, "Full Y", 0);
92 SOCKET_INT(full_width, "Full Width", 0);
93 SOCKET_INT(full_height, "Full Height", 0);
94
95 SOCKET_STRING(layer, "Layer", ustring());
96 SOCKET_STRING(view, "View", ustring());
97 SOCKET_INT(samples, "Samples", 0);
98 SOCKET_FLOAT(exposure, "Exposure", 1.0f);
99 SOCKET_BOOLEAN(use_approximate_shadow_catcher, "Use Approximate Shadow Catcher", false);
100 SOCKET_BOOLEAN(use_transparent_background, "Transparent Background", false);
101
102 /* Notes:
103 * - Skip passes since they do not follow typical container socket definition.
104 * Might look into covering those as a socket in the future.
105 *
106 * - Skip offset, stride, and pass stride since those can be delivered from the passes and
107 * rest of the sockets. */
108
109 return type;
110}
111
113{
115}
116
118{
121
122 pass_stride = 0;
123 for (const BufferPass &pass : passes) {
124 if (pass.offset != PASS_UNUSED) {
125 const int index = pass_to_index(pass);
126 if (pass_offset_[index] == PASS_UNUSED) {
127 pass_offset_[index] = pass_stride;
128 }
129
130 pass_stride += pass.get_info().num_components;
131 }
132 }
133}
134
136{
137 passes.clear();
138
139 pass_stride = 0;
140 for (const Pass *scene_pass : scene_passes) {
141 BufferPass buffer_pass(scene_pass);
142
143 if (scene_pass->is_written()) {
144 buffer_pass.offset = pass_stride;
145 pass_stride += scene_pass->get_info().num_components;
146 }
147 else {
148 buffer_pass.offset = PASS_UNUSED;
149 }
150
151 passes.emplace_back(std::move(buffer_pass));
152 }
153
155}
156
158{
159 for (int i = 0; i < kNumPassOffsets; ++i) {
161 }
162}
163
165{
166 if (pass_type == PASS_NONE) {
167 return PASS_UNUSED;
168 }
169
170 const int index = pass_type_mode_to_index(pass_type, mode);
171 return pass_offset_[index];
172}
173
174const BufferPass *BufferParams::find_pass(string_view name) const
175{
176 for (const BufferPass &pass : passes) {
177 if (pass.name == name) {
178 return &pass;
179 }
180 }
181
182 return nullptr;
183}
184
186{
187 for (const BufferPass &pass : passes) {
188 if (pass.type == type && pass.mode == mode) {
189 return &pass;
190 }
191 }
192
193 return nullptr;
194}
195
197{
198 const BufferPass *pass = find_pass(type, mode);
199 return get_actual_display_pass(pass);
200}
201
203{
204 if (!pass) {
205 return nullptr;
206 }
207
208 if (pass->type == PASS_COMBINED && pass->lightgroup.empty()) {
209 const BufferPass *shadow_catcher_matte_pass = find_pass(PASS_SHADOW_CATCHER_MATTE, pass->mode);
210 if (shadow_catcher_matte_pass) {
211 pass = shadow_catcher_matte_pass;
212 }
213 }
214
215 return pass;
216}
217
223
224bool BufferParams::modified(const BufferParams &other) const
225{
226 if (width != other.width || height != other.height) {
227 return true;
228 }
229
230 if (full_x != other.full_x || full_y != other.full_y || full_width != other.full_width ||
231 full_height != other.full_height)
232 {
233 return true;
234 }
235
236 if (window_x != other.window_x || window_y != other.window_y ||
238 {
239 return true;
240 }
241
242 if (offset != other.offset || stride != other.stride || pass_stride != other.pass_stride) {
243 return true;
244 }
245
246 if (layer != other.layer || view != other.view) {
247 return true;
248 }
249
250 if (exposure != other.exposure ||
253 {
254 return true;
255 }
256
257 return !(passes == other.passes);
258}
259
260/* --------------------------------------------------------------------
261 * Render Buffers.
262 */
263
264RenderBuffers::RenderBuffers(Device *device) : buffer(device, "RenderBuffers", MEM_READ_WRITE) {}
265
267{
268 buffer.free();
269}
270
272{
273 DCHECK(params_.pass_stride != -1);
274
275 params = params_;
276
277 /* re-allocate buffer */
278 buffer.alloc(params.width * params.pass_stride, params.height);
279}
280
282{
283 buffer.zero_to_device();
284}
285
287{
288 DCHECK(params.pass_stride != -1);
289
290 if (!buffer.device_pointer) {
291 return false;
292 }
293
294 buffer.copy_from_device(0, params.width * params.pass_stride, params.height);
295
296 return true;
297}
298
300{
301 buffer.copy_to_device();
302}
303
305 const BufferParams &dst_params,
306 const RenderBuffers *src,
307 const BufferParams &src_params,
308 const size_t src_offset)
309{
310 DCHECK_EQ(dst_params.width, src_params.width);
311 /* TODO(sergey): More sanity checks to avoid buffer overrun. */
312
313 /* Create a map of pass offsets to be copied.
314 * Assume offsets are different to allow copying passes between buffers with different set of
315 * passes. */
316
317 struct {
318 int dst_offset;
319 int src_offset;
320 } pass_offsets[PASS_NUM];
321
322 int num_passes = 0;
323
324 for (int i = 0; i < PASS_NUM; ++i) {
325 const PassType pass_type = static_cast<PassType>(i);
326
327 const int dst_pass_offset = dst_params.get_pass_offset(pass_type, PassMode::DENOISED);
328 if (dst_pass_offset == PASS_UNUSED) {
329 continue;
330 }
331
332 const int src_pass_offset = src_params.get_pass_offset(pass_type, PassMode::DENOISED);
333 if (src_pass_offset == PASS_UNUSED) {
334 continue;
335 }
336
337 pass_offsets[num_passes].dst_offset = dst_pass_offset;
338 pass_offsets[num_passes].src_offset = src_pass_offset;
339 ++num_passes;
340 }
341
342 /* Copy passes. */
343 /* TODO(sergey): Make it more reusable, allowing implement copy of noisy passes. */
344
345 const int64_t dst_width = dst_params.width;
346 const int64_t dst_height = dst_params.height;
347 const int64_t dst_pass_stride = dst_params.pass_stride;
348 const int64_t dst_num_pixels = dst_width * dst_height;
349
350 const int64_t src_pass_stride = src_params.pass_stride;
351 const int64_t src_offset_in_floats = src_offset * src_pass_stride;
352
353 const float *src_pixel = src->buffer.data() + src_offset_in_floats;
354 float *dst_pixel = dst->buffer.data();
355
356 for (int i = 0; i < dst_num_pixels;
357 ++i, src_pixel += src_pass_stride, dst_pixel += dst_pass_stride)
358 {
359 for (int pass_offset_idx = 0; pass_offset_idx < num_passes; ++pass_offset_idx) {
360 const int dst_pass_offset = pass_offsets[pass_offset_idx].dst_offset;
361 const int src_pass_offset = pass_offsets[pass_offset_idx].src_offset;
362
363 /* TODO(sergey): Support non-RGBA passes. */
364 dst_pixel[dst_pass_offset + 0] = src_pixel[src_pass_offset + 0];
365 dst_pixel[dst_pass_offset + 1] = src_pixel[src_pass_offset + 1];
366 dst_pixel[dst_pass_offset + 2] = src_pixel[src_pass_offset + 2];
367 dst_pixel[dst_pass_offset + 3] = src_pixel[src_pass_offset + 3];
368 }
369 }
370}
371
static AppView * view
long long int int64_t
static CCL_NAMESPACE_BEGIN int pass_type_mode_to_index(PassType pass_type, PassMode mode)
Definition buffers.cpp:19
void render_buffers_host_copy_denoised(RenderBuffers *dst, const BufferParams &dst_params, const RenderBuffers *src, const BufferParams &src_params, const size_t src_offset)
Definition buffers.cpp:304
static int pass_to_index(const BufferPass &pass)
Definition buffers.cpp:30
ustring view
Definition buffers.h:97
int pass_stride
Definition buffers.h:92
ustring layer
Definition buffers.h:96
int full_width
Definition buffers.h:85
int pass_offset_[kNumPassOffsets]
Definition buffers.h:147
bool use_approximate_shadow_catcher
Definition buffers.h:100
vector< BufferPass > passes
Definition buffers.h:95
static constexpr int kNumPassOffsets
Definition buffers.h:142
int get_pass_offset(PassType type, PassMode mode=PassMode::NOISY) const
Definition buffers.cpp:164
float exposure
Definition buffers.h:99
int window_y
Definition buffers.h:78
void update_offset_stride()
Definition buffers.cpp:218
bool modified(const BufferParams &other) const
Definition buffers.cpp:224
int full_height
Definition buffers.h:86
int window_height
Definition buffers.h:80
int window_width
Definition buffers.h:79
void reset_pass_offset()
Definition buffers.cpp:157
NODE_DECLARE int width
Definition buffers.h:70
const BufferPass * find_pass(string_view name) const
Definition buffers.cpp:174
const BufferPass * get_actual_display_pass(PassType type, PassMode mode=PassMode::NOISY) const
Definition buffers.cpp:196
int window_x
Definition buffers.h:77
bool use_transparent_background
Definition buffers.h:101
void update_passes()
Definition buffers.cpp:117
ustring name
Definition buffers.h:30
int offset
Definition buffers.h:34
bool include_albedo
Definition buffers.h:31
PassInfo get_info() const
Definition buffers.cpp:69
NODE_DECLARE PassType type
Definition buffers.h:28
ustring lightgroup
Definition buffers.h:32
PassMode mode
Definition buffers.h:29
Definition pass.h:50
PassInfo get_info() const
Definition pass.cpp:146
static const NodeEnum * get_type_enum()
Definition pass.cpp:45
static const NodeEnum * get_mode_enum()
Definition pass.cpp:116
device_vector< float > buffer
Definition buffers.h:158
BufferParams params
Definition buffers.h:155
bool copy_from_device()
Definition buffers.cpp:286
void copy_to_device()
Definition buffers.cpp:299
void reset(const BufferParams &params)
Definition buffers.cpp:271
RenderBuffers(Device *device)
Definition buffers.cpp:264
@ MEM_READ_WRITE
#define PASS_UNUSED
#define CCL_NAMESPACE_END
PassType
@ PASS_SHADOW_CATCHER_MATTE
@ PASS_COMBINED
@ PASS_NUM
@ PASS_NONE
#define DCHECK(expression)
Definition log.h:135
#define DCHECK_EQ(a, b)
Definition log.h:144
#define SOCKET_FLOAT(name, ui_name, default_value,...)
Definition node_type.h:211
#define SOCKET_INT(name, ui_name, default_value,...)
Definition node_type.h:205
#define NODE_DEFINE(structname)
Definition node_type.h:152
#define SOCKET_BOOLEAN(name, ui_name, default_value,...)
Definition node_type.h:203
#define SOCKET_STRING(name, ui_name, default_value,...)
Definition node_type.h:223
#define SOCKET_ENUM(name, ui_name, values, default_value,...)
Definition node_type.h:227
PassMode
Definition pass.h:20
@ DENOISED
Definition pass.h:22
const char * name
static NodeType * add(const char *name, CreateFunc create, Type type=NONE, const NodeType *base=nullptr)
const NodeType * type
Definition graph/node.h:178
ustring name
Definition graph/node.h:177
Node(const NodeType *type, ustring name=ustring())
i
Definition text_draw.cc:230