Blender V5.0
compositor_engine.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 "BLI_bounds.hh"
6#include "BLI_listbase.h"
8#include "BLI_string_ref.hh"
9#include "BLI_utildefines.h"
10
11#include "BLT_translation.hh"
12
13#include "DNA_ID.h"
14#include "DNA_ID_enums.h"
15#include "DNA_scene_types.h"
16#include "DNA_vec_types.h"
17#include "DNA_view3d_types.h"
18
20
21#include "ED_view3d.hh"
22
23#include "DRW_gpu_wrapper.hh"
24#include "DRW_render.hh"
25
26#include "COM_context.hh"
27#include "COM_domain.hh"
28#include "COM_evaluator.hh"
29#include "COM_result.hh"
30
31#include "GPU_context.hh"
32#include "GPU_state.hh"
33#include "GPU_texture.hh"
34
35#include "draw_view_data.hh"
36
37#include "compositor_engine.h" /* Own include. */
38
40
42 private:
43 /* A pointer to the info message of the compositor engine. This is a char array of size
44 * GPU_INFO_SIZE. The message is cleared prior to updating or evaluating the compositor. */
45 char *info_message_;
46 const Scene *scene_;
47
48 public:
49 Context(char *info_message) : compositor::Context(), info_message_(info_message) {}
50
51 void set_scene(const Scene *scene)
52 {
53 scene_ = scene;
54 }
55
56 const Scene &get_scene() const override
57 {
58 return *scene_;
59 }
60
61 const bNodeTree &get_node_tree() const override
62 {
63 return *scene_->compositing_node_group;
64 }
65
66 bool use_gpu() const override
67 {
68 return true;
69 }
70
75
76 /* The viewport compositor does not support viewer outputs, so treat viewers as composite
77 * outputs. */
79 {
80 return true;
81 }
82
83 /* We limit the compositing region to the camera region if in camera view, while we use the
84 * entire viewport otherwise. We also use the entire viewport when doing viewport rendering since
85 * the viewport is already the camera region in that case. */
87 {
88 const DRWContext *draw_ctx = DRW_context_get();
89 const int2 viewport_size = int2(draw_ctx->viewport_size_get());
90 const Bounds<int2> render_region = Bounds<int2>(int2(0), viewport_size);
91
92 if (draw_ctx->rv3d->persp != RV3D_CAMOB || draw_ctx->is_viewport_image_render()) {
93 return render_region;
94 }
95
96 rctf camera_border;
98 draw_ctx->depsgraph,
99 draw_ctx->region,
100 draw_ctx->v3d,
101 draw_ctx->rv3d,
102 false,
103 &camera_border);
104
105 const Bounds<int2> camera_region = Bounds<int2>(
106 int2(int(camera_border.xmin), int(camera_border.ymin)),
107 int2(int(camera_border.xmax), int(camera_border.ymax)));
108
109 return blender::bounds::intersect(render_region, camera_region)
110 .value_or(Bounds<int2>(int2(0)));
111 }
112
114 {
117 result.wrap_external(DRW_context_get()->viewport_texture_list_get()->color);
118 return result;
119 }
120
122 bool /*is_data*/,
123 compositor::ResultPrecision /*precision*/) override
124 {
127 result.wrap_external(DRW_context_get()->viewport_texture_list_get()->color);
128 return result;
129 }
130
131 compositor::Result get_pass(const Scene *scene, int view_layer_index, const char *name) override
132 {
133 /* Blender aliases the Image pass name to be the Combined pass, so we return the combined pass
134 * in that case. */
135 const char *pass_name = StringRef(name) == "Image" ? "Combined" : name;
136
137 const Scene *original_scene = DEG_get_original(scene_);
138 if (DEG_get_original(scene) != original_scene) {
139 return compositor::Result(*this);
140 }
141
142 ViewLayer *view_layer = static_cast<ViewLayer *>(
143 BLI_findlink(&original_scene->view_layers, view_layer_index));
144 if (StringRef(view_layer->name) != DRW_context_get()->view_layer->name) {
145 return compositor::Result(*this);
146 }
147
148 /* The combined pass is a special case where we return the viewport color texture, because it
149 * includes Grease Pencil objects since GP is drawn using their own engine. */
150 if (STREQ(pass_name, RE_PASSNAME_COMBINED)) {
152 compositor::Result pass = compositor::Result(*this, GPU_texture_format(combined_texture));
153 pass.wrap_external(combined_texture);
154 return pass;
155 }
156
157 /* Return the pass that was written by the engine if such pass was found. */
158 gpu::Texture *pass_texture = DRW_viewport_pass_texture_get(pass_name).gpu_texture();
159 if (pass_texture) {
160 compositor::Result pass = compositor::Result(*this, GPU_texture_format(pass_texture));
161 pass.wrap_external(pass_texture);
162 return pass;
163 }
164
165 return compositor::Result(*this);
166 }
167
169 {
170 if (name == "Image") {
171 return this->get_pass(&this->get_scene(), 0, name.data());
172 }
173
175 }
176
177 StringRef get_view_name() const override
178 {
179 const SceneRenderView *view = static_cast<SceneRenderView *>(
180 BLI_findlink(&get_render_data().views, DRW_context_get()->v3d->multiview_eye));
181 return view->name;
182 }
183
196
197 void set_info_message(StringRef message) const override
198 {
199 message.copy_utf8_truncated(info_message_, GPU_INFO_SIZE);
200 }
201};
202
203class Instance : public DrawEngine {
204 private:
205 Context context_;
206
207 public:
208 Instance() : context_(this->info) {}
209
211 {
212 return "Compositor";
213 }
214
215 void init() final {};
216 void begin_sync() final {};
218 blender::draw::Manager & /*manager*/) final {};
219 void end_sync() final {};
220
221 void draw(Manager & /*manager*/) final
222 {
224
225#if defined(__APPLE__)
227 /* NOTE(Metal): Isolate Compositor compute work in individual command buffer to improve
228 * workload scheduling. When expensive compositor nodes are in the graph, these can stall out
229 * the GPU for extended periods of time and sub-optimally schedule work for execution. */
230 GPU_flush();
231 }
232#endif
233
234 /* Execute Compositor render commands. */
235 {
236 context_.set_scene(DRW_context_get()->scene);
237 context_.set_info_message("");
238 compositor::Evaluator evaluator(context_);
239 evaluator.evaluate();
240 }
241
242#if defined(__APPLE__)
243 /* NOTE(Metal): Following previous flush to break command stream, with compositor command
244 * buffers potentially being heavy, we avoid issuing subsequent commands until compositor work
245 * has completed. If subsequent work is prematurely queued up, the subsequent command buffers
246 * will be blocked behind compositor work and may trigger a command buffer time-out error. As a
247 * result, we should wait for compositor work to complete.
248 *
249 * This is not an efficient approach for peak performance, but a catch-all to prevent command
250 * buffer failure, until the offending cases can be resolved. */
252 GPU_finish();
253 }
254#endif
256 }
257};
258
260{
261 return new Instance();
262}
263
264} // namespace blender::draw::compositor_engine
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define final(a, b, c)
Definition BLI_hash.h:19
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define STREQ(a, b)
T * DEG_get_original(T *id)
ID and Library types, which are fundamental for SDNA.
Enumerations for DNA_ID.h.
#define RE_PASSNAME_COMBINED
@ SCE_COMPOSITOR_PRECISION_FULL
@ SCE_COMPOSITOR_PRECISION_AUTO
@ RV3D_CAMOB
void DRW_submission_end()
void DRW_submission_start()
void ED_view3d_calc_camera_border(const Scene *scene, const Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const RegionView3D *rv3d, bool no_shift, rctf *r_viewborder)
static AppView * view
GPUBackendType GPU_backend_get_type()
void GPU_flush()
Definition gpu_state.cc:305
void GPU_finish()
Definition gpu_state.cc:310
blender::gpu::TextureFormat GPU_texture_format(const blender::gpu::Texture *texture)
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
constexpr const char * data() const
Result create_result(ResultType type, ResultPrecision precision)
virtual const RenderData & get_render_data() const
void wrap_external(blender::gpu::Texture *texture)
Definition result.cc:584
gpu::Texture * gpu_texture()
void set_info_message(StringRef message) const override
compositor::Result get_pass(const Scene *scene, int view_layer_index, const char *name) override
compositor::ResultPrecision get_precision() const override
const bNodeTree & get_node_tree() const override
const Scene & get_scene() const override
compositor::Result get_viewer_output(compositor::Domain, bool, compositor::ResultPrecision) override
compositor::OutputTypes needed_outputs() const override
Bounds< int2 > get_compositing_region() const override
compositor::Result get_output(compositor::Domain) override
compositor::Result get_input(StringRef name) override
bool treat_viewer_as_compositor_output() const override
void object_sync(blender::draw::ObjectRef &, blender::draw::Manager &) final
const DRWContext * DRW_context_get()
blender::draw::TextureFromPool & DRW_viewport_pass_texture_get(const char *pass_name)
#define GPU_INFO_SIZE
std::optional< Bounds< T > > intersect(const Bounds< T > &a, const Bounds< T > &b)
VecBase< int32_t, 2 > int2
const char * name
View3D * v3d
Depsgraph * depsgraph
RegionView3D * rv3d
blender::float2 viewport_size_get() const
Scene * scene
bool is_viewport_image_render() const
ARegion * region
DefaultTextureList * viewport_texture_list_get() const
blender::gpu::Texture * color
char info[GPU_INFO_SIZE]
Definition DRW_render.hh:72
ListBase view_layers
char name[64]
float xmax
float xmin
float ymax
float ymin