libs/vkd3d-shader: Add support for push constants.

This commit is contained in:
Józef Kucia 2017-07-27 15:16:49 +02:00
parent 7aaa801768
commit 92fcb9ffa2
6 changed files with 187 additions and 16 deletions

View File

@ -50,15 +50,24 @@ enum vkd3d_descriptor_type
struct vkd3d_shader_resource_binding
{
enum vkd3d_descriptor_type type;
unsigned int index;
unsigned int register_index;
uint32_t descriptor_set;
uint32_t binding;
};
struct vkd3d_shader_push_constant
{
unsigned int register_index;
unsigned int offset;
unsigned int count;
};
HRESULT vkd3d_shader_compile_dxbc(const struct vkd3d_shader_code *dxbc,
struct vkd3d_shader_code *spirv, uint32_t compiler_options,
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count);
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count,
const struct vkd3d_shader_push_constant *push_constants, unsigned int push_constant_count);
void vkd3d_shader_free_shader_code(struct vkd3d_shader_code *code);
HRESULT vkd3d_shader_parse_root_signature(const struct vkd3d_shader_code *dxbc,

View File

@ -631,6 +631,26 @@ static void vkd3d_spirv_build_op_name(struct vkd3d_spirv_builder *builder,
vkd3d_spirv_build_string(stream, name, name_size);
}
static void vkd3d_spirv_build_op_member_name(struct vkd3d_spirv_builder *builder,
uint32_t type_id, uint32_t member, const char *fmt, ...)
{
struct vkd3d_spirv_stream *stream = &builder->debug_stream;
unsigned int name_size;
char name[1024];
va_list args;
va_start(args, fmt);
vsnprintf(name, ARRAY_SIZE(name), fmt, args);
name[ARRAY_SIZE(name) - 1] = '\0';
va_end(args);
name_size = vkd3d_spirv_string_word_count(name);
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpMemberName, 3 + name_size));
vkd3d_spirv_build_word(stream, type_id);
vkd3d_spirv_build_word(stream, member);
vkd3d_spirv_build_string(stream, name, name_size);
}
static void vkd3d_spirv_build_op_decorate(struct vkd3d_spirv_builder *builder,
uint32_t target_id, SpvDecoration decoration,
uint32_t *literals, uint32_t literal_count)
@ -1347,6 +1367,12 @@ struct vkd3d_control_flow_info
} current_block;
};
struct vkd3d_push_constant_buffer
{
struct vkd3d_shader_register reg;
struct vkd3d_shader_push_constant pc;
};
struct vkd3d_dxbc_compiler
{
struct vkd3d_spirv_builder spirv_builder;
@ -1367,7 +1393,10 @@ struct vkd3d_dxbc_compiler
unsigned int binding_count;
const struct vkd3d_shader_resource_binding *bindings;
unsigned int push_constant_count;
struct vkd3d_push_constant_buffer *push_constants;
bool after_declarations_section;
const struct vkd3d_shader_signature *input_signature;
const struct vkd3d_shader_signature *output_signature;
struct
@ -1381,10 +1410,12 @@ struct vkd3d_dxbc_compiler
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
const struct vkd3d_shader_desc *shader_desc, uint32_t compiler_options,
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count)
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count,
const struct vkd3d_shader_push_constant *constants, unsigned int constant_count)
{
const struct vkd3d_shader_signature *output_signature = &shader_desc->output_signature;
struct vkd3d_dxbc_compiler *compiler;
unsigned int i;
if (!(compiler = vkd3d_malloc(sizeof(*compiler))))
return NULL;
@ -1437,9 +1468,38 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader
compiler->bindings = bindings;
}
if (constant_count)
{
compiler->push_constant_count = constant_count;
if (!(compiler->push_constants = vkd3d_calloc(constant_count, sizeof(*compiler->push_constants))))
{
vkd3d_dxbc_compiler_destroy(compiler);
return NULL;
}
for (i = 0; i < compiler->push_constant_count; ++i)
compiler->push_constants[i].pc = constants[i];
}
return compiler;
}
static struct vkd3d_push_constant_buffer *vkd3d_dxbc_compiler_find_push_constant(
struct vkd3d_dxbc_compiler *compiler, const struct vkd3d_shader_register *reg)
{
unsigned int reg_idx = reg->idx[0].offset;
unsigned int i;
for (i = 0; i < compiler->push_constant_count; ++i)
{
struct vkd3d_push_constant_buffer *current = &compiler->push_constants[i];
if (current->pc.register_index == reg_idx)
return current;
}
return NULL;
}
struct vkd3d_descriptor_binding
{
uint32_t set;
@ -1472,7 +1532,7 @@ static struct vkd3d_descriptor_binding vkd3d_dxbc_compiler_get_descriptor_bindin
{
const struct vkd3d_shader_resource_binding *current = &compiler->bindings[i];
if (current->type == descriptor_type && current->index == reg_idx)
if (current->type == descriptor_type && current->register_index == reg_idx)
{
vk_binding.set = current->descriptor_set;
vk_binding.binding = current->binding;
@ -2356,12 +2416,84 @@ static void vkd3d_dxbc_compiler_emit_dcl_temps(struct vkd3d_dxbc_compiler *compi
}
}
static void vkd3d_dxbc_compiler_emit_push_constants(struct vkd3d_dxbc_compiler *compiler)
{
const SpvStorageClass storage_class = SpvStorageClassPushConstant;
uint32_t vec4_id, length_id, struct_id, pointer_type_id, var_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int i, j, count, reg_idx, cb_size;
struct vkd3d_symbol reg_symbol;
uint32_t *member_ids;
count = 0;
for (i = 0; i < compiler->push_constant_count; ++i)
{
const struct vkd3d_push_constant_buffer *cb = &compiler->push_constants[i];
if (cb->reg.type)
++count;
}
if (!count)
return;
if (!(member_ids = vkd3d_calloc(count, sizeof(*member_ids))))
return;
vec4_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
for (i = 0, j = 0; i < compiler->push_constant_count; ++i)
{
const struct vkd3d_push_constant_buffer *cb = &compiler->push_constants[i];
if (!cb->reg.type)
continue;
cb_size = cb->reg.idx[1].offset;
length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, cb_size);
member_ids[j] = vkd3d_spirv_build_op_type_array(builder, vec4_id, length_id);
vkd3d_spirv_build_op_decorate1(builder, member_ids[j], SpvDecorationArrayStride, 16);
++j;
}
struct_id = vkd3d_spirv_build_op_type_struct(builder, member_ids, count);
vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0);
vkd3d_spirv_build_op_name(builder, struct_id, "push_cb");
vkd3d_free(member_ids);
pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
pointer_type_id, storage_class, 0);
for (i = 0, j = 0; i < compiler->push_constant_count; ++i)
{
const struct vkd3d_push_constant_buffer *cb = &compiler->push_constants[i];
if (!cb->reg.type)
continue;
reg_idx = cb->reg.idx[0].offset;
vkd3d_spirv_build_op_member_decorate1(builder, struct_id, j,
SpvDecorationOffset, cb->pc.offset * sizeof(uint32_t));
vkd3d_spirv_build_op_member_name(builder, struct_id, j, "cb%u", reg_idx);
vkd3d_symbol_make_register(&reg_symbol, &cb->reg);
reg_symbol.id = var_id;
reg_symbol.info.storage_class = storage_class;
vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
if (j)
FIXME("Multiple push constant buffers not supported yet.\n");
++j;
}
}
static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
uint32_t vec4_id, array_type_id, length_id, struct_id, pointer_type_id, var_id;
const struct vkd3d_shader_register *reg = &instruction->declaration.src.reg;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
const SpvStorageClass storage_class = SpvStorageClassUniform;
struct vkd3d_push_constant_buffer *push_cb;
struct vkd3d_symbol reg_symbol;
unsigned int cb_size;
@ -2372,6 +2504,15 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi
cb_size = reg->idx[1].offset;
if ((push_cb = vkd3d_dxbc_compiler_find_push_constant(compiler, reg)))
{
push_cb->reg = *reg;
if (cb_size * VKD3D_VEC4_SIZE != push_cb->pc.count)
FIXME("Push constant size do not match (cb size %u, constant count %u).\n",
cb_size, push_cb->pc.count);
return;
}
vec4_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
length_id = vkd3d_dxbc_compiler_get_constant_uint(compiler, cb_size);
array_type_id = vkd3d_spirv_build_op_type_array(builder, vec4_id, length_id);
@ -2382,9 +2523,9 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi
vkd3d_spirv_build_op_member_decorate1(builder, struct_id, 0, SpvDecorationOffset, 0);
vkd3d_spirv_build_op_name(builder, struct_id, "cb%u_struct", cb_size);
pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassUniform, struct_id);
pointer_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, struct_id);
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
pointer_type_id, SpvStorageClassUniform, 0);
pointer_type_id, storage_class, 0);
vkd3d_dxbc_compiler_emit_descriptor_binding(compiler, var_id, reg);
@ -2392,7 +2533,7 @@ static void vkd3d_dxbc_compiler_emit_dcl_constant_buffer(struct vkd3d_dxbc_compi
vkd3d_symbol_make_register(&reg_symbol, reg);
reg_symbol.id = var_id;
reg_symbol.info.storage_class = SpvStorageClassUniform;
reg_symbol.info.storage_class = storage_class;
vkd3d_dxbc_compiler_put_symbol(compiler, &reg_symbol);
}
@ -3574,9 +3715,26 @@ static void vkd3d_dxbc_compiler_emit_store_uav_typed(struct vkd3d_dxbc_compiler
SpvImageOperandsMaskNone, NULL, 0);
}
/* This function is called after declarations are processed. */
static void vkd3d_dxbc_compiler_emit_main_prolog(struct vkd3d_dxbc_compiler *compiler)
{
vkd3d_dxbc_compiler_emit_push_constants(compiler);
}
static bool is_dcl_instruction(enum VKD3D_SHADER_INSTRUCTION_HANDLER handler_idx)
{
return VKD3DSIH_DCL <= handler_idx && handler_idx <= VKD3DSIH_DCL_VERTICES_OUT;
}
void vkd3d_dxbc_compiler_handle_instruction(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
if (!is_dcl_instruction(instruction->handler_idx) && !compiler->after_declarations_section)
{
compiler->after_declarations_section = true;
vkd3d_dxbc_compiler_emit_main_prolog(compiler);
}
switch (instruction->handler_idx)
{
case VKD3DSIH_DCL_GLOBAL_FLAGS:

View File

@ -20,7 +20,8 @@
HRESULT vkd3d_shader_compile_dxbc(const struct vkd3d_shader_code *dxbc,
struct vkd3d_shader_code *spirv, uint32_t compiler_options,
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count)
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count,
const struct vkd3d_shader_push_constant *push_constants, unsigned int push_constant_count)
{
struct vkd3d_dxbc_compiler *spirv_compiler;
struct vkd3d_shader_version shader_version;
@ -31,8 +32,10 @@ HRESULT vkd3d_shader_compile_dxbc(const struct vkd3d_shader_code *dxbc,
HRESULT hr;
bool ret;
TRACE("dxbc {%p, %zu}, spirv %p, compiler_options %#x, bindings %p, binding_count %u.\n",
dxbc->code, dxbc->size, spirv, compiler_options, bindings, binding_count);
TRACE("dxbc {%p, %zu}, spirv %p, compiler_options %#x, bindings %p, binding_count %u, "
"push_constants %p, push_constant_count %u.\n",
dxbc->code, dxbc->size, spirv, compiler_options, bindings, binding_count,
push_constants, push_constant_count);
if (FAILED(hr = shader_extract_from_dxbc(dxbc->code, dxbc->size, &shader_desc)))
{
@ -50,8 +53,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,
&shader_desc, compiler_options, bindings, binding_count)))
if (!(spirv_compiler = vkd3d_dxbc_compiler_create(&shader_version, &shader_desc,
compiler_options, bindings, binding_count, push_constants, push_constant_count)))
{
ERR("Failed to create DXBC compiler.\n");
shader_sm4_free(parser_data);

View File

@ -823,7 +823,8 @@ struct vkd3d_dxbc_compiler;
struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader_version *shader_version,
const struct vkd3d_shader_desc *shader_desc, uint32_t compiler_options,
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count) DECLSPEC_HIDDEN;
const struct vkd3d_shader_resource_binding *bindings, unsigned int binding_count,
const struct vkd3d_shader_push_constant *constants, unsigned int constant_count) 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,

View File

@ -305,7 +305,7 @@ static uint32_t d3d12_root_signature_assign_vk_binding(struct d3d12_root_signatu
uint32_t binding = *descriptor_idx;
root_signature->descriptor_mapping[binding].type = descriptor_type;
root_signature->descriptor_mapping[binding].index = register_idx;
root_signature->descriptor_mapping[binding].register_index = register_idx;
root_signature->descriptor_mapping[binding].descriptor_set = 0;
root_signature->descriptor_mapping[binding].binding = binding;
@ -816,7 +816,7 @@ static HRESULT create_shader_stage(struct d3d12_device *device,
{
struct vkd3d_shader_code dxbc = {code->pShaderBytecode, code->BytecodeLength};
if (FAILED(hr = vkd3d_shader_compile_dxbc(&dxbc, &spirv, 0,
root_signature->descriptor_mapping, root_signature->descriptor_count)))
root_signature->descriptor_mapping, root_signature->descriptor_count, NULL, 0)))
{
WARN("Failed to compile shader, hr %#x.\n", hr);
return hr;

View File

@ -162,7 +162,7 @@ int main(int argc, char **argv)
return 1;
}
hr = vkd3d_shader_compile_dxbc(&dxbc, &spirv, options.compiler_options, NULL, 0);
hr = vkd3d_shader_compile_dxbc(&dxbc, &spirv, options.compiler_options, NULL, 0, NULL, 0);
vkd3d_shader_free_shader_code(&dxbc);
if (FAILED(hr))
{