From 2538c3b1a2fed320fdf933b12612aab67f58dc9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 11 Oct 2022 10:06:38 +0200 Subject: [PATCH 01/22] Cleanup: DRW: Improve state_stencil documentation --- source/blender/draw/intern/draw_pass.hh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh index ee2180712d1..3fae6e09932 100644 --- a/source/blender/draw/intern/draw_pass.hh +++ b/source/blender/draw/intern/draw_pass.hh @@ -174,9 +174,15 @@ class PassBase { /** * Reminders: - * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) + * - `compare_mask & reference` is what is tested against `compare_mask & stencil_value` * stencil_value being the value stored in the stencil buffer. - * - (write-mask & reference) is what gets written if the test condition is fulfilled. + * - `write-mask & reference` is what gets written if the test condition is fulfilled. + * + * This will modify the stencil state until another call to this function. + * If not specified before any draw-call, these states will be undefined. + * + * For more information see: + * https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkStencilOpState.html */ void state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask); -- 2.30.2 From 279774ad0b8fb20a9c5ea4cfabccd915e54472fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 11 Oct 2022 17:22:17 +0200 Subject: [PATCH 02/22] Overlay-Next: First commit --- source/blender/draw/CMakeLists.txt | 2 + .../draw/engines/overlay/overlay_engine.cc | 93 +++++++- .../draw/engines/overlay/overlay_engine.h | 1 + .../draw/engines/overlay/overlay_grid.cc | 1 + .../draw/engines/overlay/overlay_grid.hh | 198 ++++++++++++++++++ .../draw/engines/overlay/overlay_instance.cc | 41 ++++ .../draw/engines/overlay/overlay_instance.hh | 70 +++++++ .../draw/engines/overlay/overlay_private.hh | 10 +- .../engines/overlay/overlay_shader_shared.h | 107 ++++++++++ 9 files changed, 513 insertions(+), 10 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_grid.hh create mode 100644 source/blender/draw/engines/overlay/overlay_instance.cc create mode 100644 source/blender/draw/engines/overlay/overlay_instance.hh diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index d82ae4cd32c..9184cdbd810 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -192,6 +192,7 @@ set(SRC engines/overlay/overlay_gpencil.cc engines/overlay/overlay_grid.cc engines/overlay/overlay_image.cc + engines/overlay/overlay_instance.cc engines/overlay/overlay_lattice.cc engines/overlay/overlay_metaball.cc engines/overlay/overlay_mode_transfer.cc @@ -291,6 +292,7 @@ set(SRC engines/select/select_engine.h engines/select/select_private.h engines/overlay/overlay_engine.h + engines/overlay/overlay_instance.hh engines/overlay/overlay_private.hh ) diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc index f1fdfe98fdc..184c1f3d45d 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -20,8 +20,13 @@ #include "BKE_object.h" #include "BKE_paint.h" +#include "GPU_capabilities.h" + #include "DNA_space_types.h" +#include "draw_manager.hh" +#include "overlay_instance.hh" + #include "overlay_engine.h" #include "overlay_private.hh" @@ -46,8 +51,7 @@ static void OVERLAY_engine_init(void *vedata) /* Allocate instance. */ if (data->instance == nullptr) { - data->instance = static_cast( - MEM_callocN(sizeof(*data->instance), __func__)); + data->instance = new blender::draw::overlay::Instance(); } OVERLAY_PrivateData *pd = stl->pd; @@ -731,9 +735,70 @@ static void OVERLAY_engine_free() static void OVERLAY_instance_free(void *instance_) { - OVERLAY_Instance *instance = (OVERLAY_Instance *)instance_; - DRW_UBO_FREE_SAFE(instance->grid_ubo); - MEM_freeN(instance); + blender::draw::overlay::Instance *instance = (blender::draw::overlay::Instance *)instance_; + if (instance != nullptr) { + delete instance; + } +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Engine Instance + * \{ */ + +using namespace blender::draw; + +static void OVERLAY_next_engine_init(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + + OVERLAY_Data *ved = reinterpret_cast(vedata); + + if (ved->instance == nullptr) { + ved->instance = new overlay::Instance(); + } + + ved->instance->init(); +} + +static void OVERLAY_next_cache_init(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + reinterpret_cast(vedata)->instance->begin_sync(); +} + +static void OVERLAY_next_cache_populate(void *vedata, Object *object) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + ObjectRef ref; + ref.object = object; + ref.dupli_object = DRW_object_get_dupli(object); + ref.dupli_parent = DRW_object_get_dupli_parent(object); + + reinterpret_cast(vedata)->instance->object_sync(ref); +} + +static void OVERLAY_next_cache_finish(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + reinterpret_cast(vedata)->instance->end_sync(); +} + +static void OVERLAY_next_draw_scene(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + + reinterpret_cast(vedata)->instance->draw(*DRW_manager_get()); } /** \} */ @@ -762,6 +827,24 @@ DrawEngineType draw_engine_overlay_type = { nullptr, }; +DrawEngineType draw_engine_overlay_next_type = { + nullptr, + nullptr, + N_("Overlay"), + &overlay_data_size, + &OVERLAY_next_engine_init, + nullptr, + &OVERLAY_instance_free, + &OVERLAY_next_cache_init, + &OVERLAY_next_cache_populate, + &OVERLAY_next_cache_finish, + &OVERLAY_next_draw_scene, + nullptr, + nullptr, + nullptr, + nullptr, +}; + /** \} */ #undef SELECT_ENGINE diff --git a/source/blender/draw/engines/overlay/overlay_engine.h b/source/blender/draw/engines/overlay/overlay_engine.h index a33ea17dc1e..caf380c87af 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.h +++ b/source/blender/draw/engines/overlay/overlay_engine.h @@ -12,6 +12,7 @@ extern "C" { #endif extern DrawEngineType draw_engine_overlay_type; +extern DrawEngineType draw_engine_overlay_next_type; #ifdef __cplusplus } diff --git a/source/blender/draw/engines/overlay/overlay_grid.cc b/source/blender/draw/engines/overlay/overlay_grid.cc index e31c40fff41..860f26fc18f 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.cc +++ b/source/blender/draw/engines/overlay/overlay_grid.cc @@ -17,6 +17,7 @@ #include "UI_resources.h" +#include "overlay_instance.hh" #include "overlay_private.hh" BLI_STATIC_ASSERT(SI_GRID_STEPS_LEN == OVERLAY_GRID_STEPS_LEN, "") diff --git a/source/blender/draw/engines/overlay/overlay_grid.hh b/source/blender/draw/engines/overlay/overlay_grid.hh new file mode 100644 index 00000000000..76368f3c1d3 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_grid.hh @@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "DNA_space_types.h" +#include "ED_view3d.h" + +#include "draw_cache.h" +#include "draw_pass.hh" +#include "overlay_private.hh" +#include "overlay_shader_shared.h" + +namespace blender::draw::overlay { + +class Grid { + private: + UniformBuffer data_; + + bool enabled = false; + + PassSimple grid_ps_ = {"grid_ps_"}; + + float3 grid_axes = float3(0.0f); + float3 zplane_axes = float3(0.0f); + OVERLAY_GridBits grid_flag_; + OVERLAY_GridBits zneg_flag_; + OVERLAY_GridBits zpos_flag_; + + public: + void update_ubo() + { + float grid_steps[SI_GRID_STEPS_LEN] = { + 0.001f, 0.01f, 0.1f, 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f}; + float grid_steps_y[SI_GRID_STEPS_LEN] = {0.0f}; /* When zero, use value from grid_steps. */ + data_.line_size = max_ff(0.0f, U.pixelsize - 1.0f) * 0.5f; + /* Default, nothing is drawn. */ + grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0); + + /* SPACE_VIEW3D */ + Scene *scene = DRW_context_state_get()->scene; + View3D *v3d = DRW_context_state_get()->v3d; + RegionView3D *rv3d = DRW_context_state_get()->rv3d; + + const bool show_axis_x = true; //(pd->v3d_gridflag & V3D_SHOW_X) != 0; + const bool show_axis_y = true; //(pd->v3d_gridflag & V3D_SHOW_Y) != 0; + const bool show_axis_z = true; //(pd->v3d_gridflag & V3D_SHOW_Z) != 0; + const bool show_floor = true; //(pd->v3d_gridflag & V3D_SHOW_FLOOR) != 0; + const bool show_ortho_grid = true; //(pd->v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0; + + // if (pd->hide_overlays || !(pd->v3d_gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z | + // V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID))) { + // return; + // } + + float viewinv[4][4], wininv[4][4]; + float viewmat[4][4], winmat[4][4]; + DRW_view_winmat_get(nullptr, winmat, false); + DRW_view_winmat_get(nullptr, wininv, true); + DRW_view_viewmat_get(nullptr, viewmat, false); + DRW_view_viewmat_get(nullptr, viewinv, true); + + /* If perspective view or non-axis aligned view. */ + if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) { + if (show_axis_x) { + grid_flag_ |= PLANE_XY | SHOW_AXIS_X; + } + if (show_axis_y) { + grid_flag_ |= PLANE_XY | SHOW_AXIS_Y; + } + if (show_floor) { + grid_flag_ |= PLANE_XY | SHOW_GRID; + } + } + else { + if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT)) { + grid_flag_ = PLANE_YZ | SHOW_AXIS_Y | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK; + } + else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) { + grid_flag_ = PLANE_XY | SHOW_AXIS_X | SHOW_AXIS_Y | SHOW_GRID | GRID_BACK; + } + else if (show_ortho_grid && ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) { + grid_flag_ = PLANE_XZ | SHOW_AXIS_X | SHOW_AXIS_Z | SHOW_GRID | GRID_BACK; + } + } + + grid_axes[0] = float((grid_flag_ & (PLANE_XZ | PLANE_XY)) != 0); + grid_axes[1] = float((grid_flag_ & (PLANE_YZ | PLANE_XY)) != 0); + grid_axes[2] = float((grid_flag_ & (PLANE_YZ | PLANE_XZ)) != 0); + + /* Z axis if needed */ + if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) { + zpos_flag_ = SHOW_AXIS_Z; + + float zvec[3], campos[3]; + negate_v3_v3(zvec, viewinv[2]); + copy_v3_v3(campos, viewinv[3]); + + /* z axis : chose the most facing plane */ + if (fabsf(zvec[0]) < fabsf(zvec[1])) { + zpos_flag_ |= PLANE_XZ; + } + else { + zpos_flag_ |= PLANE_YZ; + } + + zneg_flag_ = zpos_flag_; + + /* Perspective: If camera is below floor plane, we switch clipping. + * Orthographic: If eye vector is looking up, we switch clipping. */ + if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) || + ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) { + zpos_flag_ |= CLIP_ZPOS; + zneg_flag_ |= CLIP_ZNEG; + } + else { + zpos_flag_ |= CLIP_ZNEG; + zneg_flag_ |= CLIP_ZPOS; + } + + zplane_axes[0] = float((zpos_flag_ & (PLANE_XZ | PLANE_XY)) != 0); + zplane_axes[1] = float((zpos_flag_ & (PLANE_YZ | PLANE_XY)) != 0); + zplane_axes[2] = float((zpos_flag_ & (PLANE_YZ | PLANE_XZ)) != 0); + } + else { + zneg_flag_ = zpos_flag_ = CLIP_ZNEG | CLIP_ZPOS; + } + + float dist; + // if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) { + // Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); + // dist = ((Camera *)(camera_object->data))->clip_end; + // grid_flag_ |= GRID_CAMERA; + // zneg_flag_ |= GRID_CAMERA; + // zpos_flag_ |= GRID_CAMERA; + // } + // else { + dist = v3d->clip_end; + // } + + if (winmat[3][3] == 0.0f) { + copy_v3_fl(data_.size, dist); + } + else { + float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1])); + copy_v3_fl(data_.size, viewdist * dist); + } + + data_.distance = dist / 2.0f; + + ED_view3d_grid_steps(scene, v3d, rv3d, grid_steps); + + if ((v3d->flag & (V3D_XR_SESSION_SURFACE | V3D_XR_SESSION_MIRROR)) != 0) { + /* The calculations for the grid parameters assume that the view matrix has no scale + * component, which may not be correct if the user is "shrunk" or "enlarged" by zooming in or + * out. Therefore, we need to compensate the values here. */ + /* Assumption is uniform scaling (all column vectors are of same length). */ + float viewinvscale = len_v3(viewinv[0]); + data_.distance *= viewinvscale; + } + + /* Convert to UBO alignment. */ + for (int i = 0; i < SI_GRID_STEPS_LEN; i++) { + data_.steps[i][0] = grid_steps[i]; + data_.steps[i][1] = (grid_steps_y[i] != 0.0f) ? grid_steps_y[i] : grid_steps[i]; + } + + data_.push_update(); + } + + void begin_sync() + { + update_ubo(); + + grid_ps_.init(); + grid_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); + + grid_ps_.shader_set(OVERLAY_shader_grid()); + grid_ps_.bind_ubo("grid_buf", &data_); + grid_ps_.bind_ubo("globalsBlock", &G_draw.block_ubo); + grid_ps_.bind_texture("depth_tx", &DRW_viewport_texture_list_get()->depth); + + grid_ps_.push_constant("grid_flag", grid_flag_); + grid_ps_.push_constant("plane_axes", grid_axes); + grid_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 0.0f)); + grid_ps_.draw(DRW_cache_grid_get()); + } + + void draw(Manager &manager, View &view) + { + manager.submit(grid_ps_, view); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc new file mode 100644 index 00000000000..1d27c74e19a --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#include "overlay_instance.hh" + +namespace blender::draw::overlay { + +void Instance::init() +{ + GPUTexture *viewport_depth_tx = DRW_viewport_texture_list_get()->depth; + GPUTexture *viewport_color_tx = DRW_viewport_texture_list_get()->color_overlay; + overlay_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(viewport_color_tx)); +} + +void Instance::begin_sync() +{ + grid.begin_sync(); +} + +void Instance::object_sync(ObjectRef &ob_ref) +{ + UNUSED_VARS(ob_ref); +} + +void Instance::end_sync() +{ +} + +void Instance::draw(Manager &manager) +{ + const DRWView *view_old = DRW_view_default_get(); + View view("OverlayView", view_old); + + GPU_framebuffer_bind(overlay_fb); + grid.draw(manager, view); +} + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh new file mode 100644 index 00000000000..85a73c71900 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "draw_manager.hh" + +#include "overlay_grid.hh" + +namespace blender::draw::overlay { + +class ShaderCache { + Map> cache; + + int clipping_enabled = 0; +}; + +class SceneResources { + ShaderCache shaders; + + // UniformBuffer theme_colors; + // Texture color_ramp = {"color_ramp"}; + + void weight_ramp_init() + { + /* Weight Painting color ramp texture */ + // bool user_weight_ramp = (U.flag & USER_CUSTOM_RANGE) != 0; + + // if (weight_ramp_custom != user_weight_ramp || + // (user_weight_ramp && memcmp(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)) != 0)) + // { + // DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp); + // } + + // if (G_draw.weight_ramp == NULL) { + // weight_ramp_custom = user_weight_ramp; + // memcpy(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)); + + // G_draw.weight_ramp = DRW_create_weight_colorramp_texture(); + // } + } +}; + +class Instance { + public: + ShaderCache shaders; + + /* WORKAROUND: Legacy. Move to grid pass. */ + GPUUniformBuf *grid_ubo = nullptr; + + Framebuffer overlay_fb = {"overlay_fb"}; + + Grid grid; + + ~Instance() + { + DRW_UBO_FREE_SAFE(grid_ubo); + } + + void init(); + void begin_sync(); + void object_sync(ObjectRef &ob_ref); + void end_sync(); + void draw(Manager &manager); +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index b1118e084a6..9b433928321 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -27,6 +27,10 @@ extern "C" { /* Forward declarations */ struct ImBuf; +namespace blender::draw::overlay { +class Instance; +} + typedef struct OVERLAY_FramebufferList { struct GPUFrameBuffer *overlay_default_fb; struct GPUFrameBuffer *overlay_line_fb; @@ -428,10 +432,6 @@ typedef struct OVERLAY_StorageList { struct OVERLAY_PrivateData *pd; } OVERLAY_StorageList; -typedef struct OVERLAY_Instance { - GPUUniformBuf *grid_ubo; -} OVERLAY_Instance; - typedef struct OVERLAY_Data { void *engine_type; OVERLAY_FramebufferList *fbl; @@ -439,7 +439,7 @@ typedef struct OVERLAY_Data { OVERLAY_PassList *psl; OVERLAY_StorageList *stl; - OVERLAY_Instance *instance; + blender::draw::overlay::Instance *instance; } OVERLAY_Data; typedef struct OVERLAY_DupliData { diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h index 739e5be6c2f..bb937d2c45a 100644 --- a/source/blender/draw/engines/overlay/overlay_shader_shared.h +++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #ifndef GPU_SHADER +# pragma once + # include "GPU_shader_shared_utils.h" # include "DNA_action_types.h" @@ -12,6 +14,7 @@ extern "C" { typedef enum OVERLAY_GridBits OVERLAY_GridBits; # endif typedef struct OVERLAY_GridData OVERLAY_GridData; +typedef struct ThemeColorData ThemeColorData; #endif /* TODO(fclem): Should eventually become OVERLAY_BackgroundType. @@ -84,6 +87,110 @@ BLI_STATIC_ASSERT(MOTIONPATH_VERT_SEL == (1 << 0), "Ensure value is sync"); BLI_STATIC_ASSERT(MOTIONPATH_VERT_KEY == (1 << 1), "Ensure value is sync"); #endif +struct ThemeColorData { + float4 color_wire; + float4 color_wire_edit; + float4 color_active; + float4 color_select; + float4 color_library_select; + float4 color_library; + float4 color_transform; + float4 color_light; + float4 color_speaker; + float4 color_camera; + float4 color_camera_path; + float4 color_empty; + float4 color_vertex; + float4 color_vertex_select; + float4 color_vertex_unreferenced; + float4 color_vertex_missing_data; + float4 color_edit_mesh_active; + float4 color_edge_select; + float4 color_edge_seam; + float4 color_edge_sharp; + float4 color_edge_crease; + float4 color_edge_bweight; + float4 color_edge_face_select; + float4 color_edge_freestyle; + float4 color_face; + float4 color_face_select; + float4 color_face_freestyle; + float4 color_gpencil_vertex; + float4 color_gpencil_vertex_select; + float4 color_normal; + float4 color_vnormal; + float4 color_lnormal; + float4 color_facedot; + float4 color_skinroot; + + float4 color_deselect; + float4 color_outline; + float4 color_light_no_alpha; + + float4 color_background; + float4 color_background_gradient; + float4 color_checker_primary; + float4 color_checker_secondary; + float4 color_clipping_border; + float4 color_edit_mesh_middle; + + float4 color_handle_free; + float4 color_handle_auto; + float4 color_handle_vect; + float4 color_handle_align; + float4 color_handle_autoclamp; + float4 color_handle_sel_free; + float4 color_handle_sel_auto; + float4 color_handle_sel_vect; + float4 color_handle_sel_align; + float4 color_handle_sel_autoclamp; + float4 color_nurb_uline; + float4 color_nurb_vline; + float4 color_nurb_sel_uline; + float4 color_nurb_sel_vline; + float4 color_active_spline; + + float4 color_bone_pose; + float4 color_bone_pose_active; + float4 color_bone_pose_active_unsel; + float4 color_bone_pose_constraint; + float4 color_bone_pose_ik; + float4 color_bone_pose_spline_ik; + float4 color_bone_pose_target; + float4 color_bone_solid; + float4 color_bone_locked; + float4 color_bone_active; + float4 color_bone_active_unsel; + float4 color_bone_select; + float4 color_bone_ik_line; + float4 color_bone_ik_line_no_target; + float4 color_bone_ik_line_spline; + + float4 color_text; + float4 color_text_hi; + + float4 color_bundle_solid; + + float4 color_mball_radius; + float4 color_mball_radius_select; + float4 color_mball_stiffness; + float4 color_mball_stiffness_select; + + float4 color_current_frame; + + float4 color_grid; + float4 color_grid_emphasis; + float4 color_grid_axis_x; + float4 color_grid_axis_y; + float4 color_grid_axis_z; + + float4 color_face_back; + float4 color_face_front; + + float4 color_uv_shadow; +}; +BLI_STATIC_ASSERT_ALIGN(ThemeColorData, 16) + #ifndef GPU_SHADER # ifdef __cplusplus } -- 2.30.2 From 82e298227faed952115f66e673d7ddcf2f02c244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 17:32:20 +0200 Subject: [PATCH 03/22] Cleanup: EEVEE-Next: Add precision to comment --- source/blender/draw/engines/eevee_next/eevee_shader_shared.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index fd06cdc7f23..f6a96aaaff2 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -560,7 +560,7 @@ struct LightCullingData { uint local_lights_len; /** Items that are **NOT** processed by the 2.5D culling (i.e: Sun Lights). */ uint sun_lights_len; - /** Number of items that passes the first culling test. */ + /** Number of items that passes the first culling test. (local lights only) */ uint visible_count; /** Extent of one square tile in pixels. */ float tile_size; -- 2.30.2 From 482fee9bbe1e3bdd7e87cfffb8ed08d0dc071c85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 17:33:33 +0200 Subject: [PATCH 04/22] DRW: View: Expose matrices through interface --- source/blender/draw/intern/draw_view.hh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/source/blender/draw/intern/draw_view.hh b/source/blender/draw/intern/draw_view.hh index 4fc74e3e890..94fb62508bb 100644 --- a/source/blender/draw/intern/draw_view.hh +++ b/source/blender/draw/intern/draw_view.hh @@ -79,6 +79,26 @@ class View { return -(data_.winmat[3][2] + 1.0f) / data_.winmat[2][2]; } + const float4x4 &viewmat() const + { + return data_.viewmat; + } + + const float4x4 &viewinv() const + { + return data_.viewinv; + } + + const float4x4 &winmat() const + { + return data_.winmat; + } + + const float4x4 &wininv() const + { + return data_.wininv; + } + private: /** Called from draw manager. */ void bind(); -- 2.30.2 From cd93f790c7a02f57d57a851e5aff82108b3f12a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 17:34:28 +0200 Subject: [PATCH 05/22] Overlay: Add experimental option to enable overlay-next --- release/scripts/startup/bl_ui/space_userpref.py | 1 + source/blender/draw/intern/draw_manager.c | 10 +++++++--- source/blender/makesdna/DNA_userdef_types.h | 3 ++- source/blender/makesrna/intern/rna_userdef.c | 5 +++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index a9736feb057..cbe6579a449 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -2316,6 +2316,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel): ({"property": "use_sculpt_texture_paint"}, "T96225"), ({"property": "use_full_frame_compositor"}, "T88150"), ({"property": "enable_eevee_next"}, "T93220"), + ({"property": "enable_overlay_next"}, ""), ({"property": "use_draw_manager_acquire_lock"}, "T98016"), ), ) diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index da77845feb4..d722d8ccc47 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1199,7 +1199,8 @@ static void drw_engines_enable_from_engine(const RenderEngineType *engine_type, static void drw_engines_enable_overlays(void) { - use_drw_engine(&draw_engine_overlay_type); + use_drw_engine((U.experimental.enable_overlay_next) ? &draw_engine_overlay_next_type : + &draw_engine_overlay_type); } /** * Use for select and depth-drawing. @@ -1218,7 +1219,8 @@ static void drw_engine_enable_image_editor(void) use_drw_engine(&draw_engine_image_type); } - use_drw_engine(&draw_engine_overlay_type); + use_drw_engine((U.experimental.enable_overlay_next) ? &draw_engine_overlay_next_type : + &draw_engine_overlay_type); } static void drw_engines_enable_editors(void) @@ -1236,7 +1238,8 @@ static void drw_engines_enable_editors(void) SpaceNode *snode = (SpaceNode *)space_data; if ((snode->flag & SNODE_BACKDRAW) != 0) { use_drw_engine(&draw_engine_image_type); - use_drw_engine(&draw_engine_overlay_type); + use_drw_engine((U.experimental.enable_overlay_next) ? &draw_engine_overlay_next_type : + &draw_engine_overlay_type); } } } @@ -3012,6 +3015,7 @@ void DRW_engines_register(void) DRW_engine_register(&draw_engine_gpencil_type); DRW_engine_register(&draw_engine_overlay_type); + DRW_engine_register(&draw_engine_overlay_next_type); DRW_engine_register(&draw_engine_select_type); DRW_engine_register(&draw_engine_basic_type); DRW_engine_register(&draw_engine_compositor_type); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 9d8b75450ca..885e6d48724 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -653,7 +653,8 @@ typedef struct UserDef_Experimental { char use_sculpt_texture_paint; char use_draw_manager_acquire_lock; char use_realtime_compositor; - char _pad[7]; + char enable_overlay_next; + char _pad[6]; /** `makesdna` does not allow empty structs. */ } UserDef_Experimental; diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 5d50a671f4a..f2715bb3555 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -6388,6 +6388,11 @@ static void rna_def_userdef_experimental(BlenderRNA *brna) "Enable viewport debugging options for developers in the overlays " "pop-over"); RNA_def_property_update(prop, 0, "rna_userdef_ui_update"); + + prop = RNA_def_property(srna, "enable_overlay_next", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "enable_overlay_next", 1); + RNA_def_property_ui_text( + prop, "Overlay Next", "Enable the new Overlay codebase, requires restart"); } static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop) -- 2.30.2 From f0514484f5349112a7c534806833724629242716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 17:35:29 +0200 Subject: [PATCH 06/22] DRW: Wrappers: Add TextureRef to wrap around GPUTexture pointers This adds the possibility to use the C++ API for other GPUTexture. --- source/blender/draw/intern/DRW_gpu_wrapper.hh | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/source/blender/draw/intern/DRW_gpu_wrapper.hh b/source/blender/draw/intern/DRW_gpu_wrapper.hh index d53c5fbeaa5..3be50d471e2 100644 --- a/source/blender/draw/intern/DRW_gpu_wrapper.hh +++ b/source/blender/draw/intern/DRW_gpu_wrapper.hh @@ -924,6 +924,35 @@ class TextureFromPool : public Texture, NonMovable { GPUTexture *stencil_view() = delete; }; +class TextureRef : public Texture { + public: + TextureRef() = default; + + ~TextureRef() + { + this->tx_ = nullptr; + } + + void wrap(GPUTexture *tex) + { + this->tx_ = tex; + } + + /** Remove methods that are forbidden with this type of textures. */ + bool ensure_1d(int, int, eGPUTextureFormat, float *) = delete; + bool ensure_1d_array(int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_2d(int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_2d_array(int, int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_3d(int, int, int, int, eGPUTextureFormat, float *) = delete; + bool ensure_cube(int, int, eGPUTextureFormat, float *) = delete; + bool ensure_cube_array(int, int, int, eGPUTextureFormat, float *) = delete; + void filter_mode(bool) = delete; + void free() = delete; + GPUTexture *mip_view(int) = delete; + GPUTexture *layer_view(int) = delete; + GPUTexture *stencil_view() = delete; +}; + /** * Dummy type to bind texture as image. * It is just a GPUTexture in disguise. -- 2.30.2 From 64d9660fc435e8b56f01994743cd76a0b13d982e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 17:35:52 +0200 Subject: [PATCH 07/22] Overlay-Next: Make Grid parameters work --- .../draw/engines/overlay/overlay_grid.hh | 149 ++++++++++-------- .../draw/engines/overlay/overlay_instance.cc | 72 ++++++++- .../draw/engines/overlay/overlay_instance.hh | 4 +- .../draw/engines/overlay/overlay_private.hh | 45 +++++- 4 files changed, 191 insertions(+), 79 deletions(-) diff --git a/source/blender/draw/engines/overlay/overlay_grid.hh b/source/blender/draw/engines/overlay/overlay_grid.hh index 76368f3c1d3..7de857d8888 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.hh +++ b/source/blender/draw/engines/overlay/overlay_grid.hh @@ -6,6 +6,8 @@ #pragma once +#include "DEG_depsgraph_query.h" +#include "DNA_camera_types.h" #include "DNA_space_types.h" #include "ED_view3d.h" @@ -17,21 +19,22 @@ namespace blender::draw::overlay { class Grid { + public: private: UniformBuffer data_; - bool enabled = false; - PassSimple grid_ps_ = {"grid_ps_"}; - float3 grid_axes = float3(0.0f); - float3 zplane_axes = float3(0.0f); - OVERLAY_GridBits grid_flag_; - OVERLAY_GridBits zneg_flag_; - OVERLAY_GridBits zpos_flag_; + float3 grid_axes_ = float3(0.0f); + float3 zplane_axes_ = float3(0.0f); + OVERLAY_GridBits grid_flag_ = OVERLAY_GridBits(0); + OVERLAY_GridBits zneg_flag_ = OVERLAY_GridBits(0); + OVERLAY_GridBits zpos_flag_ = OVERLAY_GridBits(0); + + bool enabled_ = false; public: - void update_ubo() + void update_ubo(const State &state, const View &view) { float grid_steps[SI_GRID_STEPS_LEN] = { 0.001f, 0.01f, 0.1f, 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f}; @@ -40,31 +43,25 @@ class Grid { /* Default, nothing is drawn. */ grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0); - /* SPACE_VIEW3D */ - Scene *scene = DRW_context_state_get()->scene; - View3D *v3d = DRW_context_state_get()->v3d; - RegionView3D *rv3d = DRW_context_state_get()->rv3d; + View3D *v3d = state.v3d; + RegionView3D *rv3d = state.rv3d; - const bool show_axis_x = true; //(pd->v3d_gridflag & V3D_SHOW_X) != 0; - const bool show_axis_y = true; //(pd->v3d_gridflag & V3D_SHOW_Y) != 0; - const bool show_axis_z = true; //(pd->v3d_gridflag & V3D_SHOW_Z) != 0; - const bool show_floor = true; //(pd->v3d_gridflag & V3D_SHOW_FLOOR) != 0; - const bool show_ortho_grid = true; //(pd->v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0; + const bool show_axis_x = (state.v3d_gridflag & V3D_SHOW_X) != 0; + const bool show_axis_y = (state.v3d_gridflag & V3D_SHOW_Y) != 0; + const bool show_axis_z = (state.v3d_gridflag & V3D_SHOW_Z) != 0; + const bool show_floor = (state.v3d_gridflag & V3D_SHOW_FLOOR) != 0; + const bool show_ortho_grid = (state.v3d_gridflag & V3D_SHOW_ORTHO_GRID) != 0; + const bool show_any = show_axis_x || show_axis_y || show_axis_z || show_floor || + show_ortho_grid; - // if (pd->hide_overlays || !(pd->v3d_gridflag & (V3D_SHOW_X | V3D_SHOW_Y | V3D_SHOW_Z | - // V3D_SHOW_FLOOR | V3D_SHOW_ORTHO_GRID))) { - // return; - // } + enabled_ = !state.hide_overlays && show_any; - float viewinv[4][4], wininv[4][4]; - float viewmat[4][4], winmat[4][4]; - DRW_view_winmat_get(nullptr, winmat, false); - DRW_view_winmat_get(nullptr, wininv, true); - DRW_view_viewmat_get(nullptr, viewmat, false); - DRW_view_viewmat_get(nullptr, viewinv, true); + if (!enabled_) { + return; + } /* If perspective view or non-axis aligned view. */ - if (winmat[3][3] == 0.0f || rv3d->view == RV3D_VIEW_USER) { + if (view.is_persp() || rv3d->view == RV3D_VIEW_USER) { if (show_axis_x) { grid_flag_ |= PLANE_XY | SHOW_AXIS_X; } @@ -87,17 +84,16 @@ class Grid { } } - grid_axes[0] = float((grid_flag_ & (PLANE_XZ | PLANE_XY)) != 0); - grid_axes[1] = float((grid_flag_ & (PLANE_YZ | PLANE_XY)) != 0); - grid_axes[2] = float((grid_flag_ & (PLANE_YZ | PLANE_XZ)) != 0); + grid_axes_[0] = float((grid_flag_ & (PLANE_XZ | PLANE_XY)) != 0); + grid_axes_[1] = float((grid_flag_ & (PLANE_YZ | PLANE_XY)) != 0); + grid_axes_[2] = float((grid_flag_ & (PLANE_YZ | PLANE_XZ)) != 0); /* Z axis if needed */ if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) { zpos_flag_ = SHOW_AXIS_Z; - float zvec[3], campos[3]; - negate_v3_v3(zvec, viewinv[2]); - copy_v3_v3(campos, viewinv[3]); + float3 zvec = -float3(view.viewinv()[2]); + float3 campos = float3(view.viewinv()[3]); /* z axis : chose the most facing plane */ if (fabsf(zvec[0]) < fabsf(zvec[1])) { @@ -106,13 +102,11 @@ class Grid { else { zpos_flag_ |= PLANE_YZ; } - zneg_flag_ = zpos_flag_; /* Perspective: If camera is below floor plane, we switch clipping. * Orthographic: If eye vector is looking up, we switch clipping. */ - if (((winmat[3][3] == 0.0f) && (campos[2] > 0.0f)) || - ((winmat[3][3] != 0.0f) && (zvec[2] < 0.0f))) { + if ((view.is_persp() && (campos[2] > 0.0f)) || (!view.is_persp() && (zvec[2] < 0.0f))) { zpos_flag_ |= CLIP_ZPOS; zneg_flag_ |= CLIP_ZNEG; } @@ -121,44 +115,44 @@ class Grid { zneg_flag_ |= CLIP_ZPOS; } - zplane_axes[0] = float((zpos_flag_ & (PLANE_XZ | PLANE_XY)) != 0); - zplane_axes[1] = float((zpos_flag_ & (PLANE_YZ | PLANE_XY)) != 0); - zplane_axes[2] = float((zpos_flag_ & (PLANE_YZ | PLANE_XZ)) != 0); + zplane_axes_[0] = float((zpos_flag_ & (PLANE_XZ | PLANE_XY)) != 0); + zplane_axes_[1] = float((zpos_flag_ & (PLANE_YZ | PLANE_XY)) != 0); + zplane_axes_[2] = float((zpos_flag_ & (PLANE_YZ | PLANE_XZ)) != 0); } else { zneg_flag_ = zpos_flag_ = CLIP_ZNEG | CLIP_ZPOS; } float dist; - // if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) { - // Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); - // dist = ((Camera *)(camera_object->data))->clip_end; - // grid_flag_ |= GRID_CAMERA; - // zneg_flag_ |= GRID_CAMERA; - // zpos_flag_ |= GRID_CAMERA; - // } - // else { - dist = v3d->clip_end; - // } - - if (winmat[3][3] == 0.0f) { - copy_v3_fl(data_.size, dist); + if (rv3d->persp == RV3D_CAMOB && v3d->camera && v3d->camera->type == OB_CAMERA) { + Object *camera_object = DEG_get_evaluated_object(state.depsgraph, v3d->camera); + dist = ((Camera *)(camera_object->data))->clip_end; + grid_flag_ |= GRID_CAMERA; + zneg_flag_ |= GRID_CAMERA; + zpos_flag_ |= GRID_CAMERA; } else { - float viewdist = 1.0f / min_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1])); - copy_v3_fl(data_.size, viewdist * dist); + dist = v3d->clip_end; + } + + if (view.is_persp()) { + data_.size = float4(dist); + } + else { + float viewdist = 1.0f / min_ff(fabsf(view.winmat()[0][0]), fabsf(view.winmat()[1][1])); + data_.size = float4(viewdist * dist); } data_.distance = dist / 2.0f; - ED_view3d_grid_steps(scene, v3d, rv3d, grid_steps); + ED_view3d_grid_steps(state.scene, v3d, rv3d, grid_steps); if ((v3d->flag & (V3D_XR_SESSION_SURFACE | V3D_XR_SESSION_MIRROR)) != 0) { /* The calculations for the grid parameters assume that the view matrix has no scale * component, which may not be correct if the user is "shrunk" or "enlarged" by zooming in or * out. Therefore, we need to compensate the values here. */ /* Assumption is uniform scaling (all column vectors are of same length). */ - float viewinvscale = len_v3(viewinv[0]); + float viewinvscale = len_v3(view.viewinv()[0]); data_.distance *= viewinvscale; } @@ -171,26 +165,45 @@ class Grid { data_.push_update(); } - void begin_sync() + void begin_sync(Resources &res, const State &state, const View &view) { - update_ubo(); + this->update_ubo(state, view); + + if (!enabled_) { + return; + } grid_ps_.init(); grid_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); - + grid_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 1.0f)); grid_ps_.shader_set(OVERLAY_shader_grid()); grid_ps_.bind_ubo("grid_buf", &data_); - grid_ps_.bind_ubo("globalsBlock", &G_draw.block_ubo); - grid_ps_.bind_texture("depth_tx", &DRW_viewport_texture_list_get()->depth); - - grid_ps_.push_constant("grid_flag", grid_flag_); - grid_ps_.push_constant("plane_axes", grid_axes); - grid_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 0.0f)); - grid_ps_.draw(DRW_cache_grid_get()); + grid_ps_.bind_ubo("globalsBlock", &res.globals_buf); + grid_ps_.bind_texture("depth_tx", &res.depth_tx); + if (zneg_flag_ & SHOW_AXIS_Z) { + grid_ps_.push_constant("grid_flag", zneg_flag_); + grid_ps_.push_constant("plane_axes", zplane_axes_); + grid_ps_.draw(DRW_cache_grid_get()); + } + if (grid_flag_) { + grid_ps_.push_constant("grid_flag", grid_flag_); + grid_ps_.push_constant("plane_axes", grid_axes_); + grid_ps_.draw(DRW_cache_grid_get()); + } + if (zpos_flag_ & SHOW_AXIS_Z) { + grid_ps_.push_constant("grid_flag", zpos_flag_); + grid_ps_.push_constant("plane_axes", zplane_axes_); + grid_ps_.draw(DRW_cache_grid_get()); + } } - void draw(Manager &manager, View &view) + void draw(Resources &res, Manager &manager, View &view) { + if (!enabled_) { + return; + } + + GPU_framebuffer_bind(res.overlay_color_only_fb); manager.submit(grid_ps_, view); } }; diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 1d27c74e19a..5145a40f4be 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -10,14 +10,57 @@ namespace blender::draw::overlay { void Instance::init() { - GPUTexture *viewport_depth_tx = DRW_viewport_texture_list_get()->depth; - GPUTexture *viewport_color_tx = DRW_viewport_texture_list_get()->color_overlay; - overlay_fb.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(viewport_color_tx)); + resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth); + resources.color_tx.wrap(DRW_viewport_texture_list_get()->color_overlay); + + /* TODO(fclem): Remove DRW global usage. */ + const DRWContextState *ctx = DRW_context_state_get(); + + state.depsgraph = ctx->depsgraph; + state.scene = ctx->scene; + state.v3d = ctx->v3d; + state.rv3d = ctx->rv3d; + + state.pixelsize = U.pixelsize; + state.ctx_mode = CTX_data_mode_enum_ex(ctx->object_edit, ctx->obact, ctx->object_mode); + state.clear_in_front = (state.v3d->shading.type != OB_SOLID); + state.use_in_front = (state.v3d->shading.type <= OB_SOLID) || + BKE_scene_uses_blender_workbench(state.scene); + state.is_wireframe_mode = (state.v3d->shading.type == OB_WIRE); + state.hide_overlays = (state.v3d->flag2 & V3D_HIDE_OVERLAYS) != 0; + state.xray_enabled = XRAY_ACTIVE(state.v3d); + state.xray_enabled_and_not_wire = state.xray_enabled && (state.v3d->shading.type > OB_WIRE); + state.xray_opacity = XRAY_ALPHA(state.v3d); + state.cfra = DEG_get_ctime(state.depsgraph); + state.clipping_state = RV3D_CLIPPING_ENABLED(state.v3d, state.rv3d) ? DRW_STATE_CLIP_PLANES : + DRWState(0); + + if (!state.hide_overlays) { + state.overlay = state.v3d->overlay; + state.v3d_flag = state.v3d->flag; + state.v3d_gridflag = state.v3d->gridflag; + } + else { + memset(&state.overlay, 0, sizeof(state.overlay)); + state.v3d_flag = 0; + state.v3d_gridflag = 0; + state.overlay.flag = V3D_OVERLAY_HIDE_TEXT | V3D_OVERLAY_HIDE_MOTION_PATHS | + V3D_OVERLAY_HIDE_BONES | V3D_OVERLAY_HIDE_OBJECT_XTRAS | + V3D_OVERLAY_HIDE_OBJECT_ORIGINS; + state.overlay.wireframe_threshold = state.v3d->overlay.wireframe_threshold; + state.overlay.wireframe_opacity = state.v3d->overlay.wireframe_opacity; + } + + /* TODO(fclem): Remove DRW global usage. */ + resources.globals_buf = G_draw.block_ubo; } void Instance::begin_sync() { - grid.begin_sync(); + const DRWView *view_legacy = DRW_view_default_get(); + View view("OverlayView", view_legacy); + + grid.begin_sync(resources, state, view); } void Instance::object_sync(ObjectRef &ob_ref) @@ -31,11 +74,24 @@ void Instance::end_sync() void Instance::draw(Manager &manager) { - const DRWView *view_old = DRW_view_default_get(); - View view("OverlayView", view_old); + const DRWView *view_legacy = DRW_view_default_get(); + View view("OverlayView", view_legacy); - GPU_framebuffer_bind(overlay_fb); - grid.draw(manager, view); + resources.line_tx.acquire(int2(resources.depth_tx.size()), GPU_RGBA8); + + resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(resources.color_tx)); + resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_tx)); + resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_tx), + GPU_ATTACHMENT_TEXTURE(resources.line_tx)); + + grid.draw(resources, manager, view); + + // anti_aliasing.draw(resources, manager, view); + + resources.line_tx.release(); } } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index 85a73c71900..f908bc1e81b 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -51,8 +51,8 @@ class Instance { /* WORKAROUND: Legacy. Move to grid pass. */ GPUUniformBuf *grid_ubo = nullptr; - Framebuffer overlay_fb = {"overlay_fb"}; - + Resources resources; + State state; Grid grid; ~Instance() diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index 9b433928321..afc4cf44b34 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -7,6 +7,7 @@ #pragma once +#include "DRW_gpu_wrapper.hh" #include "DRW_render.h" #include "overlay_shader_shared.h" @@ -29,7 +30,49 @@ struct ImBuf; namespace blender::draw::overlay { class Instance; -} + +struct State { + Depsgraph *depsgraph; + Scene *scene; + View3D *v3d; + RegionView3D *rv3d; + View3DOverlay overlay; + float pixelsize; + enum eContextObjectMode ctx_mode; + bool clear_in_front; + bool use_in_front; + bool is_wireframe_mode; + bool hide_overlays; + bool xray_enabled; + bool xray_enabled_and_not_wire; + float xray_opacity; + short v3d_flag; /* TODO: move to #View3DOverlay. */ + short v3d_gridflag; /* TODO: move to #View3DOverlay. */ + int cfra; + DRWState clipping_state; +}; + +using blender::draw::Framebuffer; +using blender::draw::Texture; +using blender::draw::TextureFromPool; +using blender::draw::TextureRef; + +struct Resources { + Framebuffer overlay_fb = {"overlay_fb"}; + Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"}; + Framebuffer overlay_color_only_fb = {"overlay_color_only_fb"}; + Framebuffer overlay_line_fb = {"overlay_line_fb"}; + Framebuffer overlay_line_in_front_fb = {"overlay_line_in_front_fb"}; + + TextureFromPool line_tx = {"line_tx"}; + + /* References, not owned. */ + GPUUniformBuf *globals_buf; + TextureRef depth_tx; + TextureRef color_tx; +}; + +} // namespace blender::draw::overlay typedef struct OVERLAY_FramebufferList { struct GPUFrameBuffer *overlay_default_fb; -- 2.30.2 From e116c67c3ab48b548a240f7e547e159316646673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 17:36:11 +0200 Subject: [PATCH 08/22] DRW: Fix gl error related to incorrect uniform size --- source/blender/draw/intern/draw_debug.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/draw/intern/draw_debug.cc b/source/blender/draw/intern/draw_debug.cc index a78dc59cb7e..55de779d85c 100644 --- a/source/blender/draw/intern/draw_debug.cc +++ b/source/blender/draw/intern/draw_debug.cc @@ -558,7 +558,7 @@ void DebugDraw::display_prints() int slot = GPU_shader_get_builtin_ssbo(shader, GPU_STORAGE_BUFFER_DEBUG_PRINT); float f_viewport[4]; GPU_viewport_size_get_f(f_viewport); - GPU_shader_uniform_4fv(shader, "viewport_size", f_viewport); + GPU_shader_uniform_2fv(shader, "viewport_size", f_viewport); if (gpu_print_buf_used) { GPU_debug_group_begin("GPU"); -- 2.30.2 From c4ecfce6bb01ed31200f675719cc0baf10c6a4a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 19:53:51 +0200 Subject: [PATCH 09/22] Overlay-Next: Port Background overlay --- .../engines/overlay/overlay_background.hh | 105 ++++++++++++++++++ .../draw/engines/overlay/overlay_grid.hh | 2 - .../draw/engines/overlay/overlay_instance.cc | 24 +++- .../draw/engines/overlay/overlay_instance.hh | 5 + .../draw/engines/overlay/overlay_private.hh | 6 +- 5 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_background.hh diff --git a/source/blender/draw/engines/overlay/overlay_background.hh b/source/blender/draw/engines/overlay/overlay_background.hh new file mode 100644 index 00000000000..37ab59abb9b --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_background.hh @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "DEG_depsgraph_query.h" +#include "DNA_camera_types.h" +#include "DNA_space_types.h" +#include "ED_view3d.h" +#include "UI_resources.h" + +#include "draw_cache.h" +#include "draw_pass.hh" +#include "overlay_private.hh" +#include "overlay_shader_shared.h" + +namespace blender::draw::overlay { + +class Background { + private: + PassSimple bg_ps_ = {"Background"}; + + public: + void begin_sync(Resources &res, const State &state) + { + DRWState pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_BACKGROUND; + float4 color_override(0.0f, 0.0f, 0.0f, 0.0f); + int background_type; + + if (DRW_state_is_opengl_render() && !DRW_state_draw_background()) { + background_type = BG_SOLID; + color_override[3] = 1.0f; + } + /* + else if (pd->space_type == SPACE_IMAGE) { + background_type = BG_SOLID_CHECKER; + } + else if (pd->space_type == SPACE_NODE) { + background_type = BG_MASK; + pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; + } + */ + else if (!DRW_state_draw_background()) { + background_type = BG_CHECKER; + } + else if (state.v3d->shading.background_type == V3D_SHADING_BACKGROUND_WORLD && + state.scene->world) { + background_type = BG_SOLID; + /* TODO(fclem): this is a scene referred linear color. we should convert + * it to display linear here. */ + color_override = float4(UNPACK3(&state.scene->world->horr), 1.0f); + } + else if (state.v3d->shading.background_type == V3D_SHADING_BACKGROUND_VIEWPORT && + state.v3d->shading.type <= OB_SOLID) { + background_type = BG_SOLID; + color_override = float4(UNPACK3(state.v3d->shading.background_color), 1.0f); + } + else { + switch (UI_GetThemeValue(TH_BACKGROUND_TYPE)) { + case TH_BACKGROUND_GRADIENT_LINEAR: + background_type = BG_GRADIENT; + break; + case TH_BACKGROUND_GRADIENT_RADIAL: + background_type = BG_RADIAL; + break; + default: + case TH_BACKGROUND_SINGLE_COLOR: + background_type = BG_SOLID; + break; + } + } + + bg_ps_.init(); + bg_ps_.clear_color(float4()); + bg_ps_.state_set(pass_state); + bg_ps_.shader_set(OVERLAY_shader_background()); + bg_ps_.bind_ubo("globalsBlock", &res.globals_buf); + bg_ps_.bind_texture("colorBuffer", &res.color_render_tx); + bg_ps_.bind_texture("depthBuffer", &res.depth_tx); + bg_ps_.push_constant("colorOverride", color_override); + bg_ps_.push_constant("bgType", background_type); + bg_ps_.draw_procedural(GPU_PRIM_TRIS, 1, 3); + + if (state.clipping_state != 0 && state.rv3d != nullptr && state.rv3d->clipbb != nullptr) { + bg_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK); + bg_ps_.shader_set(OVERLAY_shader_clipbound()); + bg_ps_.push_constant("ucolor", res.theme_settings.color_clipping_border); + bg_ps_.push_constant("boundbox", &state.rv3d->clipbb->vec[0][0], 8); + bg_ps_.draw(DRW_cache_cube_get()); + } + } + + void draw(Resources &res, Manager &manager) + { + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(res.overlay_color_only_fb); + } + manager.submit(bg_ps_); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_grid.hh b/source/blender/draw/engines/overlay/overlay_grid.hh index 7de857d8888..02de6f46e5e 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.hh +++ b/source/blender/draw/engines/overlay/overlay_grid.hh @@ -19,7 +19,6 @@ namespace blender::draw::overlay { class Grid { - public: private: UniformBuffer data_; @@ -175,7 +174,6 @@ class Grid { grid_ps_.init(); grid_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); - grid_ps_.clear_color(float4(0.0f, 0.0f, 0.0f, 1.0f)); grid_ps_.shader_set(OVERLAY_shader_grid()); grid_ps_.bind_ubo("grid_buf", &data_); grid_ps_.bind_ubo("globalsBlock", &res.globals_buf); diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 5145a40f4be..a6ab60ec22f 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -5,13 +5,15 @@ */ #include "overlay_instance.hh" +#include "draw_debug.hh" namespace blender::draw::overlay { void Instance::init() { resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth); - resources.color_tx.wrap(DRW_viewport_texture_list_get()->color_overlay); + resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay); + resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color); /* TODO(fclem): Remove DRW global usage. */ const DRWContextState *ctx = DRW_context_state_get(); @@ -53,6 +55,7 @@ void Instance::init() /* TODO(fclem): Remove DRW global usage. */ resources.globals_buf = G_draw.block_ubo; + resources.theme_settings = G_draw.block; } void Instance::begin_sync() @@ -60,6 +63,7 @@ void Instance::begin_sync() const DRWView *view_legacy = DRW_view_default_get(); View view("OverlayView", view_legacy); + background.begin_sync(resources, state); grid.begin_sync(resources, state, view); } @@ -74,19 +78,31 @@ void Instance::end_sync() void Instance::draw(Manager &manager) { + /* WORKAROUND: This is to prevent crashes when using depth picking or selection. + * The selection engine should handle theses cases instead. */ + if (!DRW_state_is_fbo()) { + return; + } + const DRWView *view_legacy = DRW_view_default_get(); View view("OverlayView", view_legacy); resources.line_tx.acquire(int2(resources.depth_tx.size()), GPU_RGBA8); resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(resources.color_tx)); + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), - GPU_ATTACHMENT_TEXTURE(resources.color_tx)); + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), - GPU_ATTACHMENT_TEXTURE(resources.color_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx), GPU_ATTACHMENT_TEXTURE(resources.line_tx)); + GPU_framebuffer_bind(resources.overlay_color_only_fb); + + float4 clear_color(0.0f); + GPU_framebuffer_clear_color(resources.overlay_color_only_fb, clear_color); + + background.draw(resources, manager); grid.draw(resources, manager, view); // anti_aliasing.draw(resources, manager, view); diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index f908bc1e81b..09029963c9a 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -8,6 +8,7 @@ #include "draw_manager.hh" +#include "overlay_background.hh" #include "overlay_grid.hh" namespace blender::draw::overlay { @@ -51,8 +52,12 @@ class Instance { /* WORKAROUND: Legacy. Move to grid pass. */ GPUUniformBuf *grid_ubo = nullptr; + /** Global types. */ Resources resources; State state; + + /** Overlay types. */ + Background background; Grid grid; ~Instance() diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index afc4cf44b34..ed905991572 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -66,10 +66,14 @@ struct Resources { TextureFromPool line_tx = {"line_tx"}; + /** TODO(fclem): Copy of G_data.block that should become theme colors only and managed by the + * engine. */ + GlobalsUboStorage theme_settings; /* References, not owned. */ GPUUniformBuf *globals_buf; TextureRef depth_tx; - TextureRef color_tx; + TextureRef color_overlay_tx; + TextureRef color_render_tx; }; } // namespace blender::draw::overlay -- 2.30.2 From 2abc4d053860559f0fe803d265f459b2b05ae7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 12 Oct 2022 23:31:03 +0200 Subject: [PATCH 10/22] Overlay-Next: Port Metaball overlay --- .../engines/overlay/overlay_background.hh | 5 +- .../draw/engines/overlay/overlay_instance.cc | 68 ++++++++- .../draw/engines/overlay/overlay_instance.hh | 33 +++++ .../draw/engines/overlay/overlay_metaball.hh | 132 ++++++++++++++++++ .../draw/engines/overlay/overlay_private.hh | 5 + .../draw/engines/overlay/overlay_shader.cc | 13 ++ 6 files changed, 248 insertions(+), 8 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_metaball.hh diff --git a/source/blender/draw/engines/overlay/overlay_background.hh b/source/blender/draw/engines/overlay/overlay_background.hh index 37ab59abb9b..6ec212c108c 100644 --- a/source/blender/draw/engines/overlay/overlay_background.hh +++ b/source/blender/draw/engines/overlay/overlay_background.hh @@ -74,7 +74,6 @@ class Background { } bg_ps_.init(); - bg_ps_.clear_color(float4()); bg_ps_.state_set(pass_state); bg_ps_.shader_set(OVERLAY_shader_background()); bg_ps_.bind_ubo("globalsBlock", &res.globals_buf); @@ -95,9 +94,7 @@ class Background { void draw(Resources &res, Manager &manager) { - if (DRW_state_is_fbo()) { - GPU_framebuffer_bind(res.overlay_color_only_fb); - } + GPU_framebuffer_bind(res.overlay_color_only_fb); manager.submit(bg_ps_); } }; diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index a6ab60ec22f..417fcd45d4a 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -12,6 +12,7 @@ namespace blender::draw::overlay { void Instance::init() { resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth); + resources.depth_in_front_tx.wrap(DRW_viewport_texture_list_get()->depth_in_front); resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay); resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color); @@ -19,6 +20,7 @@ void Instance::init() const DRWContextState *ctx = DRW_context_state_get(); state.depsgraph = ctx->depsgraph; + state.view_layer = ctx->view_layer; state.scene = ctx->scene; state.v3d = ctx->v3d; state.rv3d = ctx->rv3d; @@ -64,16 +66,54 @@ void Instance::begin_sync() View view("OverlayView", view_legacy); background.begin_sync(resources, state); + metaballs.begin_sync(); grid.begin_sync(resources, state, view); } void Instance::object_sync(ObjectRef &ob_ref) { - UNUSED_VARS(ob_ref); + const bool in_edit_mode = object_is_edit_mode(ob_ref.object); + + if (in_edit_mode && !state.hide_overlays) { + switch (ob_ref.object->type) { + case OB_MESH: + break; + case OB_ARMATURE: + break; + case OB_CURVES_LEGACY: + break; + case OB_SURF: + break; + case OB_LATTICE: + break; + case OB_MBALL: + metaballs.edit_object_sync(ob_ref, resources); + break; + case OB_FONT: + break; + case OB_CURVES: + break; + } + } + + if (!state.hide_overlays) { + switch (ob_ref.object->type) { + case OB_ARMATURE: + break; + case OB_MBALL: + if (!in_edit_mode) { + metaballs.object_sync(ob_ref, resources, state); + } + break; + case OB_GPENCIL: + break; + } + } } void Instance::end_sync() { + metaballs.end_sync(resources, state); } void Instance::draw(Manager &manager) @@ -84,18 +124,32 @@ void Instance::draw(Manager &manager) return; } + int2 render_size = int2(resources.depth_tx.size()); + const DRWView *view_legacy = DRW_view_default_get(); View view("OverlayView", view_legacy); - resources.line_tx.acquire(int2(resources.depth_tx.size()), GPU_RGBA8); + resources.line_tx.acquire(render_size, GPU_RGBA8); - resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx), GPU_ATTACHMENT_TEXTURE(resources.line_tx)); + resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); + + /* TODO(fclem): Remove mandatory allocation. */ + if (!resources.depth_in_front_tx.is_valid()) { + resources.depth_in_front_alloc_tx.acquire(render_size, GPU_DEPTH_COMPONENT24); + resources.depth_in_front_tx.wrap(resources.depth_in_front_alloc_tx); + } + + resources.overlay_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_in_front_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); + resources.overlay_line_in_front_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_in_front_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx), + GPU_ATTACHMENT_TEXTURE(resources.line_tx)); GPU_framebuffer_bind(resources.overlay_color_only_fb); @@ -103,11 +157,17 @@ void Instance::draw(Manager &manager) GPU_framebuffer_clear_color(resources.overlay_color_only_fb, clear_color); background.draw(resources, manager); + + metaballs.draw(resources, manager, view); + grid.draw(resources, manager, view); + metaballs.draw_in_front(resources, manager, view); + // anti_aliasing.draw(resources, manager, view); resources.line_tx.release(); + resources.depth_in_front_alloc_tx.release(); } } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index 09029963c9a..1fb199e4e6e 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -10,6 +10,7 @@ #include "overlay_background.hh" #include "overlay_grid.hh" +#include "overlay_metaball.hh" namespace blender::draw::overlay { @@ -58,6 +59,7 @@ class Instance { /** Overlay types. */ Background background; + Metaballs metaballs; Grid grid; ~Instance() @@ -70,6 +72,37 @@ class Instance { void object_sync(ObjectRef &ob_ref); void end_sync(); void draw(Manager &manager); + + private: + bool object_is_edit_mode(const Object *ob) + { + if (DRW_object_is_in_edit_mode(ob)) { + /* Also check for context mode as the object mode is not 100% reliable. (see T72490) */ + switch (ob->type) { + case OB_MESH: + return state.ctx_mode == CTX_MODE_EDIT_MESH; + case OB_ARMATURE: + return state.ctx_mode == CTX_MODE_EDIT_ARMATURE; + case OB_CURVES_LEGACY: + return state.ctx_mode == CTX_MODE_EDIT_CURVE; + case OB_SURF: + return state.ctx_mode == CTX_MODE_EDIT_SURFACE; + case OB_LATTICE: + return state.ctx_mode == CTX_MODE_EDIT_LATTICE; + case OB_MBALL: + return state.ctx_mode == CTX_MODE_EDIT_METABALL; + case OB_FONT: + return state.ctx_mode == CTX_MODE_EDIT_TEXT; + case OB_CURVES: + return state.ctx_mode == CTX_MODE_EDIT_CURVES; + case OB_POINTCLOUD: + case OB_VOLUME: + /* No edit mode yet. */ + return false; + } + } + return false; + } }; } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh new file mode 100644 index 00000000000..0bffac49180 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "DEG_depsgraph_query.h" +#include "DNA_camera_types.h" +#include "DNA_space_types.h" +#include "ED_view3d.h" +#include "UI_resources.h" + +#include "draw_cache.h" +#include "draw_pass.hh" +#include "overlay_private.hh" +#include "overlay_shader_shared.h" + +namespace blender::draw::overlay { + +class Metaballs { + + private: + PassSimple metaball_ps_ = {"MetaBalls"}; + PassSimple metaball_in_front_ps_ = {"MetaBalls_In_front"}; + + ArmatureSphereBuf data_buf_ = {"metaball_data_buf"}; + ArmatureSphereBuf data_in_front_buf_ = {"metaball_data_buf"}; + + public: + void begin_sync() + { + data_buf_.clear(); + data_in_front_buf_.clear(); + } + + void metaball_instance_data_set(BoneInstanceData *data, + Object *ob, + const float *pos, + const float radius, + const float color[4]) + { + /* Bone point radius is 0.05. Compensate for that. */ + mul_v3_v3fl(data->mat[0], ob->obmat[0], radius / 0.05f); + mul_v3_v3fl(data->mat[1], ob->obmat[1], radius / 0.05f); + mul_v3_v3fl(data->mat[2], ob->obmat[2], radius / 0.05f); + mul_v3_m4v3(data->mat[3], ob->obmat, pos); + /* WATCH: Reminder, alpha is wire-size. */ + OVERLAY_bone_instance_data_set_color(data, color); + } + + void edit_object_sync(const ObjectRef &ob_ref, const Resources &res) + { + ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? + data_in_front_buf_ : + data_buf_; + MetaBall *mb = static_cast(ob_ref.object->data); + + const float *color; + const float *col_radius = res.theme_settings.color_mball_radius; + const float *col_radius_select = res.theme_settings.color_mball_radius_select; + const float *col_stiffness = res.theme_settings.color_mball_stiffness; + const float *col_stiffness_select = res.theme_settings.color_mball_stiffness_select; + + LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) { + const bool is_selected = (ml->flag & SELECT) != 0; + const bool is_scale_radius = (ml->flag & MB_SCALE_RAD) != 0; + float stiffness_radius = ml->rad * atanf(ml->s) / float(M_PI_2); + BoneInstanceData instdata; + + color = (is_selected && is_scale_radius) ? col_radius_select : col_radius; + metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, ml->rad, color); + data_buf.append(*reinterpret_cast(&instdata)); + + color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness; + metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, stiffness_radius, color); + data_buf.append(*reinterpret_cast(&instdata)); + } + } + + void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state) + { + ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? + data_in_front_buf_ : + data_buf_; + MetaBall *mb = static_cast(ob_ref.object->data); + + float *color; + /* TODO(fclem): Remove DRW global usage. */ + UNUSED_VARS(res); + DRW_object_wire_theme_get(ob_ref.object, state.view_layer, &color); + + LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { + /* Draw radius only. */ + BoneInstanceData instdata; + metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, ml->rad, color); + data_buf.append(*reinterpret_cast(&instdata)); + } + } + + void end_sync(Resources &res, const State &state) + { + auto init_pass = [&](PassSimple &pass, ArmatureSphereBuf &data_buf) { + data_buf.push_update(); + + pass.init(); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + state.clipping_state); + pass.shader_set(OVERLAY_shader_armature_sphere(true)); + pass.bind_ubo("globalsBlock", &res.globals_buf); + pass.bind_ssbo("data_buf", &data_buf); + pass.draw(DRW_cache_bone_point_wire_outline_get(), data_buf.size()); + }; + init_pass(metaball_ps_, data_buf_); + init_pass(metaball_in_front_ps_, data_in_front_buf_); + } + + void draw(Resources &res, Manager &manager, View &view) + { + GPU_framebuffer_bind(res.overlay_line_fb); + manager.submit(metaball_ps_, view); + } + + void draw_in_front(Resources &res, Manager &manager, View &view) + { + GPU_framebuffer_bind(res.overlay_line_in_front_fb); + manager.submit(metaball_in_front_ps_, view); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index ed905991572..990946a11a5 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -33,6 +33,7 @@ class Instance; struct State { Depsgraph *depsgraph; + ViewLayer *view_layer; Scene *scene; View3D *v3d; RegionView3D *rv3d; @@ -53,9 +54,11 @@ struct State { }; using blender::draw::Framebuffer; +using blender::draw::StorageVectorBuffer; using blender::draw::Texture; using blender::draw::TextureFromPool; using blender::draw::TextureRef; +using ArmatureSphereBuf = StorageVectorBuffer; struct Resources { Framebuffer overlay_fb = {"overlay_fb"}; @@ -65,6 +68,7 @@ struct Resources { Framebuffer overlay_line_in_front_fb = {"overlay_line_in_front_fb"}; TextureFromPool line_tx = {"line_tx"}; + TextureFromPool depth_in_front_alloc_tx = {"overlay_depth_in_front_tx"}; /** TODO(fclem): Copy of G_data.block that should become theme colors only and managed by the * engine. */ @@ -72,6 +76,7 @@ struct Resources { /* References, not owned. */ GPUUniformBuf *globals_buf; TextureRef depth_tx; + TextureRef depth_in_front_tx; TextureRef color_overlay_tx; TextureRef color_render_tx; }; diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index b7e5e8c56b7..98e082aac84 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -11,6 +11,8 @@ #include "UI_resources.h" +#include "gpu_shader_create_info.hh" + #include "overlay_private.hh" typedef struct OVERLAY_Shaders { @@ -182,6 +184,17 @@ GPUShader *OVERLAY_shader_armature_sphere(bool use_outline) const DRWContextState *draw_ctx = DRW_context_state_get(); OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; if (use_outline && !sh_data->armature_sphere_outline) { + using namespace blender::gpu::shader; + ShaderCreateInfo &info = const_cast( + *reinterpret_cast( + GPU_shader_create_info_get("overlay_armature_sphere_outline"))); + + if (U.experimental.enable_overlay_next) { + info.storage_buf(0, Qualifier::READ, "mat4", "data_buf[]"); + info.define("inst_obmat", "data_buf[gl_InstanceID]"); + info.vertex_inputs_.pop_last(); + } + sh_data->armature_sphere_outline = GPU_shader_create_from_info_name( draw_ctx->sh_cfg ? "overlay_armature_sphere_outline_clipped" : "overlay_armature_sphere_outline"); -- 2.30.2 From cdb9b6a04172e6577dc4cf1a1642489d35b629a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 10 Feb 2023 18:46:05 +0100 Subject: [PATCH 11/22] Overlay-Next: Add support for empties Also added a shape cache and move the color selection to `Resources`. --- .../draw/engines/overlay/overlay_empty.hh | 147 ++++++++ .../draw/engines/overlay/overlay_grid.hh | 4 +- .../draw/engines/overlay/overlay_instance.cc | 14 +- .../draw/engines/overlay/overlay_instance.hh | 4 + .../draw/engines/overlay/overlay_metaball.hh | 5 +- .../draw/engines/overlay/overlay_private.hh | 90 ++++- .../draw/engines/overlay/overlay_shader.cc | 12 + .../engines/overlay/overlay_shader_shared.h | 17 + .../draw/engines/overlay/overlay_shape.hh | 330 ++++++++++++++++++ .../shaders/infos/overlay_extra_info.hh | 1 + source/blender/editors/include/ED_view3d.h | 6 +- .../editors/space_view3d/view3d_draw.cc | 6 +- 12 files changed, 619 insertions(+), 17 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_empty.hh create mode 100644 source/blender/draw/engines/overlay/overlay_shape.hh diff --git a/source/blender/draw/engines/overlay/overlay_empty.hh b/source/blender/draw/engines/overlay/overlay_empty.hh new file mode 100644 index 00000000000..1c28f0cbaa3 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_empty.hh @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "DNA_object_types.h" + +#include "draw_pass.hh" +#include "draw_shader_shared.h" +#include "overlay_private.hh" +#include "overlay_shape.hh" + +namespace blender::draw::overlay { + +class Empties { + + private: + PassSimple empty_ps_ = {"Empties"}; + PassSimple empty_in_front_ps_ = {"Empties_In_front"}; + + using EmptyInstanceBuf = StorageVectorBuffer; + + struct CallBuffers { + EmptyInstanceBuf plain_axes_buf = {"plain_axes_buf"}; + EmptyInstanceBuf single_arrow_buf = {"single_arrow_buf"}; + EmptyInstanceBuf cube_buf = {"cube_buf"}; + EmptyInstanceBuf circle_buf = {"circle_buf"}; + EmptyInstanceBuf sphere_buf = {"sphere_buf"}; + EmptyInstanceBuf cone_buf = {"cone_buf"}; + EmptyInstanceBuf arrows_buf = {"arrows_buf"}; + EmptyInstanceBuf image_buf = {"image_buf"}; + } call_buffers_[2]; + + public: + void begin_sync() + { + for (int i = 0; i < 2; i++) { + call_buffers_[i].plain_axes_buf.clear(); + call_buffers_[i].single_arrow_buf.clear(); + call_buffers_[i].cube_buf.clear(); + call_buffers_[i].circle_buf.clear(); + call_buffers_[i].sphere_buf.clear(); + call_buffers_[i].cone_buf.clear(); + call_buffers_[i].arrows_buf.clear(); + call_buffers_[i].image_buf.clear(); + } + } + + void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state) + { + CallBuffers &call_bufs = call_buffers_[int((ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0)]; + + float4 color = res.object_wire_color(ob_ref, state); + ExtraInstanceData data( + float4x4(ob_ref.object->object_to_world), color, ob_ref.object->empty_drawsize); + + switch (ob_ref.object->empty_drawtype) { + case OB_PLAINAXES: + call_bufs.plain_axes_buf.append(data); + break; + case OB_SINGLE_ARROW: + call_bufs.single_arrow_buf.append(data); + break; + case OB_CUBE: + call_bufs.cube_buf.append(data); + break; + case OB_CIRCLE: + call_bufs.circle_buf.append(data); + break; + case OB_EMPTY_SPHERE: + call_bufs.sphere_buf.append(data); + break; + case OB_EMPTY_CONE: + call_bufs.cone_buf.append(data); + break; + case OB_ARROWS: + call_bufs.arrows_buf.append(data); + break; + case OB_EMPTY_IMAGE: + /* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */ + call_bufs.image_buf.append(data); + break; + } + } + + void end_sync(Resources &res, ShapeCache &shapes, const State &state) + { + auto init_pass = [&](PassSimple &pass, CallBuffers &call_bufs) { + pass.init(); + pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | + state.clipping_state); + pass.shader_set(OVERLAY_shader_extra(false)); + pass.bind_ubo("globalsBlock", &res.globals_buf); + + call_bufs.plain_axes_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.plain_axes_buf); + pass.draw(shapes.plain_axes, call_bufs.plain_axes_buf.size()); + + call_bufs.single_arrow_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.single_arrow_buf); + pass.draw(shapes.single_arrow, call_bufs.single_arrow_buf.size()); + + call_bufs.cube_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.cube_buf); + pass.draw(shapes.cube, call_bufs.cube_buf.size()); + + call_bufs.circle_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.circle_buf); + pass.draw(shapes.circle, call_bufs.circle_buf.size()); + + call_bufs.sphere_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.sphere_buf); + pass.draw(shapes.empty_sphere, call_bufs.sphere_buf.size()); + + call_bufs.cone_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.cone_buf); + pass.draw(shapes.empty_cone, call_bufs.cone_buf.size()); + + call_bufs.arrows_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.arrows_buf); + pass.draw(shapes.arrows, call_bufs.arrows_buf.size()); + + call_bufs.image_buf.push_update(); + pass.bind_ssbo("data_buf", &call_bufs.image_buf); + pass.draw(shapes.quad_wire, call_bufs.image_buf.size()); + }; + init_pass(empty_ps_, call_buffers_[0]); + init_pass(empty_in_front_ps_, call_buffers_[1]); + } + + void draw(Resources &res, Manager &manager, View &view) + { + GPU_framebuffer_bind(res.overlay_line_fb); + manager.submit(empty_ps_, view); + } + + void draw_in_front(Resources &res, Manager &manager, View &view) + { + GPU_framebuffer_bind(res.overlay_line_in_front_fb); + manager.submit(empty_in_front_ps_, view); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_grid.hh b/source/blender/draw/engines/overlay/overlay_grid.hh index 02de6f46e5e..25db8193b4d 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.hh +++ b/source/blender/draw/engines/overlay/overlay_grid.hh @@ -42,8 +42,8 @@ class Grid { /* Default, nothing is drawn. */ grid_flag_ = zneg_flag_ = zpos_flag_ = OVERLAY_GridBits(0); - View3D *v3d = state.v3d; - RegionView3D *rv3d = state.rv3d; + const View3D *v3d = state.v3d; + const RegionView3D *rv3d = state.rv3d; const bool show_axis_x = (state.v3d_gridflag & V3D_SHOW_X) != 0; const bool show_axis_y = (state.v3d_gridflag & V3D_SHOW_Y) != 0; diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 417fcd45d4a..0726ea2b74a 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -4,9 +4,10 @@ * \ingroup overlay */ -#include "overlay_instance.hh" #include "draw_debug.hh" +#include "overlay_instance.hh" + namespace blender::draw::overlay { void Instance::init() @@ -18,12 +19,16 @@ void Instance::init() /* TODO(fclem): Remove DRW global usage. */ const DRWContextState *ctx = DRW_context_state_get(); + /* Was needed by `object_wire_theme_id()` when doing the port. Not sure if needed nowadays. */ + BKE_view_layer_synced_ensure(ctx->scene, ctx->view_layer); state.depsgraph = ctx->depsgraph; state.view_layer = ctx->view_layer; state.scene = ctx->scene; state.v3d = ctx->v3d; state.rv3d = ctx->rv3d; + state.active_base = BKE_view_layer_active_base_get(ctx->view_layer); + state.object_mode = ctx->object_mode; state.pixelsize = U.pixelsize; state.ctx_mode = CTX_data_mode_enum_ex(ctx->object_edit, ctx->obact, ctx->object_mode); @@ -66,6 +71,7 @@ void Instance::begin_sync() View view("OverlayView", view_legacy); background.begin_sync(resources, state); + empties.begin_sync(); metaballs.begin_sync(); grid.begin_sync(resources, state, view); } @@ -98,6 +104,9 @@ void Instance::object_sync(ObjectRef &ob_ref) if (!state.hide_overlays) { switch (ob_ref.object->type) { + case OB_EMPTY: + empties.object_sync(ob_ref, resources, state); + break; case OB_ARMATURE: break; case OB_MBALL: @@ -114,6 +123,7 @@ void Instance::object_sync(ObjectRef &ob_ref) void Instance::end_sync() { metaballs.end_sync(resources, state); + empties.end_sync(resources, shapes, state); } void Instance::draw(Manager &manager) @@ -158,10 +168,12 @@ void Instance::draw(Manager &manager) background.draw(resources, manager); + empties.draw(resources, manager, view); metaballs.draw(resources, manager, view); grid.draw(resources, manager, view); + empties.draw_in_front(resources, manager, view); metaballs.draw_in_front(resources, manager, view); // anti_aliasing.draw(resources, manager, view); diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index 1fb199e4e6e..c90494f6c75 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -9,8 +9,10 @@ #include "draw_manager.hh" #include "overlay_background.hh" +#include "overlay_empty.hh" #include "overlay_grid.hh" #include "overlay_metaball.hh" +#include "overlay_shape.hh" namespace blender::draw::overlay { @@ -49,6 +51,7 @@ class SceneResources { class Instance { public: ShaderCache shaders; + ShapeCache shapes; /* WORKAROUND: Legacy. Move to grid pass. */ GPUUniformBuf *grid_ubo = nullptr; @@ -60,6 +63,7 @@ class Instance { /** Overlay types. */ Background background; Metaballs metaballs; + Empties empties; Grid grid; ~Instance() diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index 6bd9811054e..df7bab02a70 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -86,10 +86,7 @@ class Metaballs { data_buf_; MetaBall *mb = static_cast(ob_ref.object->data); - float *color; - /* TODO(fclem): Remove DRW global usage. */ - UNUSED_VARS(res); - DRW_object_wire_theme_get(ob_ref.object, state.view_layer, &color); + const float4 &color = res.object_wire_color(ob_ref, state); LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { /* Draw radius only. */ diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index bd7ea90a90a..c015ee8abf5 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -7,9 +7,15 @@ #pragma once +#include "BKE_global.h" + #include "DRW_gpu_wrapper.hh" #include "DRW_render.h" +#include "UI_resources.h" + +#include "draw_handle.hh" + #include "overlay_shader_shared.h" #ifdef __cplusplus @@ -33,13 +39,15 @@ class Instance; struct State { Depsgraph *depsgraph; - ViewLayer *view_layer; - Scene *scene; - View3D *v3d; - RegionView3D *rv3d; + const ViewLayer *view_layer; + const Scene *scene; + const View3D *v3d; + const RegionView3D *rv3d; + const Base *active_base; View3DOverlay overlay; float pixelsize; enum eContextObjectMode ctx_mode; + enum eObjectMode object_mode; bool clear_in_front; bool use_in_front; bool is_wireframe_mode; @@ -79,6 +87,80 @@ struct Resources { TextureRef depth_in_front_tx; TextureRef color_overlay_tx; TextureRef color_render_tx; + + [[nodiscard]] ThemeColorID object_wire_theme_id(const ObjectRef &ob_ref, + const State &state) const + { + const bool is_edit = (state.object_mode & OB_MODE_EDIT) && + (ob_ref.object->mode & OB_MODE_EDIT); + const bool active = (state.active_base != nullptr) && + ((ob_ref.dupli_parent != nullptr) ? + (state.active_base->object == ob_ref.dupli_parent) : + (state.active_base->object == ob_ref.object)); + const bool is_selected = ((ob_ref.object->base_flag & BASE_SELECTED) != 0); + + /* Object in edit mode. */ + if (is_edit) { + return TH_WIRE_EDIT; + } + /* Transformed object during operators. */ + if (((G.moving & G_TRANSFORM_OBJ) != 0) && is_selected) { + return TH_TRANSFORM; + } + /* Sets the 'theme_id' or fallback to wire */ + if ((ob_ref.object->base_flag & BASE_SELECTED) != 0) { + return (active) ? TH_ACTIVE : TH_SELECT; + } + + switch (ob_ref.object->type) { + case OB_LAMP: + return TH_LIGHT; + case OB_SPEAKER: + return TH_SPEAKER; + case OB_CAMERA: + return TH_CAMERA; + case OB_LIGHTPROBE: + /* TODO: add light-probe color. Use empty color for now. */ + case OB_EMPTY: + return TH_EMPTY; + default: + return (is_edit) ? TH_WIRE_EDIT : TH_WIRE; + } + } + + [[nodiscard]] const float4 &object_wire_color(const ObjectRef &ob_ref, + ThemeColorID theme_id) const + { + if (UNLIKELY(ob_ref.object->base_flag & BASE_FROM_SET)) { + return theme_settings.color_wire; + } + switch (theme_id) { + case TH_WIRE_EDIT: + return theme_settings.color_wire_edit; + case TH_ACTIVE: + return theme_settings.color_active; + case TH_SELECT: + return theme_settings.color_select; + case TH_TRANSFORM: + return theme_settings.color_transform; + case TH_SPEAKER: + return theme_settings.color_speaker; + case TH_CAMERA: + return theme_settings.color_camera; + case TH_EMPTY: + return theme_settings.color_empty; + case TH_LIGHT: + return theme_settings.color_light; + default: + return theme_settings.color_wire; + } + } + + [[nodiscard]] const float4 &object_wire_color(const ObjectRef &ob_ref, const State &state) const + { + ThemeColorID theme_id = object_wire_theme_id(ob_ref, state); + return object_wire_color(ob_ref, theme_id); + } }; } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index 5bbed01d2e6..917c3636a4f 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -490,6 +490,18 @@ GPUShader *OVERLAY_shader_extra(bool is_select) OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra; if (!*sh) { + using namespace blender::gpu::shader; + ShaderCreateInfo &info = const_cast( + *reinterpret_cast(GPU_shader_create_info_get("overlay_extra"))); + + if (U.experimental.enable_overlay_next) { + info.storage_buf(0, Qualifier::READ, "ExtraInstanceData", "data_buf[]"); + info.define("color", "data_buf[gl_InstanceID].color_"); + info.define("inst_obmat", "data_buf[gl_InstanceID].object_to_world_"); + info.vertex_inputs_.pop_last(); + info.vertex_inputs_.pop_last(); + } + *sh = GPU_shader_create_from_info_name( (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? (is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") : diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h index 0b44b6ca356..5f00bec79c8 100644 --- a/source/blender/draw/engines/overlay/overlay_shader_shared.h +++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h @@ -15,6 +15,7 @@ typedef enum OVERLAY_GridBits OVERLAY_GridBits; # endif typedef struct OVERLAY_GridData OVERLAY_GridData; typedef struct ThemeColorData ThemeColorData; +typedef struct ExtraInstanceData ExtraInstanceData; #endif /* TODO(fclem): Should eventually become OVERLAY_BackgroundType. @@ -191,6 +192,22 @@ struct ThemeColorData { }; BLI_STATIC_ASSERT_ALIGN(ThemeColorData, 16) +/* TODO Move to overlay engine. */ +struct ExtraInstanceData { + float4 color_; + float4x4 object_to_world_; + +#if !defined(GPU_SHADER) && defined(__cplusplus) + ExtraInstanceData(const float4x4 &object_to_world, float4 &color, float draw_size) + { + this->color_ = color; + this->object_to_world_ = object_to_world; + this->object_to_world_[3][3] = draw_size; + }; +#endif +}; +BLI_STATIC_ASSERT_ALIGN(ExtraInstanceData, 16) + #ifndef GPU_SHADER # ifdef __cplusplus } diff --git a/source/blender/draw/engines/overlay/overlay_shape.hh b/source/blender/draw/engines/overlay/overlay_shape.hh new file mode 100644 index 00000000000..eb23d3e71a2 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_shape.hh @@ -0,0 +1,330 @@ + +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include "BLI_vector.hh" +#include "GPU_batch.h" + +namespace blender::draw::overlay { + +/** + * Contains all overlay generic geometry batches. + */ +class ShapeCache { + private: + /* Needs to be first for other lambdas to access. */ + GPUVertFormat format = []() { + GPUVertFormat format = {0}; + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "vclass", GPU_COMP_I32, 1, GPU_FETCH_INT); + return format; + }(); + + /* Matches Vertex Format. */ + struct Vertex { + float3 pos; + int vclass; + }; + + struct AutoFreeGPUBatch { + GPUBatch *batch; + + AutoFreeGPUBatch(GPUBatch *_batch) : batch(_batch){}; + + ~AutoFreeGPUBatch() + { + GPU_BATCH_DISCARD_SAFE(batch); + } + + operator GPUBatch *() + { + return batch; + } + }; + + /* Caller gets ownership of the #GPUVertBuf. */ + GPUVertBuf *vbo_from_vector(Vector &vector) + { + GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(vbo, vector.size()); + Vertex *vbo_data = (Vertex *)GPU_vertbuf_get_data(vbo); + /* Copy data to VBO using a wrapper span. Could use memcpy if that's too slow. */ + MutableSpan span(vbo_data, vector.size()); + span.copy_from(vector); + return vbo; + } + + enum VertexClass { + VCLASS_LIGHT_AREA_SHAPE = 1 << 0, + VCLASS_LIGHT_SPOT_SHAPE = 1 << 1, + VCLASS_LIGHT_SPOT_BLEND = 1 << 2, + VCLASS_LIGHT_SPOT_CONE = 1 << 3, + VCLASS_LIGHT_DIST = 1 << 4, + + VCLASS_CAMERA_FRAME = 1 << 5, + VCLASS_CAMERA_DIST = 1 << 6, + VCLASS_CAMERA_VOLUME = 1 << 7, + + VCLASS_SCREENSPACE = 1 << 8, + VCLASS_SCREENALIGNED = 1 << 9, + + VCLASS_EMPTY_SCALED = 1 << 10, + VCLASS_EMPTY_AXES = 1 << 11, + VCLASS_EMPTY_AXES_NAME = 1 << 12, + VCLASS_EMPTY_AXES_SHADOW = 1 << 13, + VCLASS_EMPTY_SIZE = 1 << 14, + }; + + static constexpr float bone_box_verts[8][3] = { + {1.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, -1.0f}, + {-1.0f, 0.0f, -1.0f}, + {-1.0f, 0.0f, 1.0f}, + {1.0f, 1.0f, 1.0f}, + {1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, -1.0f}, + {-1.0f, 1.0f, 1.0f}, + }; + + static constexpr std::array bone_box_wire = { + 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7, + }; + + /* A single ring of vertices. */ + static Vector ring_vertices(const float radius, const int segments) + { + Vector verts; + for (int i : IndexRange(segments)) { + float angle = (2 * M_PI * i) / segments; + verts.append(radius * float2(math::cos(angle), math::sin(angle))); + } + return verts; + } + + /* Returns lines segment geometry forming 3 circles, one on each axis. */ + static Vector sphere_axes_circles(const float radius, + const VertexClass vclass, + const int segments) + { + Vector ring = ring_vertices(radius, segments); + + Vector verts; + for (int axis : IndexRange(3)) { + for (int i : IndexRange(segments)) { + for (int j : IndexRange(2)) { + float2 cv = ring[(i + j) % segments]; + if (axis == 0) { + verts.append({{cv[0], cv[1], 0.0f}, vclass}); + } + else if (axis == 1) { + verts.append({{cv[0], 0.0f, cv[1]}, vclass}); + } + else { + verts.append({{0.0f, cv[0], cv[1]}, vclass}); + } + } + } + } + return verts; + } + + public: + AutoFreeGPUBatch quad_wire = [this]() { + Vector verts; + verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + + verts.append({{-1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + + verts.append({{+1.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + + verts.append({{+1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{-1.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch plain_axes = [this]() { + Vector verts; + verts.append({{0.0f, -1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, +1.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{-1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{+1.0f, 0.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 0.0f, -1.0f}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 0.0f, +1.0f}, VCLASS_EMPTY_SCALED}); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch single_arrow = [this]() { + Vector verts; + float p[3][3] = {{0}}; + p[0][2] = 1.0f; + p[1][0] = 0.035f; + p[1][1] = 0.035f; + p[2][0] = -0.035f; + p[2][1] = 0.035f; + p[1][2] = p[2][2] = 0.75f; + for (int sides : IndexRange(4)) { + if (sides % 2 == 1) { + p[1][0] = -p[1][0]; + p[2][1] = -p[2][1]; + } + else { + p[1][1] = -p[1][1]; + p[2][0] = -p[2][0]; + } + for (int i = 0, a = 1; i < 2; i++, a++) { + verts.append({{p[i][0], p[i][1], p[i][2]}, VCLASS_EMPTY_SCALED}); + verts.append({{p[a][0], p[a][1], p[a][2]}, VCLASS_EMPTY_SCALED}); + } + } + verts.append({{0.0f, 0.0f, 0.0}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 0.0f, 0.75f}, VCLASS_EMPTY_SCALED}); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch cube = [this]() { + Vector verts; + for (auto index : bone_box_wire) { + float x = bone_box_verts[index][0]; + float y = bone_box_verts[index][1] * 2.0 - 1.0f; + float z = bone_box_verts[index][2]; + verts.append({{x, y, z}, VCLASS_EMPTY_SCALED}); + } + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch circle = [this]() { + constexpr int resolution = 64; + Vector ring = ring_vertices(1.0f, resolution); + + Vector verts; + for (int a : IndexRange(resolution + 1)) { + float2 cv = ring[a % resolution]; + verts.append({{cv.x, 0.0f, cv.y}, VCLASS_EMPTY_SCALED}); + } + return GPU_batch_create_ex( + GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch empty_sphere = [this]() { + Vector verts = sphere_axes_circles(1.0f, VCLASS_EMPTY_SCALED, 32); + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch empty_cone = [this]() { + /* A single ring of vertices. */ + constexpr int resolution = 8; + Vector ring = ring_vertices(1.0f, resolution); + + Vector verts; + for (int i : IndexRange(resolution)) { + float2 cv = ring[i % resolution]; + /* Cone sides. */ + verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED}); + verts.append({{0.0f, 2.0f, 0.0f}, VCLASS_EMPTY_SCALED}); + /* Base ring. */ + for (int j : IndexRange(2)) { + float2 cv = ring[(i + j) % resolution]; + verts.append({{cv[0], 0.0f, cv[1]}, VCLASS_EMPTY_SCALED}); + } + } + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); + + AutoFreeGPUBatch arrows = [this]() { + float2 x_axis_name_scale = {0.0215f, 0.025f}; + Vector x_axis_name = { + float2(0.9f, 1.0f) * x_axis_name_scale, + float2(-1.0f, -1.0f) * x_axis_name_scale, + float2(-0.9f, 1.0f) * x_axis_name_scale, + float2(1.0f, -1.0f) * x_axis_name_scale, + }; + + float2 y_axis_name_scale = {0.0175f, 0.025f}; + Vector y_axis_name = { + float2(-1.0f, 1.0f) * y_axis_name_scale, + float2(0.0f, -0.1f) * y_axis_name_scale, + float2(1.0f, 1.0f) * y_axis_name_scale, + float2(0.0f, -0.1f) * y_axis_name_scale, + float2(0.0f, -0.1f) * y_axis_name_scale, + float2(0.0f, -1.0f) * y_axis_name_scale, + }; + + float2 z_axis_name_scale = {0.02f, 0.025f}; + Vector z_axis_name = { + float2(-0.95f, 1.00f) * z_axis_name_scale, + float2(0.95f, 1.00f) * z_axis_name_scale, + float2(0.95f, 1.00f) * z_axis_name_scale, + float2(0.95f, 0.90f) * z_axis_name_scale, + float2(0.95f, 0.90f) * z_axis_name_scale, + float2(-1.00f, -0.90f) * z_axis_name_scale, + float2(-1.00f, -0.90f) * z_axis_name_scale, + float2(-1.00f, -1.00f) * z_axis_name_scale, + float2(-1.00f, -1.00f) * z_axis_name_scale, + float2(1.00f, -1.00f) * z_axis_name_scale, + }; + + float2 axis_marker_scale = {0.007f, 0.007f}; + Vector axis_marker = { +#if 0 /* square */ + float2(-1.0f, 1.0f) * axis_marker_scale, + float2(1.0f, 1.0f) * axis_marker_scale, + float2(1.0f, 1.0f) * axis_marker_scale, + float2(1.0f, -1.0f) * axis_marker_scale, + float2(1.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, 1.0f) * axis_marker_scale, +#else /* diamond */ + float2(-1.0f, 0.0f) * axis_marker_scale, + float2(0.0f, 1.0f) * axis_marker_scale, + float2(0.0f, 1.0f) * axis_marker_scale, + float2(1.0f, 0.0f) * axis_marker_scale, + float2(1.0f, 0.0f) * axis_marker_scale, + float2(0.0f, -1.0f) * axis_marker_scale, + float2(0.0f, -1.0f) * axis_marker_scale, + float2(-1.0f, 0.0f) * axis_marker_scale, +#endif + }; + + Vector verts; + for (int axis : IndexRange(3)) { + /* Vertex layout is XY screen position and axis in Z. + * Fractional part of Z is a positive offset at axis unit position. */ + int flag = VCLASS_EMPTY_AXES | VCLASS_SCREENALIGNED; + /* Center to axis line. */ + verts.append({{0.0f, 0.0f, 0.0f}, 0}); + verts.append({{0.0f, 0.0f, float(axis)}, flag}); + /* Axis end marker. */ + constexpr int marker_fill_layer = 6; + for (int j = 1; j < marker_fill_layer + 1; j++) { + for (float2 axis_marker_vert : axis_marker) { + verts.append({{axis_marker_vert * ((4.0f * j) / marker_fill_layer), float(axis)}, flag}); + } + } + /* Axis name. */ + Vector *axis_names[3] = {&x_axis_name, &y_axis_name, &z_axis_name}; + for (float2 axis_name_vert : *(axis_names[axis])) { + int flag = VCLASS_EMPTY_AXES | VCLASS_EMPTY_AXES_NAME | VCLASS_SCREENALIGNED; + verts.append({{axis_name_vert * 4.0f, axis + 0.25f}, flag}); + } + } + return GPU_batch_create_ex( + GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); +}; + +} // namespace blender::draw::overlay \ No newline at end of file diff --git a/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh index 9e6b6e5f737..aff132cd414 100644 --- a/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh +++ b/source/blender/draw/engines/overlay/shaders/infos/overlay_extra_info.hh @@ -13,6 +13,7 @@ GPU_SHADER_INTERFACE_INFO(overlay_extra_iface, "") GPU_SHADER_CREATE_INFO(overlay_extra) .do_static_compilation(true) + .typedef_source("overlay_shader_shared.h") .vertex_in(0, Type::VEC3, "pos") .vertex_in(1, Type::INT, "vclass") /* Instance attributes. */ diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 57939bd1f46..5e4e3c2cfaf 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -1270,11 +1270,11 @@ bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d, */ float ED_scene_grid_scale(const struct Scene *scene, const char **r_grid_unit); float ED_view3d_grid_scale(const struct Scene *scene, - struct View3D *v3d, + const struct View3D *v3d, const char **r_grid_unit); void ED_view3d_grid_steps(const struct Scene *scene, - struct View3D *v3d, - struct RegionView3D *rv3d, + const struct View3D *v3d, + const struct RegionView3D *rv3d, float r_grid_steps[8]); /** * Simulates the grid scale that is actually viewed. diff --git a/source/blender/editors/space_view3d/view3d_draw.cc b/source/blender/editors/space_view3d/view3d_draw.cc index b0590fba294..7ab3be7f89d 100644 --- a/source/blender/editors/space_view3d/view3d_draw.cc +++ b/source/blender/editors/space_view3d/view3d_draw.cc @@ -850,15 +850,15 @@ float ED_scene_grid_scale(const Scene *scene, const char **r_grid_unit) return 1.0f; } -float ED_view3d_grid_scale(const Scene *scene, View3D *v3d, const char **r_grid_unit) +float ED_view3d_grid_scale(const Scene *scene, const View3D *v3d, const char **r_grid_unit) { return v3d->grid * ED_scene_grid_scale(scene, r_grid_unit); } #define STEPS_LEN 8 void ED_view3d_grid_steps(const Scene *scene, - View3D *v3d, - RegionView3D *rv3d, + const View3D *v3d, + const RegionView3D *rv3d, float r_grid_steps[STEPS_LEN]) { const void *usys; -- 2.30.2 From 84ff44769f04926d031d2405da953d672b94e26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 28 Feb 2023 21:14:29 +0100 Subject: [PATCH 12/22] Overlay-Next: Add high level separation of selection code This makes it possible to reuse the overlay engine code for selection purpose, but without any overhead for the viewport drawing. The separation is made clear by having a dummy selection implementation for viewport drawing and an object implementation for object selection. Other impementation might come later (like for depth picking). --- .../engines/overlay/overlay_background.hh | 8 +- .../draw/engines/overlay/overlay_empty.hh | 73 +++++++------------ .../draw/engines/overlay/overlay_engine.cc | 24 +++--- .../draw/engines/overlay/overlay_grid.cc | 13 +++- .../draw/engines/overlay/overlay_grid.hh | 8 +- .../draw/engines/overlay/overlay_instance.cc | 17 +++-- .../draw/engines/overlay/overlay_instance.hh | 52 ++++++------- .../draw/engines/overlay/overlay_metaball.hh | 13 ++-- .../draw/engines/overlay/overlay_private.hh | 14 +--- .../engines/overlay/overlay_shader_shared.h | 1 - .../draw/engines/overlay/overlay_shape.hh | 35 +++++++++ .../draw/engines/select/select_empty.hh | 34 +++++++++ .../draw/engines/select/select_object.hh | 63 ++++++++++++++++ 13 files changed, 235 insertions(+), 120 deletions(-) create mode 100644 source/blender/draw/engines/select/select_empty.hh create mode 100644 source/blender/draw/engines/select/select_object.hh diff --git a/source/blender/draw/engines/overlay/overlay_background.hh b/source/blender/draw/engines/overlay/overlay_background.hh index 6ec212c108c..bcbb6576abe 100644 --- a/source/blender/draw/engines/overlay/overlay_background.hh +++ b/source/blender/draw/engines/overlay/overlay_background.hh @@ -19,12 +19,14 @@ namespace blender::draw::overlay { -class Background { +template class Background { + using ResourcesT = Resources; + private: PassSimple bg_ps_ = {"Background"}; public: - void begin_sync(Resources &res, const State &state) + void begin_sync(ResourcesT &res, const State &state) { DRWState pass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_BACKGROUND; float4 color_override(0.0f, 0.0f, 0.0f, 0.0f); @@ -92,7 +94,7 @@ class Background { } } - void draw(Resources &res, Manager &manager) + void draw(ResourcesT &res, Manager &manager) { GPU_framebuffer_bind(res.overlay_color_only_fb); manager.submit(bg_ps_); diff --git a/source/blender/draw/engines/overlay/overlay_empty.hh b/source/blender/draw/engines/overlay/overlay_empty.hh index 1c28f0cbaa3..4bb69a9dd54 100644 --- a/source/blender/draw/engines/overlay/overlay_empty.hh +++ b/source/blender/draw/engines/overlay/overlay_empty.hh @@ -15,14 +15,15 @@ namespace blender::draw::overlay { -class Empties { +template class Empties { + using SelectID = typename SelectEngineT::ID; + using ResourcesT = Resources; + using EmptyInstanceBuf = ShapeInstanceBuf; private: PassSimple empty_ps_ = {"Empties"}; PassSimple empty_in_front_ps_ = {"Empties_In_front"}; - using EmptyInstanceBuf = StorageVectorBuffer; - struct CallBuffers { EmptyInstanceBuf plain_axes_buf = {"plain_axes_buf"}; EmptyInstanceBuf single_arrow_buf = {"single_arrow_buf"}; @@ -49,7 +50,7 @@ class Empties { } } - void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state) + void object_sync(const ObjectRef &ob_ref, ResourcesT &res, const State &state) { CallBuffers &call_bufs = call_buffers_[int((ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0)]; @@ -57,36 +58,39 @@ class Empties { ExtraInstanceData data( float4x4(ob_ref.object->object_to_world), color, ob_ref.object->empty_drawsize); + /* TODO(fclem): Get selection ID from the selection engine. */ + const SelectID select_id = res.select_id(ob_ref); + switch (ob_ref.object->empty_drawtype) { case OB_PLAINAXES: - call_bufs.plain_axes_buf.append(data); + call_bufs.plain_axes_buf.append(data, select_id); break; case OB_SINGLE_ARROW: - call_bufs.single_arrow_buf.append(data); + call_bufs.single_arrow_buf.append(data, select_id); break; case OB_CUBE: - call_bufs.cube_buf.append(data); + call_bufs.cube_buf.append(data, select_id); break; case OB_CIRCLE: - call_bufs.circle_buf.append(data); + call_bufs.circle_buf.append(data, select_id); break; case OB_EMPTY_SPHERE: - call_bufs.sphere_buf.append(data); + call_bufs.sphere_buf.append(data, select_id); break; case OB_EMPTY_CONE: - call_bufs.cone_buf.append(data); + call_bufs.cone_buf.append(data, select_id); break; case OB_ARROWS: - call_bufs.arrows_buf.append(data); + call_bufs.arrows_buf.append(data, select_id); break; case OB_EMPTY_IMAGE: /* This only show the frame. See OVERLAY_image_empty_cache_populate() for the image. */ - call_bufs.image_buf.append(data); + call_bufs.image_buf.append(data, select_id); break; } } - void end_sync(Resources &res, ShapeCache &shapes, const State &state) + void end_sync(ResourcesT &res, ShapeCache &shapes, const State &state) { auto init_pass = [&](PassSimple &pass, CallBuffers &call_bufs) { pass.init(); @@ -95,49 +99,26 @@ class Empties { pass.shader_set(OVERLAY_shader_extra(false)); pass.bind_ubo("globalsBlock", &res.globals_buf); - call_bufs.plain_axes_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.plain_axes_buf); - pass.draw(shapes.plain_axes, call_bufs.plain_axes_buf.size()); - - call_bufs.single_arrow_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.single_arrow_buf); - pass.draw(shapes.single_arrow, call_bufs.single_arrow_buf.size()); - - call_bufs.cube_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.cube_buf); - pass.draw(shapes.cube, call_bufs.cube_buf.size()); - - call_bufs.circle_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.circle_buf); - pass.draw(shapes.circle, call_bufs.circle_buf.size()); - - call_bufs.sphere_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.sphere_buf); - pass.draw(shapes.empty_sphere, call_bufs.sphere_buf.size()); - - call_bufs.cone_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.cone_buf); - pass.draw(shapes.empty_cone, call_bufs.cone_buf.size()); - - call_bufs.arrows_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.arrows_buf); - pass.draw(shapes.arrows, call_bufs.arrows_buf.size()); - - call_bufs.image_buf.push_update(); - pass.bind_ssbo("data_buf", &call_bufs.image_buf); - pass.draw(shapes.quad_wire, call_bufs.image_buf.size()); + call_bufs.plain_axes_buf.end_sync(pass, shapes.plain_axes); + call_bufs.single_arrow_buf.end_sync(pass, shapes.single_arrow); + call_bufs.cube_buf.end_sync(pass, shapes.cube); + call_bufs.circle_buf.end_sync(pass, shapes.circle); + call_bufs.sphere_buf.end_sync(pass, shapes.empty_sphere); + call_bufs.cone_buf.end_sync(pass, shapes.empty_cone); + call_bufs.arrows_buf.end_sync(pass, shapes.arrows); + call_bufs.image_buf.end_sync(pass, shapes.quad_wire); }; init_pass(empty_ps_, call_buffers_[0]); init_pass(empty_in_front_ps_, call_buffers_[1]); } - void draw(Resources &res, Manager &manager, View &view) + void draw(ResourcesT &res, Manager &manager, View &view) { GPU_framebuffer_bind(res.overlay_line_fb); manager.submit(empty_ps_, view); } - void draw_in_front(Resources &res, Manager &manager, View &view) + void draw_in_front(ResourcesT &res, Manager &manager, View &view) { GPU_framebuffer_bind(res.overlay_line_in_front_fb); manager.submit(empty_in_front_ps_, view); diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc index 9c08e608038..94976b104bc 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -30,6 +30,10 @@ #include "overlay_engine.h" #include "overlay_private.hh" +using namespace blender::draw; + +using Instance = blender::draw::overlay::Instance<>; + /* -------------------------------------------------------------------- */ /** \name Engine Callbacks * \{ */ @@ -51,7 +55,7 @@ static void OVERLAY_engine_init(void *vedata) /* Allocate instance. */ if (data->instance == nullptr) { - data->instance = new blender::draw::overlay::Instance(); + data->instance = new Instance(); } OVERLAY_PrivateData *pd = stl->pd; @@ -737,7 +741,7 @@ static void OVERLAY_engine_free() static void OVERLAY_instance_free(void *instance_) { - blender::draw::overlay::Instance *instance = (blender::draw::overlay::Instance *)instance_; + auto *instance = (Instance *)instance_; if (instance != nullptr) { delete instance; } @@ -748,8 +752,6 @@ static void OVERLAY_instance_free(void *instance_) /** \name Engine Instance * \{ */ -using namespace blender::draw; - static void OVERLAY_next_engine_init(void *vedata) { if (!GPU_shader_storage_buffer_objects_support()) { @@ -759,10 +761,10 @@ static void OVERLAY_next_engine_init(void *vedata) OVERLAY_Data *ved = reinterpret_cast(vedata); if (ved->instance == nullptr) { - ved->instance = new overlay::Instance(); + ved->instance = new Instance(); } - ved->instance->init(); + reinterpret_cast(ved->instance)->init(); } static void OVERLAY_next_cache_init(void *vedata) @@ -770,7 +772,7 @@ static void OVERLAY_next_cache_init(void *vedata) if (!GPU_shader_storage_buffer_objects_support()) { return; } - reinterpret_cast(vedata)->instance->begin_sync(); + reinterpret_cast(reinterpret_cast(vedata)->instance)->begin_sync(); } static void OVERLAY_next_cache_populate(void *vedata, Object *object) @@ -783,7 +785,8 @@ static void OVERLAY_next_cache_populate(void *vedata, Object *object) ref.dupli_object = DRW_object_get_dupli(object); ref.dupli_parent = DRW_object_get_dupli_parent(object); - reinterpret_cast(vedata)->instance->object_sync(ref); + reinterpret_cast(reinterpret_cast(vedata)->instance) + ->object_sync(ref); } static void OVERLAY_next_cache_finish(void *vedata) @@ -791,7 +794,7 @@ static void OVERLAY_next_cache_finish(void *vedata) if (!GPU_shader_storage_buffer_objects_support()) { return; } - reinterpret_cast(vedata)->instance->end_sync(); + reinterpret_cast(reinterpret_cast(vedata)->instance)->end_sync(); } static void OVERLAY_next_draw_scene(void *vedata) @@ -800,7 +803,8 @@ static void OVERLAY_next_draw_scene(void *vedata) return; } - reinterpret_cast(vedata)->instance->draw(*DRW_manager_get()); + reinterpret_cast(reinterpret_cast(vedata)->instance) + ->draw(*DRW_manager_get()); } /** \} */ diff --git a/source/blender/draw/engines/overlay/overlay_grid.cc b/source/blender/draw/engines/overlay/overlay_grid.cc index 232ad995fde..6a688a02f4e 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.cc +++ b/source/blender/draw/engines/overlay/overlay_grid.cc @@ -20,6 +20,10 @@ #include "overlay_instance.hh" #include "overlay_private.hh" +using namespace blender::draw; + +using Instance = blender::draw::overlay::Instance<>; + BLI_STATIC_ASSERT(SI_GRID_STEPS_LEN == OVERLAY_GRID_STEPS_LEN, "") void OVERLAY_grid_init(OVERLAY_Data *vedata) @@ -226,10 +230,11 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *ved) return; } - if (ved->instance->grid_ubo == nullptr) { - ved->instance->grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData)); + GPUUniformBuf *&grid_ubo = reinterpret_cast(ved->instance)->grid_ubo; + if (grid_ubo == nullptr) { + grid_ubo = GPU_uniformbuf_create(sizeof(OVERLAY_GridData)); } - GPU_uniformbuf_update(ved->instance->grid_ubo, &pd->grid_data); + GPU_uniformbuf_update(grid_ubo, &pd->grid_data); DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; DRW_PASS_CREATE(psl->grid_ps, state); @@ -259,7 +264,7 @@ void OVERLAY_grid_cache_init(OVERLAY_Data *ved) /* Create 3 quads to render ordered transparency Z axis */ grp = DRW_shgroup_create(sh, psl->grid_ps); - DRW_shgroup_uniform_block(grp, "grid_buf", ved->instance->grid_ubo); + DRW_shgroup_uniform_block(grp, "grid_buf", grid_ubo); DRW_shgroup_uniform_block(grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_texture_ref(grp, "depth_tx", &dtxl->depth); diff --git a/source/blender/draw/engines/overlay/overlay_grid.hh b/source/blender/draw/engines/overlay/overlay_grid.hh index 25db8193b4d..e5e9c183b40 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.hh +++ b/source/blender/draw/engines/overlay/overlay_grid.hh @@ -18,7 +18,9 @@ namespace blender::draw::overlay { -class Grid { +template class Grid { + using ResourcesT = Resources; + private: UniformBuffer data_; @@ -164,7 +166,7 @@ class Grid { data_.push_update(); } - void begin_sync(Resources &res, const State &state, const View &view) + void begin_sync(ResourcesT &res, const State &state, const View &view) { this->update_ubo(state, view); @@ -195,7 +197,7 @@ class Grid { } } - void draw(Resources &res, Manager &manager, View &view) + void draw(ResourcesT &res, Manager &manager, View &view) { if (!enabled_) { return; diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 0726ea2b74a..cbbea3dbf99 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -10,7 +10,7 @@ namespace blender::draw::overlay { -void Instance::init() +template void Instance::init() { resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth); resources.depth_in_front_tx.wrap(DRW_viewport_texture_list_get()->depth_in_front); @@ -65,7 +65,7 @@ void Instance::init() resources.theme_settings = G_draw.block; } -void Instance::begin_sync() +template void Instance::begin_sync() { const DRWView *view_legacy = DRW_view_default_get(); View view("OverlayView", view_legacy); @@ -76,7 +76,7 @@ void Instance::begin_sync() grid.begin_sync(resources, state, view); } -void Instance::object_sync(ObjectRef &ob_ref) +template void Instance::object_sync(ObjectRef &ob_ref) { const bool in_edit_mode = object_is_edit_mode(ob_ref.object); @@ -120,13 +120,13 @@ void Instance::object_sync(ObjectRef &ob_ref) } } -void Instance::end_sync() +template void Instance::end_sync() { metaballs.end_sync(resources, state); empties.end_sync(resources, shapes, state); } -void Instance::draw(Manager &manager) +template void Instance::draw(Manager &manager) { /* WORKAROUND: This is to prevent crashes when using depth picking or selection. * The selection engine should handle theses cases instead. */ @@ -182,4 +182,11 @@ void Instance::draw(Manager &manager) resources.depth_in_front_alloc_tx.release(); } +/* Instantiation. */ +template void Instance<>::init(); +template void Instance<>::begin_sync(); +template void Instance<>::object_sync(ObjectRef &ob_ref); +template void Instance<>::end_sync(); +template void Instance<>::draw(Manager &manager); + } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index c90494f6c75..bd5397e1f4a 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -14,6 +14,9 @@ #include "overlay_metaball.hh" #include "overlay_shape.hh" +#include "../select/select_empty.hh" +#include "../select/select_object.hh" + namespace blender::draw::overlay { class ShaderCache { @@ -22,32 +25,12 @@ class ShaderCache { int clipping_enabled = 0; }; -class SceneResources { - ShaderCache shaders; - - // UniformBuffer theme_colors; - // Texture color_ramp = {"color_ramp"}; - - void weight_ramp_init() - { - /* Weight Painting color ramp texture */ - // bool user_weight_ramp = (U.flag & USER_CUSTOM_RANGE) != 0; - - // if (weight_ramp_custom != user_weight_ramp || - // (user_weight_ramp && memcmp(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)) != 0)) - // { - // DRW_TEXTURE_FREE_SAFE(G_draw.weight_ramp); - // } - - // if (G_draw.weight_ramp == NULL) { - // weight_ramp_custom = user_weight_ramp; - // memcpy(&weight_ramp_copy, &U.coba_weight, sizeof(ColorBand)); - - // G_draw.weight_ramp = DRW_create_weight_colorramp_texture(); - // } - } -}; - +template< + /* Selection engine reuse most of the Overlay engine by creating selection IDs for each + * selectable component and using a special shaders for drawing. + * Making the select engine templated makes it easier to phase out any overhead of the + * selection for the regular non-selection case.*/ + typename SelectEngineT = select::EngineEmpty> class Instance { public: ShaderCache shaders; @@ -57,14 +40,14 @@ class Instance { GPUUniformBuf *grid_ubo = nullptr; /** Global types. */ - Resources resources; + Resources resources; State state; /** Overlay types. */ - Background background; - Metaballs metaballs; - Empties empties; - Grid grid; + Background background; + Metaballs metaballs; + Empties empties; + Grid grid; ~Instance() { @@ -109,4 +92,11 @@ class Instance { } }; +/* Instantiation. */ +extern template void Instance<>::init(); +extern template void Instance<>::begin_sync(); +extern template void Instance<>::object_sync(ObjectRef &ob_ref); +extern template void Instance<>::end_sync(); +extern template void Instance<>::draw(Manager &manager); + } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index df7bab02a70..b08987db180 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -19,7 +19,8 @@ namespace blender::draw::overlay { -class Metaballs { +template class Metaballs { + using ResourcesT = Resources; private: PassSimple metaball_ps_ = {"MetaBalls"}; @@ -50,7 +51,7 @@ class Metaballs { OVERLAY_bone_instance_data_set_color(data, color); } - void edit_object_sync(const ObjectRef &ob_ref, const Resources &res) + void edit_object_sync(const ObjectRef &ob_ref, const ResourcesT &res) { ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? data_in_front_buf_ : @@ -79,7 +80,7 @@ class Metaballs { } } - void object_sync(const ObjectRef &ob_ref, const Resources &res, const State &state) + void object_sync(const ObjectRef &ob_ref, const ResourcesT &res, const State &state) { ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? data_in_front_buf_ : @@ -96,7 +97,7 @@ class Metaballs { } } - void end_sync(Resources &res, const State &state) + void end_sync(ResourcesT &res, const State &state) { auto init_pass = [&](PassSimple &pass, ArmatureSphereBuf &data_buf) { data_buf.push_update(); @@ -113,13 +114,13 @@ class Metaballs { init_pass(metaball_in_front_ps_, data_in_front_buf_); } - void draw(Resources &res, Manager &manager, View &view) + void draw(ResourcesT &res, Manager &manager, View &view) { GPU_framebuffer_bind(res.overlay_line_fb); manager.submit(metaball_ps_, view); } - void draw_in_front(Resources &res, Manager &manager, View &view) + void draw_in_front(ResourcesT &res, Manager &manager, View &view) { GPU_framebuffer_bind(res.overlay_line_in_front_fb); manager.submit(metaball_in_front_ps_, view); diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index df4bcadfe1f..1381c9942cd 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -18,10 +18,6 @@ #include "overlay_shader_shared.h" -#ifdef __cplusplus -extern "C" { -#endif - #ifdef __APPLE__ # define USE_GEOM_SHADER_WORKAROUND 1 #else @@ -35,7 +31,7 @@ extern "C" { struct ImBuf; namespace blender::draw::overlay { -class Instance; +template class Instance; struct State { Depsgraph *depsgraph; @@ -68,7 +64,7 @@ using blender::draw::TextureFromPool; using blender::draw::TextureRef; using ArmatureSphereBuf = StorageVectorBuffer; -struct Resources { +template struct Resources : public SelectEngineT::SelectMap { Framebuffer overlay_fb = {"overlay_fb"}; Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"}; Framebuffer overlay_color_only_fb = {"overlay_color_only_fb"}; @@ -578,7 +574,7 @@ typedef struct OVERLAY_Data { OVERLAY_PassList *psl; OVERLAY_StorageList *stl; - blender::draw::overlay::Instance *instance; + void *instance; } OVERLAY_Data; typedef struct OVERLAY_DupliData { @@ -927,7 +923,3 @@ GPUShader *OVERLAY_shader_xray_fade(void); OVERLAY_InstanceFormats *OVERLAY_shader_instance_formats_get(void); void OVERLAY_shader_free(void); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/draw/engines/overlay/overlay_shader_shared.h b/source/blender/draw/engines/overlay/overlay_shader_shared.h index 5f00bec79c8..c38de0a1057 100644 --- a/source/blender/draw/engines/overlay/overlay_shader_shared.h +++ b/source/blender/draw/engines/overlay/overlay_shader_shared.h @@ -192,7 +192,6 @@ struct ThemeColorData { }; BLI_STATIC_ASSERT_ALIGN(ThemeColorData, 16) -/* TODO Move to overlay engine. */ struct ExtraInstanceData { float4 color_; float4x4 object_to_world_; diff --git a/source/blender/draw/engines/overlay/overlay_shape.hh b/source/blender/draw/engines/overlay/overlay_shape.hh index eb23d3e71a2..83d32d2728c 100644 --- a/source/blender/draw/engines/overlay/overlay_shape.hh +++ b/source/blender/draw/engines/overlay/overlay_shape.hh @@ -12,6 +12,41 @@ namespace blender::draw::overlay { +/** + * Buffer containing instances of a certain shape. + */ +template +struct ShapeInstanceBuf : private SelectEngineT::SelectBuf { + using SelectID = typename SelectEngineT::ID; + + StorageVectorBuffer data_buf; + + ShapeInstanceBuf(const char *name = nullptr) : data_buf(name){}; + + void clear() + { + this->select_clear(); + data_buf.clear(); + } + + void append(const InstanceDataT &data, SelectID select_id) + { + this->select_append(select_id); + data_buf.append(data); + } + + void end_sync(PassSimple &pass, GPUBatch *shape) + { + if (data_buf.size() == 0) { + return; + } + this->select_bind(pass); + data_buf.push_update(); + pass.bind_ssbo("data_buf", &data_buf); + pass.draw(shape, data_buf.size()); + } +}; + /** * Contains all overlay generic geometry batches. */ diff --git a/source/blender/draw/engines/select/select_empty.hh b/source/blender/draw/engines/select/select_empty.hh new file mode 100644 index 00000000000..cde820c4978 --- /dev/null +++ b/source/blender/draw/engines/select/select_empty.hh @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + * + * Dummy implementation of the select engine types to avoid any overhead. + */ + +#pragma once + +#include "draw_manager.hh" + +namespace blender::draw::select { + +struct EngineEmpty { + /* Add type safety to selection ID. Only the select engine should provide them. */ + struct ID {}; + + struct SelectBuf { + void select_clear(){}; + void select_append(ID){}; + void select_bind(PassSimple &){}; + }; + + struct SelectMap { + [[nodiscard]] constexpr ID select_id(const ObjectRef &) + { + return {}; + } + }; +}; + +} // namespace blender::draw::select \ No newline at end of file diff --git a/source/blender/draw/engines/select/select_object.hh b/source/blender/draw/engines/select/select_object.hh new file mode 100644 index 00000000000..feb77dd5ca6 --- /dev/null +++ b/source/blender/draw/engines/select/select_object.hh @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. */ + +/** \file + * \ingroup draw_engine + * + * This is an implementation of the Select engine specialized for selecting object. + * Should plug seamlessly inside the overlay engine logic. + */ + +#pragma once + +#include "DRW_gpu_wrapper.hh" +#include "draw_manager.hh" + +namespace blender::draw::select { + +struct EngineObject { + /* Add type safety to selection ID. Only the select engine should provide them. */ + struct ID { + uint32_t value; + }; + + /** + * Add a dedicated selection id buffer to a pass. + * Use this when not using a #PassMain which can pass the select ID via CustomID. + */ + struct SelectBuf { + StorageVectorBuffer select_buf = {"select_buf"}; + + void select_clear() + { + select_buf.clear(); + } + + void select_append(ID select_id) + { + select_buf.append(select_id.value); + } + + void select_bind(PassSimple &pass) + { + select_buf.push_update(); + pass.bind_ssbo("select_buf", &select_buf); + } + }; + + /** + * Generate selection IDs from objects and keep record of the mapping between them. + */ + struct SelectMap { + uint next_id = 0; + Map map; + + [[nodiscard]] const ID select_id(const ObjectRef &) + { + /* TODO Insert Ref into the map. */ + return {next_id++}; + } + }; +}; + +} // namespace blender::draw::select \ No newline at end of file -- 2.30.2 From 68a0f9e01cd8eb6d43b6d6a8b5c92c911b4ecc7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 28 Feb 2023 22:14:32 +0100 Subject: [PATCH 13/22] Overlay-Next: Port Metaball code to use latest design and support selectid --- .../draw/engines/overlay/overlay_empty.hh | 1 - .../draw/engines/overlay/overlay_instance.cc | 17 ++++- .../draw/engines/overlay/overlay_metaball.hh | 63 +++++++------------ .../draw/engines/overlay/overlay_private.hh | 10 ++- .../draw/engines/overlay/overlay_shape.hh | 15 +++++ .../draw/engines/select/select_empty.hh | 2 +- .../draw/engines/select/select_object.hh | 6 +- 7 files changed, 66 insertions(+), 48 deletions(-) diff --git a/source/blender/draw/engines/overlay/overlay_empty.hh b/source/blender/draw/engines/overlay/overlay_empty.hh index 4bb69a9dd54..acddc00df4e 100644 --- a/source/blender/draw/engines/overlay/overlay_empty.hh +++ b/source/blender/draw/engines/overlay/overlay_empty.hh @@ -58,7 +58,6 @@ template class Empties { ExtraInstanceData data( float4x4(ob_ref.object->object_to_world), color, ob_ref.object->empty_drawsize); - /* TODO(fclem): Get selection ID from the selection engine. */ const SelectID select_id = res.select_id(ob_ref); switch (ob_ref.object->empty_drawtype) { diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index cbbea3dbf99..2414d2ed5f6 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -122,7 +122,7 @@ template void Instance::object_sync(ObjectRef &ob_ref) template void Instance::end_sync() { - metaballs.end_sync(resources, state); + metaballs.end_sync(resources, shapes, state); empties.end_sync(resources, shapes, state); } @@ -190,3 +190,18 @@ template void Instance<>::end_sync(); template void Instance<>::draw(Manager &manager); } // namespace blender::draw::overlay + +/* TODO(fclem): Move elsewhere. */ +BoneInstanceData::BoneInstanceData(Object *ob, + const float *pos, + const float radius, + const float color[4]) +{ + /* TODO(fclem): Use C++ math API. */ + mul_v3_v3fl(this->mat[0], ob->object_to_world[0], radius); + mul_v3_v3fl(this->mat[1], ob->object_to_world[1], radius); + mul_v3_v3fl(this->mat[2], ob->object_to_world[2], radius); + mul_v3_m4v3(this->mat[3], ob->object_to_world, pos); + /* WATCH: Reminder, alpha is wire-size. */ + OVERLAY_bone_instance_data_set_color(this, color); +} diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index b08987db180..3f0eb35cdde 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -7,8 +7,8 @@ #pragma once #include "DEG_depsgraph_query.h" -#include "DNA_camera_types.h" #include "DNA_space_types.h" +#include "ED_mball.h" #include "ED_view3d.h" #include "UI_resources.h" @@ -20,14 +20,16 @@ namespace blender::draw::overlay { template class Metaballs { + using SelectID = typename SelectEngineT::ID; using ResourcesT = Resources; + using SphereOutlineInstanceBuf = ShapeInstanceBuf; private: PassSimple metaball_ps_ = {"MetaBalls"}; PassSimple metaball_in_front_ps_ = {"MetaBalls_In_front"}; - ArmatureSphereBuf data_buf_ = {"metaball_data_buf"}; - ArmatureSphereBuf data_in_front_buf_ = {"metaball_data_buf"}; + SphereOutlineInstanceBuf data_buf_ = {"metaball_data_buf"}; + SphereOutlineInstanceBuf data_in_front_buf_ = {"metaball_data_buf"}; public: void begin_sync() @@ -36,26 +38,11 @@ template class Metaballs { data_in_front_buf_.clear(); } - void metaball_instance_data_set(BoneInstanceData *data, - Object *ob, - const float *pos, - const float radius, - const float color[4]) + void edit_object_sync(const ObjectRef &ob_ref, ResourcesT &res) { - /* Bone point radius is 0.05. Compensate for that. */ - mul_v3_v3fl(data->mat[0], ob->object_to_world[0], radius / 0.05f); - mul_v3_v3fl(data->mat[1], ob->object_to_world[1], radius / 0.05f); - mul_v3_v3fl(data->mat[2], ob->object_to_world[2], radius / 0.05f); - mul_v3_m4v3(data->mat[3], ob->object_to_world, pos); - /* WATCH: Reminder, alpha is wire-size. */ - OVERLAY_bone_instance_data_set_color(data, color); - } - - void edit_object_sync(const ObjectRef &ob_ref, const ResourcesT &res) - { - ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? - data_in_front_buf_ : - data_buf_; + SphereOutlineInstanceBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? + data_in_front_buf_ : + data_buf_; MetaBall *mb = static_cast(ob_ref.object->data); const float *color; @@ -68,47 +55,43 @@ template class Metaballs { const bool is_selected = (ml->flag & SELECT) != 0; const bool is_scale_radius = (ml->flag & MB_SCALE_RAD) != 0; float stiffness_radius = ml->rad * atanf(ml->s) / float(M_PI_2); - BoneInstanceData instdata; + const SelectID radius_id = res.select_id(ob_ref, MBALLSEL_RADIUS); color = (is_selected && is_scale_radius) ? col_radius_select : col_radius; - metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, ml->rad, color); - data_buf.append(*reinterpret_cast(&instdata)); + data_buf.append({ob_ref.object, &ml->x, ml->rad, color}, radius_id); + const SelectID stiff_id = res.select_id(ob_ref, MBALLSEL_STIFF); color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness; - metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, stiffness_radius, color); - data_buf.append(*reinterpret_cast(&instdata)); + data_buf.append({ob_ref.object, &ml->x, stiffness_radius, color}, stiff_id); } } - void object_sync(const ObjectRef &ob_ref, const ResourcesT &res, const State &state) + void object_sync(const ObjectRef &ob_ref, ResourcesT &res, const State &state) { - ArmatureSphereBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? - data_in_front_buf_ : - data_buf_; + SphereOutlineInstanceBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? + data_in_front_buf_ : + data_buf_; MetaBall *mb = static_cast(ob_ref.object->data); const float4 &color = res.object_wire_color(ob_ref, state); + const SelectID select_id = res.select_id(ob_ref); LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { /* Draw radius only. */ - BoneInstanceData instdata; - metaball_instance_data_set(&instdata, ob_ref.object, &ml->x, ml->rad, color); - data_buf.append(*reinterpret_cast(&instdata)); + data_buf.append({ob_ref.object, &ml->x, ml->rad, color}, select_id); } } - void end_sync(ResourcesT &res, const State &state) + void end_sync(ResourcesT &res, ShapeCache &shapes, const State &state) { - auto init_pass = [&](PassSimple &pass, ArmatureSphereBuf &data_buf) { - data_buf.push_update(); - + auto init_pass = [&](PassSimple &pass, SphereOutlineInstanceBuf &call_buf) { pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state); pass.shader_set(OVERLAY_shader_armature_sphere(true)); pass.bind_ubo("globalsBlock", &res.globals_buf); - pass.bind_ssbo("data_buf", &data_buf); - pass.draw(DRW_cache_bone_point_wire_outline_get(), data_buf.size()); + + call_buf.end_sync(pass, shapes.metaball_wire_circle); }; init_pass(metaball_ps_, data_buf_); init_pass(metaball_in_front_ps_, data_in_front_buf_); diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index 1381c9942cd..d1e7b520a1d 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -62,7 +62,6 @@ using blender::draw::StorageVectorBuffer; using blender::draw::Texture; using blender::draw::TextureFromPool; using blender::draw::TextureRef; -using ArmatureSphereBuf = StorageVectorBuffer; template struct Resources : public SelectEngineT::SelectMap { Framebuffer overlay_fb = {"overlay_fb"}; @@ -587,7 +586,7 @@ typedef struct OVERLAY_DupliData { short base_flag; } OVERLAY_DupliData; -typedef struct BoneInstanceData { +struct BoneInstanceData { /* Keep sync with bone instance vertex format (OVERLAY_InstanceFormats) */ union { float mat[4][4]; @@ -604,7 +603,12 @@ typedef struct BoneInstanceData { float _pad03[3], amax_b; }; }; -} BoneInstanceData; + + BoneInstanceData() = default; + /* Constructor used by metaball overlays and expected to be used for drawing + * metaball_wire_sphere with armature wire shader that produces wide-lines. */ + BoneInstanceData(Object *ob, const float *pos, const float radius, const float color[4]); +}; typedef struct OVERLAY_InstanceFormats { struct GPUVertFormat *instance_pos; diff --git a/source/blender/draw/engines/overlay/overlay_shape.hh b/source/blender/draw/engines/overlay/overlay_shape.hh index 83d32d2728c..34de3c9858a 100644 --- a/source/blender/draw/engines/overlay/overlay_shape.hh +++ b/source/blender/draw/engines/overlay/overlay_shape.hh @@ -360,6 +360,21 @@ class ShapeCache { return GPU_batch_create_ex( GPU_PRIM_LINES, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); }(); + + AutoFreeGPUBatch metaball_wire_circle = [this]() { + /* A single ring of vertices. */ + constexpr int resolution = 64; + constexpr float radius = 1.0f; + Vector ring = ring_vertices(radius, resolution); + + Vector verts; + for (int i : IndexRange(resolution + 1)) { + float2 cv = ring[i % resolution]; + verts.append({{cv[0], cv[1], 0.0f}, VCLASS_SCREENALIGNED}); + } + return GPU_batch_create_ex( + GPU_PRIM_LINE_STRIP, vbo_from_vector(verts), nullptr, GPU_BATCH_OWNS_VBO); + }(); }; } // namespace blender::draw::overlay \ No newline at end of file diff --git a/source/blender/draw/engines/select/select_empty.hh b/source/blender/draw/engines/select/select_empty.hh index cde820c4978..50766ccbb9a 100644 --- a/source/blender/draw/engines/select/select_empty.hh +++ b/source/blender/draw/engines/select/select_empty.hh @@ -24,7 +24,7 @@ struct EngineEmpty { }; struct SelectMap { - [[nodiscard]] constexpr ID select_id(const ObjectRef &) + [[nodiscard]] const ID select_id(const ObjectRef &, uint = 0) { return {}; } diff --git a/source/blender/draw/engines/select/select_object.hh b/source/blender/draw/engines/select/select_object.hh index feb77dd5ca6..66362bd9da6 100644 --- a/source/blender/draw/engines/select/select_object.hh +++ b/source/blender/draw/engines/select/select_object.hh @@ -52,10 +52,12 @@ struct EngineObject { uint next_id = 0; Map map; - [[nodiscard]] const ID select_id(const ObjectRef &) + /* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object + * reference directly. */ + [[nodiscard]] const ID select_id(const ObjectRef &, uint sub_object_id = 0) { /* TODO Insert Ref into the map. */ - return {next_id++}; + return {sub_object_id | next_id++}; } }; }; -- 2.30.2 From 78ae27bab3cf1b0939a94162d18128bf1f831c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Tue, 28 Feb 2023 23:00:59 +0100 Subject: [PATCH 14/22] Overlay-Next: Add depth Prepass basics The depth prepass is supposed to replace the Basic engine: - Draw object depth when the engine doesn't give correct depth buffer - Used for object selection --- .../draw/engines/overlay/overlay_engine.cc | 2 +- .../draw/engines/overlay/overlay_instance.cc | 21 +++++- .../draw/engines/overlay/overlay_instance.hh | 6 +- .../draw/engines/overlay/overlay_metaball.hh | 30 ++++---- .../draw/engines/overlay/overlay_prepass.hh | 71 +++++++++++++++++++ .../draw/engines/overlay/overlay_shader.cc | 10 +++ 6 files changed, 120 insertions(+), 20 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_prepass.hh diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc index 94976b104bc..c344bf498b1 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -786,7 +786,7 @@ static void OVERLAY_next_cache_populate(void *vedata, Object *object) ref.dupli_parent = DRW_object_get_dupli_parent(object); reinterpret_cast(reinterpret_cast(vedata)->instance) - ->object_sync(ref); + ->object_sync(ref, *DRW_manager_get()); } static void OVERLAY_next_cache_finish(void *vedata) diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 2414d2ed5f6..bc4eb7327a6 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -71,14 +71,28 @@ template void Instance::begin_sync() View view("OverlayView", view_legacy); background.begin_sync(resources, state); + prepass.begin_sync(state); empties.begin_sync(); metaballs.begin_sync(); grid.begin_sync(resources, state, view); } -template void Instance::object_sync(ObjectRef &ob_ref) +template void Instance::object_sync(ObjectRef &ob_ref, Manager &manager) { const bool in_edit_mode = object_is_edit_mode(ob_ref.object); + const bool needs_prepass = true; /* TODO */ + + if (needs_prepass) { + switch (ob_ref.object->type) { + case OB_MESH: + case OB_SURF: + case OB_CURVES: + case OB_FONT: + case OB_CURVES_LEGACY: + prepass.object_sync(manager, ob_ref, resources); + break; + } + } if (in_edit_mode && !state.hide_overlays) { switch (ob_ref.object->type) { @@ -166,6 +180,9 @@ template void Instance::draw(Manager &manager) float4 clear_color(0.0f); GPU_framebuffer_clear_color(resources.overlay_color_only_fb, clear_color); + prepass.draw(resources, manager, view); + prepass.draw_in_front(resources, manager, view); + background.draw(resources, manager); empties.draw(resources, manager, view); @@ -185,7 +202,7 @@ template void Instance::draw(Manager &manager) /* Instantiation. */ template void Instance<>::init(); template void Instance<>::begin_sync(); -template void Instance<>::object_sync(ObjectRef &ob_ref); +template void Instance<>::object_sync(ObjectRef &ob_ref, Manager &manager); template void Instance<>::end_sync(); template void Instance<>::draw(Manager &manager); diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index bd5397e1f4a..31808843e6f 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -12,6 +12,7 @@ #include "overlay_empty.hh" #include "overlay_grid.hh" #include "overlay_metaball.hh" +#include "overlay_prepass.hh" #include "overlay_shape.hh" #include "../select/select_empty.hh" @@ -45,6 +46,7 @@ class Instance { /** Overlay types. */ Background background; + Prepass prepass; Metaballs metaballs; Empties empties; Grid grid; @@ -56,7 +58,7 @@ class Instance { void init(); void begin_sync(); - void object_sync(ObjectRef &ob_ref); + void object_sync(ObjectRef &ob_ref, Manager &manager); void end_sync(); void draw(Manager &manager); @@ -95,7 +97,7 @@ class Instance { /* Instantiation. */ extern template void Instance<>::init(); extern template void Instance<>::begin_sync(); -extern template void Instance<>::object_sync(ObjectRef &ob_ref); +extern template void Instance<>::object_sync(ObjectRef &ob_ref, Manager &manager); extern template void Instance<>::end_sync(); extern template void Instance<>::draw(Manager &manager); diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index 3f0eb35cdde..ff1b95e7249 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -28,21 +28,21 @@ template class Metaballs { PassSimple metaball_ps_ = {"MetaBalls"}; PassSimple metaball_in_front_ps_ = {"MetaBalls_In_front"}; - SphereOutlineInstanceBuf data_buf_ = {"metaball_data_buf"}; - SphereOutlineInstanceBuf data_in_front_buf_ = {"metaball_data_buf"}; + SphereOutlineInstanceBuf circle_buf_ = {"metaball_data_buf"}; + SphereOutlineInstanceBuf circle_in_front_buf_ = {"metaball_data_buf"}; public: void begin_sync() { - data_buf_.clear(); - data_in_front_buf_.clear(); + circle_buf_.clear(); + circle_in_front_buf_.clear(); } void edit_object_sync(const ObjectRef &ob_ref, ResourcesT &res) { - SphereOutlineInstanceBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? - data_in_front_buf_ : - data_buf_; + SphereOutlineInstanceBuf &circle_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? + circle_in_front_buf_ : + circle_buf_; MetaBall *mb = static_cast(ob_ref.object->data); const float *color; @@ -58,19 +58,19 @@ template class Metaballs { const SelectID radius_id = res.select_id(ob_ref, MBALLSEL_RADIUS); color = (is_selected && is_scale_radius) ? col_radius_select : col_radius; - data_buf.append({ob_ref.object, &ml->x, ml->rad, color}, radius_id); + circle_buf.append({ob_ref.object, &ml->x, ml->rad, color}, radius_id); const SelectID stiff_id = res.select_id(ob_ref, MBALLSEL_STIFF); color = (is_selected && !is_scale_radius) ? col_stiffness_select : col_stiffness; - data_buf.append({ob_ref.object, &ml->x, stiffness_radius, color}, stiff_id); + circle_buf.append({ob_ref.object, &ml->x, stiffness_radius, color}, stiff_id); } } void object_sync(const ObjectRef &ob_ref, ResourcesT &res, const State &state) { - SphereOutlineInstanceBuf &data_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? - data_in_front_buf_ : - data_buf_; + SphereOutlineInstanceBuf &circle_buf = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? + circle_in_front_buf_ : + circle_buf_; MetaBall *mb = static_cast(ob_ref.object->data); const float4 &color = res.object_wire_color(ob_ref, state); @@ -78,7 +78,7 @@ template class Metaballs { LISTBASE_FOREACH (MetaElem *, ml, &mb->elems) { /* Draw radius only. */ - data_buf.append({ob_ref.object, &ml->x, ml->rad, color}, select_id); + circle_buf.append({ob_ref.object, &ml->x, ml->rad, color}, select_id); } } @@ -93,8 +93,8 @@ template class Metaballs { call_buf.end_sync(pass, shapes.metaball_wire_circle); }; - init_pass(metaball_ps_, data_buf_); - init_pass(metaball_in_front_ps_, data_in_front_buf_); + init_pass(metaball_ps_, circle_buf_); + init_pass(metaball_in_front_ps_, circle_in_front_buf_); } void draw(ResourcesT &res, Manager &manager, View &view) diff --git a/source/blender/draw/engines/overlay/overlay_prepass.hh b/source/blender/draw/engines/overlay/overlay_prepass.hh new file mode 100644 index 00000000000..75941191005 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_prepass.hh @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + * + * A depth pass that write surface depth when it is needed. + * It is also used for selecting non overlay-only objects. + */ + +#pragma once + +#include "draw_cache.h" + +#include "overlay_private.hh" + +namespace blender::draw::overlay { + +template class Prepass { + using SelectID = typename SelectEngineT::ID; + using ResourcesT = Resources; + + private: + PassMain prepass_ps_ = {"prepass"}; + PassMain prepass_in_front_ps_ = {"prepass_in_front"}; + + public: + void begin_sync(const State &state) + { + auto init_pass = [&](PassMain &pass) { + pass.init(); + pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state); + pass.shader_set(OVERLAY_shader_depth_only()); + }; + init_pass(prepass_ps_); + init_pass(prepass_in_front_ps_); + } + + void object_sync(Manager &manager, const ObjectRef &ob_ref, ResourcesT & /*res*/) + { + PassMain &pass = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? prepass_in_front_ps_ : + prepass_ps_; + + /* TODO(fclem) This function should contain what `basic_cache_populate` contained. */ + + GPUBatch *geom = DRW_cache_object_surface_get(ob_ref.object); + if (geom) { + ResourceHandle res_handle = manager.resource_handle(ob_ref); + pass.draw(geom, res_handle); + + /* TODO */ + // const SelectID radius_id = res.select_id(ob_ref); + // pass.draw(geom, res_handle, radius_id.value); + } + } + + void draw(ResourcesT &res, Manager &manager, View &view) + { + /* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */ + GPU_framebuffer_bind(res.overlay_line_fb); + manager.submit(prepass_ps_, view); + } + + void draw_in_front(ResourcesT &res, Manager &manager, View &view) + { + /* Should be fine to use the line buffer since the prepass only writes to the depth buffer. */ + GPU_framebuffer_bind(res.overlay_line_in_front_fb); + manager.submit(prepass_in_front_ps_, view); + } +}; + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index 68bd2166e77..e426cbffd70 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -148,6 +148,16 @@ GPUShader *OVERLAY_shader_depth_only(void) const DRWContextState *draw_ctx = DRW_context_state_get(); OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; if (!sh_data->depth_only) { + if (U.experimental.enable_overlay_next) { + using namespace blender::gpu::shader; + ShaderCreateInfo &info = const_cast( + *reinterpret_cast( + GPU_shader_create_info_get("overlay_depth_only"))); + + info.additional_infos_.clear(); + info.additional_info("draw_view", "draw_modelmat_new", "draw_resource_handle_new"); + } + sh_data->depth_only = GPU_shader_create_from_info_name( (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "overlay_depth_only_clipped" : "overlay_depth_only"); -- 2.30.2 From 16cc2446f5b72a5c7931efc5ee72c849c5f95129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 1 Mar 2023 15:26:29 +0100 Subject: [PATCH 15/22] Overlay-Next: Add shader module This allows cleaner declarations of shaders as well as allowing easier swapping of the whole shader module for selection & clipping. This also allow to easier toggle between the old overlay engine and overlay-next as they don't share the same shaders anymore. --- .../engines/overlay/overlay_background.hh | 4 +- .../draw/engines/overlay/overlay_empty.hh | 2 +- .../draw/engines/overlay/overlay_engine.cc | 1 + .../draw/engines/overlay/overlay_grid.hh | 2 +- .../draw/engines/overlay/overlay_instance.cc | 2 +- .../draw/engines/overlay/overlay_instance.hh | 13 +- .../draw/engines/overlay/overlay_metaball.hh | 2 +- .../draw/engines/overlay/overlay_prepass.hh | 4 +- .../draw/engines/overlay/overlay_private.hh | 5 + .../draw/engines/overlay/overlay_shader.cc | 17 ++ .../draw/engines/overlay/overlay_shader.hh | 150 ++++++++++++++++++ .../draw/engines/select/select_empty.hh | 2 + .../draw/engines/select/select_object.hh | 3 + 13 files changed, 189 insertions(+), 18 deletions(-) create mode 100644 source/blender/draw/engines/overlay/overlay_shader.hh diff --git a/source/blender/draw/engines/overlay/overlay_background.hh b/source/blender/draw/engines/overlay/overlay_background.hh index bcbb6576abe..c0834371f61 100644 --- a/source/blender/draw/engines/overlay/overlay_background.hh +++ b/source/blender/draw/engines/overlay/overlay_background.hh @@ -77,7 +77,7 @@ template class Background { bg_ps_.init(); bg_ps_.state_set(pass_state); - bg_ps_.shader_set(OVERLAY_shader_background()); + bg_ps_.shader_set(res.shaders.background_fill); bg_ps_.bind_ubo("globalsBlock", &res.globals_buf); bg_ps_.bind_texture("colorBuffer", &res.color_render_tx); bg_ps_.bind_texture("depthBuffer", &res.depth_tx); @@ -87,7 +87,7 @@ template class Background { if (state.clipping_state != 0 && state.rv3d != nullptr && state.rv3d->clipbb != nullptr) { bg_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA | DRW_STATE_CULL_BACK); - bg_ps_.shader_set(OVERLAY_shader_clipbound()); + bg_ps_.shader_set(res.shaders.background_clip_bound); bg_ps_.push_constant("ucolor", res.theme_settings.color_clipping_border); bg_ps_.push_constant("boundbox", &state.rv3d->clipbb->vec[0][0], 8); bg_ps_.draw(DRW_cache_cube_get()); diff --git a/source/blender/draw/engines/overlay/overlay_empty.hh b/source/blender/draw/engines/overlay/overlay_empty.hh index acddc00df4e..8dae5445747 100644 --- a/source/blender/draw/engines/overlay/overlay_empty.hh +++ b/source/blender/draw/engines/overlay/overlay_empty.hh @@ -95,7 +95,7 @@ template class Empties { pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state); - pass.shader_set(OVERLAY_shader_extra(false)); + pass.shader_set(res.shaders.extra_shape); pass.bind_ubo("globalsBlock", &res.globals_buf); call_bufs.plain_axes_buf.end_sync(pass, shapes.plain_axes); diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc index c344bf498b1..8307da73091 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -737,6 +737,7 @@ static void OVERLAY_draw_scene(void *vedata) static void OVERLAY_engine_free() { OVERLAY_shader_free(); + overlay::shader_module_free(); } static void OVERLAY_instance_free(void *instance_) diff --git a/source/blender/draw/engines/overlay/overlay_grid.hh b/source/blender/draw/engines/overlay/overlay_grid.hh index e5e9c183b40..e00fc35f3a0 100644 --- a/source/blender/draw/engines/overlay/overlay_grid.hh +++ b/source/blender/draw/engines/overlay/overlay_grid.hh @@ -176,7 +176,7 @@ template class Grid { grid_ps_.init(); grid_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA); - grid_ps_.shader_set(OVERLAY_shader_grid()); + grid_ps_.shader_set(res.shaders.grid); grid_ps_.bind_ubo("grid_buf", &data_); grid_ps_.bind_ubo("globalsBlock", &res.globals_buf); grid_ps_.bind_texture("depth_tx", &res.depth_tx); diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index bc4eb7327a6..d3b6b33a01d 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -71,7 +71,7 @@ template void Instance::begin_sync() View view("OverlayView", view_legacy); background.begin_sync(resources, state); - prepass.begin_sync(state); + prepass.begin_sync(resources, state); empties.begin_sync(); metaballs.begin_sync(); grid.begin_sync(resources, state, view); diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index 31808843e6f..8730a2f4c37 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -20,12 +20,6 @@ namespace blender::draw::overlay { -class ShaderCache { - Map> cache; - - int clipping_enabled = 0; -}; - template< /* Selection engine reuse most of the Overlay engine by creating selection IDs for each * selectable component and using a special shaders for drawing. @@ -34,14 +28,13 @@ template< typename SelectEngineT = select::EngineEmpty> class Instance { public: - ShaderCache shaders; - ShapeCache shapes; - /* WORKAROUND: Legacy. Move to grid pass. */ GPUUniformBuf *grid_ubo = nullptr; + ShapeCache shapes; + /** Global types. */ - Resources resources; + Resources resources = {overlay::ShaderModule::module_get()}; State state; /** Overlay types. */ diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index ff1b95e7249..c698da3a701 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -88,7 +88,7 @@ template class Metaballs { pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state); - pass.shader_set(OVERLAY_shader_armature_sphere(true)); + pass.shader_set(res.shaders.armature_sphere_outline); pass.bind_ubo("globalsBlock", &res.globals_buf); call_buf.end_sync(pass, shapes.metaball_wire_circle); diff --git a/source/blender/draw/engines/overlay/overlay_prepass.hh b/source/blender/draw/engines/overlay/overlay_prepass.hh index 75941191005..0c650c723a5 100644 --- a/source/blender/draw/engines/overlay/overlay_prepass.hh +++ b/source/blender/draw/engines/overlay/overlay_prepass.hh @@ -24,12 +24,12 @@ template class Prepass { PassMain prepass_in_front_ps_ = {"prepass_in_front"}; public: - void begin_sync(const State &state) + void begin_sync(ResourcesT &res, const State &state) { auto init_pass = [&](PassMain &pass) { pass.init(); pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state); - pass.shader_set(OVERLAY_shader_depth_only()); + pass.shader_set(res.shaders.depth_mesh); }; init_pass(prepass_ps_); init_pass(prepass_in_front_ps_); diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index d1e7b520a1d..a19eb31293c 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -16,6 +16,7 @@ #include "draw_handle.hh" +#include "overlay_shader.hh" #include "overlay_shader_shared.h" #ifdef __APPLE__ @@ -64,6 +65,8 @@ using blender::draw::TextureFromPool; using blender::draw::TextureRef; template struct Resources : public SelectEngineT::SelectMap { + ShaderModule &shaders; + Framebuffer overlay_fb = {"overlay_fb"}; Framebuffer overlay_in_front_fb = {"overlay_in_front_fb"}; Framebuffer overlay_color_only_fb = {"overlay_color_only_fb"}; @@ -83,6 +86,8 @@ template struct Resources : public SelectEngineT::Select TextureRef color_overlay_tx; TextureRef color_render_tx; + Resources(ShaderModule &shader_module) : shaders(shader_module){}; + [[nodiscard]] ThemeColorID object_wire_theme_id(const ObjectRef &ob_ref, const State &state) const { diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index e426cbffd70..3b92fbf4d75 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -14,6 +14,7 @@ #include "gpu_shader_create_info.hh" #include "overlay_private.hh" +#include "overlay_shader.hh" struct OVERLAY_Shaders { GPUShader *antialiasing; @@ -1231,3 +1232,19 @@ void OVERLAY_shader_free(void) MEM_SAFE_FREE(*format); } } + +namespace blender::draw::overlay { + +template<> +ShaderModule *ShaderModule::g_shader_module = nullptr; + +template<> +ShaderModule *ShaderModule::g_shader_module = nullptr; + +void shader_module_free() +{ + ShaderModule::module_free(); + ShaderModule::module_free(); +} + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_shader.hh b/source/blender/draw/engines/overlay/overlay_shader.hh new file mode 100644 index 00000000000..046acbae612 --- /dev/null +++ b/source/blender/draw/engines/overlay/overlay_shader.hh @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup overlay + */ + +#pragma once + +#include + +#include "GPU_shader.h" + +#include "gpu_shader_create_info.hh" + +#include "../select/select_empty.hh" +#include "../select/select_object.hh" + +namespace blender::draw::overlay { + +/** + * Shader module. Shared between instances. + */ +template class ShaderModule { + private: + /** Shared shader module across all engine instances. */ + static ShaderModule *g_shader_module; + + /** TODO: Support clipping. This global state should be set by the overlay::Instance and switch + * to the shader variations that use clipping. */ + // bool clipping_enabled = false; + + class Shader { + protected: + GPUShader *shader_ = nullptr; + + public: + Shader() = default; + + Shader(const char *create_info_name) + : shader_(GPU_shader_create_from_info_name(create_info_name)){}; + + ~Shader() + { + DRW_SHADER_FREE_SAFE(shader_); + } + + operator GPUShader *() + { + return shader_; + } + }; + + /** + * Special class for every shader that needs to have clipped and selection variations. + */ + class ShaderGeometry : public Shader { + public: + ShaderGeometry(const char *create_info_name) + { + /* TODO: This is what it should be like with all variations defined with create infos. */ + // std::string create_info_name = base_create_info; + // create_info_name += SelectEngineT::shader_suffix; + // create_info_name += ClippingEnabled ? "_clipped" : ""; + // this->shader_ = GPU_shader_create_from_info_name(create_info_name.c_str()); + + /* WORKAROUND: ... but for now, we have to patch the create info used by the old engine. */ + gpu::shader::ShaderCreateInfo info = + *reinterpret_cast( + GPU_shader_create_info_get(create_info_name)); + + info.define(SelectEngineT::shader_define); + + this->shader_ = GPU_shader_create_from_info( + reinterpret_cast(&info)); + } + + /* WORKAROUND: Create a shader using a patch function to patch the create info. */ + ShaderGeometry(const char *create_info_name, + std::function patch) + { + gpu::shader::ShaderCreateInfo info = + *reinterpret_cast( + GPU_shader_create_info_get(create_info_name)); + + patch(info); + info.define(SelectEngineT::shader_define); + + this->shader_ = GPU_shader_create_from_info( + reinterpret_cast(&info)); + } + }; + + public: + /** ShaderGeometry */ + + ShaderGeometry armature_sphere_outline = { + "overlay_armature_sphere_outline", [](gpu::shader::ShaderCreateInfo &info) { + using namespace blender::gpu::shader; + info.storage_buf(0, Qualifier::READ, "mat4", "data_buf[]"); + info.define("inst_obmat", "data_buf[gl_InstanceID]"); + info.vertex_inputs_.pop_last(); + }}; + + ShaderGeometry depth_mesh = {"overlay_depth_only", [](gpu::shader::ShaderCreateInfo &info) { + using namespace blender::gpu::shader; + info.additional_infos_.clear(); + info.additional_info( + "draw_view", "draw_modelmat_new", "draw_resource_handle_new"); + }}; + + ShaderGeometry extra_shape = { + "overlay_extra", [](gpu::shader::ShaderCreateInfo &info) { + using namespace blender::gpu::shader; + info.storage_buf(0, Qualifier::READ, "ExtraInstanceData", "data_buf[]"); + info.define("color", "data_buf[gl_InstanceID].color_"); + info.define("inst_obmat", "data_buf[gl_InstanceID].object_to_world_"); + info.vertex_inputs_.pop_last(); + info.vertex_inputs_.pop_last(); + }}; + + /** Shader */ + + Shader grid = {"overlay_grid"}; + + Shader background_fill = {"overlay_background"}; + Shader background_clip_bound = {"overlay_clipbound"}; + + /** Only to be used by Instance constructor. */ + static ShaderModule &module_get() + { + if (g_shader_module == nullptr) { + /* TODO(@fclem) thread-safety. */ + g_shader_module = new ShaderModule(); + } + return *g_shader_module; + } + + static void module_free() + { + if (g_shader_module != nullptr) { + /* TODO(@fclem) thread-safety. */ + delete g_shader_module; + g_shader_module = nullptr; + } + } +}; + +void shader_module_free(); + +} // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/select/select_empty.hh b/source/blender/draw/engines/select/select_empty.hh index 50766ccbb9a..2a0482ef5a8 100644 --- a/source/blender/draw/engines/select/select_empty.hh +++ b/source/blender/draw/engines/select/select_empty.hh @@ -17,6 +17,8 @@ struct EngineEmpty { /* Add type safety to selection ID. Only the select engine should provide them. */ struct ID {}; + static constexpr const char *shader_define = "NO_SELECT"; + struct SelectBuf { void select_clear(){}; void select_append(ID){}; diff --git a/source/blender/draw/engines/select/select_object.hh b/source/blender/draw/engines/select/select_object.hh index 66362bd9da6..eb58e382669 100644 --- a/source/blender/draw/engines/select/select_object.hh +++ b/source/blender/draw/engines/select/select_object.hh @@ -12,6 +12,7 @@ #include "DRW_gpu_wrapper.hh" #include "draw_manager.hh" +#include "draw_pass.hh" namespace blender::draw::select { @@ -21,6 +22,8 @@ struct EngineObject { uint32_t value; }; + static constexpr const char *shader_define = "SELECT_OBJECT"; + /** * Add a dedicated selection id buffer to a pass. * Use this when not using a #PassMain which can pass the select ID via CustomID. -- 2.30.2 From ea66898bbe7320ddf91a90b09a345c702066fdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 1 Mar 2023 20:44:54 +0100 Subject: [PATCH 16/22] Select-Next: Introduce shader level patching to output selection ids This leverage imageLoad/Store operations to remove the use of cumbersome visibility queries. Patching shaders should only require 4 lines of code (2 for includes, 2 for the id passthrough). --- source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/overlay/overlay_empty.hh | 1 + .../draw/engines/overlay/overlay_instance.cc | 6 ++ .../draw/engines/overlay/overlay_metaball.hh | 1 + .../draw/engines/overlay/overlay_prepass.hh | 1 + .../draw/engines/overlay/overlay_shader.hh | 8 +- .../shaders/overlay_depth_only_frag.glsl | 4 + .../shaders/overlay_depth_only_vert.glsl | 3 + .../overlay/shaders/overlay_extra_frag.glsl | 3 + .../overlay/shaders/overlay_extra_vert.glsl | 3 + .../draw/engines/select/select_defines.h | 10 ++ .../draw/engines/select/select_empty.hh | 16 ++- .../draw/engines/select/select_engine.c | 2 +- .../draw/engines/select/select_object.hh | 99 +++++++++++++++++-- .../select/shaders/infos/select_id_info.hh | 14 ++- .../select/shaders/select_id_frag.glsl | 2 +- .../select/shaders/select_id_vert.glsl | 2 +- .../engines/select/shaders/select_lib.glsl | 34 +++++++ source/blender/gpu/CMakeLists.txt | 1 + 19 files changed, 193 insertions(+), 18 deletions(-) create mode 100644 source/blender/draw/engines/select/select_defines.h create mode 100644 source/blender/draw/engines/select/shaders/select_lib.glsl diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 4c72b7af01a..8cfc392cf7e 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -595,6 +595,7 @@ set(GLSL_SRC engines/select/shaders/select_id_vert.glsl engines/select/shaders/select_id_frag.glsl + engines/select/shaders/select_lib.glsl engines/basic/shaders/basic_conservative_depth_geom.glsl engines/basic/shaders/basic_depth_vert.glsl diff --git a/source/blender/draw/engines/overlay/overlay_empty.hh b/source/blender/draw/engines/overlay/overlay_empty.hh index 8dae5445747..89f01b8b1ee 100644 --- a/source/blender/draw/engines/overlay/overlay_empty.hh +++ b/source/blender/draw/engines/overlay/overlay_empty.hh @@ -97,6 +97,7 @@ template class Empties { state.clipping_state); pass.shader_set(res.shaders.extra_shape); pass.bind_ubo("globalsBlock", &res.globals_buf); + res.select_bind(pass); call_bufs.plain_axes_buf.end_sync(pass, shapes.plain_axes); call_bufs.single_arrow_buf.end_sync(pass, shapes.single_arrow); diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index d3b6b33a01d..c28f6c410fe 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -70,6 +70,8 @@ template void Instance::begin_sync() const DRWView *view_legacy = DRW_view_default_get(); View view("OverlayView", view_legacy); + resources.begin_sync(); + background.begin_sync(resources, state); prepass.begin_sync(resources, state); empties.begin_sync(); @@ -136,6 +138,8 @@ template void Instance::object_sync(ObjectRef &ob_ref, Manager &m template void Instance::end_sync() { + resources.end_sync(); + metaballs.end_sync(resources, shapes, state); empties.end_sync(resources, shapes, state); } @@ -197,6 +201,8 @@ template void Instance::draw(Manager &manager) resources.line_tx.release(); resources.depth_in_front_alloc_tx.release(); + + resources.read_result(); } /* Instantiation. */ diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index c698da3a701..d591581a5af 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -90,6 +90,7 @@ template class Metaballs { state.clipping_state); pass.shader_set(res.shaders.armature_sphere_outline); pass.bind_ubo("globalsBlock", &res.globals_buf); + res.select_bind(pass); call_buf.end_sync(pass, shapes.metaball_wire_circle); }; diff --git a/source/blender/draw/engines/overlay/overlay_prepass.hh b/source/blender/draw/engines/overlay/overlay_prepass.hh index 0c650c723a5..010e3d99bc4 100644 --- a/source/blender/draw/engines/overlay/overlay_prepass.hh +++ b/source/blender/draw/engines/overlay/overlay_prepass.hh @@ -30,6 +30,7 @@ template class Prepass { pass.init(); pass.state_set(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state); pass.shader_set(res.shaders.depth_mesh); + res.select_bind(pass); }; init_pass(prepass_ps_); init_pass(prepass_in_front_ps_); diff --git a/source/blender/draw/engines/overlay/overlay_shader.hh b/source/blender/draw/engines/overlay/overlay_shader.hh index 046acbae612..7806c1a2a28 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.hh +++ b/source/blender/draw/engines/overlay/overlay_shader.hh @@ -6,8 +6,6 @@ #pragma once -#include - #include "GPU_shader.h" #include "gpu_shader_create_info.hh" @@ -51,7 +49,7 @@ template class ShaderModul }; /** - * Special class for every shader that needs to have clipped and selection variations. + * Special class for any shader that needs to have clipped and selection variations. */ class ShaderGeometry : public Shader { public: @@ -83,7 +81,7 @@ template class ShaderModul GPU_shader_create_info_get(create_info_name)); patch(info); - info.define(SelectEngineT::shader_define); + SelectEngineT::SelectShader::patch(info); this->shader_ = GPU_shader_create_from_info( reinterpret_cast(&info)); @@ -125,6 +123,8 @@ template class ShaderModul Shader background_fill = {"overlay_background"}; Shader background_clip_bound = {"overlay_clipbound"}; + /** Module */ + /** Only to be used by Instance constructor. */ static ShaderModule &module_get() { diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl index 59efdd8d538..412dedff320 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_frag.glsl @@ -1,6 +1,10 @@ +#pragma BLENDER_REQUIRE(select_lib.glsl) void main() { /* No color output, only depth (line below is implicit). */ // gl_FragDepth = gl_FragCoord.z; + + /* This is optimized to noop in the non select case. */ + select_id_output(select_id); } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl index d403890f44e..a251144ba80 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl @@ -1,11 +1,14 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(select_lib.glsl) void main() { GPU_INTEL_VERTEX_SHADER_WORKAROUND + select_id_set(in_select_buf[resource_id]); + vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl index bf29b2b057e..4d4d9db5909 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_frag.glsl @@ -1,8 +1,11 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(select_lib.glsl) void main() { fragColor = finalColor; lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); + + select_id_output(select_id); } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl index 7b1e29525e9..c2e54f031f8 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_extra_vert.glsl @@ -1,6 +1,7 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(select_lib.glsl) #define lamp_area_size inst_data.xy #define lamp_clip_sta inst_data.z @@ -41,6 +42,8 @@ void main() { + select_id_set(in_select_buf[gl_InstanceID]); + /* Extract data packed inside the unused mat4 members. */ vec4 inst_data = vec4(inst_obmat[0][3], inst_obmat[1][3], inst_obmat[2][3], inst_obmat[3][3]); float inst_color_data = color.a; diff --git a/source/blender/draw/engines/select/select_defines.h b/source/blender/draw/engines/select/select_defines.h new file mode 100644 index 00000000000..663c93eb571 --- /dev/null +++ b/source/blender/draw/engines/select/select_defines.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#define SELECT_ID_IN 5 +#define SELECT_ID_OUT 6 diff --git a/source/blender/draw/engines/select/select_empty.hh b/source/blender/draw/engines/select/select_empty.hh index 2a0482ef5a8..ac78adce3cf 100644 --- a/source/blender/draw/engines/select/select_empty.hh +++ b/source/blender/draw/engines/select/select_empty.hh @@ -11,13 +11,17 @@ #include "draw_manager.hh" +#include "gpu_shader_create_info.hh" + namespace blender::draw::select { struct EngineEmpty { /* Add type safety to selection ID. Only the select engine should provide them. */ struct ID {}; - static constexpr const char *shader_define = "NO_SELECT"; + struct SelectShader { + static void patch(gpu::shader::ShaderCreateInfo &){}; + }; struct SelectBuf { void select_clear(){}; @@ -30,6 +34,16 @@ struct EngineEmpty { { return {}; } + + void begin_sync(){}; + + void select_bind(PassSimple &){}; + + void select_bind(PassMain &){}; + + void end_sync(){}; + + void read_result(){}; }; }; diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c index 7bf0bf91576..46d51d9f4dc 100644 --- a/source/blender/draw/engines/select/select_engine.c +++ b/source/blender/draw/engines/select/select_engine.c @@ -148,7 +148,7 @@ static void select_cache_init(void *vedata) } else { pd->shgrp_face_unif = DRW_shgroup_create(sh->select_id_uniform, psl->select_id_face_pass); - DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "id", 0); + DRW_shgroup_uniform_int_copy(pd->shgrp_face_unif, "select_id", 0); } if (e_data.context.select_mode & SCE_SELECT_EDGE) { diff --git a/source/blender/draw/engines/select/select_object.hh b/source/blender/draw/engines/select/select_object.hh index eb58e382669..69aac112c41 100644 --- a/source/blender/draw/engines/select/select_object.hh +++ b/source/blender/draw/engines/select/select_object.hh @@ -11,18 +11,39 @@ #pragma once #include "DRW_gpu_wrapper.hh" + #include "draw_manager.hh" #include "draw_pass.hh" +#include "gpu_shader_create_info.hh" + +#include "select_defines.h" + namespace blender::draw::select { struct EngineObject { /* Add type safety to selection ID. Only the select engine should provide them. */ struct ID { uint32_t value; + + friend constexpr bool operator==(ID a, ID b) + { + return a.value == b.value; + } + + uint64_t hash() const + { + return BLI_ghashutil_uinthash(value); + } }; - static constexpr const char *shader_define = "SELECT_OBJECT"; + struct SelectShader { + static void patch(gpu::shader::ShaderCreateInfo &info) + { + info.define("SELECT_UNORDERED"); + info.additional_info("select_id_patch"); + }; + }; /** * Add a dedicated selection id buffer to a pass. @@ -44,23 +65,85 @@ struct EngineObject { void select_bind(PassSimple &pass) { select_buf.push_update(); - pass.bind_ssbo("select_buf", &select_buf); + pass.bind_ssbo(SELECT_ID_IN, &select_buf); } }; /** * Generate selection IDs from objects and keep record of the mapping between them. + * The id's are contiguous so that we can create a destination buffer. */ struct SelectMap { - uint next_id = 0; - Map map; + /** Mapping between internal IDs and `object->runtime.select_id`. */ + Vector select_id_map; +#ifdef DEBUG + /** Debug map containing a copy of the object name. */ + Vector map_names; +#endif + /** Stores the result of the whole selection drawing. Content depends on selection mode. */ + StorageArrayBuffer select_output_buf = {"select_output_buf"}; + /** Dummy buffer. Might be better to remove, but simplify the shader create info patching. */ + StorageArrayBuffer dummy_select_buf = {"dummy_select_buf"}; /* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object - * reference directly. */ - [[nodiscard]] const ID select_id(const ObjectRef &, uint sub_object_id = 0) + * reference directly. This would isolate the selection logic to this class. */ + [[nodiscard]] const ID select_id(const ObjectRef &ob_ref, uint sub_object_id = 0) { - /* TODO Insert Ref into the map. */ - return {sub_object_id | next_id++}; + uint object_id = ob_ref.object->runtime.select_id; + uint id = select_id_map.append_and_get_index(object_id | sub_object_id); +#ifdef DEBUG + map_names.append(ob_ref.object->id.name); +#endif + return {id}; + } + + void begin_sync() + { + select_id_map.clear(); + /* Index 0 is the invalid selection ID. */ + select_id_map.append(uint(-1)); +#ifdef DEBUG + map_names.clear(); + map_names.append("Invalid Index"); +#endif + } + + void select_bind(PassSimple &pass) + { + pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf); + } + + void select_bind(PassMain &pass) + { + /* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */ + pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf); + pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf); + } + + void end_sync() + { + select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4)); + select_output_buf.push_update(); + select_output_buf.clear_to_zero(); + } + + void read_result() + { + /* TODO right barrier. */ + GPU_finish(); + select_output_buf.read(); + +#ifdef DEBUG + for (auto i : IndexRange(select_output_buf.size())) { + uint32_t word = select_output_buf[i]; + for (auto bit : IndexRange(32)) { + if ((word & 1) != 0) { + std::cout << map_names[i * 32 + bit] << std::endl; + } + word >>= 1; + } + } +#endif } }; }; diff --git a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh index e3166582197..29750768a52 100644 --- a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh +++ b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh @@ -1,12 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "gpu_shader_create_info.hh" +#include "select_defines.h" /* -------------------------------------------------------------------- */ /** \name Select ID for Edit Mesh Selection * \{ */ -GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "id"); +GPU_SHADER_INTERFACE_INFO(select_id_iface, "").flat(Type::INT, "select_id"); GPU_SHADER_CREATE_INFO(select_id_flat) .push_constant(Type::FLOAT, "sizeVertex") @@ -23,7 +24,7 @@ GPU_SHADER_CREATE_INFO(select_id_flat) GPU_SHADER_CREATE_INFO(select_id_uniform) .define("UNIFORM_ID") .push_constant(Type::FLOAT, "sizeVertex") - .push_constant(Type::INT, "id") + .push_constant(Type::INT, "select_id") .vertex_in(0, Type::VEC3, "pos") .fragment_out(0, Type::UINT, "fragColor") .vertex_source("select_id_vert.glsl") @@ -40,4 +41,13 @@ GPU_SHADER_CREATE_INFO(select_id_uniform_clipped) .additional_info("select_id_uniform") .additional_info("drw_clipped") .do_static_compilation(true); + +/* Used to patch overlay shaders. */ +GPU_SHADER_CREATE_INFO(select_id_patch) + .vertex_out(select_id_iface) + /* Select IDs for instanced draw-calls not using #PassMain. */ + .storage_buf(SELECT_ID_IN, Qualifier::READ, "int", "in_select_buf[]") + /* Stores the result of the whole selection drawing. Content depends on selection mode. */ + .storage_buf(SELECT_ID_OUT, Qualifier::READ_WRITE, "uint", "out_select_buf[]"); + /** \} */ diff --git a/source/blender/draw/engines/select/shaders/select_id_frag.glsl b/source/blender/draw/engines/select/shaders/select_id_frag.glsl index aecf57b4766..a4ba7ad35e5 100644 --- a/source/blender/draw/engines/select/shaders/select_id_frag.glsl +++ b/source/blender/draw/engines/select/shaders/select_id_frag.glsl @@ -1,4 +1,4 @@ void main() { - fragColor = floatBitsToUint(intBitsToFloat(id)); + fragColor = floatBitsToUint(intBitsToFloat(select_id)); } diff --git a/source/blender/draw/engines/select/shaders/select_id_vert.glsl b/source/blender/draw/engines/select/shaders/select_id_vert.glsl index 7b3b0f9984d..81064626235 100644 --- a/source/blender/draw/engines/select/shaders/select_id_vert.glsl +++ b/source/blender/draw/engines/select/shaders/select_id_vert.glsl @@ -4,7 +4,7 @@ void main() { #ifndef UNIFORM_ID - id = offset + index; + select_id = offset + index; #endif vec3 world_pos = point_object_to_world(pos); diff --git a/source/blender/draw/engines/select/shaders/select_lib.glsl b/source/blender/draw/engines/select/shaders/select_lib.glsl new file mode 100644 index 00000000000..469773a1d6a --- /dev/null +++ b/source/blender/draw/engines/select/shaders/select_lib.glsl @@ -0,0 +1,34 @@ + +#if !(defined(SELECT_UNORDERED) || defined(SELECT_DEPTH_PICKING)) +/* Avoid requesting the select_id when not in selection mode. */ +# define select_id_set(select_id) +# define select_id_output(select_id) + +#elif defined(GPU_VERTEX_SHADER) + +void select_id_set(int id) +{ + /* Declared in the create info. */ + select_id = id; +} + +#elif defined(GPU_FRAGMENT_SHADER) + +void select_id_output(int id) +{ +# if defined(SELECT_UNORDERED) + /* Used by rectangle selection. + * Set the bit of the select id in the bitmap. */ + atomicOr(out_select_buf[id / 32u], 1u << (uint(id) % 32u)); + +# elif defined(SELECT_DEPTH_PICKING) + /* Used by mouse-clicking selection. + * Stores the nearest depth for this select id. */ + atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z)); + +# else +# error +# endif +} + +#endif diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5ce5d8c902b..2c9d1f9ba49 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -29,6 +29,7 @@ set(INC # For *_info.hh includes. ../compositor/realtime_compositor ../draw/engines/eevee_next + ../draw/engines/select ../draw/engines/workbench ../draw/intern -- 2.30.2 From 34afb6c05f2c3a037935800ca5b12e2daa3ebf6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 1 Mar 2023 22:29:55 +0100 Subject: [PATCH 17/22] Select-Next: Fix IDs for meshes and metaballs handles --- .../draw/engines/overlay/overlay_prepass.hh | 8 ++----- .../overlay_armature_sphere_solid_vert.glsl | 3 +++ .../shaders/overlay_armature_wire_frag.glsl | 2 ++ .../shaders/overlay_depth_only_vert.glsl | 2 +- .../draw/engines/select/select_object.hh | 23 ++++++++----------- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/source/blender/draw/engines/overlay/overlay_prepass.hh b/source/blender/draw/engines/overlay/overlay_prepass.hh index 010e3d99bc4..046319098d5 100644 --- a/source/blender/draw/engines/overlay/overlay_prepass.hh +++ b/source/blender/draw/engines/overlay/overlay_prepass.hh @@ -36,7 +36,7 @@ template class Prepass { init_pass(prepass_in_front_ps_); } - void object_sync(Manager &manager, const ObjectRef &ob_ref, ResourcesT & /*res*/) + void object_sync(Manager &manager, const ObjectRef &ob_ref, ResourcesT &res) { PassMain &pass = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0 ? prepass_in_front_ps_ : prepass_ps_; @@ -46,11 +46,7 @@ template class Prepass { GPUBatch *geom = DRW_cache_object_surface_get(ob_ref.object); if (geom) { ResourceHandle res_handle = manager.resource_handle(ob_ref); - pass.draw(geom, res_handle); - - /* TODO */ - // const SelectID radius_id = res.select_id(ob_ref); - // pass.draw(geom, res_handle, radius_id.value); + pass.draw(geom, res_handle, res.select_id(ob_ref).value); } } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl index 3d2dfc018bb..e786e38acc8 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_sphere_solid_vert.glsl @@ -1,12 +1,15 @@ #pragma BLENDER_REQUIRE(common_view_clipping_lib.glsl) #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(select_lib.glsl) /* Sphere radius */ const float rad = 0.05; void main() { + select_id_set(in_select_buf[gl_InstanceID]); + vec4 bone_color, state_color; mat4 model_mat = extract_matrix_packed_data(inst_obmat, state_color, bone_color); diff --git a/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl index 2c454a8becd..5bf9f9491b9 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_armature_wire_frag.glsl @@ -1,8 +1,10 @@ #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(select_lib.glsl) void main() { lineOutput = pack_line_data(gl_FragCoord.xy, edgeStart, edgePos); fragColor = vec4(finalColor.rgb, finalColor.a * alpha); + select_id_output(select_id); } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl index a251144ba80..2a3a8e7b560 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_depth_only_vert.glsl @@ -7,7 +7,7 @@ void main() { GPU_INTEL_VERTEX_SHADER_WORKAROUND - select_id_set(in_select_buf[resource_id]); + select_id_set(drw_CustomID); vec3 world_pos = point_object_to_world(pos); gl_Position = point_world_to_ndc(world_pos); diff --git a/source/blender/draw/engines/select/select_object.hh b/source/blender/draw/engines/select/select_object.hh index 69aac112c41..ee4fc25f84c 100644 --- a/source/blender/draw/engines/select/select_object.hh +++ b/source/blender/draw/engines/select/select_object.hh @@ -25,22 +25,18 @@ struct EngineObject { /* Add type safety to selection ID. Only the select engine should provide them. */ struct ID { uint32_t value; - - friend constexpr bool operator==(ID a, ID b) - { - return a.value == b.value; - } - - uint64_t hash() const - { - return BLI_ghashutil_uinthash(value); - } }; struct SelectShader { static void patch(gpu::shader::ShaderCreateInfo &info) { info.define("SELECT_UNORDERED"); + /* Replace additional info. */ + for (StringRefNull &str : info.additional_infos_) { + if (str == "draw_modelmat_new") { + str = "draw_modelmat_new_with_custom_id"; + } + } info.additional_info("select_id_patch"); }; }; @@ -100,11 +96,8 @@ struct EngineObject { void begin_sync() { select_id_map.clear(); - /* Index 0 is the invalid selection ID. */ - select_id_map.append(uint(-1)); #ifdef DEBUG map_names.clear(); - map_names.append("Invalid Index"); #endif } @@ -115,6 +108,7 @@ struct EngineObject { void select_bind(PassMain &pass) { + pass.use_custom_ids = true; /* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */ pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf); pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf); @@ -138,7 +132,8 @@ struct EngineObject { uint32_t word = select_output_buf[i]; for (auto bit : IndexRange(32)) { if ((word & 1) != 0) { - std::cout << map_names[i * 32 + bit] << std::endl; + uint index = i * 32 + bit; + std::cout << index << map_names[index] << std::endl; } word >>= 1; } -- 2.30.2 From a9397b5458637cd7403280f693dadb8dd20c11b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 2 Mar 2023 14:08:55 +0100 Subject: [PATCH 18/22] Select-Next: Reorganize and rename stuffs --- source/blender/draw/CMakeLists.txt | 2 + .../draw/engines/overlay/overlay_instance.hh | 5 +- .../draw/engines/overlay/overlay_metaball.hh | 2 + .../draw/engines/overlay/overlay_prepass.hh | 2 +- .../draw/engines/overlay/overlay_shader.cc | 9 +- .../draw/engines/overlay/overlay_shader.hh | 3 +- .../draw/engines/select/select_defines.h | 1 + .../draw/engines/select/select_empty.hh | 50 ----------- .../{select_object.hh => select_instance.hh} | 82 +++++++++++++++++-- .../engines/select/select_shader_shared.hh | 28 +++++++ .../select/shaders/infos/select_id_info.hh | 4 + .../engines/select/shaders/select_lib.glsl | 39 ++++++--- 12 files changed, 148 insertions(+), 79 deletions(-) delete mode 100644 source/blender/draw/engines/select/select_empty.hh rename source/blender/draw/engines/select/{select_object.hh => select_instance.hh} (66%) create mode 100644 source/blender/draw/engines/select/select_shader_shared.hh diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 8cfc392cf7e..453fa1de808 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -597,6 +597,8 @@ set(GLSL_SRC engines/select/shaders/select_id_frag.glsl engines/select/shaders/select_lib.glsl + engines/select/select_shader_shared.hh + engines/basic/shaders/basic_conservative_depth_geom.glsl engines/basic/shaders/basic_depth_vert.glsl engines/basic/shaders/basic_depth_vert_conservative_no_geom.glsl diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index 8730a2f4c37..08ba2e8c291 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -15,8 +15,7 @@ #include "overlay_prepass.hh" #include "overlay_shape.hh" -#include "../select/select_empty.hh" -#include "../select/select_object.hh" +#include "../select/select_instance.hh" namespace blender::draw::overlay { @@ -25,7 +24,7 @@ template< * selectable component and using a special shaders for drawing. * Making the select engine templated makes it easier to phase out any overhead of the * selection for the regular non-selection case.*/ - typename SelectEngineT = select::EngineEmpty> + typename SelectEngineT = select::Instance> class Instance { public: /* WORKAROUND: Legacy. Move to grid pass. */ diff --git a/source/blender/draw/engines/overlay/overlay_metaball.hh b/source/blender/draw/engines/overlay/overlay_metaball.hh index d591581a5af..4d6f2882091 100644 --- a/source/blender/draw/engines/overlay/overlay_metaball.hh +++ b/source/blender/draw/engines/overlay/overlay_metaball.hh @@ -88,6 +88,8 @@ template class Metaballs { pass.init(); pass.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL | state.clipping_state); + /* NOTE: Use armature sphere outline shader to have perspective correct outline instead of + * just a circle facing the camera. */ pass.shader_set(res.shaders.armature_sphere_outline); pass.bind_ubo("globalsBlock", &res.globals_buf); res.select_bind(pass); diff --git a/source/blender/draw/engines/overlay/overlay_prepass.hh b/source/blender/draw/engines/overlay/overlay_prepass.hh index 046319098d5..09c8977e106 100644 --- a/source/blender/draw/engines/overlay/overlay_prepass.hh +++ b/source/blender/draw/engines/overlay/overlay_prepass.hh @@ -46,7 +46,7 @@ template class Prepass { GPUBatch *geom = DRW_cache_object_surface_get(ob_ref.object); if (geom) { ResourceHandle res_handle = manager.resource_handle(ob_ref); - pass.draw(geom, res_handle, res.select_id(ob_ref).value); + pass.draw(geom, res_handle, res.select_id(ob_ref).get()); } } diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index 3b92fbf4d75..d329f3e7af5 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -1236,15 +1236,16 @@ void OVERLAY_shader_free(void) namespace blender::draw::overlay { template<> -ShaderModule *ShaderModule::g_shader_module = nullptr; +ShaderModule *ShaderModule::g_shader_module = nullptr; template<> -ShaderModule *ShaderModule::g_shader_module = nullptr; +ShaderModule *ShaderModule::g_shader_module = + nullptr; void shader_module_free() { - ShaderModule::module_free(); - ShaderModule::module_free(); + ShaderModule::module_free(); + ShaderModule::module_free(); } } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_shader.hh b/source/blender/draw/engines/overlay/overlay_shader.hh index 7806c1a2a28..89eaf99a8b0 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.hh +++ b/source/blender/draw/engines/overlay/overlay_shader.hh @@ -10,8 +10,7 @@ #include "gpu_shader_create_info.hh" -#include "../select/select_empty.hh" -#include "../select/select_object.hh" +#include "../select/select_instance.hh" namespace blender::draw::overlay { diff --git a/source/blender/draw/engines/select/select_defines.h b/source/blender/draw/engines/select/select_defines.h index 663c93eb571..7f77b77be1d 100644 --- a/source/blender/draw/engines/select/select_defines.h +++ b/source/blender/draw/engines/select/select_defines.h @@ -6,5 +6,6 @@ #pragma once +#define SELECT_DATA 4 #define SELECT_ID_IN 5 #define SELECT_ID_OUT 6 diff --git a/source/blender/draw/engines/select/select_empty.hh b/source/blender/draw/engines/select/select_empty.hh deleted file mode 100644 index ac78adce3cf..00000000000 --- a/source/blender/draw/engines/select/select_empty.hh +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2023 Blender Foundation. */ - -/** \file - * \ingroup draw_engine - * - * Dummy implementation of the select engine types to avoid any overhead. - */ - -#pragma once - -#include "draw_manager.hh" - -#include "gpu_shader_create_info.hh" - -namespace blender::draw::select { - -struct EngineEmpty { - /* Add type safety to selection ID. Only the select engine should provide them. */ - struct ID {}; - - struct SelectShader { - static void patch(gpu::shader::ShaderCreateInfo &){}; - }; - - struct SelectBuf { - void select_clear(){}; - void select_append(ID){}; - void select_bind(PassSimple &){}; - }; - - struct SelectMap { - [[nodiscard]] const ID select_id(const ObjectRef &, uint = 0) - { - return {}; - } - - void begin_sync(){}; - - void select_bind(PassSimple &){}; - - void select_bind(PassMain &){}; - - void end_sync(){}; - - void read_result(){}; - }; -}; - -} // namespace blender::draw::select \ No newline at end of file diff --git a/source/blender/draw/engines/select/select_object.hh b/source/blender/draw/engines/select/select_instance.hh similarity index 66% rename from source/blender/draw/engines/select/select_object.hh rename to source/blender/draw/engines/select/select_instance.hh index ee4fc25f84c..5609adc8b79 100644 --- a/source/blender/draw/engines/select/select_object.hh +++ b/source/blender/draw/engines/select/select_instance.hh @@ -4,8 +4,6 @@ /** \file * \ingroup draw_engine * - * This is an implementation of the Select engine specialized for selecting object. - * Should plug seamlessly inside the overlay engine logic. */ #pragma once @@ -18,19 +16,72 @@ #include "gpu_shader_create_info.hh" #include "select_defines.h" +#include "select_shader_shared.hh" namespace blender::draw::select { -struct EngineObject { +/** + * Dummy implementation of the select engine types to avoid any overhead. + * Bypass any selection logic. + */ +struct InstanceDummy { /* Add type safety to selection ID. Only the select engine should provide them. */ - struct ID { + class ID { + public: + constexpr uint32_t get() const + { + return 0; + } + }; + + struct SelectShader { + static void patch(gpu::shader::ShaderCreateInfo &){}; + }; + + struct SelectBuf { + void select_clear(){}; + void select_append(ID){}; + void select_bind(PassSimple &){}; + }; + + struct SelectMap { + [[nodiscard]] const ID select_id(const ObjectRef &, uint = 0) + { + return {}; + } + + void begin_sync(){}; + + void select_bind(PassSimple &){}; + + void select_bind(PassMain &){}; + + void end_sync(){}; + + void read_result(){}; + }; +}; + +/** + * This is an implementation of the Select engine specialized for selecting object. + * Should plug seamlessly inside the overlay engine logic. + */ +struct Instance { + /* Add type safety to selection ID. Only the select engine should provide them. */ + class ID { + public: uint32_t value; + + uint32_t get() const + { + return value; + } }; struct SelectShader { static void patch(gpu::shader::ShaderCreateInfo &info) { - info.define("SELECT_UNORDERED"); + info.define("SELECT_ENABLE"); /* Replace additional info. */ for (StringRefNull &str : info.additional_infos_) { if (str == "draw_modelmat_new") { @@ -43,7 +94,7 @@ struct EngineObject { /** * Add a dedicated selection id buffer to a pass. - * Use this when not using a #PassMain which can pass the select ID via CustomID. + * To be used when not using a #PassMain which can pass the select ID via CustomID. */ struct SelectBuf { StorageVectorBuffer select_buf = {"select_buf"}; @@ -55,7 +106,7 @@ struct EngineObject { void select_append(ID select_id) { - select_buf.append(select_id.value); + select_buf.append(select_id.get()); } void select_bind(PassSimple &pass) @@ -80,6 +131,8 @@ struct EngineObject { StorageArrayBuffer select_output_buf = {"select_output_buf"}; /** Dummy buffer. Might be better to remove, but simplify the shader create info patching. */ StorageArrayBuffer dummy_select_buf = {"dummy_select_buf"}; + /** Uniform buffer to bind to all passes to pass information about the selection state. */ + UniformBuffer info_buf; /* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object * reference directly. This would isolate the selection logic to this class. */ @@ -93,6 +146,12 @@ struct EngineObject { return {id}; } + /* Load an invalid index that will not write to the output (not selectable). */ + [[nodiscard]] const ID select_invalid_id() + { + return {uint32_t(-1)}; + } + void begin_sync() { select_id_map.clear(); @@ -101,14 +160,18 @@ struct EngineObject { #endif } + /** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */ void select_bind(PassSimple &pass) { + pass.bind_ubo(SELECT_DATA, &info_buf); pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf); } + /** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */ void select_bind(PassMain &pass) { pass.use_custom_ids = true; + pass.bind_ubo(SELECT_DATA, &info_buf); /* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */ pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf); pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf); @@ -116,6 +179,11 @@ struct EngineObject { void end_sync() { + info_buf.mode = SelectType::SELECT_ALL; + /* TODO: Should be select rect center. */ + info_buf.cursor = int2(512, 512); + info_buf.push_update(); + select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4)); select_output_buf.push_update(); select_output_buf.clear_to_zero(); diff --git a/source/blender/draw/engines/select/select_shader_shared.hh b/source/blender/draw/engines/select/select_shader_shared.hh new file mode 100644 index 00000000000..0538561d39b --- /dev/null +++ b/source/blender/draw/engines/select/select_shader_shared.hh @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef GPU_SHADER +# pragma once + +# include "GPU_shader_shared_utils.h" + +namespace blender::draw::select { + +#endif + +/* Matches eV3DSelectMode */ +enum SelectType : uint32_t { + SELECT_ALL = 0u, + SELECT_PICK_ALL = 1u, + SELECT_PICK_NEAREST = 2u, +}; + +struct SelectInfoData { + int2 cursor; + SelectType mode; + uint _pad0; +}; +BLI_STATIC_ASSERT_ALIGN(SelectInfoData, 16) + +#ifndef GPU_SHADER +} // namespace blender::draw::select +#endif diff --git a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh index 29750768a52..e415b176de6 100644 --- a/source/blender/draw/engines/select/shaders/infos/select_id_info.hh +++ b/source/blender/draw/engines/select/shaders/infos/select_id_info.hh @@ -44,7 +44,11 @@ GPU_SHADER_CREATE_INFO(select_id_uniform_clipped) /* Used to patch overlay shaders. */ GPU_SHADER_CREATE_INFO(select_id_patch) + .typedef_source("select_shader_shared.hh") .vertex_out(select_id_iface) + /* Need to make sure the depth & stencil comparison runs before the fragment shader. */ + .early_fragment_test(true) + .uniform_buf(SELECT_DATA, "SelectInfoData", "select_info_buf") /* Select IDs for instanced draw-calls not using #PassMain. */ .storage_buf(SELECT_ID_IN, Qualifier::READ, "int", "in_select_buf[]") /* Stores the result of the whole selection drawing. Content depends on selection mode. */ diff --git a/source/blender/draw/engines/select/shaders/select_lib.glsl b/source/blender/draw/engines/select/shaders/select_lib.glsl index 469773a1d6a..fc17c6edef8 100644 --- a/source/blender/draw/engines/select/shaders/select_lib.glsl +++ b/source/blender/draw/engines/select/shaders/select_lib.glsl @@ -1,5 +1,5 @@ -#if !(defined(SELECT_UNORDERED) || defined(SELECT_DEPTH_PICKING)) +#ifndef SELECT_ENABLE /* Avoid requesting the select_id when not in selection mode. */ # define select_id_set(select_id) # define select_id_output(select_id) @@ -16,19 +16,34 @@ void select_id_set(int id) void select_id_output(int id) { -# if defined(SELECT_UNORDERED) - /* Used by rectangle selection. - * Set the bit of the select id in the bitmap. */ - atomicOr(out_select_buf[id / 32u], 1u << (uint(id) % 32u)); + if (id == -1) { + /* Invalid index */ + return; + } -# elif defined(SELECT_DEPTH_PICKING) - /* Used by mouse-clicking selection. - * Stores the nearest depth for this select id. */ - atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z)); + if (select_info_buf.mode == SELECT_ALL) { + /* Set the bit of the select id in the bitmap. */ + atomicOr(out_select_buf[id / 32u], 1u << (uint(id) % 32u)); + } + else if (select_info_buf.mode == SELECT_PICK_ALL) { + /* Stores the nearest depth for this select id. */ + atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z)); + } + else if (select_info_buf.mode == SELECT_PICK_NEAREST) { + /* Stores the nearest depth with the distance to the cursor. */ -# else -# error -# endif + /* Distance function to the cursor. Currently a simple pixel ring distance. */ + ivec2 coord = abs(ivec2(gl_FragCoord.xy) - select_info_buf.cursor); + uint dist = uint(max(coord.x, coord.y)); + + uint depth = uint(gl_FragCoord.z * float(0x00FFFFFFu)); + + /* Reject hits outside of valid range. */ + if (dist < 0xFFu) { + /* Packed values to ensure the atomicMin is performed on the whole result. */ + atomicMin(out_select_buf[id], (depth << 8u) | dist); + } + } } #endif -- 2.30.2 From 3ac54f67bf450109a9052a6ede154e22a2d01190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Thu, 2 Mar 2023 16:26:05 +0100 Subject: [PATCH 19/22] Select-Next: Add result buffer injection This allow compatibility with the old system. --- source/blender/draw/CMakeLists.txt | 1 + .../draw/engines/overlay/overlay_instance.cc | 54 +++++--- .../draw/engines/overlay/overlay_instance.hh | 8 +- .../draw/engines/overlay/overlay_private.hh | 2 + .../draw/engines/select/select_engine.h | 12 ++ .../draw/engines/select/select_instance.cc | 117 ++++++++++++++++++ .../draw/engines/select/select_instance.hh | 77 +++++++++--- source/blender/draw/intern/draw_manager.c | 20 ++- .../editors/space_view3d/view3d_view.c | 4 +- source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/GPU_select.h | 9 ++ source/blender/gpu/intern/gpu_select.c | 53 +++++++- source/blender/gpu/intern/gpu_select_next.cc | 91 ++++++++++++++ .../blender/gpu/intern/gpu_select_private.h | 13 ++ 14 files changed, 415 insertions(+), 47 deletions(-) create mode 100644 source/blender/draw/engines/select/select_instance.cc create mode 100644 source/blender/gpu/intern/gpu_select_next.cc diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 453fa1de808..5afcc61ad75 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -191,6 +191,7 @@ set(SRC engines/gpencil/gpencil_shader_fx.c engines/select/select_draw_utils.c engines/select/select_engine.c + engines/select/select_instance.cc engines/overlay/overlay_antialiasing.cc engines/overlay/overlay_armature.cc engines/overlay/overlay_background.cc diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index c28f6c410fe..8afd91bb23a 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -12,11 +12,6 @@ namespace blender::draw::overlay { template void Instance::init() { - resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth); - resources.depth_in_front_tx.wrap(DRW_viewport_texture_list_get()->depth_in_front); - resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay); - resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color); - /* TODO(fclem): Remove DRW global usage. */ const DRWContextState *ctx = DRW_context_state_get(); /* Was needed by `object_wire_theme_id()` when doing the port. Not sure if needed nowadays. */ @@ -146,26 +141,41 @@ template void Instance::end_sync() template void Instance::draw(Manager &manager) { - /* WORKAROUND: This is to prevent crashes when using depth picking or selection. - * The selection engine should handle theses cases instead. */ - if (!DRW_state_is_fbo()) { - return; - } + resources.depth_tx.wrap(DRW_viewport_texture_list_get()->depth); + resources.depth_in_front_tx.wrap(DRW_viewport_texture_list_get()->depth_in_front); + resources.color_overlay_tx.wrap(DRW_viewport_texture_list_get()->color_overlay); + resources.color_render_tx.wrap(DRW_viewport_texture_list_get()->color); int2 render_size = int2(resources.depth_tx.size()); const DRWView *view_legacy = DRW_view_default_get(); View view("OverlayView", view_legacy); - resources.line_tx.acquire(render_size, GPU_RGBA8); + /* TODO: Better semantical switch? */ + if (!resources.color_overlay_tx.is_valid()) { + /* Likely to be the selection case. Allocate dummy texture and bind only depth buffer. */ + resources.line_tx.acquire(int2(1, 1), GPU_RGBA8); + resources.color_overlay_alloc_tx.acquire(int2(1, 1), GPU_SRGB8_A8); + resources.color_render_alloc_tx.acquire(int2(1, 1), GPU_SRGB8_A8); - resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), - GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); - resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), - GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx), - GPU_ATTACHMENT_TEXTURE(resources.line_tx)); - resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); + resources.color_overlay_tx.wrap(resources.color_overlay_alloc_tx); + resources.color_render_tx.wrap(resources.color_render_alloc_tx); + + resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx)); + resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx)); + resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE); + } + else { + resources.line_tx.acquire(render_size, GPU_RGBA8); + + resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); + resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx), + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx), + GPU_ATTACHMENT_TEXTURE(resources.line_tx)); + resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); + } /* TODO(fclem): Remove mandatory allocation. */ if (!resources.depth_in_front_tx.is_valid()) { @@ -201,6 +211,8 @@ template void Instance::draw(Manager &manager) resources.line_tx.release(); resources.depth_in_front_alloc_tx.release(); + resources.color_overlay_alloc_tx.release(); + resources.color_render_alloc_tx.release(); resources.read_result(); } @@ -212,6 +224,12 @@ template void Instance<>::object_sync(ObjectRef &ob_ref, Manager &manager); template void Instance<>::end_sync(); template void Instance<>::draw(Manager &manager); +template void Instance::init(); +template void Instance::begin_sync(); +template void Instance::object_sync(ObjectRef &ob_ref, Manager &manager); +template void Instance::end_sync(); +template void Instance::draw(Manager &manager); + } // namespace blender::draw::overlay /* TODO(fclem): Move elsewhere. */ diff --git a/source/blender/draw/engines/overlay/overlay_instance.hh b/source/blender/draw/engines/overlay/overlay_instance.hh index 08ba2e8c291..7fa290fdd79 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.hh +++ b/source/blender/draw/engines/overlay/overlay_instance.hh @@ -24,7 +24,7 @@ template< * selectable component and using a special shaders for drawing. * Making the select engine templated makes it easier to phase out any overhead of the * selection for the regular non-selection case.*/ - typename SelectEngineT = select::Instance> + typename SelectEngineT = select::InstanceDummy> class Instance { public: /* WORKAROUND: Legacy. Move to grid pass. */ @@ -93,4 +93,10 @@ extern template void Instance<>::object_sync(ObjectRef &ob_ref, Manager &manager extern template void Instance<>::end_sync(); extern template void Instance<>::draw(Manager &manager); +extern template void Instance::init(); +extern template void Instance::begin_sync(); +extern template void Instance::object_sync(ObjectRef &ob_ref, Manager &manager); +extern template void Instance::end_sync(); +extern template void Instance::draw(Manager &manager); + } // namespace blender::draw::overlay diff --git a/source/blender/draw/engines/overlay/overlay_private.hh b/source/blender/draw/engines/overlay/overlay_private.hh index a19eb31293c..64f31e4ab1d 100644 --- a/source/blender/draw/engines/overlay/overlay_private.hh +++ b/source/blender/draw/engines/overlay/overlay_private.hh @@ -75,6 +75,8 @@ template struct Resources : public SelectEngineT::Select TextureFromPool line_tx = {"line_tx"}; TextureFromPool depth_in_front_alloc_tx = {"overlay_depth_in_front_tx"}; + TextureFromPool color_overlay_alloc_tx = {"overlay_color_overlay_alloc_tx"}; + TextureFromPool color_render_alloc_tx = {"overlay_color_render_alloc_tx"}; /** TODO(fclem): Copy of G_data.block that should become theme colors only and managed by the * engine. */ diff --git a/source/blender/draw/engines/select/select_engine.h b/source/blender/draw/engines/select/select_engine.h index 2151d605578..4bd6afd1cd1 100644 --- a/source/blender/draw/engines/select/select_engine.h +++ b/source/blender/draw/engines/select/select_engine.h @@ -7,6 +7,10 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /* select_engine.c */ extern DrawEngineType draw_engine_select_type; @@ -22,3 +26,11 @@ struct SELECTID_Context *DRW_select_engine_context_get(void); struct GPUFrameBuffer *DRW_engine_select_framebuffer_get(void); struct GPUTexture *DRW_engine_select_texture_get(void); + +/* select_instance.cc */ + +extern DrawEngineType draw_engine_select_next_type; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/engines/select/select_instance.cc b/source/blender/draw/engines/select/select_instance.cc new file mode 100644 index 00000000000..6d422a1d190 --- /dev/null +++ b/source/blender/draw/engines/select/select_instance.cc @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup select + */ + +#include "DRW_render.h" + +#include "GPU_capabilities.h" + +#include "select_engine.h" + +#include "../overlay/overlay_instance.hh" +#include "select_instance.hh" + +using namespace blender::draw; + +/* -------------------------------------------------------------------- */ +/** \name Select-Next Engine + * \{ */ + +using Instance = overlay::Instance; + +typedef struct SELECT_NextData { + void *engine_type; + DRWViewportEmptyList *fbl; + DRWViewportEmptyList *txl; + DRWViewportEmptyList *psl; + DRWViewportEmptyList *stl; + + Instance *instance; +} SELECT_NextData; + +static void SELECT_next_engine_init(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + + OVERLAY_Data *ved = reinterpret_cast(vedata); + + if (ved->instance == nullptr) { + ved->instance = new Instance(); + } + + reinterpret_cast(ved->instance)->init(); +} + +static void SELECT_next_cache_init(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + reinterpret_cast(reinterpret_cast(vedata)->instance)->begin_sync(); +} + +static void SELECT_next_cache_populate(void *vedata, Object *object) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + ObjectRef ref; + ref.object = object; + ref.dupli_object = DRW_object_get_dupli(object); + ref.dupli_parent = DRW_object_get_dupli_parent(object); + + reinterpret_cast(reinterpret_cast(vedata)->instance) + ->object_sync(ref, *DRW_manager_get()); +} + +static void SELECT_next_cache_finish(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + reinterpret_cast(reinterpret_cast(vedata)->instance)->end_sync(); +} + +static void SELECT_next_draw_scene(void *vedata) +{ + if (!GPU_shader_storage_buffer_objects_support()) { + return; + } + + reinterpret_cast(reinterpret_cast(vedata)->instance) + ->draw(*DRW_manager_get()); +} + +static void SELECT_next_instance_free(void *instance_) +{ + auto *instance = (Instance *)instance_; + if (instance != nullptr) { + delete instance; + } +} + +static const DrawEngineDataSize SELECT_next_data_size = DRW_VIEWPORT_DATA_SIZE(SELECT_NextData); + +DrawEngineType draw_engine_select_next_type = { + NULL, + NULL, + N_("Select-Next"), + &SELECT_next_data_size, + &SELECT_next_engine_init, + NULL, + &SELECT_next_instance_free, + &SELECT_next_cache_init, + &SELECT_next_cache_populate, + &SELECT_next_cache_finish, + &SELECT_next_draw_scene, + NULL, + NULL, + NULL, + NULL, +}; + +/** \} */ \ No newline at end of file diff --git a/source/blender/draw/engines/select/select_instance.hh b/source/blender/draw/engines/select/select_instance.hh index 5609adc8b79..dca28d280ec 100644 --- a/source/blender/draw/engines/select/select_instance.hh +++ b/source/blender/draw/engines/select/select_instance.hh @@ -10,6 +10,10 @@ #include "DRW_gpu_wrapper.hh" +#include "GPU_select.h" + +#include "../intern/gpu_select_private.h" + #include "draw_manager.hh" #include "draw_pass.hh" @@ -133,6 +137,8 @@ struct Instance { StorageArrayBuffer dummy_select_buf = {"dummy_select_buf"}; /** Uniform buffer to bind to all passes to pass information about the selection state. */ UniformBuffer info_buf; + /** Will remove the depth test state from any pass drawing objects with select id. */ + bool disable_depth_test; /* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object * reference directly. This would isolate the selection logic to this class. */ @@ -154,23 +160,52 @@ struct Instance { void begin_sync() { + switch (gpu_select_next_get_mode()) { + case GPU_SELECT_ALL: + info_buf.mode = SelectType::SELECT_ALL; + disable_depth_test = true; + break; + /* Not sure if these 2 NEAREST are mapped to the right algorithm. */ + case GPU_SELECT_NEAREST_FIRST_PASS: + case GPU_SELECT_NEAREST_SECOND_PASS: + case GPU_SELECT_PICK_ALL: + info_buf.mode = SelectType::SELECT_PICK_ALL; + info_buf.cursor = int2(gpu_select_next_get_pick_area_center()); + disable_depth_test = true; + break; + case GPU_SELECT_PICK_NEAREST: + info_buf.mode = SelectType::SELECT_PICK_NEAREST; + info_buf.cursor = int2(gpu_select_next_get_pick_area_center()); + disable_depth_test = true; + break; + } + info_buf.push_update(); + select_id_map.clear(); #ifdef DEBUG map_names.clear(); #endif } - /** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */ + /** IMPORTANT: Changes the draw state. Need to be called after the pass own state_set. */ void select_bind(PassSimple &pass) { + if (disable_depth_test) { + /* TODO: clipping state. */ + pass.state_set(DRW_STATE_WRITE_COLOR); + } pass.bind_ubo(SELECT_DATA, &info_buf); pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf); } - /** IMPORTANT: Changes the draw state. Need to be called after the pass own state. */ + /** IMPORTANT: Changes the draw state. Need to be called after the pass own state_set. */ void select_bind(PassMain &pass) { pass.use_custom_ids = true; + if (disable_depth_test) { + /* TODO: clipping state. */ + pass.state_set(DRW_STATE_WRITE_COLOR); + } pass.bind_ubo(SELECT_DATA, &info_buf); /* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */ pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf); @@ -179,11 +214,6 @@ struct Instance { void end_sync() { - info_buf.mode = SelectType::SELECT_ALL; - /* TODO: Should be select rect center. */ - info_buf.cursor = int2(512, 512); - info_buf.push_update(); - select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4)); select_output_buf.push_update(); select_output_buf.clear_to_zero(); @@ -195,18 +225,31 @@ struct Instance { GPU_finish(); select_output_buf.read(); -#ifdef DEBUG - for (auto i : IndexRange(select_output_buf.size())) { - uint32_t word = select_output_buf[i]; - for (auto bit : IndexRange(32)) { - if ((word & 1) != 0) { - uint index = i * 32 + bit; - std::cout << index << map_names[index] << std::endl; + Vector result; + + /* Convert raw data from GPU to #GPUSelectResult. */ + switch (info_buf.mode) { + case SelectType::SELECT_ALL: + for (auto i : IndexRange(select_id_map.size())) { + if (((select_output_buf[i / 32] >> (i % 32)) & 1) != 0) { + result.append({select_id_map[i], 0xFFFFu}); + } } - word >>= 1; - } + break; + + case SelectType::SELECT_PICK_ALL: + case SelectType::SELECT_PICK_NEAREST: + for (auto i : IndexRange(select_id_map.size())) { + if (select_output_buf[i] != 0) { + /* NOTE: For `SELECT_PICK_NEAREST`, `select_output_buf` also contains the screen + * distance to cursor in the lowest bits. */ + result.append({select_id_map[i], select_output_buf[i]}); + } + } + break; } -#endif + + gpu_select_next_set_result(result.data(), result.size()); } }; }; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 5ed196f57cb..5030b1f9702 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2457,7 +2457,10 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DST.options.is_material_select = do_material_sub_selection; drw_task_graph_init(); /* Get list of enabled engines */ - if (use_obedit) { + if (U.experimental.enable_overlay_next) { + use_drw_engine(&draw_engine_select_next_type); + } + else if (use_obedit) { drw_engines_enable_overlays(); } else if (!draw_surface) { @@ -2566,6 +2569,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, draw_select_framebuffer_depth_only_setup(viewport_size); GPU_framebuffer_bind(g_select_buffer.framebuffer_depth_only); GPU_framebuffer_clear_depth(g_select_buffer.framebuffer_depth_only, 1.0f); + /* WORKAROUND: Needed for Select-Next for keeping the same codeflow as Overlay-Next. */ + BLI_assert(DRW_viewport_texture_list_get()->depth == NULL); + DRW_viewport_texture_list_get()->depth = g_select_buffer.texture_depth; /* Start Drawing */ DRW_state_reset(); @@ -2578,11 +2584,15 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) { break; } - DRW_state_lock(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_TEST_ENABLED); + if (!U.experimental.enable_overlay_next) { + DRW_state_lock(DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_TEST_ENABLED); + } drw_engines_draw_scene(); - DRW_state_lock(0); + if (!U.experimental.enable_overlay_next) { + DRW_state_lock(0); + } if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) { break; @@ -2591,6 +2601,9 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, DRW_smoke_exit(DST.vmempool); + /* WORKAROUND: Do not leave ownership to the viewport list. */ + DRW_viewport_texture_list_get()->depth = NULL; + DRW_state_reset(); drw_engines_disable(); @@ -3012,6 +3025,7 @@ void DRW_engines_register(void) DRW_engine_register(&draw_engine_overlay_type); DRW_engine_register(&draw_engine_overlay_next_type); + DRW_engine_register(&draw_engine_select_next_type); DRW_engine_register(&draw_engine_select_type); DRW_engine_register(&draw_engine_basic_type); DRW_engine_register(&draw_engine_compositor_type); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 4cc282a1cab..e0e6c61469c 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -485,7 +485,7 @@ static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data) bool continue_pass = false; struct DrawSelectLoopUserData *data = user_data; if (stage == DRW_SELECT_PASS_PRE) { - GPU_select_begin( + GPU_select_begin_next( data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits); /* always run POST after PRE. */ continue_pass = true; @@ -596,7 +596,7 @@ int view3d_opengl_select_ex(ViewContext *vc, /* Re-use cache (rect must be smaller than the cached) * other context is assumed to be unchanged */ if (GPU_select_is_cached()) { - GPU_select_begin(buffer, buffer_len, &rect, gpu_select_mode, 0); + GPU_select_begin_next(buffer, buffer_len, &rect, gpu_select_mode, 0); GPU_select_cache_load_id(); hits = GPU_select_end(); goto finally; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index b7f7770f3f2..d397dc3a853 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -68,6 +68,7 @@ set(SRC intern/gpu_platform.cc intern/gpu_query.cc intern/gpu_select.c + intern/gpu_select_next.cc intern/gpu_select_pick.c intern/gpu_select_sample_query.cc intern/gpu_shader.cc diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h index 8fb81c8a3b4..bca72542ad4 100644 --- a/source/blender/gpu/GPU_select.h +++ b/source/blender/gpu/GPU_select.h @@ -50,6 +50,15 @@ void GPU_select_begin(GPUSelectResult *buffer, const struct rcti *input, eGPUSelectMode mode, int oldhits); +/** + * Initialize and provide buffer for results. + * Uses the new Select-Next engine if enabled. + */ +void GPU_select_begin_next(GPUSelectResult *buffer, + const uint buffer_len, + const struct rcti *input, + eGPUSelectMode mode, + int oldhits); /** * Loads a new selection id and ends previous query, if any. * In second pass of selection it also returns diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c index 7afba20c2d9..e0dd3d62c64 100644 --- a/source/blender/gpu/intern/gpu_select.c +++ b/source/blender/gpu/intern/gpu_select.c @@ -10,6 +10,8 @@ #include #include +#include "DNA_userdef_types.h" + #include "GPU_select.h" #include "BLI_rect.h" @@ -30,6 +32,8 @@ typedef enum eGPUSelectAlgo { /** Read depth buffer for every drawing pass and extract depths, `gpu_select_pick.c` * Only sets 4th component (ID) correctly. */ ALGO_GL_PICK = 2, + /** Use Select-Next draw engine. */ + ALGO_SELECT_NEXT = 3, } eGPUSelectAlgo; typedef struct GPUSelectState { @@ -60,11 +64,12 @@ static GPUSelectState g_select_state = {0}; /** \name Public API * \{ */ -void GPU_select_begin(GPUSelectResult *buffer, - const uint buffer_len, - const rcti *input, - eGPUSelectMode mode, - int oldhits) +static void gpu_select_begin_ex(GPUSelectResult *buffer, + const uint buffer_len, + const rcti *input, + eGPUSelectMode mode, + int oldhits, + bool use_select_next) { if (mode == GPU_SELECT_NEAREST_SECOND_PASS) { /* In the case hits was '-1', @@ -76,7 +81,10 @@ void GPU_select_begin(GPUSelectResult *buffer, g_select_state.select_is_active = true; g_select_state.mode = mode; - if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) { + if (use_select_next) { + g_select_state.algorithm = ALGO_SELECT_NEXT; + } + else if (ELEM(g_select_state.mode, GPU_SELECT_PICK_ALL, GPU_SELECT_PICK_NEAREST)) { g_select_state.algorithm = ALGO_GL_PICK; } else { @@ -89,6 +97,7 @@ void GPU_select_begin(GPUSelectResult *buffer, g_select_state.use_cache_needs_init = false; switch (g_select_state.algorithm) { + case ALGO_SELECT_NEXT: case ALGO_GL_QUERY: { g_select_state.use_cache = false; break; @@ -102,6 +111,10 @@ void GPU_select_begin(GPUSelectResult *buffer, } switch (g_select_state.algorithm) { + case ALGO_SELECT_NEXT: { + gpu_select_next_begin(buffer, buffer_len, input, mode); + break; + } case ALGO_GL_QUERY: { gpu_select_query_begin(buffer, buffer_len, input, mode, oldhits); break; @@ -114,6 +127,25 @@ void GPU_select_begin(GPUSelectResult *buffer, } } +void GPU_select_begin_next(GPUSelectResult *buffer, + const uint buffer_len, + const rcti *input, + eGPUSelectMode mode, + int oldhits) +{ + gpu_select_begin_ex( + buffer, buffer_len, input, mode, oldhits, U.experimental.enable_overlay_next); +} + +void GPU_select_begin(GPUSelectResult *buffer, + const uint buffer_len, + const rcti *input, + eGPUSelectMode mode, + int oldhits) +{ + gpu_select_begin_ex(buffer, buffer_len, input, mode, oldhits, false); +} + bool GPU_select_load_id(uint id) { /* if no selection mode active, ignore */ @@ -122,6 +154,11 @@ bool GPU_select_load_id(uint id) } switch (g_select_state.algorithm) { + case ALGO_SELECT_NEXT: + /* This shouldn't use this pipeline. */ + BLI_assert_unreachable(); + return 0; + case ALGO_GL_QUERY: { return gpu_select_query_load_id(id); } @@ -137,6 +174,10 @@ uint GPU_select_end(void) uint hits = 0; switch (g_select_state.algorithm) { + case ALGO_SELECT_NEXT: { + hits = gpu_select_next_end(); + break; + } case ALGO_GL_QUERY: { hits = gpu_select_query_end(); break; diff --git a/source/blender/gpu/intern/gpu_select_next.cc b/source/blender/gpu/intern/gpu_select_next.cc new file mode 100644 index 00000000000..17724fa4fec --- /dev/null +++ b/source/blender/gpu/intern/gpu_select_next.cc @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2017 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup gpu + * + * Glue to make the new Select-Next engine work with the old GPU select API. + */ +#include + +#include "BLI_rect.h" +#include "BLI_span.hh" + +#include "GPU_select.h" + +#include "gpu_select_private.h" + +struct GPUSelectNextState { + /** Result buffer set on initialization. */ + GPUSelectResult *buffer; + uint buffer_len; + /** Area of the viewport to render / select from. */ + rcti rect; + /** Number of hits. Set to -1 if it overflows buffer_len. */ + uint hits; + /** Mode of operation. */ + eGPUSelectMode mode; +}; + +static GPUSelectNextState g_state = {}; + +void gpu_select_next_begin(GPUSelectResult *buffer, + uint buffer_len, + const rcti *input, + eGPUSelectMode mode) + +{ + g_state.buffer = buffer; + g_state.rect = *input; + g_state.buffer_len = buffer_len; + g_state.mode = mode; +} + +int gpu_select_next_get_pick_area_center() +{ + BLI_assert(BLI_rcti_size_x(&g_state.rect) == BLI_rcti_size_y(&g_state.rect)); + return BLI_rcti_size_x(&g_state.rect) / 2; +} + +eGPUSelectMode gpu_select_next_get_mode() +{ + return g_state.mode; +} + +void gpu_select_next_set_result(GPUSelectResult *hit_buf, uint hit_len) + +{ + if (hit_len > g_state.buffer_len) { + g_state.hits = -1; + return; + } + + blender::MutableSpan result(g_state.buffer, g_state.buffer_len); + blender::Span hits(hit_buf, hit_len); + + /* TODO(fclem): There might be some conversion to do to align to the other APIs output. */ + switch (g_state.mode) { + case eGPUSelectMode::GPU_SELECT_ALL: + result.take_front(hit_len).copy_from(hits); + break; + case eGPUSelectMode::GPU_SELECT_NEAREST_FIRST_PASS: + result.take_front(hit_len).copy_from(hits); + break; + case eGPUSelectMode::GPU_SELECT_NEAREST_SECOND_PASS: + result.take_front(hit_len).copy_from(hits); + break; + case eGPUSelectMode::GPU_SELECT_PICK_ALL: + result.take_front(hit_len).copy_from(hits); + break; + case eGPUSelectMode::GPU_SELECT_PICK_NEAREST: + result.take_front(hit_len).copy_from(hits); + break; + } + + g_state.hits = hit_len; +} + +uint gpu_select_next_end() +{ + return g_state.hits; +} diff --git a/source/blender/gpu/intern/gpu_select_private.h b/source/blender/gpu/intern/gpu_select_private.h index 1b9a69f0e07..0b564ee7012 100644 --- a/source/blender/gpu/intern/gpu_select_private.h +++ b/source/blender/gpu/intern/gpu_select_private.h @@ -37,6 +37,19 @@ void gpu_select_query_begin( bool gpu_select_query_load_id(uint id); uint gpu_select_query_end(void); +/* gpu_select_next */ + +void gpu_select_next_begin(GPUSelectResult *buffer, + uint buffer_len, + const rcti *input, + eGPUSelectMode mode); +uint gpu_select_next_end(void); + +/* Return a single offset since picking uses squared viewport. */ +int gpu_select_next_get_pick_area_center(void); +eGPUSelectMode gpu_select_next_get_mode(void); +void gpu_select_next_set_result(GPUSelectResult *buffer, uint buffer_len); + #define SELECT_ID_NONE ((uint)0xffffffff) #ifdef __cplusplus -- 2.30.2 From f25b2156dfec45e946cf99d095879268fb3ddd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 17 Apr 2023 16:23:34 +0200 Subject: [PATCH 20/22] Fix crash when using old overlay engine before enabling overlay-next --- .../draw/engines/overlay/overlay_shader.cc | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/source/blender/draw/engines/overlay/overlay_shader.cc b/source/blender/draw/engines/overlay/overlay_shader.cc index 6951e9acf33..d29cb7ba400 100644 --- a/source/blender/draw/engines/overlay/overlay_shader.cc +++ b/source/blender/draw/engines/overlay/overlay_shader.cc @@ -150,16 +150,6 @@ GPUShader *OVERLAY_shader_depth_only(void) const DRWContextState *draw_ctx = DRW_context_state_get(); OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; if (!sh_data->depth_only) { - if (U.experimental.enable_overlay_next) { - using namespace blender::gpu::shader; - ShaderCreateInfo &info = const_cast( - *reinterpret_cast( - GPU_shader_create_info_get("overlay_depth_only"))); - - info.additional_infos_.clear(); - info.additional_info("draw_view", "draw_modelmat_new", "draw_resource_handle_new"); - } - sh_data->depth_only = GPU_shader_create_from_info_name( (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "overlay_depth_only_clipped" : "overlay_depth_only"); @@ -211,17 +201,6 @@ GPUShader *OVERLAY_shader_armature_sphere(bool use_outline) const DRWContextState *draw_ctx = DRW_context_state_get(); OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; if (use_outline && !sh_data->armature_sphere_outline) { - using namespace blender::gpu::shader; - ShaderCreateInfo &info = const_cast( - *reinterpret_cast( - GPU_shader_create_info_get("overlay_armature_sphere_outline"))); - - if (U.experimental.enable_overlay_next) { - info.storage_buf(0, Qualifier::READ, "mat4", "data_buf[]"); - info.define("inst_obmat", "data_buf[gl_InstanceID]"); - info.vertex_inputs_.pop_last(); - } - sh_data->armature_sphere_outline = GPU_shader_create_from_info_name( (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? "overlay_armature_sphere_outline_clipped" : "overlay_armature_sphere_outline"); @@ -515,18 +494,6 @@ GPUShader *OVERLAY_shader_extra(bool is_select) OVERLAY_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; GPUShader **sh = (is_select) ? &sh_data->extra_select : &sh_data->extra; if (!*sh) { - using namespace blender::gpu::shader; - ShaderCreateInfo &info = const_cast( - *reinterpret_cast(GPU_shader_create_info_get("overlay_extra"))); - - if (U.experimental.enable_overlay_next) { - info.storage_buf(0, Qualifier::READ, "ExtraInstanceData", "data_buf[]"); - info.define("color", "data_buf[gl_InstanceID].color_"); - info.define("inst_obmat", "data_buf[gl_InstanceID].object_to_world_"); - info.vertex_inputs_.pop_last(); - info.vertex_inputs_.pop_last(); - } - *sh = GPU_shader_create_from_info_name( (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) ? (is_select ? "overlay_extra_select_clipped" : "overlay_extra_clipped") : -- 2.30.2 From d9fd7397329e95a936959b9241cae753db5453d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 17 Apr 2023 16:58:52 +0200 Subject: [PATCH 21/22] Fix assert in gpu debug mode --- source/blender/draw/engines/overlay/overlay_instance.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/draw/engines/overlay/overlay_instance.cc b/source/blender/draw/engines/overlay/overlay_instance.cc index 7b6729cbd5a..01429aae1e2 100644 --- a/source/blender/draw/engines/overlay/overlay_instance.cc +++ b/source/blender/draw/engines/overlay/overlay_instance.cc @@ -163,7 +163,9 @@ template void Instance::draw(Manager &manager) resources.overlay_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx)); resources.overlay_line_fb.ensure(GPU_ATTACHMENT_TEXTURE(resources.depth_tx)); - resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE); + /* Create it but shouldn't even be used. */ + resources.overlay_color_only_fb.ensure(GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(resources.color_overlay_tx)); } else { resources.line_tx.acquire(render_size, GPU_RGBA8); -- 2.30.2 From ba2992719054617496f5c84f19e6a1fc7dd89b1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 17 Apr 2023 16:59:05 +0200 Subject: [PATCH 22/22] Fix buggy selection --- .../blender/draw/engines/select/select_instance.hh | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/blender/draw/engines/select/select_instance.hh b/source/blender/draw/engines/select/select_instance.hh index dca28d280ec..d96ebd7722a 100644 --- a/source/blender/draw/engines/select/select_instance.hh +++ b/source/blender/draw/engines/select/select_instance.hh @@ -216,13 +216,19 @@ struct Instance { { select_output_buf.resize(ceil_to_multiple_u(select_id_map.size(), 4)); select_output_buf.push_update(); - select_output_buf.clear_to_zero(); + if (info_buf.mode == SelectType::SELECT_ALL) { + /* This mode uses atomicOr and store result as a bitmap. Clear to 0 (no selection). */ + GPU_storagebuf_clear(select_output_buf, 0); + } + else { + /* Other modes use atomicMin. Clear to UINT_MAX. */ + GPU_storagebuf_clear(select_output_buf, 0xFFFFFFFFu); + } } void read_result() { - /* TODO right barrier. */ - GPU_finish(); + GPU_memory_barrier(GPU_BARRIER_BUFFER_UPDATE); select_output_buf.read(); Vector result; @@ -240,7 +246,7 @@ struct Instance { case SelectType::SELECT_PICK_ALL: case SelectType::SELECT_PICK_NEAREST: for (auto i : IndexRange(select_id_map.size())) { - if (select_output_buf[i] != 0) { + if (select_output_buf[i] != 0xFFFFFFFFu) { /* NOTE: For `SELECT_PICK_NEAREST`, `select_output_buf` also contains the screen * distance to cursor in the lowest bits. */ result.append({select_id_map[i], select_output_buf[i]}); -- 2.30.2