Draw: Custom IDs #105261

Merged
Clément Foucault merged 12 commits from pragma37/blender:pull-thin-handles into main 2023-03-01 21:42:37 +01:00
14 changed files with 107 additions and 42 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_with_custom_id", "draw_resource_handle_new");
GPU_SHADER_CREATE_INFO(workbench_next_curves)
/* TODO Adding workbench_next_mesh to avoid shader compilation errors */

View File

@ -16,8 +16,12 @@ void main()
normal_interp = normalize(normal_object_to_view(nor));
object_id = int(uint(resource_id) & 0xFFFFu) + 1;
#ifdef WORKBENCH_NEXT
workbench_material_data_get(
int(drw_CustomID), ac.rgb, color_interp, alpha_interp, _roughness, metallic);
#else
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

@ -68,6 +68,7 @@ class Instance {
resolution,
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW);
resources.material_buf.clear();
opaque_ps.sync(scene_state, resources);
transparent_ps.sync(scene_state, resources);
@ -202,12 +203,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);
Material &mat = resources.material_buf.get_or_resize(_handle.resource_index());
Material mat;
if (::Material *_mat = BKE_object_material_get_eval(ob_ref.object, i + 1)) {
mat = Material(*_mat);
@ -225,7 +222,7 @@ class Instance {
get_material_image(ob_ref.object, i + 1, image, iuser, sampler_state);
}
draw_mesh(ob_ref, mat, batches[i], _handle, image, sampler_state, iuser);
draw_mesh(ob_ref, mat, batches[i], handle, image, sampler_state, iuser);
}
}
}
@ -247,7 +244,7 @@ class Instance {
}
if (batch) {
Material &mat = resources.material_buf.get_or_resize(handle.resource_index());
Material mat;
if (object_state.color_type == V3D_SHADING_OBJECT_COLOR) {
mat = Material(*ob_ref.object);
@ -291,9 +288,11 @@ class Instance {
ImageUser *iuser = nullptr)
{
const bool in_front = (ob_ref.object->dtx & OB_DRAW_IN_FRONT) != 0;
resources.material_buf.append(material);
int material_index = resources.material_buf.size() - 1;
auto draw = [&](MeshPass &pass) {
pass.draw(ob_ref, batch, handle, image, sampler_state, iuser);
pass.draw(ob_ref, batch, handle, material_index, image, sampler_state, iuser);
};
if (scene_state.xray_mode || material.is_transparent()) {

View File

@ -18,6 +18,7 @@ bool MeshPass::is_empty() const
void MeshPass::init_pass(SceneResources &resources, DRWState state, int clip_planes)
{
use_custom_ids = true;
is_empty_ = true;
PassMain::init();
state_set(state, clip_planes);
@ -57,6 +58,7 @@ void MeshPass::init_subpasses(ePipelineType pipeline,
void MeshPass::draw(ObjectRef &ref,
GPUBatch *batch,
ResourceHandle handle,
uint material_index,
::Image *image /* = nullptr */,
eGPUSamplerState sampler_state /* = GPU_SAMPLER_DEFAULT */,
ImageUser *iuser /* = nullptr */)
@ -95,11 +97,11 @@ void MeshPass::draw(ObjectRef &ref,
};
texture_subpass_map_.lookup_or_add_cb(TextureSubPassKey(texture, geometry_type), add_cb)
->draw(batch, handle);
->draw(batch, handle, material_index);
return;
}
}
passes_[int(geometry_type)][int(eShaderType::MATERIAL)]->draw(batch, handle);
passes_[int(geometry_type)][int(eShaderType::MATERIAL)]->draw(batch, handle, material_index);
}
/** \} */

View File

@ -184,6 +184,7 @@ class MeshPass : public PassMain {
void draw(ObjectRef &ref,
GPUBatch *batch,
ResourceHandle handle,
uint material_index,
::Image *image = nullptr,
eGPUSamplerState sampler_state = eGPUSamplerState::GPU_SAMPLER_DEFAULT,
ImageUser *iuser = nullptr);

View File

@ -600,14 +600,13 @@ void DrawCommandBuf::bind(RecordingState &state,
}
void DrawMultiBuf::bind(RecordingState &state,
Vector<Header, 0> &headers,
Vector<Undetermined, 0> &commands,
Vector<Header, 0> & /*headers*/,
Vector<Undetermined, 0> & /*commands*/,
VisibilityBuf &visibility_buf,
int visibility_word_per_draw,
int view_len)
int view_len,
bool use_custom_ids)
{
UNUSED_VARS(headers, commands);
GPU_debug_group_begin("DrawMultiBuf.bind");
resource_id_count_ = 0u;
@ -636,7 +635,7 @@ void DrawMultiBuf::bind(RecordingState &state,
group_buf_.push_update();
prototype_buf_.push_update();
/* Allocate enough for the expansion pass. */
resource_id_buf_.get_or_resize(resource_id_count_);
resource_id_buf_.get_or_resize(resource_id_count_ * (use_custom_ids ? 2 : 1));
/* Two command per group. */
command_buf_.get_or_resize(group_count_ * 2);
@ -646,6 +645,7 @@ void DrawMultiBuf::bind(RecordingState &state,
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_shader_uniform_1b(shader, "use_custom_ids", use_custom_ids);
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"));

View File

@ -433,7 +433,8 @@ class DrawCommandBuf {
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceHandle handle)
ResourceHandle handle,
uint /*custom_id*/)
{
vertex_first = vertex_first != -1 ? vertex_first : 0;
instance_len = instance_len != -1 ? instance_len : 1;
@ -533,7 +534,8 @@ class DrawMultiBuf {
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceHandle handle)
ResourceHandle handle,
uint custom_id)
{
/* 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);
@ -555,6 +557,7 @@ class DrawMultiBuf {
DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++);
draw.resource_handle = handle.raw;
draw.custom_id = custom_id;
draw.instance_len = instance_len;
draw.group_id = group_id;
@ -594,7 +597,8 @@ class DrawMultiBuf {
Vector<Undetermined, 0> &commands,
VisibilityBuf &visibility_buf,
int visibility_word_per_draw,
int view_len);
int view_len,
bool use_custom_ids);
};
/** \} */

View File

@ -72,9 +72,10 @@ struct DrawPrototype {
uint group_id;
/* Resource handle associated with this call. Also reference visibility. */
uint resource_handle;
/* Custom extra value to be used by the engines. */
uint custom_id;
/* Number of instances. */
uint instance_len;
uint _pad0;
};
BLI_STATIC_ASSERT_ALIGN(DrawPrototype, 16)

View File

@ -186,7 +186,8 @@ void Manager::submit(PassMain &pass, View &view)
pass.commands_,
view.get_visibility_buffer(),
view.visibility_word_per_draw(),
view.view_len_);
view.view_len_,
pass.use_custom_ids);
resource_bind();

View File

@ -135,6 +135,8 @@ class PassBase {
public:
const char *debug_name;
bool use_custom_ids;
PassBase(const char *name,
DrawCommandBufType &draw_command_buf,
SubPassVector<PassBase<DrawCommandBufType>> &sub_passes,
@ -142,7 +144,8 @@ class PassBase {
: draw_commands_buf_(draw_command_buf),
sub_passes_(sub_passes),
shader_(shader),
debug_name(name){};
debug_name(name),
use_custom_ids(false){};
/**
* Reset the pass command pool.
@ -224,13 +227,14 @@ class PassBase {
uint instance_len = -1,
uint vertex_len = -1,
uint vertex_first = -1,
ResourceHandle handle = {0});
ResourceHandle handle = {0},
uint custom_id = 0);
/**
* Shorter version for the common case.
* \note Implemented in derived class. Not a virtual function to avoid indirection.
*/
void draw(GPUBatch *batch, ResourceHandle handle);
void draw(GPUBatch *batch, ResourceHandle handle, uint custom_id = 0);
/**
* Record a procedural draw call. Geometry is **NOT** source from a GPUBatch.
@ -240,7 +244,8 @@ class PassBase {
uint instance_len,
uint vertex_len,
uint vertex_first = -1,
ResourceHandle handle = {0});
ResourceHandle handle = {0},
uint custom_id = 0);
/**
* Indirect variants.
@ -654,20 +659,25 @@ template<class T> std::string PassBase<T>::serialize(std::string line_prefix) co
* \{ */
template<class T>
inline void PassBase<T>::draw(
GPUBatch *batch, uint instance_len, uint vertex_len, uint vertex_first, ResourceHandle handle)
inline void PassBase<T>::draw(GPUBatch *batch,
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceHandle handle,
uint custom_id)
{
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);
headers_, commands_, batch, instance_len, vertex_len, vertex_first, handle, custom_id);
}
template<class T> inline void PassBase<T>::draw(GPUBatch *batch, ResourceHandle handle)
template<class T>
inline void PassBase<T>::draw(GPUBatch *batch, ResourceHandle handle, uint custom_id)
{
this->draw(batch, -1, -1, -1, handle);
this->draw(batch, -1, -1, -1, handle, custom_id);
}
template<class T>
@ -675,9 +685,11 @@ inline void PassBase<T>::draw_procedural(GPUPrimType primitive,
uint instance_len,
uint vertex_len,
uint vertex_first,
ResourceHandle handle)
ResourceHandle handle,
uint custom_id)
{
this->draw(procedural_batch_get(primitive), instance_len, vertex_len, vertex_first, handle);
this->draw(
procedural_batch_get(primitive), instance_len, vertex_len, vertex_first, handle, custom_id);
}
/** \} */

View File

@ -108,7 +108,14 @@ void main()
uint view_index = i * 32u;
while (word != 0u) {
if ((word & 1u) != 0u) {
resource_id_buf[dst_index++] = view_index | (resource_index << view_shift);
if (use_custom_ids) {
resource_id_buf[dst_index * 2] = view_index | (resource_index << view_shift);
resource_id_buf[dst_index * 2 + 1] = proto.custom_id;
}
else {
resource_id_buf[dst_index] = view_index | (resource_index << view_shift);
}
dst_index++;
}
view_index++;
word >>= 1u;
@ -117,7 +124,13 @@ void main()
}
else {
for (uint i = dst_index; i < dst_index + visible_instance_len; i++) {
resource_id_buf[i] = resource_index;
if (use_custom_ids) {
resource_id_buf[i * 2] = resource_index;
resource_id_buf[i * 2 + 1] = proto.custom_id;
}
else {
resource_id_buf[i] = resource_index;
}
}
}
}

View File

@ -189,6 +189,7 @@ GPU_SHADER_CREATE_INFO(draw_command_generate)
.push_constant(Type::INT, "prototype_len")
.push_constant(Type::INT, "visibility_word_per_draw")
.push_constant(Type::INT, "view_shift")
.push_constant(Type::BOOL, "use_custom_ids")
.compute_source("draw_command_generate_comp.glsl");
/** \} */
@ -200,9 +201,18 @@ GPU_SHADER_CREATE_INFO(draw_command_generate)
GPU_SHADER_CREATE_INFO(draw_resource_id_new)
.define("UNIFORM_RESOURCE_ID_NEW")
/* TODO (Miguel Pozo): This is an int for compatibility.
* It should become uint once the "Next" ports are complete. */
.storage_buf(DRW_RESOURCE_ID_SLOT, Qualifier::READ, "int", "resource_id_buf[]")
.define("drw_ResourceID", "resource_id_buf[gpu_BaseInstance + gl_InstanceID]");
GPU_SHADER_CREATE_INFO(draw_resource_with_custom_id_new)
.define("UNIFORM_RESOURCE_ID_NEW")
.define("WITH_CUSTOM_IDS")
.storage_buf(DRW_RESOURCE_ID_SLOT, Qualifier::READ, "int2", "resource_id_buf[]")
.define("drw_ResourceID", "resource_id_buf[gpu_BaseInstance + gl_InstanceID].x")
.define("drw_CustomID", "resource_id_buf[gpu_BaseInstance + gl_InstanceID].y");
pragma37 marked this conversation as resolved

It isn't uint2 because of compatibility with older code. This should become a TODO.

It isn't `uint2` because of compatibility with older code. This should become a TODO.
/**
* Workaround the lack of gl_BaseInstance by binding the resource_id_buf as vertex buf.
*/
@ -210,6 +220,13 @@ GPU_SHADER_CREATE_INFO(draw_resource_id_fallback)
.define("UNIFORM_RESOURCE_ID_NEW")
.vertex_in(15, Type::INT, "drw_ResourceID");
pragma37 marked this conversation as resolved

Rename draw_resource_and_custom_id to draw_resource_with_custom_id.

Rename `draw_resource_and_custom_id` to `draw_resource_with_custom_id`.
GPU_SHADER_CREATE_INFO(draw_resource_with_custom_id_fallback)
.define("UNIFORM_RESOURCE_ID_NEW")
.define("WITH_CUSTOM_IDS")
.vertex_in(15, Type::IVEC2, "vertex_in_drw_ResourceID")
.define("drw_ResourceID", "vertex_in_drw_ResourceID.x")
.define("drw_CustomID", "vertex_in_drw_ResourceID.y");
/** TODO mask view id bits. */
GPU_SHADER_CREATE_INFO(draw_resource_handle_new).define("resource_handle", "drw_ResourceID");
@ -219,14 +236,19 @@ GPU_SHADER_CREATE_INFO(draw_resource_handle_new).define("resource_handle", "drw_
/** \name Draw Object Resources
* \{ */
pragma37 marked this conversation as resolved

Remove the _ suffix here.

Remove the `_` suffix here.
GPU_SHADER_CREATE_INFO(draw_modelmat_new)
GPU_SHADER_CREATE_INFO(draw_modelmat_new_common)
.typedef_source("draw_shader_shared.h")
.storage_buf(DRW_OBJ_MAT_SLOT, Qualifier::READ, "ObjectMatrices", "drw_matrix_buf[]")
.define("drw_ModelMatrixInverse", "drw_matrix_buf[resource_id].model_inverse")
.define("drw_ModelMatrix", "drw_matrix_buf[resource_id].model")
/* TODO For compatibility with old shaders. To be removed. */
.define("ModelMatrixInverse", "drw_ModelMatrixInverse")
.define("ModelMatrix", "drw_ModelMatrix")
.additional_info("draw_resource_id_new");
.define("ModelMatrix", "drw_ModelMatrix");
GPU_SHADER_CREATE_INFO(draw_modelmat_new)
.additional_info("draw_modelmat_new_common", "draw_resource_id_new");
GPU_SHADER_CREATE_INFO(draw_modelmat_new_with_custom_id)
.additional_info("draw_modelmat_new_common", "draw_resource_with_custom_id_new");
/** \} */

View File

@ -317,6 +317,7 @@ void gpu_shader_create_info_init()
/* WORKAROUND: Replace the use of gpu_BaseInstance by an instance attribute. */
if (GPU_shader_draw_parameters_support() == false) {
draw_resource_id_new = draw_resource_id_fallback;
draw_resource_with_custom_id_new = draw_resource_with_custom_id_fallback;
}
#ifdef WITH_METAL_BACKEND

View File

@ -121,12 +121,18 @@ void GLVertArray::update_bindings(const GLuint vao,
if (batch->resource_id_buf) {
const ShaderInput *input = interface->attr_get("drw_ResourceID");
int component_len = 1;
pragma37 marked this conversation as resolved

Use comp_len or component_len.
size is generally reserved for size in bytes use _len suffix for the rest.
Try to avoid calling variable just len or size. They are always size of length of something.

Use `comp_len` or `component_len`. `size` is generally reserved for size in bytes use `_len` suffix for the rest. Try to avoid calling variable just `len` or `size`. They are always size of length of something.
if (input == nullptr) {
/* Uses Custom IDs */
input = interface->attr_get("vertex_in_drw_ResourceID_");
component_len = 2;
}
if (input) {
dynamic_cast<GLStorageBuf *>(unwrap(batch->resource_id_buf))->bind_as(GL_ARRAY_BUFFER);
glEnableVertexAttribArray(input->location);
glVertexAttribDivisor(input->location, 1);
glVertexAttribIPointer(
input->location, 1, to_gl(GPU_COMP_I32), sizeof(uint32_t), (GLvoid *)nullptr);
input->location, component_len, to_gl(GPU_COMP_I32), 0, (GLvoid *)nullptr);
attr_mask &= ~(1 << input->location);
}
}