mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-12-15 08:03:30 -08:00
vkd3d-shader/ir: Allow controlling fog through parameters.
Fog requires several parameters to even implement the most basic of functionality correctly, so this commit is relatively large.
This commit is contained in:
committed by
Henri Verbeet
parent
a1de406de4
commit
f86d1e72a4
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
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2023 Conor McCarthy for CodeWeavers
|
||||
* Copyright 2023-2024 Elizabeth Figura for CodeWeavers
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@@ -222,6 +223,14 @@ static void src_param_init_parameter(struct vkd3d_shader_src_param *src, uint32_
|
||||
src->reg.idx[0].offset = idx;
|
||||
}
|
||||
|
||||
static void src_param_init_parameter_vec4(struct vkd3d_shader_src_param *src, uint32_t idx, enum vkd3d_data_type type)
|
||||
{
|
||||
vsir_src_param_init(src, VKD3DSPR_PARAMETER, type, 1);
|
||||
src->reg.idx[0].offset = idx;
|
||||
src->reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
src->swizzle = VKD3D_SHADER_NO_SWIZZLE;
|
||||
}
|
||||
|
||||
static void vsir_src_param_init_resource(struct vkd3d_shader_src_param *src, unsigned int id, unsigned int idx)
|
||||
{
|
||||
vsir_src_param_init(src, VKD3DSPR_RESOURCE, VKD3D_DATA_UNUSED, 2);
|
||||
@@ -251,6 +260,14 @@ static void src_param_init_ssa_float(struct vkd3d_shader_src_param *src, unsigne
|
||||
src->reg.idx[0].offset = idx;
|
||||
}
|
||||
|
||||
static void src_param_init_ssa_float4(struct vkd3d_shader_src_param *src, unsigned int idx)
|
||||
{
|
||||
vsir_src_param_init(src, VKD3DSPR_SSA, VKD3D_DATA_FLOAT, 1);
|
||||
src->reg.idx[0].offset = idx;
|
||||
src->reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
src->swizzle = VKD3D_SHADER_NO_SWIZZLE;
|
||||
}
|
||||
|
||||
static void src_param_init_temp_bool(struct vkd3d_shader_src_param *src, unsigned int idx)
|
||||
{
|
||||
vsir_src_param_init(src, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
|
||||
@@ -306,6 +323,14 @@ static void dst_param_init_ssa_float(struct vkd3d_shader_dst_param *dst, unsigne
|
||||
dst->reg.idx[0].offset = idx;
|
||||
}
|
||||
|
||||
static void dst_param_init_ssa_float4(struct vkd3d_shader_dst_param *dst, unsigned int idx)
|
||||
{
|
||||
vsir_dst_param_init(dst, VKD3DSPR_SSA, VKD3D_DATA_FLOAT, 1);
|
||||
dst->reg.idx[0].offset = idx;
|
||||
dst->reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
dst->write_mask = VKD3DSP_WRITEMASK_ALL;
|
||||
}
|
||||
|
||||
static void dst_param_init_temp_bool(struct vkd3d_shader_dst_param *dst, unsigned int idx)
|
||||
{
|
||||
vsir_dst_param_init(dst, VKD3DSPR_TEMP, VKD3D_DATA_BOOL, 1);
|
||||
@@ -864,11 +889,36 @@ static enum vkd3d_result vsir_program_ensure_ret(struct vsir_program *program,
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
static bool add_signature_element(struct shader_signature *signature, const char *semantic_name,
|
||||
uint32_t semantic_index, uint32_t mask, uint32_t register_index,
|
||||
enum vkd3d_shader_interpolation_mode interpolation_mode)
|
||||
{
|
||||
struct signature_element *new_elements, *e;
|
||||
|
||||
if (!(new_elements = vkd3d_realloc(signature->elements,
|
||||
(signature->element_count + 1) * sizeof(*signature->elements))))
|
||||
return false;
|
||||
signature->elements = new_elements;
|
||||
e = &signature->elements[signature->element_count++];
|
||||
memset(e, 0, sizeof(*e));
|
||||
e->semantic_name = vkd3d_strdup(semantic_name);
|
||||
e->semantic_index = semantic_index;
|
||||
e->sysval_semantic = VKD3D_SHADER_SV_NONE;
|
||||
e->component_type = VKD3D_SHADER_COMPONENT_FLOAT;
|
||||
e->register_count = 1;
|
||||
e->mask = mask;
|
||||
e->used_mask = mask;
|
||||
e->register_index = register_index;
|
||||
e->target_location = register_index;
|
||||
e->interpolation_mode = interpolation_mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum vkd3d_result vsir_program_add_diffuse_output(struct vsir_program *program,
|
||||
struct vsir_transformation_context *ctx)
|
||||
{
|
||||
struct shader_signature *signature = &program->output_signature;
|
||||
struct signature_element *new_elements, *e;
|
||||
struct signature_element *e;
|
||||
|
||||
if (program->shader_version.type != VKD3D_SHADER_TYPE_VERTEX)
|
||||
return VKD3D_OK;
|
||||
@@ -881,22 +931,8 @@ static enum vkd3d_result vsir_program_add_diffuse_output(struct vsir_program *pr
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
if (!(new_elements = vkd3d_realloc(signature->elements,
|
||||
(signature->element_count + 1) * sizeof(*signature->elements))))
|
||||
if (!add_signature_element(signature, "COLOR", 0, VKD3DSP_WRITEMASK_ALL, SM1_COLOR_REGISTER_OFFSET, VKD3DSIM_NONE))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
signature->elements = new_elements;
|
||||
e = &signature->elements[signature->element_count++];
|
||||
memset(e, 0, sizeof(*e));
|
||||
e->semantic_name = vkd3d_strdup("COLOR");
|
||||
e->sysval_semantic = VKD3D_SHADER_SV_NONE;
|
||||
e->component_type = VKD3D_SHADER_COMPONENT_FLOAT;
|
||||
e->register_count = 1;
|
||||
e->mask = VKD3DSP_WRITEMASK_ALL;
|
||||
e->used_mask = VKD3DSP_WRITEMASK_ALL;
|
||||
e->register_index = SM1_COLOR_REGISTER_OFFSET;
|
||||
e->target_location = SM1_COLOR_REGISTER_OFFSET;
|
||||
e->interpolation_mode = VKD3DSIM_NONE;
|
||||
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
@@ -6685,6 +6721,187 @@ static enum vkd3d_result vsir_program_insert_point_coord(struct vsir_program *pr
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
static enum vkd3d_result vsir_program_add_fog_input(struct vsir_program *program,
|
||||
struct vsir_transformation_context *ctx)
|
||||
{
|
||||
struct shader_signature *signature = &program->input_signature;
|
||||
uint32_t register_idx = 0;
|
||||
|
||||
if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL)
|
||||
return VKD3D_OK;
|
||||
|
||||
if (!vsir_program_get_parameter(program, VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE))
|
||||
return VKD3D_OK;
|
||||
|
||||
/* We could check the value and skip this if NONE, but chances are if a
|
||||
* user specifies the fog fragment mode as a parameter, they'll want to
|
||||
* enable it dynamically. Always specifying it (and hence always outputting
|
||||
* it from the VS) avoids an extra VS variant. */
|
||||
|
||||
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_fragment_fog_before_ret(struct vsir_program *program,
|
||||
const struct vkd3d_shader_instruction *ret, enum vkd3d_shader_fog_fragment_mode mode,
|
||||
uint32_t fog_signature_idx, uint32_t colour_signature_idx, uint32_t colour_temp,
|
||||
size_t *ret_pos, struct vkd3d_shader_message_context *message_context)
|
||||
{
|
||||
struct vkd3d_shader_instruction_array *instructions = &program->instructions;
|
||||
struct vkd3d_shader_location loc = ret->location;
|
||||
uint32_t ssa_factor = program->ssa_count++;
|
||||
size_t pos = ret - instructions->elements;
|
||||
struct vkd3d_shader_instruction *ins;
|
||||
uint32_t ssa_temp;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case VKD3D_SHADER_FOG_FRAGMENT_LINEAR:
|
||||
/* We generate the following code:
|
||||
*
|
||||
* add sr0, FOG_END, -vFOG.x
|
||||
* mul_sat srFACTOR, sr0, FOG_SCALE
|
||||
*/
|
||||
if (!shader_instruction_array_insert_at(&program->instructions, pos, 4))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
*ret_pos = pos + 4;
|
||||
|
||||
ssa_temp = program->ssa_count++;
|
||||
|
||||
ins = &program->instructions.elements[pos];
|
||||
|
||||
vsir_instruction_init_with_params(program, ins, &loc, VKD3DSIH_ADD, 1, 2);
|
||||
dst_param_init_ssa_float(&ins->dst[0], ssa_temp);
|
||||
src_param_init_parameter(&ins->src[0], VKD3D_SHADER_PARAMETER_NAME_FOG_END, VKD3D_DATA_FLOAT);
|
||||
vsir_src_param_init(&ins->src[1], VKD3DSPR_INPUT, VKD3D_DATA_FLOAT, 1);
|
||||
ins->src[1].reg.idx[0].offset = fog_signature_idx;
|
||||
ins->src[1].reg.dimension = VSIR_DIMENSION_VEC4;
|
||||
ins->src[1].swizzle = VKD3D_SHADER_SWIZZLE(X, X, X, X);
|
||||
ins->src[1].modifiers = VKD3DSPSM_NEG;
|
||||
|
||||
vsir_instruction_init_with_params(program, ++ins, &loc, VKD3DSIH_MUL, 1, 2);
|
||||
dst_param_init_ssa_float(&ins->dst[0], ssa_factor);
|
||||
ins->dst[0].modifiers = VKD3DSPDM_SATURATE;
|
||||
src_param_init_ssa_float(&ins->src[0], ssa_temp);
|
||||
src_param_init_parameter(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, VKD3D_DATA_FLOAT);
|
||||
break;
|
||||
|
||||
default:
|
||||
vkd3d_unreachable();
|
||||
}
|
||||
|
||||
/* We generate the following code:
|
||||
*
|
||||
* add sr0, FRAG_COLOUR, -FOG_COLOUR
|
||||
* mad oC0, sr0, srFACTOR, FOG_COLOUR
|
||||
*/
|
||||
|
||||
vsir_instruction_init_with_params(program, ++ins, &loc, VKD3DSIH_ADD, 1, 2);
|
||||
dst_param_init_ssa_float4(&ins->dst[0], program->ssa_count++);
|
||||
src_param_init_temp_float4(&ins->src[0], colour_temp);
|
||||
src_param_init_parameter_vec4(&ins->src[1], VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR, VKD3D_DATA_FLOAT);
|
||||
ins->src[1].modifiers = VKD3DSPSM_NEG;
|
||||
|
||||
vsir_instruction_init_with_params(program, ++ins, &loc, VKD3DSIH_MAD, 1, 3);
|
||||
dst_param_init_output(&ins->dst[0], VKD3D_DATA_FLOAT, colour_signature_idx,
|
||||
program->output_signature.elements[colour_signature_idx].mask);
|
||||
src_param_init_ssa_float4(&ins->src[0], program->ssa_count - 1);
|
||||
src_param_init_ssa_float(&ins->src[1], ssa_factor);
|
||||
src_param_init_parameter_vec4(&ins->src[2], VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR, VKD3D_DATA_FLOAT);
|
||||
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
static enum vkd3d_result vsir_program_insert_fragment_fog(struct vsir_program *program,
|
||||
struct vsir_transformation_context *ctx)
|
||||
{
|
||||
struct vkd3d_shader_message_context *message_context = ctx->message_context;
|
||||
uint32_t colour_signature_idx, fog_signature_idx, colour_temp;
|
||||
const struct vkd3d_shader_parameter1 *mode_parameter = NULL;
|
||||
static const struct vkd3d_shader_location no_loc;
|
||||
const struct signature_element *fog_element;
|
||||
enum vkd3d_shader_fog_fragment_mode mode;
|
||||
struct vkd3d_shader_instruction *ins;
|
||||
size_t new_pos;
|
||||
int ret;
|
||||
|
||||
if (program->shader_version.type != VKD3D_SHADER_TYPE_PIXEL)
|
||||
return VKD3D_OK;
|
||||
|
||||
if (!vsir_signature_find_sysval(&program->output_signature, VKD3D_SHADER_SV_TARGET, 0, &colour_signature_idx))
|
||||
return VKD3D_OK;
|
||||
|
||||
if (!(mode_parameter = vsir_program_get_parameter(program, VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE)))
|
||||
return VKD3D_OK;
|
||||
|
||||
if (mode_parameter->type != VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT)
|
||||
{
|
||||
vkd3d_shader_error(message_context, &no_loc, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
|
||||
"Unsupported fog fragment mode parameter type %#x.", mode_parameter->type);
|
||||
return VKD3D_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (mode_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 fragment mode parameter data type %#x.", mode_parameter->data_type);
|
||||
return VKD3D_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
mode = mode_parameter->u.immediate_constant.u.u32;
|
||||
|
||||
if (mode == VKD3D_SHADER_FOG_FRAGMENT_NONE)
|
||||
return VKD3D_OK;
|
||||
|
||||
/* Should have been added by vsir_program_add_fog_input(). */
|
||||
if (!(fog_element = vsir_signature_find_element_by_name(&program->input_signature, "FOG", 0)))
|
||||
{
|
||||
ERR("Fog input not found.\n");
|
||||
return VKD3D_ERROR_INVALID_SHADER;
|
||||
}
|
||||
fog_signature_idx = fog_element - program->input_signature.elements;
|
||||
|
||||
/* We're going to be reading from the output, so we need to go
|
||||
* through the whole shader and convert it to a temp. */
|
||||
colour_temp = program->temp_count++;
|
||||
|
||||
for (size_t i = 0; i < program->instructions.count; ++i)
|
||||
{
|
||||
ins = &program->instructions.elements[i];
|
||||
|
||||
if (vsir_instruction_is_dcl(ins))
|
||||
continue;
|
||||
|
||||
if (ins->opcode == VKD3DSIH_RET)
|
||||
{
|
||||
if ((ret = insert_fragment_fog_before_ret(program, ins, mode, fog_signature_idx,
|
||||
colour_signature_idx, colour_temp, &new_pos, message_context)) < 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 == colour_signature_idx)
|
||||
{
|
||||
dst->reg.type = VKD3DSPR_TEMP;
|
||||
dst->reg.idx[0].offset = colour_temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
struct validation_context
|
||||
{
|
||||
struct vkd3d_shader_message_context *message_context;
|
||||
@@ -8769,6 +8986,9 @@ enum vkd3d_result vsir_program_transform_early(struct vsir_program *program, uin
|
||||
if (program->shader_version.major <= 2)
|
||||
vsir_transform(&ctx, vsir_program_add_diffuse_output);
|
||||
|
||||
/* For vsir_program_insert_fragment_fog(). */
|
||||
vsir_transform(&ctx, vsir_program_add_fog_input);
|
||||
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
@@ -8823,6 +9043,7 @@ enum vkd3d_result vsir_program_transform(struct vsir_program *program, uint64_t
|
||||
vsir_transform(&ctx, vsir_program_insert_point_size);
|
||||
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);
|
||||
|
||||
if (TRACE_ON())
|
||||
vsir_program_trace(program);
|
||||
|
||||
@@ -3316,13 +3316,19 @@ static uint32_t spirv_compiler_emit_variable(struct spirv_compiler *compiler,
|
||||
static const struct vkd3d_spec_constant_info
|
||||
{
|
||||
enum vkd3d_shader_parameter_name name;
|
||||
uint32_t default_value;
|
||||
union
|
||||
{
|
||||
uint32_t u;
|
||||
float f;
|
||||
} default_value;
|
||||
const char *debug_name;
|
||||
}
|
||||
vkd3d_shader_parameters[] =
|
||||
{
|
||||
{VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, 1, "sample_count"},
|
||||
{VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, 0, "alpha_test_ref"},
|
||||
{VKD3D_SHADER_PARAMETER_NAME_RASTERIZER_SAMPLE_COUNT, {.u = 1}, "sample_count"},
|
||||
{VKD3D_SHADER_PARAMETER_NAME_ALPHA_TEST_REF, {.f = 0.0f}, "alpha_test_ref"},
|
||||
{VKD3D_SHADER_PARAMETER_NAME_FOG_END, {.f = 1.0f}, "fog_end"},
|
||||
{VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE, {.f = 1.0f}, "fog_scale"},
|
||||
};
|
||||
|
||||
static const struct vkd3d_spec_constant_info *get_spec_constant_info(enum vkd3d_shader_parameter_name name)
|
||||
@@ -3383,7 +3389,7 @@ static uint32_t spirv_compiler_emit_spec_constant(struct spirv_compiler *compile
|
||||
const struct vkd3d_spec_constant_info *info;
|
||||
|
||||
info = get_spec_constant_info(name);
|
||||
default_value = info ? info->default_value : 0;
|
||||
default_value = info ? info->default_value.u : 0;
|
||||
|
||||
scalar_type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), 1);
|
||||
vector_type_id = vkd3d_spirv_get_type_id(builder, vkd3d_component_type_from_data_type(type), component_count);
|
||||
|
||||
Reference in New Issue
Block a user