Blender V4.3
external_engine.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12#include "DRW_engine.hh"
13#include "DRW_render.hh"
14
15#include "DNA_modifier_types.h"
16#include "DNA_screen_types.h"
17#include "DNA_view3d_types.h"
18
19#include "BKE_object.hh"
20#include "BKE_particle.h"
21
22#include "ED_image.hh"
23#include "ED_screen.hh"
24
25#include "GPU_batch.hh"
26#include "GPU_debug.hh"
27#include "GPU_matrix.hh"
28#include "GPU_shader.hh"
29#include "GPU_state.hh"
30#include "GPU_viewport.hh"
31
32#include "RE_engine.h"
33#include "RE_pipeline.h"
34
35#include "external_engine.h" /* own include */
36
37/* Shaders */
38
39#define EXTERNAL_ENGINE "BLENDER_EXTERNAL"
40
43
45
46/* *********** LISTS *********** */
47
48/* GPUViewport.storage
49 * Is freed every time the viewport engine changes. */
51 int dummy;
52};
53
58
60 GPUFrameBuffer *depth_buffer_fb;
61};
62
64 /* default */
65 GPUTexture *depth_buffer_tx;
66};
67
71
82
83/* *********** STATIC *********** */
84
85static struct {
86 /* Depth Pre Pass */
88} e_data = {nullptr}; /* Engine data */
89
92
93 /* Do we need to update the depth or can we reuse the last calculated texture. */
96}; /* Transient data */
97
98/* Functions */
99
100static void external_engine_init(void *vedata)
101{
102 EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
103 const DRWContextState *draw_ctx = DRW_context_state_get();
104 ARegion *region = draw_ctx->region;
105
106 /* Depth pre-pass. */
107 if (!e_data.depth_sh) {
108 /* NOTE: Reuse Basic engine depth only shader. */
109 e_data.depth_sh = GPU_shader_create_from_info_name("basic_depth_mesh");
110 }
111
112 if (!stl->g_data) {
113 /* Alloc transient pointers */
114 stl->g_data = MEM_cnew<EXTERNAL_PrivateData>(__func__);
115 stl->g_data->need_depth = true;
116 }
117
118 stl->g_data->update_depth = true;
119
120 /* Progressive render samples are tagged with no rebuild, in that case we
121 * can skip updating the depth buffer */
122 if (region && (region->do_draw & RGN_DRAW_NO_REBUILD)) {
123 stl->g_data->update_depth = false;
124 }
125}
126
127/* Add shading group call which will take care of writing to the depth buffer, so that the
128 * alpha-under overlay will happen for the render buffer. */
130{
131 float obmat[4][4];
132 unit_m4(obmat);
133 scale_m4_fl(obmat, 0.5f);
134
135 /* NOTE: Use the same Z-depth value as in the regular image drawing engine. */
136 translate_m4(obmat, 1.0f, 1.0f, 0.75f);
137
138 blender::gpu::Batch *geom = DRW_cache_quad_get();
139
140 DRW_shgroup_call_obmat(grp, geom, obmat);
141}
142
143static void external_cache_init(void *vedata)
144{
145 EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl;
146 EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
147 EXTERNAL_TextureList *txl = ((EXTERNAL_Data *)vedata)->txl;
148 EXTERNAL_FramebufferList *fbl = ((EXTERNAL_Data *)vedata)->fbl;
149 const DRWContextState *draw_ctx = DRW_context_state_get();
150 const View3D *v3d = draw_ctx->v3d;
151
152 {
155
157 {
158 GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx),
159 });
160 }
161
162 /* Depth Pass */
163 {
164 psl->depth_pass = DRW_pass_create("Depth Pass",
166 stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass);
167 }
168
169 if (v3d != nullptr) {
170 /* Do not draw depth pass when overlays are turned off. */
171 stl->g_data->need_depth = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0;
172 }
173 else if (draw_ctx->space_data != nullptr) {
174 const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
175 if (space_type == SPACE_IMAGE) {
177
178 stl->g_data->need_depth = true;
179 stl->g_data->update_depth = true;
180 }
181 }
182}
183
184static void external_cache_populate(void *vedata, Object *ob)
185{
186 const DRWContextState *draw_ctx = DRW_context_state_get();
187 EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
188
189 if (draw_ctx->space_data != nullptr) {
190 const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
191 if (space_type == SPACE_IMAGE) {
192 return;
193 }
194 }
195
196 if (!(DRW_object_is_renderable(ob) &&
198 {
199 return;
200 }
201
202 if (ob->type == OB_GPENCIL_LEGACY) {
203 /* Grease Pencil objects need correct depth to do the blending. */
204 stl->g_data->need_depth = true;
205 return;
206 }
207
208 if (ob->type == OB_MESH && ob->modifiers.first != nullptr) {
210 if (md->type != eModifierType_ParticleSystem) {
211 continue;
212 }
213 ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys;
215 continue;
216 }
217 ParticleSettings *part = psys->part;
218 const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
219
220 if (draw_as == PART_DRAW_PATH) {
221 blender::gpu::Batch *hairs = DRW_cache_particles_get_hair(ob, psys, nullptr);
222 DRW_shgroup_call(stl->g_data->depth_shgrp, hairs, nullptr);
223 }
224 }
225 }
226 blender::gpu::Batch *geom = DRW_cache_object_surface_get(ob);
227 if (geom) {
228 /* Depth Pre-pass. */
229 DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob);
230 }
231}
232
233static void external_cache_finish(void * /*vedata*/) {}
234
235static void external_draw_scene_do_v3d(void *vedata)
236{
237 const DRWContextState *draw_ctx = DRW_context_state_get();
238 RegionView3D *rv3d = draw_ctx->rv3d;
239 ARegion *region = draw_ctx->region;
240
242
243 /* The external engine can use the OpenGL rendering API directly, so make sure the state is
244 * already applied. */
246
247 /* Create render engine. */
248 RenderEngine *render_engine = nullptr;
249 if (!rv3d->view_render) {
250 RenderEngineType *engine_type = draw_ctx->engine_type;
251
252 if (!(engine_type->view_update && engine_type->view_draw)) {
253 return;
254 }
255
256 rv3d->view_render = RE_NewViewRender(engine_type);
257 render_engine = RE_view_engine_get(rv3d->view_render);
258 engine_type->view_update(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
259 }
260 else {
261 render_engine = RE_view_engine_get(rv3d->view_render);
262 }
263
264 /* Rendered draw. */
267 ED_region_pixelspace(region);
268
269 /* Render result draw. */
270 const RenderEngineType *type = render_engine->type;
271 type->view_draw(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
272
273 GPU_bgl_end();
274
277
278 /* Set render info. */
279 EXTERNAL_Data *data = static_cast<EXTERNAL_Data *>(vedata);
280 if (render_engine->text[0] != '\0') {
281 STRNCPY(data->info, render_engine->text);
282 }
283 else {
284 data->info[0] = '\0';
285 }
286}
287
288/* Configure current matrix stack so that the external engine can use the same drawing code for
289 * both viewport and image editor drawing.
290 *
291 * The engine draws result in the pixel space, and is applying render offset. For image editor we
292 * need to switch from normalized space to pixel space, and "un-apply" offset. */
294{
295 BLI_assert(engine != nullptr);
296
297 const DRWContextState *draw_ctx = DRW_context_state_get();
298 const DRWView *view = DRW_view_get_active();
299 SpaceImage *space_image = (SpaceImage *)draw_ctx->space_data;
300
301 /* Apply current view as transformation matrix.
302 * This will configure drawing for normalized space with current zoom and pan applied. */
303
304 float view_matrix[4][4];
305 DRW_view_viewmat_get(view, view_matrix, false);
306
307 float projection_matrix[4][4];
308 DRW_view_winmat_get(view, projection_matrix, false);
309
310 GPU_matrix_projection_set(projection_matrix);
311 GPU_matrix_set(view_matrix);
312
313 /* Switch from normalized space to pixel space. */
314 {
315 int width, height;
316 ED_space_image_get_size(space_image, &width, &height);
317
318 const float width_inv = width ? 1.0f / width : 0.0f;
319 const float height_inv = height ? 1.0f / height : 0.0f;
320 GPU_matrix_scale_2f(width_inv, height_inv);
321 }
322
323 /* Un-apply render offset. */
324 {
325 Render *render = engine->re;
326 rctf view_rect;
327 rcti render_rect;
328 RE_GetViewPlane(render, &view_rect, &render_rect);
329
330 GPU_matrix_translate_2f(-render_rect.xmin, -render_rect.ymin);
331 }
332}
333
334static void external_draw_scene_do_image(void * /*vedata*/)
335{
336 const DRWContextState *draw_ctx = DRW_context_state_get();
337 Scene *scene = draw_ctx->scene;
338 Render *re = RE_GetSceneRender(scene);
339 RenderEngine *engine = RE_engine_get(re);
340
341 /* Is tested before enabling the drawing engine. */
342 BLI_assert(re != nullptr);
343 BLI_assert(engine != nullptr);
344
346
347 /* The external engine can use the OpenGL rendering API directly, so make sure the state is
348 * already applied. */
350
352
353 /* Clear the depth buffer to the value used by the background overlay so that the overlay is not
354 * happening outside of the drawn image.
355 *
356 * NOTE: The external engine only draws color. The depth is taken care of using the depth pass
357 * which initialized the depth to the values expected by the background overlay. */
359
362
364
365 GPU_debug_group_begin("External Engine");
366
367 const RenderEngineType *engine_type = engine->type;
368 BLI_assert(engine_type != nullptr);
369 BLI_assert(engine_type->draw != nullptr);
370
371 engine_type->draw(engine, draw_ctx->evil_C, draw_ctx->depsgraph);
372
374
377
379 GPU_bgl_end();
380
382}
383
384static void external_draw_scene_do(void *vedata)
385{
386 const DRWContextState *draw_ctx = DRW_context_state_get();
387
388 if (draw_ctx->v3d != nullptr) {
390 return;
391 }
392
393 if (draw_ctx->space_data == nullptr) {
394 return;
395 }
396
397 const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
398 if (space_type == SPACE_IMAGE) {
400 return;
401 }
402}
403
404static void external_draw_scene(void *vedata)
405{
406 const DRWContextState *draw_ctx = DRW_context_state_get();
407 EXTERNAL_StorageList *stl = ((EXTERNAL_Data *)vedata)->stl;
408 EXTERNAL_PassList *psl = ((EXTERNAL_Data *)vedata)->psl;
409 EXTERNAL_FramebufferList *fbl = ((EXTERNAL_Data *)vedata)->fbl;
411
412 /* Will be nullptr during OpenGL render.
413 * OpenGL render is used for quick preview (thumbnails or sequencer preview)
414 * where using the rendering engine to preview doesn't make so much sense. */
415 if (draw_ctx->evil_C) {
416 const float clear_col[4] = {0, 0, 0, 0};
417 /* This is to keep compatibility with external engine. */
418 /* TODO(fclem): remove it eventually. */
420 GPU_framebuffer_clear_color(dfbl->default_fb, clear_col);
421
423 }
424
425 if (stl->g_data->update_depth && stl->g_data->need_depth) {
427 /* Copy main depth buffer to cached framebuffer. */
429 }
430
431 /* Copy cached depth buffer to main framebuffer. */
433}
434
436{
438}
439
441
443 /*next*/ nullptr,
444 /*prev*/ nullptr,
445 /*idname*/ N_("External"),
446 /*vedata_size*/ &external_data_size,
447 /*engine_init*/ &external_engine_init,
448 /*engine_free*/ &external_engine_free,
449 /*instance_free*/ nullptr,
450 /*cache_init*/ &external_cache_init,
451 /*cache_populate*/ &external_cache_populate,
452 /*cache_finish*/ &external_cache_finish,
453 /*draw_scene*/ &external_draw_scene,
454 /*view_update*/ nullptr,
455 /*id_update*/ nullptr,
456 /*render_to_image*/ nullptr,
457 /*store_metadata*/ nullptr,
458};
459
460/* NOTE: currently unused,
461 * we should not register unless we want to see this when debugging the view. */
462
464 /*next*/ nullptr,
465 /*prev*/ nullptr,
466 /*idname*/ EXTERNAL_ENGINE,
467 /*name*/ N_("External"),
469 /*update*/ nullptr,
470 /*render*/ nullptr,
471 /*render_frame_finish*/ nullptr,
472 /*draw*/ nullptr,
473 /*bake*/ nullptr,
474 /*view_update*/ nullptr,
475 /*view_draw*/ nullptr,
476 /*update_script_node*/ nullptr,
477 /*update_render_passes*/ nullptr,
478 /*draw_engine*/ &draw_engine_external_type,
479 /*rna_ext*/
480 {
481 /*data*/ nullptr,
482 /*srna*/ nullptr,
483 /*call*/ nullptr,
484 },
485};
486
488{
489 const DRWContextState *draw_ctx = DRW_context_state_get();
490 const SpaceLink *space_data = draw_ctx->space_data;
491 Scene *scene = draw_ctx->scene;
492
493 if (space_data == nullptr) {
494 return false;
495 }
496
497 const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
498 if (space_type != SPACE_IMAGE) {
499 return false;
500 }
501
502 SpaceImage *space_image = (SpaceImage *)space_data;
503 const Image *image = ED_space_image(space_image);
504 if (image == nullptr || image->type != IMA_TYPE_R_RESULT) {
505 return false;
506 }
507
508 if (image->render_slot != image->last_render_slot) {
509 return false;
510 }
511
512 /* Render is allocated on main thread, so it is safe to access it from here. */
513 Render *re = RE_GetSceneRender(scene);
514
515 if (re == nullptr) {
516 return false;
517 }
518
519 return RE_engine_draw_acquire(re);
520}
521
523{
524 if (rv3d->view_render) {
525 /* Free engine with DRW context enabled, as this may clean up per-context
526 * resources like VAOs. */
529 rv3d->view_render = nullptr;
531 }
532}
533
534#undef EXTERNAL_ENGINE
General operations, lookup, etc. for blender objects.
@ OB_VISIBLE_SELF
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
void unit_m4(float m[4][4])
Definition rct.c:1127
void translate_m4(float mat[4][4], float Tx, float Ty, float Tz)
void scale_m4_fl(float R[4][4], float scale)
#define STRNCPY(dst, src)
Definition BLI_string.h:593
@ IMA_TYPE_R_RESULT
@ eModifierType_ParticleSystem
@ OB_MESH
@ OB_GPENCIL_LEGACY
@ PART_DRAW_PATH
@ PART_DRAW_REND
@ RGN_DRAW_NO_REBUILD
eSpace_Type
@ SPACE_IMAGE
@ V3D_HIDE_OVERLAYS
void DRW_gpu_context_disable_ex(bool restore)
void DRW_gpu_context_enable_ex(bool restore)
DRWTextureFlag
#define DRW_SHADER_FREE_SAFE(shader)
#define DRW_shgroup_call_obmat(shgroup, geom, obmat)
#define DRW_VIEWPORT_DATA_SIZE(ty)
#define DRW_shgroup_call(shgroup, geom, ob)
void ED_space_image_get_size(SpaceImage *sima, int *r_width, int *r_height)
Image * ED_space_image(const SpaceImage *sima)
Definition image_edit.cc:40
void ED_region_pixelspace(const ARegion *region)
Definition area.cc:121
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
@ GPU_DEPTH_BIT
void GPU_framebuffer_bind(GPUFrameBuffer *framebuffer)
void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
#define GPU_framebuffer_ensure_config(_fb,...)
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, eGPUFrameBufferBits blit_buffers)
void GPU_matrix_scale_2f(float x, float y)
#define GPU_matrix_set(x)
void GPU_matrix_push()
void GPU_matrix_push_projection()
void GPU_matrix_pop_projection()
#define GPU_matrix_projection_set(x)
void GPU_matrix_pop()
void GPU_matrix_translate_2f(float x, float y)
GPUShader * GPU_shader_create_from_info_name(const char *info_name)
void GPU_bgl_end()
Definition gpu_state.cc:349
void GPU_apply_state()
Definition gpu_state.cc:304
@ GPU_DEPTH24_STENCIL8
@ RE_INTERNAL
Definition RE_engine.h:47
@ RE_USE_STEREO_VIEWPORT
Definition RE_engine.h:53
struct GPUShader GPUShader
blender::gpu::Batch * DRW_cache_object_surface_get(Object *ob)
blender::gpu::Batch * DRW_cache_particles_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
blender::gpu::Batch * DRW_cache_quad_get()
DefaultFramebufferList * DRW_viewport_framebuffer_list_get()
bool DRW_object_is_renderable(const Object *ob)
int DRW_object_visibility_in_active_context(const Object *ob)
bool DRW_object_is_visible_psys_in_active_context(const Object *object, const ParticleSystem *psys)
const DRWContextState * DRW_context_state_get()
DRWShadingGroup * DRW_shgroup_create(GPUShader *shader, DRWPass *pass)
DRWPass * DRW_pass_create(const char *name, DRWState state)
void DRW_view_winmat_get(const DRWView *view, float mat[4][4], bool inverse)
void DRW_view_viewmat_get(const DRWView *view, float mat[4][4], bool inverse)
void DRW_draw_pass(DRWPass *pass)
void DRW_state_reset()
void DRW_state_reset_ex(DRWState state)
const DRWView * DRW_view_get_active()
void DRW_texture_ensure_fullscreen_2d(GPUTexture **tex, eGPUTextureFormat format, DRWTextureFlag flags)
@ DRW_STATE_WRITE_DEPTH
Definition draw_state.hh:29
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_DEPTH_LESS_EQUAL
Definition draw_state.hh:38
#define GPU_INFO_SIZE
static void external_cache_populate(void *vedata, Object *ob)
RenderEngineType DRW_engine_viewport_external_type
GPUShader * depth_sh
static void external_cache_finish(void *)
bool DRW_engine_external_acquire_for_image_editor()
static void external_draw_scene(void *vedata)
static void external_draw_scene_do_v3d(void *vedata)
char datatoc_common_view_lib_glsl[]
static void external_cache_image_add(DRWShadingGroup *grp)
char datatoc_basic_depth_vert_glsl[]
DrawEngineType draw_engine_external_type
static void external_engine_init(void *vedata)
static struct @199 e_data
void DRW_engine_external_free(RegionView3D *rv3d)
static void external_draw_scene_do_image(void *)
char datatoc_basic_depth_frag_glsl[]
static void external_image_space_matrix_set(const RenderEngine *engine)
#define EXTERNAL_ENGINE
static const DrawEngineDataSize external_data_size
static void external_draw_scene_do(void *vedata)
static void external_cache_init(void *vedata)
static void external_engine_free()
void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect)
void RE_engine_draw_release(Render *re)
RenderEngine * RE_view_engine_get(const ViewRender *view_render)
RenderEngine * RE_engine_get(const Render *re)
bool RE_engine_draw_acquire(Render *re)
ViewRender * RE_NewViewRender(RenderEngineType *engine_type)
Render * RE_GetSceneRender(const Scene *scene)
void RE_FreeViewRender(ViewRender *view_render)
Depsgraph * depsgraph
ARegion * region
const bContext * evil_C
RenderEngineType * engine_type
RegionView3D * rv3d
SpaceLink * space_data
GPUFrameBuffer * depth_only_fb
GPUFrameBuffer * default_fb
EXTERNAL_FramebufferList * fbl
char info[GPU_INFO_SIZE]
EXTERNAL_StorageList * stl
EXTERNAL_PassList * psl
EXTERNAL_TextureList * txl
GPUFrameBuffer * depth_buffer_fb
DRWShadingGroup * depth_shgrp
struct EXTERNAL_PrivateData * g_data
EXTERNAL_Storage * storage
GPUTexture * depth_buffer_tx
void * first
ListBase modifiers
ParticleSettings * part
struct ViewRender * view_render
void(* view_draw)(struct RenderEngine *engine, const struct bContext *context, struct Depsgraph *depsgraph)
Definition RE_engine.h:108
void(* view_update)(struct RenderEngine *engine, const struct bContext *context, struct Depsgraph *depsgraph)
Definition RE_engine.h:105
void(* draw)(struct RenderEngine *engine, const struct bContext *context, struct Depsgraph *depsgraph)
Definition RE_engine.h:93
RenderEngineType * type
Definition RE_engine.h:134
char text[512]
Definition RE_engine.h:143
struct Render * re
Definition RE_engine.h:141
int ymin
int xmin
#define N_(msgid)