llvmpipe,lavapipe: Relayout lp_descriptor

This is more robust in case of a descriptor type mismatch.

Fixes test_null_descriptor_mismatch_type (vkd3d-proton).

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23996>
This commit is contained in:
Konstantin Seurer
2023-07-04 21:01:23 +02:00
committed by Marge Bot
parent 7b1a1e2163
commit 39427352f6
7 changed files with 84 additions and 79 deletions

View File

@@ -182,7 +182,7 @@ lp_bld_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base
: offsetof(struct lp_texture_functions, sample_functions);
LLVMValueRef texture_base_ptr = load_texture_functions_ptr(
gallivm, texture_descriptor, offsetof(union lp_descriptor, sample_functions), functions_offset);
gallivm, texture_descriptor, offsetof(struct lp_descriptor, functions), functions_offset);
LLVMTypeRef texture_function_type = lp_build_sample_function_type(gallivm, params->sample_key);
LLVMTypeRef texture_function_ptr_type = LLVMPointerType(texture_function_type, 0);
@@ -201,7 +201,7 @@ lp_bld_llvm_sampler_soa_emit_fetch_texel(const struct lp_build_sampler_soa *base
} else {
sampler_desc_ptr = lp_llvm_descriptor_base(gallivm, consts, params->sampler_resource, LP_MAX_TGSI_CONST_BUFFERS);
LLVMValueRef sampler_index_offset = lp_build_const_int64(gallivm, offsetof(union lp_descriptor, sampler_index));
LLVMValueRef sampler_index_offset = lp_build_const_int64(gallivm, offsetof(struct lp_descriptor, sampler_index));
LLVMValueRef sampler_index_ptr = LLVMBuildAdd(builder, sampler_desc_ptr, sampler_index_offset, "");
LLVMTypeRef sampler_index_type = LLVMInt32TypeInContext(gallivm->context);
@@ -359,7 +359,7 @@ lp_bld_llvm_sampler_soa_emit_size_query(const struct lp_build_sampler_soa *base,
: offsetof(struct lp_texture_functions, size_function);
LLVMValueRef texture_base_ptr = load_texture_functions_ptr(
gallivm, texture_descriptor, offsetof(union lp_descriptor, sample_functions), functions_offset);
gallivm, texture_descriptor, offsetof(struct lp_descriptor, functions), functions_offset);
LLVMTypeRef texture_function_type = lp_build_size_function_type(gallivm, params);
LLVMTypeRef texture_function_ptr_type = LLVMPointerType(texture_function_type, 0);
@@ -470,7 +470,7 @@ lp_bld_llvm_image_soa_emit_op(const struct lp_build_image_soa *base,
LLVMValueRef image_descriptor = lp_llvm_descriptor_base(gallivm, consts, params->resource, LP_MAX_TGSI_CONST_BUFFERS);
LLVMValueRef image_base_ptr = load_texture_functions_ptr(
gallivm, image_descriptor, offsetof(union lp_descriptor, image_functions),
gallivm, image_descriptor, offsetof(struct lp_descriptor, functions),
offsetof(struct lp_texture_functions, image_functions));
LLVMTypeRef image_function_type = lp_build_image_function_type(gallivm, params, params->ms_index);

View File

@@ -72,7 +72,7 @@ lp_llvm_descriptor_base(struct gallivm_state *gallivm,
if (LLVMGetTypeKind(LLVMTypeOf(binding_index)) == LLVMVectorTypeKind)
binding_index = LLVMBuildExtractElement(builder, binding_index, lp_build_const_int32(gallivm, 0), "");
LLVMValueRef binding_offset = LLVMBuildMul(builder, binding_index, lp_build_const_int32(gallivm, sizeof(union lp_descriptor)), "");
LLVMValueRef binding_offset = LLVMBuildMul(builder, binding_index, lp_build_const_int32(gallivm, sizeof(struct lp_descriptor)), "");
LLVMTypeRef int64_type = LLVMInt64TypeInContext(gallivm->context);
binding_offset = LLVMBuildIntCast2(builder, binding_offset, int64_type, false, "");
@@ -352,7 +352,7 @@ lp_build_llvm_texture_member(struct gallivm_state *gallivm,
LLVMValueRef ptr;
if (gallivm->texture_descriptor) {
static_assert(offsetof(union lp_descriptor, texture) == 0, "Invalid texture offset!");
static_assert(offsetof(struct lp_descriptor, texture) == 0, "Invalid texture offset!");
LLVMValueRef texture_ptr = gallivm->texture_descriptor;
LLVMTypeRef texture_ptr_type = LLVMStructGetTypeAtIndex(resources_type, LP_JIT_RES_TEXTURES);
@@ -484,7 +484,7 @@ lp_build_llvm_sampler_member(struct gallivm_state *gallivm,
LLVMValueRef ptr;
if (gallivm->sampler_descriptor) {
LLVMValueRef sampler_offset = lp_build_const_int64(gallivm, offsetof(union lp_descriptor, sampler));
LLVMValueRef sampler_offset = lp_build_const_int64(gallivm, offsetof(struct lp_descriptor, sampler));
LLVMValueRef sampler_ptr = LLVMBuildAdd(builder, gallivm->sampler_descriptor, sampler_offset, "");
LLVMTypeRef sampler_ptr_type = LLVMStructGetTypeAtIndex(resources_type, LP_JIT_RES_SAMPLERS);
@@ -569,7 +569,7 @@ lp_build_llvm_image_member(struct gallivm_state *gallivm,
LLVMValueRef ptr;
if (gallivm->texture_descriptor) {
LLVMValueRef image_offset = lp_build_const_int64(gallivm, offsetof(union lp_descriptor, image));
LLVMValueRef image_offset = lp_build_const_int64(gallivm, offsetof(struct lp_descriptor, image));
LLVMValueRef image_ptr = LLVMBuildAdd(builder, gallivm->texture_descriptor, image_offset, "");
LLVMTypeRef image_ptr_type = LLVMStructGetTypeAtIndex(resources_type, LP_JIT_RES_IMAGES);

View File

@@ -226,18 +226,23 @@ struct lp_texture_handle {
uint32_t sampler_index;
};
union lp_descriptor {
struct {
struct lp_jit_texture texture;
struct lp_jit_sampler sampler;
void *sample_functions;
uint32_t sampler_index;
struct lp_descriptor {
union {
struct {
struct lp_jit_texture texture;
struct lp_jit_sampler sampler;
};
struct {
struct lp_jit_image image;
};
struct lp_jit_buffer buffer;
};
struct {
struct lp_jit_image image;
void *image_functions;
};
struct lp_jit_buffer buffer;
/* Store sample/image functions in the same location since some d3d12 games
* rely on mismatched descriptor types with null descriptors.
*/
uint32_t sampler_index;
void *functions;
};
#define LP_MAX_TEX_FUNC_ARGS 32

View File

@@ -73,7 +73,7 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateDescriptorSetLayout(
size_t size = sizeof(struct lvp_descriptor_set_layout) +
num_bindings * sizeof(set_layout->binding[0]) +
immutable_sampler_count * sizeof(union lp_descriptor*);
immutable_sampler_count * sizeof(struct lp_descriptor*);
set_layout = vk_descriptor_set_layout_zalloc(&device->vk, size);
if (!set_layout)
@@ -81,8 +81,8 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateDescriptorSetLayout(
set_layout->immutable_sampler_count = immutable_sampler_count;
/* We just allocate all the samplers at the end of the struct */
union lp_descriptor **samplers =
(union lp_descriptor **)&set_layout->binding[num_bindings];
struct lp_descriptor **samplers =
(struct lp_descriptor **)&set_layout->binding[num_bindings];
set_layout->binding_count = num_bindings;
set_layout->shader_stages = 0;
@@ -171,7 +171,7 @@ VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateDescriptorSetLayout(
}
for (uint32_t i = 0; i < pCreateInfo->bindingCount; i++)
set_layout->binding[i].uniform_block_offset += set_layout->size * sizeof(union lp_descriptor);
set_layout->binding[i].uniform_block_offset += set_layout->size * sizeof(struct lp_descriptor);
free(bindings);
@@ -316,7 +316,7 @@ lvp_descriptor_set_create(struct lvp_device *device,
set->layout = layout;
vk_descriptor_set_layout_ref(&layout->vk);
uint64_t bo_size = layout->size * sizeof(union lp_descriptor);
uint64_t bo_size = layout->size * sizeof(struct lp_descriptor);
for (unsigned i = 0; i < layout->binding_count; i++)
bo_size += layout->binding[i].uniform_block_size;
@@ -346,7 +346,7 @@ lvp_descriptor_set_create(struct lvp_device *device,
if (!bind_layout->immutable_samplers)
continue;
union lp_descriptor *desc = set->map;
struct lp_descriptor *desc = set->map;
desc += bind_layout->descriptor_index;
for (uint32_t sampler_index = 0; sampler_index < bind_layout->array_size; sampler_index++) {
@@ -444,7 +444,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
continue;
}
union lp_descriptor *desc = set->map;
struct lp_descriptor *desc = set->map;
desc += bind_layout->descriptor_index + write->dstArrayElement;
switch (write->descriptorType) {
@@ -464,7 +464,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
write->pImageInfo[j].imageView);
if (iview) {
lp_jit_texture_from_pipe(&desc[j].texture, iview->sv);
desc[j].sample_functions = iview->texture_handle->functions;
desc[j].functions = iview->texture_handle->functions;
if (!bind_layout->immutable_samplers) {
LVP_FROM_HANDLE(lvp_sampler, sampler,
@@ -474,7 +474,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
desc[j].sampler_index = sampler->desc.sampler_index;
}
} else {
desc[j].sample_functions = device->null_texture_handle->functions;
desc[j].functions = device->null_texture_handle->functions;
desc[j].sampler_index = 0;
}
}
@@ -487,9 +487,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
if (iview) {
lp_jit_texture_from_pipe(&desc[j].texture, iview->sv);
desc[j].sample_functions = iview->texture_handle->functions;
desc[j].functions = iview->texture_handle->functions;
} else {
desc[j].sample_functions = device->null_texture_handle->functions;
desc[j].functions = device->null_texture_handle->functions;
desc[j].sampler_index = 0;
}
}
@@ -502,9 +502,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
if (iview) {
lp_jit_image_from_pipe(&desc[j].image, &iview->iv);
desc[j].image_functions = iview->image_handle->functions;
desc[j].functions = iview->image_handle->functions;
} else {
desc[j].image_functions = device->null_image_handle->functions;
desc[j].functions = device->null_image_handle->functions;
}
}
break;
@@ -516,9 +516,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
if (bview) {
lp_jit_texture_from_pipe(&desc[j].texture, bview->sv);
desc[j].sample_functions = bview->texture_handle->functions;
desc[j].functions = bview->texture_handle->functions;
} else {
desc[j].sample_functions = device->null_texture_handle->functions;
desc[j].functions = device->null_texture_handle->functions;
desc[j].sampler_index = 0;
}
}
@@ -531,9 +531,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
if (bview) {
lp_jit_image_from_pipe(&desc[j].image, &bview->iv);
desc[j].image_functions = bview->image_handle->functions;
desc[j].functions = bview->image_handle->functions;
} else {
desc[j].image_functions = device->null_image_handle->functions;
desc[j].functions = device->null_image_handle->functions;
}
}
break;
@@ -594,12 +594,12 @@ VKAPI_ATTR void VKAPI_CALL lvp_UpdateDescriptorSets(
const struct lvp_descriptor_set_binding_layout *src_layout =
&src->layout->binding[copy->srcBinding];
union lp_descriptor *src_desc = src->map;
struct lp_descriptor *src_desc = src->map;
src_desc += src_layout->descriptor_index;
const struct lvp_descriptor_set_binding_layout *dst_layout =
&dst->layout->binding[copy->dstBinding];
union lp_descriptor *dst_desc = dst->map;
struct lp_descriptor *dst_desc = dst->map;
dst_desc += dst_layout->descriptor_index;
if (src_layout->type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK) {
@@ -789,7 +789,7 @@ lvp_descriptor_set_update_with_template(VkDevice _device, VkDescriptorSet descri
continue;
}
union lp_descriptor *desc = set->map;
struct lp_descriptor *desc = set->map;
desc += bind_layout->descriptor_index;
for (j = 0; j < entry->descriptorCount; ++j) {
@@ -809,7 +809,7 @@ lvp_descriptor_set_update_with_template(VkDevice _device, VkDescriptorSet descri
if (iview) {
lp_jit_texture_from_pipe(&desc[idx].texture, iview->sv);
desc[idx].sample_functions = iview->texture_handle->functions;
desc[idx].functions = iview->texture_handle->functions;
if (!bind_layout->immutable_samplers) {
LVP_FROM_HANDLE(lvp_sampler, sampler, info->sampler);
@@ -818,7 +818,7 @@ lvp_descriptor_set_update_with_template(VkDevice _device, VkDescriptorSet descri
desc[idx].sampler_index = sampler->desc.sampler_index;
}
} else {
desc[j].sample_functions = device->null_texture_handle->functions;
desc[j].functions = device->null_texture_handle->functions;
desc[j].sampler_index = 0;
}
break;
@@ -829,9 +829,9 @@ lvp_descriptor_set_update_with_template(VkDevice _device, VkDescriptorSet descri
if (iview) {
lp_jit_texture_from_pipe(&desc[idx].texture, iview->sv);
desc[idx].sample_functions = iview->texture_handle->functions;
desc[idx].functions = iview->texture_handle->functions;
} else {
desc[j].sample_functions = device->null_texture_handle->functions;
desc[j].functions = device->null_texture_handle->functions;
desc[j].sampler_index = 0;
}
break;
@@ -843,9 +843,9 @@ lvp_descriptor_set_update_with_template(VkDevice _device, VkDescriptorSet descri
if (iview) {
lp_jit_image_from_pipe(&desc[idx].image, &iview->iv);
desc[idx].image_functions = iview->image_handle->functions;
desc[idx].functions = iview->image_handle->functions;
} else {
desc[idx].image_functions = device->null_image_handle->functions;
desc[idx].functions = device->null_image_handle->functions;
}
break;
}
@@ -855,9 +855,9 @@ lvp_descriptor_set_update_with_template(VkDevice _device, VkDescriptorSet descri
if (bview) {
lp_jit_texture_from_pipe(&desc[idx].texture, bview->sv);
desc[idx].sample_functions = bview->texture_handle->functions;
desc[idx].functions = bview->texture_handle->functions;
} else {
desc[j].sample_functions = device->null_texture_handle->functions;
desc[j].functions = device->null_texture_handle->functions;
desc[j].sampler_index = 0;
}
break;
@@ -868,9 +868,9 @@ lvp_descriptor_set_update_with_template(VkDevice _device, VkDescriptorSet descri
if (bview) {
lp_jit_image_from_pipe(&desc[idx].image, &bview->iv);
desc[idx].image_functions = bview->image_handle->functions;
desc[idx].functions = bview->image_handle->functions;
} else {
desc[idx].image_functions = device->null_image_handle->functions;
desc[idx].functions = device->null_image_handle->functions;
}
break;
}
@@ -945,7 +945,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorSetLayoutSizeEXT(
{
LVP_FROM_HANDLE(lvp_descriptor_set_layout, layout, _layout);
*pSize = layout->size * sizeof(union lp_descriptor);
*pSize = layout->size * sizeof(struct lp_descriptor);
for (unsigned i = 0; i < layout->binding_count; i++)
*pSize += layout->binding[i].uniform_block_size;
@@ -964,7 +964,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorSetLayoutBindingOffsetEXT(
if (bind_layout->type == VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK)
*pOffset = bind_layout->uniform_block_offset;
else
*pOffset = bind_layout->descriptor_index * sizeof(union lp_descriptor);
*pOffset = bind_layout->descriptor_index * sizeof(struct lp_descriptor);
}
VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
@@ -975,7 +975,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
{
LVP_FROM_HANDLE(lvp_device, device, _device);
union lp_descriptor *desc = pDescriptor;
struct lp_descriptor *desc = pDescriptor;
struct pipe_sampler_state sampler = {
.seamless_cube_map = 1,
@@ -1005,7 +1005,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
LVP_FROM_HANDLE(lvp_image_view, iview, info->imageView);
lp_jit_texture_from_pipe(&desc->texture, iview->sv);
desc->sample_functions = iview->texture_handle->functions;
desc->functions = iview->texture_handle->functions;
if (info->sampler) {
LVP_FROM_HANDLE(lvp_sampler, sampler, info->sampler);
@@ -1016,7 +1016,7 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
desc->sampler_index = 0;
}
} else {
desc->sample_functions = device->null_texture_handle->functions;
desc->functions = device->null_texture_handle->functions;
desc->sampler_index = 0;
}
@@ -1027,9 +1027,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
if (pCreateInfo->data.pSampledImage && pCreateInfo->data.pSampledImage->imageView) {
LVP_FROM_HANDLE(lvp_image_view, iview, pCreateInfo->data.pSampledImage->imageView);
lp_jit_texture_from_pipe(&desc->texture, iview->sv);
desc->sample_functions = iview->texture_handle->functions;
desc->functions = iview->texture_handle->functions;
} else {
desc->sample_functions = device->null_texture_handle->functions;
desc->functions = device->null_texture_handle->functions;
desc->sampler_index = 0;
}
break;
@@ -1041,9 +1041,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
if (pCreateInfo->data.pStorageImage && pCreateInfo->data.pStorageImage->imageView) {
LVP_FROM_HANDLE(lvp_image_view, iview, pCreateInfo->data.pStorageImage->imageView);
lp_jit_image_from_pipe(&desc->image, &iview->iv);
desc->image_functions = iview->image_handle->functions;
desc->functions = iview->image_handle->functions;
} else {
desc->image_functions = device->null_image_handle->functions;
desc->functions = device->null_image_handle->functions;
}
break;
}
@@ -1052,9 +1052,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
if (bda && bda->address) {
enum pipe_format pformat = vk_format_to_pipe_format(bda->format);
lp_jit_texture_buffer_from_bda(&desc->texture, (void*)(uintptr_t)bda->address, bda->range, pformat);
desc->sample_functions = get_texture_handle_bda(device, bda, pformat).functions;
desc->functions = get_texture_handle_bda(device, bda, pformat).functions;
} else {
desc->sample_functions = device->null_texture_handle->functions;
desc->functions = device->null_texture_handle->functions;
desc->sampler_index = 0;
}
break;
@@ -1064,9 +1064,9 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetDescriptorEXT(
if (bda && bda->address) {
enum pipe_format pformat = vk_format_to_pipe_format(bda->format);
lp_jit_image_buffer_from_bda(&desc->image, (void *)(uintptr_t)bda->address, bda->range, pformat);
desc->image_functions = get_image_handle_bda(device, bda, pformat).functions;
desc->functions = get_image_handle_bda(device, bda, pformat).functions;
} else {
desc->image_functions = device->null_image_handle->functions;
desc->functions = device->null_image_handle->functions;
}
break;
}

View File

@@ -1252,19 +1252,19 @@ VKAPI_ATTR void VKAPI_CALL lvp_GetPhysicalDeviceProperties2(
props->imageViewCaptureReplayDescriptorDataSize = 0;
props->samplerCaptureReplayDescriptorDataSize = 0;
props->accelerationStructureCaptureReplayDescriptorDataSize = 0;
props->samplerDescriptorSize = sizeof(union lp_descriptor);
props->combinedImageSamplerDescriptorSize = sizeof(union lp_descriptor);
props->sampledImageDescriptorSize = sizeof(union lp_descriptor);
props->storageImageDescriptorSize = sizeof(union lp_descriptor);
props->uniformTexelBufferDescriptorSize = sizeof(union lp_descriptor);
props->robustUniformTexelBufferDescriptorSize = sizeof(union lp_descriptor);
props->storageTexelBufferDescriptorSize = sizeof(union lp_descriptor);
props->robustStorageTexelBufferDescriptorSize = sizeof(union lp_descriptor);
props->uniformBufferDescriptorSize = sizeof(union lp_descriptor);
props->robustUniformBufferDescriptorSize = sizeof(union lp_descriptor);
props->storageBufferDescriptorSize = sizeof(union lp_descriptor);
props->robustStorageBufferDescriptorSize = sizeof(union lp_descriptor);
props->inputAttachmentDescriptorSize = sizeof(union lp_descriptor);
props->samplerDescriptorSize = sizeof(struct lp_descriptor);
props->combinedImageSamplerDescriptorSize = sizeof(struct lp_descriptor);
props->sampledImageDescriptorSize = sizeof(struct lp_descriptor);
props->storageImageDescriptorSize = sizeof(struct lp_descriptor);
props->uniformTexelBufferDescriptorSize = sizeof(struct lp_descriptor);
props->robustUniformTexelBufferDescriptorSize = sizeof(struct lp_descriptor);
props->storageTexelBufferDescriptorSize = sizeof(struct lp_descriptor);
props->robustStorageTexelBufferDescriptorSize = sizeof(struct lp_descriptor);
props->uniformBufferDescriptorSize = sizeof(struct lp_descriptor);
props->robustUniformBufferDescriptorSize = sizeof(struct lp_descriptor);
props->storageBufferDescriptorSize = sizeof(struct lp_descriptor);
props->robustStorageBufferDescriptorSize = sizeof(struct lp_descriptor);
props->inputAttachmentDescriptorSize = sizeof(struct lp_descriptor);
props->accelerationStructureDescriptorSize = 0;
props->maxSamplerDescriptorBufferRange = 1<<27; //spec minimum
props->maxResourceDescriptorBufferRange = 1<<27; //spec minimum

View File

@@ -1131,7 +1131,7 @@ apply_dynamic_offsets(struct lvp_descriptor_set **out_set, uint32_t *offsets, ui
binding->type != VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
continue;
union lp_descriptor *desc = set->map;
struct lp_descriptor *desc = set->map;
desc += binding->descriptor_index;
for (uint32_t j = 0; j < binding->array_size; j++) {
@@ -4015,7 +4015,7 @@ bind_db_samplers(struct rendering_state *state, bool is_compute, unsigned set)
if (!bind_layout->immutable_samplers)
continue;
union lp_descriptor *desc = (void*)db;
struct lp_descriptor *desc = (void*)db;
desc += bind_layout->descriptor_index;
for (uint32_t sampler_index = 0; sampler_index < bind_layout->array_size; sampler_index++) {

View File

@@ -276,7 +276,7 @@ struct lvp_image_view {
struct lvp_sampler {
struct vk_object_base base;
union lp_descriptor desc;
struct lp_descriptor desc;
struct lp_texture_handle *texture_handle;
};
@@ -294,7 +294,7 @@ struct lvp_descriptor_set_binding_layout {
uint32_t uniform_block_size;
/* Immutable samplers (or NULL if no immutable samplers) */
union lp_descriptor **immutable_samplers;
struct lp_descriptor **immutable_samplers;
};
struct lvp_descriptor_set_layout {