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