Blender V4.5
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
11
12#include "BKE_paint.hh"
13#include "DNA_particle_types.h"
14#include "DRW_engine.hh"
15#include "DRW_render.hh"
16
17#include "BLI_string.h"
18
19#include "BLT_translation.hh"
20
21#include "DNA_screen_types.h"
22#include "DNA_view3d_types.h"
23
24#include "ED_image.hh"
25#include "ED_screen.hh"
26#include "ED_view3d.hh"
27
28#include "GPU_debug.hh"
29#include "GPU_matrix.hh"
30#include "GPU_state.hh"
31
32#include "RE_engine.h"
33#include "RE_pipeline.h"
34
35#include "draw_cache.hh"
36#include "draw_cache_impl.hh"
37#include "draw_command.hh"
38#include "draw_common.hh"
39#include "draw_pass.hh"
40#include "draw_sculpt.hh"
41#include "draw_view.hh"
42#include "draw_view_data.hh"
43
44#include "external_engine.h" /* own include */
45
46/* Shaders */
47
49
55class Prepass {
56 private:
57 PassMain ps_ = {"prepass"};
58 PassMain::Sub *mesh_ps_ = nullptr;
59 PassMain::Sub *curves_ps_ = nullptr;
60 PassMain::Sub *pointcloud_ps_ = nullptr;
61
62 /* Reuse overlay shaders. */
63 gpu::StaticShader depth_mesh = {"overlay_depth_mesh"};
64 gpu::StaticShader depth_curves = {"overlay_depth_curves"};
65 gpu::StaticShader depth_pointcloud = {"overlay_depth_pointcloud"};
66
68
69 public:
71 {
72 dummy_buf.push_update();
73
74 ps_.init();
76 /* Dummy binds. They are unused in the variant we use.
77 * Just avoid validation layers complaining. */
78 ps_.bind_ubo(OVERLAY_GLOBALS_SLOT, &dummy_buf);
79 ps_.bind_ubo(DRW_CLIPPING_UBO_SLOT, &dummy_buf);
80 {
81 auto &sub = ps_.sub("Mesh");
82 sub.shader_set(depth_mesh.get());
83 mesh_ps_ = ⊂
84 }
85 {
86 auto &sub = ps_.sub("Curves");
87 sub.shader_set(depth_curves.get());
88 curves_ps_ = ⊂
89 }
90 {
91 auto &sub = ps_.sub("PointCloud");
92 sub.shader_set(depth_pointcloud.get());
93 pointcloud_ps_ = ⊂
94 }
95 }
96
97 void particle_sync(Manager &manager, const ObjectRef &ob_ref)
98 {
99 Object *ob = ob_ref.object;
100
101 ResourceHandle handle = {0};
102
105 continue;
106 }
107
108 const ParticleSettings *part = psys->part;
109 const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as;
110 if (draw_as == PART_DRAW_PATH && part->draw_as == PART_DRAW_REND) {
111 /* Case where the render engine should have rendered it, but we need to draw it for
112 * selection purpose. */
113 if (handle.raw == 0u) {
114 handle = manager.resource_handle_for_psys(ob_ref,
116 }
117
118 gpu::Batch *geom = DRW_cache_particles_get_hair(ob, psys, nullptr);
119 mesh_ps_->draw(geom, handle);
120 break;
121 }
122 }
123 }
124
125 void sculpt_sync(Manager &manager, const ObjectRef &ob_ref)
126 {
127 ResourceHandle handle = manager.resource_handle_for_sculpt(ob_ref);
128
130 mesh_ps_->draw(batch.batch, handle);
131 }
132 }
133
134 void object_sync(Manager &manager, const ObjectRef &ob_ref, const DRWContext &draw_ctx)
135 {
136 bool is_solid = ob_ref.object->dt >= OB_SOLID ||
138
139 if (!is_solid) {
140 return;
141 }
142
143 particle_sync(manager, ob_ref);
144
145 const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob_ref.object, draw_ctx.rv3d);
146
147 if (use_sculpt_pbvh) {
148 sculpt_sync(manager, ob_ref);
149 return;
150 }
151
152 gpu::Batch *geom_single = nullptr;
153 Span<gpu::Batch *> geom_list(&geom_single, 1);
154
155 PassMain::Sub *pass = nullptr;
156 switch (ob_ref.object->type) {
157 case OB_MESH:
158 geom_single = DRW_cache_mesh_surface_get(ob_ref.object);
159 pass = mesh_ps_;
160 break;
161 case OB_POINTCLOUD:
162 geom_single = pointcloud_sub_pass_setup(*pointcloud_ps_, ob_ref.object);
163 pass = pointcloud_ps_;
164 break;
165 case OB_CURVES:
166 geom_single = curves_sub_pass_setup(*curves_ps_, draw_ctx.scene, ob_ref.object);
167 pass = curves_ps_;
168 break;
169 default:
170 break;
171 }
172
173 if (pass == nullptr) {
174 return;
175 }
176
177 ResourceHandle res_handle = manager.unique_handle(ob_ref);
178
179 for (int material_id : geom_list.index_range()) {
180 pass->draw(geom_list[material_id], res_handle);
181 }
182 }
183
184 void submit(Manager &manager, View &view)
185 {
186 manager.submit(ps_, view);
187 }
188};
189
190class Instance : public DrawEngine {
191 const DRWContext *draw_ctx = nullptr;
192
193 Prepass prepass;
194 /* Only do prepass if there is a need for it.
195 * This is only needed for GPencil integration. */
196 bool do_prepass = false;
197
199 {
200 return "External";
201 }
202
203 void init() final
204 {
205 draw_ctx = DRW_context_get();
206 do_prepass = DRW_gpencil_engine_needed_viewport(draw_ctx->depsgraph, draw_ctx->v3d);
207 }
208
209 void begin_sync() final
210 {
211 if (do_prepass) {
212 prepass.begin_sync();
213 }
214 }
215
216 void object_sync(blender::draw::ObjectRef &ob_ref, blender::draw::Manager &manager) final
217 {
218 if (do_prepass) {
219 prepass.object_sync(manager, ob_ref, *draw_ctx);
220 }
221 }
222
223 void end_sync() final {}
224
225 void draw_scene_do_v3d(blender::draw::Manager &manager, draw::View &view)
226 {
227 RegionView3D *rv3d = draw_ctx->rv3d;
228 ARegion *region = draw_ctx->region;
229
231
232 /* The external engine can use the OpenGL rendering API directly, so make sure the state is
233 * already applied. */
235
236 /* Create render engine. */
237 RenderEngine *render_engine = nullptr;
238 if (!rv3d->view_render) {
239 RenderEngineType *engine_type = ED_view3d_engine_type(draw_ctx->scene,
240 draw_ctx->v3d->shading.type);
241
242 if (!(engine_type->view_update && engine_type->view_draw)) {
243 return;
244 }
245
246 rv3d->view_render = RE_NewViewRender(engine_type);
247 render_engine = RE_view_engine_get(rv3d->view_render);
248 engine_type->view_update(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
249 }
250 else {
251 render_engine = RE_view_engine_get(rv3d->view_render);
252 }
253
254 /* Rendered draw. */
257 ED_region_pixelspace(region);
258
259 /* Render result draw. */
260 const RenderEngineType *type = render_engine->type;
261 type->view_draw(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph);
262
263 GPU_bgl_end();
264
267
268 if (do_prepass) {
269 prepass.submit(manager, view);
270 }
271
272 /* Set render info. */
273 if (render_engine->text[0] != '\0') {
274 STRNCPY(info, render_engine->text);
275 }
276 else {
277 info[0] = '\0';
278 }
279 }
280
281 /* Configure current matrix stack so that the external engine can use the same drawing code for
282 * both viewport and image editor drawing.
283 *
284 * The engine draws result in the pixel space, and is applying render offset. For image editor we
285 * need to switch from normalized space to pixel space, and "un-apply" offset. */
286 void external_image_space_matrix_set(const RenderEngine *engine)
287 {
288 BLI_assert(engine != nullptr);
289
290 SpaceImage *space_image = (SpaceImage *)draw_ctx->space_data;
291
292 /* Apply current view as transformation matrix.
293 * This will configure drawing for normalized space with current zoom and pan applied. */
294
296 float4x4 projection_matrix = blender::draw::View::default_get().winmat();
297
298 GPU_matrix_projection_set(projection_matrix.ptr());
299 GPU_matrix_set(view_matrix.ptr());
300
301 /* Switch from normalized space to pixel space. */
302 {
303 int width, height;
304 ED_space_image_get_size(space_image, &width, &height);
305
306 const float width_inv = width ? 1.0f / width : 0.0f;
307 const float height_inv = height ? 1.0f / height : 0.0f;
308 GPU_matrix_scale_2f(width_inv, height_inv);
309 }
310
311 /* Un-apply render offset. */
312 {
313 Render *render = engine->re;
314 rctf view_rect;
315 rcti render_rect;
316 RE_GetViewPlane(render, &view_rect, &render_rect);
317
318 GPU_matrix_translate_2f(-render_rect.xmin, -render_rect.ymin);
319 }
320 }
321
322 void draw_scene_do_image()
323 {
324 Scene *scene = draw_ctx->scene;
325 Render *re = RE_GetSceneRender(scene);
326 RenderEngine *engine = RE_engine_get(re);
327
328 /* Is tested before enabling the drawing engine. */
329 BLI_assert(re != nullptr);
330 BLI_assert(engine != nullptr);
331
333
334 /* The external engine can use the OpenGL rendering API directly, so make sure the state is
335 * already applied. */
337
338 const DefaultFramebufferList *dfbl = draw_ctx->viewport_framebuffer_list_get();
339
340 /* Clear the depth buffer to the value used by the background overlay so that the overlay is
341 * not happening outside of the drawn image.
342 *
343 * NOTE: The external engine only draws color. The depth is taken care of using the depth pass
344 * which initialized the depth to the values expected by the background overlay. */
346
349
350 external_image_space_matrix_set(engine);
351
352 GPU_debug_group_begin("External Engine");
353
354 const RenderEngineType *engine_type = engine->type;
355 BLI_assert(engine_type != nullptr);
356 BLI_assert(engine_type->draw != nullptr);
357
358 engine_type->draw(engine, draw_ctx->evil_C, draw_ctx->depsgraph);
359
361
364
366 GPU_bgl_end();
367
369 }
370
371 void draw_scene_do(blender::draw::Manager &manager, View &view)
372 {
373 if (draw_ctx->v3d != nullptr) {
374 draw_scene_do_v3d(manager, view);
375 return;
376 }
377
378 if (draw_ctx->space_data == nullptr) {
379 return;
380 }
381
382 const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
383 if (space_type == SPACE_IMAGE) {
384 draw_scene_do_image();
385 return;
386 }
387 }
388
389 void draw(blender::draw::Manager &manager) final
390 {
391 /* TODO(fclem): Remove global access. */
393
394 const DefaultFramebufferList *dfbl = draw_ctx->viewport_framebuffer_list_get();
395
396 /* Will be nullptr during OpenGL render.
397 * OpenGL render is used for quick preview (thumbnails or sequencer preview)
398 * where using the rendering engine to preview doesn't make so much sense. */
399 if (draw_ctx->evil_C) {
400 const float clear_col[4] = {0, 0, 0, 0};
401 /* This is to keep compatibility with external engine. */
402 /* TODO(fclem): remove it eventually. */
404 GPU_framebuffer_clear_color(dfbl->default_fb, clear_col);
405
407 draw_scene_do(manager, view);
409 }
410 }
411};
412
414{
415 return new Instance();
416}
417
418} // namespace blender::draw::external
419
420/* Functions */
421
422/* NOTE: currently unused,
423 * we should not register unless we want to see this when debugging the view. */
424
426 /*next*/ nullptr,
427 /*prev*/ nullptr,
428 /*idname*/ "BLENDER_EXTERNAL",
429 /*name*/ N_("External"),
431 /*update*/ nullptr,
432 /*render*/ nullptr,
433 /*render_frame_finish*/ nullptr,
434 /*draw*/ nullptr,
435 /*bake*/ nullptr,
436 /*view_update*/ nullptr,
437 /*view_draw*/ nullptr,
438 /*update_script_node*/ nullptr,
439 /*update_render_passes*/ nullptr,
440 /*update_custom_camera*/ nullptr,
441 /*draw_engine*/ nullptr,
442 /*rna_ext*/
443 {
444 /*data*/ nullptr,
445 /*srna*/ nullptr,
446 /*call*/ nullptr,
447 },
448};
449
451{
452 const SpaceLink *space_data = draw_ctx->space_data;
453 Scene *scene = draw_ctx->scene;
454
455 if (space_data == nullptr) {
456 return false;
457 }
458
459 const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype);
460 if (space_type != SPACE_IMAGE) {
461 return false;
462 }
463
464 SpaceImage *space_image = (SpaceImage *)space_data;
465 const Image *image = ED_space_image(space_image);
466 if (image == nullptr || image->type != IMA_TYPE_R_RESULT) {
467 return false;
468 }
469
470 if (image->render_slot != image->last_render_slot) {
471 return false;
472 }
473
474 /* Render is allocated on main thread, so it is safe to access it from here. */
475 Render *re = RE_GetSceneRender(scene);
476
477 if (re == nullptr) {
478 return false;
479 }
480
481 return RE_engine_draw_acquire(re);
482}
483
485{
486 if (rv3d->view_render) {
487 /* Free engine with DRW context enabled, as this may clean up per-context
488 * resources like VAOs. */
491 rv3d->view_render = nullptr;
493 }
494}
bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const RegionView3D *rv3d)
Definition paint.cc:2928
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
@ IMA_TYPE_R_RESULT
@ OB_SOLID
@ OB_HIDE_CAMERA
@ OB_MESH
@ OB_POINTCLOUD
@ OB_CURVES
@ PART_DRAW_PATH
@ PART_DRAW_REND
eSpace_Type
@ SPACE_IMAGE
void DRW_submission_end()
bool DRW_gpencil_engine_needed_viewport(Depsgraph *depsgraph, View3D *v3d)
void DRW_gpu_context_disable_ex(bool restore)
void DRW_gpu_context_enable_ex(bool restore)
void DRW_engine_external_free(RegionView3D *rv3d)
void DRW_submission_start()
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:123
RenderEngineType * ED_view3d_engine_type(const Scene *scene, int drawtype)
static AppView * view
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
void GPU_framebuffer_bind(GPUFrameBuffer *fb)
void GPU_framebuffer_clear_color(GPUFrameBuffer *fb, const float clear_col[4])
void GPU_framebuffer_clear_depth(GPUFrameBuffer *fb, float clear_depth)
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)
void GPU_bgl_end()
Definition gpu_state.cc:360
void GPU_apply_state()
Definition gpu_state.cc:315
@ RE_INTERNAL
Definition RE_engine.h:43
@ RE_USE_STEREO_VIEWPORT
Definition RE_engine.h:49
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
ResourceHandle resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix)
ResourceHandleRange unique_handle(const ObjectRef &ref)
ResourceHandleRange resource_handle_for_sculpt(const ObjectRef &ref)
void submit(PassSimple &pass, View &view)
const float4x4 & winmat(int view_id=0) const
Definition draw_view.hh:148
const float4x4 & viewmat(int view_id=0) const
Definition draw_view.hh:136
static View & default_get()
Definition draw_view.cc:317
void draw(gpu::Batch *batch, uint instance_len=-1, uint vertex_len=-1, uint vertex_first=-1, ResourceHandleRange handle={0}, uint custom_id=0)
Definition draw_pass.hh:884
detail::PassBase< command::DrawMultiBuf > Sub
Definition draw_pass.hh:490
void sculpt_sync(Manager &manager, const ObjectRef &ob_ref)
void particle_sync(Manager &manager, const ObjectRef &ob_ref)
void object_sync(Manager &manager, const ObjectRef &ob_ref, const DRWContext &draw_ctx)
void submit(Manager &manager, View &view)
const DRWContext * DRW_context_get()
bool DRW_object_is_visible_psys_in_active_context(const Object *object, const ParticleSystem *psys)
#define DRW_CLIPPING_UBO_SLOT
#define OVERLAY_GLOBALS_SLOT
@ 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
bool DRW_engine_external_acquire_for_image_editor(const DRWContext *draw_ctx)
RenderEngineType DRW_engine_viewport_external_type
struct @064345207361167251075330302113175271221317160336::@113254110077376341056327177062323111323010325277 batch
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)
gpu::Batch * curves_sub_pass_setup(PassMain::Sub &ps, const Scene *scene, Object *ob, GPUMaterial *gpu_material=nullptr)
detail::Pass< command::DrawMultiBuf > PassMain
gpu::Batch * pointcloud_sub_pass_setup(PassMain::Sub &sub_ps, Object *object, GPUMaterial *gpu_material=nullptr)
Vector< SculptBatch > sculpt_batches_get(const Object *ob, SculptBatchFeature features)
float4x4 DRW_particles_dupli_matrix_get(const ObjectRef &ob_ref)
gpu::Batch * DRW_cache_particles_get_hair(Object *object, ParticleSystem *psys, ModifierData *md)
gpu::Batch * DRW_cache_mesh_surface_get(Object *ob)
MatBase< float, 4, 4 > float4x4
ViewRender * RE_NewViewRender(RenderEngineType *engine_type)
Render * RE_GetSceneRender(const Scene *scene)
void RE_FreeViewRender(ViewRender *view_render)
RegionView3D * rv3d
Scene * scene
SpaceLink * space_data
GPUFrameBuffer * default_fb
virtual void begin_sync()=0
virtual void init()=0
char info[GPU_INFO_SIZE]
Definition DRW_render.hh:70
virtual blender::StringRefNull name_get()=0
virtual void end_sync()=0
short last_render_slot
short render_slot
ListBase particlesystem
short visibility_flag
struct ViewRender * view_render
void(* view_draw)(struct RenderEngine *engine, const struct bContext *context, struct Depsgraph *depsgraph)
Definition RE_engine.h:104
void(* view_update)(struct RenderEngine *engine, const struct bContext *context, struct Depsgraph *depsgraph)
Definition RE_engine.h:101
void(* draw)(struct RenderEngine *engine, const struct bContext *context, struct Depsgraph *depsgraph)
Definition RE_engine.h:89
struct Depsgraph * depsgraph
Definition RE_engine.h:155
RenderEngineType * type
Definition RE_engine.h:131
char text[512]
Definition RE_engine.h:140
struct Render * re
Definition RE_engine.h:138
const c_style_mat & ptr() const
static void set(DRWState state=DRW_STATE_DEFAULT)
DrawEngine * create_instance() final
int ymin
int xmin
#define N_(msgid)