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.
This commit is contained in:
2022-11-14 00:42:31 +01:00
parent ab3fcd62cc
commit bfb6ea898b
11 changed files with 224 additions and 93 deletions

View File

@@ -567,7 +567,9 @@ void DrawCommandBuf::bind(RecordingState &state,
void DrawMultiBuf::bind(RecordingState &state,
Vector<Header, 0> &headers,
Vector<Undetermined, 0> &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"));

View File

@@ -558,7 +558,9 @@ class DrawMultiBuf {
void bind(RecordingState &state,
Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
VisibilityBuf &visibility_buf);
VisibilityBuf &visibility_buf,
int visibility_word_per_draw,
int view_len);
};
/** \} */

View File

@@ -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();

View File

@@ -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. */

View File

@@ -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<BoundBox *>(&culling_.corners);
BoundSphere &bound_sphere = *reinterpret_cast<BoundSphere *>(&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<BoundBox *>(&culling_[view_id].corners);
BoundSphere &bound_sphere = *reinterpret_cast<BoundSphere *>(&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<ViewMatrices>(data_);
data_freeze_[0] = static_cast<ViewMatrices>(data_[0]);
data_freeze_.push_update();
culling_freeze_ = static_cast<ViewCullingData>(culling_);
culling_freeze_[0] = static_cast<ViewCullingData>(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);

View File

@@ -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<ObjectBounds, 128>;
/** \note Using uint4 for declaration but bound as uint. */
using VisibilityBuf = StorageArrayBuffer<uint4, 1, true>;
using VisibilityBuf = StorageArrayBuffer<uint, 4, true>;
class View {
friend Manager;
private:
UniformBuffer<ViewMatrices> data_;
UniformBuffer<ViewCullingData> culling_;
/** TODO(fclem): Maybe try to reduce the minimum cost if the number of view is lower. */
UniformArrayBuffer<ViewMatrices, DRW_VIEW_MAX> data_;
UniformArrayBuffer<ViewCullingData, DRW_VIEW_MAX> culling_;
/** Frozen version of data_ used for debugging culling. */
UniformBuffer<ViewMatrices> data_freeze_;
UniformBuffer<ViewCullingData> culling_freeze_;
/** Result of the visibility computation. 1 bit per resource ID. */
UniformArrayBuffer<ViewMatrices, DRW_VIEW_MAX> data_freeze_;
UniformArrayBuffer<ViewCullingData, DRW_VIEW_MAX> 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

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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");
/** \} */

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}