vkd3d-shader/ir: Allow controlling the fog source through a parameter.

This commit is contained in:
Elizabeth Figura
2024-11-13 19:16:39 -06:00
committed by Henri Verbeet
parent fc98cb482f
commit 1fbbc82f3a
Notes: Henri Verbeet 2024-12-02 17:19:05 +01:00
Approved-by: Henri Verbeet (@hverbeet)
Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/1265
9 changed files with 351 additions and 1 deletions

View File

@@ -968,6 +968,8 @@ static void shader_sm1_read_dst_param(struct vkd3d_shader_sm1_parser *sm1, const
if (dst_param->reg.type == VKD3DSPR_RASTOUT && dst_param->reg.idx[0].offset == VSIR_RASTOUT_POINT_SIZE)
sm1->p.program->has_point_size = true;
if (dst_param->reg.type == VKD3DSPR_RASTOUT && dst_param->reg.idx[0].offset == VSIR_RASTOUT_FOG)
sm1->p.program->has_fog = true;
}
static void shader_sm1_read_semantic(struct vkd3d_shader_sm1_parser *sm1,

View File

@@ -6907,6 +6907,177 @@ static enum vkd3d_result vsir_program_insert_fragment_fog(struct vsir_program *p
return VKD3D_OK;
}
static enum vkd3d_result vsir_program_add_fog_output(struct vsir_program *program,
struct vsir_transformation_context *ctx)
{
struct shader_signature *signature = &program->output_signature;
const struct vkd3d_shader_parameter1 *source_parameter;
uint32_t register_idx = 0;
if (!is_pre_rasterization_shader(program->shader_version.type))
return VKD3D_OK;
if (!(source_parameter = vsir_program_get_parameter(program, VKD3D_SHADER_PARAMETER_NAME_FOG_SOURCE)))
return VKD3D_OK;
if (source_parameter->type == VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT)
{
enum vkd3d_shader_fog_source source = source_parameter->u.immediate_constant.u.u32;
if (source == VKD3D_SHADER_FOG_SOURCE_FOG)
return VKD3D_OK;
if (source == VKD3D_SHADER_FOG_SOURCE_FOG_OR_SPECULAR_W
&& !vsir_signature_find_element_by_name(signature, "COLOR", 1))
return VKD3D_OK;
}
if (vsir_signature_find_element_by_name(signature, "FOG", 0))
return VKD3D_OK;
for (unsigned int i = 0; i < signature->element_count; ++i)
register_idx = max(register_idx, signature->elements[i].register_index + 1);
if (!add_signature_element(signature, "FOG", 0, VKD3DSP_WRITEMASK_0, register_idx, VKD3DSIM_LINEAR))
return VKD3D_ERROR_OUT_OF_MEMORY;
return VKD3D_OK;
}
static enum vkd3d_result insert_vertex_fog_before_ret(struct vsir_program *program,
const struct vkd3d_shader_instruction *ret, enum vkd3d_shader_fog_source source, uint32_t temp,
uint32_t fog_signature_idx, uint32_t source_signature_idx, size_t *ret_pos)
{
const struct signature_element *e = &program->output_signature.elements[source_signature_idx];
struct vkd3d_shader_instruction_array *instructions = &program->instructions;
size_t pos = ret - instructions->elements;
struct vkd3d_shader_instruction *ins;
if (!shader_instruction_array_insert_at(&program->instructions, pos, 2))
return VKD3D_ERROR_OUT_OF_MEMORY;
ins = &program->instructions.elements[pos];
/* Write the fog output. */
vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_MOV, 1, 1);
dst_param_init_output(&ins->dst[0], VKD3D_DATA_FLOAT, fog_signature_idx, 0x1);
src_param_init_temp_float4(&ins->src[0], temp);
if (source == VKD3D_SHADER_FOG_SOURCE_Z)
ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(Z, Z, Z, Z);
else /* Position or specular W. */
ins->src[0].swizzle = VKD3D_SHADER_SWIZZLE(W, W, W, W);
++ins;
/* Write the position or specular output. */
vsir_instruction_init_with_params(program, ins, &ret->location, VKD3DSIH_MOV, 1, 1);
dst_param_init_output(&ins->dst[0], vkd3d_data_type_from_component_type(e->component_type),
source_signature_idx, e->mask);
src_param_init_temp_float4(&ins->src[0], temp);
++ins;
*ret_pos = pos + 2;
return VKD3D_OK;
}
static enum vkd3d_result vsir_program_insert_vertex_fog(struct vsir_program *program,
struct vsir_transformation_context *ctx)
{
struct vkd3d_shader_message_context *message_context = ctx->message_context;
const struct vkd3d_shader_parameter1 *source_parameter = NULL;
uint32_t fog_signature_idx, source_signature_idx, temp;
static const struct vkd3d_shader_location no_loc;
enum vkd3d_shader_fog_source source;
const struct signature_element *e;
if (!is_pre_rasterization_shader(program->shader_version.type))
return VKD3D_OK;
if (!(source_parameter = vsir_program_get_parameter(program, VKD3D_SHADER_PARAMETER_NAME_FOG_SOURCE)))
return VKD3D_OK;
if (source_parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT)
{
vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
"Unsupported fog source parameter type %#x.", source_parameter->type);
return VKD3D_ERROR_NOT_IMPLEMENTED;
}
if (source_parameter->data_type != VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32)
{
vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_INVALID_DATA_TYPE,
"Invalid fog source parameter data type %#x.", source_parameter->data_type);
return VKD3D_ERROR_INVALID_ARGUMENT;
}
source = source_parameter->u.immediate_constant.u.u32;
TRACE("Fog source %#x.\n", source);
if (source == VKD3D_SHADER_FOG_SOURCE_FOG)
return VKD3D_OK;
if (source == VKD3D_SHADER_FOG_SOURCE_FOG_OR_SPECULAR_W)
{
if (program->has_fog || !(e = vsir_signature_find_element_by_name(&program->output_signature, "COLOR", 1)))
return VKD3D_OK;
source_signature_idx = e - program->output_signature.elements;
}
else
{
if (!vsir_signature_find_sysval(&program->output_signature,
VKD3D_SHADER_SV_POSITION, 0, &source_signature_idx))
{
vkd3d_shader_error(ctx->message_context, &no_loc,
VKD3D_SHADER_ERROR_VSIR_MISSING_SEMANTIC, "Shader does not write position.");
return VKD3D_ERROR_INVALID_SHADER;
}
}
if (!(e = vsir_signature_find_element_by_name(&program->output_signature, "FOG", 0)))
{
ERR("Fog output not found.\n");
return VKD3D_ERROR_INVALID_SHADER;
}
fog_signature_idx = e - program->output_signature.elements;
temp = program->temp_count++;
/* Insert a fog write before each ret, and convert either specular or
* position output to a temp. */
for (size_t i = 0; i < program->instructions.count; ++i)
{
struct vkd3d_shader_instruction *ins = &program->instructions.elements[i];
if (vsir_instruction_is_dcl(ins))
continue;
if (ins->opcode == VKD3DSIH_RET)
{
size_t new_pos;
int ret;
if ((ret = insert_vertex_fog_before_ret(program, ins, source, temp,
fog_signature_idx, source_signature_idx, &new_pos)) < 0)
return ret;
i = new_pos;
continue;
}
for (size_t j = 0; j < ins->dst_count; ++j)
{
struct vkd3d_shader_dst_param *dst = &ins->dst[j];
/* Note we run after I/O normalization. */
if (dst->reg.type == VKD3DSPR_OUTPUT && dst->reg.idx[0].offset == source_signature_idx)
{
dst->reg.type = VKD3DSPR_TEMP;
dst->reg.idx[0].offset = temp;
}
}
}
program->has_fog = true;
return VKD3D_OK;
}
struct validation_context
{
struct vkd3d_shader_message_context *message_context;
@@ -8994,6 +9165,9 @@ enum vkd3d_result vsir_program_transform_early(struct vsir_program *program, uin
/* For vsir_program_insert_fragment_fog(). */
vsir_transform(&ctx, vsir_program_add_fog_input);
/* For vsir_program_insert_vertex_fog(). */
vsir_transform(&ctx, vsir_program_add_fog_output);
return ctx.result;
}
@@ -9049,6 +9223,7 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t
vsir_transform(&ctx, vsir_program_insert_point_size_clamp);
vsir_transform(&ctx, vsir_program_insert_point_coord);
vsir_transform(&ctx, vsir_program_insert_fragment_fog);
vsir_transform(&ctx, vsir_program_insert_vertex_fog);
if (TRACE_ON())
vsir_program_trace(program);

View File

@@ -1428,6 +1428,7 @@ struct vsir_program
bool use_vocp;
bool has_point_size;
bool has_point_coord;
bool has_fog;
uint8_t diffuse_written_mask;
enum vsir_control_flow_type cf_type;
enum vsir_normalisation_level normalisation_level;