Blender V4.5
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_listbase.h"
7#include "BLI_rect.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_->nodetree;
64 }
65
66 bool use_gpu() const override
67 {
68 return true;
69 }
70
76
81
82 /* The viewport compositor does not support viewer outputs, so treat viewers as composite
83 * outputs. */
85 {
86 return true;
87 }
88
89 const RenderData &get_render_data() const override
90 {
91 return scene_->r;
92 }
93
94 int2 get_render_size() const override
95 {
96 return int2(DRW_context_get()->viewport_size_get());
97 }
98
99 /* We limit the compositing region to the camera region if in camera view, while we use the
100 * entire viewport otherwise. We also use the entire viewport when doing viewport rendering since
101 * the viewport is already the camera region in that case. */
103 {
104 const DRWContext *draw_ctx = DRW_context_get();
105 const int2 viewport_size = int2(draw_ctx->viewport_size_get());
106 const rcti render_region = rcti{0, viewport_size.x, 0, viewport_size.y};
107
108 if (draw_ctx->rv3d->persp != RV3D_CAMOB || draw_ctx->is_viewport_image_render()) {
109 return render_region;
110 }
111
112 rctf camera_border;
114 draw_ctx->depsgraph,
115 draw_ctx->region,
116 draw_ctx->v3d,
117 draw_ctx->rv3d,
118 false,
119 &camera_border);
120
121 rcti camera_region;
122 BLI_rcti_rctf_copy_floor(&camera_region, &camera_border);
123
124 rcti visible_camera_region;
125 BLI_rcti_isect(&render_region, &camera_region, &visible_camera_region);
126
127 return visible_camera_region;
128 }
129
131 {
134 result.wrap_external(DRW_context_get()->viewport_texture_list_get()->color);
135 return result;
136 }
137
139 bool /*is_data*/,
140 compositor::ResultPrecision /*precision*/) override
141 {
144 result.wrap_external(DRW_context_get()->viewport_texture_list_get()->color);
145 return result;
146 }
147
148 compositor::Result get_pass(const Scene *scene, int view_layer_index, const char *name) override
149 {
150 /* Blender aliases the Image pass name to be the Combined pass, so we return the combined pass
151 * in that case. */
152 const char *pass_name = StringRef(name) == "Image" ? "Combined" : name;
153
154 const Scene *original_scene = DEG_get_original(scene_);
155 if (DEG_get_original(scene) != original_scene) {
156 return compositor::Result(*this);
157 }
158
159 ViewLayer *view_layer = static_cast<ViewLayer *>(
160 BLI_findlink(&original_scene->view_layers, view_layer_index));
161 if (StringRef(view_layer->name) != DRW_context_get()->view_layer->name) {
162 return compositor::Result(*this);
163 }
164
165 /* The combined pass is a special case where we return the viewport color texture, because it
166 * includes Grease Pencil objects since GP is drawn using their own engine. */
167 if (STREQ(pass_name, RE_PASSNAME_COMBINED)) {
168 GPUTexture *combined_texture = DRW_context_get()->viewport_texture_list_get()->color;
169 compositor::Result pass = compositor::Result(*this, GPU_texture_format(combined_texture));
170 pass.wrap_external(combined_texture);
171 return pass;
172 }
173
174 /* Return the pass that was written by the engine if such pass was found. */
175 GPUTexture *pass_texture = DRW_viewport_pass_texture_get(pass_name).gpu_texture();
176 if (pass_texture) {
177 compositor::Result pass = compositor::Result(*this, GPU_texture_format(pass_texture));
178 pass.wrap_external(pass_texture);
179 return pass;
180 }
181
182 return compositor::Result(*this);
183 }
184
185 StringRef get_view_name() const override
186 {
187 const SceneRenderView *view = static_cast<SceneRenderView *>(
188 BLI_findlink(&get_render_data().views, DRW_context_get()->v3d->multiview_eye));
189 return view->name;
190 }
191
204
205 void set_info_message(StringRef message) const override
206 {
207 message.copy_utf8_truncated(info_message_, GPU_INFO_SIZE);
208 }
209};
210
211class Instance : public DrawEngine {
212 private:
213 Context context_;
214
215 public:
216 Instance() : context_(this->info) {}
217
219 {
220 return "Compositor";
221 }
222
223 void init() final{};
226 blender::draw::Manager & /*manager*/) final{};
227 void end_sync() final{};
228
229 void draw(Manager & /*manager*/) final
230 {
232
233#if defined(__APPLE__)
235 /* NOTE(Metal): Isolate Compositor compute work in individual command buffer to improve
236 * workload scheduling. When expensive compositor nodes are in the graph, these can stall out
237 * the GPU for extended periods of time and sub-optimally schedule work for execution. */
238 GPU_flush();
239 }
240#endif
241
242 /* Execute Compositor render commands. */
243 {
244 context_.set_scene(DRW_context_get()->scene);
245 context_.set_info_message("");
246 compositor::Evaluator evaluator(context_);
247 evaluator.evaluate();
248 }
249
250#if defined(__APPLE__)
251 /* NOTE(Metal): Following previous flush to break command stream, with compositor command
252 * buffers potentially being heavy, we avoid issuing subsequent commands until compositor work
253 * has completed. If subsequent work is prematurely queued up, the subsequent command buffers
254 * will be blocked behind compositor work and may trigger a command buffer time-out error. As a
255 * result, we should wait for compositor work to complete.
256 *
257 * This is not an efficient approach for peak performance, but a catch-all to prevent command
258 * buffer failure, until the offending cases can be resolved. */
260 GPU_finish();
261 }
262#endif
264 }
265};
266
268{
269 return new Instance();
270}
271
272} // 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
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src)
bool BLI_rcti_isect(const struct rcti *src1, const struct rcti *src2, struct rcti *dest)
#define STREQ(a, b)
T * DEG_get_original(T *id)
ID and Library types, which are fundamental for SDNA.
Enumerations for DNA_ID.h.
eCompositorDenoiseQaulity
#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
eGPUBackendType GPU_backend_get_type()
void GPU_flush()
Definition gpu_state.cc:305
void GPU_finish()
Definition gpu_state.cc:310
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
void copy_utf8_truncated(char *dst, int64_t dst_size) const
Definition string_ref.cc:28
Result create_result(ResultType type, ResultPrecision precision)
void wrap_external(GPUTexture *texture)
Definition result.cc:448
compositor::Result get_viewer_output_result(compositor::Domain, bool, compositor::ResultPrecision) override
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::OutputTypes needed_outputs() const override
const RenderData & get_render_data() const override
compositor::Result get_output_result() override
eCompositorDenoiseQaulity get_denoise_quality() 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
#define this
VecBase< int32_t, 2 > int2
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
char info[GPU_INFO_SIZE]
Definition DRW_render.hh:70
int compositor_denoise_preview_quality
ListBase view_layers
char name[64]