WIP: Draw: Thin Handles #105034

Closed
Miguel Pozo wants to merge 5 commits from pragma37/blender:pull-thin-handles into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
17 changed files with 298 additions and 81 deletions

View File

@ -40,8 +40,7 @@ GPU_SHADER_CREATE_INFO(workbench_next_mesh)
.vertex_in(2, Type::VEC4, "ac")
.vertex_in(3, Type::VEC2, "au")
.vertex_source("workbench_prepass_vert.glsl")
.additional_info("draw_modelmat_new")
.additional_info("draw_resource_handle_new");
.additional_info("draw_modelmat_new", "draw_resource_handle_new", "with_thin_handles");
GPU_SHADER_CREATE_INFO(workbench_next_curves)
/* TODO Adding workbench_next_mesh to avoid shader compilation errors */

View File

@ -16,8 +16,13 @@ void main()
normal_interp = normalize(normal_object_to_view(nor));
#ifdef WORKBENCH_NEXT
object_id = int(uint(resource_id) & 0xFFFFu) + 1;
workbench_material_data_get(
int(resource_handle), ac.rgb, color_interp, alpha_interp, _roughness, metallic);
#else
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
workbench_material_data_get(
resource_handle, ac.rgb, color_interp, alpha_interp, _roughness, metallic);
object_id = int(uint(resource_handle) & 0xFFFFu) + 1;
#endif
}

View File

@ -202,10 +202,8 @@ class Instance {
if (batches[i] == nullptr) {
continue;
}
/* TODO(fclem): This create a cull-able instance for each sub-object. This is done
* for simplicity to reduce complexity. But this increase the overhead per object.
* Instead, we should use an indirection buffer to the material buffer. */
ResourceHandle _handle = i == 0 ? handle : manager.resource_handle(ob_ref);
ResourceThinHandle _handle = manager.resource_thin_handle(handle);
Material &mat = resources.material_buf.get_or_resize(_handle.resource_index());
@ -247,7 +245,8 @@ class Instance {
}
if (batch) {
Material &mat = resources.material_buf.get_or_resize(handle.resource_index());
ResourceThinHandle _handle = manager.resource_thin_handle(handle);
Material &mat = resources.material_buf.get_or_resize(_handle.resource_index());
if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) {
mat = Material(*ob_ref.object);
@ -270,7 +269,7 @@ class Instance {
draw_mesh(ob_ref,
mat,
batch,
handle,
_handle,
object_state.image_paint_override,
object_state.override_sampler_state);
}
@ -285,7 +284,7 @@ class Instance {
void draw_mesh(ObjectRef &ob_ref,
Material &material,
GPUBatch *batch,
ResourceHandle handle,
ResourceThinHandle handle,
::Image *image = nullptr,
eGPUSamplerState sampler_state = GPU_SAMPLER_DEFAULT,
ImageUser *iuser = nullptr)

View File

@ -8,7 +8,7 @@ namespace blender::workbench {
/** \name MeshPass
* \{ */
MeshPass::MeshPass(const char *name) : PassMain(name){};
MeshPass::MeshPass(const char *name) : PassMainThin(name){};
/* Move to draw::Pass */
bool MeshPass::is_empty() const
@ -19,7 +19,7 @@ bool MeshPass::is_empty() const
void MeshPass::init_pass(SceneResources &resources, DRWState state, int clip_planes)
{
is_empty_ = true;
PassMain::init();
PassMainThin::init();
state_set(state, clip_planes);
bind_texture(WB_MATCAP_SLOT, resources.matcap_tx);
bind_ssbo(WB_MATERIAL_SLOT, &resources.material_buf);
@ -47,7 +47,7 @@ void MeshPass::init_subpasses(ePipelineType pipeline,
std::string(get_name(shader_type));
}
GPUShader *sh = shaders.prepass_shader_get(pipeline, geom_type, shader_type, lighting, clip);
PassMain::Sub *pass = &sub(pass_names[geom][shader].c_str());
PassMainThin::Sub *pass = &sub(pass_names[geom][shader].c_str());
pass->shader_set(sh);
passes_[geom][shader] = pass;
}
@ -56,7 +56,7 @@ void MeshPass::init_subpasses(ePipelineType pipeline,
void MeshPass::draw(ObjectRef &ref,
GPUBatch *batch,
ResourceHandle handle,
ResourceThinHandle handle,
::Image *image /* = nullptr */,
eGPUSamplerState sampler_state /* = GPU_SAMPLER_DEFAULT */,
ImageUser *iuser /* = nullptr */)
@ -76,7 +76,7 @@ void MeshPass::draw(ObjectRef &ref,
}
if (texture) {
auto add_cb = [&] {
PassMain::Sub *sub_pass = passes_[int(geometry_type)][int(eShaderType::TEXTURE)];
PassMainThin::Sub *sub_pass = passes_[int(geometry_type)][int(eShaderType::TEXTURE)];
sub_pass = &sub_pass->sub(image->id.name);
if (tilemap) {
sub_pass->bind_texture(WB_TILE_ARRAY_SLOT, texture, sampler_state);

View File

@ -159,13 +159,13 @@ struct SceneResources {
void load_jitter_tx(int total_samples);
};
class MeshPass : public PassMain {
class MeshPass : public PassMainThin {
private:
using TextureSubPassKey = std::pair<GPUTexture *, eGeometryType>;
Map<TextureSubPassKey, PassMain::Sub *> texture_subpass_map_ = {};
Map<TextureSubPassKey, PassMainThin::Sub *> texture_subpass_map_ = {};
PassMain::Sub *passes_[geometry_type_len][shader_type_len] = {{nullptr}};
PassMainThin::Sub *passes_[geometry_type_len][shader_type_len] = {{nullptr}};
bool is_empty_ = false;
@ -183,7 +183,7 @@ class MeshPass : public PassMain {
void draw(ObjectRef &ref,
GPUBatch *batch,
ResourceHandle handle,
ResourceThinHandle handle,
::Image *image = nullptr,
eGPUSamplerState sampler_state = eGPUSamplerState::GPU_SAMPLER_DEFAULT,
ImageUser *iuser = nullptr);

View File

@ -104,8 +104,8 @@ void Draw::execute(RecordingState &state) const
void DrawMulti::execute(RecordingState &state) const
{
DrawMultiBuf::DrawCommandBuf &indirect_buf = multi_draw_buf->command_buf_;
DrawMultiBuf::DrawGroupBuf &groups = multi_draw_buf->group_buf_;
DrawMultiBufBase::DrawCommandBuf &indirect_buf = multi_draw_buf->command_buf_;
DrawMultiBufBase::DrawGroupBuf &groups = multi_draw_buf->group_buf_;
uint group_index = this->group_first;
while (group_index != uint(-1)) {
@ -397,7 +397,7 @@ std::string Draw::serialize() const
std::string DrawMulti::serialize(std::string line_prefix) const
{
DrawMultiBuf::DrawGroupBuf &groups = multi_draw_buf->group_buf_;
DrawMultiBufBase::DrawGroupBuf &groups = multi_draw_buf->group_buf_;
MutableSpan<DrawPrototype> prototypes(multi_draw_buf->prototype_buf_.data(),
multi_draw_buf->prototype_count_);
@ -599,15 +599,10 @@ void DrawCommandBuf::bind(RecordingState &state,
}
}
void DrawMultiBuf::bind(RecordingState &state,
Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
VisibilityBuf &visibility_buf,
int visibility_word_per_draw,
int view_len)
void DrawMultiBufBase::bind_base(RecordingState &state,
int view_len,
std::function<void()> generate_commands)
{
UNUSED_VARS(headers, commands);
GPU_debug_group_begin("DrawMultiBuf.bind");
resource_id_count_ = 0u;
@ -641,17 +636,8 @@ void DrawMultiBuf::bind(RecordingState &state,
command_buf_.get_or_resize(group_count_ * 2);
if (prototype_count_ > 0) {
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_binding(shader, "group_buf"));
GPU_storagebuf_bind(visibility_buf, GPU_shader_get_ssbo_binding(shader, "visibility_buf"));
GPU_storagebuf_bind(prototype_buf_, GPU_shader_get_ssbo_binding(shader, "prototype_buf"));
GPU_storagebuf_bind(command_buf_, GPU_shader_get_ssbo_binding(shader, "command_buf"));
GPU_storagebuf_bind(resource_id_buf_, DRW_RESOURCE_ID_SLOT);
GPU_compute_dispatch(shader, divide_ceil_u(prototype_count_, DRW_COMMAND_GROUP_SIZE), 1, 1);
generate_commands();
if (GPU_shader_draw_parameters_support() == false) {
GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY);
state.resource_id_buf = resource_id_buf_;
@ -664,6 +650,52 @@ void DrawMultiBuf::bind(RecordingState &state,
GPU_debug_group_end();
}
void DrawMultiBuf::bind(RecordingState &state,
Vector<Header, 0> & /*headers*/,
Vector<Undetermined, 0> & /*commands*/,
VisibilityBuf &visibility_buf,
int visibility_word_per_draw,
int view_len)
{
bind_base(state, view_len, [&]() {
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_binding(shader, "group_buf"));
GPU_storagebuf_bind(visibility_buf, GPU_shader_get_ssbo_binding(shader, "visibility_buf"));
GPU_storagebuf_bind(prototype_buf_, GPU_shader_get_ssbo_binding(shader, "prototype_buf"));
GPU_storagebuf_bind(command_buf_, GPU_shader_get_ssbo_binding(shader, "command_buf"));
GPU_storagebuf_bind(resource_id_buf_, DRW_RESOURCE_ID_SLOT);
GPU_compute_dispatch(shader, divide_ceil_u(prototype_count_, DRW_COMMAND_GROUP_SIZE), 1, 1);
});
}
void DrawMultiThinBuf::bind(RecordingState &state,
Vector<Header, 0> & /*headers*/,
Vector<Undetermined, 0> & /*commands*/,
VisibilityBuf &visibility_buf,
int visibility_word_per_draw,
int view_len,
ThinMapBuf &thin_map_buf)
{
bind_base(state, view_len, [&]() {
GPUShader *shader = DRW_shader_draw_command_with_thin_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_binding(shader, "group_buf"));
GPU_storagebuf_bind(visibility_buf, GPU_shader_get_ssbo_binding(shader, "visibility_buf"));
GPU_storagebuf_bind(prototype_buf_, GPU_shader_get_ssbo_binding(shader, "prototype_buf"));
GPU_storagebuf_bind(command_buf_, GPU_shader_get_ssbo_binding(shader, "command_buf"));
GPU_storagebuf_bind(resource_id_buf_, DRW_RESOURCE_ID_SLOT);
GPU_storagebuf_bind(thin_map_buf, DRW_RESOURCE_THIN_MAP_SLOT);
GPU_compute_dispatch(shader, divide_ceil_u(prototype_count_, DRW_COMMAND_GROUP_SIZE), 1, 1);
});
}
/** \} */
}; // namespace blender::draw::command

View File

@ -30,7 +30,9 @@ template<typename DrawCommandBufType> class PassBase;
namespace blender::draw::command {
class DrawCommandBuf;
class DrawMultiBuf;
class DrawMultiBufBase;
using ThinMapBuf = StorageArrayBuffer<uint, 128>;
/* -------------------------------------------------------------------- */
/** \name Recording State
@ -297,7 +299,7 @@ struct Draw {
struct DrawMulti {
GPUBatch *batch;
DrawMultiBuf *multi_draw_buf;
DrawMultiBufBase *multi_draw_buf;
uint group_first;
uint uuid;
@ -486,11 +488,11 @@ class DrawCommandBuf {
*
* \{ */
class DrawMultiBuf {
class DrawMultiBufBase {
friend Manager;
friend DrawMulti;
private:
protected:
using DrawGroupBuf = StorageArrayBuffer<DrawGroup, 16>;
using DrawPrototypeBuf = StorageArrayBuffer<DrawPrototype, 16>;
using DrawCommandBuf = StorageArrayBuffer<DrawCommand, 16, true>;
@ -518,22 +520,14 @@ class DrawMultiBuf {
/** Used items in the resource_id_buf_. Not it's allocated length. */
uint resource_id_count_ = 0;
public:
void clear()
{
header_id_counter_ = 0;
group_count_ = 0;
prototype_count_ = 0;
group_ids_.clear();
}
void append_draw(Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
GPUBatch *batch,
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceHandle handle)
void append_draw_base(Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
GPUBatch *batch,
uint instance_len,
uint vertex_len,
uint vertex_first,
uint handle_index,
bool inverted_handedness)
{
/* Custom draw-calls cannot be batched and will produce one group per draw. */
const bool custom_group = ((vertex_first != 0 && vertex_first != -1) || vertex_len != -1);
@ -551,10 +545,8 @@ class DrawMultiBuf {
uint &group_id = group_ids_.lookup_or_add(DrawGroupKey(cmd.uuid, batch), uint(-1));
bool inverted = handle.has_inverted_handedness();
DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++);
draw.resource_handle = handle.raw;
draw.resource_handle = handle_index;
draw.instance_len = instance_len;
draw.group_id = group_id;
@ -565,7 +557,7 @@ class DrawMultiBuf {
DrawGroup &group = group_buf_.get_or_resize(new_group_id);
group.next = cmd.group_first;
group.len = instance_len;
group.front_facing_len = inverted ? 0 : instance_len;
group.front_facing_len = inverted_handedness ? 0 : instance_len;
group.gpu_batch = batch;
group.front_proto_len = 0;
group.back_proto_len = 0;
@ -576,19 +568,51 @@ class DrawMultiBuf {
group_id = new_group_id;
}
/* For serialization only. */
(inverted ? group.back_proto_len : group.front_proto_len)++;
(inverted_handedness ? group.back_proto_len : group.front_proto_len)++;
/* Append to list. */
cmd.group_first = new_group_id;
}
else {
DrawGroup &group = group_buf_[group_id];
group.len += instance_len;
group.front_facing_len += inverted ? 0 : instance_len;
group.front_facing_len += inverted_handedness ? 0 : instance_len;
/* For serialization only. */
(inverted ? group.back_proto_len : group.front_proto_len)++;
(inverted_handedness ? group.back_proto_len : group.front_proto_len)++;
}
}
void bind_base(RecordingState &state, int view_len, std::function<void()> generate_commands);
public:
void clear()
{
header_id_counter_ = 0;
group_count_ = 0;
prototype_count_ = 0;
group_ids_.clear();
}
};
class DrawMultiBuf : public DrawMultiBufBase {
public:
void append_draw(Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
GPUBatch *batch,
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceHandle handle)
{
append_draw_base(headers,
commands,
batch,
instance_len,
vertex_len,
vertex_first,
handle.raw,
handle.has_inverted_handedness());
}
void bind(RecordingState &state,
Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
@ -597,6 +621,35 @@ class DrawMultiBuf {
int view_len);
};
class DrawMultiThinBuf : public DrawMultiBufBase {
public:
void append_draw(Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
GPUBatch *batch,
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceThinHandle handle)
{
append_draw_base(headers,
commands,
batch,
instance_len,
vertex_len,
vertex_first,
handle.raw,
handle.object_handle.has_inverted_handedness());
}
void bind(RecordingState &state,
Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
VisibilityBuf &visibility_buf,
int visibility_word_per_draw,
int view_len,
ThinMapBuf &thin_map_buf);
};
/** \} */
}; // namespace blender::draw::command

View File

@ -17,6 +17,7 @@
#define DRW_LAYER_ATTR_UBO_SLOT 3
#define DRW_RESOURCE_THIN_MAP_SLOT 12
#define DRW_RESOURCE_ID_SLOT 11
#define DRW_OBJ_MAT_SLOT 10
#define DRW_OBJ_INFOS_SLOT 9

View File

@ -47,6 +47,14 @@ struct ResourceHandle {
}
};
struct ResourceThinHandle : public ResourceHandle {
ResourceHandle object_handle;
ResourceThinHandle(const ResourceHandle object_handle, uint thin_index)
: ResourceHandle(thin_index, object_handle.has_inverted_handedness()),
object_handle(object_handle){};
};
/* TODO(fclem): Move to somewhere more appropriated after cleaning up the header dependencies. */
struct ObjectRef {
Object *object;

View File

@ -30,6 +30,7 @@ void Manager::begin_sync()
matrix_buf.swap();
bounds_buf.swap();
infos_buf.swap();
thin_map_buf.swap();
/* TODO: This means the reference is kept until further redraw or manager tear-down. Instead,
* they should be released after each draw loop. But for now, mimics old DRW behavior. */
@ -52,8 +53,12 @@ void Manager::begin_sync()
memset(infos_buf.current().data(),
0xF0,
matrix_buf.current().size() * sizeof(*infos_buf.current().data()));
memset(thin_map_buf.current().data(),
0xF0,
thin_map_buf.current().size() * sizeof(*thin_map_buf.current().data()));
#endif
resource_len_ = 0;
resource_thin_len_ = 0;
attribute_len_ = 0;
/* TODO(fclem): Resize buffers if too big, but with an hysteresis threshold. */
@ -101,6 +106,7 @@ void Manager::end_sync()
matrix_buf.current().push_update();
bounds_buf.current().push_update();
infos_buf.current().push_update();
thin_map_buf.current().push_update();
attributes_buf.push_update();
layer_attributes_buf.push_update();
attributes_buf_legacy.push_update();
@ -195,6 +201,35 @@ void Manager::submit(PassMain &pass, View &view)
state.cleanup();
}
void Manager::submit(PassMainThin &pass, View &view)
{
view.bind();
debug_bind();
bool freeze_culling = (U.experimental.use_viewport_debug && DST.draw_ctx.v3d &&
(DST.draw_ctx.v3d->debug_flag & V3D_DEBUG_FREEZE_CULLING) != 0);
view.compute_visibility(bounds_buf.current(), resource_len_, freeze_culling);
command::RecordingState state;
state.inverted_view = view.is_inverted();
pass.draw_commands_buf_.bind(state,
pass.headers_,
pass.commands_,
view.get_visibility_buffer(),
view.visibility_word_per_draw(),
view.view_len_,
thin_map_buf.current());
resource_bind();
pass.submit(state);
state.cleanup();
}
void Manager::submit(PassSortable &pass, View &view)
{
pass.sort();
@ -253,6 +288,7 @@ Manager::DataDebugOutput Manager::data_debug()
matrix_buf.current().read();
bounds_buf.current().read();
infos_buf.current().read();
/* TODO (Miguel Pozo): thin_map_buf.current().read(); */
Manager::DataDebugOutput output;
output.matrices = {matrix_buf.current().data(), resource_len_};

View File

@ -33,16 +33,19 @@ template<typename T> class Pass;
namespace command {
class DrawCommandBuf;
class DrawMultiBuf;
class DrawMultiThinBuf;
} // namespace command
using PassSimple = detail::Pass<command::DrawCommandBuf>;
using PassMain = detail::Pass<command::DrawMultiBuf>;
using PassMainThin = detail::Pass<command::DrawMultiThinBuf>;
class PassSortable;
class Manager {
using ObjectMatricesBuf = StorageArrayBuffer<ObjectMatrices, 128>;
using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>;
using ThinMapBuf = StorageArrayBuffer<uint, 128>;
using ObjectAttributeBuf = StorageArrayBuffer<ObjectAttribute, 128>;
using LayerAttributeBuf = UniformArrayBuffer<LayerAttribute, 512>;
/**
@ -76,6 +79,8 @@ class Manager {
SwapChain<ObjectBoundsBuf, 2> bounds_buf;
SwapChain<ObjectInfosBuf, 2> infos_buf;
SwapChain<ThinMapBuf, 2> thin_map_buf;
/**
* Object Attributes are reference by indirection data inside ObjectInfos.
* This is because attribute list is arbitrary.
@ -106,6 +111,8 @@ class Manager {
private:
/** Number of resource handle recorded. */
uint resource_len_ = 0;
/** Number of resource thin handle recorded. */
uint resource_thin_len_ = 0;
/** Number of object attribute recorded. */
uint attribute_len_ = 0;
@ -134,6 +141,8 @@ class Manager {
const float3 &bounds_center,
const float3 &bounds_half_extent);
ResourceThinHandle resource_thin_handle(const ResourceHandle object_handle);
/**
* Populate additional per resource data on demand.
*/
@ -152,6 +161,7 @@ class Manager {
*/
void submit(PassSimple &pass, View &view);
void submit(PassMain &pass, View &view);
void submit(PassMainThin &pass, View &view);
void submit(PassSortable &pass, View &view);
/**
* Variant without any view. Must not contain any shader using `draw_view` create info.
@ -217,6 +227,12 @@ inline ResourceHandle Manager::resource_handle(const float4x4 &model_matrix,
return ResourceHandle(resource_len_++, false);
}
inline ResourceThinHandle Manager::resource_thin_handle(const ResourceHandle object_handle)
{
thin_map_buf.current().get_or_resize(resource_thin_len_) = object_handle.raw;
return ResourceThinHandle(object_handle, resource_thin_len_++);
}
inline void Manager::extract_object_attributes(ResourceHandle handle,
const ObjectRef &ref,
Span<GPUMaterial *> materials)

View File

@ -253,6 +253,16 @@ class PassBase {
StorageBuffer<DrawCommand, true> &indirect_buffer,
ResourceHandle handle = {0});
/**
* Thin variants.
*/
void draw(GPUBatch *batch,
uint instance_len = -1,
uint vertex_len = -1,
uint vertex_first = -1,
ResourceThinHandle handle = {0});
void draw(GPUBatch *batch, ResourceThinHandle handle);
/**
* Record a compute dispatch call.
*/
@ -706,6 +716,32 @@ inline void PassBase<T>::draw_procedural_indirect(
/** \} */
/* -------------------------------------------------------------------- */
/** \name Thin Handle draw calls
* \{ */
template<class T>
inline void PassBase<T>::draw(GPUBatch *batch,
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceThinHandle handle)
{
if (instance_len == 0 || vertex_len == 0) {
return;
}
BLI_assert(shader_);
draw_commands_buf_.append_draw(
headers_, commands_, batch, instance_len, vertex_len, vertex_first, handle);
}
template<class T> inline void PassBase<T>::draw(GPUBatch *batch, ResourceThinHandle handle)
{
this->draw(batch, -1, -1, -1, handle);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Compute Dispatch Implementation
* \{ */

View File

@ -27,6 +27,7 @@ static struct {
struct GPUShader *draw_view_finalize_sh;
struct GPUShader *draw_resource_finalize_sh;
struct GPUShader *draw_command_generate_sh;
struct GPUShader *draw_command_with_thin_generate_sh;
} e_data = {{nullptr}};
/* -------------------------------------------------------------------- */
@ -146,6 +147,15 @@ GPUShader *DRW_shader_draw_command_generate_get()
return e_data.draw_command_generate_sh;
}
GPUShader *DRW_shader_draw_command_with_thin_generate_get()
{
if (e_data.draw_command_with_thin_generate_sh == nullptr) {
e_data.draw_command_with_thin_generate_sh = GPU_shader_create_from_info_name(
"draw_command_with_thin_generate");
}
return e_data.draw_command_with_thin_generate_sh;
}
/** \} */
void DRW_shaders_free()
@ -159,4 +169,5 @@ void DRW_shaders_free()
DRW_SHADER_FREE_SAFE(e_data.draw_view_finalize_sh);
DRW_SHADER_FREE_SAFE(e_data.draw_resource_finalize_sh);
DRW_SHADER_FREE_SAFE(e_data.draw_command_generate_sh);
DRW_SHADER_FREE_SAFE(e_data.draw_command_with_thin_generate_sh);
}

View File

@ -32,6 +32,7 @@ GPUShader *DRW_shader_draw_visibility_compute_get();
GPUShader *DRW_shader_draw_view_finalize_get();
GPUShader *DRW_shader_draw_resource_finalize_get();
GPUShader *DRW_shader_draw_command_generate_get();
GPUShader *DRW_shader_draw_command_with_thin_generate_get();
#endif

View File

@ -88,9 +88,9 @@ uniform int drw_resourceChunk;
/* This is in the case we want to do a special instance drawcall for one object but still want to
* have the right resourceId and all the correct ubo datas. */
uniform int drw_ResourceID;
# define resource_id drw_ResourceID
# define _resource_id_ drw_ResourceID
# else
# define resource_id (gpu_BaseInstance + instanceId)
# define _resource_id_ (gpu_BaseInstance + instanceId)
# endif
/* Use this to declare and pass the value if
@ -114,23 +114,23 @@ uniform int drw_ResourceID;
#ifdef USE_GPU_SHADER_CREATE_INFO
/* TODO(fclem): Rename PASS_RESOURCE_ID to DRW_RESOURCE_ID_VARYING_SET */
# if defined(UNIFORM_RESOURCE_ID)
# define resource_id drw_ResourceID
# define _resource_id_ drw_ResourceID
# define PASS_RESOURCE_ID
# elif defined(GPU_VERTEX_SHADER)
# if defined(UNIFORM_RESOURCE_ID_NEW)
# define resource_id (drw_ResourceID >> DRW_VIEW_SHIFT)
# define _resource_id_ (drw_ResourceID >> DRW_VIEW_SHIFT)
# else
# define resource_id gpu_InstanceIndex
# define _resource_id_ gpu_InstanceIndex
# endif
# define PASS_RESOURCE_ID drw_ResourceID_iface.resource_index = resource_id;
# elif defined(GPU_GEOMETRY_SHADER)
# define resource_id drw_ResourceID_iface_in[0].resource_index
# define _resource_id_ drw_ResourceID_iface_in[0].resource_index
# define PASS_RESOURCE_ID drw_ResourceID_iface_out.resource_index = resource_id;
# elif defined(GPU_FRAGMENT_SHADER)
# define resource_id drw_ResourceID_iface.resource_index
# define _resource_id_ drw_ResourceID_iface.resource_index
# endif
/* TODO(fclem): Remove. */
@ -149,7 +149,7 @@ uniform int drw_ResourceID;
# define RESOURCE_ID_VARYING
# endif
# define resource_id resourceIDGeom
# define _resource_id_ resourceIDGeom
# define PASS_RESOURCE_ID resourceIDFrag = resource_id[0];
# endif
@ -157,10 +157,17 @@ uniform int drw_ResourceID;
# if !defined(EEVEE_GENERATED_INTERFACE)
flat in int resourceIDFrag;
# endif
# define resource_id resourceIDFrag
# define _resource_id_ resourceIDFrag
# endif
#endif
#ifdef WITH_THIN_HANDLES
# define resource_thin_id _resource_id_
# define resource_id thin_map_buf[_resource_id_]
#else
# define resource_id _resource_id_
#endif
/* Breaking this across multiple lines causes issues for some older GLSL compilers. */
/* clang-format off */
#if !defined(GPU_INTEL) && !defined(GPU_DEPRECATED_AMD_DRIVER) && (!defined(OS_MAC) || defined(GPU_METAL)) && !defined(INSTANCED_ATTR) && !defined(DRW_LEGACY_MODEL_MATRIX)

View File

@ -54,11 +54,15 @@ void main()
uint group_id = proto.group_id;
bool is_inverted = (proto.resource_handle & 0x80000000u) != 0;
uint resource_index = (proto.resource_handle & 0x7FFFFFFFu);
uint visibility_index = resource_index;
#ifdef WITH_THIN_HANDLES
visibility_index = thin_map_buf[resource_index] & 0x7FFFFFFFu;
#endif
/* Visibility test result. */
uint visible_instance_len = 0;
if (visibility_word_per_draw > 0) {
uint visibility_word = resource_index * visibility_word_per_draw;
uint visibility_word = visibility_index * visibility_word_per_draw;
for (uint i = 0; i < visibility_word_per_draw; i++, visibility_word++) {
/* NOTE: This assumes `proto.instance_len` is 1. */
/* TODO: Assert. */
@ -66,7 +70,7 @@ void main()
}
}
else {
if ((visibility_buf[resource_index / 32u] & (1u << (resource_index % 32u))) != 0) {
if ((visibility_buf[visibility_index / 32u] & (1u << (visibility_index % 32u))) != 0) {
visible_instance_len = proto.instance_len;
}
}
@ -102,12 +106,13 @@ void main()
/* 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;
uint visibility_word = visibility_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) {
/* TODO (Miguel Pozo): ??? */
resource_id_buf[dst_index++] = view_index | (resource_index << view_shift);
}
view_index++;

View File

@ -191,6 +191,14 @@ GPU_SHADER_CREATE_INFO(draw_command_generate)
.push_constant(Type::INT, "view_shift")
.compute_source("draw_command_generate_comp.glsl");
GPU_SHADER_CREATE_INFO(with_thin_handles)
.define("WITH_THIN_HANDLES")
.storage_buf(DRW_RESOURCE_THIN_MAP_SLOT, Qualifier::READ, "uint", "thin_map_buf[]");
GPU_SHADER_CREATE_INFO(draw_command_with_thin_generate)
.do_static_compilation(true)
.additional_info("draw_command_generate", "with_thin_handles");
/** \} */
/* -------------------------------------------------------------------- */