mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-11-21 16:46:41 -08:00
libs/vkd3d-shader: Generate SPIR-V modules.
This commit is contained in:
parent
eff8428c71
commit
dd31e5e918
@ -23,12 +23,61 @@
|
||||
static void vkd3d_spirv_dump(const struct vkd3d_shader_code *spirv) {}
|
||||
static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv) {}
|
||||
|
||||
struct vkd3d_spirv_stream
|
||||
{
|
||||
uint32_t *words;
|
||||
size_t capacity;
|
||||
size_t word_count;
|
||||
};
|
||||
|
||||
static void vkd3d_spirv_stream_init(struct vkd3d_spirv_stream *stream)
|
||||
{
|
||||
stream->capacity = 256;
|
||||
if (!(stream->words = vkd3d_calloc(stream->capacity, sizeof(*stream->words))))
|
||||
stream->capacity = 0;
|
||||
stream->word_count = 0;
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_stream_free(struct vkd3d_spirv_stream *stream)
|
||||
{
|
||||
vkd3d_free(stream->words);
|
||||
}
|
||||
|
||||
static bool vkd3d_spirv_stream_append(struct vkd3d_spirv_stream *dst_stream,
|
||||
const struct vkd3d_spirv_stream *src_stream)
|
||||
{
|
||||
if (!vkd3d_array_reserve((void **)&dst_stream->words, &dst_stream->capacity,
|
||||
dst_stream->word_count + src_stream->word_count, sizeof(*dst_stream->words)))
|
||||
return false;
|
||||
|
||||
assert(dst_stream->word_count + src_stream->word_count <= dst_stream->capacity);
|
||||
memcpy(&dst_stream->words[dst_stream->word_count], src_stream->words,
|
||||
src_stream->word_count * sizeof(*src_stream->words));
|
||||
dst_stream->word_count += src_stream->word_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct vkd3d_spirv_builder
|
||||
{
|
||||
uint64_t capability_mask;
|
||||
SpvExecutionModel execution_model;
|
||||
|
||||
uint32_t current_id;
|
||||
uint32_t main_function_id;
|
||||
uint32_t type_id[VKD3D_TYPE_COUNT][VKD3D_VEC4_SIZE];
|
||||
|
||||
struct vkd3d_spirv_stream debug_stream; /* debug instructions */
|
||||
struct vkd3d_spirv_stream annotation_stream; /* decoration instructions */
|
||||
struct vkd3d_spirv_stream global_stream; /* types, constants, global variables */
|
||||
struct vkd3d_spirv_stream function_stream; /* function definitions */
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t local_size[3];
|
||||
} compute;
|
||||
} u;
|
||||
};
|
||||
|
||||
static void vkd3d_spirv_enable_capability(struct vkd3d_spirv_builder *builder,
|
||||
@ -62,17 +111,369 @@ static void vkd3d_spirv_set_execution_model(struct vkd3d_spirv_builder *builder,
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_opcode_word(SpvOp op, unsigned int word_count)
|
||||
{
|
||||
assert(!(op & ~SpvOpCodeMask));
|
||||
return (word_count << SpvWordCountShift) | op;
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_word(struct vkd3d_spirv_stream *stream, uint32_t word)
|
||||
{
|
||||
if (!vkd3d_array_reserve((void **)&stream->words, &stream->capacity,
|
||||
stream->word_count + 1, sizeof(*stream->words)))
|
||||
return;
|
||||
|
||||
stream->words[stream->word_count++] = word;
|
||||
}
|
||||
|
||||
static unsigned int vkd3d_spirv_string_word_count(const char *str)
|
||||
{
|
||||
return align(strlen(str) + 1, sizeof(uint32_t)) / sizeof(uint32_t);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_string(struct vkd3d_spirv_stream *stream,
|
||||
const char *str, unsigned int word_count)
|
||||
{
|
||||
unsigned int word_idx, i;
|
||||
const char *ptr = str;
|
||||
|
||||
for (word_idx = 0; word_idx < word_count; ++word_idx)
|
||||
{
|
||||
uint32_t word = 0;
|
||||
for (i = 0; i < sizeof(uint32_t) && *ptr; ++i)
|
||||
word |= (uint32_t)*ptr++ << (8 * i);
|
||||
vkd3d_spirv_build_word(stream, word);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* vkd3d_spirv_build_op[1-3][v]()
|
||||
* vkd3d_spirv_build_op_[t][r][1-3][v]()
|
||||
*
|
||||
* t - result type
|
||||
* r - result id
|
||||
* 1-3 - the number of operands
|
||||
* v - variable number of operands
|
||||
*/
|
||||
static void vkd3d_spirv_build_op(struct vkd3d_spirv_stream *stream, SpvOp op)
|
||||
{
|
||||
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 1));
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op1(struct vkd3d_spirv_stream *stream,
|
||||
SpvOp op, uint32_t operand)
|
||||
{
|
||||
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 2));
|
||||
vkd3d_spirv_build_word(stream, operand);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op1v(struct vkd3d_spirv_stream *stream,
|
||||
SpvOp op, uint32_t operand0, const uint32_t *operands, unsigned int operand_count)
|
||||
{
|
||||
unsigned int i;
|
||||
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 2 + operand_count));
|
||||
vkd3d_spirv_build_word(stream, operand0);
|
||||
for (i = 0; i < operand_count; ++i)
|
||||
vkd3d_spirv_build_word(stream, operands[i]);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op2v(struct vkd3d_spirv_stream *stream,
|
||||
SpvOp op, uint32_t operand0, uint32_t operand1,
|
||||
const uint32_t *operands, unsigned int operand_count)
|
||||
{
|
||||
unsigned int i;
|
||||
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 3 + operand_count));
|
||||
vkd3d_spirv_build_word(stream, operand0);
|
||||
vkd3d_spirv_build_word(stream, operand1);
|
||||
for (i = 0; i < operand_count; ++i)
|
||||
vkd3d_spirv_build_word(stream, operands[i]);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op2(struct vkd3d_spirv_stream *stream,
|
||||
SpvOp op, uint32_t operand0, uint32_t operand1)
|
||||
{
|
||||
return vkd3d_spirv_build_op2v(stream, op, operand0, operand1, NULL, 0);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_rv(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, SpvOp op,
|
||||
const uint32_t *operands, unsigned int operand_count)
|
||||
{
|
||||
uint32_t result_id = builder->current_id++;
|
||||
vkd3d_spirv_build_op1v(stream, op, result_id, operands, operand_count);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_r(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, SpvOp op)
|
||||
{
|
||||
return vkd3d_spirv_build_op_rv(builder, stream, op, NULL, 0);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_r1(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t operand0)
|
||||
{
|
||||
return vkd3d_spirv_build_op_rv(builder, stream, op, &operand0, 1);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_r2(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t operand0, uint32_t operand1)
|
||||
{
|
||||
uint32_t operands[] = {operand0, operand1};
|
||||
return vkd3d_spirv_build_op_rv(builder, stream, op, operands, ARRAY_SIZE(operands));
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_r1v(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t operand0,
|
||||
const uint32_t *operands, unsigned int operand_count)
|
||||
{
|
||||
uint32_t result_id = builder->current_id++;
|
||||
vkd3d_spirv_build_op2v(stream, op, result_id, operand0, operands, operand_count);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_trv(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
|
||||
const uint32_t *operands, unsigned int operand_count)
|
||||
{
|
||||
uint32_t result_id = builder->current_id++;
|
||||
vkd3d_spirv_build_op2v(stream, op, result_type, result_id, operands, operand_count);
|
||||
return result_id;
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_tr2(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
|
||||
uint32_t operand0, uint32_t operand1)
|
||||
{
|
||||
uint32_t operands[] = {operand0, operand1};
|
||||
return vkd3d_spirv_build_op_trv(builder, stream, op, result_type,
|
||||
operands, ARRAY_SIZE(operands));
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_capability(struct vkd3d_spirv_stream *stream,
|
||||
SpvCapability cap)
|
||||
{
|
||||
vkd3d_spirv_build_op1(stream, SpvOpCapability, cap);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_memory_model(struct vkd3d_spirv_stream *stream,
|
||||
SpvAddressingModel addressing_model, SpvMemoryModel memory_model)
|
||||
{
|
||||
vkd3d_spirv_build_op2(stream, SpvOpMemoryModel, addressing_model, memory_model);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_entry_point(struct vkd3d_spirv_stream *stream,
|
||||
SpvExecutionModel model, uint32_t function_id, const char *name,
|
||||
uint32_t *interface_list, unsigned int interface_size)
|
||||
{
|
||||
unsigned int i, name_size = vkd3d_spirv_string_word_count(name);
|
||||
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpEntryPoint, 3 + name_size + interface_size));
|
||||
vkd3d_spirv_build_word(stream, model);
|
||||
vkd3d_spirv_build_word(stream, function_id);
|
||||
vkd3d_spirv_build_string(stream, name, name_size);
|
||||
for (i = 0; i < interface_size; ++i)
|
||||
vkd3d_spirv_build_word(stream, interface_list[i]);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_execution_mode(struct vkd3d_spirv_stream *stream,
|
||||
uint32_t entry_point, SpvExecutionMode mode, uint32_t *literals, uint32_t literal_count)
|
||||
{
|
||||
vkd3d_spirv_build_op2v(stream, SpvOpExecutionMode, entry_point, mode, literals, literal_count);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_name(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t id, const char *name)
|
||||
{
|
||||
unsigned int name_size = vkd3d_spirv_string_word_count(name);
|
||||
struct vkd3d_spirv_stream *stream = &builder->debug_stream;
|
||||
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpName, 2 + name_size));
|
||||
vkd3d_spirv_build_word(stream, id);
|
||||
vkd3d_spirv_build_string(stream, name, name_size);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_type_void(struct vkd3d_spirv_builder *builder)
|
||||
{
|
||||
return vkd3d_spirv_build_op_r(builder, &builder->global_stream, SpvOpTypeVoid);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_type_float(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t width)
|
||||
{
|
||||
return vkd3d_spirv_build_op_r1(builder, &builder->global_stream, SpvOpTypeFloat, width);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_type_int(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t width, uint32_t signedness)
|
||||
{
|
||||
return vkd3d_spirv_build_op_r2(builder, &builder->global_stream, SpvOpTypeInt, width, signedness);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_type_vector(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t component_type, uint32_t component_count)
|
||||
{
|
||||
return vkd3d_spirv_build_op_r2(builder, &builder->global_stream,
|
||||
SpvOpTypeVector, component_type, component_count);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_type_function(struct vkd3d_spirv_builder *builder,
|
||||
uint32_t return_type, uint32_t *param_types, unsigned int param_count)
|
||||
{
|
||||
return vkd3d_spirv_build_op_r1v(builder, &builder->global_stream,
|
||||
SpvOpTypeFunction, return_type, param_types, param_count);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
|
||||
SpvOpFunction, result_type, function_control, function_type);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_function_end(struct vkd3d_spirv_builder *builder)
|
||||
{
|
||||
vkd3d_spirv_build_op(&builder->function_stream, SpvOpFunctionEnd);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_build_op_label(struct vkd3d_spirv_builder *builder)
|
||||
{
|
||||
return vkd3d_spirv_build_op_r(builder, &builder->function_stream, SpvOpLabel);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_return(struct vkd3d_spirv_builder *builder)
|
||||
{
|
||||
vkd3d_spirv_build_op(&builder->function_stream, SpvOpReturn);
|
||||
}
|
||||
|
||||
static uint32_t vkd3d_spirv_get_type_id(struct vkd3d_spirv_builder *builder,
|
||||
enum vkd3d_component_type component_type, unsigned int component_count)
|
||||
{
|
||||
uint32_t id, scalar_id;
|
||||
|
||||
assert(0 < component_count && component_count <= VKD3D_VEC4_SIZE);
|
||||
|
||||
if (!(id = builder->type_id[component_type][component_count - 1]))
|
||||
{
|
||||
if (component_count == 1)
|
||||
{
|
||||
switch (component_type)
|
||||
{
|
||||
case VKD3D_TYPE_VOID:
|
||||
id = vkd3d_spirv_build_op_type_void(builder);
|
||||
break;
|
||||
case VKD3D_TYPE_FLOAT:
|
||||
id = vkd3d_spirv_build_op_type_float(builder, 32);
|
||||
break;
|
||||
case VKD3D_TYPE_INT:
|
||||
case VKD3D_TYPE_UINT:
|
||||
id = vkd3d_spirv_build_op_type_int(builder, 32, component_type == VKD3D_TYPE_INT);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled component type %#x.\n", component_type);
|
||||
id = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(component_type != VKD3D_TYPE_VOID);
|
||||
scalar_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
|
||||
id = vkd3d_spirv_build_op_type_vector(builder, scalar_id, component_count);
|
||||
}
|
||||
|
||||
builder->type_id[component_type][component_count - 1] = id;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_builder_init(struct vkd3d_spirv_builder *builder)
|
||||
{
|
||||
uint32_t void_id, function_type_id;
|
||||
|
||||
vkd3d_spirv_stream_init(&builder->debug_stream);
|
||||
vkd3d_spirv_stream_init(&builder->annotation_stream);
|
||||
vkd3d_spirv_stream_init(&builder->global_stream);
|
||||
vkd3d_spirv_stream_init(&builder->function_stream);
|
||||
|
||||
builder->current_id = 1;
|
||||
|
||||
void_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_VOID, 1);
|
||||
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_build_op_name(builder, builder->main_function_id, "main");
|
||||
vkd3d_spirv_build_op_label(builder);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_builder_free(struct vkd3d_spirv_builder *builder)
|
||||
{
|
||||
vkd3d_spirv_stream_free(&builder->debug_stream);
|
||||
vkd3d_spirv_stream_free(&builder->annotation_stream);
|
||||
vkd3d_spirv_stream_free(&builder->global_stream);
|
||||
vkd3d_spirv_stream_free(&builder->function_stream);
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_execution_mode_declarations(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_spirv_stream *stream)
|
||||
{
|
||||
if (builder->execution_model == SpvExecutionModelGLCompute)
|
||||
{
|
||||
vkd3d_spirv_build_op_execution_mode(stream, builder->main_function_id, SpvExecutionModeLocalSize,
|
||||
builder->u.compute.local_size, ARRAY_SIZE(builder->u.compute.local_size));
|
||||
}
|
||||
}
|
||||
|
||||
static bool vkd3d_spirv_compile_module(struct vkd3d_spirv_builder *builder,
|
||||
struct vkd3d_shader_code *spirv)
|
||||
{
|
||||
FIXME("Not implemented!\n");
|
||||
uint64_t capability_mask = builder->capability_mask;
|
||||
struct vkd3d_spirv_stream stream;
|
||||
uint32_t *code;
|
||||
unsigned int i;
|
||||
size_t size;
|
||||
|
||||
return false;
|
||||
vkd3d_spirv_build_op_function_end(builder);
|
||||
|
||||
vkd3d_spirv_stream_init(&stream);
|
||||
|
||||
vkd3d_spirv_build_word(&stream, SpvMagicNumber);
|
||||
vkd3d_spirv_build_word(&stream, SpvVersion);
|
||||
vkd3d_spirv_build_word(&stream, 0); /* generator */
|
||||
vkd3d_spirv_build_word(&stream, builder->current_id); /* bound */
|
||||
vkd3d_spirv_build_word(&stream, 0); /* schema, reserved */
|
||||
|
||||
for (i = 0; capability_mask; ++i)
|
||||
{
|
||||
if (capability_mask & 1)
|
||||
vkd3d_spirv_build_op_capability(&stream, i);
|
||||
capability_mask >>= 1;
|
||||
}
|
||||
|
||||
vkd3d_spirv_build_op_memory_model(&stream, SpvAddressingModelLogical, SpvMemoryModelGLSL450);
|
||||
vkd3d_spirv_build_op_entry_point(&stream, builder->execution_model, builder->main_function_id,
|
||||
"main", NULL, 0);
|
||||
|
||||
vkd3d_spirv_build_execution_mode_declarations(builder, &stream);
|
||||
|
||||
vkd3d_spirv_stream_append(&stream, &builder->debug_stream);
|
||||
vkd3d_spirv_stream_append(&stream, &builder->annotation_stream);
|
||||
vkd3d_spirv_stream_append(&stream, &builder->global_stream);
|
||||
vkd3d_spirv_stream_append(&stream, &builder->function_stream);
|
||||
|
||||
if (!(code = vkd3d_calloc(stream.word_count, sizeof(*code))))
|
||||
{
|
||||
vkd3d_spirv_stream_free(&stream);
|
||||
return false;
|
||||
}
|
||||
|
||||
size = stream.word_count * sizeof(*code);
|
||||
memcpy(code, stream.words, size);
|
||||
vkd3d_spirv_stream_free(&stream);
|
||||
|
||||
spirv->code = code;
|
||||
spirv->size = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct vkd3d_dxbc_compiler
|
||||
@ -121,10 +522,23 @@ struct vkd3d_dxbc_compiler *vkd3d_dxbc_compiler_create(const struct vkd3d_shader
|
||||
return compiler;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void vkd3d_dxbc_compiler_handle_instruction(struct vkd3d_dxbc_compiler *compiler,
|
||||
const struct vkd3d_shader_instruction *instruction)
|
||||
{
|
||||
FIXME("Unhandled instruction %#x.\n", instruction->handler_idx);
|
||||
switch (instruction->handler_idx)
|
||||
{
|
||||
case VKD3DSIH_RET:
|
||||
vkd3d_dxbc_compiler_emit_return(compiler, instruction);
|
||||
break;
|
||||
default:
|
||||
FIXME("Unhandled instruction %#x.\n", instruction->handler_idx);
|
||||
}
|
||||
}
|
||||
|
||||
bool vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
|
||||
@ -144,5 +558,7 @@ bool vkd3d_dxbc_compiler_generate_spirv(struct vkd3d_dxbc_compiler *compiler,
|
||||
|
||||
void vkd3d_dxbc_compiler_destroy(struct vkd3d_dxbc_compiler *compiler)
|
||||
{
|
||||
vkd3d_spirv_builder_free(&compiler->spirv_builder);
|
||||
|
||||
vkd3d_free(compiler);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user