diff --git a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh index 92452eefed2..7ca56f5ab85 100644 --- a/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh +++ b/source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh @@ -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 */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 7fcfb9b1c54..c7e9fc86ccf 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -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 } diff --git a/source/blender/draw/engines/workbench/workbench_engine.cc b/source/blender/draw/engines/workbench/workbench_engine.cc index 4fa0aa1a920..43c2cd36ddf 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.cc +++ b/source/blender/draw/engines/workbench/workbench_engine.cc @@ -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()) { diff --git a/source/blender/draw/engines/workbench/workbench_mesh_passes.cc b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc index 9e6d746cfa0..b0ce39282c0 100644 --- a/source/blender/draw/engines/workbench/workbench_mesh_passes.cc +++ b/source/blender/draw/engines/workbench/workbench_mesh_passes.cc @@ -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); } /** \} */ diff --git a/source/blender/draw/engines/workbench/workbench_private.hh b/source/blender/draw/engines/workbench/workbench_private.hh index 8ce55ed9699..ce926c5df8d 100644 --- a/source/blender/draw/engines/workbench/workbench_private.hh +++ b/source/blender/draw/engines/workbench/workbench_private.hh @@ -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); diff --git a/source/blender/draw/intern/draw_command.cc b/source/blender/draw/intern/draw_command.cc index 3fc4e66fb60..a413f94bd96 100644 --- a/source/blender/draw/intern/draw_command.cc +++ b/source/blender/draw/intern/draw_command.cc @@ -600,14 +600,13 @@ void DrawCommandBuf::bind(RecordingState &state, } void DrawMultiBuf::bind(RecordingState &state, - Vector &headers, - Vector &commands, + Vector & /*headers*/, + Vector & /*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")); diff --git a/source/blender/draw/intern/draw_command.hh b/source/blender/draw/intern/draw_command.hh index 45a7ff417ac..b9fd0e52f17 100644 --- a/source/blender/draw/intern/draw_command.hh +++ b/source/blender/draw/intern/draw_command.hh @@ -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 &commands, VisibilityBuf &visibility_buf, int visibility_word_per_draw, - int view_len); + int view_len, + bool use_custom_ids); }; /** \} */ diff --git a/source/blender/draw/intern/draw_command_shared.hh b/source/blender/draw/intern/draw_command_shared.hh index 4bb9aa777f3..b6afdfa5edc 100644 --- a/source/blender/draw/intern/draw_command_shared.hh +++ b/source/blender/draw/intern/draw_command_shared.hh @@ -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) diff --git a/source/blender/draw/intern/draw_manager.cc b/source/blender/draw/intern/draw_manager.cc index f34650255a5..188d4e23093 100644 --- a/source/blender/draw/intern/draw_manager.cc +++ b/source/blender/draw/intern/draw_manager.cc @@ -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(); diff --git a/source/blender/draw/intern/draw_pass.hh b/source/blender/draw/intern/draw_pass.hh index d05564c415a..03fb73aa273 100644 --- a/source/blender/draw/intern/draw_pass.hh +++ b/source/blender/draw/intern/draw_pass.hh @@ -135,6 +135,8 @@ class PassBase { public: const char *debug_name; + bool use_custom_ids; + PassBase(const char *name, DrawCommandBufType &draw_command_buf, SubPassVector> &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 std::string PassBase::serialize(std::string line_prefix) co * \{ */ template -inline void PassBase::draw( - GPUBatch *batch, uint instance_len, uint vertex_len, uint vertex_first, ResourceHandle handle) +inline void PassBase::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 inline void PassBase::draw(GPUBatch *batch, ResourceHandle handle) +template +inline void PassBase::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 @@ -675,9 +685,11 @@ inline void PassBase::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); } /** \} */ 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 11bf862a911..f2b3bfd98e4 100644 --- a/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl +++ b/source/blender/draw/intern/shaders/draw_command_generate_comp.glsl @@ -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; + } } } } diff --git a/source/blender/draw/intern/shaders/draw_view_info.hh b/source/blender/draw/intern/shaders/draw_view_info.hh index ee274ef9d59..5f61dec7a00 100644 --- a/source/blender/draw/intern/shaders/draw_view_info.hh +++ b/source/blender/draw/intern/shaders/draw_view_info.hh @@ -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"); + /** * 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"); +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 * \{ */ -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"); /** \} */ diff --git a/source/blender/gpu/intern/gpu_shader_create_info.cc b/source/blender/gpu/intern/gpu_shader_create_info.cc index c8ed68bc28e..25fba5c80c4 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.cc +++ b/source/blender/gpu/intern/gpu_shader_create_info.cc @@ -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 diff --git a/source/blender/gpu/opengl/gl_vertex_array.cc b/source/blender/gpu/opengl/gl_vertex_array.cc index d5aa1141521..97027ba9afa 100644 --- a/source/blender/gpu/opengl/gl_vertex_array.cc +++ b/source/blender/gpu/opengl/gl_vertex_array.cc @@ -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; + if (input == nullptr) { + /* Uses Custom IDs */ + input = interface->attr_get("vertex_in_drw_ResourceID_"); + component_len = 2; + } if (input) { dynamic_cast(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); } }