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