From bfb6ea898bf10a445cd331024e8e3abcb8bba1c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Mon, 14 Nov 2022 00:42:31 +0100 Subject: [PATCH] DRW: View: Add base for multi-view support This implements the base needed for supporting multiple view concurently inside the same drawcall. The view used by common macros and view related functions is indexed using a global variable `drw_view_id` which can be set arbitrarly or read from the `drw_ResourceID`. This is needed for EEVEE-Next shadow but can be used for other purpose in the future. Note that a shader specialization is needed for it to work. `DRW_VIEW_LEN` needs to be defined to the amount of view the shader will access. The number of views contained in a `draw::View` is set at construction time. Note that the maximum number of object correctly drawn by the shaders using multiple views will be lower than thoses who don't. --- source/blender/draw/intern/draw_command.cc | 6 +- source/blender/draw/intern/draw_command.hh | 4 +- source/blender/draw/intern/draw_manager.cc | 7 +- .../blender/draw/intern/draw_shader_shared.h | 39 ++++++++ source/blender/draw/intern/draw_view.cc | 76 ++++++++------- source/blender/draw/intern/draw_view.hh | 95 ++++++++++++------- .../draw/intern/shaders/common_view_lib.glsl | 2 +- .../shaders/draw_command_generate_comp.glsl | 40 ++++++-- .../draw/intern/shaders/draw_view_info.hh | 11 ++- .../intern/shaders/draw_visibility_comp.glsl | 33 ++++--- .../gpu/intern/gpu_shader_interface.hh | 4 +- 11 files changed, 224 insertions(+), 93 deletions(-) diff --git a/source/blender/draw/intern/draw_command.cc b/source/blender/draw/intern/draw_command.cc index 69e1c069ff8..98c20a9e695 100644 --- a/source/blender/draw/intern/draw_command.cc +++ b/source/blender/draw/intern/draw_command.cc @@ -567,7 +567,9 @@ void DrawCommandBuf::bind(RecordingState &state, void DrawMultiBuf::bind(RecordingState &state, Vector &headers, Vector &commands, - VisibilityBuf &visibility_buf) + VisibilityBuf &visibility_buf, + int visibility_word_per_draw, + int view_len) { UNUSED_VARS(headers, commands); @@ -607,6 +609,8 @@ void DrawMultiBuf::bind(RecordingState &state, GPUShader *shader = DRW_shader_draw_command_generate_get(); GPU_shader_bind(shader); GPU_shader_uniform_1i(shader, "prototype_len", prototype_count_); + GPU_shader_uniform_1i(shader, "visibility_word_per_draw", visibility_word_per_draw); + GPU_shader_uniform_1i(shader, "view_shift", log2_ceil_u(view_len)); GPU_storagebuf_bind(group_buf_, GPU_shader_get_ssbo(shader, "group_buf")); GPU_storagebuf_bind(visibility_buf, GPU_shader_get_ssbo(shader, "visibility_buf")); GPU_storagebuf_bind(prototype_buf_, GPU_shader_get_ssbo(shader, "prototype_buf")); diff --git a/source/blender/draw/intern/draw_command.hh b/source/blender/draw/intern/draw_command.hh index 607f0b36583..f13bc2ea49d 100644 --- a/source/blender/draw/intern/draw_command.hh +++ b/source/blender/draw/intern/draw_command.hh @@ -558,7 +558,9 @@ class DrawMultiBuf { void bind(RecordingState &state, Vector &headers, Vector &commands, - VisibilityBuf &visibility_buf); + VisibilityBuf &visibility_buf, + int visibility_word_per_draw, + int view_len); }; /** \} */ diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc index c644cadd18c..37ed1de1dfe 100644 --- a/source/blender/draw/intern/draw_manager.cc +++ b/source/blender/draw/intern/draw_manager.cc @@ -171,7 +171,12 @@ void Manager::submit(PassMain &pass, View &view) command::RecordingState state; state.inverted_view = view.is_inverted(); - pass.draw_commands_buf_.bind(state, pass.headers_, pass.commands_, view.visibility_buf_); + pass.draw_commands_buf_.bind(state, + pass.headers_, + pass.commands_, + view.visibility_buf_, + view.visibility_word_per_draw(), + view.view_len_); resource_bind(); diff --git a/source/blender/draw/intern/draw_shader_shared.h b/source/blender/draw/intern/draw_shader_shared.h index 75a7e28fa75..0733468631c 100644 --- a/source/blender/draw/intern/draw_shader_shared.h +++ b/source/blender/draw/intern/draw_shader_shared.h @@ -54,6 +54,45 @@ typedef enum eObjectInfoFlag eObjectInfoFlag; * This should be kept in sync with `GPU_ATTR_MAX` */ #define DRW_ATTRIBUTE_PER_CURVES_MAX 15 +/* -------------------------------------------------------------------- */ +/** \name Views + * \{ */ + +/** + * The maximum of indexable views is dictated by: + * - The UBO limit (16KiB) of the ViewMatrices container. + * - The maximum resource index supported for shaders using multi-view (see DRW_VIEW_SHIFT). + */ +#define DRW_VIEW_MAX 64 + +#ifndef DRW_VIEW_LEN +/* Single-view case (default). */ +# define drw_view_id 0 +# define DRW_VIEW_LEN 1 +# define DRW_VIEW_SHIFT 0 +#else + +/* Multi-view case. */ +/** This should be already defined at shaderCreateInfo level. */ +// # define DRW_VIEW_LEN 64 +/** Global that needs to be set correctly in each shader stage. */ +uint drw_view_id = 0; +/** + * In order to reduce the memory requirements, the view id is merged with resource id to avoid + * doubling the memory required only for view indexing. + */ +/** \note This is simply log2(DRW_VIEW_LEN) but making sure it is optimized out. */ +# define DRW_VIEW_SHIFT \ + ((DRW_VIEW_LEN > 32) ? 6 : \ + (DRW_VIEW_LEN > 16) ? 5 : \ + (DRW_VIEW_LEN > 8) ? 4 : \ + (DRW_VIEW_LEN > 4) ? 3 : \ + (DRW_VIEW_LEN > 2) ? 2 : \ + 1) +# define DRW_VIEW_MASK ~(0xFFFFFFFFu << DRW_VIEW_SHIFT) +# define DRW_VIEW_FROM_RESOURCE_ID (drw_ResourceID & DRW_VIEW_MASK) +#endif + struct ViewCullingData { /** \note vec3 array padded to vec4. */ /** Frustum corners. */ diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc index cf86558f80f..28e8bef912b 100644 --- a/source/blender/draw/intern/draw_view.cc +++ b/source/blender/draw/intern/draw_view.cc @@ -15,25 +15,25 @@ namespace blender::draw { -void View::sync(const float4x4 &view_mat, const float4x4 &win_mat) +void View::sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id) { - data_.viewmat = view_mat; - data_.viewinv = view_mat.inverted(); - data_.winmat = win_mat; - data_.wininv = win_mat.inverted(); + data_[view_id].viewmat = view_mat; + data_[view_id].viewinv = view_mat.inverted(); + data_[view_id].winmat = win_mat; + data_[view_id].wininv = win_mat.inverted(); is_inverted_ = (is_negative_m4(view_mat.ptr()) == is_negative_m4(win_mat.ptr())); - BoundBox &bound_box = *reinterpret_cast(&culling_.corners); - BoundSphere &bound_sphere = *reinterpret_cast(&culling_.bound_sphere); - frustum_boundbox_calc(bound_box); - frustum_culling_planes_calc(); - frustum_culling_sphere_calc(bound_box, bound_sphere); + BoundBox &bound_box = *reinterpret_cast(&culling_[view_id].corners); + BoundSphere &bound_sphere = *reinterpret_cast(&culling_[view_id].bound_sphere); + frustum_boundbox_calc(bound_box, view_id); + frustum_culling_planes_calc(view_id); + frustum_culling_sphere_calc(bound_box, bound_sphere, view_id); dirty_ = true; } -void View::frustum_boundbox_calc(BoundBox &bbox) +void View::frustum_boundbox_calc(BoundBox &bbox, int view_id) { /* Extract the 8 corners from a Projection Matrix. */ #if 0 /* Equivalent to this but it has accuracy problems. */ @@ -44,9 +44,9 @@ void View::frustum_boundbox_calc(BoundBox &bbox) #endif float left, right, bottom, top, near, far; - bool is_persp = data_.winmat[3][3] == 0.0f; + bool is_persp = data_[view_id].winmat[3][3] == 0.0f; - projmat_dimensions(data_.winmat.ptr(), &left, &right, &bottom, &top, &near, &far); + projmat_dimensions(data_[view_id].winmat.ptr(), &left, &right, &bottom, &top, &near, &far); bbox.vec[0][2] = bbox.vec[3][2] = bbox.vec[7][2] = bbox.vec[4][2] = -near; bbox.vec[0][0] = bbox.vec[3][0] = left; @@ -71,31 +71,31 @@ void View::frustum_boundbox_calc(BoundBox &bbox) /* Transform into world space. */ for (int i = 0; i < 8; i++) { - mul_m4_v3(data_.viewinv.ptr(), bbox.vec[i]); + mul_m4_v3(data_[view_id].viewinv.ptr(), bbox.vec[i]); } } -void View::frustum_culling_planes_calc() +void View::frustum_culling_planes_calc(int view_id) { - float4x4 persmat = data_.winmat * data_.viewmat; + float4x4 persmat = data_[view_id].winmat * data_[view_id].viewmat; planes_from_projmat(persmat.ptr(), - culling_.planes[0], - culling_.planes[5], - culling_.planes[1], - culling_.planes[3], - culling_.planes[4], - culling_.planes[2]); + culling_[view_id].planes[0], + culling_[view_id].planes[5], + culling_[view_id].planes[1], + culling_[view_id].planes[3], + culling_[view_id].planes[4], + culling_[view_id].planes[2]); /* Normalize. */ for (int p = 0; p < 6; p++) { - culling_.planes[p].w /= normalize_v3(culling_.planes[p]); + culling_[view_id].planes[p].w /= normalize_v3(culling_[view_id].planes[p]); } } -void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere) +void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere, int view_id) { /* Extract Bounding Sphere */ - if (data_.winmat[3][3] != 0.0f) { + if (data_[view_id].winmat[3][3] != 0.0f) { /* Orthographic */ /* The most extreme points on the near and far plane. (normalized device coords). */ const float *nearpoint = bbox.vec[0]; @@ -105,7 +105,7 @@ void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bspher mid_v3_v3v3(bsphere.center, farpoint, nearpoint); bsphere.radius = len_v3v3(bsphere.center, farpoint); } - else if (data_.winmat[2][0] == 0.0f && data_.winmat[2][1] == 0.0f) { + else if (data_[view_id].winmat[2][0] == 0.0f && data_[view_id].winmat[2][1] == 0.0f) { /* Perspective with symmetrical frustum. */ /* We obtain the center and radius of the circumscribed circle of the @@ -157,7 +157,7 @@ void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bspher float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */ for (int i = 0; i < 4; i++) { float point[3]; - mul_v3_project_m4_v3(point, data_.wininv.ptr(), corner); + mul_v3_project_m4_v3(point, data_[view_id].wininv.ptr(), corner); float len = len_squared_v3(point); if (len > F) { copy_v3_v3(nfar, corner); @@ -175,7 +175,7 @@ void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bspher mul_v3_fl(farcenter, 0.25f); /* the extreme near point is the opposite point on the near clipping plane */ copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f); - mul_v3_project_m4_v3(nearpoint, data_.wininv.ptr(), nfar); + mul_v3_project_m4_v3(nearpoint, data_[view_id].wininv.ptr(), nfar); /* this is a frustum projection */ N = len_squared_v3(nearpoint); e = farpoint[2]; @@ -197,8 +197,8 @@ void View::frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bspher /* For XR, the view matrix may contain a scale factor. Then, transforming only the center * into world space after calculating the radius will result in incorrect behavior. */ - mul_m4_v3(data_.viewinv.ptr(), bsphere.center); /* Transform to world space. */ - mul_m4_v3(data_.viewinv.ptr(), farpoint); + mul_m4_v3(data_[view_id].viewinv.ptr(), bsphere.center); /* Transform to world space. */ + mul_m4_v3(data_[view_id].viewinv.ptr(), farpoint); bsphere.radius = len_v3v3(bsphere.center, farpoint); } } @@ -218,14 +218,14 @@ void View::bind() void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool debug_freeze) { if (debug_freeze && frozen_ == false) { - data_freeze_ = static_cast(data_); + data_freeze_[0] = static_cast(data_[0]); data_freeze_.push_update(); - culling_freeze_ = static_cast(culling_); + culling_freeze_[0] = static_cast(culling_[0]); culling_freeze_.push_update(); } #ifdef DEBUG if (debug_freeze) { - float4x4 persmat = data_freeze_.winmat * data_freeze_.viewmat; + float4x4 persmat = data_freeze_[0].winmat * data_freeze_[0].viewmat; drw_debug_matrix_as_bbox(persmat.inverted(), float4(0, 1, 0, 1)); } #endif @@ -234,8 +234,14 @@ void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool d GPU_debug_group_begin("View.compute_visibility"); /* TODO(fclem): Early out if visibility hasn't changed. */ + + uint word_per_draw = this->visibility_word_per_draw(); + /* Switch between tightly packed and set of whole word per instance. */ + uint words_len = (view_len_ == 1) ? divide_ceil_u(resource_len, 32) : + resource_len * word_per_draw; + words_len = ceil_to_multiple_u(max_ii(1, words_len), 4); /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */ - visibility_buf_.resize(divide_ceil_u(resource_len, 128)); + visibility_buf_.resize(words_len); uint32_t data = 0xFFFFFFFFu; GPU_storagebuf_clear(visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); @@ -244,6 +250,8 @@ void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool d GPUShader *shader = DRW_shader_draw_visibility_compute_get(); GPU_shader_bind(shader); GPU_shader_uniform_1i(shader, "resource_len", resource_len); + GPU_shader_uniform_1i(shader, "view_len", view_len_); + GPU_shader_uniform_1i(shader, "visibility_word_per_draw", word_per_draw); GPU_storagebuf_bind(bounds, GPU_shader_get_ssbo(shader, "bounds_buf")); GPU_storagebuf_bind(visibility_buf_, GPU_shader_get_ssbo(shader, "visibility_buf")); GPU_uniformbuf_bind((frozen_) ? data_freeze_ : data_, DRW_VIEW_UBO_SLOT); diff --git a/source/blender/draw/intern/draw_view.hh b/source/blender/draw/intern/draw_view.hh index 94fb62508bb..03296c76e60 100644 --- a/source/blender/draw/intern/draw_view.hh +++ b/source/blender/draw/intern/draw_view.hh @@ -5,6 +5,15 @@ /** \file * \ingroup draw + * + * View description and states. + * + * A `draw::View` object is required for drawing geometry using the DRW api and its internal + * culling system. + * + * One `View` object can actually contain multiple view matrices if the template parameter + * `view_len` is greater than 1. This is called multi-view rendering and the vertex shader must + * setting `drw_view_id` accordingly. */ #include "DRW_gpu_wrapper.hh" @@ -18,32 +27,41 @@ class Manager; /* TODO: de-duplicate. */ using ObjectBoundsBuf = StorageArrayBuffer; -/** \note Using uint4 for declaration but bound as uint. */ -using VisibilityBuf = StorageArrayBuffer; +using VisibilityBuf = StorageArrayBuffer; class View { friend Manager; private: - UniformBuffer data_; - UniformBuffer culling_; + /** TODO(fclem): Maybe try to reduce the minimum cost if the number of view is lower. */ + + UniformArrayBuffer data_; + UniformArrayBuffer culling_; /** Frozen version of data_ used for debugging culling. */ - UniformBuffer data_freeze_; - UniformBuffer culling_freeze_; - /** Result of the visibility computation. 1 bit per resource ID. */ + UniformArrayBuffer data_freeze_; + UniformArrayBuffer culling_freeze_; + /** Result of the visibility computation. 1 bit or 1 or 2 word per resource ID per view. */ VisibilityBuf visibility_buf_; const char *debug_name_; + int view_len_ = 0; + bool is_inverted_ = false; bool do_visibility_ = true; bool dirty_ = true; bool frozen_ = false; public: - View(const char *name) : visibility_buf_(name), debug_name_(name){}; + View(const char *name, int view_len = 1) + : visibility_buf_(name), debug_name_(name), view_len_(view_len) + { + BLI_assert(view_len < DRW_VIEW_MAX); + } + /* For compatibility with old system. Will be removed at some point. */ - View(const char *name, const DRWView *view) : visibility_buf_(name), debug_name_(name) + View(const char *name, const DRWView *view) + : visibility_buf_(name), debug_name_(name), view_len_(1) { float4x4 view_mat, win_mat; DRW_view_viewmat_get(view, view_mat.ptr(), false); @@ -51,52 +69,65 @@ class View { this->sync(view_mat, win_mat); } - void sync(const float4x4 &view_mat, const float4x4 &win_mat); + void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id = 0); - bool is_persp() const + bool is_persp(int view_id = 0) const { - return data_.winmat[3][3] == 0.0f; + BLI_assert(view_id < view_len_); + return data_[view_id].winmat[3][3] == 0.0f; } - bool is_inverted() const + bool is_inverted(int view_id = 0) const { + BLI_assert(view_id < view_len_); return is_inverted_; } - float far_clip() const + float far_clip(int view_id = 0) const { - if (is_persp()) { - return -data_.winmat[3][2] / (data_.winmat[2][2] + 1.0f); + BLI_assert(view_id < view_len_); + if (is_persp(view_id)) { + return -data_[view_id].winmat[3][2] / (data_[view_id].winmat[2][2] + 1.0f); } - return -(data_.winmat[3][2] - 1.0f) / data_.winmat[2][2]; + return -(data_[view_id].winmat[3][2] - 1.0f) / data_[view_id].winmat[2][2]; } - float near_clip() const + float near_clip(int view_id = 0) const { - if (is_persp()) { - return -data_.winmat[3][2] / (data_.winmat[2][2] - 1.0f); + BLI_assert(view_id < view_len_); + if (is_persp(view_id)) { + return -data_[view_id].winmat[3][2] / (data_[view_id].winmat[2][2] - 1.0f); } - return -(data_.winmat[3][2] + 1.0f) / data_.winmat[2][2]; + return -(data_[view_id].winmat[3][2] + 1.0f) / data_[view_id].winmat[2][2]; } - const float4x4 &viewmat() const + const float4x4 &viewmat(int view_id = 0) const { - return data_.viewmat; + BLI_assert(view_id < view_len_); + return data_[view_id].viewmat; } - const float4x4 &viewinv() const + const float4x4 &viewinv(int view_id = 0) const { - return data_.viewinv; + BLI_assert(view_id < view_len_); + return data_[view_id].viewinv; } - const float4x4 &winmat() const + const float4x4 &winmat(int view_id = 0) const { - return data_.winmat; + BLI_assert(view_id < view_len_); + return data_[view_id].winmat; } - const float4x4 &wininv() const + const float4x4 &wininv(int view_id = 0) const { - return data_.wininv; + BLI_assert(view_id < view_len_); + return data_[view_id].wininv; + } + + int visibility_word_per_draw() const + { + return (view_len_ == 1) ? 0 : divide_ceil_u(view_len_, 32); } private: @@ -106,9 +137,9 @@ class View { void update_viewport_size(); - void frustum_boundbox_calc(BoundBox &bbox); - void frustum_culling_planes_calc(); - void frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere); + void frustum_boundbox_calc(BoundBox &bbox, int view_id); + void frustum_culling_planes_calc(int view_id); + void frustum_culling_sphere_calc(const BoundBox &bbox, BoundSphere &bsphere, int view_id); }; } // namespace blender::draw diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index 90c1e0490b8..6ae58f71a1b 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -137,7 +137,7 @@ uniform int drw_ResourceID; # elif defined(GPU_VERTEX_SHADER) # if defined(UNIFORM_RESOURCE_ID_NEW) -# define resource_id drw_ResourceID +# define resource_id (drw_ResourceID >> DRW_VIEW_SHIFT) # else # define resource_id gpu_InstanceIndex # endif diff --git a/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl b/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl index 3e640540777..b08c5a4d314 100644 --- a/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl @@ -47,7 +47,19 @@ void main() uint resource_index = (proto.resource_handle & 0x7FFFFFFFu); /* Visibility test result. */ - bool is_visible = ((visibility_buf[resource_index / 32u] & (1u << (resource_index % 32u)))) != 0; + uint visible_instance_len = 0; + if (visibility_word_per_draw > 0) { + uint visibility_word = resource_index * visibility_word_per_draw; + for (uint i = 0; i < visibility_word_per_draw; i++, visibility_word++) { + visible_instance_len += bitCount(visibility_buf[visibility_word]); + } + } + else { + if ((visibility_buf[resource_index / 32u] & (1u << (resource_index % 32u))) != 0) { + visible_instance_len = proto.instance_len; + } + } + bool is_visible = visible_instance_len > 0; DrawGroup group = group_buf[group_id]; @@ -63,22 +75,38 @@ void main() uint front_facing_len = group.front_facing_len; uint dst_index = group.start; if (is_inverted) { - uint offset = atomicAdd(group_buf[group_id].back_facing_counter, proto.instance_len); + uint offset = atomicAdd(group_buf[group_id].back_facing_counter, visible_instance_len); dst_index += offset; if (atomicAddAndGet(group_buf[group_id].total_counter, proto.instance_len) == group.len) { write_draw_call(group, group_id); } } else { - uint offset = atomicAdd(group_buf[group_id].front_facing_counter, proto.instance_len); + uint offset = atomicAdd(group_buf[group_id].front_facing_counter, visible_instance_len); dst_index += back_facing_len + offset; if (atomicAddAndGet(group_buf[group_id].total_counter, proto.instance_len) == group.len) { write_draw_call(group, group_id); } } - for (uint i = dst_index; i < dst_index + proto.instance_len; i++) { - /* Fill resource_id buffer for each instance of this draw */ - resource_id_buf[i] = resource_index; + /* Fill resource_id buffer for each instance of this draw */ + if (visibility_word_per_draw > 0) { + uint visibility_word = resource_index * visibility_word_per_draw; + for (uint i = 0; i < visibility_word_per_draw; i++, visibility_word++) { + uint word = visibility_buf[visibility_word]; + uint view_index = i * 32u; + while (word != 0u) { + if ((word & 1u) != 0u) { + resource_id_buf[dst_index++] = view_index | (resource_index << view_shift); + } + view_index++; + word >>= 1u; + } + } + } + else { + for (uint i = dst_index; i < dst_index + visible_instance_len; i++) { + resource_id_buf[i] = resource_index; + } } } diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index 23892a39062..ebac78d8044 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -45,11 +45,13 @@ GPU_SHADER_CREATE_INFO(draw_resource_handle) * \{ */ GPU_SHADER_CREATE_INFO(draw_view) - .uniform_buf(DRW_VIEW_UBO_SLOT, "ViewMatrices", "drw_view", Frequency::PASS) + .uniform_buf(DRW_VIEW_UBO_SLOT, "ViewMatrices", "drw_view_[DRW_VIEW_LEN]", Frequency::PASS) + .define("drw_view", "drw_view_[drw_view_id]") .typedef_source("draw_shader_shared.h"); GPU_SHADER_CREATE_INFO(draw_view_culling) - .uniform_buf(DRW_VIEW_CULLING_UBO_SLOT, "ViewCullingData", "drw_view_culling") + .uniform_buf(DRW_VIEW_CULLING_UBO_SLOT, "ViewCullingData", "drw_view_culling_[DRW_VIEW_LEN]") + .define("drw_view_culling", "drw_view_culling_[drw_view_id]") .typedef_source("draw_shader_shared.h"); GPU_SHADER_CREATE_INFO(draw_modelmat) @@ -150,9 +152,12 @@ GPU_SHADER_CREATE_INFO(draw_resource_finalize) GPU_SHADER_CREATE_INFO(draw_visibility_compute) .do_static_compilation(true) .local_group_size(DRW_VISIBILITY_GROUP_SIZE) + .define("DRW_VIEW_LEN", "64") .storage_buf(0, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .storage_buf(1, Qualifier::READ_WRITE, "uint", "visibility_buf[]") .push_constant(Type::INT, "resource_len") + .push_constant(Type::INT, "view_len") + .push_constant(Type::INT, "visibility_word_per_draw") .compute_source("draw_visibility_comp.glsl") .additional_info("draw_view", "draw_view_culling"); @@ -167,6 +172,8 @@ GPU_SHADER_CREATE_INFO(draw_command_generate) .storage_buf(3, Qualifier::WRITE, "DrawCommand", "command_buf[]") .storage_buf(DRW_RESOURCE_ID_SLOT, Qualifier::WRITE, "uint", "resource_id_buf[]") .push_constant(Type::INT, "prototype_len") + .push_constant(Type::INT, "visibility_word_per_draw") + .push_constant(Type::INT, "view_shift") .compute_source("draw_command_generate_comp.glsl"); /** \} */ diff --git a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl index 86add2d1fe2..7e89120a79f 100644 --- a/source/blender/draw/intern/shaders/draw_visibility_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_visibility_comp.glsl @@ -9,10 +9,15 @@ shared uint shared_result; -void mask_visibility_bit() +void mask_visibility_bit(uint view_id) { - uint bit = 1u << gl_LocalInvocationID.x; - atomicAnd(visibility_buf[gl_WorkGroupID.x], ~bit); + if (view_len > 1) { + uint index = gl_GlobalInvocationID.x * uint(visibility_word_per_draw) + (view_id / 32u); + visibility_buf[index] &= ~(1u << view_id); + } + else { + atomicAnd(visibility_buf[gl_WorkGroupID.x], ~(1u << gl_LocalInvocationID.x)); + } } void main() @@ -31,16 +36,18 @@ void main() Sphere bounding_sphere = Sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w); Sphere inscribed_sphere = Sphere(bounds.bounding_sphere.xyz, bounds._inner_sphere_radius); - if (intersect_view(inscribed_sphere) == true) { - /* Visible. */ - } - else if (intersect_view(bounding_sphere) == false) { - /* Not visible. */ - mask_visibility_bit(); - } - else if (intersect_view(box) == false) { - /* Not visible. */ - mask_visibility_bit(); + for (drw_view_id = 0; drw_view_id < view_len; drw_view_id++) { + if (intersect_view(inscribed_sphere) == true) { + /* Visible. */ + } + else if (intersect_view(bounding_sphere) == false) { + /* Not visible. */ + mask_visibility_bit(drw_view_id); + } + else if (intersect_view(box) == false) { + /* Not visible. */ + mask_visibility_bit(drw_view_id); + } } } } diff --git a/source/blender/gpu/intern/gpu_shader_interface.hh b/source/blender/gpu/intern/gpu_shader_interface.hh index d223daa4a61..d2cba056190 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.hh +++ b/source/blender/gpu/intern/gpu_shader_interface.hh @@ -223,13 +223,13 @@ inline const char *ShaderInterface::builtin_uniform_block_name(GPUUniformBlockBu return "infoBlock"; case GPU_UNIFORM_BLOCK_DRW_VIEW: - return "drw_view"; + return "drw_view_"; case GPU_UNIFORM_BLOCK_DRW_MODEL: return "drw_matrices"; case GPU_UNIFORM_BLOCK_DRW_INFOS: return "drw_infos"; case GPU_UNIFORM_BLOCK_DRW_CLIPPING: - return "drw_clipping"; + return "drw_clipping_"; default: return nullptr; }