From 65fc10bd33fbe19a8beb2b7319b1b0bbdc52f1cb Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Mon, 5 Jun 2023 12:08:30 +0200 Subject: [PATCH] Compositor: first steps to use realtime compositor for renders * Enable "Experimental Compositors" in preferences, then choose Realtime GPU execution mode in node editor sidebar. * Only supports combined pass input and Render Result combined output. * No viewer nodes, no file output nodes, and no node previews yet. Pull Request: https://projects.blender.org/blender/blender/pulls/108629 --- scripts/startup/bl_ui/space_node.py | 10 +- scripts/startup/bl_ui/space_userpref.py | 2 +- source/blender/compositor/COM_compositor.h | 8 +- .../compositor/intern/COM_compositor.cc | 54 ++-- .../realtime_compositor/CMakeLists.txt | 1 + .../blender/editors/space_node/node_draw.cc | 6 + .../blender/editors/space_node/node_edit.cc | 11 +- source/blender/makesdna/DNA_node_types.h | 1 + source/blender/makesrna/intern/rna_nodetree.c | 5 + source/blender/makesrna/intern/rna_userdef.c | 11 +- source/blender/nodes/NOD_composite.h | 8 +- .../nodes/composite/node_composite_tree.cc | 5 +- source/blender/render/CMakeLists.txt | 6 + source/blender/render/RE_compositor.hh | 59 ++++ source/blender/render/intern/compositor.cc | 300 ++++++++++++++++++ source/blender/render/intern/pipeline.cc | 2 +- 16 files changed, 456 insertions(+), 33 deletions(-) create mode 100644 source/blender/render/RE_compositor.hh create mode 100644 source/blender/render/intern/compositor.cc diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index 7f3c6c913c0..f00a2be4912 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -764,20 +764,26 @@ class NODE_PT_quality(bpy.types.Panel): tree = snode.node_tree prefs = bpy.context.preferences + use_realtime = False col = layout.column() - if prefs.experimental.use_full_frame_compositor: + if prefs.experimental.use_experimental_compositors: col.prop(tree, "execution_mode") + use_realtime = tree.execution_mode == 'REALTIME' + col = layout.column() + col.active = not use_realtime col.prop(tree, "render_quality", text="Render") col.prop(tree, "edit_quality", text="Edit") col.prop(tree, "chunk_size") col = layout.column() + col.active = not use_realtime col.prop(tree, "use_opencl") col.prop(tree, "use_groupnode_buffer") col.prop(tree, "use_two_pass") col.prop(tree, "use_viewer_border") - col.separator() + + col = layout.column() col.prop(snode, "use_auto_render") diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index 7740188a700..00e82f83685 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -2423,7 +2423,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel): ({"property": "use_new_curves_tools"}, ("blender/blender/issues/68981", "#68981")), ({"property": "use_new_point_cloud_type"}, ("blender/blender/issues/75717", "#75717")), ({"property": "use_sculpt_texture_paint"}, ("blender/blender/issues/96225", "#96225")), - ({"property": "use_full_frame_compositor"}, ("blender/blender/issues/88150", "#88150")), + ({"property": "use_experimental_compositors"}, ("blender/blender/issues/88150", "#88150")), ({"property": "enable_eevee_next"}, ("blender/blender/issues/93220", "#93220")), ({"property": "enable_workbench_next"}, ("blender/blender/issues/101619", "#101619")), ({"property": "use_grease_pencil_version3"}, ("blender/blender/projects/40", "Grease Pencil 3.0")), diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index 2d405cc1ca0..d547bd688e5 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -11,6 +11,8 @@ extern "C" { #endif +struct Render; + /* Keep ascii art. */ /* clang-format off */ @@ -294,6 +296,9 @@ extern "C" { * It can be executed during editing (blenkernel/node.cc) or rendering * (renderer/pipeline.c) * + * \param render: [struct Render] + * Render instance for GPU context. + * * \param render_data: [struct RenderData] * Render data for this composite, this won't always belong to a scene. * @@ -326,7 +331,8 @@ extern "C" { */ /* clang-format off */ -void COM_execute(RenderData *render_data, +void COM_execute(Render *render, + RenderData *render_data, Scene *scene, bNodeTree *node_tree, bool rendering, diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc index b727b4d5bb4..fbe2018487a 100644 --- a/source/blender/compositor/intern/COM_compositor.cc +++ b/source/blender/compositor/intern/COM_compositor.cc @@ -14,6 +14,8 @@ #include "COM_WorkScheduler.h" #include "COM_compositor.h" +#include "RE_compositor.hh" + static struct { bool is_initialized = false; ThreadMutex mutex; @@ -47,7 +49,8 @@ static void compositor_reset_node_tree_status(bNodeTree *node_tree) node_tree->runtime->stats_draw(node_tree->runtime->sdh, IFACE_("Compositing")); } -void COM_execute(RenderData *render_data, +void COM_execute(Render *render, + RenderData *render_data, Scene *scene, bNodeTree *node_tree, bool rendering, @@ -73,26 +76,41 @@ void COM_execute(RenderData *render_data, compositor_init_node_previews(render_data, node_tree); compositor_reset_node_tree_status(node_tree); - /* Initialize workscheduler. */ - const bool use_opencl = (node_tree->flag & NTREE_COM_OPENCL) != 0; - blender::compositor::WorkScheduler::initialize(use_opencl, BKE_render_num_threads(render_data)); + if (U.experimental.use_full_frame_compositor && + node_tree->execution_mode == NTREE_EXECUTION_MODE_REALTIME) + { + /* Realtime GPU compositer. */ - /* Execute. */ - const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering; - if (twopass) { - blender::compositor::ExecutionSystem fast_pass( - render_data, scene, node_tree, rendering, true, view_name); - fast_pass.execute(); - - if (node_tree->runtime->test_break(node_tree->runtime->tbh)) { - BLI_mutex_unlock(&g_compositor.mutex); - return; - } + /* TODO: add persistence and depsgraph updates for better performance. */ + blender::render::RealtimeCompositor compositer( + *render, *scene, *render_data, *node_tree, rendering, view_name); + compositer.execute(); } + else { + /* Tiled and Full Frame compositers. */ - blender::compositor::ExecutionSystem system( - render_data, scene, node_tree, rendering, false, view_name); - system.execute(); + /* Initialize workscheduler. */ + const bool use_opencl = (node_tree->flag & NTREE_COM_OPENCL) != 0; + blender::compositor::WorkScheduler::initialize(use_opencl, + BKE_render_num_threads(render_data)); + + /* Execute. */ + const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering; + if (twopass) { + blender::compositor::ExecutionSystem fast_pass( + render_data, scene, node_tree, rendering, true, view_name); + fast_pass.execute(); + + if (node_tree->runtime->test_break(node_tree->runtime->tbh)) { + BLI_mutex_unlock(&g_compositor.mutex); + return; + } + } + + blender::compositor::ExecutionSystem system( + render_data, scene, node_tree, rendering, false, view_name); + system.execute(); + } BLI_mutex_unlock(&g_compositor.mutex); } diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index c2227545e8f..f26627b29cc 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -9,6 +9,7 @@ set(INC ../../blenkernel ../../blenlib ../../blentranslation + ../../draw ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index 277ddcb1075..79902db4c62 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -3327,6 +3327,12 @@ static bool realtime_compositor_is_in_use(const bContext &context) return false; } + if (U.experimental.use_full_frame_compositor && + scene->nodetree->execution_mode == NTREE_EXECUTION_MODE_REALTIME) + { + return true; + } + const Main *main = CTX_data_main(&context); LISTBASE_FOREACH (const bScreen *, screen, &main->screens) { LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) { diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 663ccc095a0..0c4f438952a 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -95,6 +95,8 @@ struct CompoJob { /* Evaluated state/ */ Depsgraph *compositor_depsgraph; bNodeTree *localtree; + /* Render instance. */ + Render *re; /* Jon system integration. */ const bool *stop; bool *do_update; @@ -239,6 +241,9 @@ static void compo_initjob(void *cjv) if (cj->recalc_flags) { compo_tag_output_nodes(cj->localtree, cj->recalc_flags); } + + cj->re = RE_NewSceneRender(scene); + RE_gl_context_create(cj->re); } /* Called before redraw notifiers, it moves finished previews over. */ @@ -286,17 +291,19 @@ static void compo_startjob(void *cjv, BKE_callback_exec_id(cj->bmain, &scene->id, BKE_CB_EVT_COMPOSITE_PRE); if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) { - ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, ""); + ntreeCompositExecTree(cj->re, cj->scene, ntree, &cj->scene->r, false, true, ""); } else { LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) { if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) { continue; } - ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, srv->name); + ntreeCompositExecTree(cj->re, cj->scene, ntree, &cj->scene->r, false, true, srv->name); } } + RE_gl_context_destroy(cj->re); + ntree->runtime->test_break = nullptr; ntree->runtime->stats_draw = nullptr; ntree->runtime->progress = nullptr; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4882a721bb6..fecb977d067 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -684,6 +684,7 @@ typedef struct bNodeTree { typedef enum eNodeTreeExecutionMode { NTREE_EXECUTION_MODE_TILED = 0, NTREE_EXECUTION_MODE_FULL_FRAME = 1, + NTREE_EXECUTION_MODE_REALTIME = 2, } eNodeTreeExecutionMode; typedef enum eNodeTreeRuntimeFlag { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d6c6d595a3e..18bac5e2f50 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -136,6 +136,11 @@ static const EnumPropertyItem rna_enum_execution_mode_items[] = { 0, "Full Frame", "Composites full image result as fast as possible"}, + {NTREE_EXECUTION_MODE_REALTIME, + "REALTIME", + 0, + "Realtime GPU", + "Use GPU accelerated compositing with more limited functionality"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index ab37cd10f4a..ea0e960b047 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6650,12 +6650,13 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) RNA_def_property_ui_text( prop, "New Point Cloud Type", "Enable the new point cloud type in the ui"); - prop = RNA_def_property(srna, "use_full_frame_compositor", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "use_experimental_compositors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "use_full_frame_compositor", 1); - RNA_def_property_ui_text(prop, - "Full Frame Compositor", - "Enable compositor full frame execution mode option (no tiling, " - "reduces execution time and memory usage)"); + RNA_def_property_ui_text( + prop, + "Experimental Compositors", + "Enable compositor full frame and realtime GPU execution mode options (no tiling, " + "reduces execution time and memory usage)"); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop = RNA_def_property(srna, "use_new_curves_tools", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 4285aaa01e4..83df048f7ec 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -14,6 +14,11 @@ extern "C" { #endif +struct Scene; +struct RenderData; +struct Render; +struct ViewLayer; + extern struct bNodeTreeType *ntreeType_Composite; void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node); @@ -27,7 +32,8 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index); void register_node_type_cmp_custom_group(bNodeType *ntype); -void ntreeCompositExecTree(struct Scene *scene, +void ntreeCompositExecTree(struct Render *render, + struct Scene *scene, struct bNodeTree *ntree, struct RenderData *rd, bool rendering, diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index 0e2a722dcc5..2c5711f3522 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -171,7 +171,8 @@ void register_node_tree_type_cmp() ntreeTypeAdd(tt); } -void ntreeCompositExecTree(Scene *scene, +void ntreeCompositExecTree(Render *render, + Scene *scene, bNodeTree *ntree, RenderData *rd, bool rendering, @@ -179,7 +180,7 @@ void ntreeCompositExecTree(Scene *scene, const char *view_name) { #ifdef WITH_COMPOSITOR_CPU - COM_execute(rd, scene, ntree, rendering, view_name); + COM_execute(render, rd, scene, ntree, rendering, view_name); #else UNUSED_VARS(scene, ntree, rd, rendering, view_name); #endif diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt index a7b2c84d3c2..c141d3c6fca 100644 --- a/source/blender/render/CMakeLists.txt +++ b/source/blender/render/CMakeLists.txt @@ -9,9 +9,12 @@ set(INC ../blenkernel ../blenlib ../blentranslation + ../compositor/realtime_compositor + ../compositor/realtime_compositor/cached_resources ../depsgraph ../draw ../gpu + ../gpu/intern ../imbuf ../makesdna ../makesrna @@ -30,6 +33,7 @@ set(INC_SYS set(SRC intern/bake.cc + intern/compositor.cc intern/engine.cc intern/initrender.cc intern/multires_bake.cc @@ -42,6 +46,7 @@ set(SRC intern/zbuf.c RE_bake.h + RE_compositor.hh RE_engine.h RE_multires_bake.h RE_pipeline.h @@ -56,6 +61,7 @@ set(SRC ) set(LIB + bf_realtime_compositor ) if(WITH_PYTHON) diff --git a/source/blender/render/RE_compositor.hh b/source/blender/render/RE_compositor.hh new file mode 100644 index 00000000000..e11c4e28f76 --- /dev/null +++ b/source/blender/render/RE_compositor.hh @@ -0,0 +1,59 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +struct bNodeTree; +struct Depsgraph; +struct Render; +struct RenderData; +struct Scene; + +namespace blender { + +namespace realtime_compositor { +class Evaluator; +} + +namespace render { +class Context; +class TexturePool; + +/* ------------------------------------------------------------------------------------------------ + * Render Realtime Compositor + * + * Implementation of the compositor for final rendering, as opposed to the viewport compositor + * that is part of the draw manager. The input and output of this is pre-existing RenderResult + * buffers in scenes, that are uploaded to and read back from the GPU. */ + +class RealtimeCompositor { + private: + /* Render instance for GPU context to run compositor in. */ + Render &render_; + + std::unique_ptr texture_pool_; + std::unique_ptr context_; + std::unique_ptr evaluator_; + + public: + RealtimeCompositor(Render &render, + const Scene &scene, + const RenderData &render_data, + const bNodeTree &node_tree, + const bool use_file_output, + const char *view_name); + + ~RealtimeCompositor(); + + /* Evaluate the compositor and output to the scene render result. */ + void execute(); + + /* If the compositor node tree changed, reset the evaluator. */ + void update(const Depsgraph *depsgraph); +}; + +} // namespace render +} // namespace blender diff --git a/source/blender/render/intern/compositor.cc b/source/blender/render/intern/compositor.cc new file mode 100644 index 00000000000..1b5bbf4fcfe --- /dev/null +++ b/source/blender/render/intern/compositor.cc @@ -0,0 +1,300 @@ +/* SPDX-FileCopyrightText: 2023 Blender Foundation + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_threads.h" +#include "BLI_vector.hh" + +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_node.hh" +#include "BKE_scene.h" + +#include "DRW_engine.h" + +#include "COM_context.hh" +#include "COM_evaluator.hh" + +#include "RE_compositor.hh" +#include "RE_pipeline.h" + +namespace blender::render { + +/* Render Texture Pool */ + +class TexturePool : public realtime_compositor::TexturePool { + public: + Vector textures_; + + virtual ~TexturePool() + { + for (GPUTexture *texture : textures_) { + GPU_texture_free(texture); + } + } + + GPUTexture *allocate_texture(int2 size, eGPUTextureFormat format) override + { + /* TODO: should share pool with draw manager. It needs some globals + * initialization figured out there first. */ +#if 0 + DrawEngineType *owner = (DrawEngineType *)this; + return DRW_texture_pool_query_2d(size.x, size.y, format, owner); +#else + GPUTexture *texture = GPU_texture_create_2d( + "compositor_texture_pool", size.x, size.y, 1, format, GPU_TEXTURE_USAGE_GENERAL, NULL); + textures_.append(texture); + return texture; +#endif + } +}; + +/* Render Context */ + +class Context : public realtime_compositor::Context { + private: + /* Input data. */ + const Scene &scene_; + const RenderData &render_data_; + const bNodeTree &node_tree_; + const bool use_file_output_; + const char *view_name_; + + /* Output combined texture. */ + GPUTexture *output_texture_ = nullptr; + + public: + Context(const Scene &scene, + const RenderData &render_data, + const bNodeTree &node_tree, + const bool use_file_output, + const char *view_name, + TexturePool &texture_pool) + : realtime_compositor::Context(texture_pool), + scene_(scene), + render_data_(render_data), + node_tree_(node_tree), + use_file_output_(use_file_output), + view_name_(view_name) + { + } + + virtual ~Context() + { + GPU_texture_free(output_texture_); + } + + const bNodeTree &get_node_tree() const override + { + return node_tree_; + } + + bool use_file_output() const override + { + return use_file_output_; + } + + bool use_texture_color_management() const override + { + return BKE_scene_check_color_management_enabled(&scene_); + } + + const RenderData &get_render_data() const override + { + return render_data_; + } + + int2 get_render_size() const override + { + int width, height; + BKE_render_resolution(&render_data_, false, &width, &height); + return int2(width, height); + } + + rcti get_compositing_region() const override + { + const int2 render_size = get_render_size(); + const rcti render_region = rcti{0, render_size.x, 0, render_size.y}; + + return render_region; + } + + GPUTexture *get_output_texture() override + { + /* TODO: support outputting for viewers and previews. + * TODO: just a temporary hack, needs to get stored in RenderResult, + * once that supports GPU buffers. */ + if (output_texture_ == nullptr) { + const int2 size = get_render_size(); + output_texture_ = GPU_texture_create_2d("compositor_output_texture", + size.x, + size.y, + 1, + GPU_RGBA16F, + GPU_TEXTURE_USAGE_GENERAL, + NULL); + } + + return output_texture_; + } + + GPUTexture *get_input_texture(int view_layer_id, const char *pass_name) override + { + /* TODO: eventually this should get cached on the RenderResult itself when + * it supports storing GPU buffers, for faster updates. But will also need + * some eviction strategy to avoid too much GPU memory usage. */ + Render *re = RE_GetSceneRender(&scene_); + RenderResult *rr = nullptr; + GPUTexture *input_texture = nullptr; + + if (re) { + rr = RE_AcquireResultRead(re); + } + + if (rr) { + ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene_.view_layers, view_layer_id); + if (view_layer) { + RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name); + if (rl) { + RenderPass *rpass = (RenderPass *)BLI_findstring( + &rl->passes, pass_name, offsetof(RenderPass, name)); + + if (rpass && rpass->buffer.data) { + const int2 size(rl->rectx, rl->recty); + + if (rpass->channels == 1) { + input_texture = texture_pool().acquire_float(size); + if (input_texture) { + GPU_texture_update(input_texture, GPU_DATA_FLOAT, rpass->buffer.data); + } + } + else if (rpass->channels == 3) { + input_texture = texture_pool().acquire_color(size); + if (input_texture) { + /* TODO: conversion could be done as part of GPU upload somehow? */ + const float *rgb_buffer = rpass->buffer.data; + Vector rgba_buffer(4 * size.x * size.y); + for (size_t i = 0; (size_t)size.x * (size_t)size.y; i++) { + rgba_buffer[i * 4 + 0] = rgb_buffer[i * 3 + 0]; + rgba_buffer[i * 4 + 1] = rgb_buffer[i * 3 + 1]; + rgba_buffer[i * 4 + 2] = rgb_buffer[i * 3 + 2]; + rgba_buffer[i * 4 + 3] = 1.0f; + } + GPU_texture_update(input_texture, GPU_DATA_FLOAT, rgba_buffer.data()); + } + } + else if (rpass->channels == 4) { + input_texture = texture_pool().acquire_color(size); + if (input_texture) { + GPU_texture_update(input_texture, GPU_DATA_FLOAT, rpass->buffer.data); + } + } + } + } + } + } + + if (re) { + RE_ReleaseResult(re); + re = nullptr; + } + + return input_texture; + } + + StringRef get_view_name() override + { + return view_name_; + } + + void set_info_message(StringRef /* message */) const override + { + /* TODO: ignored for now. Currently only used to communicate incomplete node support + * which is already shown on the node itself. + * + * Perhaps this overall info message could be replaced by a boolean indicating + * incomplete support, and leave more specific message to individual nodes? */ + } + + IDRecalcFlag query_id_recalc_flag(ID *id) const override + { + /* TODO: implement? */ + return IDRecalcFlag(0); + } + + void output_to_render_result() + { + Render *re = RE_GetSceneRender(&scene_); + RenderResult *rr = RE_AcquireResultWrite(re); + + if (rr) { + RenderView *rv = RE_RenderViewGetByName(rr, view_name_); + + GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); + float *output_buffer = (float *)GPU_texture_read(output_texture_, GPU_DATA_FLOAT, 0); + + if (output_buffer) { + RE_RenderBuffer_assign_data(&rv->combined_buffer, output_buffer); + } + + /* TODO: z-buffer output. */ + + rr->have_combined = true; + } + + if (re) { + RE_ReleaseResult(re); + re = nullptr; + } + + Image *image = BKE_image_ensure_viewer(G.main, IMA_TYPE_R_RESULT, "Render Result"); + BKE_image_partial_update_mark_full_update(image); + BLI_thread_lock(LOCK_DRAW_IMAGE); + BKE_image_signal(G.main, image, nullptr, IMA_SIGNAL_FREE); + BLI_thread_unlock(LOCK_DRAW_IMAGE); + } +}; + +/* Render Realtime Compositor */ + +RealtimeCompositor::RealtimeCompositor(Render &render, + const Scene &scene, + const RenderData &render_data, + const bNodeTree &node_tree, + const bool use_file_output, + const char *view_name) + : render_(render) +{ + /* Create resources with GPU context enabled. */ + DRW_render_context_enable(&render_); + texture_pool_ = std::make_unique(); + context_ = std::make_unique( + scene, render_data, node_tree, use_file_output, view_name, *texture_pool_); + evaluator_ = std::make_unique(*context_); + DRW_render_context_disable(&render_); +} + +RealtimeCompositor::~RealtimeCompositor() +{ + /* Free resources with GPU context enabled. */ + DRW_render_context_enable(&render_); + evaluator_.reset(); + context_.reset(); + texture_pool_.reset(); + DRW_render_context_disable(&render_); +} + +void RealtimeCompositor::execute() +{ + DRW_render_context_enable(&render_); + evaluator_->evaluate(); + context_->output_to_render_result(); + DRW_render_context_disable(&render_); +} + +void RealtimeCompositor::update(const Depsgraph *depsgraph) +{ + /* TODO: implement */ +} + +} // namespace blender::render diff --git a/source/blender/render/intern/pipeline.cc b/source/blender/render/intern/pipeline.cc index 53896aaeea8..db8e1da92c8 100644 --- a/source/blender/render/intern/pipeline.cc +++ b/source/blender/render/intern/pipeline.cc @@ -1194,7 +1194,7 @@ static void do_render_compositor(Render *re) LISTBASE_FOREACH (RenderView *, rv, &re->result->views) { ntreeCompositExecTree( - re->pipeline_scene_eval, ntree, &re->r, true, G.background == 0, rv->name); + re, re->pipeline_scene_eval, ntree, &re->r, true, G.background == 0, rv->name); } ntree->runtime->stats_draw = nullptr;