Fix #142097: Vulkan: Crash with unbound textures

On the Vulkan side, ensure that unbound textures don't result in
accessing uninitialized or out of bounds memory.
On the Draw side, ensure all Hair and Curves attributes have, at least,
a dummy attribute bound.

Pull Request: https://projects.blender.org/blender/blender/pulls/142265
This commit is contained in:
Miguel Pozo
2025-07-21 15:14:10 +02:00
parent 230813f2ab
commit a8975bf651
4 changed files with 54 additions and 23 deletions

View File

@@ -301,13 +301,21 @@ gpu::Batch *curves_sub_pass_setup_implementation(PassT &sub_ps,
CurvesEvalCache *curves_cache = drw_curves_cache_get(
curves_id, gpu_material, subdiv, thickness_res);
/* Fix issue with certain driver not drawing anything if there is nothing bound to
* "ac", "au", "u" or "c". */
/* Ensure we have no unbound resources.
* Required for Vulkan.
* Fixes issues with certain GL drivers not drawing anything. */
sub_ps.bind_texture("u", module.dummy_vbo);
sub_ps.bind_texture("au", module.dummy_vbo);
sub_ps.bind_texture("a", module.dummy_vbo);
sub_ps.bind_texture("c", module.dummy_vbo);
sub_ps.bind_texture("ac", module.dummy_vbo);
sub_ps.bind_texture("a", module.dummy_vbo);
if (gpu_material) {
ListBase attr_list = GPU_material_attributes(gpu_material);
ListBaseWrapper<GPUMaterialAttribute> attrs(attr_list);
for (const GPUMaterialAttribute *attr : attrs) {
sub_ps.bind_texture(attr->input_name, module.dummy_vbo);
}
}
/* TODO: Generalize radius implementation for curves data type. */
float hair_rad_shape = 0.0f;

View File

@@ -178,6 +178,25 @@ blender::gpu::Batch *hair_sub_pass_setup_implementation(PassT &sub_ps,
ParticleHairCache *hair_cache = drw_hair_particle_cache_get(
object, psys, md, gpu_material, subdiv, thickness_res);
/* TODO(fclem): Remove Global access. */
CurvesModule &module = *drw_get().data->curves_module;
/* Ensure we have no unbound resources.
* Required for Vulkan.
* Fixes issues with certain GL drivers not drawing anything. */
sub_ps.bind_texture("u", module.dummy_vbo);
sub_ps.bind_texture("au", module.dummy_vbo);
sub_ps.bind_texture("a", module.dummy_vbo);
sub_ps.bind_texture("c", module.dummy_vbo);
sub_ps.bind_texture("ac", module.dummy_vbo);
if (gpu_material) {
ListBase attr_list = GPU_material_attributes(gpu_material);
ListBaseWrapper<GPUMaterialAttribute> attrs(attr_list);
for (const GPUMaterialAttribute *attr : attrs) {
sub_ps.bind_texture(attr->input_name, module.dummy_vbo);
}
}
/* TODO: optimize this. Only bind the ones #GPUMaterial needs. */
for (int i : IndexRange(hair_cache->num_uv_layers)) {
for (int n = 0; n < MAX_LAYER_NAME_CT && hair_cache->uv_layer_names[i][n][0] != '\0'; n++) {
@@ -190,21 +209,6 @@ blender::gpu::Batch *hair_sub_pass_setup_implementation(PassT &sub_ps,
}
}
/* TODO(fclem): Remove Global access. */
CurvesModule &module = *drw_get().data->curves_module;
/* Fix issue with certain driver not drawing anything if there is nothing bound to
* "ac", "au", "u" or "c". */
if (hair_cache->num_uv_layers == 0) {
sub_ps.bind_texture("u", module.dummy_vbo);
sub_ps.bind_texture("au", module.dummy_vbo);
sub_ps.bind_texture("a", module.dummy_vbo);
}
if (hair_cache->num_col_layers == 0) {
sub_ps.bind_texture("c", module.dummy_vbo);
sub_ps.bind_texture("ac", module.dummy_vbo);
}
float4x4 dupli_mat = ob_ref.particles_matrix();
/* Get hair shape parameters. */

View File

@@ -92,7 +92,13 @@ void VKDescriptorSetUpdator::bind_texture_resource(const VKDevice &device,
const VKResourceBinding &resource_binding,
render_graph::VKResourceAccessInfo &access_info)
{
const BindSpaceTextures::Elem &elem = state_manager.textures_.get(resource_binding.binding);
const BindSpaceTextures::Elem *elem_ptr = state_manager.textures_.get(resource_binding.binding);
if (!elem_ptr) {
/* Unbound resource. */
BLI_assert_unreachable();
return;
}
const BindSpaceTextures::Elem &elem = *elem_ptr;
switch (elem.resource_type) {
case BindSpaceTextures::Type::VertexBuffer: {
VKVertexBuffer &vertex_buffer = *static_cast<VKVertexBuffer *>(elem.resource);
@@ -162,7 +168,14 @@ void VKDescriptorSetUpdator::bind_input_attachment_resource(
}
else {
bool supports_dynamic_rendering = device.extensions_get().dynamic_rendering;
const BindSpaceTextures::Elem &elem = state_manager.textures_.get(resource_binding.binding);
const BindSpaceTextures::Elem *elem_ptr = state_manager.textures_.get(
resource_binding.binding);
if (!elem_ptr) {
/* Unbound resource. */
BLI_assert_unreachable();
return;
}
const BindSpaceTextures::Elem &elem = *elem_ptr;
VKTexture *texture = static_cast<VKTexture *>(elem.resource);
BLI_assert(texture);
BLI_assert(elem.resource_type == BindSpaceTextures::Type::Texture);

View File

@@ -174,16 +174,22 @@ class BindSpaceTextures {
void bind(Type resource_type, void *resource, GPUSamplerState sampler, int binding)
{
if (bound_resources.size() <= binding) {
bound_resources.resize(binding + 1);
bound_resources.resize(binding + 1, {});
}
bound_resources[binding].resource_type = resource_type;
bound_resources[binding].resource = resource;
bound_resources[binding].sampler = sampler;
}
const Elem &get(int binding) const
const Elem *get(int binding) const
{
return bound_resources[binding];
if (binding >= bound_resources.size()) {
/* TODO: Check with @Jeroen-Bakker.
* Could we ensure state_manager adds default initialized bindings for each ShaderInterface
* resource? (See #142097). */
return nullptr;
}
return &bound_resources[binding];
}
void unbind(void *resource)