Blender V4.5
render/intern/compositor.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <cstring>
6#include <string>
7
8#include "BLI_listbase.h"
10#include "BLI_threads.h"
11#include "BLI_vector.hh"
12
13#include "MEM_guardedalloc.h"
14
15#include "BKE_cryptomatte.hh"
16#include "BKE_global.hh"
17#include "BKE_image.hh"
18#include "BKE_node.hh"
19#include "BKE_scene.hh"
20
21#include "DRW_engine.hh"
22#include "DRW_render.hh"
23
24#include "IMB_imbuf.hh"
25
26#include "COM_context.hh"
27#include "COM_domain.hh"
28#include "COM_evaluator.hh"
29#include "COM_render_context.hh"
30
31#include "RE_compositor.hh"
32#include "RE_pipeline.h"
33
34#include "WM_api.hh"
35
36#include "GPU_context.hh"
37#include "GPU_state.hh"
38#include "GPU_texture_pool.hh"
39
40#include "render_types.h"
41
42namespace blender::render {
43
77
78/* Render Context Data */
79
81 private:
82 /* Input data. */
83 ContextInputData input_data_;
84
85 /* Output combined result. */
86 compositor::Result output_result_;
87
88 /* Viewer output result. */
89 compositor::Result viewer_output_result_;
90
91 /* Cached GPU and CPU passes that the compositor took ownership of. Those had their reference
92 * count incremented when accessed during evaluation and need to be freed/have their reference
93 * count decremented after evaluation. */
94 Vector<GPUTexture *> cached_gpu_passes_;
95 Vector<ImBuf *> cached_cpu_passes_;
96
97 public:
98 Context(const ContextInputData &input_data)
100 input_data_(input_data),
101 output_result_(this->create_result(compositor::ResultType::Color)),
102 viewer_output_result_(this->create_result(compositor::ResultType::Color))
103 {
104 }
105
106 virtual ~Context()
107 {
108 output_result_.release();
109 viewer_output_result_.release();
110 this->release_cached_passes();
111 }
112
113 void update_input_data(const ContextInputData &input_data)
114 {
115 input_data_ = input_data;
116 }
117
118 const Scene &get_scene() const override
119 {
120 return *input_data_.scene;
121 }
122
123 const bNodeTree &get_node_tree() const override
124 {
125 return *input_data_.node_tree;
126 }
127
128 bool use_gpu() const override
129 {
131 }
132
134 {
135 if (this->render_context()) {
136 return static_cast<eCompositorDenoiseQaulity>(
138 }
139
140 return static_cast<eCompositorDenoiseQaulity>(
142 }
143
145 {
146 return input_data_.needed_outputs;
147 }
148
149 const RenderData &get_render_data() const override
150 {
151 return *(input_data_.render_data);
152 }
153
154 int2 get_render_size() const override
155 {
156 Render *render = RE_GetSceneRender(input_data_.scene);
157 RenderResult *render_result = RE_AcquireResultRead(render);
158
159 /* If a render result already exist, use its size, since the compositor operates on the render
160 * settings at which the render happened. Otherwise, use the size from the render data. */
161 int2 size;
162 if (render_result) {
163 size = int2(render_result->rectx, render_result->recty);
164 }
165 else {
166 BKE_render_resolution(input_data_.render_data, true, &size.x, &size.y);
167 }
168
170
171 return size;
172 }
173
175 {
176 const int2 render_size = get_render_size();
177 const rcti render_region = rcti{0, render_size.x, 0, render_size.y};
178
179 return render_region;
180 }
181
183 {
184 const int2 render_size = get_render_size();
185 if (output_result_.is_allocated()) {
186 /* If the allocated result have the same size as the render size, return it as is. */
187 if (render_size == output_result_.domain().size) {
188 return output_result_;
189 }
190 /* Otherwise, the size changed, so release its data and reset it, then we reallocate it on
191 * the new render size below. */
192 output_result_.release();
193 output_result_ = this->create_result(compositor::ResultType::Color);
194 }
195
196 output_result_.allocate_texture(render_size, false);
197 return output_result_;
198 }
199
201 const bool is_data,
202 compositor::ResultPrecision precision) override
203 {
204 viewer_output_result_.set_transformation(domain.transformation);
205 viewer_output_result_.meta_data.is_non_color_data = is_data;
206
207 if (viewer_output_result_.is_allocated()) {
208 /* If the allocated result have the same size and precision as requested, return it as is. */
209 if (domain.size == viewer_output_result_.domain().size &&
210 precision == viewer_output_result_.precision())
211 {
212 return viewer_output_result_;
213 }
214
215 /* Otherwise, the size or precision changed, so release its data and reset it, then we
216 * reallocate it on the new domain below. */
217 viewer_output_result_.release();
218 viewer_output_result_ = this->create_result(compositor::ResultType::Color);
219 viewer_output_result_.set_transformation(domain.transformation);
220 viewer_output_result_.meta_data.is_non_color_data = is_data;
221 }
222
223 viewer_output_result_.set_precision(precision);
224 viewer_output_result_.allocate_texture(domain, false);
225 return viewer_output_result_;
226 }
227
229 int view_layer_id,
230 const char *pass_name) override
231 {
232 if (!scene) {
233 return compositor::Result(*this);
234 }
235
236 ViewLayer *view_layer = static_cast<ViewLayer *>(
237 BLI_findlink(&scene->view_layers, view_layer_id));
238 if (!view_layer) {
239 return compositor::Result(*this);
240 }
241
243 if (!render) {
244 return compositor::Result(*this);
245 }
246
247 RenderResult *render_result = RE_AcquireResultRead(render);
248 if (!render_result) {
250 return compositor::Result(*this);
251 }
252
253 RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name);
254 if (!render_layer) {
256 return compositor::Result(*this);
257 }
258
259 RenderPass *render_pass = RE_pass_find_by_name(
260 render_layer, pass_name, this->get_view_name().data());
261 if (!render_pass) {
263 return compositor::Result(*this);
264 }
265
266 if (!render_pass || !render_pass->ibuf || !render_pass->ibuf->float_buffer.data) {
268 return compositor::Result(*this);
269 }
270
273
274 if (this->use_gpu()) {
275 GPUTexture *pass_texture = RE_pass_ensure_gpu_texture_cache(render, render_pass);
276 /* Don't assume render will keep pass data stored, add our own reference. */
277 GPU_texture_ref(pass_texture);
278 pass.wrap_external(pass_texture);
279 cached_gpu_passes_.append(pass_texture);
280 }
281 else {
282 /* Don't assume render will keep pass data stored, add our own reference. */
283 IMB_refImBuf(render_pass->ibuf);
284 pass.wrap_external(render_pass->ibuf->float_buffer.data,
285 int2(render_pass->ibuf->x, render_pass->ibuf->y));
286 cached_cpu_passes_.append(render_pass->ibuf);
287 }
288
290 return pass;
291 }
292
294 {
295 for (GPUTexture *pass : cached_gpu_passes_) {
296 GPU_texture_free(pass);
297 }
298 cached_gpu_passes_.clear();
299 for (ImBuf *pass : cached_cpu_passes_) {
300 IMB_freeImBuf(pass);
301 }
302 cached_cpu_passes_.clear();
303 }
304
306 {
307 switch (pass->channels) {
308 case 1:
310 case 2:
312 case 3:
314 case 4:
315 if (StringRef(pass->chan_id) == "XYZW") {
317 }
318 else {
320 }
321 default:
322 break;
323 }
324
327 }
328
329 StringRef get_view_name() const override
330 {
331 return input_data_.view_name;
332 }
333
335 {
336 switch (input_data_.scene->r.compositor_precision) {
338 /* Auto uses full precision for final renders and half procession otherwise. */
339 if (this->render_context()) {
341 }
342 else {
344 }
347 }
348
351 }
352
353 void set_info_message(StringRef /*message*/) const override
354 {
355 /* TODO: ignored for now. Currently only used to communicate incomplete node support
356 * which is already shown on the node itself.
357 *
358 * Perhaps this overall info message could be replaced by a boolean indicating
359 * incomplete support, and leave more specific message to individual nodes? */
360 }
361
363 int view_layer_id,
364 const char *pass_name,
365 compositor::MetaData &meta_data) const override
366 {
367 if (!scene) {
368 return;
369 }
370
371 ViewLayer *view_layer = static_cast<ViewLayer *>(
372 BLI_findlink(&scene->view_layers, view_layer_id));
373 if (!view_layer) {
374 return;
375 }
376
378 if (!render) {
379 return;
380 }
381
382 RenderResult *render_result = RE_AcquireResultRead(render);
383 if (!render_result || !render_result->stamp_data) {
385 return;
386 }
387
388 /* We assume the given pass is a Cryptomatte pass and retrieve its layer name. If it wasn't a
389 * Cryptomatte pass, the checks below will fail anyways. */
390 const std::string combined_pass_name = std::string(view_layer->name) + "." + pass_name;
392 combined_pass_name);
393
394 struct StampCallbackData {
395 std::string cryptomatte_layer_name;
396 compositor::MetaData *meta_data;
397 };
398
399 /* Go over the stamp data and add any Cryptomatte related meta data. */
400 StampCallbackData callback_data = {cryptomatte_layer_name, &meta_data};
402 &callback_data,
403 render_result->stamp_data,
404 [](void *user_data, const char *key, char *value, int /*value_length*/) {
405 StampCallbackData *data = static_cast<StampCallbackData *>(user_data);
406
407 const std::string manifest_key = bke::cryptomatte::BKE_cryptomatte_meta_data_key(
408 data->cryptomatte_layer_name, "manifest");
409 if (key == manifest_key) {
410 data->meta_data->cryptomatte.manifest = value;
411 }
412
414 data->cryptomatte_layer_name, "hash");
415 if (key == hash_key) {
416 data->meta_data->cryptomatte.hash = value;
417 }
418
419 const std::string conversion_key = bke::cryptomatte::BKE_cryptomatte_meta_data_key(
420 data->cryptomatte_layer_name, "conversion");
421 if (key == conversion_key) {
422 data->meta_data->cryptomatte.conversion = value;
423 }
424 },
425 false);
426
428 }
429
431 {
432 if (!output_result_.is_allocated()) {
433 return;
434 }
435
436 Render *re = RE_GetSceneRender(input_data_.scene);
438
439 if (rr) {
440 RenderView *rv = RE_RenderViewGetByName(rr, input_data_.view_name.c_str());
441 ImBuf *ibuf = RE_RenderViewEnsureImBuf(rr, rv);
442 rr->have_combined = true;
443
444 if (this->use_gpu()) {
446 float *output_buffer = static_cast<float *>(
447 GPU_texture_read(output_result_, GPU_DATA_FLOAT, 0));
448 IMB_assign_float_buffer(ibuf, output_buffer, IB_TAKE_OWNERSHIP);
449 }
450 else {
451 float *data = MEM_malloc_arrayN<float>(4 * size_t(rr->rectx) * size_t(rr->recty),
452 __func__);
454 std::memcpy(
455 data, output_result_.cpu_data().data(), rr->rectx * rr->recty * 4 * sizeof(float));
456 }
457 }
458
459 if (re) {
461 re = nullptr;
462 }
463
464 Image *image = BKE_image_ensure_viewer(G.main, IMA_TYPE_R_RESULT, "Render Result");
467 BKE_image_signal(G.main, image, nullptr, IMA_SIGNAL_FREE);
469 }
470
472 {
473 if (!viewer_output_result_.is_allocated()) {
474 return;
475 }
476
477 Image *image = BKE_image_ensure_viewer(G.main, IMA_TYPE_COMPOSITE, "Viewer Node");
478 const float2 translation = viewer_output_result_.domain().transformation.location();
479 image->runtime->backdrop_offset[0] = translation.x;
480 image->runtime->backdrop_offset[1] = translation.y;
481
482 if (viewer_output_result_.meta_data.is_non_color_data) {
483 image->flag &= ~IMA_VIEW_AS_RENDER;
484 }
485 else {
486 image->flag |= IMA_VIEW_AS_RENDER;
487 }
488
489 ImageUser image_user = {nullptr};
490 image_user.multi_index = BKE_scene_multiview_view_id_get(input_data_.render_data,
491 input_data_.view_name.c_str());
492
493 if (BKE_scene_multiview_is_render_view_first(input_data_.render_data,
494 input_data_.view_name.c_str()))
495 {
496 BKE_image_ensure_viewer_views(input_data_.render_data, image, &image_user);
497 }
498
500
501 void *lock;
502 ImBuf *image_buffer = BKE_image_acquire_ibuf(image, &image_user, &lock);
503
504 const int2 size = viewer_output_result_.domain().size;
505 if (image_buffer->x != size.x || image_buffer->y != size.y) {
506 IMB_free_byte_pixels(image_buffer);
507 IMB_free_float_pixels(image_buffer);
508 image_buffer->x = size.x;
509 image_buffer->y = size.y;
510 IMB_alloc_float_pixels(image_buffer, 4);
511 image_buffer->userflags |= IB_DISPLAY_BUFFER_INVALID;
512 }
513
514 BKE_image_release_ibuf(image, image_buffer, lock);
516
517 if (this->use_gpu()) {
519 float *output_buffer = static_cast<float *>(
520 GPU_texture_read(viewer_output_result_, GPU_DATA_FLOAT, 0));
521
522 std::memcpy(
523 image_buffer->float_buffer.data, output_buffer, size.x * size.y * 4 * sizeof(float));
524 MEM_freeN(output_buffer);
525 }
526 else {
527 std::memcpy(image_buffer->float_buffer.data,
528 viewer_output_result_.cpu_data().data(),
529 size.x * size.y * 4 * sizeof(float));
530 }
531
533 if (input_data_.node_tree->runtime->update_draw) {
534 input_data_.node_tree->runtime->update_draw(input_data_.node_tree->runtime->udh);
535 }
536 }
537
539 {
540 return input_data_.render_context;
541 }
542
544 {
545 return input_data_.profiler;
546 }
547
548 void evaluate_operation_post() const override
549 {
550 /* If no render context exist, that means this is an interactive compositor evaluation due to
551 * the user editing the node tree. In that case, we wait until the operation finishes executing
552 * on the GPU before we continue to improve interactivity. The improvement comes from the fact
553 * that the user might be rapidly changing values, so we need to cancel previous evaluations to
554 * make editing faster, but we can't do that if all operations are submitted to the GPU all at
555 * once, and we can't cancel work that was already submitted to the GPU. This does have a
556 * performance penalty, but in practice, the improved interactivity is worth it according to
557 * user feedback. */
558 if (this->use_gpu() && !this->render_context()) {
559 GPU_finish();
560 }
561 }
562};
563
564/* Render Compositor */
565
567 private:
568 /* Render instance for GPU context to run compositor in. */
569 Render &render_;
570
571 std::unique_ptr<Context> context_;
572
573 /* Stores the execution device and precision used in the last evaluation of the compositor. Those
574 * might be different from the current values returned by the context, since the user might have
575 * changed them since the last evaluation. See the needs_to_be_recreated method for more info on
576 * why those are needed. */
577 bool uses_gpu_;
578 compositor::ResultPrecision used_precision_;
579
580 public:
581 Compositor(Render &render, const ContextInputData &input_data) : render_(render)
582 {
583 context_ = std::make_unique<Context>(input_data);
584
585 uses_gpu_ = context_->use_gpu();
586 used_precision_ = context_->get_precision();
587 }
588
590 {
591 /* Use uses_gpu_ instead of context_->use_gpu() because we are freeing resources from the last
592 * evaluation. See uses_gpu_ for more information. */
593 if (uses_gpu_) {
594 /* Free resources with GPU context enabled. Cleanup may happen from the
595 * main thread, and we must use the main context there. */
596 if (BLI_thread_is_main()) {
598 }
599 else {
601 }
602 }
603
604 context_.reset();
605
606 /* See comment above on context enabling. */
607 if (uses_gpu_) {
608 if (BLI_thread_is_main()) {
610 }
611 else {
613 }
614 }
615 }
616
617 void update_input_data(const ContextInputData &input_data)
618 {
619 context_->update_input_data(input_data);
620 }
621
622 void execute()
623 {
624 if (context_->use_gpu()) {
625 /* For main thread rendering in background mode, blocking rendering, or when we do not have a
626 * render system GPU context, use the DRW context directly, while for threaded rendering when
627 * we have a render system GPU context, use the render's system GPU context to avoid blocking
628 * with the global DST. */
629 void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
630 if (BLI_thread_is_main() || re_system_gpu_context == nullptr) {
632 }
633 else {
634 void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
635 WM_system_gpu_context_activate(re_system_gpu_context);
636
637 void *re_blender_gpu_context = RE_blender_gpu_context_ensure(&render_);
638
640 GPU_context_active_set(static_cast<GPUContext *>(re_blender_gpu_context));
641 }
642 }
643
644 {
645 compositor::Evaluator evaluator(*context_);
646 evaluator.evaluate();
647 }
648
649 context_->output_to_render_result();
650 context_->viewer_output_to_viewer_image();
651 context_->release_cached_passes();
652
653 if (context_->use_gpu()) {
655
656 void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
657 if (BLI_thread_is_main() || re_system_gpu_context == nullptr) {
659 }
660 else {
662 GPU_context_active_set(nullptr);
663 void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
664 WM_system_gpu_context_release(re_system_gpu_context);
665 }
666 }
667 }
668
669 /* Returns true if the compositor should be freed and reconstructed, which is needed when the
670 * compositor execution device or precision changed, because we either need to update all cached
671 * and pooled resources for the new execution device and precision, or we simply recreate the
672 * entire compositor, since it is much easier and safer. */
674 {
675 /* See uses_gpu_ and used_precision_ for more information what how they are different from the
676 * ones returned from the context. */
677 return context_->use_gpu() != uses_gpu_ || context_->get_precision() != used_precision_;
678 }
679};
680
681} // namespace blender::render
682
684 const RenderData &render_data,
685 const bNodeTree &node_tree,
686 const char *view_name,
690{
691 std::unique_lock lock(this->compositor_mutex);
692
694 scene, render_data, node_tree, view_name, render_context, profiler, needed_outputs);
695
696 if (this->compositor) {
697 this->compositor->update_input_data(input_data);
698
699 if (this->compositor->needs_to_be_recreated()) {
700 /* Free it here and it will be recreated in the check below. */
701 delete this->compositor;
702 this->compositor = nullptr;
703 }
704 }
705
706 if (!this->compositor) {
707 this->compositor = new blender::render::Compositor(*this, input_data);
708 }
709
710 this->compositor->execute();
711}
712
714{
715 std::unique_lock lock(this->compositor_mutex);
716
717 if (this->compositor != nullptr) {
718 delete this->compositor;
719 this->compositor = nullptr;
720 }
721}
722
724 const Scene &scene,
725 const RenderData &render_data,
726 const bNodeTree &node_tree,
727 const char *view_name,
731{
732 render.compositor_execute(
733 scene, render_data, node_tree, view_name, render_context, profiler, needed_outputs);
734}
735
737{
738 render.compositor_free();
739}
ImBuf * BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock)
void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser *iuser)
Image * BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock)
#define IMA_SIGNAL_FREE
Definition BKE_image.hh:162
void BKE_stamp_info_callback(void *data, StampData *stamp_data, StampCallback callback, bool noskip)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
void BKE_image_partial_update_mark_full_update(Image *image)
Mark the whole image to be updated.
void BKE_render_resolution(const RenderData *r, const bool use_crop, int *r_width, int *r_height)
Definition scene.cc:2927
bool BKE_scene_multiview_is_render_view_first(const RenderData *rd, const char *viewname)
Definition scene.cc:3026
int BKE_scene_multiview_view_id_get(const RenderData *rd, const char *viewname)
Definition scene.cc:3094
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
void BLI_thread_unlock(int type)
Definition threads.cc:333
void BLI_thread_lock(int type)
Definition threads.cc:328
@ LOCK_DRAW_IMAGE
Definition BLI_threads.h:64
int BLI_thread_is_main(void)
Definition threads.cc:179
float[4] Color
@ IMA_VIEW_AS_RENDER
@ IMA_TYPE_R_RESULT
@ IMA_TYPE_COMPOSITE
eCompositorDenoiseQaulity
@ SCE_COMPOSITOR_PRECISION_FULL
@ SCE_COMPOSITOR_PRECISION_AUTO
@ SCE_COMPOSITOR_DEVICE_GPU
void DRW_gpu_context_disable()
void DRW_gpu_context_enable()
void DRW_render_context_disable(Render *render)
void DRW_render_context_enable(Render *render)
void GPU_render_end()
void GPU_render_begin()
void GPU_context_active_set(GPUContext *)
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:385
void GPU_finish()
Definition gpu_state.cc:310
@ GPU_BARRIER_TEXTURE_UPDATE
Definition GPU_state.hh:39
void GPU_texture_free(GPUTexture *texture)
void GPU_texture_ref(GPUTexture *texture)
void * GPU_texture_read(GPUTexture *texture, eGPUDataFormat data_format, int mip_level)
@ GPU_DATA_FLOAT
void IMB_assign_float_buffer(ImBuf *ibuf, float *buffer_data, ImBufOwnership ownership)
void IMB_freeImBuf(ImBuf *ibuf)
void IMB_free_float_pixels(ImBuf *ibuf)
void IMB_refImBuf(ImBuf *ibuf)
void IMB_free_byte_pixels(ImBuf *ibuf)
bool IMB_alloc_float_pixels(ImBuf *ibuf, const unsigned int channels, bool initialize_pixels=true)
@ IB_DISPLAY_BUFFER_INVALID
@ IB_TAKE_OWNERSHIP
Read Guarded memory(de)allocation.
uint32_t hash_key
volatile int lock
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
Result create_result(ResultType type, ResultPrecision precision)
void set_transformation(const float3x3 &transformation)
Definition result.cc:484
void wrap_external(GPUTexture *texture)
Definition result.cc:448
void reset(bool force_free=false)
static TexturePool & get()
Compositor(Render &render, const ContextInputData &input_data)
void update_input_data(const ContextInputData &input_data)
compositor::RenderContext * render_context
ContextInputData(const Scene &scene, const RenderData &render_data, const bNodeTree &node_tree, const char *view_name, compositor::RenderContext *render_context, compositor::Profiler *profiler, compositor::OutputTypes needed_outputs)
compositor::Result get_pass(const Scene *scene, int view_layer_id, const char *pass_name) override
const Scene & get_scene() const override
void set_info_message(StringRef) const override
StringRef get_view_name() const override
compositor::RenderContext * render_context() const override
void populate_meta_data_for_pass(const Scene *scene, int view_layer_id, const char *pass_name, compositor::MetaData &meta_data) const override
compositor::ResultPrecision get_precision() const override
eCompositorDenoiseQaulity get_denoise_quality() const override
void evaluate_operation_post() const override
compositor::ResultType result_type_from_pass(const RenderPass *pass)
compositor::OutputTypes needed_outputs() const override
Context(const ContextInputData &input_data)
compositor::Result get_output_result() override
compositor::Result get_viewer_output_result(compositor::Domain domain, const bool is_data, compositor::ResultPrecision precision) override
compositor::Profiler * profiler() const override
void update_input_data(const ContextInputData &input_data)
const RenderData & get_render_data() const override
rcti get_compositing_region() const override
const bNodeTree & get_node_tree() const override
int2 get_render_size() const override
#define this
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
StringRef BKE_cryptomatte_extract_layer_name(StringRef render_pass_name)
std::string BKE_cryptomatte_meta_data_key(StringRef layer_name, StringRefNull key_name)
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
void RE_compositor_free(Render &render)
void RE_compositor_execute(Render &render, const Scene &scene, const RenderData &render_data, const bNodeTree &node_tree, const char *view_name, blender::compositor::RenderContext *render_context, blender::compositor::Profiler *profiler, blender::compositor::OutputTypes needed_outputs)
GPUTexture * RE_pass_ensure_gpu_texture_cache(Render *re, RenderPass *rpass)
RenderView * RE_RenderViewGetByName(RenderResult *rr, const char *viewname)
ImBuf * RE_RenderViewEnsureImBuf(const RenderResult *render_result, RenderView *render_view)
void * RE_blender_gpu_context_ensure(Render *re)
void * RE_system_gpu_context_get(Render *re)
RenderPass * RE_pass_find_by_name(RenderLayer *rl, const char *name, const char *viewname)
RenderResult * RE_AcquireResultWrite(Render *re)
RenderResult * RE_AcquireResultRead(Render *re)
RenderLayer * RE_GetRenderLayer(RenderResult *rr, const char *name)
void RE_ReleaseResult(Render *re)
Render * RE_GetSceneRender(const Scene *scene)
ImBufFloatBuffer float_buffer
short multi_index
ImageRuntimeHandle * runtime
int compositor_denoise_preview_quality
int compositor_denoise_final_quality
struct ImBuf * ibuf
Definition RE_pipeline.h:60
char chan_id[8]
Definition RE_pipeline.h:51
struct StampData * stamp_data
void compositor_free() override
blender::render::Compositor * compositor
Scene * scene
blender::Mutex compositor_mutex
void compositor_execute(const Scene &scene, const RenderData &render_data, const bNodeTree &node_tree, const char *view_name, blender::compositor::RenderContext *render_context, blender::compositor::Profiler *profiler, blender::compositor::OutputTypes needed_outputs) override
ListBase view_layers
char name[64]
void WM_system_gpu_context_activate(void *context)
void WM_system_gpu_context_release(void *context)