Blender V4.3
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_camera_types.h"
16#include "DNA_object_types.h"
17#include "DNA_scene_types.h"
18#include "DNA_vec_types.h"
19#include "DNA_view3d_types.h"
20
22
23#include "ED_view3d.hh"
24
25#include "DRW_gpu_wrapper.hh"
26#include "DRW_render.hh"
27
28#include "COM_context.hh"
29#include "COM_domain.hh"
30#include "COM_evaluator.hh"
31#include "COM_result.hh"
32#include "COM_texture_pool.hh"
33
34#include "GPU_context.hh"
35#include "GPU_texture.hh"
36
37#include "compositor_engine.h" /* Own include. */
38
40
42 public:
43 GPUTexture *allocate_texture(int2 size, eGPUTextureFormat format) override
44 {
45 DrawEngineType *owner = (DrawEngineType *)this;
46 return DRW_texture_pool_query_2d(size.x, size.y, format, owner);
47 }
48};
49
51 private:
52 /* A pointer to the info message of the compositor engine. This is a char array of size
53 * GPU_INFO_SIZE. The message is cleared prior to updating or evaluating the compositor. */
54 char *info_message_;
55
56 public:
58 : realtime_compositor::Context(texture_pool), info_message_(info_message)
59 {
60 }
61
62 const Scene &get_scene() const override
63 {
65 }
66
67 const bNodeTree &get_node_tree() const override
68 {
70 }
71
72 bool use_gpu() const override
73 {
74 return true;
75 }
76
77 bool use_file_output() const override
78 {
79 return false;
80 }
81
82 bool should_compute_node_previews() const override
83 {
84 return false;
85 }
86
87 /* The viewport compositor doesn't really support the composite output, it only displays the
88 * viewer output in the viewport. Settings this to false will make the compositor use the
89 * composite output as fallback viewer if no other viewer exists. */
90 bool use_composite_output() const override
91 {
92 return false;
93 }
94
95 const RenderData &get_render_data() const override
96 {
97 return DRW_context_state_get()->scene->r;
98 }
99
100 int2 get_render_size() const override
101 {
103 }
104
105 /* We limit the compositing region to the camera region if in camera view, while we use the
106 * entire viewport otherwise. We also use the entire viewport when doing viewport rendering since
107 * the viewport is already the camera region in that case. */
109 {
110 const int2 viewport_size = int2(float2(DRW_viewport_size_get()));
111 const rcti render_region = rcti{0, viewport_size.x, 0, viewport_size.y};
112
114 {
115 return render_region;
116 }
117
118 rctf camera_border;
121 DRW_context_state_get()->region,
123 DRW_context_state_get()->rv3d,
124 false,
125 &camera_border);
126
127 rcti camera_region;
128 BLI_rcti_rctf_copy_floor(&camera_region, &camera_border);
129
130 rcti visible_camera_region;
131 BLI_rcti_isect(&render_region, &camera_region, &visible_camera_region);
132
133 return visible_camera_region;
134 }
135
143
154
155 GPUTexture *get_input_texture(const Scene *scene, int view_layer, const char *pass_name) override
156 {
157 if (DEG_get_original_id(const_cast<ID *>(&scene->id)) !=
159 {
160 return nullptr;
161 }
162
163 if (view_layer != 0) {
164 return nullptr;
165 }
166
167 /* The combined pass is a special case where we return the viewport color texture, because it
168 * includes Grease Pencil objects since GP is drawn using their own engine. */
169 if (STREQ(pass_name, RE_PASSNAME_COMBINED)) {
171 }
172
173 /* Return the pass that was written by the engine if such pass was found. */
174 GPUTexture *pass_texture = DRW_viewport_pass_texture_get(pass_name).gpu_texture();
175 if (pass_texture) {
176 return pass_texture;
177 }
178
179 /* If no Z pass was found above, return the viewport depth as a fallback, which might be
180 * populated if overlays are enabled. */
181 if (STREQ(pass_name, RE_PASSNAME_Z)) {
183 }
184
185 return nullptr;
186 }
187
188 StringRef get_view_name() const override
189 {
190 const SceneRenderView *view = static_cast<SceneRenderView *>(
191 BLI_findlink(&get_render_data().views, DRW_context_state_get()->v3d->multiview_eye));
192 return view->name;
193 }
194
207
208 void set_info_message(StringRef message) const override
209 {
210 message.copy(info_message_, GPU_INFO_SIZE);
211 }
212
214 {
216 DrawData *draw_data = DRW_drawdata_ensure(id, owner, sizeof(DrawData), nullptr, nullptr);
217 IDRecalcFlag recalc_flag = IDRecalcFlag(draw_data->recalc);
218 draw_data->recalc = IDRecalcFlag(0);
219 return recalc_flag;
220 }
221};
222
223class Engine {
224 private:
225 TexturePool texture_pool_;
226 Context context_;
228 /* Stores the compositing region size at the time the last compositor evaluation happened. See
229 * the update_compositing_region_size method for more information. */
230 int2 last_compositing_region_size_;
231
232 public:
233 Engine(char *info_message)
234 : context_(texture_pool_, info_message),
235 evaluator_(context_),
236 last_compositing_region_size_(context_.get_compositing_region_size())
237 {
238 }
239
240 /* Update the compositing region size and evaluate the compositor. */
241 void draw()
242 {
244 evaluator_.evaluate();
245 }
246
247 /* If the size of the compositing region changed from the last time the compositor was evaluated,
248 * update the last compositor region size and reset the evaluator. That's because the evaluator
249 * compiles the node tree in a manner that is specifically optimized for the size of the
250 * compositing region. This should be called before evaluating the compositor. */
252 {
253 if (last_compositing_region_size_ == context_.get_compositing_region_size()) {
254 return;
255 }
256
257 last_compositing_region_size_ = context_.get_compositing_region_size();
258
259 evaluator_.reset();
260 }
261
262 /* If the compositor node tree changed, reset the evaluator. */
263 void update(const Depsgraph *depsgraph)
264 {
266 evaluator_.reset();
267 }
268 }
269};
270
271} // namespace blender::draw::compositor
272
273using namespace blender::draw::compositor;
274
284
285static void compositor_engine_init(void *data)
286{
287 COMPOSITOR_Data *compositor_data = static_cast<COMPOSITOR_Data *>(data);
288
289 if (!compositor_data->instance_data) {
290 compositor_data->instance_data = new Engine(compositor_data->info);
291 }
292}
293
294static void compositor_engine_free(void *instance_data)
295{
296 Engine *engine = static_cast<Engine *>(instance_data);
297 delete engine;
298}
299
300static void compositor_engine_draw(void *data)
301{
302 COMPOSITOR_Data *compositor_data = static_cast<COMPOSITOR_Data *>(data);
303
304#if defined(__APPLE__)
306 /* NOTE(Metal): Isolate Compositor compute work in individual command buffer to improve
307 * workload scheduling. When expensive compositor nodes are in the graph, these can stall out
308 * the GPU for extended periods of time and sub-optimally schedule work for execution. */
309 GPU_flush();
310 }
311#endif
312
313 /* Execute Compositor render commands. */
314 compositor_data->instance_data->draw();
315
316#if defined(__APPLE__)
317 /* NOTE(Metal): Following previous flush to break command stream, with compositor command
318 * buffers potentially being heavy, we avoid issuing subsequent commands until compositor work
319 * has completed. If subsequent work is prematurely queued up, the subsequent command buffers
320 * will be blocked behind compositor work and may trigger a command buffer time-out error. As a
321 * result, we should wait for compositor work to complete.
322 *
323 * This is not an efficient approach for peak performance, but a catch-all to prevent command
324 * buffer failure, until the offending cases can be resolved. */
326 GPU_finish();
327 }
328#endif
329}
330
331static void compositor_engine_update(void *data)
332{
333 COMPOSITOR_Data *compositor_data = static_cast<COMPOSITOR_Data *>(data);
334
335 /* Clear any info message that was set in a previous update. */
336 compositor_data->info[0] = '\0';
337
338 if (compositor_data->instance_data) {
340 }
341}
342
343extern "C" {
344
346
348 /*next*/ nullptr,
349 /*prev*/ nullptr,
350 /*idname*/ N_("Compositor"),
351 /*vedata_size*/ &compositor_data_size,
352 /*engine_init*/ &compositor_engine_init,
353 /*engine_free*/ nullptr,
354 /*instance_free*/ &compositor_engine_free,
355 /*cache_init*/ nullptr,
356 /*cache_populate*/ nullptr,
357 /*cache_finish*/ nullptr,
358 /*draw_scene*/ &compositor_engine_draw,
359 /*view_update*/ &compositor_engine_update,
360 /*id_update*/ nullptr,
361 /*render_to_image*/ nullptr,
362 /*store_metadata*/ nullptr,
363};
364}
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
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)
bool DEG_id_type_updated(const Depsgraph *depsgraph, short id_type)
ID * DEG_get_original_id(ID *id)
ID and Library types, which are fundamental for SDNA.
IDRecalcFlag
Definition DNA_ID.h:1016
Enumerations for DNA_ID.h.
@ ID_NT
Object is a sort of wrapper for general info.
#define RE_PASSNAME_COMBINED
@ SCE_COMPOSITOR_PRECISION_FULL
@ SCE_COMPOSITOR_PRECISION_AUTO
#define RE_PASSNAME_Z
@ RV3D_CAMOB
char DRWViewportEmptyList
Definition DRW_render.hh:97
#define DRW_VIEWPORT_DATA_SIZE(ty)
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)
eGPUBackendType GPU_backend_get_type()
void GPU_flush()
Definition gpu_state.cc:294
void GPU_finish()
Definition gpu_state.cc:299
eGPUTextureFormat
void copy(char *dst, int64_t dst_size) const
realtime_compositor::Result get_viewer_output_result(realtime_compositor::Domain, bool, realtime_compositor::ResultPrecision) override
bool should_compute_node_previews() const override
const bNodeTree & get_node_tree() const override
IDRecalcFlag query_id_recalc_flag(ID *id) const override
Context(realtime_compositor::TexturePool &texture_pool, char *info_message)
StringRef get_view_name() const override
const RenderData & get_render_data() const override
realtime_compositor::Result get_output_result() override
const Scene & get_scene() const override
rcti get_compositing_region() const override
bool use_composite_output() const override
realtime_compositor::ResultPrecision get_precision() const override
GPUTexture * get_input_texture(const Scene *scene, int view_layer, const char *pass_name) override
void set_info_message(StringRef message) const override
void update(const Depsgraph *depsgraph)
GPUTexture * allocate_texture(int2 size, eGPUTextureFormat format) override
Result create_result(ResultType type, ResultPrecision precision)
void wrap_external(GPUTexture *texture)
Definition result.cc:321
static const DrawEngineDataSize compositor_data_size
static void compositor_engine_draw(void *data)
static void compositor_engine_update(void *data)
static void compositor_engine_free(void *instance_data)
static void compositor_engine_init(void *data)
DrawEngineType draw_engine_compositor_type
const Depsgraph * depsgraph
bool DRW_state_is_viewport_image_render()
blender::draw::TextureFromPool & DRW_viewport_pass_texture_get(const char *pass_name)
const float * DRW_viewport_size_get()
DrawData * DRW_drawdata_ensure(ID *id, DrawEngineType *engine_type, size_t size, DrawDataInitCb init_cb, DrawDataFreeCb free_cb)
DefaultTextureList * DRW_viewport_texture_list_get()
const DRWContextState * DRW_context_state_get()
GPUTexture * DRW_texture_pool_query_2d(int w, int h, eGPUTextureFormat format, DrawEngineType *engine_type)
#define GPU_INFO_SIZE
format
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
DRWViewportEmptyList * txl
DRWViewportEmptyList * stl
DRWViewportEmptyList * fbl
DrawEngineType * engine_type
DRWViewportEmptyList * psl
char info[GPU_INFO_SIZE]
Depsgraph * depsgraph
unsigned int recalc
Definition DNA_ID.h:50
Definition DNA_ID.h:413
struct bNodeTree * nodetree
struct RenderData r
#define N_(msgid)