vkd3d-shader/hlsl: Always work with the extern resource's component type.

We need to distinguish between the data type of a resource and the data
type of its components. These are usually the same except for 4.0
profiles where an array (or multi-dimensional array) of resources is
still considered a single resource, so it is possible for it to hold
more than one component.

In the latter case, we often need to access the type of a single
component (all components have the same type) instead of the type of the
whole array which often doesn't contain the required information, such
as sampler dimension.

This patch replaces the extern_resource.data_type field with the
extern_resource.component_type field, which points to the type of a
single component in the resource. Using it relieves many other code
paths from considering the possibility of the resource being an array.

This fixes runtime errors reported by UBSan, such as this:

    vkd3d/libs/vkd3d-shader/tpf.c:6075:87: runtime error: load of value 7, which is not a valid value for type '_Bool'

when trying to compile shaders that contain UAV arrays on 4.0 profiles.

Before this commit, tpf.c accesses the

    hlsl_type->e.resource.rasteriser_ordered

field, but on 4.0 and 4.1 profiles these code paths can also be reached
by UAV arrays which are HLSL_CLASS_ARRAY and this field is not supposed
to be accessed.

By coincidence, the value of hlsl_type->e.array.elements_count was being
read because these fields have the same offset in the hlsl_type.e union.
This commit is contained in:
Francisco Casas 2024-08-08 17:17:50 -04:00 committed by Henri Verbeet
parent 9cf479d4bb
commit 412f91a14c
Notes: Henri Verbeet 2024-08-14 22:15:27 +02:00
Approved-by: Elizabeth Figura (@zfigura)
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/972

View File

@ -3110,8 +3110,6 @@ static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type)
{ {
switch (type->class) switch (type->class)
{ {
case HLSL_CLASS_ARRAY:
return sm4_resource_type(type->e.array.type);
case HLSL_CLASS_SAMPLER: case HLSL_CLASS_SAMPLER:
return D3D_SIT_SAMPLER; return D3D_SIT_SAMPLER;
case HLSL_CLASS_TEXTURE: case HLSL_CLASS_TEXTURE:
@ -3127,9 +3125,6 @@ static D3D_SHADER_INPUT_TYPE sm4_resource_type(const struct hlsl_type *type)
static D3D_RESOURCE_RETURN_TYPE sm4_resource_format(const struct hlsl_type *type) static D3D_RESOURCE_RETURN_TYPE sm4_resource_format(const struct hlsl_type *type)
{ {
if (type->class == HLSL_CLASS_ARRAY)
return sm4_resource_format(type->e.array.type);
switch (type->e.resource.format->e.numeric.type) switch (type->e.resource.format->e.numeric.type)
{ {
case HLSL_TYPE_DOUBLE: case HLSL_TYPE_DOUBLE:
@ -3154,9 +3149,6 @@ static D3D_RESOURCE_RETURN_TYPE sm4_resource_format(const struct hlsl_type *type
static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *type) static D3D_SRV_DIMENSION sm4_rdef_resource_dimension(const struct hlsl_type *type)
{ {
if (type->class == HLSL_CLASS_ARRAY)
return sm4_rdef_resource_dimension(type->e.array.type);
switch (type->sampler_dim) switch (type->sampler_dim)
{ {
case HLSL_SAMPLER_DIM_1D: case HLSL_SAMPLER_DIM_1D:
@ -3193,9 +3185,14 @@ struct extern_resource
const struct hlsl_buffer *buffer; const struct hlsl_buffer *buffer;
char *name; char *name;
struct hlsl_type *data_type;
bool is_user_packed; bool is_user_packed;
/* The data type of a single component of the resource.
* This might be different from the data type of the resource itself in 4.0
* profiles, where an array (or multi-dimensional array) is handled as a
* single resource, unlike in 5.0. */
struct hlsl_type *component_type;
enum hlsl_regset regset; enum hlsl_regset regset;
unsigned int id, space, index, bind_count; unsigned int id, space, index, bind_count;
@ -3294,9 +3291,10 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un
extern_resources[*count].buffer = NULL; extern_resources[*count].buffer = NULL;
extern_resources[*count].name = name; extern_resources[*count].name = name;
extern_resources[*count].data_type = component_type;
extern_resources[*count].is_user_packed = !!var->reg_reservation.reg_type; extern_resources[*count].is_user_packed = !!var->reg_reservation.reg_type;
extern_resources[*count].component_type = component_type;
extern_resources[*count].regset = regset; extern_resources[*count].regset = regset;
extern_resources[*count].id = var->regs[regset].id; extern_resources[*count].id = var->regs[regset].id;
extern_resources[*count].space = var->regs[regset].space; extern_resources[*count].space = var->regs[regset].space;
@ -3339,12 +3337,13 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un
extern_resources[*count].buffer = NULL; extern_resources[*count].buffer = NULL;
extern_resources[*count].name = name; extern_resources[*count].name = name;
extern_resources[*count].data_type = var->data_type;
/* For some reason 5.1 resources aren't marked as /* For some reason 5.1 resources aren't marked as
* user-packed, but cbuffers still are. */ * user-packed, but cbuffers still are. */
extern_resources[*count].is_user_packed = hlsl_version_lt(ctx, 5, 1) extern_resources[*count].is_user_packed = hlsl_version_lt(ctx, 5, 1)
&& !!var->reg_reservation.reg_type; && !!var->reg_reservation.reg_type;
extern_resources[*count].component_type = hlsl_type_get_component_type(ctx, var->data_type, 0);
extern_resources[*count].regset = r; extern_resources[*count].regset = r;
extern_resources[*count].id = var->regs[r].id; extern_resources[*count].id = var->regs[r].id;
extern_resources[*count].space = var->regs[r].space; extern_resources[*count].space = var->regs[r].space;
@ -3381,9 +3380,10 @@ static struct extern_resource *sm4_get_extern_resources(struct hlsl_ctx *ctx, un
extern_resources[*count].buffer = buffer; extern_resources[*count].buffer = buffer;
extern_resources[*count].name = name; extern_resources[*count].name = name;
extern_resources[*count].data_type = NULL;
extern_resources[*count].is_user_packed = !!buffer->reservation.reg_type; extern_resources[*count].is_user_packed = !!buffer->reservation.reg_type;
extern_resources[*count].component_type = NULL;
extern_resources[*count].regset = HLSL_REGSET_NUMERIC; extern_resources[*count].regset = HLSL_REGSET_NUMERIC;
extern_resources[*count].id = buffer->reg.id; extern_resources[*count].id = buffer->reg.id;
extern_resources[*count].space = buffer->reg.space; extern_resources[*count].space = buffer->reg.space;
@ -3466,13 +3466,13 @@ static void write_sm4_rdef(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc)
if (resource->buffer) if (resource->buffer)
put_u32(&buffer, resource->buffer->type == HLSL_BUFFER_CONSTANT ? D3D_SIT_CBUFFER : D3D_SIT_TBUFFER); put_u32(&buffer, resource->buffer->type == HLSL_BUFFER_CONSTANT ? D3D_SIT_CBUFFER : D3D_SIT_TBUFFER);
else else
put_u32(&buffer, sm4_resource_type(resource->data_type)); put_u32(&buffer, sm4_resource_type(resource->component_type));
if (resource->regset == HLSL_REGSET_TEXTURES || resource->regset == HLSL_REGSET_UAVS) if (resource->regset == HLSL_REGSET_TEXTURES || resource->regset == HLSL_REGSET_UAVS)
{ {
unsigned int dimx = hlsl_type_get_component_type(ctx, resource->data_type, 0)->e.resource.format->dimx; unsigned int dimx = resource->component_type->e.resource.format->dimx;
put_u32(&buffer, sm4_resource_format(resource->data_type)); put_u32(&buffer, sm4_resource_format(resource->component_type));
put_u32(&buffer, sm4_rdef_resource_dimension(resource->data_type)); put_u32(&buffer, sm4_rdef_resource_dimension(resource->component_type));
put_u32(&buffer, ~0u); /* FIXME: multisample count */ put_u32(&buffer, ~0u); /* FIXME: multisample count */
flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT; flags |= (dimx - 1) << VKD3D_SM4_SIF_TEXTURE_COMPONENTS_SHIFT;
} }
@ -4284,7 +4284,6 @@ static void write_sm4_dcl_constant_buffer(const struct tpf_writer *tpf, const st
static void write_sm4_dcl_samplers(const struct tpf_writer *tpf, const struct extern_resource *resource) static void write_sm4_dcl_samplers(const struct tpf_writer *tpf, const struct extern_resource *resource)
{ {
struct hlsl_type *component_type;
unsigned int i; unsigned int i;
struct sm4_instruction instr = struct sm4_instruction instr =
{ {
@ -4294,13 +4293,11 @@ static void write_sm4_dcl_samplers(const struct tpf_writer *tpf, const struct ex
.dst_count = 1, .dst_count = 1,
}; };
component_type = hlsl_type_get_component_type(tpf->ctx, resource->data_type, 0);
if (component_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON)
instr.extra_bits |= VKD3D_SM4_SAMPLER_COMPARISON << VKD3D_SM4_SAMPLER_MODE_SHIFT;
VKD3D_ASSERT(resource->regset == HLSL_REGSET_SAMPLERS); VKD3D_ASSERT(resource->regset == HLSL_REGSET_SAMPLERS);
if (resource->component_type->sampler_dim == HLSL_SAMPLER_DIM_COMPARISON)
instr.extra_bits |= VKD3D_SM4_SAMPLER_COMPARISON << VKD3D_SM4_SAMPLER_MODE_SHIFT;
for (i = 0; i < resource->bind_count; ++i) for (i = 0; i < resource->bind_count; ++i)
{ {
if (resource->var && !resource->var->objects_usage[HLSL_REGSET_SAMPLERS][i].used) if (resource->var && !resource->var->objects_usage[HLSL_REGSET_SAMPLERS][i].used)
@ -4337,7 +4334,7 @@ static void write_sm4_dcl_textures(const struct tpf_writer *tpf, const struct ex
VKD3D_ASSERT(resource->regset == regset); VKD3D_ASSERT(resource->regset == regset);
component_type = hlsl_type_get_component_type(tpf->ctx, resource->data_type, 0); component_type = resource->component_type;
for (i = 0; i < resource->bind_count; ++i) for (i = 0; i < resource->bind_count; ++i)
{ {
@ -4384,18 +4381,18 @@ static void write_sm4_dcl_textures(const struct tpf_writer *tpf, const struct ex
if (uav) if (uav)
{ {
switch (resource->data_type->sampler_dim) switch (component_type->sampler_dim)
{ {
case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER: case HLSL_SAMPLER_DIM_STRUCTURED_BUFFER:
instr.opcode = VKD3D_SM5_OP_DCL_UAV_STRUCTURED; instr.opcode = VKD3D_SM5_OP_DCL_UAV_STRUCTURED;
instr.byte_stride = resource->data_type->e.resource.format->reg_size[HLSL_REGSET_NUMERIC] * 4; instr.byte_stride = component_type->e.resource.format->reg_size[HLSL_REGSET_NUMERIC] * 4;
break; break;
default: default:
instr.opcode = VKD3D_SM5_OP_DCL_UAV_TYPED; instr.opcode = VKD3D_SM5_OP_DCL_UAV_TYPED;
break; break;
} }
if (resource->data_type->e.resource.rasteriser_ordered) if (component_type->e.resource.rasteriser_ordered)
instr.opcode |= VKD3DSUF_RASTERISER_ORDERED_VIEW << VKD3D_SM5_UAV_FLAGS_SHIFT; instr.opcode |= VKD3DSUF_RASTERISER_ORDERED_VIEW << VKD3D_SM5_UAV_FLAGS_SHIFT;
} }
else else
@ -6105,7 +6102,7 @@ static void write_sm4_sfi0(struct hlsl_ctx *ctx, struct dxbc_writer *dxbc)
extern_resources = sm4_get_extern_resources(ctx, &extern_resources_count); extern_resources = sm4_get_extern_resources(ctx, &extern_resources_count);
for (unsigned int i = 0; i < extern_resources_count; ++i) for (unsigned int i = 0; i < extern_resources_count; ++i)
{ {
if (extern_resources[i].data_type && extern_resources[i].data_type->e.resource.rasteriser_ordered) if (extern_resources[i].component_type && extern_resources[i].component_type->e.resource.rasteriser_ordered)
*flags |= VKD3D_SM4_REQUIRES_ROVS; *flags |= VKD3D_SM4_REQUIRES_ROVS;
} }
sm4_free_extern_resources(extern_resources, extern_resources_count); sm4_free_extern_resources(extern_resources, extern_resources_count);