vkd3d-shader: Reduce masks to only read components in vsir_program_remap_output_signature().

This commit is contained in:
Elizabeth Figura 2024-10-29 12:09:58 -05:00 committed by Henri Verbeet
parent 61bda1c054
commit cc9fcee676
Notes: Henri Verbeet 2024-11-04 17:11:05 +01:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1236
2 changed files with 100 additions and 7 deletions

View File

@ -820,14 +820,84 @@ static const struct vkd3d_shader_varying_map *find_varying_map(
return NULL;
}
static bool target_allows_subset_masks(const struct vkd3d_shader_compile_info *info)
{
const struct vkd3d_shader_spirv_target_info *spirv_info;
enum vkd3d_shader_spirv_environment environment;
switch (info->target_type)
{
case VKD3D_SHADER_TARGET_SPIRV_BINARY:
spirv_info = vkd3d_find_struct(info->next, SPIRV_TARGET_INFO);
environment = spirv_info ? spirv_info->environment : VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0;
switch (environment)
{
case VKD3D_SHADER_SPIRV_ENVIRONMENT_OPENGL_4_5:
return true;
case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_0:
case VKD3D_SHADER_SPIRV_ENVIRONMENT_VULKAN_1_1:
/* FIXME: Allow KHR_maintenance4. */
return false;
default:
FIXME("Unrecognized environment %#x.\n", environment);
return false;
}
default:
return true;
}
}
static void remove_unread_output_components(const struct shader_signature *signature,
struct vkd3d_shader_instruction *ins, struct vkd3d_shader_dst_param *dst)
{
const struct signature_element *e;
switch (dst->reg.type)
{
case VKD3DSPR_OUTPUT:
e = vsir_signature_find_element_for_reg(signature, dst->reg.idx[0].offset, 0);
break;
case VKD3DSPR_ATTROUT:
e = vsir_signature_find_element_for_reg(signature,
SM1_COLOR_REGISTER_OFFSET + dst->reg.idx[0].offset, 0);
break;
case VKD3DSPR_RASTOUT:
e = vsir_signature_find_element_for_reg(signature,
SM1_RASTOUT_REGISTER_OFFSET + dst->reg.idx[0].offset, 0);
break;
default:
return;
}
/* We already changed the mask earlier. */
dst->write_mask &= e->mask;
if (!dst->write_mask)
{
if (ins->dst_count == 1)
vkd3d_shader_instruction_make_nop(ins);
else
vsir_dst_param_init(dst, VKD3DSPR_NULL, VKD3D_DATA_UNUSED, 0);
}
}
static enum vkd3d_result vsir_program_remap_output_signature(struct vsir_program *program,
struct vsir_transformation_context *ctx)
{
const struct vkd3d_shader_location location = {.source_name = ctx->compile_info->source_name};
struct vkd3d_shader_message_context *message_context = ctx->message_context;
const struct vkd3d_shader_compile_info *compile_info = ctx->compile_info;
bool allows_subset_masks = target_allows_subset_masks(compile_info);
struct shader_signature *signature = &program->output_signature;
const struct vkd3d_shader_varying_map_info *varying_map;
unsigned int subset_varying_count = 0;
unsigned int i;
if (!(varying_map = vkd3d_find_struct(compile_info->next, VARYING_MAP_INFO)))
@ -844,14 +914,21 @@ static enum vkd3d_result vsir_program_remap_output_signature(struct vsir_program
e->target_location = map->input_register_index;
/* It is illegal in Vulkan if the next shader uses the same varying
* location with a different mask. */
if (input_mask && input_mask != e->mask)
if ((input_mask & e->mask) == input_mask)
{
++subset_varying_count;
if (!allows_subset_masks)
{
e->mask = input_mask;
e->used_mask &= input_mask;
}
}
else if (input_mask && input_mask != e->mask)
{
vkd3d_shader_error(message_context, &location, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
"Aborting due to not yet implemented feature: "
"Output mask %#x does not match input mask %#x.",
e->mask, input_mask);
"Input mask %#x reads components not written in output mask %#x.",
input_mask, e->mask);
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
}
@ -872,6 +949,22 @@ static enum vkd3d_result vsir_program_remap_output_signature(struct vsir_program
}
}
/* Vulkan (without KHR_maintenance4) disallows any mismatching masks,
* including when the input mask is a proper subset of the output mask.
* Resolve this by rewriting the shader to remove unread components from
* any writes to the output variable. */
if (!subset_varying_count || allows_subset_masks)
return VKD3D_OK;
for (i = 0; i < program->instructions.count; ++i)
{
struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
for (unsigned int j = 0; j < ins->dst_count; ++j)
remove_unread_output_components(signature, ins, &ins->dst[j]);
}
return VKD3D_OK;
}

View File

@ -85,7 +85,7 @@ float4 main(in apple a) : sv_target
}
[test]
todo(sm<4 | msl) draw quad
todo(msl) draw quad
probe (0, 0) rgba (10.0, 20.0, 30.0, 40.0)
@ -287,7 +287,7 @@ float4 main(in float4 a : TEXCOORD0, in float3 b : TEXCOORD1) : sv_target
}
[test]
todo(sm<4 | msl) draw quad
todo(msl) draw quad
probe (0, 0) rgba (10.0, 11.0, 20.0, 21.0)