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:
Elizabeth Figura 2024-10-05 10:26:20 -05:00 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
8 changed files with 504 additions and 29 deletions

View File

@ -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),
};

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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 = &parameter_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);