From 92968c23fe1663ab81dfa6b2b66aa61acc06ab9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cle=CC=81ment=20Foucault?= Date: Mon, 17 Mar 2025 10:31:22 +0100 Subject: [PATCH] Refactor: DRW: Make DrawEngine a virtual class This removes the old `DrawEngineType` and use the new `DrawEngine` virtual class instead. This removes a lot of boilerplate functions that were only there for legacy reason. To this end, some engines that were based on static functions have been refactored into `Instance` classes. This was particularly cumbersome for the Grease pencil engine which needed some more refactoring. The `Engine` class that is in each namespace is a workaround to isolate the internal implementation (i.e. the `Instance`) to the engine modules. Without this, the whole engine is getting included in each compile unit that includes the `Instance` class. Eventually, if we get rid of these intricate dependencies, we could remove the `Engine` class. Pull Request: https://projects.blender.org/blender/blender/pulls/136001 --- source/blender/draw/CMakeLists.txt | 6 +- source/blender/draw/DRW_engine.hh | 5 +- .../engines/compositor/compositor_engine.cc | 127 +-- .../engines/compositor/compositor_engine.h | 10 +- .../draw/engines/eevee_next/eevee_engine.cc | 185 +--- .../draw/engines/eevee_next/eevee_engine.h | 11 +- .../draw/engines/eevee_next/eevee_instance.cc | 96 +- .../draw/engines/eevee_next/eevee_instance.hh | 22 +- .../draw/engines/eevee_next/eevee_velocity.cc | 13 +- .../draw/engines/external/external_engine.cc | 397 ++++---- .../draw/engines/external/external_engine.h | 12 +- .../engines/gpencil/gpencil_antialiasing.cc | 20 +- .../engines/gpencil/gpencil_cache_utils.cc | 20 +- .../draw/engines/gpencil/gpencil_draw_data.cc | 69 +- .../draw/engines/gpencil/gpencil_engine.hh | 22 + .../draw/engines/gpencil/gpencil_engine_c.cc | 377 ++++---- ...cil_engine.h => gpencil_engine_private.hh} | 150 ++- .../draw/engines/gpencil/gpencil_render.cc | 100 +- ...{gpencil_shader_c.cc => gpencil_shader.hh} | 80 +- .../draw/engines/gpencil/gpencil_shader_fx.cc | 32 +- .../draw/engines/image/image_engine.cc | 82 +- .../blender/draw/engines/image/image_engine.h | 12 +- .../draw/engines/image/image_instance.hh | 42 +- .../draw/engines/overlay/overlay_engine.h | 12 +- .../overlay/overlay_next_attribute_text.hh | 2 + .../engines/overlay/overlay_next_engine.cc | 81 +- .../engines/overlay/overlay_next_instance.hh | 20 +- .../engines/select/select_debug_engine.cc | 99 +- .../draw/engines/select/select_engine.cc | 854 +++++++++--------- .../draw/engines/select/select_engine.hh | 34 +- .../draw/engines/select/select_instance.cc | 72 +- .../draw/engines/select/select_private.hh | 59 -- .../engines/workbench/workbench_engine.cc | 159 ++-- .../draw/engines/workbench/workbench_engine.h | 12 + .../engines/workbench/workbench_private.hh | 2 - source/blender/draw/intern/DRW_render.hh | 112 ++- source/blender/draw/intern/draw_context.cc | 304 ++----- .../blender/draw/intern/draw_manager_text.cc | 3 + source/blender/draw/intern/draw_view_data.cc | 95 +- source/blender/draw/intern/draw_view_data.hh | 96 +- 40 files changed, 1601 insertions(+), 2305 deletions(-) create mode 100644 source/blender/draw/engines/gpencil/gpencil_engine.hh rename source/blender/draw/engines/gpencil/{gpencil_engine.h => gpencil_engine_private.hh} (79%) rename source/blender/draw/engines/gpencil/{gpencil_shader_c.cc => gpencil_shader.hh} (52%) delete mode 100644 source/blender/draw/engines/select/select_private.hh diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 18584063de2..20c8465e5fd 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -140,7 +140,6 @@ set(SRC engines/gpencil/gpencil_draw_data.cc engines/gpencil/gpencil_engine_c.cc engines/gpencil/gpencil_render.cc - engines/gpencil/gpencil_shader_c.cc engines/gpencil/gpencil_shader_fx.cc engines/select/select_engine.cc engines/select/select_instance.cc @@ -220,7 +219,9 @@ set(SRC engines/eevee_next/eevee_volume.hh engines/eevee_next/eevee_world.hh engines/external/external_engine.h - engines/gpencil/gpencil_engine.h + engines/gpencil/gpencil_engine_private.hh + engines/gpencil/gpencil_engine.hh + engines/gpencil/gpencil_shader.hh engines/image/image_batches.hh engines/image/image_buffer_cache.hh engines/image/image_drawing_mode.hh @@ -281,7 +282,6 @@ set(SRC engines/select/select_defines.hh engines/select/select_engine.hh engines/select/select_instance.hh - engines/select/select_private.hh engines/workbench/workbench_defines.hh engines/workbench/workbench_engine.h engines/workbench/workbench_enums.hh diff --git a/source/blender/draw/DRW_engine.hh b/source/blender/draw/DRW_engine.hh index d7d5504e6ab..1a37fbcd4c6 100644 --- a/source/blender/draw/DRW_engine.hh +++ b/source/blender/draw/DRW_engine.hh @@ -13,7 +13,6 @@ struct DRWData; struct DRWInstanceDataList; struct Depsgraph; struct DrawDataList; -struct DrawEngineType; struct GPUMaterial; struct GPUOffScreen; struct GPUVertFormat; @@ -109,10 +108,8 @@ bool DRW_draw_in_progress(); */ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph); /** - * Render grease pencil on top of other render engine output (but only for non-draw-engine). + * Render grease pencil on top of other render engine output. * This function creates a DRWContext. - * `DRW_render_to_image()` applies grease pencil using `DRW_render_gpencil_to_image` as it - * already has a DRWContext setup. */ void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph); diff --git a/source/blender/draw/engines/compositor/compositor_engine.cc b/source/blender/draw/engines/compositor/compositor_engine.cc index 68e06a1c711..23b31a7b7f2 100644 --- a/source/blender/draw/engines/compositor/compositor_engine.cc +++ b/source/blender/draw/engines/compositor/compositor_engine.cc @@ -196,90 +196,63 @@ class Context : public compositor::Context { } }; -class Engine { +class Instance : public DrawEngine { private: Context context_; public: - Engine(char *info_message) : context_(info_message) {} + Instance() : context_(this->info) {} - void draw() + StringRefNull name_get() final { - compositor::Evaluator evaluator(context_); - evaluator.evaluate(); + return "Compositor"; + } + + void init() final{}; + void begin_sync() final{}; + void object_sync(blender::draw::ObjectRef & /*ob_ref*/, + blender::draw::Manager & /*manager*/) final{}; + void end_sync() final{}; + + void draw(Manager & /*manager*/) final + { + DRW_submission_start(); + +#if defined(__APPLE__) + if (GPU_backend_get_type() == GPU_BACKEND_METAL) { + /* NOTE(Metal): Isolate Compositor compute work in individual command buffer to improve + * workload scheduling. When expensive compositor nodes are in the graph, these can stall out + * the GPU for extended periods of time and sub-optimally schedule work for execution. */ + GPU_flush(); + } +#endif + + /* Execute Compositor render commands. */ + { + compositor::Evaluator evaluator(context_); + evaluator.evaluate(); + } + +#if defined(__APPLE__) + /* NOTE(Metal): Following previous flush to break command stream, with compositor command + * buffers potentially being heavy, we avoid issuing subsequent commands until compositor work + * has completed. If subsequent work is prematurely queued up, the subsequent command buffers + * will be blocked behind compositor work and may trigger a command buffer time-out error. As a + * result, we should wait for compositor work to complete. + * + * This is not an efficient approach for peak performance, but a catch-all to prevent command + * buffer failure, until the offending cases can be resolved. */ + if (GPU_backend_get_type() == GPU_BACKEND_METAL) { + GPU_finish(); + } +#endif + DRW_submission_end(); } }; +DrawEngine *Engine::create_instance() +{ + return new Instance(); +} + } // namespace blender::draw::compositor_engine - -using namespace blender::draw::compositor_engine; - -struct COMPOSITOR_Data { - DrawEngineType *engine_type; - Engine *instance_data; - char info[GPU_INFO_SIZE]; -}; - -static void compositor_engine_init(void *data) -{ - COMPOSITOR_Data *compositor_data = static_cast(data); - - if (!compositor_data->instance_data) { - compositor_data->instance_data = new Engine(compositor_data->info); - } -} - -static void compositor_engine_free(void *instance_data) -{ - Engine *engine = static_cast(instance_data); - delete engine; -} - -static void compositor_engine_draw(void *data) -{ - COMPOSITOR_Data *compositor_data = static_cast(data); - - DRW_submission_start(); - -#if defined(__APPLE__) - if (GPU_backend_get_type() == GPU_BACKEND_METAL) { - /* NOTE(Metal): Isolate Compositor compute work in individual command buffer to improve - * workload scheduling. When expensive compositor nodes are in the graph, these can stall out - * the GPU for extended periods of time and sub-optimally schedule work for execution. */ - GPU_flush(); - } -#endif - - /* Execute Compositor render commands. */ - compositor_data->instance_data->draw(); - -#if defined(__APPLE__) - /* NOTE(Metal): Following previous flush to break command stream, with compositor command - * buffers potentially being heavy, we avoid issuing subsequent commands until compositor work - * has completed. If subsequent work is prematurely queued up, the subsequent command buffers - * will be blocked behind compositor work and may trigger a command buffer time-out error. As a - * result, we should wait for compositor work to complete. - * - * This is not an efficient approach for peak performance, but a catch-all to prevent command - * buffer failure, until the offending cases can be resolved. */ - if (GPU_backend_get_type() == GPU_BACKEND_METAL) { - GPU_finish(); - } -#endif - DRW_submission_end(); -} - -DrawEngineType draw_engine_compositor_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("Compositor"), - /*engine_init*/ &compositor_engine_init, - /*engine_free*/ nullptr, - /*instance_free*/ &compositor_engine_free, - /*cache_init*/ nullptr, - /*cache_populate*/ nullptr, - /*cache_finish*/ nullptr, - /*draw_scene*/ &compositor_engine_draw, - /*render_to_image*/ nullptr, - /*store_metadata*/ nullptr, -}; diff --git a/source/blender/draw/engines/compositor/compositor_engine.h b/source/blender/draw/engines/compositor/compositor_engine.h index b45fa056538..d07de63de04 100644 --- a/source/blender/draw/engines/compositor/compositor_engine.h +++ b/source/blender/draw/engines/compositor/compositor_engine.h @@ -4,6 +4,12 @@ #pragma once -struct DrawEngineType; +#include "DRW_render.hh" -extern DrawEngineType draw_engine_compositor_type; +namespace blender::draw::compositor_engine { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; +}; + +} // namespace blender::draw::compositor_engine diff --git a/source/blender/draw/engines/eevee_next/eevee_engine.cc b/source/blender/draw/engines/eevee_next/eevee_engine.cc index 1db62e26d3e..9716aa1e9ae 100644 --- a/source/blender/draw/engines/eevee_next/eevee_engine.cc +++ b/source/blender/draw/engines/eevee_next/eevee_engine.cc @@ -19,177 +19,60 @@ #include "eevee_instance.hh" -using namespace blender; +namespace blender::eevee { -struct EEVEE_Data { - DrawEngineType *engine_type; - eevee::Instance *instance; - - char info[GPU_INFO_SIZE]; -}; - -static void eevee_engine_init(void *vedata) +DrawEngine *Engine::create_instance() { - EEVEE_Data *ved = reinterpret_cast(vedata); - if (ved->instance == nullptr) { - ved->instance = new eevee::Instance(); - } - - const DRWContext *ctx_state = DRW_context_get(); - Depsgraph *depsgraph = ctx_state->depsgraph; - Scene *scene = ctx_state->scene; - View3D *v3d = ctx_state->v3d; - ARegion *region = ctx_state->region; - RegionView3D *rv3d = ctx_state->rv3d; - - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - int2 size = int2(GPU_texture_width(dtxl->color), GPU_texture_height(dtxl->color)); - - draw::View &default_view = draw::View::default_get(); - - Object *camera = nullptr; - /* Get render borders. */ - rcti rect; - BLI_rcti_init(&rect, 0, size[0], 0, size[1]); - rcti visible_rect = rect; - if (v3d) { - if (rv3d && (rv3d->persp == RV3D_CAMOB)) { - camera = v3d->camera; - } - - if (camera) { - rctf default_border; - BLI_rctf_init(&default_border, 0.0f, 1.0f, 0.0f, 1.0f); - bool is_default_border = BLI_rctf_compare(&scene->r.border, &default_border, 0.0f); - bool use_border = scene->r.mode & R_BORDER; - if (!is_default_border && use_border) { - rctf viewborder; - /* TODO(fclem) Might be better to get it from DRW. */ - ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, false, &viewborder); - float viewborder_sizex = BLI_rctf_size_x(&viewborder); - float viewborder_sizey = BLI_rctf_size_y(&viewborder); - rect.xmin = floorf(viewborder.xmin + (scene->r.border.xmin * viewborder_sizex)); - rect.ymin = floorf(viewborder.ymin + (scene->r.border.ymin * viewborder_sizey)); - rect.xmax = floorf(viewborder.xmin + (scene->r.border.xmax * viewborder_sizex)); - rect.ymax = floorf(viewborder.ymin + (scene->r.border.ymax * viewborder_sizey)); - } - } - else if (v3d->flag2 & V3D_RENDER_BORDER) { - rect.xmin = v3d->render_border.xmin * size[0]; - rect.ymin = v3d->render_border.ymin * size[1]; - rect.xmax = v3d->render_border.xmax * size[0]; - rect.ymax = v3d->render_border.ymax * size[1]; - } - - if (DRW_state_is_viewport_image_render()) { - const float2 vp_size = DRW_viewport_size_get(); - visible_rect.xmax = vp_size[0]; - visible_rect.ymax = vp_size[1]; - visible_rect.xmin = visible_rect.ymin = 0; - } - else { - visible_rect = *ED_region_visible_rect(region); - } - } - - ved->instance->init( - size, &rect, &visible_rect, nullptr, depsgraph, camera, nullptr, &default_view, v3d, rv3d); + return new Instance(); } -static void eevee_draw_scene(void *vedata) +void Engine::free_static() { - EEVEE_Data *ved = reinterpret_cast(vedata); - if (DRW_state_is_viewport_image_render()) { - ved->instance->draw_viewport_image_render(); - } - else { - ved->instance->draw_viewport(); - } - STRNCPY(ved->info, ved->instance->info_get()); - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - GPU_framebuffer_viewport_reset(dfbl->default_fb); + ShaderModule::module_free(); } -static void eevee_cache_init(void *vedata) +} // namespace blender::eevee + +using namespace blender::eevee; + +void eevee_render(RenderEngine *engine, Depsgraph *depsgraph) { - reinterpret_cast(vedata)->instance->begin_sync(); -} + Instance *instance = nullptr; -static void eevee_cache_populate(void *vedata, draw::ObjectRef &ob_ref) -{ - reinterpret_cast(vedata)->instance->object_sync(ob_ref); -} + auto eevee_render_to_image = [&](RenderEngine *engine, RenderLayer *layer, const rcti /*rect*/) { + Render *render = engine->re; + Depsgraph *depsgraph = DRW_context_get()->depsgraph; + Object *camera_original_ob = RE_GetCamera(engine->re); + const char *viewname = RE_GetActiveRenderView(engine->re); + int size[2] = {engine->resolution_x, engine->resolution_y}; -static void eevee_cache_finish(void *vedata) -{ - reinterpret_cast(vedata)->instance->end_sync(); -} + /* WORKAROUND: Fails if created in the parent scope. Must be because of lack of active + * `DRWContext`. To be revisited. */ + instance = new Instance(); -static void eevee_engine_free() -{ - eevee::ShaderModule::module_free(); -} + rctf view_rect; + rcti rect; + RE_GetViewPlane(render, &view_rect, &rect); + rcti visible_rect = rect; -static void eevee_instance_free(void *instance) -{ - delete reinterpret_cast(instance); -} + instance->init(size, &rect, &visible_rect, engine, depsgraph, camera_original_ob, layer); + instance->render_frame(engine, layer, viewname); + }; -static void eevee_render_to_image(void *vedata, - RenderEngine *engine, - RenderLayer *layer, - const rcti * /*rect*/) -{ - eevee::Instance *instance = new eevee::Instance(); + auto eevee_store_metadata = [&](RenderResult *render_result) { + instance->store_metadata(render_result); + }; - Render *render = engine->re; - Depsgraph *depsgraph = DRW_context_get()->depsgraph; - Object *camera_original_ob = RE_GetCamera(engine->re); - const char *viewname = RE_GetActiveRenderView(engine->re); - int size[2] = {engine->resolution_x, engine->resolution_y}; + DRW_render_to_image(engine, depsgraph, eevee_render_to_image, eevee_store_metadata); - rctf view_rect; - rcti rect; - RE_GetViewPlane(render, &view_rect, &rect); - rcti visible_rect = rect; - - instance->init(size, &rect, &visible_rect, engine, depsgraph, camera_original_ob, layer); - instance->render_frame(engine, layer, viewname); - - EEVEE_Data *ved = static_cast(vedata); - delete ved->instance; - ved->instance = instance; -} - -static void eevee_store_metadata(void *vedata, RenderResult *render_result) -{ - EEVEE_Data *ved = static_cast(vedata); - eevee::Instance *instance = ved->instance; - instance->store_metadata(render_result); delete instance; - ved->instance = nullptr; } static void eevee_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) { - eevee::Instance::update_passes(engine, scene, view_layer); + Instance::update_passes(engine, scene, view_layer); } -DrawEngineType draw_engine_eevee_next_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("EEVEE"), - /*engine_init*/ &eevee_engine_init, - /*engine_free*/ &eevee_engine_free, - /*instance_free*/ &eevee_instance_free, - /*cache_init*/ &eevee_cache_init, - /*cache_populate*/ &eevee_cache_populate, - /*cache_finish*/ &eevee_cache_finish, - /*draw_scene*/ &eevee_draw_scene, - /*render_to_image*/ &eevee_render_to_image, - /*store_metadata*/ &eevee_store_metadata, -}; - RenderEngineType DRW_engine_viewport_eevee_next_type = { /*next*/ nullptr, /*prev*/ nullptr, @@ -197,7 +80,7 @@ RenderEngineType DRW_engine_viewport_eevee_next_type = { /*name*/ N_("EEVEE"), /*flag*/ RE_INTERNAL | RE_USE_PREVIEW | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT, /*update*/ nullptr, - /*render*/ &DRW_render_to_image, + /*render*/ &eevee_render, /*render_frame_finish*/ nullptr, /*draw*/ nullptr, /*bake*/ nullptr, @@ -205,7 +88,7 @@ RenderEngineType DRW_engine_viewport_eevee_next_type = { /*view_draw*/ nullptr, /*update_script_node*/ nullptr, /*update_render_passes*/ &eevee_render_update_passes, - /*draw_engine*/ &draw_engine_eevee_next_type, + /*draw_engine*/ nullptr, /*rna_ext*/ { /*data*/ nullptr, diff --git a/source/blender/draw/engines/eevee_next/eevee_engine.h b/source/blender/draw/engines/eevee_next/eevee_engine.h index e9012e280ce..8e0b223415a 100644 --- a/source/blender/draw/engines/eevee_next/eevee_engine.h +++ b/source/blender/draw/engines/eevee_next/eevee_engine.h @@ -11,5 +11,14 @@ #include "DRW_render.hh" #include "RE_engine.h" -extern DrawEngineType draw_engine_eevee_next_type; extern RenderEngineType DRW_engine_viewport_eevee_next_type; + +namespace blender::eevee { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; + + static void free_static(); +}; + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index f3d8906bfae..5d5adb65c1e 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -22,6 +22,8 @@ #include "DNA_lightprobe_types.h" #include "DNA_modifier_types.h" +#include "ED_screen.hh" +#include "ED_view3d.hh" #include "GPU_context.hh" #include "IMB_imbuf_types.hh" @@ -52,6 +54,68 @@ void *Instance::debug_scope_irradiance_sample = nullptr; * Any attempt to do so will likely produce use after free situations. * \{ */ +void Instance::init() +{ + const DRWContext *ctx_state = DRW_context_get(); + Depsgraph *depsgraph = ctx_state->depsgraph; + Scene *scene = ctx_state->scene; + View3D *v3d = ctx_state->v3d; + ARegion *region = ctx_state->region; + RegionView3D *rv3d = ctx_state->rv3d; + + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + int2 size = int2(GPU_texture_width(dtxl->color), GPU_texture_height(dtxl->color)); + + draw::View &default_view = draw::View::default_get(); + + Object *camera = nullptr; + /* Get render borders. */ + rcti rect; + BLI_rcti_init(&rect, 0, size[0], 0, size[1]); + rcti visible_rect = rect; + if (v3d) { + if (rv3d && (rv3d->persp == RV3D_CAMOB)) { + camera = v3d->camera; + } + + if (camera) { + rctf default_border; + BLI_rctf_init(&default_border, 0.0f, 1.0f, 0.0f, 1.0f); + bool is_default_border = BLI_rctf_compare(&scene->r.border, &default_border, 0.0f); + bool use_border = scene->r.mode & R_BORDER; + if (!is_default_border && use_border) { + rctf viewborder; + /* TODO(fclem) Might be better to get it from DRW. */ + ED_view3d_calc_camera_border(scene, depsgraph, region, v3d, rv3d, false, &viewborder); + float viewborder_sizex = BLI_rctf_size_x(&viewborder); + float viewborder_sizey = BLI_rctf_size_y(&viewborder); + rect.xmin = floorf(viewborder.xmin + (scene->r.border.xmin * viewborder_sizex)); + rect.ymin = floorf(viewborder.ymin + (scene->r.border.ymin * viewborder_sizey)); + rect.xmax = floorf(viewborder.xmin + (scene->r.border.xmax * viewborder_sizex)); + rect.ymax = floorf(viewborder.ymin + (scene->r.border.ymax * viewborder_sizey)); + } + } + else if (v3d->flag2 & V3D_RENDER_BORDER) { + rect.xmin = v3d->render_border.xmin * size[0]; + rect.ymin = v3d->render_border.ymin * size[1]; + rect.xmax = v3d->render_border.xmax * size[0]; + rect.ymax = v3d->render_border.ymax * size[1]; + } + + if (DRW_state_is_viewport_image_render()) { + const float2 vp_size = DRW_viewport_size_get(); + visible_rect.xmax = vp_size[0]; + visible_rect.ymax = vp_size[1]; + visible_rect.xmin = visible_rect.ymin = 0; + } + else { + visible_rect = *ED_region_visible_rect(region); + } + } + + init(size, &rect, &visible_rect, nullptr, depsgraph, camera, nullptr, &default_view, v3d, rv3d); +} + void Instance::init(const int2 &output_res, const rcti *output_rect, const rcti *visible_rect, @@ -249,7 +313,7 @@ void Instance::begin_sync() } } -void Instance::object_sync(ObjectRef &ob_ref) +void Instance::object_sync(ObjectRef &ob_ref, Manager & /*manager*/) { if (skip_render_) { return; @@ -314,16 +378,6 @@ void Instance::object_sync(ObjectRef &ob_ref) } } -void Instance::object_sync_render(void *instance_, - ObjectRef &ob_ref, - RenderEngine *engine, - Depsgraph *depsgraph) -{ - UNUSED_VARS(engine, depsgraph); - Instance &inst = *reinterpret_cast(instance_); - inst.object_sync(ob_ref); -} - void Instance::end_sync() { if (skip_render_) { @@ -354,7 +408,10 @@ void Instance::render_sync() begin_sync(); - DRW_render_object_iter(this, render, depsgraph, object_sync_render); + DRW_render_object_iter( + render, depsgraph, [this](blender::draw::ObjectRef &ob_ref, RenderEngine *, Depsgraph *) { + this->object_sync(ob_ref, *this->manager); + }); velocity.geometry_steps_fill(); @@ -621,6 +678,19 @@ void Instance::draw_viewport_image_render() } } +void Instance::draw(Manager & /*manager*/) +{ + if (DRW_state_is_viewport_image_render()) { + draw_viewport_image_render(); + } + else { + draw_viewport(); + } + STRNCPY(info, info_get()); + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + GPU_framebuffer_viewport_reset(dfbl->default_fb); +} + void Instance::store_metadata(RenderResult *render_result) { if (skip_render_) { @@ -710,7 +780,7 @@ void Instance::light_bake_irradiance( auto custom_pipeline_wrapper = [&](FunctionRef callback) { context_enable(); - DRW_custom_pipeline_begin(draw_ctx, &draw_engine_eevee_next_type, depsgraph); + DRW_custom_pipeline_begin(draw_ctx, depsgraph); callback(); DRW_custom_pipeline_end(draw_ctx); context_disable(); diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index e5a0431669e..fe6aefc3102 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -72,7 +72,7 @@ struct UniformDataModule { * \class Instance * \brief A running instance of the engine. */ -class Instance { +class Instance : public DrawEngine { friend VelocityModule; friend MotionBlurModule; @@ -180,6 +180,11 @@ class Instance { volume(*this, uniform_data.data.volumes){}; ~Instance(){}; + blender::StringRefNull name_get() final + { + return "EEVEE"; + } + /* Render & Viewport. */ /* TODO(fclem): Split for clarity. */ void init(const int2 &output_res, @@ -193,9 +198,11 @@ class Instance { const View3D *v3d = nullptr, const RegionView3D *rv3d = nullptr); - void begin_sync(); - void object_sync(ObjectRef &ob_ref); - void end_sync(); + void init() final; + + void begin_sync() final; + void object_sync(ObjectRef &ob_ref, Manager &manager) final; + void end_sync() final; /** * Return true when probe pipeline is used during this sample. @@ -221,6 +228,8 @@ class Instance { void draw_viewport(); void draw_viewport_image_render(); + void draw(Manager &manager) final; + /* Light bake. */ void init_light_bake(Depsgraph *depsgraph, draw::Manager *manager); @@ -370,11 +379,6 @@ class Instance { } private: - /** Wrapper to use with #DRW_render_object_iter. */ - static void object_sync_render(void *instance_, - ObjectRef &ob_ref, - RenderEngine *engine, - Depsgraph *depsgraph); /** * Conceptually renders one sample per pixel. * Everything based on random sampling should be done here (i.e: DRWViews jitter) diff --git a/source/blender/draw/engines/eevee_next/eevee_velocity.cc b/source/blender/draw/engines/eevee_next/eevee_velocity.cc index 259389802bb..b960f54f199 100644 --- a/source/blender/draw/engines/eevee_next/eevee_velocity.cc +++ b/source/blender/draw/engines/eevee_next/eevee_velocity.cc @@ -60,13 +60,8 @@ void VelocityModule::init() } /* Similar to Instance::object_sync, but only syncs velocity. */ -static void step_object_sync_render(void *instance, - ObjectRef &ob_ref, - RenderEngine * /*engine*/, - Depsgraph * /*depsgraph*/) +static void step_object_sync_render(Instance &inst, ObjectRef &ob_ref) { - Instance &inst = *reinterpret_cast(instance); - Object *ob = ob_ref.object; const bool is_velocity_type = ELEM(ob->type, OB_CURVES, OB_MESH, OB_POINTCLOUD); @@ -107,7 +102,11 @@ void VelocityModule::step_sync(eVelocityStep step, float time) object_steps_usage[step_] = 0; step_camera_sync(); - DRW_render_object_iter(&inst_, inst_.render, inst_.depsgraph, step_object_sync_render); + DRW_render_object_iter(inst_.render, + inst_.depsgraph, + [&](blender::draw::ObjectRef &ob_ref, RenderEngine *, Depsgraph *) { + step_object_sync_render(inst_, ob_ref); + }); geometry_steps_fill(); } diff --git a/source/blender/draw/engines/external/external_engine.cc b/source/blender/draw/engines/external/external_engine.cc index d2af904e12d..3b2952c6455 100644 --- a/source/blender/draw/engines/external/external_engine.cc +++ b/source/blender/draw/engines/external/external_engine.cc @@ -38,226 +38,227 @@ /* Shaders */ -#define EXTERNAL_ENGINE "BLENDER_EXTERNAL" +namespace blender::draw::external { +class Instance : public DrawEngine { + blender::StringRefNull name_get() final + { + return "External"; + } -struct EXTERNAL_Data { - void *engine_type; - void *instance_data; + void init() final {} - char info[GPU_INFO_SIZE]; -}; + void begin_sync() final {} -/* Functions */ + void object_sync(blender::draw::ObjectRef & /*ob_ref*/, + blender::draw::Manager & /*manager*/) final + { + } -static void external_draw_scene_do_v3d(void *vedata) -{ - const DRWContext *draw_ctx = DRW_context_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - ARegion *region = draw_ctx->region; + void end_sync() final {} - blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR); + void draw_scene_do_v3d() + { + const DRWContext *draw_ctx = DRW_context_get(); + RegionView3D *rv3d = draw_ctx->rv3d; + ARegion *region = draw_ctx->region; - /* The external engine can use the OpenGL rendering API directly, so make sure the state is - * already applied. */ - GPU_apply_state(); + blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR); - /* Create render engine. */ - RenderEngine *render_engine = nullptr; - if (!rv3d->view_render) { - RenderEngineType *engine_type = ED_view3d_engine_type(draw_ctx->scene, - draw_ctx->v3d->shading.type); + /* The external engine can use the OpenGL rendering API directly, so make sure the state is + * already applied. */ + GPU_apply_state(); - if (!(engine_type->view_update && engine_type->view_draw)) { + /* Create render engine. */ + RenderEngine *render_engine = nullptr; + if (!rv3d->view_render) { + RenderEngineType *engine_type = ED_view3d_engine_type(draw_ctx->scene, + draw_ctx->v3d->shading.type); + + if (!(engine_type->view_update && engine_type->view_draw)) { + return; + } + + rv3d->view_render = RE_NewViewRender(engine_type); + render_engine = RE_view_engine_get(rv3d->view_render); + engine_type->view_update(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph); + } + else { + render_engine = RE_view_engine_get(rv3d->view_render); + } + + /* Rendered draw. */ + GPU_matrix_push_projection(); + GPU_matrix_push(); + ED_region_pixelspace(region); + + /* Render result draw. */ + const RenderEngineType *type = render_engine->type; + type->view_draw(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph); + + GPU_bgl_end(); + + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + + /* Set render info. */ + if (render_engine->text[0] != '\0') { + STRNCPY(info, render_engine->text); + } + else { + info[0] = '\0'; + } + } + + /* Configure current matrix stack so that the external engine can use the same drawing code for + * both viewport and image editor drawing. + * + * The engine draws result in the pixel space, and is applying render offset. For image editor we + * need to switch from normalized space to pixel space, and "un-apply" offset. */ + static void external_image_space_matrix_set(const RenderEngine *engine) + { + BLI_assert(engine != nullptr); + + const DRWContext *draw_ctx = DRW_context_get(); + SpaceImage *space_image = (SpaceImage *)draw_ctx->space_data; + + /* Apply current view as transformation matrix. + * This will configure drawing for normalized space with current zoom and pan applied. */ + + float4x4 view_matrix = blender::draw::View::default_get().viewmat(); + float4x4 projection_matrix = blender::draw::View::default_get().winmat(); + + GPU_matrix_projection_set(projection_matrix.ptr()); + GPU_matrix_set(view_matrix.ptr()); + + /* Switch from normalized space to pixel space. */ + { + int width, height; + ED_space_image_get_size(space_image, &width, &height); + + const float width_inv = width ? 1.0f / width : 0.0f; + const float height_inv = height ? 1.0f / height : 0.0f; + GPU_matrix_scale_2f(width_inv, height_inv); + } + + /* Un-apply render offset. */ + { + Render *render = engine->re; + rctf view_rect; + rcti render_rect; + RE_GetViewPlane(render, &view_rect, &render_rect); + + GPU_matrix_translate_2f(-render_rect.xmin, -render_rect.ymin); + } + } + + void draw_scene_do_image() + { + const DRWContext *draw_ctx = DRW_context_get(); + Scene *scene = draw_ctx->scene; + Render *re = RE_GetSceneRender(scene); + RenderEngine *engine = RE_engine_get(re); + + /* Is tested before enabling the drawing engine. */ + BLI_assert(re != nullptr); + BLI_assert(engine != nullptr); + + blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR); + + /* The external engine can use the OpenGL rendering API directly, so make sure the state is + * already applied. */ + GPU_apply_state(); + + const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + /* Clear the depth buffer to the value used by the background overlay so that the overlay is + * not happening outside of the drawn image. + * + * NOTE: The external engine only draws color. The depth is taken care of using the depth pass + * which initialized the depth to the values expected by the background overlay. */ + GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f); + + GPU_matrix_push_projection(); + GPU_matrix_push(); + + external_image_space_matrix_set(engine); + + GPU_debug_group_begin("External Engine"); + + const RenderEngineType *engine_type = engine->type; + BLI_assert(engine_type != nullptr); + BLI_assert(engine_type->draw != nullptr); + + engine_type->draw(engine, draw_ctx->evil_C, draw_ctx->depsgraph); + + GPU_debug_group_end(); + + GPU_matrix_pop(); + GPU_matrix_pop_projection(); + + blender::draw::command::StateSet::set(); + GPU_bgl_end(); + + RE_engine_draw_release(re); + } + + void draw_scene_do() + { + const DRWContext *draw_ctx = DRW_context_get(); + + if (draw_ctx->v3d != nullptr) { + draw_scene_do_v3d(); return; } - rv3d->view_render = RE_NewViewRender(engine_type); - render_engine = RE_view_engine_get(rv3d->view_render); - engine_type->view_update(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph); - } - else { - render_engine = RE_view_engine_get(rv3d->view_render); + if (draw_ctx->space_data == nullptr) { + return; + } + + const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype); + if (space_type == SPACE_IMAGE) { + draw_scene_do_image(); + return; + } } - /* Rendered draw. */ - GPU_matrix_push_projection(); - GPU_matrix_push(); - ED_region_pixelspace(region); - - /* Render result draw. */ - const RenderEngineType *type = render_engine->type; - type->view_draw(render_engine, draw_ctx->evil_C, draw_ctx->depsgraph); - - GPU_bgl_end(); - - GPU_matrix_pop(); - GPU_matrix_pop_projection(); - - /* Set render info. */ - EXTERNAL_Data *data = static_cast(vedata); - if (render_engine->text[0] != '\0') { - STRNCPY(data->info, render_engine->text); - } - else { - data->info[0] = '\0'; - } -} - -/* Configure current matrix stack so that the external engine can use the same drawing code for - * both viewport and image editor drawing. - * - * The engine draws result in the pixel space, and is applying render offset. For image editor we - * need to switch from normalized space to pixel space, and "un-apply" offset. */ -static void external_image_space_matrix_set(const RenderEngine *engine) -{ - BLI_assert(engine != nullptr); - - const DRWContext *draw_ctx = DRW_context_get(); - SpaceImage *space_image = (SpaceImage *)draw_ctx->space_data; - - /* Apply current view as transformation matrix. - * This will configure drawing for normalized space with current zoom and pan applied. */ - - float4x4 view_matrix = blender::draw::View::default_get().viewmat(); - float4x4 projection_matrix = blender::draw::View::default_get().winmat(); - - GPU_matrix_projection_set(projection_matrix.ptr()); - GPU_matrix_set(view_matrix.ptr()); - - /* Switch from normalized space to pixel space. */ + void draw(blender::draw::Manager & /*manager*/) final { - int width, height; - ED_space_image_get_size(space_image, &width, &height); + const DRWContext *draw_ctx = DRW_context_get(); + const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - const float width_inv = width ? 1.0f / width : 0.0f; - const float height_inv = height ? 1.0f / height : 0.0f; - GPU_matrix_scale_2f(width_inv, height_inv); + /* Will be nullptr during OpenGL render. + * OpenGL render is used for quick preview (thumbnails or sequencer preview) + * where using the rendering engine to preview doesn't make so much sense. */ + if (draw_ctx->evil_C) { + const float clear_col[4] = {0, 0, 0, 0}; + /* This is to keep compatibility with external engine. */ + /* TODO(fclem): remove it eventually. */ + GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_clear_color(dfbl->default_fb, clear_col); + + DRW_submission_start(); + draw_scene_do(); + DRW_submission_end(); + } } - - /* Un-apply render offset. */ - { - Render *render = engine->re; - rctf view_rect; - rcti render_rect; - RE_GetViewPlane(render, &view_rect, &render_rect); - - GPU_matrix_translate_2f(-render_rect.xmin, -render_rect.ymin); - } -} - -static void external_draw_scene_do_image(void * /*vedata*/) -{ - const DRWContext *draw_ctx = DRW_context_get(); - Scene *scene = draw_ctx->scene; - Render *re = RE_GetSceneRender(scene); - RenderEngine *engine = RE_engine_get(re); - - /* Is tested before enabling the drawing engine. */ - BLI_assert(re != nullptr); - BLI_assert(engine != nullptr); - - blender::draw::command::StateSet::set(DRW_STATE_WRITE_COLOR); - - /* The external engine can use the OpenGL rendering API directly, so make sure the state is - * already applied. */ - GPU_apply_state(); - - const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - - /* Clear the depth buffer to the value used by the background overlay so that the overlay is not - * happening outside of the drawn image. - * - * NOTE: The external engine only draws color. The depth is taken care of using the depth pass - * which initialized the depth to the values expected by the background overlay. */ - GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f); - - GPU_matrix_push_projection(); - GPU_matrix_push(); - - external_image_space_matrix_set(engine); - - GPU_debug_group_begin("External Engine"); - - const RenderEngineType *engine_type = engine->type; - BLI_assert(engine_type != nullptr); - BLI_assert(engine_type->draw != nullptr); - - engine_type->draw(engine, draw_ctx->evil_C, draw_ctx->depsgraph); - - GPU_debug_group_end(); - - GPU_matrix_pop(); - GPU_matrix_pop_projection(); - - blender::draw::command::StateSet::set(); - GPU_bgl_end(); - - RE_engine_draw_release(re); -} - -static void external_draw_scene_do(void *vedata) -{ - const DRWContext *draw_ctx = DRW_context_get(); - - if (draw_ctx->v3d != nullptr) { - external_draw_scene_do_v3d(vedata); - return; - } - - if (draw_ctx->space_data == nullptr) { - return; - } - - const eSpace_Type space_type = eSpace_Type(draw_ctx->space_data->spacetype); - if (space_type == SPACE_IMAGE) { - external_draw_scene_do_image(vedata); - return; - } -} - -static void external_draw_scene(void *vedata) -{ - const DRWContext *draw_ctx = DRW_context_get(); - const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - - /* Will be nullptr during OpenGL render. - * OpenGL render is used for quick preview (thumbnails or sequencer preview) - * where using the rendering engine to preview doesn't make so much sense. */ - if (draw_ctx->evil_C) { - const float clear_col[4] = {0, 0, 0, 0}; - /* This is to keep compatibility with external engine. */ - /* TODO(fclem): remove it eventually. */ - GPU_framebuffer_bind(dfbl->default_fb); - GPU_framebuffer_clear_color(dfbl->default_fb, clear_col); - - DRW_submission_start(); - external_draw_scene_do(vedata); - DRW_submission_end(); - } -} - -DrawEngineType draw_engine_external_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("External"), - /*engine_init*/ nullptr, - /*engine_free*/ nullptr, - /*instance_free*/ nullptr, - /*cache_init*/ nullptr, - /*cache_populate*/ nullptr, - /*cache_finish*/ nullptr, - /*draw_scene*/ &external_draw_scene, - /*render_to_image*/ nullptr, - /*store_metadata*/ nullptr, }; +DrawEngine *Engine::create_instance() +{ + return new Instance(); +} + +} // namespace blender::draw::external + +/* Functions */ + /* NOTE: currently unused, * we should not register unless we want to see this when debugging the view. */ RenderEngineType DRW_engine_viewport_external_type = { /*next*/ nullptr, /*prev*/ nullptr, - /*idname*/ EXTERNAL_ENGINE, + /*idname*/ "BLENDER_EXTERNAL", /*name*/ N_("External"), /*flag*/ RE_INTERNAL | RE_USE_STEREO_VIEWPORT, /*update*/ nullptr, @@ -269,7 +270,7 @@ RenderEngineType DRW_engine_viewport_external_type = { /*view_draw*/ nullptr, /*update_script_node*/ nullptr, /*update_render_passes*/ nullptr, - /*draw_engine*/ &draw_engine_external_type, + /*draw_engine*/ nullptr, /*rna_ext*/ { /*data*/ nullptr, @@ -324,5 +325,3 @@ void DRW_engine_external_free(RegionView3D *rv3d) DRW_gpu_context_disable_ex(true); } } - -#undef EXTERNAL_ENGINE diff --git a/source/blender/draw/engines/external/external_engine.h b/source/blender/draw/engines/external/external_engine.h index 78dd6932e58..4255399b93f 100644 --- a/source/blender/draw/engines/external/external_engine.h +++ b/source/blender/draw/engines/external/external_engine.h @@ -8,10 +8,10 @@ #pragma once -struct DrawEngineType; +#include "DRW_render.hh" + struct RenderEngineType; -extern DrawEngineType draw_engine_external_type; extern RenderEngineType DRW_engine_viewport_external_type; /* Check whether an external engine is to be used to draw content of an image editor. @@ -20,3 +20,11 @@ extern RenderEngineType DRW_engine_viewport_external_type; * * NOTE: Released by the draw engine when it is done drawing. */ bool DRW_engine_external_acquire_for_image_editor(void); + +namespace blender::draw::external { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; +}; + +} // namespace blender::draw::external diff --git a/source/blender/draw/engines/gpencil/gpencil_antialiasing.cc b/source/blender/draw/engines/gpencil/gpencil_antialiasing.cc index 0133cd6cf00..5a5d451c088 100644 --- a/source/blender/draw/engines/gpencil/gpencil_antialiasing.cc +++ b/source/blender/draw/engines/gpencil/gpencil_antialiasing.cc @@ -9,11 +9,13 @@ #include "DNA_scene_types.h" #include "DRW_render.hh" -#include "gpencil_engine.h" +#include "gpencil_engine_private.hh" #include "BLI_smaa_textures.h" -void GPENCIL_antialiasing_init(GPENCIL_Instance *inst) +namespace blender::draw::gpencil { + +void GPENCIL_antialiasing_init(Instance *inst) { const float2 size_f = DRW_viewport_size_get(); const int2 size(size_f[0], size_f[1]); @@ -24,7 +26,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst) blender::draw::PassSimple &pass = inst->smaa_resolve_ps; pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); - pass.shader_set(GPENCIL_shader_antialiasing(2)); + pass.shader_set(ShaderCache::get().antialiasing[2].get()); pass.bind_texture("blendTex", &inst->color_tx); pass.bind_texture("colorTex", &inst->color_tx); pass.bind_texture("revealTex", &inst->reveal_tx); @@ -61,7 +63,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst) blender::draw::PassSimple &pass = inst->smaa_edge_ps; pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR); - pass.shader_set(GPENCIL_shader_antialiasing(0)); + pass.shader_set(ShaderCache::get().antialiasing[0].get()); pass.bind_texture("colorTex", &inst->color_tx); pass.bind_texture("revealTex", &inst->reveal_tx); pass.push_constant("viewportMetrics", metrics); @@ -74,7 +76,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst) blender::draw::PassSimple &pass = inst->smaa_weight_ps; pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR); - pass.shader_set(GPENCIL_shader_antialiasing(1)); + pass.shader_set(ShaderCache::get().antialiasing[1].get()); pass.bind_texture("edgesTex", &inst->smaa_edge_tx); pass.bind_texture("areaTex", &inst->smaa_area_tx); pass.bind_texture("searchTex", &inst->smaa_search_tx); @@ -87,7 +89,7 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst) blender::draw::PassSimple &pass = inst->smaa_resolve_ps; pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); - pass.shader_set(GPENCIL_shader_antialiasing(2)); + pass.shader_set(ShaderCache::get().antialiasing[2].get()); pass.bind_texture("blendTex", &inst->smaa_weight_tx); pass.bind_texture("colorTex", &inst->color_tx); pass.bind_texture("revealTex", &inst->reveal_tx); @@ -98,10 +100,8 @@ void GPENCIL_antialiasing_init(GPENCIL_Instance *inst) } } -void GPENCIL_antialiasing_draw(GPENCIL_Data *vedata) +void GPENCIL_antialiasing_draw(Instance *inst) { - GPENCIL_Instance *inst = vedata->instance; - blender::draw::Manager *manager = DRW_manager_get(); if (!inst->simplify_antialias) { @@ -115,3 +115,5 @@ void GPENCIL_antialiasing_draw(GPENCIL_Data *vedata) GPU_framebuffer_bind(inst->scene_fb); manager->submit(inst->smaa_resolve_ps); } + +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc b/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc index 820e8c5185b..1f41d0453ea 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.cc @@ -27,17 +27,19 @@ #include "BLI_math_vector.hh" #include "BLI_memblock.h" -#include "gpencil_engine.h" +#include "gpencil_engine_private.hh" #include "DEG_depsgraph.hh" #include "UI_resources.hh" +namespace blender::draw::gpencil { + /* -------------------------------------------------------------------- */ /** \name Object * \{ */ -GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_Instance *inst, +GPENCIL_tObject *gpencil_object_cache_add(Instance *inst, Object *ob, const bool is_stroke_order_3d, const blender::Bounds bounds) @@ -144,7 +146,7 @@ static int gpencil_tobject_dist_sort(const void *a, const void *b) return 0; } -void gpencil_object_cache_sort(GPENCIL_Instance *inst) +void gpencil_object_cache_sort(Instance *inst) { /* Sort object by distance to the camera. */ if (inst->tobjects.first) { @@ -184,7 +186,7 @@ void gpencil_object_cache_sort(GPENCIL_Instance *inst) /** \name Layer * \{ */ -static float grease_pencil_layer_final_opacity_get(const GPENCIL_Instance *inst, +static float grease_pencil_layer_final_opacity_get(const Instance *inst, const Object *ob, const GreasePencil &grease_pencil, const blender::bke::greasepencil::Layer &layer) @@ -206,7 +208,7 @@ static float grease_pencil_layer_final_opacity_get(const GPENCIL_Instance *inst, return layer.opacity; } -static float4 grease_pencil_layer_final_tint_and_alpha_get(const GPENCIL_Instance *inst, +static float4 grease_pencil_layer_final_tint_and_alpha_get(const Instance *inst, const GreasePencil &grease_pencil, const int onion_id, float *r_alpha) @@ -286,7 +288,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_get(GPENCIL_tObject *tgp_ob, return nullptr; } -GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst, +GPENCIL_tLayer *grease_pencil_layer_cache_add(Instance *inst, const Object *ob, const blender::bke::greasepencil::Layer &layer, const int onion_id, @@ -407,7 +409,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst, PassSimple &pass = *tgp_layer->blend_ps; pass.init(); pass.state_set(state); - pass.shader_set(GPENCIL_shader_layer_blend_get()); + pass.shader_set(ShaderCache::get().layer_blend.get()); pass.push_constant("blendMode", int(layer.blend_mode)); pass.push_constant("blendOpacity", layer_opacity); pass.bind_texture("colorBuf", &inst->color_layer_tx); @@ -445,7 +447,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst, state |= DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; pass.state_set(state); - pass.shader_set(GPENCIL_shader_geometry_get()); + pass.shader_set(ShaderCache::get().geometry.get()); pass.bind_texture("gpSceneDepthTexture", depth_tex); pass.bind_texture("gpMaskTexture", mask_tex); pass.push_constant("gpNormal", tgp_ob->plane_normal); @@ -471,3 +473,5 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst, return tgp_layer; } /** \} */ + +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.cc b/source/blender/draw/engines/gpencil/gpencil_draw_data.cc index fe2fa06835d..85abbb2a084 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.cc +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.cc @@ -22,13 +22,15 @@ #include "IMB_imbuf_types.hh" -#include "gpencil_engine.h" +#include "gpencil_engine_private.hh" + +namespace blender::draw::gpencil { /* -------------------------------------------------------------------- */ /** \name Material * \{ */ -static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_Instance *inst) +static GPENCIL_MaterialPool *gpencil_material_pool_add(Instance *inst) { GPENCIL_MaterialPool *matpool = static_cast( BLI_memblock_alloc(inst->gp_material_pool)); @@ -41,7 +43,7 @@ static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_Instance *inst) return matpool; } -static GPUTexture *gpencil_image_texture_get(Image *image, bool *r_alpha_premult) +static GPUTexture *gpencil_image_texture_get(::Image *image, bool *r_alpha_premult) { ImageUser iuser = {nullptr}; GPUTexture *gpu_tex = nullptr; @@ -88,7 +90,7 @@ static void gpencil_shade_color(float color[3]) /* Apply all overrides from the solid viewport mode to the GPencil material. */ static MaterialGPencilStyle *gpencil_viewport_material_overrides( - GPENCIL_Instance *inst, + Instance *inst, Object *ob, int color_type, MaterialGPencilStyle *gp_style, @@ -159,7 +161,7 @@ static MaterialGPencilStyle *gpencil_viewport_material_overrides( return gp_style; } -GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_Instance *inst, +GPENCIL_MaterialPool *gpencil_material_pool_create(Instance *inst, Object *ob, int *ofs, const bool is_vertex_mode) @@ -327,7 +329,7 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool, /** \name Lights * \{ */ -GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_Instance *inst) +GPENCIL_LightPool *gpencil_light_pool_add(Instance *inst) { GPENCIL_LightPool *lightpool = static_cast( BLI_memblock_alloc(inst->gp_light_pool)); @@ -414,7 +416,7 @@ void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob) } } -GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_Instance *inst, Object * /*ob*/) +GPENCIL_LightPool *gpencil_light_pool_create(Instance *inst, Object * /*ob*/) { GPENCIL_LightPool *lightpool = inst->last_light_pool; @@ -427,57 +429,6 @@ GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_Instance *inst, Object * /* return lightpool; } -void gpencil_material_pool_free(void *storage) -{ - GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage; - GPU_UBO_FREE_SAFE(matpool->ubo); -} - -void gpencil_light_pool_free(void *storage) -{ - GPENCIL_LightPool *lightpool = (GPENCIL_LightPool *)storage; - GPU_UBO_FREE_SAFE(lightpool->ubo); -} - /** \} */ -/* -------------------------------------------------------------------- */ -/** \name View Layer Data - * \{ */ - -static void gpencil_view_layer_data_free(void *storage) -{ - GPENCIL_ViewLayerData *vldata = (GPENCIL_ViewLayerData *)storage; - - BLI_memblock_destroy(vldata->gp_light_pool, gpencil_light_pool_free); - BLI_memblock_destroy(vldata->gp_material_pool, gpencil_material_pool_free); - BLI_memblock_destroy(vldata->gp_maskbit_pool, nullptr); - BLI_memblock_destroy(vldata->gp_object_pool, nullptr); - delete vldata->gp_layer_pool; - delete vldata->gp_vfx_pool; -} - -GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure() -{ - GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure( - &draw_engine_gpencil_type, gpencil_view_layer_data_free); - - /* NOTE(@fclem): Putting this stuff in view-layer means it is shared by all viewports. - * For now it is ok, but in the future, it could become a problem if we implement - * the caching system. */ - if (*vldata == nullptr) { - *vldata = static_cast( - MEM_callocN(sizeof(**vldata), "GPENCIL_ViewLayerData")); - - (*vldata)->gp_light_pool = BLI_memblock_create(sizeof(GPENCIL_LightPool)); - (*vldata)->gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool)); - (*vldata)->gp_maskbit_pool = BLI_memblock_create(BLI_BITMAP_SIZE(GP_MAX_MASKBITS)); - (*vldata)->gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject)); - (*vldata)->gp_layer_pool = new GPENCIL_tLayer_Pool(); - (*vldata)->gp_vfx_pool = new GPENCIL_tVfx_Pool(); - } - - return *vldata; -} - -/** \} */ +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.hh b/source/blender/draw/engines/gpencil/gpencil_engine.hh new file mode 100644 index 00000000000..6f16aede8ef --- /dev/null +++ b/source/blender/draw/engines/gpencil/gpencil_engine.hh @@ -0,0 +1,22 @@ +/* SPDX-FileCopyrightText: 2017 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup draw + */ + +#pragma once + +#include "DRW_render.hh" + +namespace blender::draw::gpencil { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; + + static void render_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti rect); + static void free_static(); +}; + +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc index ce4cca802d0..50512acc0d0 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine_c.cc +++ b/source/blender/draw/engines/gpencil/gpencil_engine_c.cc @@ -39,7 +39,8 @@ #include "draw_manager.hh" #include "draw_view.hh" -#include "gpencil_engine.h" +#include "gpencil_engine.hh" +#include "gpencil_engine_private.hh" #include "DEG_depsgraph_query.hh" @@ -49,67 +50,62 @@ #include "GPU_debug.hh" -/* *********** FUNCTIONS *********** */ +namespace blender::draw::gpencil { -void GPENCIL_engine_init(void *ved) +using namespace blender::draw; + +void Instance::init() { - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; const DRWContext *ctx = DRW_context_get(); const View3D *v3d = ctx->v3d; - if (vedata->instance == nullptr) { - vedata->instance = new GPENCIL_Instance(); - } - GPENCIL_Instance &inst = *vedata->instance; - - if (!inst.dummy_texture.is_valid()) { + if (!dummy_texture.is_valid()) { const float pixels[1][4] = {{1.0f, 0.0f, 1.0f, 1.0f}}; - inst.dummy_texture.ensure_2d(GPU_RGBA8, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, &pixels[0][0]); + dummy_texture.ensure_2d(GPU_RGBA8, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, &pixels[0][0]); } - if (!inst.dummy_depth.is_valid()) { + if (!dummy_depth.is_valid()) { const float pixels[1] = {1.0f}; - inst.dummy_depth.ensure_2d( + dummy_depth.ensure_2d( GPU_DEPTH_COMPONENT24, int2(1), GPU_TEXTURE_USAGE_SHADER_READ, &pixels[0]); } - GPENCIL_ViewLayerData *vldata = GPENCIL_view_layer_data_ensure(); - /* Resize and reset memory-blocks. */ - BLI_memblock_clear(vldata->gp_light_pool, gpencil_light_pool_free); - BLI_memblock_clear(vldata->gp_material_pool, gpencil_material_pool_free); - BLI_memblock_clear(vldata->gp_object_pool, nullptr); - vldata->gp_layer_pool->clear(); - vldata->gp_vfx_pool->clear(); - BLI_memblock_clear(vldata->gp_maskbit_pool, nullptr); + BLI_memblock_clear(vldata.gp_light_pool, ViewLayerData::light_pool_free); + BLI_memblock_clear(vldata.gp_material_pool, ViewLayerData::material_pool_free); + BLI_memblock_clear(vldata.gp_object_pool, nullptr); + vldata.gp_layer_pool->clear(); + vldata.gp_vfx_pool->clear(); + BLI_memblock_clear(vldata.gp_maskbit_pool, nullptr); - inst.gp_light_pool = vldata->gp_light_pool; - inst.gp_material_pool = vldata->gp_material_pool; - inst.gp_maskbit_pool = vldata->gp_maskbit_pool; - inst.gp_object_pool = vldata->gp_object_pool; - inst.gp_layer_pool = vldata->gp_layer_pool; - inst.gp_vfx_pool = vldata->gp_vfx_pool; - inst.view_layer = ctx->view_layer; - inst.scene = ctx->scene; - inst.v3d = ctx->v3d; - inst.last_light_pool = nullptr; - inst.last_material_pool = nullptr; - inst.tobjects.first = nullptr; - inst.tobjects.last = nullptr; - inst.tobjects_infront.first = nullptr; - inst.tobjects_infront.last = nullptr; - inst.sbuffer_tobjects.first = nullptr; - inst.sbuffer_tobjects.last = nullptr; - inst.dummy_tx = inst.dummy_texture; - inst.draw_wireframe = (v3d && v3d->shading.type == OB_WIRE); - inst.scene_depth_tx = nullptr; - inst.scene_fb = nullptr; - inst.is_render = inst.render_depth_tx.is_valid() || (v3d && v3d->shading.type == OB_RENDER); - inst.is_viewport = (v3d != nullptr); - inst.global_light_pool = gpencil_light_pool_add(&inst); - inst.shadeless_light_pool = gpencil_light_pool_add(&inst); + /* TODO remove */ + this->gp_light_pool = vldata.gp_light_pool; + this->gp_material_pool = vldata.gp_material_pool; + this->gp_maskbit_pool = vldata.gp_maskbit_pool; + this->gp_object_pool = vldata.gp_object_pool; + this->gp_layer_pool = vldata.gp_layer_pool; + this->gp_vfx_pool = vldata.gp_vfx_pool; + this->view_layer = ctx->view_layer; + this->scene = ctx->scene; + this->v3d = ctx->v3d; + this->last_light_pool = nullptr; + this->last_material_pool = nullptr; + this->tobjects.first = nullptr; + this->tobjects.last = nullptr; + this->tobjects_infront.first = nullptr; + this->tobjects_infront.last = nullptr; + this->sbuffer_tobjects.first = nullptr; + this->sbuffer_tobjects.last = nullptr; + this->dummy_tx = this->dummy_texture; + this->draw_wireframe = (v3d && v3d->shading.type == OB_WIRE); + this->scene_depth_tx = nullptr; + this->scene_fb = nullptr; + this->is_render = this->render_depth_tx.is_valid() || (v3d && v3d->shading.type == OB_RENDER); + this->is_viewport = (v3d != nullptr); + this->global_light_pool = gpencil_light_pool_add(this); + this->shadeless_light_pool = gpencil_light_pool_add(this); /* Small HACK: we don't want the global pool to be reused, * so we set the last light pool to nullptr. */ - inst.last_light_pool = nullptr; + this->last_light_pool = nullptr; bool use_scene_lights = false; bool use_scene_world = false; @@ -119,76 +115,72 @@ void GPENCIL_engine_init(void *ved) use_scene_world = V3D_USES_SCENE_WORLD(v3d); - inst.v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1; + this->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1; /* Special case: If we're in Vertex Paint mode, enforce #V3D_SHADING_VERTEX_COLOR setting. */ if (v3d->shading.type == OB_SOLID && ctx->obact && (ctx->obact->mode & OB_MODE_VERTEX_GREASE_PENCIL) != 0) { - inst.v3d_color_type = V3D_SHADING_VERTEX_COLOR; + this->v3d_color_type = V3D_SHADING_VERTEX_COLOR; } - copy_v3_v3(inst.v3d_single_color, v3d->shading.single_color); + copy_v3_v3(this->v3d_single_color, v3d->shading.single_color); /* For non active frame, use only lines in multiedit mode. */ const bool overlays_on = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; - inst.use_multiedit_lines_only = overlays_on && - (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0; + this->use_multiedit_lines_only = overlays_on && + (v3d->gp_flag & V3D_GP_SHOW_MULTIEDIT_LINES) != 0; const bool shmode_xray_support = v3d->shading.type <= OB_SOLID; - inst.xray_alpha = (shmode_xray_support && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f; - inst.force_stroke_order_3d = v3d->gp_flag & V3D_GP_FORCE_STROKE_ORDER_3D; + this->xray_alpha = (shmode_xray_support && XRAY_ENABLED(v3d)) ? XRAY_ALPHA(v3d) : 1.0f; + this->force_stroke_order_3d = v3d->gp_flag & V3D_GP_FORCE_STROKE_ORDER_3D; } - else if (inst.is_render) { + else if (this->is_render) { use_scene_lights = true; use_scene_world = true; - inst.use_multiedit_lines_only = false; - inst.xray_alpha = 1.0f; - inst.v3d_color_type = -1; - inst.force_stroke_order_3d = false; + this->use_multiedit_lines_only = false; + this->xray_alpha = 1.0f; + this->v3d_color_type = -1; + this->force_stroke_order_3d = false; } - inst.use_lighting = (v3d && v3d->shading.type > OB_SOLID) || inst.is_render; - inst.use_lights = use_scene_lights; + this->use_lighting = (v3d && v3d->shading.type > OB_SOLID) || this->is_render; + this->use_lights = use_scene_lights; - gpencil_light_ambient_add(inst.shadeless_light_pool, blender::float3{1.0f, 1.0f, 1.0f}); + gpencil_light_ambient_add(this->shadeless_light_pool, blender::float3{1.0f, 1.0f, 1.0f}); World *world = ctx->scene->world; if (world != nullptr && use_scene_world) { - gpencil_light_ambient_add(inst.global_light_pool, &world->horr); + gpencil_light_ambient_add(this->global_light_pool, &world->horr); } else if (v3d) { float world_light[3]; copy_v3_fl(world_light, v3d->shading.studiolight_intensity); - gpencil_light_ambient_add(inst.global_light_pool, world_light); + gpencil_light_ambient_add(this->global_light_pool, world_light); } float4x4 viewmatinv = blender::draw::View::default_get().viewinv(); - copy_v3_v3(inst.camera_z_axis, viewmatinv[2]); - copy_v3_v3(inst.camera_pos, viewmatinv[3]); - inst.camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]); + copy_v3_v3(this->camera_z_axis, viewmatinv[2]); + copy_v3_v3(this->camera_pos, viewmatinv[3]); + this->camera_z_offset = dot_v3v3(viewmatinv[3], viewmatinv[2]); if (ctx && ctx->rv3d && v3d) { - inst.camera = (ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : nullptr; + this->camera = (ctx->rv3d->persp == RV3D_CAMOB) ? v3d->camera : nullptr; } else { - inst.camera = nullptr; + this->camera = nullptr; } } -void GPENCIL_cache_init(void *ved) +void Instance::begin_sync() { - using namespace blender::draw; - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; - GPENCIL_Instance *inst = vedata->instance; - const DRWContext *draw_ctx = DRW_context_get(); - inst->cfra = int(DEG_get_ctime(draw_ctx->depsgraph)); - inst->simplify_antialias = GPENCIL_SIMPLIFY_AA(draw_ctx->scene); - inst->use_layer_fb = false; - inst->use_object_fb = false; - inst->use_mask_fb = false; + this->cfra = int(DEG_get_ctime(draw_ctx->depsgraph)); + this->simplify_antialias = GPENCIL_SIMPLIFY_AA(draw_ctx->scene); + this->use_layer_fb = false; + this->use_object_fb = false; + this->use_mask_fb = false; /* Always use high precision for render. */ - inst->use_signed_fb = !inst->is_viewport; + this->use_signed_fb = !this->is_viewport; if (draw_ctx->v3d) { const bool hide_overlay = ((draw_ctx->v3d->flag2 & V3D_HIDE_OVERLAYS) != 0); @@ -197,95 +189,95 @@ void GPENCIL_cache_init(void *ved) ED_screen_animation_playing(CTX_wm_manager(draw_ctx->evil_C)) != nullptr : false; - inst->do_onion = show_onion && !hide_overlay && !playing; - inst->playing = playing; + this->do_onion = show_onion && !hide_overlay && !playing; + this->playing = playing; /* Save simplify flags (can change while drawing, so it's better to save). */ Scene *scene = draw_ctx->scene; - inst->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing); - inst->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, playing) || + this->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, playing); + this->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, playing) || (draw_ctx->v3d->shading.type < OB_RENDER); /* Fade Layer. */ - const bool is_fade_layer = ((!hide_overlay) && (!inst->is_render) && + const bool is_fade_layer = ((!hide_overlay) && (!this->is_render) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_LAYERS)); - inst->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f; - inst->vertex_paint_opacity = draw_ctx->v3d->overlay.gpencil_vertex_paint_opacity; + this->fade_layer_opacity = (is_fade_layer) ? draw_ctx->v3d->overlay.gpencil_fade_layer : -1.0f; + this->vertex_paint_opacity = draw_ctx->v3d->overlay.gpencil_vertex_paint_opacity; /* Fade GPencil Objects. */ - const bool is_fade_object = ((!hide_overlay) && (!inst->is_render) && + const bool is_fade_object = ((!hide_overlay) && (!this->is_render) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_NOACTIVE_GPENCIL)); - inst->fade_gp_object_opacity = (is_fade_object) ? + this->fade_gp_object_opacity = (is_fade_object) ? draw_ctx->v3d->overlay.gpencil_paper_opacity : -1.0f; - inst->fade_3d_object_opacity = ((!hide_overlay) && (!inst->is_render) && + this->fade_3d_object_opacity = ((!hide_overlay) && (!this->is_render) && (draw_ctx->v3d->gp_flag & V3D_GP_FADE_OBJECTS)) ? draw_ctx->v3d->overlay.gpencil_paper_opacity : -1.0f; } else { - inst->do_onion = true; + this->do_onion = true; Scene *scene = draw_ctx->scene; - inst->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, false); - inst->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, false); - inst->fade_layer_opacity = -1.0f; - inst->playing = false; + this->simplify_fill = GPENCIL_SIMPLIFY_FILL(scene, false); + this->simplify_fx = GPENCIL_SIMPLIFY_FX(scene, false); + this->fade_layer_opacity = -1.0f; + this->playing = false; } { - inst->stroke_batch = nullptr; - inst->fill_batch = nullptr; - inst->do_fast_drawing = false; + this->stroke_batch = nullptr; + this->fill_batch = nullptr; + this->do_fast_drawing = false; - inst->obact = draw_ctx->obact; + this->obact = draw_ctx->obact; } - if (inst->do_fast_drawing) { - inst->snapshot_buffer_dirty = !inst->snapshot_depth_tx.is_valid(); + if (this->do_fast_drawing) { + this->snapshot_buffer_dirty = !this->snapshot_depth_tx.is_valid(); const float2 size = DRW_viewport_size_get(); eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT; - inst->snapshot_depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, int2(size), usage); - inst->snapshot_color_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage); - inst->snapshot_reveal_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage); + this->snapshot_depth_tx.ensure_2d(GPU_DEPTH24_STENCIL8, int2(size), usage); + this->snapshot_color_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage); + this->snapshot_reveal_tx.ensure_2d(GPU_R11F_G11F_B10F, int2(size), usage); - inst->snapshot_fb.ensure(GPU_ATTACHMENT_TEXTURE(inst->snapshot_depth_tx), - GPU_ATTACHMENT_TEXTURE(inst->snapshot_color_tx), - GPU_ATTACHMENT_TEXTURE(inst->snapshot_reveal_tx)); + this->snapshot_fb.ensure(GPU_ATTACHMENT_TEXTURE(this->snapshot_depth_tx), + GPU_ATTACHMENT_TEXTURE(this->snapshot_color_tx), + GPU_ATTACHMENT_TEXTURE(this->snapshot_reveal_tx)); } else { /* Free unneeded buffers. */ - inst->snapshot_depth_tx.free(); - inst->snapshot_color_tx.free(); - inst->snapshot_reveal_tx.free(); + this->snapshot_depth_tx.free(); + this->snapshot_color_tx.free(); + this->snapshot_reveal_tx.free(); } { - blender::draw::PassSimple &pass = inst->merge_depth_ps; + blender::draw::PassSimple &pass = this->merge_depth_ps; pass.init(); pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); - pass.shader_set(GPENCIL_shader_depth_merge_get()); - pass.bind_texture("depthBuf", &inst->depth_tx); - pass.push_constant("strokeOrder3d", &inst->is_stroke_order_3d); - pass.push_constant("gpModelMatrix", &inst->object_bound_mat); + pass.shader_set(ShaderCache::get().depth_merge.get()); + pass.bind_texture("depthBuf", &this->depth_tx); + pass.push_constant("strokeOrder3d", &this->is_stroke_order_3d); + pass.push_constant("gpModelMatrix", &this->object_bound_mat); pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); } { - blender::draw::PassSimple &pass = inst->mask_invert_ps; + blender::draw::PassSimple &pass = this->mask_invert_ps; pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_LOGIC_INVERT); - pass.shader_set(GPENCIL_shader_mask_invert_get()); + pass.shader_set(ShaderCache::get().mask_invert.get()); pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); } Camera *cam = static_cast( - (inst->camera != nullptr && inst->camera->type == OB_CAMERA) ? inst->camera->data : nullptr); + (this->camera != nullptr && this->camera->type == OB_CAMERA) ? this->camera->data : nullptr); /* Pseudo DOF setup. */ if (cam && (cam->dof.flag & CAM_DOF_ENABLED)) { const float2 vp_size = DRW_viewport_size_get(); float fstop = cam->dof.aperture_fstop; float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); - float focus_dist = BKE_camera_object_dof_distance(inst->camera); + float focus_dist = BKE_camera_object_dof_distance(this->camera); float focal_len = cam->lens; const float scale_camera = 0.001f; @@ -298,13 +290,13 @@ void GPENCIL_cache_init(void *ved) sensor_scaled *= draw_ctx->rv3d->viewcamtexcofac[0]; } - inst->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); - inst->dof_params[1] *= vp_size[0] / sensor_scaled; - inst->dof_params[0] = -focus_dist * inst->dof_params[1]; + this->dof_params[1] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); + this->dof_params[1] *= vp_size[0] / sensor_scaled; + this->dof_params[0] = -focus_dist * this->dof_params[1]; } else { /* Disable DoF blur scaling. */ - inst->camera = nullptr; + this->camera = nullptr; } } @@ -358,7 +350,7 @@ static bool use_layer_in_render(const GreasePencil &grease_pencil, } static GPENCIL_tObject *grease_pencil_object_cache_populate( - GPENCIL_Instance *inst, Object *ob, blender::draw::ResourceHandle res_handle) + Instance *inst, Object *ob, blender::draw::ResourceHandle res_handle) { using namespace blender; using namespace blender::ed::greasepencil; @@ -590,10 +582,8 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate( return tgp_ob; } -void GPENCIL_cache_populate(void *ved, blender::draw::ObjectRef &ob_ref) +void Instance::object_sync(ObjectRef &ob_ref, Manager &manager) { - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; - GPENCIL_Instance *inst = vedata->instance; Object *ob = ob_ref.object; /* object must be visible */ @@ -602,43 +592,39 @@ void GPENCIL_cache_populate(void *ved, blender::draw::ObjectRef &ob_ref) } if (ob->data && (ob->type == OB_GREASE_PENCIL) && (ob->dt >= OB_SOLID)) { - blender::draw::Manager *manager = DRW_manager_get(); - blender::draw::ResourceHandle res_handle = manager->unique_handle(ob_ref); + blender::draw::ResourceHandle res_handle = manager.unique_handle(ob_ref); - GPENCIL_tObject *tgp_ob = grease_pencil_object_cache_populate(inst, ob, res_handle); + GPENCIL_tObject *tgp_ob = grease_pencil_object_cache_populate(this, ob, res_handle); gpencil_vfx_cache_populate( - vedata, + this, ob, tgp_ob, ELEM(ob->mode, OB_MODE_EDIT, OB_MODE_SCULPT_GREASE_PENCIL, OB_MODE_WEIGHT_GREASE_PENCIL)); } - if (ob->type == OB_LAMP && inst->use_lights) { - gpencil_light_pool_populate(inst->global_light_pool, ob); + if (ob->type == OB_LAMP && this->use_lights) { + gpencil_light_pool_populate(this->global_light_pool, ob); } } -void GPENCIL_cache_finish(void *ved) +void Instance::end_sync() { - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; - GPENCIL_Instance *inst = vedata->instance; - /* Upload UBO data. */ BLI_memblock_iter iter; - BLI_memblock_iternew(inst->gp_material_pool, &iter); + BLI_memblock_iternew(this->gp_material_pool, &iter); GPENCIL_MaterialPool *pool; while ((pool = (GPENCIL_MaterialPool *)BLI_memblock_iterstep(&iter))) { GPU_uniformbuf_update(pool->ubo, pool->mat_data); } - BLI_memblock_iternew(inst->gp_light_pool, &iter); + BLI_memblock_iternew(this->gp_light_pool, &iter); GPENCIL_LightPool *lpool; while ((lpool = (GPENCIL_LightPool *)BLI_memblock_iterstep(&iter))) { GPU_uniformbuf_update(lpool->ubo, lpool->light_data); } } -void GPENCIL_Instance::acquire_resources() +void Instance::acquire_resources() { /* Create frame-buffers only if needed. */ if (this->tobjects.first == nullptr) { @@ -690,7 +676,7 @@ void GPENCIL_Instance::acquire_resources() } } -void GPENCIL_Instance::release_resources() +void Instance::release_resources() { this->depth_tx.release(); this->color_tx.release(); @@ -706,12 +692,11 @@ void GPENCIL_Instance::release_resources() this->smaa_weight_tx.release(); } -static void gpencil_draw_mask(GPENCIL_Data *vedata, +static void gpencil_draw_mask(Instance *inst, blender::draw::View &view, GPENCIL_tObject *ob, GPENCIL_tLayer *layer) { - GPENCIL_Instance *inst = vedata->instance; blender::draw::Manager *manager = DRW_manager_get(); const float clear_col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -759,11 +744,8 @@ static void gpencil_draw_mask(GPENCIL_Data *vedata, GPU_debug_group_end(); } -static void GPENCIL_draw_object(GPENCIL_Data *vedata, - blender::draw::View &view, - GPENCIL_tObject *ob) +static void GPENCIL_draw_object(Instance *inst, blender::draw::View &view, GPENCIL_tObject *ob) { - GPENCIL_Instance *inst = vedata->instance; blender::draw::Manager *manager = DRW_manager_get(); const float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}; @@ -781,7 +763,7 @@ static void GPENCIL_draw_object(GPENCIL_Data *vedata, LISTBASE_FOREACH (GPENCIL_tLayer *, layer, &ob->layers) { if (layer->mask_bits) { - gpencil_draw_mask(vedata, view, ob, layer); + gpencil_draw_mask(inst, view, ob, layer); } if (layer->blend_ps) { @@ -816,10 +798,8 @@ static void GPENCIL_draw_object(GPENCIL_Data *vedata, GPU_debug_group_end(); } -static void GPENCIL_fast_draw_start(GPENCIL_Data *vedata) +static void GPENCIL_fast_draw_start(Instance *inst) { - GPENCIL_Instance *inst = vedata->instance; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); if (!inst->snapshot_buffer_dirty) { @@ -832,10 +812,8 @@ static void GPENCIL_fast_draw_start(GPENCIL_Data *vedata) } } -static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata, blender::draw::View &view) +static void GPENCIL_fast_draw_end(Instance *inst, blender::draw::View &view) { - GPENCIL_Instance *inst = vedata->instance; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); if (inst->snapshot_buffer_dirty) { @@ -847,109 +825,92 @@ static void GPENCIL_fast_draw_end(GPENCIL_Data *vedata, blender::draw::View &vie } /* Draw the sbuffer stroke(s). */ LISTBASE_FOREACH (GPENCIL_tObject *, ob, &inst->sbuffer_tobjects) { - GPENCIL_draw_object(vedata, view, ob); + GPENCIL_draw_object(inst, view, ob); } } -void GPENCIL_draw_scene(void *ved) +void Instance::draw(Manager & /*manager*/) { - using namespace blender::draw; - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; - GPENCIL_Instance &inst = *vedata->instance; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - if (inst.render_depth_tx.is_valid()) { - inst.scene_depth_tx = inst.render_depth_tx; - inst.scene_fb = inst.render_fb; + if (this->render_depth_tx.is_valid()) { + this->scene_depth_tx = this->render_depth_tx; + this->scene_fb = this->render_fb; } else { - inst.scene_fb = dfbl->default_fb; - inst.scene_depth_tx = dtxl->depth; + this->scene_fb = dfbl->default_fb; + this->scene_depth_tx = dtxl->depth; } - BLI_assert(inst.scene_depth_tx); + BLI_assert(this->scene_depth_tx); float clear_cols[2][4] = {{0.0f, 0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}; /* Fade 3D objects. */ - if ((!inst.is_render) && (inst.fade_3d_object_opacity > -1.0f) && (inst.obact != nullptr) && - ELEM(inst.obact->type, OB_GREASE_PENCIL)) + if ((!this->is_render) && (this->fade_3d_object_opacity > -1.0f) && (this->obact != nullptr) && + ELEM(this->obact->type, OB_GREASE_PENCIL)) { float background_color[3]; - ED_view3d_background_color_get(inst.scene, inst.v3d, background_color); + ED_view3d_background_color_get(this->scene, this->v3d, background_color); /* Blend color. */ - interp_v3_v3v3(clear_cols[0], background_color, clear_cols[0], inst.fade_3d_object_opacity); + interp_v3_v3v3(clear_cols[0], background_color, clear_cols[0], this->fade_3d_object_opacity); - mul_v4_fl(clear_cols[1], inst.fade_3d_object_opacity); + mul_v4_fl(clear_cols[1], this->fade_3d_object_opacity); } /* Sort object by decreasing Z to avoid most of alpha ordering issues. */ - gpencil_object_cache_sort(&inst); + gpencil_object_cache_sort(this); - if (inst.tobjects.first == nullptr) { + if (this->tobjects.first == nullptr) { return; } DRW_submission_start(); - GPENCIL_antialiasing_init(&inst); + GPENCIL_antialiasing_init(this); - inst.acquire_resources(); + this->acquire_resources(); - if (inst.do_fast_drawing) { - GPENCIL_fast_draw_start(vedata); + if (this->do_fast_drawing) { + GPENCIL_fast_draw_start(this); } - if (inst.tobjects.first) { - GPU_framebuffer_bind(inst.gpencil_fb); - GPU_framebuffer_multi_clear(inst.gpencil_fb, clear_cols); + if (this->tobjects.first) { + GPU_framebuffer_bind(this->gpencil_fb); + GPU_framebuffer_multi_clear(this->gpencil_fb, clear_cols); } blender::draw::View &view = blender::draw::View::default_get(); - LISTBASE_FOREACH (GPENCIL_tObject *, ob, &inst.tobjects) { - GPENCIL_draw_object(vedata, view, ob); + LISTBASE_FOREACH (GPENCIL_tObject *, ob, &this->tobjects) { + GPENCIL_draw_object(this, view, ob); } - if (inst.do_fast_drawing) { - GPENCIL_fast_draw_end(vedata, view); + if (this->do_fast_drawing) { + GPENCIL_fast_draw_end(this, view); } - if (inst.scene_fb) { - GPENCIL_antialiasing_draw(vedata); + if (this->scene_fb) { + GPENCIL_antialiasing_draw(this); } - inst.gp_object_pool = inst.gp_maskbit_pool = nullptr; - inst.gp_vfx_pool = nullptr; - inst.gp_layer_pool = nullptr; + this->gp_object_pool = this->gp_maskbit_pool = nullptr; + this->gp_vfx_pool = nullptr; + this->gp_layer_pool = nullptr; - inst.release_resources(); + this->release_resources(); DRW_submission_end(); } -static void GPENCIL_engine_free() +DrawEngine *Engine::create_instance() { - GPENCIL_shader_free(); + return new Instance(); } -static void GPENCIL_instance_free(void *instance) +void Engine::free_static() { - delete reinterpret_cast(instance); + ShaderCache::release(); } -DrawEngineType draw_engine_gpencil_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("GpencilMode"), - /*engine_init*/ &GPENCIL_engine_init, - /*engine_free*/ &GPENCIL_engine_free, - /*instance_free*/ &GPENCIL_instance_free, - /*cache_init*/ &GPENCIL_cache_init, - /*cache_populate*/ &GPENCIL_cache_populate, - /*cache_finish*/ &GPENCIL_cache_finish, - /*draw_scene*/ &GPENCIL_draw_scene, - /*render_to_image*/ &GPENCIL_render_to_image, - /*store_metadata*/ nullptr, -}; +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine_private.hh similarity index 79% rename from source/blender/draw/engines/gpencil/gpencil_engine.h rename to source/blender/draw/engines/gpencil/gpencil_engine_private.hh index 974d1af3f07..088f6b378df 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine_private.hh @@ -8,6 +8,7 @@ #pragma once +#include "BLI_memblock.h" #include "DRW_render.hh" #include "BLI_bitmap.h" @@ -22,10 +23,9 @@ #define GP_LIGHT #include "gpencil_defines.h" +#include "gpencil_shader.hh" #include "gpencil_shader_shared.h" -extern DrawEngineType draw_engine_gpencil_type; - struct GPENCIL_Data; struct GPENCIL_StorageList; namespace blender::gpu { @@ -45,13 +45,13 @@ struct View3D; #define GP_MAX_MASKBITS 256 +namespace blender::draw::gpencil { + +using namespace blender::draw; + struct GPENCIL_tVfx; struct GPENCIL_tLayer; -using PassSimple = blender::draw::PassSimple; -using Texture = blender::draw::Texture; -using TextureFromPool = blender::draw::TextureFromPool; -using Framebuffer = blender::draw::Framebuffer; /* NOTE: These do not preserve the PassSimple memory across frames. * If that becomes a bottleneck, these containers can be improved. */ using GPENCIL_tVfx_Pool = blender::draw::detail::SubPassVector; @@ -81,21 +81,6 @@ typedef struct GPENCIL_LightPool { int light_used; } GPENCIL_LightPool; -struct GPENCIL_ViewLayerData { - /* GPENCIL_tObject */ - struct BLI_memblock *gp_object_pool; - /* GPENCIL_tLayer */ - GPENCIL_tLayer_Pool *gp_layer_pool; - /* GPENCIL_tVfx */ - GPENCIL_tVfx_Pool *gp_vfx_pool; - /* GPENCIL_MaterialPool */ - struct BLI_memblock *gp_material_pool; - /* GPENCIL_LightPool */ - struct BLI_memblock *gp_light_pool; - /* BLI_bitmap */ - struct BLI_memblock *gp_maskbit_pool; -}; - /* *********** GPencil *********** */ struct GPENCIL_tVfx { @@ -148,12 +133,46 @@ typedef struct GPENCIL_tObject { } GPENCIL_tObject; -/* *********** LISTS *********** */ -typedef struct GPENCIL_StorageList { - struct GPENCIL_Instance *inst; -} GPENCIL_StorageList; +struct ViewLayerData { + /* GPENCIL_tObject */ + struct BLI_memblock *gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject)); + /* GPENCIL_tLayer */ + GPENCIL_tLayer_Pool *gp_layer_pool = new GPENCIL_tLayer_Pool(); + /* GPENCIL_tVfx */ + GPENCIL_tVfx_Pool *gp_vfx_pool = new GPENCIL_tVfx_Pool(); + /* GPENCIL_MaterialPool */ + struct BLI_memblock *gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool)); + /* GPENCIL_LightPool */ + struct BLI_memblock *gp_light_pool = BLI_memblock_create(sizeof(GPENCIL_LightPool)); + /* BLI_bitmap */ + struct BLI_memblock *gp_maskbit_pool = BLI_memblock_create(BLI_BITMAP_SIZE(GP_MAX_MASKBITS)); -struct GPENCIL_Instance { + ~ViewLayerData() + { + BLI_memblock_destroy(gp_light_pool, light_pool_free); + BLI_memblock_destroy(gp_material_pool, material_pool_free); + BLI_memblock_destroy(gp_maskbit_pool, nullptr); + BLI_memblock_destroy(gp_object_pool, nullptr); + delete gp_layer_pool; + delete gp_vfx_pool; + } + + static void material_pool_free(void *storage) + { + GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage; + GPU_UBO_FREE_SAFE(matpool->ubo); + } + + static void light_pool_free(void *storage) + { + GPENCIL_LightPool *lightpool = (GPENCIL_LightPool *)storage; + GPU_UBO_FREE_SAFE(lightpool->ubo); + } +}; + +/* *********** LISTS *********** */ + +struct Instance : public DrawEngine { PassSimple smaa_edge_ps = {"smaa_edge"}; PassSimple smaa_weight_ps = {"smaa_weight"}; PassSimple smaa_resolve_ps = {"smaa_resolve"}; @@ -204,7 +223,9 @@ struct GPENCIL_Instance { Framebuffer smaa_edge_fb = {"smaa_edge_fb"}; Framebuffer smaa_weight_fb = {"smaa_weight_fb"}; - /* Pointers copied from GPENCIL_ViewLayerData. */ + ViewLayerData vldata; + + /* Pointers copied from blender::draw::gpencil::ViewLayerData. */ struct BLI_memblock *gp_object_pool; GPENCIL_tLayer_Pool *gp_layer_pool; GPENCIL_tVfx_Pool *gp_vfx_pool; @@ -310,11 +331,24 @@ struct GPENCIL_Instance { void acquire_resources(); void release_resources(); + + blender::StringRefNull name_get() final + { + return "Grease Pencil"; + } + + void init() final; + + void begin_sync() final; + void object_sync(blender::draw::ObjectRef &ob_ref, blender::draw::Manager &manager) final; + void end_sync() final; + + void draw(blender::draw::Manager &manager) final; }; struct GPENCIL_Data { void *engine_type; /* Required */ - struct GPENCIL_Instance *instance; + struct Instance *instance; char info[GPU_INFO_SIZE]; }; @@ -322,17 +356,17 @@ struct GPENCIL_Data { /* geometry batch cache functions */ struct GpencilBatchCache *gpencil_batch_cache_get(struct Object *ob, int cfra); -GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_Instance *inst, +GPENCIL_tObject *gpencil_object_cache_add(Instance *inst, Object *ob, bool is_stroke_order_3d, blender::Bounds bounds); -void gpencil_object_cache_sort(GPENCIL_Instance *inst); +void gpencil_object_cache_sort(Instance *inst); GPENCIL_tLayer *grease_pencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int layer_id, bool skip_onion); -GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst, +GPENCIL_tLayer *grease_pencil_layer_cache_add(Instance *inst, const Object *ob, const blender::bke::greasepencil::Layer &layer, int onion_id, @@ -343,7 +377,7 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_Instance *inst, * We merge the material pools together if object does not contain a huge amount of materials. * Also return an offset to the first material of the object in the UBO. */ -GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_Instance *inst, +GPENCIL_MaterialPool *gpencil_material_pool_create(Instance *inst, Object *ob, int *ofs, bool is_vertex_mode); @@ -355,62 +389,22 @@ void gpencil_material_resources_get(GPENCIL_MaterialPool *first_pool, void gpencil_light_ambient_add(GPENCIL_LightPool *lightpool, const float color[3]); void gpencil_light_pool_populate(GPENCIL_LightPool *lightpool, Object *ob); -GPENCIL_LightPool *gpencil_light_pool_add(GPENCIL_Instance *inst); +GPENCIL_LightPool *gpencil_light_pool_add(Instance *inst); /** * Creates a single pool containing all lights assigned (light linked) for a given object. */ -GPENCIL_LightPool *gpencil_light_pool_create(GPENCIL_Instance *inst, Object *ob); +GPENCIL_LightPool *gpencil_light_pool_create(Instance *inst, Object *ob); /* effects */ -void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, +void gpencil_vfx_cache_populate(Instance *inst, Object *ob, GPENCIL_tObject *tgp_ob, const bool is_edit_mode); -/* Shaders */ -struct GPUShader *GPENCIL_shader_antialiasing(int stage); -struct GPUShader *GPENCIL_shader_geometry_get(void); -struct GPUShader *GPENCIL_shader_layer_blend_get(void); -struct GPUShader *GPENCIL_shader_mask_invert_get(void); -struct GPUShader *GPENCIL_shader_depth_merge_get(void); -struct GPUShader *GPENCIL_shader_fx_blur_get(void); -struct GPUShader *GPENCIL_shader_fx_colorize_get(void); -struct GPUShader *GPENCIL_shader_fx_composite_get(void); -struct GPUShader *GPENCIL_shader_fx_transform_get(void); -struct GPUShader *GPENCIL_shader_fx_glow_get(void); -struct GPUShader *GPENCIL_shader_fx_pixelize_get(void); -struct GPUShader *GPENCIL_shader_fx_rim_get(void); -struct GPUShader *GPENCIL_shader_fx_shadow_get(void); - -void GPENCIL_shader_free(void); - /* Antialiasing */ -void GPENCIL_antialiasing_init(GPENCIL_Instance *inst); -void GPENCIL_antialiasing_draw(struct GPENCIL_Data *vedata); - -/* main functions */ -void GPENCIL_engine_init(void *vedata); -void GPENCIL_cache_init(void *vedata); -void GPENCIL_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref); -void GPENCIL_cache_finish(void *vedata); -void GPENCIL_draw_scene(void *vedata); +void GPENCIL_antialiasing_init(Instance *inst); +void GPENCIL_antialiasing_draw(Instance *inst); /* render */ -/** - * Initialize render data. - */ -void GPENCIL_render_init(struct GPENCIL_Data *ved, - struct RenderEngine *engine, - struct RenderLayer *render_layer, - const struct Depsgraph *depsgraph, - const rcti *rect); -void GPENCIL_render_to_image(void *vedata, - struct RenderEngine *engine, - struct RenderLayer *render_layer, - const rcti *rect); - -/* Draw Data. */ -void gpencil_light_pool_free(void *storage); -void gpencil_material_pool_free(void *storage); -GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void); +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/gpencil/gpencil_render.cc b/source/blender/draw/engines/gpencil/gpencil_render.cc index f2cbed53edb..cc62d17592b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.cc +++ b/source/blender/draw/engines/gpencil/gpencil_render.cc @@ -19,19 +19,16 @@ #include "IMB_imbuf_types.hh" -#include "gpencil_engine.h" +#include "gpencil_engine_private.hh" -void GPENCIL_render_init(GPENCIL_Data *vedata, - RenderEngine *engine, - RenderLayer *render_layer, - const Depsgraph *depsgraph, - const rcti *rect) +namespace blender::draw::gpencil { + +static void render_init(Instance &inst, + RenderEngine *engine, + RenderLayer *render_layer, + const Depsgraph *depsgraph, + const rcti *rect) { - if (vedata->instance == nullptr) { - vedata->instance = new GPENCIL_Instance(); - } - GPENCIL_Instance &inst = *vedata->instance; - Scene *scene = DEG_get_evaluated_scene(depsgraph); const int2 size = int2(DRW_viewport_size_get()); @@ -140,25 +137,10 @@ void GPENCIL_render_init(GPENCIL_Data *vedata, MEM_SAFE_FREE(pix_z); } -/* render all objects and select only grease pencil */ -static void GPENCIL_render_cache(void *vedata, - blender::draw::ObjectRef &ob_ref, - RenderEngine * /*engine*/, - Depsgraph * /*depsgraph*/) -{ - if (!ELEM(ob_ref.object->type, OB_GREASE_PENCIL, OB_LAMP)) { - return; - } - if (!(DRW_object_visibility_in_active_context(ob_ref.object) & OB_VISIBLE_SELF)) { - return; - } - GPENCIL_cache_populate(vedata, ob_ref); -} - -static void GPENCIL_render_result_z(RenderLayer *rl, - const char *viewname, - GPENCIL_Data *vedata, - const rcti *rect) +static void render_result_z(RenderLayer *rl, + const char *viewname, + Instance &instance, + const rcti *rect) { const DRWContext *draw_ctx = DRW_context_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -172,7 +154,7 @@ static void GPENCIL_render_result_z(RenderLayer *rl, float *ro_buffer_data = rp->ibuf->float_buffer.data; - GPU_framebuffer_read_depth(vedata->instance->render_fb, + GPU_framebuffer_read_depth(instance.render_fb, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), @@ -213,15 +195,15 @@ static void GPENCIL_render_result_z(RenderLayer *rl, } } -static void GPENCIL_render_result_combined(RenderLayer *rl, - const char *viewname, - GPENCIL_Data *vedata, - const rcti *rect) +static void render_result_combined(RenderLayer *rl, + const char *viewname, + Instance &instance, + const rcti *rect) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname); - GPU_framebuffer_bind(vedata->instance->render_fb); - GPU_framebuffer_read_color(vedata->instance->render_fb, + GPU_framebuffer_bind(instance.render_fb); + GPU_framebuffer_read_color(instance.render_fb, rect->xmin, rect->ymin, BLI_rcti_size_x(rect), @@ -232,33 +214,45 @@ static void GPENCIL_render_result_combined(RenderLayer *rl, rp->ibuf->float_buffer.data); } -void GPENCIL_render_to_image(void *ved, - RenderEngine *engine, - RenderLayer *render_layer, - const rcti *rect) +void Engine::render_to_image(RenderEngine *engine, RenderLayer *render_layer, const rcti rect) { - GPENCIL_Data *vedata = (GPENCIL_Data *)ved; const char *viewname = RE_GetActiveRenderView(engine->re); + const DRWContext *draw_ctx = DRW_context_get(); Depsgraph *depsgraph = draw_ctx->depsgraph; - DRW_manager_get()->begin_sync(); + blender::draw::gpencil::Instance inst; - GPENCIL_render_init(vedata, engine, render_layer, depsgraph, rect); - GPENCIL_engine_init(vedata); + Manager &manager = *DRW_manager_get(); - vedata->instance->camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + render_init(inst, engine, render_layer, depsgraph, &rect); + inst.init(); + + inst.camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + + manager.begin_sync(); /* Loop over all objects and create draw structure. */ - GPENCIL_cache_init(vedata); - DRW_render_object_iter(vedata, engine, depsgraph, GPENCIL_render_cache); - GPENCIL_cache_finish(vedata); + inst.begin_sync(); + DRW_render_object_iter( + engine, depsgraph, [&](blender::draw::ObjectRef &ob_ref, RenderEngine *, Depsgraph *) { + if (!ELEM(ob_ref.object->type, OB_GREASE_PENCIL, OB_LAMP)) { + return; + } + if (!(DRW_object_visibility_in_active_context(ob_ref.object) & OB_VISIBLE_SELF)) { + return; + } + inst.object_sync(ob_ref, manager); + }); + inst.end_sync(); - DRW_manager_get()->end_sync(); + manager.end_sync(); /* Render the gpencil object and merge the result to the underlying render. */ - GPENCIL_draw_scene(vedata); + inst.draw(manager); - GPENCIL_render_result_combined(render_layer, viewname, vedata, rect); - GPENCIL_render_result_z(render_layer, viewname, vedata, rect); + render_result_combined(render_layer, viewname, inst, &rect); + render_result_z(render_layer, viewname, inst, &rect); } + +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_c.cc b/source/blender/draw/engines/gpencil/gpencil_shader.hh similarity index 52% rename from source/blender/draw/engines/gpencil/gpencil_shader_c.cc rename to source/blender/draw/engines/gpencil/gpencil_shader.hh index 81db93fe911..b37505e2116 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_c.cc +++ b/source/blender/draw/engines/gpencil/gpencil_shader.hh @@ -5,11 +5,10 @@ /** \file * \ingroup draw */ -#include "DRW_render.hh" -#include "BLI_string.h" +#pragma once -#include "gpencil_engine.h" +#include "GPU_shader.hh" namespace blender::draw::gpencil { @@ -57,78 +56,3 @@ class ShaderCache { }; } // namespace blender::draw::gpencil - -using namespace blender::draw::gpencil; - -void GPENCIL_shader_free() -{ - ShaderCache::get().release(); -} - -GPUShader *GPENCIL_shader_antialiasing(int stage) -{ - BLI_assert(stage < 3); - return ShaderCache::get().antialiasing[stage].get(); -} - -GPUShader *GPENCIL_shader_geometry_get() -{ - return ShaderCache::get().geometry.get(); -} - -GPUShader *GPENCIL_shader_layer_blend_get() -{ - return ShaderCache::get().layer_blend.get(); -} - -GPUShader *GPENCIL_shader_mask_invert_get() -{ - return ShaderCache::get().mask_invert.get(); -} - -GPUShader *GPENCIL_shader_depth_merge_get() -{ - return ShaderCache::get().depth_merge.get(); -} - -/* ------- FX Shaders --------- */ - -GPUShader *GPENCIL_shader_fx_blur_get() -{ - return ShaderCache::get().fx_blur.get(); -} - -GPUShader *GPENCIL_shader_fx_colorize_get() -{ - return ShaderCache::get().fx_colorize.get(); -} - -GPUShader *GPENCIL_shader_fx_composite_get() -{ - return ShaderCache::get().fx_composite.get(); -} - -GPUShader *GPENCIL_shader_fx_glow_get() -{ - return ShaderCache::get().fx_glow.get(); -} - -GPUShader *GPENCIL_shader_fx_pixelize_get() -{ - return ShaderCache::get().fx_pixelize.get(); -} - -GPUShader *GPENCIL_shader_fx_rim_get() -{ - return ShaderCache::get().fx_rim.get(); -} - -GPUShader *GPENCIL_shader_fx_shadow_get() -{ - return ShaderCache::get().fx_shadow.get(); -} - -GPUShader *GPENCIL_shader_fx_transform_get() -{ - return ShaderCache::get().fx_transform.get(); -} diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc b/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc index ed910ebf226..4eaf4123345 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.cc @@ -20,7 +20,9 @@ #include "BKE_camera.h" -#include "gpencil_engine.h" +#include "gpencil_engine_private.hh" + +namespace blender::draw::gpencil { using namespace blender::draw; @@ -45,7 +47,7 @@ static bool effect_is_active(ShaderFxData *fx, bool is_edit, bool is_viewport) } struct gpIterVfxData { - GPENCIL_Instance *inst; + Instance *inst; GPENCIL_tObject *tgp_ob; GPUFrameBuffer **target_fb; GPUFrameBuffer **source_fb; @@ -118,7 +120,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it mul_v2_fl(blur_size, distance_factor); } - GPUShader *sh = GPENCIL_shader_fx_blur_get(); + GPUShader *sh = ShaderCache::get().fx_blur.get(); DRWState state = DRW_STATE_WRITE_COLOR; if (blur_size[0] > 0.0f) { @@ -137,7 +139,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it static void gpencil_vfx_colorize(ColorizeShaderFxData *fx, Object * /*ob*/, gpIterVfxData *iter) { - GPUShader *sh = GPENCIL_shader_fx_colorize_get(); + GPUShader *sh = ShaderCache::get().fx_colorize.get(); DRWState state = DRW_STATE_WRITE_COLOR; auto &grp = gpencil_vfx_pass_create("Fx Colorize", state, iter, sh); @@ -154,7 +156,7 @@ static void gpencil_vfx_flip(FlipShaderFxData *fx, Object * /*ob*/, gpIterVfxDat axis_flip[0] = (fx->flag & FX_FLIP_HORIZONTAL) ? -1.0f : 1.0f; axis_flip[1] = (fx->flag & FX_FLIP_VERTICAL) ? -1.0f : 1.0f; - GPUShader *sh = GPENCIL_shader_fx_transform_get(); + GPUShader *sh = ShaderCache::get().fx_transform.get(); DRWState state = DRW_STATE_WRITE_COLOR; auto &grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh); @@ -184,7 +186,7 @@ static void gpencil_vfx_rim(RimShaderFxData *fx, Object *ob, gpIterVfxData *iter mul_v2_v2(offset, vp_size_inv); mul_v2_fl(blur_size, distance_factor); - GPUShader *sh = GPENCIL_shader_fx_rim_get(); + GPUShader *sh = ShaderCache::get().fx_rim.get(); { DRWState state = DRW_STATE_WRITE_COLOR; @@ -267,7 +269,7 @@ static void gpencil_vfx_pixelize(PixelShaderFxData *fx, Object *ob, gpIterVfxDat /* Center to texel */ madd_v2_v2fl(ob_center, pixel_size, -0.5f); - GPUShader *sh = GPENCIL_shader_fx_pixelize_get(); + GPUShader *sh = ShaderCache::get().fx_pixelize.get(); DRWState state = DRW_STATE_WRITE_COLOR; @@ -374,7 +376,7 @@ static void gpencil_vfx_shadow(ShadowShaderFxData *fx, Object *ob, gpIterVfxData wave_phase = 0.0f; } - GPUShader *sh = GPENCIL_shader_fx_shadow_get(); + GPUShader *sh = ShaderCache::get().fx_shadow.get(); copy_v2_fl2(blur_dir, blur_size[0] * vp_size_inv[0], 0.0f); @@ -422,7 +424,7 @@ static void gpencil_vfx_glow(GlowShaderFxData *fx, Object * /*ob*/, gpIterVfxDat const float s = sin(fx->rotation); const float c = cos(fx->rotation); - GPUShader *sh = GPENCIL_shader_fx_glow_get(); + GPUShader *sh = ShaderCache::get().fx_glow.get(); float ref_col[4]; @@ -528,7 +530,7 @@ static void gpencil_vfx_wave(WaveShaderFxData *fx, Object *ob, gpIterVfxData *it /* Phase start at shadow center. */ wave_phase = fx->phase - dot_v2v2(wave_center, wave_dir); - GPUShader *sh = GPENCIL_shader_fx_transform_get(); + GPUShader *sh = ShaderCache::get().fx_transform.get(); DRWState state = DRW_STATE_WRITE_COLOR; auto &grp = gpencil_vfx_pass_create("Fx Wave", state, iter, sh); @@ -572,7 +574,7 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object * /*ob*/, gpIterVfxD return; } - GPUShader *sh = GPENCIL_shader_fx_transform_get(); + GPUShader *sh = ShaderCache::get().fx_transform.get(); DRWState state = DRW_STATE_WRITE_COLOR; auto &grp = gpencil_vfx_pass_create("Fx Flip", state, iter, sh); @@ -584,13 +586,11 @@ static void gpencil_vfx_swirl(SwirlShaderFxData *fx, Object * /*ob*/, gpIterVfxD grp.draw_procedural(GPU_PRIM_TRIS, 1, 3); } -void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, +void gpencil_vfx_cache_populate(Instance *inst, Object *ob, GPENCIL_tObject *tgp_ob, const bool is_edit_mode) { - GPENCIL_Instance *inst = vedata->instance; - /* These may not be allocated yet, use address of future pointer. */ gpIterVfxData iter{}; iter.inst = inst; @@ -645,7 +645,7 @@ void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, /* We need an extra pass to combine result to main buffer. */ iter.target_fb = &inst->gpencil_fb; - GPUShader *sh = GPENCIL_shader_fx_composite_get(); + GPUShader *sh = ShaderCache::get().fx_composite.get(); DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; auto &grp = gpencil_vfx_pass_create("GPencil Object Compose", state, &iter, sh); @@ -662,3 +662,5 @@ void gpencil_vfx_cache_populate(GPENCIL_Data *vedata, inst->use_layer_fb = true; } } + +} // namespace blender::draw::gpencil diff --git a/source/blender/draw/engines/image/image_engine.cc b/source/blender/draw/engines/image/image_engine.cc index 3b2486fb4ec..319ce9c4432 100644 --- a/source/blender/draw/engines/image/image_engine.cc +++ b/source/blender/draw/engines/image/image_engine.cc @@ -8,96 +8,20 @@ * Draw engine to draw the Image/UV editor */ -#include "DRW_render.hh" - -#include "BLT_translation.hh" - -#include "BKE_context.hh" -#include "BKE_image.hh" -#include "BKE_main.hh" -#include "BKE_object.hh" - -#include "ED_image.hh" - -#include "draw_view_data.hh" - -#include "image_drawing_mode.hh" #include "image_engine.h" #include "image_instance.hh" #include "image_shader.hh" namespace blender::image_engine { -struct IMAGE_Data { - void *engine_type; - Instance *instance; - char info[GPU_INFO_SIZE]; -}; - -/* -------------------------------------------------------------------- */ -/** \name Engine Callbacks - * \{ */ - -static void IMAGE_engine_init(void *vedata) +DrawEngine *Engine::create_instance() { - IMAGE_Data *ved = reinterpret_cast(vedata); - if (ved->instance == nullptr) { - ved->instance = new image_engine::Instance(); - } - - const DRWContext *ctx_state = DRW_context_get(); - Main *bmain = CTX_data_main(ctx_state->evil_C); - ved->instance->init(bmain, ctx_state->space_data, ctx_state->region); + return new Instance(); } -static void IMAGE_cache_init(void *vedata) -{ - IMAGE_Data *ved = reinterpret_cast(vedata); - ved->instance->begin_sync(); - ved->instance->image_sync(); -} - -static void IMAGE_cache_populate(void * /*vedata*/, blender::draw::ObjectRef & /*ob_ref*/) -{ - /* Function intentional left empty. `cache_populate` is required to be implemented. */ -} - -static void IMAGE_draw_scene(void *vedata) -{ - IMAGE_Data *ved = reinterpret_cast(vedata); - DRW_submission_start(); - ved->instance->draw_viewport(); - ved->instance->draw_finish(); - DRW_submission_end(); -} - -static void IMAGE_engine_free() +void Engine::free_static() { ShaderModule::module_free(); } -static void IMAGE_instance_free(void *instance) -{ - delete reinterpret_cast(instance); -} - -/** \} */ - } // namespace blender::image_engine - -using namespace blender::image_engine; - -DrawEngineType draw_engine_image_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("UV/Image"), - /*engine_init*/ &IMAGE_engine_init, - /*engine_free*/ &IMAGE_engine_free, - /*instance_free*/ &IMAGE_instance_free, - /*cache_init*/ &IMAGE_cache_init, - /*cache_populate*/ &IMAGE_cache_populate, - /*cache_finish*/ nullptr, - /*draw_scene*/ &IMAGE_draw_scene, - /*render_to_image*/ nullptr, - /*store_metadata*/ nullptr, -}; diff --git a/source/blender/draw/engines/image/image_engine.h b/source/blender/draw/engines/image/image_engine.h index a7cb77ba2e5..5f815d8478c 100644 --- a/source/blender/draw/engines/image/image_engine.h +++ b/source/blender/draw/engines/image/image_engine.h @@ -8,6 +8,14 @@ #pragma once -struct DrawEngineType; +#include "DRW_render.hh" -extern DrawEngineType draw_engine_image_type; +namespace blender::image_engine { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; + + static void free_static(); +}; + +} // namespace blender::image_engine diff --git a/source/blender/draw/engines/image/image_instance.hh b/source/blender/draw/engines/image/image_instance.hh index f19c83d9a49..641a09e84e2 100644 --- a/source/blender/draw/engines/image/image_instance.hh +++ b/source/blender/draw/engines/image/image_instance.hh @@ -6,6 +6,10 @@ #include +#include "BKE_context.hh" + +#include "DRW_engine.hh" + #include "image_drawing_mode.hh" #include "image_private.hh" #include "image_space.hh" @@ -33,7 +37,7 @@ static inline std::unique_ptr space_accessor_from_space( return nullptr; } -class Instance { +class Instance : public DrawEngine { private: std::unique_ptr space_; Main *main_; @@ -48,17 +52,23 @@ class Instance { public: Instance() : drawing_mode_(*this) {} - void init(Main *main, SpaceLink *space_link, const ARegion *_region) + virtual ~Instance() = default; + + StringRefNull name_get() final { - main_ = main; - region = _region; - space_ = space_accessor_from_space(space_link); + return "UV/Image"; + } + + void init() final + { + const DRWContext *ctx_state = DRW_context_get(); + main_ = CTX_data_main(ctx_state->evil_C); + region = ctx_state->region; + space_ = space_accessor_from_space(ctx_state->space_data); manager = DRW_manager_get(); } - virtual ~Instance() = default; - - void begin_sync() + void begin_sync() final { drawing_mode_.begin_sync(); @@ -68,6 +78,8 @@ class Instance { float4x4 winmat = float4x4::identity(); state.view.sync(viewmat, winmat); state.flags.do_tile_drawing = false; + + image_sync(); } void image_sync() @@ -102,15 +114,17 @@ class Instance { drawing_mode_.image_sync(state.image, iuser); } - void draw_finish() + void object_sync(ObjectRef & /*obref*/, Manager & /*manager*/) final {} + + void end_sync() final {} + + void draw(Manager & /*manager */) final { + DRW_submission_start(); + drawing_mode_.draw_viewport(); drawing_mode_.draw_finish(); state.image = nullptr; - } - - void draw_viewport() - { - drawing_mode_.draw_viewport(); + DRW_submission_end(); } }; } // namespace blender::image_engine diff --git a/source/blender/draw/engines/overlay/overlay_engine.h b/source/blender/draw/engines/overlay/overlay_engine.h index 9467e03db56..58b69b3d562 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.h +++ b/source/blender/draw/engines/overlay/overlay_engine.h @@ -8,6 +8,14 @@ #pragma once -struct DrawEngineType; +#include "DRW_render.hh" -extern DrawEngineType draw_engine_overlay_next_type; +namespace blender::draw::overlay { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; + + static void free_static(); +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_next_attribute_text.hh b/source/blender/draw/engines/overlay/overlay_next_attribute_text.hh index 203c4ab6fad..2580e746eb3 100644 --- a/source/blender/draw/engines/overlay/overlay_next_attribute_text.hh +++ b/source/blender/draw/engines/overlay/overlay_next_attribute_text.hh @@ -6,6 +6,8 @@ * \ingroup draw_engine */ +#pragma once + #include "BLI_math_quaternion_types.hh" #include "BLI_string.h" diff --git a/source/blender/draw/engines/overlay/overlay_next_engine.cc b/source/blender/draw/engines/overlay/overlay_next_engine.cc index 741a13388e6..32d57bee35a 100644 --- a/source/blender/draw/engines/overlay/overlay_next_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_next_engine.cc @@ -8,89 +8,20 @@ * Engine for drawing a selection map where the pixels indicate the selection indices. */ -#include "DRW_engine.hh" -#include "DRW_render.hh" - -#include "BLT_translation.hh" - -#include "draw_manager.hh" #include "overlay_next_instance.hh" #include "overlay_engine.h" -#include "overlay_next_private.hh" -using namespace blender::draw; +namespace blender::draw::overlay { -using Instance = blender::draw::overlay::Instance; - -/* -------------------------------------------------------------------- */ -/** \name Engine Instance - * \{ */ - -static void OVERLAY_next_engine_init(void *vedata) +DrawEngine *Engine::create_instance() { - OVERLAY_Data *ved = reinterpret_cast(vedata); - - if (ved->instance == nullptr) { - ved->instance = new Instance(select::SelectionType::DISABLED); - } - reinterpret_cast(ved->instance)->init(); + return new Instance(); } -static void OVERLAY_next_cache_init(void *vedata) +void Engine::free_static() { - reinterpret_cast(reinterpret_cast(vedata)->instance)->begin_sync(); + ShaderModule::module_free(); } -static void OVERLAY_next_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref) -{ - reinterpret_cast(reinterpret_cast(vedata)->instance) - ->object_sync(ob_ref, *DRW_manager_get()); -} - -static void OVERLAY_next_cache_finish(void *vedata) -{ - reinterpret_cast(reinterpret_cast(vedata)->instance)->end_sync(); -} - -static void OVERLAY_next_draw_scene(void *vedata) -{ - DRW_submission_start(); - reinterpret_cast(reinterpret_cast(vedata)->instance) - ->draw(*DRW_manager_get()); - DRW_submission_end(); -} - -static void OVERLAY_next_instance_free(void *instance_) -{ - Instance *instance = (Instance *)instance_; - delete instance; -} - -static void OVERLAY_next_engine_free() -{ - overlay::ShaderModule::module_free(); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Engine Type - * \{ */ - -DrawEngineType draw_engine_overlay_next_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("Overlay"), - /*engine_init*/ &OVERLAY_next_engine_init, - /*engine_free*/ &OVERLAY_next_engine_free, - /*instance_free*/ &OVERLAY_next_instance_free, - /*cache_init*/ &OVERLAY_next_cache_init, - /*cache_populate*/ &OVERLAY_next_cache_populate, - /*cache_finish*/ &OVERLAY_next_cache_finish, - /*draw_scene*/ &OVERLAY_next_draw_scene, - /*render_to_image*/ nullptr, - /*store_metadata*/ nullptr, -}; - -/** \} */ +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_next_instance.hh b/source/blender/draw/engines/overlay/overlay_next_instance.hh index 635d6f9775b..f8ebc1cd2d6 100644 --- a/source/blender/draw/engines/overlay/overlay_next_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_next_instance.hh @@ -54,14 +54,11 @@ namespace blender::draw::overlay { * Selection engine reuse most of the Overlay engine by creating selection IDs for each * selectable component and using a special shaders for drawing. */ -class Instance { +class Instance : public DrawEngine { const SelectionType selection_type_; bool clipping_enabled_; public: - /* WORKAROUND: Legacy. Move to grid pass. */ - GPUUniformBuf *grid_ubo = nullptr; - ShapeCache shapes; /** Global types. */ @@ -115,18 +112,19 @@ class Instance { AntiAliasing anti_aliasing; XrayFade xray_fade; + Instance() : selection_type_(select::SelectionType::DISABLED){}; Instance(const SelectionType selection_type) : selection_type_(selection_type){}; - ~Instance() + blender::StringRefNull name_get() final { - GPU_UBO_FREE_SAFE(grid_ubo); + return "Overlay"; } - void init(); - void begin_sync(); - void object_sync(ObjectRef &ob_ref, Manager &manager); - void end_sync(); - void draw(Manager &manager); + void init() final; + void begin_sync() final; + void object_sync(ObjectRef &ob_ref, Manager &manager) final; + void end_sync() final; + void draw(Manager &manager) final; private: bool object_is_selected(const ObjectRef &ob_ref); diff --git a/source/blender/draw/engines/select/select_debug_engine.cc b/source/blender/draw/engines/select/select_debug_engine.cc index c1811ab1487..6ff68fd7777 100644 --- a/source/blender/draw/engines/select/select_debug_engine.cc +++ b/source/blender/draw/engines/select/select_debug_engine.cc @@ -20,21 +20,15 @@ #include "select_engine.hh" -#define SELECT_DEBUG_ENGINE "SELECT_DEBUG_ENGINE" - /* -------------------------------------------------------------------- */ /** \name Structs and static variables * \{ */ -struct SELECTIDDEBUG_Data { - void *engine_type; -}; - -namespace blender::draw::SelectDebug { - -using StaticShader = gpu::StaticShader; +namespace blender::draw::edit_select_debug { class ShaderCache { + using StaticShader = gpu::StaticShader; + private: static gpu::StaticShaderCache &get_static_cache() { @@ -55,63 +49,48 @@ class ShaderCache { StaticShader select_debug = {"select_debug_fullscreen"}; }; -} // namespace blender::draw::SelectDebug - -using namespace blender::draw::SelectDebug; - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Engine Functions - * \{ */ - -static void select_debug_draw_scene(void * /*vedata*/) -{ - GPUTexture *texture_u32 = DRW_engine_select_texture_get(); - if (texture_u32 == nullptr) { - return; +class Instance : public DrawEngine { + StringRefNull name_get() final + { + return "Select ID Debug"; } - using namespace blender::draw; - PassSimple pass = {"SelectEngineDebug"}; - pass.init(); - pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); - pass.shader_set(ShaderCache::get().select_debug.get()); - pass.bind_texture("image", texture_u32); - pass.bind_texture("image", texture_u32); - pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); + void init() final{}; + void begin_sync() final{}; + void object_sync(blender::draw::ObjectRef & /*ob_ref*/, + blender::draw::Manager & /*manager*/) final{}; + void end_sync() final{}; - DRW_submission_start(); - DRW_manager_get()->submit(pass); - DRW_submission_end(); + void draw(blender::draw::Manager &manager) final + { + GPUTexture *texture_u32 = DRW_engine_select_texture_get(); + if (texture_u32 == nullptr) { + return; + } + using namespace blender::draw; + + PassSimple pass = {"SelectEngineDebug"}; + pass.init(); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); + pass.shader_set(ShaderCache::get().select_debug.get()); + pass.bind_texture("image", texture_u32); + pass.bind_texture("image", texture_u32); + pass.draw_procedural(GPU_PRIM_TRIS, 1, 3); + + DRW_submission_start(); + manager.submit(pass); + DRW_submission_end(); + } +}; + +DrawEngine *Engine::create_instance() +{ + return new Instance(); } -static void select_debug_engine_free() +void Engine::free_static() { ShaderCache::release(); } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Engine Type - * \{ */ - -DrawEngineType draw_engine_debug_select_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("Select ID Debug"), - /*engine_init*/ nullptr, - /*engine_free*/ &select_debug_engine_free, - /*instance_free*/ nullptr, - /*cache_init*/ nullptr, - /*cache_populate*/ nullptr, - /*cache_finish*/ nullptr, - /*draw_scene*/ &select_debug_draw_scene, - /*render_to_image*/ nullptr, - /*store_metadata*/ nullptr, -}; - -/** \} */ - -#undef SELECT_DEBUG_ENGINE +} // namespace blender::draw::edit_select_debug diff --git a/source/blender/draw/engines/select/select_engine.cc b/source/blender/draw/engines/select/select_engine.cc index bb69bc7f57e..67e70f5afe0 100644 --- a/source/blender/draw/engines/select/select_engine.cc +++ b/source/blender/draw/engines/select/select_engine.cc @@ -25,453 +25,465 @@ #include "draw_cache_impl.hh" #include "draw_common_c.hh" #include "draw_context_private.hh" +#include "draw_manager.hh" +#include "draw_pass.hh" +#include "draw_view_data.hh" #include "../overlay/overlay_next_private.hh" #include "select_engine.hh" -#include "select_private.hh" -#define SELECT_ENGINE "SELECT_ENGINE" +namespace blender::draw::edit_select { -/* *********** STATIC *********** */ +#define USE_CAGE_OCCLUSION -struct SelectEngineData { - GPUFrameBuffer *framebuffer_select_id; - GPUTexture *texture_u32; +struct Instance : public DrawEngine { + private: + PassSimple depth_only_ps = {"depth_only_ps"}; + PassSimple::Sub *depth_only = nullptr; + PassSimple::Sub *depth_occlude = nullptr; - SELECTID_Shaders sh_data[GPU_SHADER_CFG_LEN]; - SELECTID_Context context; -}; + PassSimple select_edge_ps = {"select_id_edge_ps"}; + PassSimple::Sub *select_edge = nullptr; -static SelectEngineData &get_engine_data() -{ - static SelectEngineData data = {}; - return data; -} + PassSimple select_id_vert_ps = {"select_id_vert_ps"}; + PassSimple::Sub *select_vert = nullptr; -/* -------------------------------------------------------------------- */ -/** \name Utils - * \{ */ + PassSimple select_face_ps = {"select_id_face_ps"}; + PassSimple::Sub *select_face_uniform = nullptr; + PassSimple::Sub *select_face_flat = nullptr; -static void select_engine_framebuffer_setup() -{ - SelectEngineData &e_data = get_engine_data(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - int size[2]; - size[0] = GPU_texture_width(dtxl->depth); - size[1] = GPU_texture_height(dtxl->depth); + View view_faces = {"view_faces"}; + View view_edges = {"view_edges"}; + View view_verts = {"view_verts"}; - if (e_data.framebuffer_select_id == nullptr) { - e_data.framebuffer_select_id = GPU_framebuffer_create("framebuffer_select_id"); - } + public: + struct StaticData { + GPUFrameBuffer *framebuffer_select_id; + GPUTexture *texture_u32; - if ((e_data.texture_u32 != nullptr) && ((GPU_texture_width(e_data.texture_u32) != size[0]) || - (GPU_texture_height(e_data.texture_u32) != size[1]))) - { - GPU_texture_free(e_data.texture_u32); - e_data.texture_u32 = nullptr; - } + struct Shaders { + /* Depth Pre Pass */ + GPUShader *select_id_flat; + GPUShader *select_id_uniform; + } sh_data[GPU_SHADER_CFG_LEN]; - /* Make sure the depth texture is attached. - * It may disappear when loading another Blender session. */ - GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, dtxl->depth, 0, 0); + SELECTID_Context context; - if (e_data.texture_u32 == nullptr) { - eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT; - e_data.texture_u32 = GPU_texture_create_2d( - "select_buf_ids", size[0], size[1], 1, GPU_R32UI, usage, nullptr); - GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, e_data.texture_u32, 0, 0); - - GPU_framebuffer_check_valid(e_data.framebuffer_select_id, nullptr); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Engine Functions - * \{ */ - -static void select_engine_init(void *vedata) -{ - SelectEngineData &e_data = get_engine_data(); - const DRWContext *draw_ctx = DRW_context_get(); - eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ? - GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - - SELECTID_Data *ved = reinterpret_cast(vedata); - SELECTID_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - - if (ved->instance == nullptr) { - ved->instance = new SELECTID_Instance(); - } - - /* Prepass */ - if (!sh_data->select_id_flat) { - sh_data->select_id_flat = GPU_shader_create_from_info_name( - sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_flat_clipped" : "select_id_flat"); - } - if (!sh_data->select_id_uniform) { - sh_data->select_id_uniform = GPU_shader_create_from_info_name( - sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_uniform_clipped" : "select_id_uniform"); - } -} - -static short select_id_get_object_select_mode(Scene *scene, Object *ob) -{ - short r_select_mode = 0; - if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) { - /* In order to sample flat colors for vertex weights / texture-paint / vertex-paint - * we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up - * a shgroup with select_id_flat. - * Note this is not working correctly for vertex-paint (yet), but has been discussed - * in #66645 and there is a solution by @mano-wii in P1032. - * So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */ - Mesh *me_orig = static_cast(DEG_get_original_object(ob)->data); - if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) { - r_select_mode = SCE_SELECT_VERTEX; - } - else { - r_select_mode = SCE_SELECT_FACE; - } - } - else { - r_select_mode = scene->toolsettings->selectmode; - } - - return r_select_mode; -} - -static void select_cache_init(void *vedata) -{ - SELECTID_Instance &inst = *reinterpret_cast(vedata)->instance; - SelectEngineData &e_data = get_engine_data(); - const DRWContext *draw_ctx = DRW_context_get(); - eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ? - GPU_SHADER_CFG_CLIPPED : - GPU_SHADER_CFG_DEFAULT; - - SELECTID_Shaders *sh = &e_data.sh_data[sh_cfg]; - - if (e_data.context.select_mode == -1) { - e_data.context.select_mode = select_id_get_object_select_mode(draw_ctx->scene, - draw_ctx->obact); - BLI_assert(e_data.context.select_mode != 0); - } - - DRWState state = DRW_STATE_DEFAULT; - if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) { - state |= DRW_STATE_CLIP_PLANES; - } - - bool retopology_occlusion = RETOPOLOGY_ENABLED(draw_ctx->v3d) && !XRAY_ENABLED(draw_ctx->v3d); - float retopology_offset = RETOPOLOGY_OFFSET(draw_ctx->v3d); - - /* Note there might be less than 6 planes, but we always compute the 6 of them for simplicity. */ - int clipping_plane_count = RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d) ? 6 : 0; - - { - inst.depth_only_ps.init(); - inst.depth_only_ps.state_set(state, clipping_plane_count); - inst.depth_only = nullptr; - inst.depth_occlude = nullptr; + static StaticData &get() { - auto &sub = inst.depth_only_ps.sub("DepthOnly"); - sub.shader_set(sh->select_id_uniform); - sub.push_constant("retopologyOffset", retopology_offset); - sub.push_constant("select_id", 0); - inst.depth_only = ⊂ + static StaticData data = {}; + return data; } - if (retopology_occlusion) { - auto &sub = inst.depth_only_ps.sub("Occlusion"); - sub.shader_set(sh->select_id_uniform); - sub.push_constant("retopologyOffset", 0.0f); - sub.push_constant("select_id", 0); - inst.depth_occlude = ⊂ + }; + + blender::StringRefNull name_get() final + { + return "SelectID"; + } + + void init() final + { + StaticData &e_data = StaticData::get(); + const DRWContext *draw_ctx = DRW_context_get(); + eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ? + GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; + + StaticData::Shaders *sh_data = &e_data.sh_data[sh_cfg]; + + /* Prepass */ + if (!sh_data->select_id_flat) { + sh_data->select_id_flat = GPU_shader_create_from_info_name( + sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_flat_clipped" : "select_id_flat"); + } + if (!sh_data->select_id_uniform) { + sh_data->select_id_uniform = GPU_shader_create_from_info_name( + sh_cfg == GPU_SHADER_CFG_CLIPPED ? "select_id_uniform_clipped" : "select_id_uniform"); + } + } + + void begin_sync() final + { + StaticData &e_data = StaticData::get(); + const DRWContext *draw_ctx = DRW_context_get(); + eGPUShaderConfig sh_cfg = (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) ? + GPU_SHADER_CFG_CLIPPED : + GPU_SHADER_CFG_DEFAULT; + + StaticData::Shaders *sh = &e_data.sh_data[sh_cfg]; + + if (e_data.context.select_mode == -1) { + e_data.context.select_mode = get_object_select_mode(draw_ctx->scene, draw_ctx->obact); + BLI_assert(e_data.context.select_mode != 0); } - inst.select_face_ps.init(); - inst.select_face_ps.state_set(state, clipping_plane_count); - inst.select_face_uniform = nullptr; - inst.select_face_flat = nullptr; - if (e_data.context.select_mode & SCE_SELECT_FACE) { - auto &sub = inst.select_face_ps.sub("Face"); - sub.shader_set(sh->select_id_flat); - sub.push_constant("retopologyOffset", retopology_offset); - inst.select_face_flat = ⊂ + DRWState state = DRW_STATE_DEFAULT; + if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) { + state |= DRW_STATE_CLIP_PLANES; + } + + bool retopology_occlusion = RETOPOLOGY_ENABLED(draw_ctx->v3d) && !XRAY_ENABLED(draw_ctx->v3d); + float retopology_offset = RETOPOLOGY_OFFSET(draw_ctx->v3d); + + /* Note there might be less than 6 planes, but we always compute the 6 of them for simplicity. + */ + int clipping_plane_count = RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d) ? 6 : 0; + + { + depth_only_ps.init(); + depth_only_ps.state_set(state, clipping_plane_count); + depth_only = nullptr; + depth_occlude = nullptr; + { + auto &sub = depth_only_ps.sub("DepthOnly"); + sub.shader_set(sh->select_id_uniform); + sub.push_constant("retopologyOffset", retopology_offset); + sub.push_constant("select_id", 0); + depth_only = ⊂ + } + if (retopology_occlusion) { + auto &sub = depth_only_ps.sub("Occlusion"); + sub.shader_set(sh->select_id_uniform); + sub.push_constant("retopologyOffset", 0.0f); + sub.push_constant("select_id", 0); + depth_occlude = ⊂ + } + + select_face_ps.init(); + select_face_ps.state_set(state, clipping_plane_count); + select_face_uniform = nullptr; + select_face_flat = nullptr; + if (e_data.context.select_mode & SCE_SELECT_FACE) { + auto &sub = select_face_ps.sub("Face"); + sub.shader_set(sh->select_id_flat); + sub.push_constant("retopologyOffset", retopology_offset); + select_face_flat = ⊂ + } + else { + auto &sub = select_face_ps.sub("FaceNoSelect"); + sub.shader_set(sh->select_id_uniform); + sub.push_constant("select_id", 0); + sub.push_constant("retopologyOffset", retopology_offset); + select_face_uniform = ⊂ + } + + select_edge_ps.init(); + select_edge = nullptr; + if (e_data.context.select_mode & SCE_SELECT_EDGE) { + auto &sub = select_edge_ps.sub("Sub"); + sub.state_set(state | DRW_STATE_FIRST_VERTEX_CONVENTION, clipping_plane_count); + sub.shader_set(sh->select_id_flat); + sub.push_constant("retopologyOffset", retopology_offset); + select_edge = ⊂ + } + + select_id_vert_ps.init(); + select_vert = nullptr; + if (e_data.context.select_mode & SCE_SELECT_VERTEX) { + const float vertex_size = blender::draw::overlay::Resources::vertex_size_get(); + auto &sub = select_id_vert_ps.sub("Sub"); + sub.state_set(state, clipping_plane_count); + sub.shader_set(sh->select_id_flat); + sub.push_constant("vertex_size", float(2 * vertex_size)); + sub.push_constant("retopologyOffset", retopology_offset); + select_vert = ⊂ + } + } + + e_data.context.elem_ranges.clear(); + + e_data.context.persmat = float4x4(draw_ctx->rv3d->persmat); + e_data.context.max_index_drawn_len = 1; + framebuffer_setup(); + GPU_framebuffer_bind(e_data.framebuffer_select_id); + GPU_framebuffer_clear_color_depth(e_data.framebuffer_select_id, blender::float4{0.0f}, 1.0f); + } + + ElemIndexRanges edit_mesh_sync(Object *ob, + ResourceHandle res_handle, + short select_mode, + bool draw_facedot, + const uint initial_index) + { + using namespace blender::draw; + using namespace blender; + Mesh &mesh = *static_cast(ob->data); + BMEditMesh *em = mesh.runtime->edit_mesh.get(); + + ElemIndexRanges ranges{}; + ranges.total = IndexRange::from_begin_size(initial_index, 0); + + BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); + + if (select_mode & SCE_SELECT_FACE) { + ranges.face = alloc_range(ranges.total, em->bm->totface); + + gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh); + PassSimple::Sub *face_sub = select_face_flat; + face_sub->push_constant("offset", int(ranges.face.start())); + face_sub->draw(geom_faces, res_handle); + + if (draw_facedot) { + gpu::Batch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(mesh); + face_sub->draw(geom_facedots, res_handle); + } } else { - auto &sub = inst.select_face_ps.sub("FaceNoSelect"); - sub.shader_set(sh->select_id_uniform); - sub.push_constant("select_id", 0); - sub.push_constant("retopologyOffset", retopology_offset); - inst.select_face_uniform = ⊂ + if (ob->dt >= OB_SOLID) { +#ifdef USE_CAGE_OCCLUSION + gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh); +#else + gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(mesh); +#endif + select_face_uniform->draw(geom_faces, res_handle); + } } - inst.select_edge_ps.init(); - inst.select_edge = nullptr; - if (e_data.context.select_mode & SCE_SELECT_EDGE) { - auto &sub = inst.select_edge_ps.sub("Sub"); - sub.state_set(state | DRW_STATE_FIRST_VERTEX_CONVENTION, clipping_plane_count); - sub.shader_set(sh->select_id_flat); - sub.push_constant("retopologyOffset", retopology_offset); - inst.select_edge = ⊂ + /* Unlike faces, only draw edges if edge select mode. */ + if (select_mode & SCE_SELECT_EDGE) { + ranges.edge = alloc_range(ranges.total, em->bm->totedge); + + gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh); + select_edge->push_constant("offset", int(ranges.edge.start())); + select_edge->draw(geom_edges, res_handle); } - inst.select_id_vert_ps.init(); - inst.select_vert = nullptr; - if (e_data.context.select_mode & SCE_SELECT_VERTEX) { - const float vertex_size = blender::draw::overlay::Resources::vertex_size_get(); - auto &sub = inst.select_id_vert_ps.sub("Sub"); - sub.state_set(state, clipping_plane_count); - sub.shader_set(sh->select_id_flat); - sub.push_constant("vertex_size", float(2 * vertex_size)); - sub.push_constant("retopologyOffset", retopology_offset); - inst.select_vert = ⊂ + /* Unlike faces, only verts if vert select mode. */ + if (select_mode & SCE_SELECT_VERTEX) { + ranges.vert = alloc_range(ranges.total, em->bm->totvert); + + gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh); + select_vert->push_constant("offset", int(ranges.vert.start())); + select_vert->draw(geom_verts, res_handle); } + return ranges; } - e_data.context.elem_ranges.clear(); + ElemIndexRanges mesh_sync(Object *ob, + ResourceHandle res_handle, + short select_mode, + const uint initial_index) + { + using namespace blender::draw; + using namespace blender; + Mesh &mesh = *static_cast(ob->data); - e_data.context.persmat = float4x4(draw_ctx->rv3d->persmat); - e_data.context.max_index_drawn_len = 1; - select_engine_framebuffer_setup(); - GPU_framebuffer_bind(e_data.framebuffer_select_id); - GPU_framebuffer_clear_color_depth(e_data.framebuffer_select_id, blender::float4{0.0f}, 1.0f); -} - -static bool check_ob_drawface_dot(short select_mode, const View3D *v3d, eDrawType dt) -{ - if (select_mode & SCE_SELECT_FACE) { - if ((dt < OB_SOLID) || XRAY_FLAG_ENABLED(v3d)) { - return true; - } - if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) { - return true; - } - } - return false; -} - -namespace blender { - -/* Return a new range if size `n` after `total_range` and grow `total_range` by the same amount. */ -static IndexRange alloc_range(IndexRange &total_range, uint size) -{ - const IndexRange indices = total_range.after(size); - total_range = IndexRange::from_begin_size(total_range.start(), total_range.size() + size); - return indices; -} - -} // namespace blender - -static ElemIndexRanges select_id_edit_mesh_sync(SELECTID_Instance &inst, - Object *ob, - ResourceHandle res_handle, - short select_mode, - bool draw_facedot, - const uint initial_index) -{ - using namespace blender::draw; - using namespace blender; - Mesh &mesh = *static_cast(ob->data); - BMEditMesh *em = mesh.runtime->edit_mesh.get(); - - ElemIndexRanges ranges{}; - ranges.total = IndexRange::from_begin_size(initial_index, 0); - - BM_mesh_elem_table_ensure(em->bm, BM_VERT | BM_EDGE | BM_FACE); - - if (select_mode & SCE_SELECT_FACE) { - ranges.face = alloc_range(ranges.total, em->bm->totface); + ElemIndexRanges ranges{}; + ranges.total = IndexRange::from_begin_size(initial_index, 0); gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh); - PassSimple::Sub *face_sub = inst.select_face_flat; - face_sub->push_constant("offset", int(ranges.face.start())); - face_sub->draw(geom_faces, res_handle); + if (select_mode & SCE_SELECT_FACE) { + ranges.face = alloc_range(ranges.total, mesh.faces_num); - if (draw_facedot) { - gpu::Batch *geom_facedots = DRW_mesh_batch_cache_get_facedots_with_select_id(mesh); - face_sub->draw(geom_facedots, res_handle); + select_face_flat->push_constant("offset", int(ranges.face.start())); + select_face_flat->draw(geom_faces, res_handle); } - } - else { - if (ob->dt >= OB_SOLID) { -#ifdef USE_CAGE_OCCLUSION - gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh); -#else - gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface(mesh); -#endif - inst.select_face_uniform->draw(geom_faces, res_handle); + else { + /* Only draw faces to mask out verts, we don't want their selection ID's. */ + select_face_uniform->draw(geom_faces, res_handle); } + + if (select_mode & SCE_SELECT_EDGE) { + ranges.edge = alloc_range(ranges.total, mesh.edges_num); + + gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh); + select_edge->push_constant("offset", int(ranges.edge.start())); + select_edge->draw(geom_edges, res_handle); + } + + if (select_mode & SCE_SELECT_VERTEX) { + ranges.vert = alloc_range(ranges.total, mesh.verts_num); + + gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh); + select_vert->push_constant("offset", int(ranges.vert.start())); + select_vert->draw(geom_verts, res_handle); + } + + return ranges; } - /* Unlike faces, only draw edges if edge select mode. */ - if (select_mode & SCE_SELECT_EDGE) { - ranges.edge = alloc_range(ranges.total, em->bm->totedge); + ElemIndexRanges object_sync( + View3D *v3d, Object *ob, ResourceHandle res_handle, short select_mode, uint index_start) + { + BLI_assert_msg(index_start > 0, "Index 0 is reserved for no selection"); - gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh); - inst.select_edge->push_constant("offset", int(ranges.edge.start())); - inst.select_edge->draw(geom_edges, res_handle); - } - - /* Unlike faces, only verts if vert select mode. */ - if (select_mode & SCE_SELECT_VERTEX) { - ranges.vert = alloc_range(ranges.total, em->bm->totvert); - - gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh); - inst.select_vert->push_constant("offset", int(ranges.vert.start())); - inst.select_vert->draw(geom_verts, res_handle); - } - return ranges; -} - -static ElemIndexRanges select_id_mesh_sync(SELECTID_Instance &inst, - Object *ob, - ResourceHandle res_handle, - short select_mode, - const uint initial_index) -{ - using namespace blender::draw; - using namespace blender; - Mesh &mesh = *static_cast(ob->data); - - ElemIndexRanges ranges{}; - ranges.total = IndexRange::from_begin_size(initial_index, 0); - - gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_triangles_with_select_id(mesh); - if (select_mode & SCE_SELECT_FACE) { - ranges.face = alloc_range(ranges.total, mesh.faces_num); - - inst.select_face_flat->push_constant("offset", int(ranges.face.start())); - inst.select_face_flat->draw(geom_faces, res_handle); - } - else { - /* Only draw faces to mask out verts, we don't want their selection ID's. */ - inst.select_face_uniform->draw(geom_faces, res_handle); - } - - if (select_mode & SCE_SELECT_EDGE) { - ranges.edge = alloc_range(ranges.total, mesh.edges_num); - - gpu::Batch *geom_edges = DRW_mesh_batch_cache_get_edges_with_select_id(mesh); - inst.select_edge->push_constant("offset", int(ranges.edge.start())); - inst.select_edge->draw(geom_edges, res_handle); - } - - if (select_mode & SCE_SELECT_VERTEX) { - ranges.vert = alloc_range(ranges.total, mesh.verts_num); - - gpu::Batch *geom_verts = DRW_mesh_batch_cache_get_verts_with_select_id(mesh); - inst.select_vert->push_constant("offset", int(ranges.vert.start())); - inst.select_vert->draw(geom_verts, res_handle); - } - - return ranges; -} - -static ElemIndexRanges select_id_object_sync(SELECTID_Instance &inst, - View3D *v3d, - Object *ob, - ResourceHandle res_handle, - short select_mode, - uint index_start) -{ - BLI_assert_msg(index_start > 0, "Index 0 is reserved for no selection"); - - switch (ob->type) { - case OB_MESH: { - const Mesh &mesh = *static_cast(ob->data); - if (mesh.runtime->edit_mesh) { - bool draw_facedot = check_ob_drawface_dot(select_mode, v3d, eDrawType(ob->dt)); - return select_id_edit_mesh_sync( - inst, ob, res_handle, select_mode, draw_facedot, index_start); + switch (ob->type) { + case OB_MESH: { + const Mesh &mesh = *static_cast(ob->data); + if (mesh.runtime->edit_mesh) { + bool draw_facedot = check_ob_drawface_dot(select_mode, v3d, eDrawType(ob->dt)); + return edit_mesh_sync(ob, res_handle, select_mode, draw_facedot, index_start); + } + return mesh_sync(ob, res_handle, select_mode, index_start); } - return select_id_mesh_sync(inst, ob, res_handle, select_mode, index_start); + case OB_CURVES_LEGACY: + case OB_SURF: + break; } - case OB_CURVES_LEGACY: - case OB_SURF: - break; - } - BLI_assert_unreachable(); - return ElemIndexRanges{}; -} - -static void select_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref) -{ - Manager &manager = *DRW_manager_get(); - Object *ob = ob_ref.object; - SelectEngineData &e_data = get_engine_data(); - SELECTID_Context &sel_ctx = e_data.context; - SELECTID_Instance &inst = *reinterpret_cast(vedata)->instance; - const DRWContext *draw_ctx = DRW_context_get(); - - if (!sel_ctx.objects.contains(ob) && ob->dt >= OB_SOLID) { - /* This object is not selectable. It is here to participate in occlusion. - * This is the case in retopology mode. */ - blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface( - *static_cast(ob->data)); - - inst.depth_occlude->draw(geom_faces, manager.resource_handle(ob_ref)); - return; + BLI_assert_unreachable(); + return ElemIndexRanges{}; } - /* Only sync selectable object once. - * This can happen in retopology mode where there is two sync loop. */ - sel_ctx.elem_ranges.lookup_or_add_cb(ob, [&]() { - ResourceHandle res_handle = manager.resource_handle(ob_ref); - ElemIndexRanges elem_ranges = select_id_object_sync( - inst, draw_ctx->v3d, ob, res_handle, sel_ctx.select_mode, sel_ctx.max_index_drawn_len); - sel_ctx.max_index_drawn_len = elem_ranges.total.one_after_last(); - return elem_ranges; - }); -} - -static void select_draw_scene(void *vedata) -{ - Manager &manager = *DRW_manager_get(); - SelectEngineData &e_data = get_engine_data(); - SELECTID_Instance &inst = *reinterpret_cast(vedata)->instance; - - DRW_submission_start(); + void object_sync(ObjectRef &ob_ref, Manager &manager) final { + Object *ob = ob_ref.object; + StaticData &e_data = StaticData::get(); + SELECTID_Context &sel_ctx = e_data.context; const DRWContext *draw_ctx = DRW_context_get(); - View::OffsetData offset_data(*draw_ctx->rv3d); - /* Create view with depth offset */ - const View &view = View::default_get(); - inst.view_faces.sync(view.viewmat(), view.winmat()); - inst.view_edges.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.0f)); - inst.view_verts.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.1f)); + + if (!sel_ctx.objects.contains(ob) && ob->dt >= OB_SOLID) { + /* This object is not selectable. It is here to participate in occlusion. + * This is the case in retopology mode. */ + blender::gpu::Batch *geom_faces = DRW_mesh_batch_cache_get_surface( + *static_cast(ob->data)); + + depth_occlude->draw(geom_faces, manager.resource_handle(ob_ref)); + return; + } + + /* Only sync selectable object once. + * This can happen in retopology mode where there is two sync loop. */ + sel_ctx.elem_ranges.lookup_or_add_cb(ob, [&]() { + ResourceHandle res_handle = manager.resource_handle(ob_ref); + ElemIndexRanges elem_ranges = object_sync( + draw_ctx->v3d, ob, res_handle, sel_ctx.select_mode, sel_ctx.max_index_drawn_len); + sel_ctx.max_index_drawn_len = elem_ranges.total.one_after_last(); + return elem_ranges; + }); } + void end_sync() final {} + + void draw(Manager &manager) final { - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - GPU_framebuffer_bind(dfbl->depth_only_fb); - GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0f); - manager.submit(inst.depth_only_ps, inst.view_faces); + StaticData &e_data = StaticData::get(); + + DRW_submission_start(); + { + const DRWContext *draw_ctx = DRW_context_get(); + View::OffsetData offset_data(*draw_ctx->rv3d); + /* Create view with depth offset */ + const View &view = View::default_get(); + view_faces.sync(view.viewmat(), view.winmat()); + view_edges.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.0f)); + view_verts.sync(view.viewmat(), offset_data.winmat_polygon_offset(view.winmat(), 1.1f)); + } + + { + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + GPU_framebuffer_bind(dfbl->depth_only_fb); + GPU_framebuffer_clear_depth(dfbl->depth_only_fb, 1.0f); + manager.submit(depth_only_ps, view_faces); + } + + /* Setup framebuffer */ + GPU_framebuffer_bind(e_data.framebuffer_select_id); + + manager.submit(select_face_ps, view_faces); + + if (e_data.context.select_mode & SCE_SELECT_EDGE) { + manager.submit(select_edge_ps, view_edges); + } + + if (e_data.context.select_mode & SCE_SELECT_VERTEX) { + manager.submit(select_id_vert_ps, view_verts); + } + DRW_submission_end(); } - /* Setup framebuffer */ - GPU_framebuffer_bind(e_data.framebuffer_select_id); + private: + void framebuffer_setup() + { + StaticData &e_data = StaticData::get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + int size[2]; + size[0] = GPU_texture_width(dtxl->depth); + size[1] = GPU_texture_height(dtxl->depth); - manager.submit(inst.select_face_ps, inst.view_faces); + if (e_data.framebuffer_select_id == nullptr) { + e_data.framebuffer_select_id = GPU_framebuffer_create("framebuffer_select_id"); + } - if (e_data.context.select_mode & SCE_SELECT_EDGE) { - manager.submit(inst.select_edge_ps, inst.view_edges); + if ((e_data.texture_u32 != nullptr) && ((GPU_texture_width(e_data.texture_u32) != size[0]) || + (GPU_texture_height(e_data.texture_u32) != size[1]))) + { + GPU_texture_free(e_data.texture_u32); + e_data.texture_u32 = nullptr; + } + + /* Make sure the depth texture is attached. + * It may disappear when loading another Blender session. */ + GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, dtxl->depth, 0, 0); + + if (e_data.texture_u32 == nullptr) { + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT; + e_data.texture_u32 = GPU_texture_create_2d( + "select_buf_ids", size[0], size[1], 1, GPU_R32UI, usage, nullptr); + GPU_framebuffer_texture_attach(e_data.framebuffer_select_id, e_data.texture_u32, 0, 0); + + GPU_framebuffer_check_valid(e_data.framebuffer_select_id, nullptr); + } } - if (e_data.context.select_mode & SCE_SELECT_VERTEX) { - manager.submit(inst.select_id_vert_ps, inst.view_verts); + short get_object_select_mode(Scene *scene, Object *ob) + { + short r_select_mode = 0; + if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) { + /* In order to sample flat colors for vertex weights / texture-paint / vertex-paint + * we need to be in SCE_SELECT_FACE mode so select_cache_init() correctly sets up + * a shgroup with select_id_flat. + * Note this is not working correctly for vertex-paint (yet), but has been discussed + * in #66645 and there is a solution by @mano-wii in P1032. + * So OB_MODE_VERTEX_PAINT is already included here [required for P1032 I guess]. */ + Mesh *me_orig = static_cast(DEG_get_original_object(ob)->data); + if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) { + r_select_mode = SCE_SELECT_VERTEX; + } + else { + r_select_mode = SCE_SELECT_FACE; + } + } + else { + r_select_mode = scene->toolsettings->selectmode; + } + + return r_select_mode; } - DRW_submission_end(); + + bool check_ob_drawface_dot(short select_mode, const View3D *v3d, eDrawType dt) + { + if (select_mode & SCE_SELECT_FACE) { + if ((dt < OB_SOLID) || XRAY_FLAG_ENABLED(v3d)) { + return true; + } + if (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_FACE_DOT) { + return true; + } + } + return false; + } + + /* Return a new range if size `n` after `total_range` and grow `total_range` by the same amount. + */ + IndexRange alloc_range(IndexRange &total_range, uint size) + { + const IndexRange indices = total_range.after(size); + total_range = IndexRange::from_begin_size(total_range.start(), total_range.size() + size); + return indices; + } +}; + +DrawEngine *Engine::create_instance() +{ + return new Instance(); } -static void select_engine_free() +void Engine::free_static() { - SelectEngineData &e_data = get_engine_data(); + Instance::StaticData &e_data = Instance::StaticData::get(); for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) { - SELECTID_Shaders *sh_data = &e_data.sh_data[sh_data_index]; + Instance::StaticData::Shaders *sh_data = &e_data.sh_data[sh_data_index]; GPU_SHADER_FREE_SAFE(sh_data->select_id_flat); GPU_SHADER_FREE_SAFE(sh_data->select_id_uniform); } @@ -480,57 +492,7 @@ static void select_engine_free() GPU_FRAMEBUFFER_FREE_SAFE(e_data.framebuffer_select_id); } -static void select_instance_free(void *instance) -{ - delete reinterpret_cast(instance); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Engine Type - * \{ */ - -DrawEngineType draw_engine_select_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("Select ID"), - /*engine_init*/ &select_engine_init, - /*engine_free*/ &select_engine_free, - /*instance_free*/ select_instance_free, - /*cache_init*/ &select_cache_init, - /*cache_populate*/ &select_cache_populate, - /*cache_finish*/ nullptr, - /*draw_scene*/ &select_draw_scene, - /*render_to_image*/ nullptr, - /*store_metadata*/ nullptr, -}; - -/* NOTE: currently unused, we may want to register so we can see this when debugging the view. */ - -RenderEngineType DRW_engine_viewport_select_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ SELECT_ENGINE, - /*name*/ N_("Select ID"), - /*flag*/ RE_INTERNAL | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT, - /*update*/ nullptr, - /*render*/ nullptr, - /*render_frame_finish*/ nullptr, - /*draw*/ nullptr, - /*bake*/ nullptr, - /*view_update*/ nullptr, - /*view_draw*/ nullptr, - /*update_script_node*/ nullptr, - /*update_render_passes*/ nullptr, - /*draw_engine*/ &draw_engine_select_type, - /*rna_ext*/ - { - /*data*/ nullptr, - /*srna*/ nullptr, - /*call*/ nullptr, - }, -}; +} // namespace blender::draw::edit_select /** \} */ @@ -538,24 +500,24 @@ RenderEngineType DRW_engine_viewport_select_type = { /** \name Exposed `select_private.h` functions * \{ */ +using namespace blender::draw::edit_select; + SELECTID_Context *DRW_select_engine_context_get() { - SelectEngineData &e_data = get_engine_data(); + Instance::StaticData &e_data = Instance::StaticData::get(); return &e_data.context; } GPUFrameBuffer *DRW_engine_select_framebuffer_get() { - SelectEngineData &e_data = get_engine_data(); + Instance::StaticData &e_data = Instance::StaticData::get(); return e_data.framebuffer_select_id; } GPUTexture *DRW_engine_select_texture_get() { - SelectEngineData &e_data = get_engine_data(); + Instance::StaticData &e_data = Instance::StaticData::get(); return e_data.texture_u32; } /** \} */ - -#undef SELECT_ENGINE diff --git a/source/blender/draw/engines/select/select_engine.hh b/source/blender/draw/engines/select/select_engine.hh index 92a445e0f9b..1c2b4a7ea16 100644 --- a/source/blender/draw/engines/select/select_engine.hh +++ b/source/blender/draw/engines/select/select_engine.hh @@ -8,15 +8,23 @@ #pragma once -/* `select_engine.cc` */ +#include "DRW_render.hh" -extern DrawEngineType draw_engine_select_type; -extern RenderEngineType DRW_engine_viewport_select_type; +/* `select_engine.cc` */ #ifdef WITH_DRAW_DEBUG /* `select_debug_engine.cc` */ -extern DrawEngineType draw_engine_debug_select_type; +namespace blender::draw::edit_select_debug { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; + + static void free_static(); +}; + +} // namespace blender::draw::edit_select_debug + #endif struct SELECTID_Context *DRW_select_engine_context_get(); @@ -25,4 +33,20 @@ struct GPUTexture *DRW_engine_select_texture_get(); /* select_instance.cc */ -extern DrawEngineType draw_engine_select_next_type; +namespace blender::draw::select { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; +}; + +} // namespace blender::draw::select + +namespace blender::draw::edit_select { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; + + static void free_static(); +}; + +} // namespace blender::draw::edit_select diff --git a/source/blender/draw/engines/select/select_instance.cc b/source/blender/draw/engines/select/select_instance.cc index 49163bd6c14..86ddbb4e417 100644 --- a/source/blender/draw/engines/select/select_instance.cc +++ b/source/blender/draw/engines/select/select_instance.cc @@ -8,79 +8,21 @@ #include "DRW_render.hh" -#include "BLT_translation.hh" - #include "select_engine.hh" #include "../overlay/overlay_next_instance.hh" #include "select_instance.hh" -using namespace blender::draw; +namespace blender::draw::select { -/* -------------------------------------------------------------------- */ -/** \name Select-Next Engine - * \{ */ - -using Instance = overlay::Instance; - -struct SELECT_NextData { - void *engine_type; - Instance *instance; +class Instance : public overlay::Instance { + public: + Instance() : overlay::Instance(SelectionType::ENABLED){}; }; -static void SELECT_next_engine_init(void *vedata) +DrawEngine *Engine::create_instance() { - OVERLAY_Data *ved = reinterpret_cast(vedata); - - if (ved->instance == nullptr) { - ved->instance = new Instance(select::SelectionType::ENABLED); - } - reinterpret_cast(ved->instance)->init(); + return new Instance(); } -static void SELECT_next_cache_init(void *vedata) -{ - reinterpret_cast(reinterpret_cast(vedata)->instance)->begin_sync(); -} - -static void SELECT_next_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref) -{ - reinterpret_cast(reinterpret_cast(vedata)->instance) - ->object_sync(ob_ref, *DRW_manager_get()); -} - -static void SELECT_next_cache_finish(void *vedata) -{ - reinterpret_cast(reinterpret_cast(vedata)->instance)->end_sync(); -} - -static void SELECT_next_draw_scene(void *vedata) -{ - DRW_submission_start(); - reinterpret_cast(reinterpret_cast(vedata)->instance) - ->draw(*DRW_manager_get()); - DRW_submission_end(); -} - -static void SELECT_next_instance_free(void *instance_) -{ - Instance *instance = (Instance *)instance_; - delete instance; -} - -DrawEngineType draw_engine_select_next_type = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("Select-Next"), - /*engine_init*/ &SELECT_next_engine_init, - /*engine_free*/ nullptr, - /*instance_free*/ &SELECT_next_instance_free, - /*cache_init*/ &SELECT_next_cache_init, - /*cache_populate*/ &SELECT_next_cache_populate, - /*cache_finish*/ &SELECT_next_cache_finish, - /*draw_scene*/ &SELECT_next_draw_scene, - /*render_to_image*/ nullptr, - /*store_metadata*/ nullptr, -}; - -/** \} */ +} // namespace blender::draw::select diff --git a/source/blender/draw/engines/select/select_private.hh b/source/blender/draw/engines/select/select_private.hh deleted file mode 100644 index c562479e9e3..00000000000 --- a/source/blender/draw/engines/select/select_private.hh +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-FileCopyrightText: 2019 Blender Authors - * - * SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup draw_engine - */ - -#pragma once - -#define USE_CAGE_OCCLUSION - -#include "draw_manager.hh" -#include "draw_pass.hh" -#include "draw_view_data.hh" - -#include "DRW_render.hh" -#include "DRW_select_buffer.hh" - -using namespace blender::draw; - -/* GPUViewport.storage - * Is freed every time the viewport engine changes. */ -struct SELECTID_StorageList { - struct SELECTID_PrivateData *g_data; -}; - -struct SELECTID_Instance { - PassSimple depth_only_ps = {"depth_only_ps"}; - PassSimple::Sub *depth_only = nullptr; - PassSimple::Sub *depth_occlude = nullptr; - - PassSimple select_edge_ps = {"select_id_edge_ps"}; - PassSimple::Sub *select_edge = nullptr; - - PassSimple select_id_vert_ps = {"select_id_vert_ps"}; - PassSimple::Sub *select_vert = nullptr; - - PassSimple select_face_ps = {"select_id_face_ps"}; - PassSimple::Sub *select_face_uniform = nullptr; - PassSimple::Sub *select_face_flat = nullptr; - - View view_faces = {"view_faces"}; - View view_edges = {"view_edges"}; - View view_verts = {"view_verts"}; -}; - -struct SELECTID_Data { - void *engine_type; - SELECTID_Instance *instance; - - char info[GPU_INFO_SIZE]; -}; - -struct SELECTID_Shaders { - /* Depth Pre Pass */ - GPUShader *select_id_flat; - GPUShader *select_id_uniform; -}; diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 707202bd0e3..3fdc75a9dbf 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -41,7 +41,7 @@ namespace blender::workbench { using namespace draw; -class Instance { +class Instance : public DrawEngine { private: View view_ = {"DefaultView"}; @@ -67,6 +67,11 @@ class Instance { uint64_t depsgraph_last_update_ = 0; public: + blender::StringRefNull name_get() final + { + return "Workbench"; + } + Span get_dummy_gpu_materials(int material_count) { if (material_count > dummy_gpu_materials_.size()) { @@ -75,6 +80,11 @@ class Instance { return dummy_gpu_materials_.as_span().slice(IndexRange(material_count)); }; + void init() final + { + init(DRW_context_get()->depsgraph); + } + void init(Depsgraph *depsgraph, Object *camera_ob = nullptr) { bool scene_updated = assign_if_different(depsgraph_last_update_, @@ -89,7 +99,7 @@ class Instance { anti_aliasing_ps_.init(scene_state_); } - void begin_sync() + void begin_sync() final { resources_.material_buf.clear_and_trim(); @@ -104,7 +114,7 @@ class Instance { anti_aliasing_ps_.sync(scene_state_, resources_); } - void end_sync() + void end_sync() final { resources_.material_buf.push_update(); } @@ -132,7 +142,7 @@ class Instance { } } - void object_sync(Manager &manager, ObjectRef &ob_ref) + void object_sync(ObjectRef &ob_ref, Manager &manager) final { if (scene_state_.render_finished) { return; @@ -494,6 +504,20 @@ class Instance { } } + void draw(Manager &manager) final + { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + DRW_submission_start(); + if (DRW_state_is_viewport_image_render()) { + draw_image_render(manager, dtxl->depth, dtxl->depth_in_front, dtxl->color); + } + else { + draw_viewport(manager, dtxl->depth, dtxl->depth_in_front, dtxl->color); + } + DRW_submission_end(); + } + void draw_image_render(Manager &manager, GPUTexture *depth_tx, GPUTexture *depth_in_front_tx, @@ -523,6 +547,16 @@ class Instance { } }; +DrawEngine *Engine::create_instance() +{ + return new Instance(); +} + +void Engine::free_static() +{ + ShaderCache::release(); +} + } // namespace blender::workbench /* -------------------------------------------------------------------- */ @@ -531,66 +565,6 @@ class Instance { using namespace blender; -struct WORKBENCH_Data { - DrawEngineType *engine_type; - workbench::Instance *instance; - - char info[GPU_INFO_SIZE]; -}; - -static void workbench_engine_init(void *vedata) -{ - WORKBENCH_Data *ved = reinterpret_cast(vedata); - if (ved->instance == nullptr) { - ved->instance = new workbench::Instance(); - } - - ved->instance->init(DRW_context_get()->depsgraph); -} - -static void workbench_cache_init(void *vedata) -{ - reinterpret_cast(vedata)->instance->begin_sync(); -} - -static void workbench_cache_populate(void *vedata, blender::draw::ObjectRef &ob_ref) -{ - draw::Manager *manager = DRW_manager_get(); - - reinterpret_cast(vedata)->instance->object_sync(*manager, ob_ref); -} - -static void workbench_cache_finish(void *vedata) -{ - reinterpret_cast(vedata)->instance->end_sync(); -} - -static void workbench_draw_scene(void *vedata) -{ - WORKBENCH_Data *ved = reinterpret_cast(vedata); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - draw::Manager *manager = DRW_manager_get(); - - DRW_submission_start(); - if (DRW_state_is_viewport_image_render()) { - ved->instance->draw_image_render(*manager, dtxl->depth, dtxl->depth_in_front, dtxl->color); - } - else { - ved->instance->draw_viewport(*manager, dtxl->depth, dtxl->depth_in_front, dtxl->color); - } - DRW_submission_end(); -} - -static void workbench_instance_free(void *instance) -{ - delete reinterpret_cast(instance); -} - -static void workbench_engine_free() -{ - workbench::ShaderCache::release(); -} - /* RENDER */ static bool workbench_render_framebuffers_init() @@ -704,10 +678,7 @@ static void write_render_z_output(RenderLayer *layer, } } -static void workbench_render_to_image(void *vedata, - RenderEngine *engine, - RenderLayer *layer, - const rcti *rect) +static void workbench_render_to_image(RenderEngine *engine, RenderLayer *layer, const rcti rect) { using namespace blender::draw; if (!workbench_render_framebuffers_init()) { @@ -720,10 +691,7 @@ static void workbench_render_to_image(void *vedata, const DRWContext *draw_ctx = DRW_context_get(); Depsgraph *depsgraph = draw_ctx->depsgraph; - WORKBENCH_Data *ved = reinterpret_cast(vedata); - if (ved->instance == nullptr) { - ved->instance = new workbench::Instance(); - } + workbench::Instance instance; /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ Object *camera_ob = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); @@ -739,34 +707,33 @@ static void workbench_render_to_image(void *vedata, DRW_cache_restart(); blender::draw::View::default_set(float4x4(viewmat), float4x4(winmat)); - ved->instance->init(depsgraph, camera_ob); + instance.init(depsgraph, camera_ob); draw::Manager &manager = *DRW_manager_get(); manager.begin_sync(); - workbench_cache_init(vedata); - auto workbench_render_cache = [](void *vedata, - blender::draw::ObjectRef &ob_ref, - RenderEngine * /*engine*/, - Depsgraph * /*depsgraph*/) { - workbench_cache_populate(vedata, ob_ref); - }; - DRW_render_object_iter(vedata, engine, depsgraph, workbench_render_cache); - workbench_cache_finish(vedata); + instance.begin_sync(); + DRW_render_object_iter( + engine, + depsgraph, + [&](blender::draw::ObjectRef &ob_ref, RenderEngine * /*engine*/, Depsgraph * /*depsgraph*/) { + instance.object_sync(ob_ref, manager); + }); + instance.end_sync(); manager.end_sync(); DRW_submission_start(); DefaultTextureList &dtxl = *DRW_viewport_texture_list_get(); - ved->instance->draw_image_render(manager, dtxl.depth, dtxl.depth_in_front, dtxl.color, engine); + instance.draw_image_render(manager, dtxl.depth, dtxl.depth_in_front, dtxl.color, engine); DRW_submission_end(); /* Write image */ const char *viewname = RE_GetActiveRenderView(engine->re); - write_render_color_output(layer, viewname, dfbl->default_fb, rect); - write_render_z_output(layer, viewname, dfbl->default_fb, rect, winmat); + write_render_color_output(layer, viewname, dfbl->default_fb, &rect); + write_render_z_output(layer, viewname, dfbl->default_fb, &rect, winmat); } static void workbench_render_update_passes(RenderEngine *engine, @@ -781,20 +748,10 @@ static void workbench_render_update_passes(RenderEngine *engine, } } -DrawEngineType draw_engine_workbench = { - /*next*/ nullptr, - /*prev*/ nullptr, - /*idname*/ N_("Workbench"), - /*engine_init*/ &workbench_engine_init, - /*engine_free*/ &workbench_engine_free, - /*instance_free*/ &workbench_instance_free, - /*cache_init*/ &workbench_cache_init, - /*cache_populate*/ &workbench_cache_populate, - /*cache_finish*/ &workbench_cache_finish, - /*draw_scene*/ &workbench_draw_scene, - /*render_to_image*/ &workbench_render_to_image, - /*store_metadata*/ nullptr, -}; +void workbench_render(RenderEngine *engine, Depsgraph *depsgraph) +{ + DRW_render_to_image(engine, depsgraph, workbench_render_to_image, [](RenderResult *) {}); +} RenderEngineType DRW_engine_viewport_workbench_type = { /*next*/ nullptr, @@ -803,7 +760,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = { /*name*/ N_("Workbench"), /*flag*/ RE_INTERNAL | RE_USE_STEREO_VIEWPORT | RE_USE_GPU_CONTEXT, /*update*/ nullptr, - /*render*/ &DRW_render_to_image, + /*render*/ &workbench_render, /*render_frame_finish*/ nullptr, /*draw*/ nullptr, /*bake*/ nullptr, @@ -811,7 +768,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = { /*view_draw*/ nullptr, /*update_script_node*/ nullptr, /*update_render_passes*/ &workbench_render_update_passes, - /*draw_engine*/ &draw_engine_workbench, + /*draw_engine*/ nullptr, /*rna_ext*/ { /*data*/ nullptr, diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h index ea8c0947fa6..d2d977bb752 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.h +++ b/source/blender/draw/engines/workbench/workbench_engine.h @@ -8,6 +8,18 @@ #pragma once +#include "DRW_render.hh" + struct RenderEngineType; extern RenderEngineType DRW_engine_viewport_workbench_type; + +namespace blender::workbench { + +struct Engine : public DrawEngine::Pointer { + DrawEngine *create_instance() final; + + static void free_static(); +}; + +} // namespace blender::workbench diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh index d514bc2746c..4b03b229add 100644 --- a/source/blender/draw/engines/workbench/workbench_private.hh +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -16,8 +16,6 @@ #include "GPU_capabilities.hh" -extern "C" DrawEngineType draw_engine_workbench; - namespace blender::workbench { using namespace draw; diff --git a/source/blender/draw/intern/DRW_render.hh b/source/blender/draw/intern/DRW_render.hh index 804943f7bfd..42bac12eec1 100644 --- a/source/blender/draw/intern/DRW_render.hh +++ b/source/blender/draw/intern/DRW_render.hh @@ -54,6 +54,7 @@ struct GPUViewport; namespace blender::draw { class TextureFromPool; struct ObjectRef; +class Manager; } // namespace blender::draw typedef struct DRWPass DRWPass; @@ -65,27 +66,63 @@ struct BoundSphere { float center[3], radius; }; -struct DrawEngineType { - DrawEngineType *next, *prev; +struct DrawEngine { + static constexpr int GPU_INFO_SIZE = 512; /* IMA_MAX_RENDER_TEXT_SIZE */ - char idname[32]; + char info[GPU_INFO_SIZE] = {'\0'}; + DRWTextStore *text_draw_cache = nullptr; - void (*engine_init)(void *vedata); - void (*engine_free)(); + bool used = false; - void (*instance_free)(void *instance_data); + virtual ~DrawEngine() = default; - void (*cache_init)(void *vedata); - void (*cache_populate)(void *vedata, blender::draw::ObjectRef &ob_ref); - void (*cache_finish)(void *vedata); + virtual blender::StringRefNull name_get() = 0; - void (*draw_scene)(void *vedata); + /* Functions called for viewport. */ - void (*render_to_image)(void *vedata, - RenderEngine *engine, - RenderLayer *layer, - const rcti *rect); - void (*store_metadata)(void *vedata, RenderResult *render_result); + /* Init engine. Run first and for every redraw. */ + virtual void init() = 0; + /* Scene synchronization. Command buffers building. */ + virtual void begin_sync() = 0; + virtual void object_sync(blender::draw::ObjectRef &ob_ref, blender::draw::Manager &manager) = 0; + virtual void end_sync() = 0; + /* Command Submission. */ + virtual void draw(blender::draw::Manager &manager) = 0; + + /* Called when closing blender. + * Cleanup all lazily initialized static members that have GPU resources. + * Implemented on a case by case basis and called directly. */ + // static void exit(){}; + + struct Pointer { + DrawEngine *instance = nullptr; + + ~Pointer() + { + free_instance(); + } + + void free_instance() + { + delete instance; + instance = nullptr; + } + + void set_used(bool used) + { + if (used) { + if (instance == nullptr) { + instance = create_instance(); + } + instance->used = true; + } + else if (instance) { + instance->used = false; + } + } + + virtual DrawEngine *create_instance() = 0; + }; }; /* Shaders */ @@ -120,19 +157,24 @@ blender::float2 DRW_viewport_size_get(); DefaultFramebufferList *DRW_viewport_framebuffer_list_get(); DefaultTextureList *DRW_viewport_texture_list_get(); -/* See DRW_viewport_pass_texture_get. */ +/* Returns a TextureFromPool stored in the given view data for the pass identified by the given + * pass name. Engines should call this function for each of the passes needed by the viewport + * compositor in every redraw, then it should allocate the texture and write the pass data to it. + * The texture should cover the entire viewport. */ blender::draw::TextureFromPool &DRW_viewport_pass_texture_get(const char *pass_name); void DRW_viewport_request_redraw(); -void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph); -void DRW_render_object_iter(void *vedata, - RenderEngine *engine, - Depsgraph *depsgraph, - void (*callback)(void *vedata, - blender::draw::ObjectRef &ob_ref, - RenderEngine *engine, - Depsgraph *depsgraph)); +void DRW_render_to_image( + RenderEngine *engine, + Depsgraph *depsgraph, + std::function render_view_cb, + std::function store_metadata_cb); + +void DRW_render_object_iter( + RenderEngine *engine, + Depsgraph *depsgraph, + std::function); /** * \warning Changing frame might free the #ViewLayerEngineData. @@ -144,9 +186,7 @@ void DRW_render_set_time(RenderEngine *engine, Depsgraph *depsgraph, int frame, * This function only setup DST and execute the given function. * \warning similar to DRW_render_to_image you cannot use default lists (`dfbl` & `dtxl`). */ -void DRW_custom_pipeline_begin(DRWContext &draw_ctx, - DrawEngineType *draw_engine_type, - Depsgraph *depsgraph); +void DRW_custom_pipeline_begin(DRWContext &draw_ctx, Depsgraph *depsgraph); void DRW_custom_pipeline_end(DRWContext &draw_ctx); /** @@ -155,24 +195,6 @@ void DRW_custom_pipeline_end(DRWContext &draw_ctx); */ void DRW_cache_restart(); -/* ViewLayers */ - -void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); -void **DRW_view_layer_engine_data_ensure_ex(ViewLayer *view_layer, - DrawEngineType *engine_type, - void (*callback)(void *storage)); -void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, - void (*callback)(void *storage)); - -/* DrawData */ - -DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type); -DrawData *DRW_drawdata_ensure(ID *id, - DrawEngineType *engine_type, - size_t size, - DrawDataInitCb init_cb, - DrawDataFreeCb free_cb); - /* Settings. */ bool DRW_object_is_renderable(const Object *ob); diff --git a/source/blender/draw/intern/draw_context.cc b/source/blender/draw/intern/draw_context.cc index 5ba980499d4..34de6468d1d 100644 --- a/source/blender/draw/intern/draw_context.cc +++ b/source/blender/draw/intern/draw_context.cc @@ -88,7 +88,7 @@ #include "engines/compositor/compositor_engine.h" #include "engines/eevee_next/eevee_engine.h" #include "engines/external/external_engine.h" -#include "engines/gpencil/gpencil_engine.h" +#include "engines/gpencil/gpencil_engine.hh" #include "engines/image/image_engine.h" #include "engines/overlay/overlay_engine.h" #include "engines/select/select_engine.hh" @@ -197,8 +197,7 @@ DRWContext::~DRWContext() GPUFrameBuffer *DRWContext::default_framebuffer() { - DefaultFramebufferList *dfbl = DRW_view_data_default_framebuffer_list_get(view_data_active); - return dfbl->default_fb; + return view_data_active->dfbl.default_fb; } static bool draw_show_annotation() @@ -496,17 +495,18 @@ void DRWContext::release_data() DefaultFramebufferList *DRW_viewport_framebuffer_list_get() { - return DRW_view_data_default_framebuffer_list_get(drw_get().view_data_active); + return &drw_get().view_data_active->dfbl; } DefaultTextureList *DRW_viewport_texture_list_get() { - return DRW_view_data_default_texture_list_get(drw_get().view_data_active); + return &drw_get().view_data_active->dtxl; } blender::draw::TextureFromPool &DRW_viewport_pass_texture_get(const char *pass_name) { - return DRW_view_data_pass_texture_get(drw_get().view_data_active, pass_name); + return *drw_get().view_data_active->viewport_compositor_passes.lookup_or_add_cb( + pass_name, [&]() { return std::make_unique(pass_name); }); } void DRW_viewport_request_redraw() @@ -634,49 +634,6 @@ void DupliCacheManager::extract_all(ExtractionGraph &extraction) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name ViewLayers (DRW_scenelayer) - * \{ */ - -void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type) -{ - LISTBASE_FOREACH (ViewLayerEngineData *, sled, &drw_get().view_layer->drawdata) { - if (sled->engine_type == engine_type) { - return sled->storage; - } - } - return nullptr; -} - -void **DRW_view_layer_engine_data_ensure_ex(ViewLayer *view_layer, - DrawEngineType *engine_type, - void (*callback)(void *storage)) -{ - ViewLayerEngineData *sled; - - LISTBASE_FOREACH (ViewLayerEngineData *, sled, &view_layer->drawdata) { - if (sled->engine_type == engine_type) { - return &sled->storage; - } - } - - sled = static_cast( - MEM_callocN(sizeof(ViewLayerEngineData), "ViewLayerEngineData")); - sled->engine_type = engine_type; - sled->free = callback; - BLI_addtail(&view_layer->drawdata, sled); - - return &sled->storage; -} - -void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, - void (*callback)(void *storage)) -{ - return DRW_view_layer_engine_data_ensure_ex(drw_get().view_layer, engine_type, callback); -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Draw Data (DRW_drawdata) * \{ */ @@ -737,56 +694,6 @@ DrawDataList *DRW_drawdatalist_from_id(ID *id) return nullptr; } -DrawData *DRW_drawdata_get(ID *id, DrawEngineType *engine_type) -{ - DrawDataList *drawdata = DRW_drawdatalist_from_id(id); - - if (drawdata == nullptr) { - return nullptr; - } - - LISTBASE_FOREACH (DrawData *, dd, drawdata) { - if (dd->engine_type == engine_type) { - return dd; - } - } - return nullptr; -} - -DrawData *DRW_drawdata_ensure(ID *id, - DrawEngineType *engine_type, - size_t size, - DrawDataInitCb init_cb, - DrawDataFreeCb free_cb) -{ - BLI_assert(size >= sizeof(DrawData)); - BLI_assert(id_can_have_drawdata(id)); - BLI_assert_msg( - GS(id->name) != ID_OB, - "Objects should not use DrawData anymore. Use last_update instead for update detection"); - /* Try to re-use existing data. */ - DrawData *dd = DRW_drawdata_get(id, engine_type); - if (dd != nullptr) { - return dd; - } - - DrawDataList *drawdata = DRW_drawdatalist_from_id(id); - - /* Allocate new data. */ - { - dd = static_cast(MEM_callocN(size, "DrawData")); - } - dd->engine_type = engine_type; - dd->free = free_cb; - /* Perform user-side initialization, if needed. */ - if (init_cb != nullptr) { - init_cb(dd); - } - /* Register in the list. */ - BLI_addtail((ListBase *)drawdata, dd); - return dd; -} - void DRW_drawdata_free(ID *id) { DrawDataList *drawdata = DRW_drawdatalist_from_id(id); @@ -908,11 +815,7 @@ static void drw_engines_cache_populate(blender::draw::ObjectRef &ref, Extraction DRWContext &ctx = drw_get(); ctx.view_data_active->foreach_enabled_engine( - [&](ViewportEngineData *data, DrawEngineType *engine) { - if (engine->cache_populate) { - engine->cache_populate(data, ref); - } - }); + [&](DrawEngine &instance) { instance.object_sync(ref, *DRW_manager_get()); }); /* TODO: in the future it would be nice to generate once for all viewports. * But we need threaded DRW manager first. */ @@ -947,34 +850,24 @@ void DRWContext::sync(iter_callback_t iter_callback) void DRWContext::engines_init_and_sync(iter_callback_t iter_callback) { - view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) { - if (engine->engine_init) { - engine->engine_init(data); - } - }); + view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { instance.init(); }); - view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) { + view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { /* TODO(fclem): Remove. Only there for overlay engine. */ - if (data->text_draw_cache) { - DRW_text_cache_destroy(data->text_draw_cache); - data->text_draw_cache = nullptr; + if (instance.text_draw_cache) { + DRW_text_cache_destroy(instance.text_draw_cache); + instance.text_draw_cache = nullptr; } if (drw_get().text_store_p == nullptr) { - drw_get().text_store_p = &data->text_draw_cache; + drw_get().text_store_p = &instance.text_draw_cache; } - if (engine->cache_init) { - engine->cache_init(data); - } + instance.begin_sync(); }); sync(iter_callback); - view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) { - if (engine->cache_finish) { - engine->cache_finish(data); - } - }); + view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { instance.end_sync(); }); } void DRWContext::engines_draw_scene() @@ -982,12 +875,10 @@ void DRWContext::engines_draw_scene() /* Start Drawing */ blender::draw::command::StateSet::set(); - view_data_active->foreach_enabled_engine([&](ViewportEngineData *data, DrawEngineType *engine) { - if (engine->draw_scene) { - GPU_debug_group_begin(engine->idname); - engine->draw_scene(data); - GPU_debug_group_end(); - } + view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { + GPU_debug_group_begin(instance.name_get().c_str()); + instance.draw(*DRW_manager_get()); + GPU_debug_group_end(); }); /* Reset state after drawing */ @@ -1002,30 +893,28 @@ void DRWContext::engines_draw_scene() static void drw_engines_draw_text() { DRWContext &ctx = drw_get(); - ctx.view_data_active->foreach_enabled_engine( - [&](ViewportEngineData *data, DrawEngineType * /*engine*/) { - if (data->text_draw_cache) { - DRW_text_cache_draw(data->text_draw_cache, ctx.region, ctx.v3d); - } - }); + ctx.view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { + if (instance.text_draw_cache) { + DRW_text_cache_draw(instance.text_draw_cache, ctx.region, ctx.v3d); + } + }); } void DRW_draw_region_engine_info(int xoffset, int *yoffset, int line_height) { DRWContext &ctx = drw_get(); - ctx.view_data_active->foreach_enabled_engine( - [&](ViewportEngineData *data, DrawEngineType * /*engine*/) { - if (data->info[0] != '\0') { - const char *buf_step = IFACE_(data->info); - do { - const char *buf = buf_step; - buf_step = BLI_strchr_or_end(buf, '\n'); - const int buf_len = buf_step - buf; - *yoffset -= line_height; - BLF_draw_default(xoffset, *yoffset, 0.0f, buf, buf_len); - } while (*buf_step ? ((void)buf_step++, true) : false); - } - }); + ctx.view_data_active->foreach_enabled_engine([&](DrawEngine &instance) { + if (instance.info[0] != '\0') { + const char *buf_step = IFACE_(instance.info); + do { + const char *buf = buf_step; + buf_step = BLI_strchr_or_end(buf, '\n'); + const int buf_len = buf_step - buf; + *yoffset -= line_height; + BLF_draw_default(xoffset, *yoffset, 0.0f, buf, buf_len); + } while (*buf_step ? ((void)buf_step++, true) : false); + } + }); } void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *render_engine_type) @@ -1035,12 +924,12 @@ void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *re SpaceLink *space_data = this->space_data; if (space_data && space_data->spacetype == SPACE_IMAGE) { if (DRW_engine_external_acquire_for_image_editor()) { - view_data.external.used = true; + view_data.external.set_used(true); } else { - view_data.image.used = true; + view_data.image.set_used(true); } - view_data.overlay.used = true; + view_data.overlay.set_used(true); return; } @@ -1048,26 +937,26 @@ void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *re /* Only enable when drawing the space image backdrop. */ SpaceNode *snode = (SpaceNode *)space_data; if ((snode->flag & SNODE_BACKDRAW) != 0) { - view_data.image.used = true; - view_data.overlay.used = true; + view_data.image.set_used(true); + view_data.overlay.set_used(true); } return; } if (ELEM(this->mode, DRWContext::SELECT_OBJECT, DRWContext::SELECT_OBJECT_MATERIAL)) { - this->view_data_active->grease_pencil.used = gpencil_engine_needed; - this->view_data_active->object_select.used = true; + view_data.grease_pencil.set_used(gpencil_engine_needed); + view_data.object_select.set_used(true); return; } if (ELEM(this->mode, DRWContext::SELECT_EDIT_MESH)) { - this->view_data_active->edit_select.used = true; + view_data.edit_select.set_used(true); return; } if (ELEM(this->mode, DRWContext::DEPTH)) { - this->view_data_active->grease_pencil.used = gpencil_engine_needed; - this->view_data_active->overlay.used = true; + view_data.grease_pencil.set_used(gpencil_engine_needed); + view_data.overlay.set_used(true); return; } @@ -1080,41 +969,39 @@ void DRWContext::enable_engines(bool gpencil_engine_needed, RenderEngineType *re switch (drawtype) { case OB_WIRE: case OB_SOLID: - view_data.workbench.used = true; + view_data.workbench.set_used(true); break; case OB_MATERIAL: case OB_RENDER: default: - if (render_engine_type->draw_engine != nullptr) { - if (render_engine_type == &DRW_engine_viewport_eevee_next_type) { - view_data.eevee.used = true; - } - else if (render_engine_type == &DRW_engine_viewport_workbench_type) { - view_data.workbench.used = true; - } - else { - BLI_assert_unreachable(); - } + if (render_engine_type == &DRW_engine_viewport_eevee_next_type) { + view_data.eevee.set_used(true); + } + else if (render_engine_type == &DRW_engine_viewport_workbench_type) { + view_data.workbench.set_used(true); } else if ((render_engine_type->flag & RE_INTERNAL) == 0) { - view_data.external.used = true; + view_data.external.set_used(true); + } + else { + BLI_assert_unreachable(); } break; } - if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) { - view_data.grease_pencil.used = true; + if ((drawtype >= OB_SOLID) || !use_xray) { + view_data.grease_pencil.set_used(gpencil_engine_needed); } if (DRW_state_viewport_compositor_enabled()) { - view_data.compositor.used = true; + view_data.compositor.set_used(true); } - view_data.overlay.used = true; + view_data.overlay.set_used(true); #ifdef WITH_DRAW_DEBUG if (G.debug_value == 31) { - view_data_active.edit_select_debug.used = true; + view_data.edit_select_debug.set_used(true); } #endif } @@ -1605,21 +1492,9 @@ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph) return false; } -static void drw_render_gpencil_to_image(RenderEngine *engine, - RenderLayer *render_layer, - const rcti *rect) -{ - DrawEngineType *draw_engine = &draw_engine_gpencil_type; - - if (draw_engine->render_to_image) { - ViewportEngineData *gpdata = DRW_view_data_engine_data_get_ensure(drw_get().view_data_active, - draw_engine); - draw_engine->render_to_image(gpdata, engine, render_layer, rect); - } -} - void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph) { + using namespace blender::draw; /* This function should only be called if there are grease pencil objects, * especially important to avoid failing in background renders without GPU context. */ BLI_assert(DRW_render_check_grease_pencil(depsgraph)); @@ -1655,10 +1530,10 @@ void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph) render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - drw_render_gpencil_to_image(engine, render_layer, &render_rect); + gpencil::Engine::render_to_image(engine, render_layer, render_rect); } - blender::draw::command::StateSet::set(); + command::StateSet::set(); GPU_depth_test(GPU_DEPTH_NONE); @@ -1672,13 +1547,15 @@ void DRW_render_gpencil(RenderEngine *engine, Depsgraph *depsgraph) DRW_render_context_disable(render); } -void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph) +void DRW_render_to_image( + RenderEngine *engine, + Depsgraph *depsgraph, + std::function render_view_cb, + std::function store_metadata_cb) { using namespace blender::draw; Scene *scene = DEG_get_evaluated_scene(depsgraph); ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); - RenderEngineType *engine_type = engine->type; - DrawEngineType *draw_engine_type = engine_type->draw_engine; Render *render = engine->re; /* IMPORTANT: We don't support immediate mode in render mode! @@ -1694,9 +1571,6 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph) /* Init modules ahead of time because the begin_sync happens before DRW_render_object_iter. */ draw_ctx.data->modules_init(); - ViewportEngineData *data = DRW_view_data_engine_data_get_ensure(drw_get().view_data_active, - draw_engine_type); - /* Main rendering. */ rctf view_rect; rcti render_rect; @@ -1706,7 +1580,7 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph) } /* Reset state before drawing */ - blender::draw::command::StateSet::set(); + command::StateSet::set(); /* set default viewport */ GPU_viewport(0, 0, draw_ctx.size[0], draw_ctx.size[1]); @@ -1725,15 +1599,12 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph) render_view = render_view->next) { RE_SetActiveRenderView(render, render_view->name); - engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); + render_view_cb(engine, render_layer, render_rect); } RE_engine_end_result(engine, render_result, false, false, false); - if (engine_type->draw_engine->store_metadata) { - RenderResult *final_render_result = RE_engine_get_result(engine); - engine_type->draw_engine->store_metadata(data, final_render_result); - } + store_metadata_cb(RE_engine_get_result(engine)); GPU_framebuffer_restore(); @@ -1746,13 +1617,10 @@ void DRW_render_to_image(RenderEngine *engine, Depsgraph *depsgraph) GPU_render_end(); } -void DRW_render_object_iter(void *vedata, - RenderEngine *engine, - Depsgraph *depsgraph, - void (*callback)(void *vedata, - blender::draw::ObjectRef &ob_ref, - RenderEngine *engine, - Depsgraph *depsgraph)) +void DRW_render_object_iter( + RenderEngine *engine, + Depsgraph *depsgraph, + std::function callback) { DRWContext &draw_ctx = drw_get(); @@ -1772,7 +1640,7 @@ void DRW_render_object_iter(void *vedata, if (ob_ref.is_dupli() == false) { drw_batch_cache_validate(ob); } - callback(vedata, ob_ref, engine, depsgraph); + callback(ob_ref, engine, depsgraph); if (ob_ref.is_dupli() == false) { drw_batch_cache_generate_requested(ob, *extraction.graph); } @@ -1782,9 +1650,7 @@ void DRW_render_object_iter(void *vedata, }); } -void DRW_custom_pipeline_begin(DRWContext &draw_ctx, - DrawEngineType * /*draw_engine_type*/, - Depsgraph * /*depsgraph*/) +void DRW_custom_pipeline_begin(DRWContext &draw_ctx, Depsgraph * /*depsgraph*/) { draw_ctx.acquire_data(); draw_ctx.data->modules_init(); @@ -2245,15 +2111,15 @@ void DRW_engines_register() void DRW_engines_free() { - DRW_engine_viewport_eevee_next_type.draw_engine->engine_free(); - DRW_engine_viewport_workbench_type.draw_engine->engine_free(); - draw_engine_gpencil_type.engine_free(); - draw_engine_image_type.engine_free(); - draw_engine_overlay_next_type.engine_free(); + blender::eevee::Engine::free_static(); + blender::workbench::Engine::free_static(); + blender::draw::gpencil::Engine::free_static(); + blender::image_engine::Engine::free_static(); + blender::draw::overlay::Engine::free_static(); + blender::draw::edit_select::Engine::free_static(); #ifdef WITH_DRAW_DEBUG - draw_engine_debug_select_type.engine_free(); + blender::draw::edit_select_debug::Engine::free_static(); #endif - draw_engine_select_type.engine_free(); } /** \} */ diff --git a/source/blender/draw/intern/draw_manager_text.cc b/source/blender/draw/intern/draw_manager_text.cc index 03de2f225eb..fcefb2130e4 100644 --- a/source/blender/draw/intern/draw_manager_text.cc +++ b/source/blender/draw/intern/draw_manager_text.cc @@ -81,6 +81,9 @@ DRWTextStore *DRW_text_cache_create() void DRW_text_cache_destroy(DRWTextStore *dt) { + if (dt == nullptr) { + return; + } BLI_memiter_destroy(dt->cache_strings); MEM_freeN(dt); } diff --git a/source/blender/draw/intern/draw_view_data.cc b/source/blender/draw/intern/draw_view_data.cc index 38bb6523484..e2e2a08bbc8 100644 --- a/source/blender/draw/intern/draw_view_data.cc +++ b/source/blender/draw/intern/draw_view_data.cc @@ -23,30 +23,9 @@ #include "draw_manager.hh" #include "draw_view_data.hh" -#include "engines/compositor/compositor_engine.h" -#include "engines/eevee_next/eevee_engine.h" -#include "engines/external/external_engine.h" -#include "engines/gpencil/gpencil_engine.h" -#include "engines/image/image_engine.h" -#include "engines/overlay/overlay_engine.h" -#include "engines/select/select_engine.hh" -#include "engines/workbench/workbench_engine.h" - using namespace blender; DRWViewData::DRWViewData() - : eevee(DRW_engine_viewport_eevee_next_type.draw_engine), - workbench(DRW_engine_viewport_workbench_type.draw_engine), - external(&draw_engine_external_type), - image(&draw_engine_image_type), - grease_pencil(&draw_engine_gpencil_type), - overlay(&draw_engine_overlay_next_type), - object_select(&draw_engine_select_next_type), - edit_select(&draw_engine_select_type), -#ifdef WITH_DRAW_DEBUG - edit_select_debug(DRW_engine_viewport_select_type.draw_engine), -#endif - compositor(&draw_engine_compositor_type) { manager = new draw::Manager(); }; @@ -57,13 +36,6 @@ DRWViewData::~DRWViewData() delete manager; }; -draw::TextureFromPool &DRW_view_data_pass_texture_get(DRWViewData *view_data, - const char *pass_name) -{ - return *view_data->viewport_compositor_passes.lookup_or_add_cb( - pass_name, [&]() { return std::make_unique(pass_name); }); -} - void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewport *viewport) { int active_view = GPU_viewport_active_view_get(viewport); @@ -103,22 +75,6 @@ void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewpo }); } -static void draw_viewport_engines_data_clear(ViewportEngineData *data, bool clear_instance_data) -{ - DrawEngineType *engine_type = data->draw_engine; - - if (clear_instance_data && data->instance_data) { - BLI_assert(engine_type->instance_free != nullptr); - engine_type->instance_free(data->instance_data); - data->instance_data = nullptr; - } - - if (data->text_draw_cache) { - DRW_text_cache_destroy(data->text_draw_cache); - data->text_draw_cache = nullptr; - } -} - void DRWViewData::clear(bool free_instance_data) { GPU_FRAMEBUFFER_FREE_SAFE(this->dfbl.default_fb); @@ -135,9 +91,15 @@ void DRWViewData::clear(bool free_instance_data) } GPU_TEXTURE_FREE_SAFE(this->dtxl.depth_in_front); - foreach_engine([&](ViewportEngineData *data, DrawEngineType * /*engine*/) { - draw_viewport_engines_data_clear(data, free_instance_data); - }); + if (free_instance_data) { + foreach_engine([&](DrawEngine::Pointer &ptr) { + if (ptr.instance) { + /* TODO Move where it belongs. */ + DRW_text_cache_destroy(ptr.instance->text_draw_cache); + ptr.free_instance(); + } + }); + } } void DRWViewData::texture_list_size_validate(const blender::int2 &size) @@ -148,28 +110,9 @@ void DRWViewData::texture_list_size_validate(const blender::int2 &size) } } -ViewportEngineData *DRW_view_data_engine_data_get_ensure(DRWViewData *view_data, - DrawEngineType *engine_type) -{ - ViewportEngineData *result = nullptr; - view_data->foreach_engine([&](ViewportEngineData *data, DrawEngineType *engine) { - if (engine_type == engine) { - result = data; - } - }); - return result; -} - -void DRW_view_data_use_engine(DRWViewData *view_data, DrawEngineType *engine_type) -{ - ViewportEngineData *engine = DRW_view_data_engine_data_get_ensure(view_data, engine_type); - engine->used = true; -} - void DRW_view_data_reset(DRWViewData *view_data) { - view_data->foreach_enabled_engine( - [&](ViewportEngineData *data, DrawEngineType * /*engine*/) { data->used = false; }); + view_data->foreach_enabled_engine([&](DrawEngine &instance) { instance.used = false; }); for (std::unique_ptr &texture : view_data->viewport_compositor_passes.values()) @@ -181,23 +124,15 @@ void DRW_view_data_reset(DRWViewData *view_data) void DRW_view_data_free_unused(DRWViewData *view_data) { - view_data->foreach_engine([&](ViewportEngineData *data, DrawEngineType * /*engine*/) { - if (data->used == false) { - draw_viewport_engines_data_clear(data, false); + view_data->foreach_engine([&](DrawEngine::Pointer &ptr) { + if (ptr.instance && ptr.instance->used == false) { + /* TODO Move where it belongs. */ + DRW_text_cache_destroy(ptr.instance->text_draw_cache); + ptr.free_instance(); } }); } -DefaultFramebufferList *DRW_view_data_default_framebuffer_list_get(DRWViewData *view_data) -{ - return &view_data->dfbl; -} - -DefaultTextureList *DRW_view_data_default_texture_list_get(DRWViewData *view_data) -{ - return &view_data->dtxl; -} - draw::Manager *DRW_manager_get() { BLI_assert(drw_get().view_data_active->manager); diff --git a/source/blender/draw/intern/draw_view_data.hh b/source/blender/draw/intern/draw_view_data.hh index 39c7f28e4c1..830f11bdecd 100644 --- a/source/blender/draw/intern/draw_view_data.hh +++ b/source/blender/draw/intern/draw_view_data.hh @@ -17,6 +17,15 @@ #include "DRW_render.hh" #include "draw_context_private.hh" +#include "engines/compositor/compositor_engine.h" +#include "engines/eevee_next/eevee_engine.h" +#include "engines/external/external_engine.h" +#include "engines/gpencil/gpencil_engine.hh" +#include "engines/image/image_engine.h" +#include "engines/overlay/overlay_engine.h" +#include "engines/select/select_engine.hh" +#include "engines/workbench/workbench_engine.h" + #define GPU_INFO_SIZE 512 /* IMA_MAX_RENDER_TEXT_SIZE */ namespace blender::draw { @@ -24,40 +33,12 @@ class TextureFromPool; class Manager; } // namespace blender::draw -struct DrawEngineType; struct DRWTextStore; struct GPUFrameBuffer; struct GPUTexture; struct GPUViewport; struct ListBase; -struct ViewportEngineData { - /* Not owning pointer to the draw engine. */ - DrawEngineType *draw_engine; - - /** - * \brief Memory block that can be freely used by the draw engine. - * When used the draw engine must implement #DrawEngineType.instance_free callback. - */ - void *instance_data = nullptr; - - char info[GPU_INFO_SIZE] = {'\0'}; - - /* we may want to put this elsewhere */ - DRWTextStore *text_draw_cache = nullptr; - - bool used = false; - - ViewportEngineData(DrawEngineType *engine_type) : draw_engine(engine_type) {} -}; - -struct ViewportEngineData_Info { - int fbl_len; - int txl_len; - int psl_len; - int stl_len; -}; - /* Buffer and textures used by the viewport by default */ struct DefaultFramebufferList { GPUFrameBuffer *default_fb; @@ -86,19 +67,18 @@ struct DRWViewData { blender::int2 texture_list_size = {0, 0}; /* Engines running for this viewport. nullptr if not enabled. */ - /* TODO(fclem): Directly use each engine class. */ - ViewportEngineData eevee; - ViewportEngineData workbench; - ViewportEngineData external; - ViewportEngineData image; - ViewportEngineData grease_pencil; - ViewportEngineData overlay; - ViewportEngineData object_select; - ViewportEngineData edit_select; + blender::eevee::Engine eevee; + blender::workbench::Engine workbench; + blender::draw::external::Engine external; + blender::image_engine::Engine image; + blender::draw::gpencil::Engine grease_pencil; + blender::draw::overlay::Engine overlay; + blender::draw::select::Engine object_select; + blender::draw::edit_select::Engine edit_select; #ifdef WITH_DRAW_DEBUG - ViewportEngineData edit_select_debug; + blender::draw::edit_select_debug::Engine edit_select_debug; #endif - ViewportEngineData compositor; + blender::draw::compositor_engine::Engine compositor; /* Stores passes needed by the viewport compositor. Engines are expected to populate those in * every redraw using calls to the DRW_viewport_pass_texture_get function. The compositor can @@ -121,32 +101,32 @@ struct DRWViewData { /* IMPORTANT: Order here defines the draw order. */ /* Render engines. Output to the render result framebuffer. Mutually exclusive. */ - callback(&eevee, eevee.draw_engine); - callback(&workbench, workbench.draw_engine); - callback(&external, external.draw_engine); - callback(&image, image.draw_engine); + callback(eevee); + callback(workbench); + callback(external); + callback(image); #ifdef WITH_DRAW_DEBUG - callback(&edit_select_debug, edit_select_debug.draw_engine); + callback(edit_select_debug); #endif /* Grease pencil. Merge its output to the render result framebuffer. */ - callback(&grease_pencil, grease_pencil.draw_engine); + callback(grease_pencil); /* GPU compositor. Processes render result and output to the render result framebuffer. */ - callback(&compositor, compositor.draw_engine); + callback(compositor); /* Overlays. Draw on a separate overlay framebuffer. Can read render result. */ - callback(&overlay, overlay.draw_engine); + callback(overlay); /* Selection. Are always enabled alone and have no interaction with other engines. */ - callback(&object_select, object_select.draw_engine); - callback(&edit_select, edit_select.draw_engine); + callback(object_select); + callback(edit_select); } template void foreach_enabled_engine(CallbackT callback) { - foreach_engine([&](ViewportEngineData *data, DrawEngineType *engine) { - if (!data->used) { + foreach_engine([&](DrawEngine::Pointer &ptr) { + if (ptr.instance == nullptr || ptr.instance->used == false) { return; } - callback(data, engine); + callback(*ptr.instance); }); } @@ -154,18 +134,6 @@ struct DRWViewData { void clear(bool free_instance_data); }; -/* Returns a TextureFromPool stored in the given view data for the pass identified by the given - * pass name. Engines should call this function for each of the passes needed by the viewport - * compositor in every redraw, then it should allocate the texture and write the pass data to it. - * The texture should cover the entire viewport. */ -blender::draw::TextureFromPool &DRW_view_data_pass_texture_get(DRWViewData *view_data, - const char *pass_name); - void DRW_view_data_default_lists_from_viewport(DRWViewData *view_data, GPUViewport *viewport); -ViewportEngineData *DRW_view_data_engine_data_get_ensure(DRWViewData *view_data, - DrawEngineType *engine_type); -void DRW_view_data_use_engine(DRWViewData *view_data, DrawEngineType *engine_type); void DRW_view_data_reset(DRWViewData *view_data); void DRW_view_data_free_unused(DRWViewData *view_data); -DefaultFramebufferList *DRW_view_data_default_framebuffer_list_get(DRWViewData *view_data); -DefaultTextureList *DRW_view_data_default_texture_list_get(DRWViewData *view_data);