mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-01-28 13:05:02 -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:
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
@ -476,6 +476,45 @@ enum vkd3d_shader_binding_flag
|
||||
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_BINDING_FLAG),
|
||||
};
|
||||
|
||||
/**
|
||||
* The factor used to interpolate the fragment output colour with fog.
|
||||
*
|
||||
* See VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE for specification of the
|
||||
* interpolation factor as defined here.
|
||||
*
|
||||
* The following variables may be used to determine the interpolation factor:
|
||||
*
|
||||
* c = The fog coordinate value output from the vertex shader. This is an
|
||||
* inter-stage varying with the semantic name "FOG" and semantic index 0.
|
||||
* E = The value of VKD3D_SHADER_PARAMETER_NAME_FOG_END.
|
||||
* k = The value of VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE.
|
||||
*
|
||||
* \since 1.15
|
||||
*/
|
||||
enum vkd3d_shader_fog_fragment_mode
|
||||
{
|
||||
/**
|
||||
* No fog interpolation is applied;
|
||||
* the output colour is passed through unmodified.
|
||||
* Equivalently, the fog interpolation factor is 1.
|
||||
*/
|
||||
VKD3D_SHADER_FOG_FRAGMENT_NONE = 0x0,
|
||||
/**
|
||||
* The fog interpolation factor is (E - c) * k.
|
||||
*
|
||||
* In order to implement traditional linear fog, as present in Direct3D and
|
||||
* OpenGL, i.e.
|
||||
*
|
||||
* (end - c) / (end - start)
|
||||
*
|
||||
* set
|
||||
*
|
||||
* E = end
|
||||
* k = 1 / (end - start)
|
||||
*/
|
||||
VKD3D_SHADER_FOG_FRAGMENT_LINEAR = 0x3,
|
||||
};
|
||||
|
||||
/**
|
||||
* The manner in which a parameter value is provided to the shader, used in
|
||||
* struct vkd3d_shader_parameter and struct vkd3d_shader_parameter1.
|
||||
@ -739,6 +778,73 @@ enum vkd3d_shader_parameter_name
|
||||
* \since 1.14
|
||||
*/
|
||||
VKD3D_SHADER_PARAMETER_NAME_POINT_SPRITE,
|
||||
/**
|
||||
* Fog mode used in fragment shaders.
|
||||
*
|
||||
* The value specified by this parameter must be a member of
|
||||
* enum vkd3d_shader_fog_fragment_mode.
|
||||
*
|
||||
* If not VKD3D_SHADER_FOG_FRAGMENT_NONE, the pixel shader colour output at
|
||||
* location 0 is linearly interpolated with the fog colour defined by
|
||||
* VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR. The interpolation factor is
|
||||
* defined according to the enumerant selected by this parameter.
|
||||
* The interpolated value is then outputted instead of the original value at
|
||||
* location 0.
|
||||
*
|
||||
* An interpolation factor of 0 specifies to use the fog colour; a factor of
|
||||
* 1 specifies to use the original colour output. The interpolation factor
|
||||
* is clamped to the [0, 1] range before interpolating.
|
||||
*
|
||||
* The default value is VKD3D_SHADER_FOG_FRAGMENT_NONE.
|
||||
*
|
||||
* The data type for this parameter must be
|
||||
* VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32.
|
||||
*
|
||||
* Only VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT is supported in this
|
||||
* version of vkd3d-shader.
|
||||
*
|
||||
* \since 1.15
|
||||
*/
|
||||
VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE,
|
||||
/**
|
||||
* Fog colour.
|
||||
* See VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE for documentation of
|
||||
* fog.
|
||||
*
|
||||
* The data type for this parameter must be
|
||||
* VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4.
|
||||
*
|
||||
* The default value is transparent black, i.e. the vector {0, 0, 0, 0}.
|
||||
*
|
||||
* \since 1.15
|
||||
*/
|
||||
VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR,
|
||||
/**
|
||||
* End coordinate for linear fog.
|
||||
* See VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE for documentation of
|
||||
* fog.
|
||||
*
|
||||
* The data type for this parameter must be
|
||||
* VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32.
|
||||
*
|
||||
* The default value is 1.0.
|
||||
*
|
||||
* \since 1.15
|
||||
*/
|
||||
VKD3D_SHADER_PARAMETER_NAME_FOG_END,
|
||||
/**
|
||||
* Scale value for linear fog.
|
||||
* See VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE for documentation of
|
||||
* fog.
|
||||
*
|
||||
* The data type for this parameter must be
|
||||
* VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32.
|
||||
*
|
||||
* The default value is 1.0.
|
||||
*
|
||||
* \since 1.15
|
||||
*/
|
||||
VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE,
|
||||
|
||||
VKD3D_FORCE_32_BIT_ENUM(VKD3D_SHADER_PARAMETER_NAME),
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -27,3 +27,46 @@ float4 main(float2 fog : fog) : sv_target
|
||||
[test]
|
||||
todo(msl) draw quad
|
||||
probe (0, 0) rgba (0.1, 0.2, 0, 1)
|
||||
|
||||
|
||||
[require]
|
||||
fog
|
||||
|
||||
[input layout]
|
||||
0 r32g32b32a32-float position
|
||||
|
||||
[vb 0]
|
||||
-1.0 -1.0 0.2 1.0
|
||||
-1.0 1.0 0.2 1.0
|
||||
1.0 -1.0 0.6 1.0
|
||||
1.0 1.0 0.6 1.0
|
||||
|
||||
[vertex shader]
|
||||
float4 main(float4 pos : position, out float fog : fog) : sv_position
|
||||
{
|
||||
fog = 0.2;
|
||||
return pos;
|
||||
}
|
||||
|
||||
[pixel shader]
|
||||
float4 main() : sv_target
|
||||
{
|
||||
return float4(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
[test]
|
||||
fog-colour 0.0 1.0 1.0 1.0
|
||||
|
||||
fog disable
|
||||
draw triangle strip 4
|
||||
probe (160, 120) rgba (0.0, 0.0, 1.0, 1.0)
|
||||
probe (480, 360) rgba (0.0, 0.0, 1.0, 1.0)
|
||||
probe (160, 120) rgba (0.0, 0.0, 1.0, 1.0)
|
||||
probe (480, 360) rgba (0.0, 0.0, 1.0, 1.0)
|
||||
|
||||
fog none
|
||||
draw triangle strip 4
|
||||
probe (160, 120) rgba (0.0, 0.8, 1.0, 1.0)
|
||||
probe (480, 360) rgba (0.0, 0.8, 1.0, 1.0)
|
||||
probe (160, 120) rgba (0.0, 0.8, 1.0, 1.0)
|
||||
probe (480, 360) rgba (0.0, 0.8, 1.0, 1.0)
|
||||
|
@ -335,6 +335,7 @@ static const char *const shader_cap_strings[] =
|
||||
[SHADER_CAP_CLIP_PLANES] = "clip-planes",
|
||||
[SHADER_CAP_DEPTH_BOUNDS] = "depth-bounds",
|
||||
[SHADER_CAP_FLOAT64] = "float64",
|
||||
[SHADER_CAP_FOG] = "fog",
|
||||
[SHADER_CAP_GEOMETRY_SHADER] = "geometry-shader",
|
||||
[SHADER_CAP_INT64] = "int64",
|
||||
[SHADER_CAP_POINT_SIZE] = "point-size",
|
||||
@ -1424,6 +1425,28 @@ static void parse_test_directive(struct shader_runner *runner, const char *line)
|
||||
else
|
||||
runner->point_sprite = false;
|
||||
}
|
||||
else if (match_string(line, "fog", &line))
|
||||
{
|
||||
if (match_string(line, "disable", &line))
|
||||
runner->fog_mode = FOG_MODE_DISABLE;
|
||||
else if (match_string(line, "none", &line))
|
||||
runner->fog_mode = FOG_MODE_NONE;
|
||||
else if (match_string(line, "linear", &line))
|
||||
runner->fog_mode = FOG_MODE_LINEAR;
|
||||
else if (match_string(line, "exp", &line))
|
||||
runner->fog_mode = FOG_MODE_EXP;
|
||||
else if (match_string(line, "exp2", &line))
|
||||
runner->fog_mode = FOG_MODE_EXP2;
|
||||
else
|
||||
fatal_error("Invalid fog mode '%s'.\n", line);
|
||||
}
|
||||
else if (match_string(line, "fog-colour", &line))
|
||||
{
|
||||
struct vec4 *v = &runner->fog_colour;
|
||||
|
||||
if (sscanf(line, "%f %f %f %f", &v->x, &v->y, &v->z, &v->w) < 4)
|
||||
fatal_error("Malformed float4 constant '%s'.\n", line);
|
||||
}
|
||||
else
|
||||
{
|
||||
fatal_error("Unknown test directive '%s'.\n", line);
|
||||
@ -1872,6 +1895,7 @@ void run_shader_tests(struct shader_runner *runner, const struct shader_runner_c
|
||||
runner->point_size = 1.0f;
|
||||
runner->point_size_min = 1.0f;
|
||||
runner->point_size_max = FLT_MAX;
|
||||
runner->fog_mode = FOG_MODE_DISABLE;
|
||||
|
||||
runner->sample_mask = ~0u;
|
||||
runner->depth_bounds = false;
|
||||
|
@ -141,6 +141,7 @@ enum shader_cap
|
||||
SHADER_CAP_CLIP_PLANES,
|
||||
SHADER_CAP_DEPTH_BOUNDS,
|
||||
SHADER_CAP_FLOAT64,
|
||||
SHADER_CAP_FOG,
|
||||
SHADER_CAP_GEOMETRY_SHADER,
|
||||
SHADER_CAP_INT64,
|
||||
SHADER_CAP_POINT_SIZE,
|
||||
@ -173,6 +174,15 @@ static inline unsigned int shader_runner_caps_get_feature_flags(const struct sha
|
||||
return flags;
|
||||
}
|
||||
|
||||
enum fog_mode
|
||||
{
|
||||
FOG_MODE_NONE = 0,
|
||||
FOG_MODE_EXP = 1,
|
||||
FOG_MODE_EXP2 = 2,
|
||||
FOG_MODE_LINEAR = 3,
|
||||
FOG_MODE_DISABLE,
|
||||
};
|
||||
|
||||
struct shader_runner
|
||||
{
|
||||
const struct shader_runner_ops *ops;
|
||||
@ -222,6 +232,8 @@ struct shader_runner
|
||||
struct vec4 clip_planes[8];
|
||||
float point_size, point_size_min, point_size_max;
|
||||
bool point_sprite;
|
||||
struct vec4 fog_colour;
|
||||
enum fog_mode fog_mode;
|
||||
};
|
||||
|
||||
struct shader_runner_ops
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 Zebediah Figura for CodeWeavers
|
||||
* Copyright 2021-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
|
||||
@ -145,6 +145,7 @@ static bool init_test_context(struct d3d9_shader_runner *runner)
|
||||
runner->caps.minimum_shader_model = SHADER_MODEL_2_0;
|
||||
runner->caps.maximum_shader_model = SHADER_MODEL_3_0;
|
||||
runner->caps.shader_caps[SHADER_CAP_CLIP_PLANES] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_FOG] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_POINT_SIZE] = true;
|
||||
|
||||
return true;
|
||||
@ -325,16 +326,19 @@ static bool d3d9_runner_dispatch(struct shader_runner *r, unsigned int x, unsign
|
||||
fatal_error("Compute shaders are not supported.\n");
|
||||
}
|
||||
|
||||
static uint32_t d3d_color_from_vec4(const struct vec4 *v)
|
||||
{
|
||||
return vkd3d_make_u32(vkd3d_make_u16(v->z * 255.0f, v->y * 255.0f),
|
||||
vkd3d_make_u16(v->x * 255.0f, v->w * 255.0f));
|
||||
}
|
||||
|
||||
static void d3d9_runner_clear(struct shader_runner *r, struct resource *resource, const struct vec4 *clear_value)
|
||||
{
|
||||
struct d3d9_shader_runner *runner = d3d9_shader_runner(r);
|
||||
unsigned int colour;
|
||||
HRESULT hr;
|
||||
|
||||
colour = vkd3d_make_u32(vkd3d_make_u16(clear_value->z * 255.0, clear_value->y * 255.0),
|
||||
vkd3d_make_u16(clear_value->x * 255.0, clear_value->w * 255.0));
|
||||
|
||||
hr = IDirect3DDevice9_ColorFill(runner->device, d3d9_resource(resource)->surface, NULL, colour);
|
||||
hr = IDirect3DDevice9_ColorFill(runner->device, d3d9_resource(resource)->surface,
|
||||
NULL, d3d_color_from_vec4(clear_value));
|
||||
ok(hr == S_OK, "Got hr %#lx.\n", hr);
|
||||
}
|
||||
|
||||
@ -498,6 +502,16 @@ static bool d3d9_runner_draw(struct shader_runner *r,
|
||||
hr = IDirect3DDevice9_SetRenderState(device, D3DRS_POINTSPRITEENABLE, runner->r.point_sprite);
|
||||
ok(hr == D3D_OK, "Failed to set render state, hr %#lx.\n", hr);
|
||||
|
||||
hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGENABLE, (runner->r.fog_mode != FOG_MODE_DISABLE));
|
||||
ok(hr == D3D_OK, "Failed to set render state, hr %#lx.\n", hr);
|
||||
if (runner->r.fog_mode != FOG_MODE_DISABLE)
|
||||
{
|
||||
hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGTABLEMODE, runner->r.fog_mode);
|
||||
ok(hr == D3D_OK, "Failed to set render state, hr %#lx.\n", hr);
|
||||
}
|
||||
hr = IDirect3DDevice9_SetRenderState(device, D3DRS_FOGCOLOR, d3d_color_from_vec4(&runner->r.fog_colour));
|
||||
ok(hr == D3D_OK, "Failed to set render state, hr %#lx.\n", hr);
|
||||
|
||||
hr = IDirect3DDevice9_CreateVertexDeclaration(device, decl_elements, &vertex_declaration);
|
||||
ok(hr == D3D_OK, "Failed to create vertex declaration, hr %#lx.\n", hr);
|
||||
hr = IDirect3DDevice9_CreateVertexShader(device, ID3D10Blob_GetBufferPointer(vs_code), &vs);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Shader runner which uses libvkd3d-shader to compile HLSL -> D3D bytecode -> SPIR-V
|
||||
*
|
||||
* Copyright 2020-2022 Zebediah Figura for CodeWeavers
|
||||
* Copyright 2020-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
|
||||
@ -267,15 +267,27 @@ static void vulkan_runner_destroy_resource(struct shader_runner *r, struct resou
|
||||
free(resource);
|
||||
}
|
||||
|
||||
static enum vkd3d_shader_fog_fragment_mode get_fog_fragment_mode(enum fog_mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case FOG_MODE_DISABLE: return VKD3D_SHADER_FOG_FRAGMENT_NONE;
|
||||
case FOG_MODE_NONE: return VKD3D_SHADER_FOG_FRAGMENT_LINEAR;
|
||||
default: fatal_error("Unhandled fog mode %#x.\n", mode);
|
||||
}
|
||||
}
|
||||
|
||||
static bool compile_hlsl_and_scan(struct vulkan_shader_runner *runner, enum shader_type type)
|
||||
{
|
||||
struct vkd3d_shader_parameter_info parameter_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_PARAMETER_INFO};
|
||||
struct vkd3d_shader_compile_info info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO};
|
||||
struct vkd3d_shader_parameter1 parameters[1];
|
||||
enum vkd3d_result ret;
|
||||
|
||||
if (!(runner->d3d_blobs[type] = compile_hlsl(&runner->r, type)))
|
||||
return false;
|
||||
|
||||
info.next = &runner->signatures[type];
|
||||
info.next = ¶meter_info;
|
||||
info.source.code = ID3D10Blob_GetBufferPointer(runner->d3d_blobs[type]);
|
||||
info.source.size = ID3D10Blob_GetBufferSize(runner->d3d_blobs[type]);
|
||||
if (runner->r.minimum_shader_model < SHADER_MODEL_4_0)
|
||||
@ -284,6 +296,15 @@ static bool compile_hlsl_and_scan(struct vulkan_shader_runner *runner, enum shad
|
||||
info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF;
|
||||
info.target_type = VKD3D_SHADER_TARGET_SPIRV_BINARY;
|
||||
|
||||
parameter_info.next = &runner->signatures[type];
|
||||
parameter_info.parameter_count = ARRAY_SIZE(parameters);
|
||||
parameter_info.parameters = parameters;
|
||||
|
||||
parameters[0].name = VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE;
|
||||
parameters[0].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT;
|
||||
parameters[0].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32;
|
||||
parameters[0].u.immediate_constant.u.u32 = get_fog_fragment_mode(runner->r.fog_mode);
|
||||
|
||||
runner->signatures[type].type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO;
|
||||
runner->signatures[type].next = NULL;
|
||||
ret = vkd3d_shader_scan(&info, NULL);
|
||||
@ -306,7 +327,7 @@ static bool compile_d3d_code(struct vulkan_shader_runner *runner,
|
||||
struct vkd3d_shader_varying_map varying_map[12];
|
||||
struct vkd3d_shader_resource_binding *binding;
|
||||
struct vkd3d_shader_compile_option options[2];
|
||||
struct vkd3d_shader_parameter1 parameters[17];
|
||||
struct vkd3d_shader_parameter1 parameters[21];
|
||||
unsigned int i;
|
||||
char *messages;
|
||||
int ret;
|
||||
@ -460,6 +481,30 @@ static bool compile_d3d_code(struct vulkan_shader_runner *runner,
|
||||
parameters[16].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32;
|
||||
parameters[16].u.immediate_constant.u.u32 = runner->r.point_sprite;
|
||||
|
||||
parameters[17].name = VKD3D_SHADER_PARAMETER_NAME_FOG_COLOUR;
|
||||
parameters[17].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT;
|
||||
parameters[17].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32_VEC4;
|
||||
memcpy(parameters[17].u.immediate_constant.u.f32_vec4, &runner->r.fog_colour, sizeof(struct vec4));
|
||||
|
||||
parameters[18].name = VKD3D_SHADER_PARAMETER_NAME_FOG_FRAGMENT_MODE;
|
||||
parameters[18].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT;
|
||||
parameters[18].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_UINT32;
|
||||
parameters[18].u.immediate_constant.u.u32 = get_fog_fragment_mode(runner->r.fog_mode);
|
||||
|
||||
parameters[19].name = VKD3D_SHADER_PARAMETER_NAME_FOG_END;
|
||||
parameters[19].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT;
|
||||
parameters[19].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32;
|
||||
|
||||
parameters[20].name = VKD3D_SHADER_PARAMETER_NAME_FOG_SCALE;
|
||||
parameters[20].type = VKD3D_SHADER_PARAMETER_TYPE_IMMEDIATE_CONSTANT;
|
||||
parameters[20].data_type = VKD3D_SHADER_PARAMETER_DATA_TYPE_FLOAT32;
|
||||
|
||||
if (runner->r.fog_mode == FOG_MODE_NONE)
|
||||
{
|
||||
parameters[19].u.immediate_constant.u.f32 = 0.0f;
|
||||
parameters[20].u.immediate_constant.u.f32 = -1.0f;
|
||||
}
|
||||
|
||||
parameter_info.parameter_count = ARRAY_SIZE(parameters);
|
||||
parameter_info.parameters = parameters;
|
||||
|
||||
@ -1656,6 +1701,7 @@ static bool init_vulkan_runner(struct vulkan_shader_runner *runner)
|
||||
}
|
||||
|
||||
runner->caps.shader_caps[SHADER_CAP_CLIP_PLANES] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_FOG] = true;
|
||||
runner->caps.shader_caps[SHADER_CAP_POINT_SIZE] = true;
|
||||
|
||||
device_desc.pEnabledFeatures = &features;
|
||||
@ -1758,6 +1804,9 @@ void run_shader_tests_vulkan(void)
|
||||
runner.caps.maximum_shader_model = SHADER_MODEL_3_0;
|
||||
run_shader_tests(&runner.r, &runner.caps, &vulkan_runner_ops, NULL);
|
||||
|
||||
/* Fog requires remapping, which is only correct for sm1. */
|
||||
runner.caps.shader_caps[SHADER_CAP_FOG] = false;
|
||||
|
||||
runner.caps.minimum_shader_model = SHADER_MODEL_4_0;
|
||||
runner.caps.maximum_shader_model = SHADER_MODEL_5_1;
|
||||
run_shader_tests(&runner.r, &runner.caps, &vulkan_runner_ops, NULL);
|
||||
|
Loading…
x
Reference in New Issue
Block a user