mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-01-28 13:05:02 -08:00
libs/vkd3d-shader: Add support for multiple shader outputs packed into single register.
This commit is contained in:
parent
7f1242888e
commit
682e725d6e
@ -590,10 +590,18 @@ static uint32_t vkd3d_spirv_build_op_variable(struct vkd3d_spirv_builder *builde
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_function(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t result_type, uint32_t function_control, uint32_t function_type)
|
||||
uint32_t result_type, uint32_t result_id, uint32_t function_control, uint32_t function_type)
|
||||
{
|
||||
return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
|
||||
SpvOpFunction, result_type, function_control, function_type);
|
||||
vkd3d_spirv_build_op3v(&builder->function_stream,
|
||||
SpvOpFunction, result_type, result_id, function_control, &function_type, 1);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_function_parameter(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t result_type)
|
||||
{
|
||||
return vkd3d_spirv_build_op_tr(builder, &builder->function_stream,
|
||||
SpvOpFunctionParameter, result_type);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_function_end(struct vkd3d_spirv_builder *builder)
|
||||
@ -601,6 +609,13 @@ static void vkd3d_spirv_build_op_function_end(struct vkd3d_spirv_builder *builde
|
||||
vkd3d_spirv_build_op(&builder->function_stream, SpvOpFunctionEnd);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_function_call(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t result_type, uint32_t function_id, const uint32_t *arguments, unsigned int argument_count)
|
||||
{
|
||||
return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
|
||||
SpvOpFunctionCall, result_type, function_id, arguments, argument_count);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_undef(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, uint32_t type_id)
|
||||
{
|
||||
@ -816,7 +831,7 @@ static void vkd3d_spirv_builder_init(struct vkd3d_spirv_builder *builder)
|
||||
function_type_id = vkd3d_spirv_build_op_type_function(builder, void_id, NULL, 0);
|
||||
|
||||
builder->main_function_id = vkd3d_spirv_build_op_function(builder, void_id,
|
||||
SpvFunctionControlMaskNone, function_type_id);
|
||||
vkd3d_spirv_alloc_id(builder), SpvFunctionControlMaskNone, function_type_id);
|
||||
vkd3d_spirv_build_op_name(builder, builder->main_function_id, "main");
|
||||
vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
|
||||
}
|
||||
@ -850,8 +865,6 @@ static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder,
|
||||
unsigned int i;
|
||||
size_t size;
|
||||
|
||||
vkd3d_spirv_build_op_function_end(builder);
|
||||
|
||||
vkd3d_spirv_stream_init(&stream);
|
||||
|
||||
vkd3d_spirv_build_word(&stream, SpvMagicNumber);
|
||||
@ -1028,10 +1041,19 @@ struct vkd3d_dxbc_compiler
|
||||
|
||||
unsigned int branch_id;
|
||||
struct vkd3d_control_flow_info control_flow_info;
|
||||
|
||||
const struct vkd3d_shader_signature *output_signature;
|
||||
struct
|
||||
{
|
||||
uint32_t id;
|
||||
enum vkd3d_component_type component_type;
|
||||
} *output_info;
|
||||
uint32_t private_output_variable[MAX_REG_OUTPUT];
|
||||
uint32_t output_setup_function_id;
|
||||
};
|
||||
|
||||
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
|
||||
uint32_t compiler_options)
|
||||
const struct vkd3d_shader_signature *output_signature, uint32_t compiler_options)
|
||||
{
|
||||
struct vkd3d_dxbc_compiler *compiler;
|
||||
|
||||
@ -1039,6 +1061,13 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader
|
||||
return NULL;
|
||||
|
||||
memset(compiler, 0, sizeof(*compiler));
|
||||
|
||||
if (!(compiler->output_info = vkd3d_calloc(output_signature->element_count, sizeof(*compiler->output_info))))
|
||||
{
|
||||
vkd3d_free(compiler);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vkd3d_spirv_builder_init(&compiler->spirv_builder);
|
||||
compiler->options = compiler_options;
|
||||
|
||||
@ -1070,6 +1099,8 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader
|
||||
|
||||
compiler->shader_type = shader_version->type;
|
||||
|
||||
compiler->output_signature = output_signature;
|
||||
|
||||
return compiler;
|
||||
}
|
||||
|
||||
@ -1563,6 +1594,31 @@ static void vkd3d_dxbc_compiler_emit_store_dst(struct vkd3d_dxbc_compiler *compi
|
||||
vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_dxbc_compiler_emit_extract_components(struct vkd3d_dxbc_compiler *compiler,
|
||||
uint32_t val_id, DWORD write_mask, enum vkd3d_component_type component_type)
|
||||
{
|
||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||
unsigned int i, j, component_idx, component_count;
|
||||
uint32_t type_id, components[VKD3D_VEC4_SIZE];
|
||||
|
||||
if (write_mask == VKD3DSP_WRITEMASK_ALL)
|
||||
return val_id;
|
||||
|
||||
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
|
||||
component_count = vkd3d_write_mask_component_count(write_mask);
|
||||
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
|
||||
|
||||
if (component_count == 1)
|
||||
return vkd3d_spirv_build_op_composite_extract(builder, type_id, val_id, &component_idx, 1);
|
||||
|
||||
for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
|
||||
{
|
||||
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
|
||||
components[j++] = i;
|
||||
}
|
||||
return vkd3d_spirv_build_op_vector_shuffle(builder, type_id, val_id, val_id, components, component_count);
|
||||
}
|
||||
|
||||
static enum vkd3d_component_type vkd3d_component_type_for_register(enum vkd3d_shader_register_type reg_type,
|
||||
enum vkd3d_shader_input_sysval_semantic sysval)
|
||||
{
|
||||
@ -1752,28 +1808,93 @@ static uint32_t vkd3d_dxbc_compiler_emit_input(struct vkd3d_dxbc_compiler *compi
|
||||
static uint32_t vkd3d_dxbc_compiler_emit_output(struct vkd3d_dxbc_compiler *compiler,
|
||||
const struct vkd3d_shader_dst_param *dst, enum vkd3d_shader_input_sysval_semantic sysval)
|
||||
{
|
||||
unsigned int component_idx, component_count, output_component_count;
|
||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||
const struct vkd3d_shader_signature_element *signature_element;
|
||||
const struct vkd3d_shader_register *reg = &dst->reg;
|
||||
const struct vkd3d_shader_signature *signature;
|
||||
enum vkd3d_component_type component_type;
|
||||
struct vkd3d_symbol reg_symbol;
|
||||
SpvStorageClass storage_class;
|
||||
uint32_t id;
|
||||
struct rb_entry *entry = NULL;
|
||||
unsigned int signature_idx;
|
||||
bool use_private_variable;
|
||||
uint32_t id, var_id;
|
||||
|
||||
component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
|
||||
component_count = vkd3d_write_mask_component_count(dst->write_mask);
|
||||
/* FIXME: Consider output signature when choosing component type for output variable. */
|
||||
component_type = vkd3d_component_type_for_register(reg->type, sysval);
|
||||
if (!(output_component_count = vkd3d_component_count_for_register(reg->type, sysval)))
|
||||
output_component_count = component_count;
|
||||
assert(component_count <= output_component_count);
|
||||
|
||||
signature_element = NULL;
|
||||
signature = compiler->output_signature;
|
||||
for (signature_idx = 0; signature_idx < signature->element_count; ++signature_idx)
|
||||
{
|
||||
if (signature->elements[signature_idx].register_idx == reg->idx[0].offset
|
||||
&& (signature->elements[signature_idx].mask & 0xff) == dst->write_mask)
|
||||
{
|
||||
signature_element = &signature->elements[signature_idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!signature_element)
|
||||
{
|
||||
FIXME("Could not find shader signature element (register %u, write mask %#x).\n",
|
||||
reg->idx[0].offset, dst->write_mask);
|
||||
}
|
||||
|
||||
storage_class = SpvStorageClassOutput;
|
||||
|
||||
id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
|
||||
storage_class, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
|
||||
storage_class, component_type, component_count);
|
||||
vkd3d_spirv_add_iface_variable(builder, id);
|
||||
if (sysval)
|
||||
vkd3d_dxbc_compiler_decorate_builtin(compiler, id, dst->reg.type, sysval);
|
||||
{
|
||||
vkd3d_dxbc_compiler_decorate_builtin(compiler, id, reg->type, sysval);
|
||||
if (component_idx)
|
||||
FIXME("Unhandled component index %u.\n", component_idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, reg->idx[0].offset);
|
||||
if (component_idx)
|
||||
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationComponent, component_idx);
|
||||
}
|
||||
if (signature_element)
|
||||
{
|
||||
compiler->output_info[signature_idx].id = id;
|
||||
compiler->output_info[signature_idx].component_type = component_type;
|
||||
}
|
||||
|
||||
vkd3d_dxbc_compiler_emit_register_debug_name(builder, id, reg);
|
||||
if ((use_private_variable = component_type != VKD3D_TYPE_FLOAT || component_count != VKD3D_VEC4_SIZE))
|
||||
storage_class = SpvStorageClassPrivate;
|
||||
|
||||
vkd3d_symbol_make_register(®_symbol, &dst->reg);
|
||||
reg_symbol.id = id;
|
||||
reg_symbol.info.storage_class = storage_class;
|
||||
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
|
||||
vkd3d_symbol_make_register(®_symbol, reg);
|
||||
|
||||
if (!use_private_variable)
|
||||
var_id = id;
|
||||
else if ((entry = rb_get(&compiler->symbol_table, ®_symbol)))
|
||||
var_id = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry)->id;
|
||||
else
|
||||
var_id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
|
||||
storage_class, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
|
||||
if (!entry)
|
||||
{
|
||||
reg_symbol.id = var_id;
|
||||
reg_symbol.info.storage_class = storage_class;
|
||||
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
|
||||
|
||||
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, reg);
|
||||
}
|
||||
|
||||
if (use_private_variable)
|
||||
{
|
||||
compiler->private_output_variable[reg->idx[0].offset] = var_id;
|
||||
if (!compiler->output_setup_function_id)
|
||||
compiler->output_setup_function_id = vkd3d_spirv_alloc_id(builder);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
@ -2334,7 +2455,23 @@ static void vkd3d_dxbc_compiler_emit_comparison_instruction(struct vkd3d_dxbc_co
|
||||
static void vkd3d_dxbc_compiler_emit_return(struct vkd3d_dxbc_compiler *compiler,
|
||||
const struct vkd3d_shader_instruction *instruction)
|
||||
{
|
||||
vkd3d_spirv_build_op_return(&compiler->spirv_builder);
|
||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||
uint32_t void_id, function_id, arguments[MAX_REG_OUTPUT];
|
||||
unsigned int i, count;;
|
||||
|
||||
if ((function_id = compiler->output_setup_function_id))
|
||||
{
|
||||
void_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_VOID, 1);
|
||||
for (i = 0, count = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
|
||||
{
|
||||
if (compiler->private_output_variable[i])
|
||||
arguments[count++] = compiler->private_output_variable[i];
|
||||
}
|
||||
|
||||
vkd3d_spirv_build_op_function_call(builder, void_id, function_id, arguments, count);
|
||||
}
|
||||
|
||||
vkd3d_spirv_build_op_return(builder);
|
||||
}
|
||||
|
||||
static void vkd3d_dxbc_compiler_emit_control_flow_instruction(struct vkd3d_dxbc_compiler *compiler,
|
||||
@ -2526,6 +2663,70 @@ void vkd3d_dxbc_compiler_handle_instruction(struct vkd3d_dxbc_compiler *compiler
|
||||
}
|
||||
}
|
||||
|
||||
static void vkd3d_dxbc_compiler_emit_output_setup_function(struct vkd3d_dxbc_compiler *compiler)
|
||||
{
|
||||
uint32_t void_id, type_id, ptr_type_id, function_type_id, function_id, val_id;
|
||||
const struct vkd3d_shader_signature *signature = compiler->output_signature;
|
||||
uint32_t param_type_id[MAX_REG_OUTPUT], param_id[MAX_REG_OUTPUT] = {};
|
||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||
DWORD write_mask, reg_idx;
|
||||
unsigned int i, count;
|
||||
|
||||
function_id = compiler->output_setup_function_id;
|
||||
|
||||
void_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_VOID, 1);
|
||||
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 4);
|
||||
ptr_type_id = vkd3d_dxbc_compiler_get_pointer_type(compiler, type_id, SpvStorageClassPrivate);
|
||||
for (i = 0, count = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
|
||||
{
|
||||
if (compiler->private_output_variable[i])
|
||||
param_type_id[count++] = ptr_type_id;
|
||||
}
|
||||
function_type_id = vkd3d_spirv_build_op_type_function(builder, void_id, param_type_id, count);
|
||||
|
||||
vkd3d_spirv_build_op_function(builder, void_id, function_id,
|
||||
SpvFunctionControlMaskNone, function_type_id);
|
||||
vkd3d_spirv_build_op_name(builder, function_id, "setup_output");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
|
||||
{
|
||||
if (compiler->private_output_variable[i])
|
||||
param_id[i] = vkd3d_spirv_build_op_function_parameter(builder, ptr_type_id);
|
||||
}
|
||||
|
||||
vkd3d_spirv_build_op_label(builder, vkd3d_spirv_alloc_id(builder));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(compiler->private_output_variable); ++i)
|
||||
{
|
||||
if (compiler->private_output_variable[i])
|
||||
param_id[i] = vkd3d_spirv_build_op_load(builder, type_id, param_id[i], SpvMemoryAccessMaskNone);
|
||||
}
|
||||
|
||||
for (i = 0; i < signature->element_count; ++i)
|
||||
{
|
||||
reg_idx = signature->elements[i].register_idx;
|
||||
write_mask = signature->elements[i].mask & 0xff;
|
||||
|
||||
if (!param_id[reg_idx])
|
||||
continue;
|
||||
|
||||
val_id = vkd3d_dxbc_compiler_emit_extract_components(compiler, param_id[reg_idx],
|
||||
write_mask, VKD3D_TYPE_FLOAT);
|
||||
|
||||
if (compiler->output_info[i].component_type != VKD3D_TYPE_FLOAT)
|
||||
{
|
||||
type_id = vkd3d_spirv_get_type_id(builder, compiler->output_info[i].component_type,
|
||||
vkd3d_write_mask_component_count(write_mask));
|
||||
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
|
||||
}
|
||||
|
||||
vkd3d_spirv_build_op_store(builder, compiler->output_info[i].id, val_id, SpvMemoryAccessMaskNone);
|
||||
}
|
||||
|
||||
vkd3d_spirv_build_op_return(&compiler->spirv_builder);
|
||||
vkd3d_spirv_build_op_function_end(builder);
|
||||
}
|
||||
|
||||
bool vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
|
||||
struct vkd3d_shader_code *spirv)
|
||||
{
|
||||
@ -2534,6 +2735,11 @@ bool vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
|
||||
if (compiler->options & VKD3D_SHADER_STRIP_DEBUG)
|
||||
vkd3d_spirv_stream_clear(&builder->debug_stream);
|
||||
|
||||
vkd3d_spirv_build_op_function_end(builder);
|
||||
|
||||
if (compiler->output_setup_function_id)
|
||||
vkd3d_dxbc_compiler_emit_output_setup_function(compiler);
|
||||
|
||||
if (!vkd3d_spirv_compile_module(builder, spirv))
|
||||
return false;
|
||||
|
||||
@ -2548,6 +2754,8 @@ bool vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
|
||||
|
||||
void vkd3d_dxbc_compiler_destroy(struct vkd3d_dxbc_compiler *compiler)
|
||||
{
|
||||
vkd3d_free(compiler->output_info);
|
||||
|
||||
vkd3d_spirv_builder_free(&compiler->spirv_builder);
|
||||
|
||||
rb_destroy(&compiler->symbol_table, vkd3d_symbol_free, NULL);
|
||||
|
@ -49,7 +49,8 @@ HRESULT vkd3d_shader_compile_dxbc(const struct vkd3d_shader_code *dxbc,
|
||||
|
||||
shader_sm4_read_header(parser_data, &ptr, &shader_version);
|
||||
|
||||
if (!(spirv_compiler = vkd3d_dxbc_compiler_create(&shader_version, compiler_options)))
|
||||
if (!(spirv_compiler = vkd3d_dxbc_compiler_create(&shader_version,
|
||||
&shader_desc.output_signature, compiler_options)))
|
||||
{
|
||||
ERR("Failed to create DXBC compiler.\n");
|
||||
shader_sm4_free(parser_data);
|
||||
|
@ -821,8 +821,8 @@ void free_shader_desc(struct vkd3d_shader_desc *desc) DECLSPEC_HIDDEN;
|
||||
|
||||
struct vkd3d_dxbc_compiler;
|
||||
|
||||
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(
|
||||
const struct vkd3d_shader_version *shader_version, uint32_t compiler_options) DECLSPEC_HIDDEN;
|
||||
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
|
||||
const struct vkd3d_shader_signature *output_signature, uint32_t compiler_options) DECLSPEC_HIDDEN;
|
||||
void vkd3d_dxbc_compiler_handle_instruction(struct vkd3d_dxbc_compiler *compiler,
|
||||
const struct vkd3d_shader_instruction *instruction) DECLSPEC_HIDDEN;
|
||||
bool vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
|
||||
|
Loading…
x
Reference in New Issue
Block a user