Newer
Older
/*
* Copyright 2017 Józef Kucia for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "vkd3d_shader_private.h"
#include <stdarg.h>
#include "spirv/1.0/spirv.h"
#include "spirv/1.0/GLSL.std.450.h"
Józef Kucia
committed
#ifdef HAVE_SPIRV_TOOLS
# include "spirv-tools/libspirv.h"
#endif /* HAVE_SPIRV_TOOLS */
#ifdef HAVE_SPIRV_TOOLS
static void vkd3d_spirv_dump(const struct vkd3d_shader_code *spirv)
{
const static uint32_t options
= SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT;
spv_diagnostic diagnostic = NULL;
spv_text text = NULL;
spv_context context;
spv_result_t ret;
context = spvContextCreate(SPV_ENV_VULKAN_1_0);
if (!(ret = spvBinaryToText(context, spirv->code, spirv->size / sizeof(uint32_t),
options, &text, &diagnostic)))
{
const char *str, *current = text->str;
while ((str = strchr(current, '\n')))
{
TRACE("%.*s\n", (int)(str - current), current);
current = str + 1;
}
}
else
{
Józef Kucia
committed
FIXME("Failed to convert SPIR-V binary to text, ret %d.\n", ret);
FIXME("Diagnostic message: %s.\n", debugstr_a(diagnostic->error));
Józef Kucia
committed
}
spvTextDestroy(text);
spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
}
static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv)
{
spv_diagnostic diagnostic = NULL;
spv_context context;
spv_result_t ret;
context = spvContextCreate(SPV_ENV_VULKAN_1_0);
if ((ret = spvValidateBinary(context, spirv->code, spirv->size / sizeof(uint32_t),
&diagnostic)))
{
Józef Kucia
committed
FIXME("Failed to validate SPIR-V binary, ret %d.\n", ret);
FIXME("Diagnostic message: %s.\n", debugstr_a(diagnostic->error));
Józef Kucia
committed
}
spvDiagnosticDestroy(diagnostic);
spvContextDestroy(context);
}
#else
static void vkd3d_spirv_dump(const struct vkd3d_shader_code *spirv) {}
static void vkd3d_spirv_validate(const struct vkd3d_shader_code *spirv) {}
Józef Kucia
committed
#endif /* HAVE_SPIRV_TOOLS */
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 void vkd3d_spirv_stream_clear(struct vkd3d_spirv_stream *stream)
{
stream->word_count = 0;
}
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;
uint32_t ext_instr_set_glsl_450;
SpvExecutionModel execution_model;
uint32_t current_id;
struct rb_tree declarations;
Józef Kucia
committed
uint32_t type_sampler_id;
Józef Kucia
committed
uint32_t type_bool_id;
uint32_t type_void_id;
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;
/* entry point interface */
uint32_t *iface;
size_t iface_capacity;
size_t iface_element_count;
static uint32_t vkd3d_spirv_alloc_id(struct vkd3d_spirv_builder *builder)
{
return builder->current_id++;
}
static void vkd3d_spirv_enable_capability(struct vkd3d_spirv_builder *builder,
SpvCapability cap)
{
assert(cap < sizeof(builder->capability_mask) * CHAR_BIT);
builder->capability_mask |= 1ull << cap;
}
static uint32_t vkd3d_spirv_get_glsl_std450_instr_set(struct vkd3d_spirv_builder *builder)
{
if (!builder->ext_instr_set_glsl_450)
builder->ext_instr_set_glsl_450 = vkd3d_spirv_alloc_id(builder);
return builder->ext_instr_set_glsl_450;
}
static void vkd3d_spirv_add_iface_variable(struct vkd3d_spirv_builder *builder,
uint32_t id)
{
if (!vkd3d_array_reserve((void **)&builder->iface, &builder->iface_capacity,
builder->iface_element_count + 1, sizeof(*builder->iface)))
return;
builder->iface[builder->iface_element_count++] = id;
}
static void vkd3d_spirv_set_execution_model(struct vkd3d_spirv_builder *builder,
SpvExecutionModel model)
{
builder->execution_model = model;
switch (model)
{
case SpvExecutionModelVertex:
case SpvExecutionModelFragment:
case SpvExecutionModelGLCompute:
vkd3d_spirv_enable_capability(builder, SpvCapabilityShader);
break;
case SpvExecutionModelTessellationControl:
case SpvExecutionModelTessellationEvaluation:
vkd3d_spirv_enable_capability(builder, SpvCapabilityTessellation);
break;
case SpvExecutionModelGeometry:
vkd3d_spirv_enable_capability(builder, SpvCapabilityGeometry);
break;
default:
ERR("Unhandled execution model %#x.\n", model);
}
}
static void vkd3d_spirv_set_local_size(struct vkd3d_spirv_builder *builder,
unsigned int x, unsigned int y, unsigned int z)
{
assert(builder->execution_model == SpvExecutionModelGLCompute);
builder->u.compute.local_size[0] = x;
builder->u.compute.local_size[1] = y;
builder->u.compute.local_size[2] = z;
}
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
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);
}
}
typedef uint32_t (*vkd3d_spirv_build_pfn)(struct vkd3d_spirv_builder *builder);
typedef uint32_t (*vkd3d_spirv_build1_pfn)(struct vkd3d_spirv_builder *builder,
uint32_t operand0);
typedef uint32_t (*vkd3d_spirv_build2_pfn)(struct vkd3d_spirv_builder *builder,
uint32_t operand0, uint32_t operand1);
Józef Kucia
committed
static uint32_t vkd3d_spirv_build_once(struct vkd3d_spirv_builder *builder,
uint32_t *id, vkd3d_spirv_build_pfn build_pfn)
Józef Kucia
committed
{
if (!(*id))
*id = build_pfn(builder);
return *id;
}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
#define MAX_SPIRV_DECLARATION_PARAMETER_COUNT 2
struct vkd3d_spirv_declaration
{
struct rb_entry entry;
SpvOp op;
unsigned int parameter_count;
uint32_t parameters[MAX_SPIRV_DECLARATION_PARAMETER_COUNT];
uint32_t id;
};
static int vkd3d_spirv_declaration_compare(const void *key, const struct rb_entry *e)
{
const struct vkd3d_spirv_declaration *a = key;
const struct vkd3d_spirv_declaration *b = RB_ENTRY_VALUE(e, const struct vkd3d_spirv_declaration, entry);
if (a->op != b->op)
return a->op - b->op;
if (a->parameter_count != b->parameter_count)
return a->parameter_count - b->parameter_count;
assert(a->parameter_count <= ARRAY_SIZE(a->parameters));
return memcmp(&a->parameters, &b->parameters, a->parameter_count * sizeof(*a->parameters));
}
static void vkd3d_spirv_declaration_free(struct rb_entry *entry, void *context)
{
struct vkd3d_spirv_declaration *d = RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry);
vkd3d_free(d);
}
static void vkd3d_spirv_insert_declaration(struct vkd3d_spirv_builder *builder,
const struct vkd3d_spirv_declaration *declaration)
{
struct vkd3d_spirv_declaration *d;
if (!(d = vkd3d_malloc(sizeof(*d))))
return;
memcpy(d, declaration, sizeof(*d));
if (rb_put(&builder->declarations, d, &d->entry) == -1)
{
ERR("Failed to insert declaration entry.\n");
vkd3d_free(d);
}
}
static uint32_t vkd3d_spirv_build_once1(struct vkd3d_spirv_builder *builder,
SpvOp op, uint32_t operand0, vkd3d_spirv_build1_pfn build_pfn)
{
struct vkd3d_spirv_declaration declaration;
struct rb_entry *entry;
declaration.op = op;
declaration.parameter_count = 1;
declaration.parameters[0] = operand0;
if ((entry = rb_get(&builder->declarations, &declaration)))
return RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry)->id;
declaration.id = build_pfn(builder, operand0);
vkd3d_spirv_insert_declaration(builder, &declaration);
return declaration.id;
}
static uint32_t vkd3d_spirv_build_once2(struct vkd3d_spirv_builder *builder,
SpvOp op, uint32_t operand0, uint32_t operand1, vkd3d_spirv_build2_pfn build_pfn)
{
struct vkd3d_spirv_declaration declaration;
struct rb_entry *entry;
declaration.op = op;
declaration.parameter_count = 2;
declaration.parameters[0] = operand0;
declaration.parameters[1] = operand1;
if ((entry = rb_get(&builder->declarations, &declaration)))
return RB_ENTRY_VALUE(entry, struct vkd3d_spirv_declaration, entry)->id;
declaration.id = build_pfn(builder, operand0, operand1);
vkd3d_spirv_insert_declaration(builder, &declaration);
return declaration.id;
}
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
/*
* 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_op3v(struct vkd3d_spirv_stream *stream,
SpvOp op, uint32_t operand0, uint32_t operand1, uint32_t operand2,
const uint32_t *operands, unsigned int operand_count)
{
unsigned int i;
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 4 + operand_count));
vkd3d_spirv_build_word(stream, operand0);
vkd3d_spirv_build_word(stream, operand1);
vkd3d_spirv_build_word(stream, operand2);
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 void vkd3d_spirv_build_op3(struct vkd3d_spirv_stream *stream,
SpvOp op, uint32_t operand0, uint32_t operand1, uint32_t operand2)
{
return vkd3d_spirv_build_op2v(stream, op, operand0, operand1, &operand2, 1);
}
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 = vkd3d_spirv_alloc_id(builder);
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
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 = vkd3d_spirv_alloc_id(builder);
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 = vkd3d_spirv_alloc_id(builder);
vkd3d_spirv_build_op2v(stream, op, result_type, result_id, operands, operand_count);
return result_id;
}
static uint32_t vkd3d_spirv_build_op_tr(struct vkd3d_spirv_builder *builder,
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type)
{
return vkd3d_spirv_build_op_trv(builder, stream, op, result_type, NULL, 0);
}
static uint32_t vkd3d_spirv_build_op_tr1(struct vkd3d_spirv_builder *builder,
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
uint32_t operand0)
{
return vkd3d_spirv_build_op_trv(builder, stream, op, result_type, &operand0, 1);
}
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 uint32_t vkd3d_spirv_build_op_tr1v(struct vkd3d_spirv_builder *builder,
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
uint32_t operand0, const uint32_t *operands, unsigned int operand_count)
{
uint32_t result_id = vkd3d_spirv_alloc_id(builder);
vkd3d_spirv_build_op3v(stream, op, result_type, result_id, operand0, operands, operand_count);
return result_id;
}
static uint32_t vkd3d_spirv_build_op_tr2v(struct vkd3d_spirv_builder *builder,
struct vkd3d_spirv_stream *stream, SpvOp op, uint32_t result_type,
uint32_t operand0, uint32_t operand1, const uint32_t *operands, unsigned int operand_count)
{
uint32_t result_id = vkd3d_spirv_alloc_id(builder);
unsigned int i;
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(op, 5 + operand_count));
vkd3d_spirv_build_word(stream, result_type);
vkd3d_spirv_build_word(stream, result_id);
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]);
return result_id;
}
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_ext_inst_import(struct vkd3d_spirv_stream *stream,
uint32_t result_id, const char *name)
{
unsigned int name_size = vkd3d_spirv_string_word_count(name);
vkd3d_spirv_build_word(stream, vkd3d_spirv_opcode_word(SpvOpExtInstImport, 2 + name_size));
vkd3d_spirv_build_word(stream, result_id);
vkd3d_spirv_build_string(stream, name, name_size);
}
static uint32_t vkd3d_spirv_build_op_ext_inst(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t inst_set, uint32_t inst_number,
uint32_t *operands, unsigned int operand_count)
{
return vkd3d_spirv_build_op_tr2v(builder, &builder->function_stream,
SpvOpExtInst, result_type, inst_set, inst_number, operands, operand_count);
}
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, unsigned int 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 *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(SpvOpName, 2 + name_size));
vkd3d_spirv_build_word(stream, id);
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)
{
vkd3d_spirv_build_op2v(&builder->annotation_stream,
SpvOpDecorate, target_id, decoration, literals, literal_count);
}
static void vkd3d_spirv_build_op_decorate1(struct vkd3d_spirv_builder *builder,
uint32_t target_id, SpvDecoration decoration, uint32_t operand0)
{
return vkd3d_spirv_build_op_decorate(builder, target_id, decoration, &operand0, 1);
}
static void vkd3d_spirv_build_op_member_decorate(struct vkd3d_spirv_builder *builder,
uint32_t structure_type_id, uint32_t member_idx, SpvDecoration decoration,
uint32_t *literals, uint32_t literal_count)
{
vkd3d_spirv_build_op3v(&builder->annotation_stream, SpvOpMemberDecorate,
structure_type_id, member_idx, decoration, literals, literal_count);
}
static void vkd3d_spirv_build_op_member_decorate1(struct vkd3d_spirv_builder *builder,
uint32_t structure_type_id, uint32_t member_idx, SpvDecoration decoration, uint32_t operand0)
{
vkd3d_spirv_build_op_member_decorate(builder, structure_type_id, member_idx, decoration, &operand0, 1);
}
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);
}
Józef Kucia
committed
static uint32_t vkd3d_spirv_get_op_type_void(struct vkd3d_spirv_builder *builder)
{
return vkd3d_spirv_build_once(builder, &builder->type_void_id, vkd3d_spirv_build_op_type_void);
}
static uint32_t vkd3d_spirv_build_op_type_bool(struct vkd3d_spirv_builder *builder)
{
return vkd3d_spirv_build_op_r(builder, &builder->global_stream, SpvOpTypeBool);
}
Józef Kucia
committed
static uint32_t vkd3d_spirv_get_op_type_bool(struct vkd3d_spirv_builder *builder)
{
return vkd3d_spirv_build_once(builder, &builder->type_bool_id, vkd3d_spirv_build_op_type_bool);
}
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_get_op_type_float(struct vkd3d_spirv_builder *builder,
uint32_t width)
{
return vkd3d_spirv_build_once1(builder, SpvOpTypeFloat, width, vkd3d_spirv_build_op_type_float);
}
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_get_op_type_int(struct vkd3d_spirv_builder *builder,
uint32_t width, uint32_t signedness)
{
return vkd3d_spirv_build_once2(builder, SpvOpTypeInt, width, signedness,
vkd3d_spirv_build_op_type_int);
}
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_get_op_type_vector(struct vkd3d_spirv_builder *builder,
uint32_t component_type, uint32_t component_count)
{
return vkd3d_spirv_build_once2(builder, SpvOpTypeVector, component_type, component_count,
vkd3d_spirv_build_op_type_vector);
}
static uint32_t vkd3d_spirv_build_op_type_array(struct vkd3d_spirv_builder *builder,
uint32_t element_type, uint32_t length_id)
{
return vkd3d_spirv_build_op_r2(builder, &builder->global_stream,
SpvOpTypeArray, element_type, length_id);
}
static uint32_t vkd3d_spirv_build_op_type_struct(struct vkd3d_spirv_builder *builder,
uint32_t *members, unsigned int member_count)
{
return vkd3d_spirv_build_op_rv(builder, &builder->global_stream,
SpvOpTypeStruct, members, member_count);
}
static uint32_t vkd3d_spirv_build_op_type_sampler(struct vkd3d_spirv_builder *builder)
{
return vkd3d_spirv_build_op_r(builder, &builder->global_stream, SpvOpTypeSampler);
}
Józef Kucia
committed
static uint32_t vkd3d_spirv_get_op_type_sampler(struct vkd3d_spirv_builder *builder)
{
return vkd3d_spirv_build_once(builder, &builder->type_sampler_id, vkd3d_spirv_build_op_type_sampler);
}
/* Access qualifiers are not supported. */
static uint32_t vkd3d_spirv_build_op_type_image(struct vkd3d_spirv_builder *builder,
uint32_t sampled_type_id, SpvDim dim, uint32_t depth, uint32_t arrayed,
uint32_t ms, uint32_t sampled, SpvImageFormat format)
{
uint32_t operands[] = {sampled_type_id, dim, depth, arrayed, ms, sampled, format};
return vkd3d_spirv_build_op_rv(builder, &builder->global_stream,
SpvOpTypeImage, operands, ARRAY_SIZE(operands));
}
static uint32_t vkd3d_spirv_build_op_type_sampled_image(struct vkd3d_spirv_builder *builder,
uint32_t image_type_id)
{
return vkd3d_spirv_build_op_r1(builder, &builder->global_stream,
SpvOpTypeSampledImage, image_type_id);
}
static uint32_t vkd3d_spirv_get_op_type_sampled_image(struct vkd3d_spirv_builder *builder,
uint32_t image_type_id)
{
return vkd3d_spirv_build_once1(builder, SpvOpTypeSampledImage, image_type_id,
vkd3d_spirv_build_op_type_sampled_image);
}
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_type_pointer(struct vkd3d_spirv_builder *builder,
uint32_t storage_class, uint32_t type_id)
{
return vkd3d_spirv_build_op_r2(builder, &builder->global_stream,
SpvOpTypePointer, storage_class, type_id);
}
static uint32_t vkd3d_spirv_get_op_type_pointer(struct vkd3d_spirv_builder *builder,
uint32_t storage_class, uint32_t type_id)
{
return vkd3d_spirv_build_once2(builder, SpvOpTypePointer, storage_class, type_id,
vkd3d_spirv_build_op_type_pointer);
}
/* Types larger than 32-bits are not supported. */
static uint32_t vkd3d_spirv_build_op_constant(struct vkd3d_spirv_builder *builder,
uint32_t result_type, const uint32_t value)
{
return vkd3d_spirv_build_op_tr1(builder, &builder->global_stream,
SpvOpConstant, result_type, value);
}
static uint32_t vkd3d_spirv_build_op_constant_composite(struct vkd3d_spirv_builder *builder,
uint32_t result_type, const uint32_t* constituents, unsigned int constituent_count)
{
return vkd3d_spirv_build_op_trv(builder, &builder->global_stream,
SpvOpConstantComposite, result_type, constituents, constituent_count);
}
static uint32_t vkd3d_spirv_build_op_variable(struct vkd3d_spirv_builder *builder,
struct vkd3d_spirv_stream *stream, uint32_t type_id, uint32_t storage_class, uint32_t initializer)
return vkd3d_spirv_build_op_tr1v(builder, stream,
SpvOpVariable, type_id, storage_class, &initializer, !!initializer);
static uint32_t vkd3d_spirv_build_op_function(struct vkd3d_spirv_builder *builder,
Józef Kucia
committed
uint32_t result_type, uint32_t result_id, uint32_t function_control, uint32_t function_type)
Józef Kucia
committed
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)
{
vkd3d_spirv_build_op(&builder->function_stream, SpvOpFunctionEnd);
}
Józef Kucia
committed
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)
{
return vkd3d_spirv_build_op_tr(builder, stream, SpvOpUndef, type_id);
}
static uint32_t vkd3d_spirv_build_op_access_chain(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t base_id, uint32_t *indexes, uint32_t index_count)
{
return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
SpvOpAccessChain, result_type, base_id, indexes, index_count);
}
static uint32_t vkd3d_spirv_build_op_in_bounds_access_chain(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t base_id, uint32_t *indexes, uint32_t index_count)
{
return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream,
SpvOpInBoundsAccessChain, result_type, base_id, indexes, index_count);
}
static uint32_t vkd3d_spirv_build_op_vector_shuffle(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t vector1_id, uint32_t vector2_id,
const uint32_t *components, uint32_t component_count)
{
return vkd3d_spirv_build_op_tr2v(builder, &builder->function_stream, SpvOpVectorShuffle,
result_type, vector1_id, vector2_id, components, component_count);
}
static uint32_t vkd3d_spirv_build_op_composite_construct(struct vkd3d_spirv_builder *builder,
uint32_t result_type, const uint32_t *constituents, unsigned int constituent_count)
{
return vkd3d_spirv_build_op_trv(builder, &builder->function_stream, SpvOpCompositeConstruct,
result_type, constituents, constituent_count);
}
static uint32_t vkd3d_spirv_build_op_composite_extract(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t composite_id, const uint32_t *indexes, unsigned int index_count)
{
return vkd3d_spirv_build_op_tr1v(builder, &builder->function_stream, SpvOpCompositeExtract,
result_type, composite_id, indexes, index_count);
}
static uint32_t vkd3d_spirv_build_op_load(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t pointer_id, uint32_t memory_access)
{
if (!memory_access)
return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream, SpvOpLoad,
result_type, pointer_id);
else
return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream, SpvOpLoad,
result_type, pointer_id, memory_access);
}
static void vkd3d_spirv_build_op_store(struct vkd3d_spirv_builder *builder,
uint32_t pointer_id, uint32_t object_id, uint32_t memory_access)
{
if (!memory_access)
return vkd3d_spirv_build_op2(&builder->function_stream, SpvOpStore,
pointer_id, object_id);
else
return vkd3d_spirv_build_op3(&builder->function_stream, SpvOpStore,
pointer_id, object_id, memory_access);
}
static uint32_t vkd3d_spirv_build_op_select(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t condition_id, uint32_t object0_id, uint32_t object1_id)
{
uint32_t operands[] = {condition_id, object0_id, object1_id};
return vkd3d_spirv_build_op_trv(builder, &builder->function_stream, SpvOpSelect,
result_type, operands, ARRAY_SIZE(operands));
}
static void vkd3d_spirv_build_op_return(struct vkd3d_spirv_builder *builder)
{
vkd3d_spirv_build_op(&builder->function_stream, SpvOpReturn);
}
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
static uint32_t vkd3d_spirv_build_op_label(struct vkd3d_spirv_builder *builder,
uint32_t label_id)
{
vkd3d_spirv_build_op1(&builder->function_stream, SpvOpLabel, label_id);
return label_id;
}
static void vkd3d_spirv_build_op_selection_merge(struct vkd3d_spirv_builder *builder,
uint32_t merge_block, uint32_t selection_control)
{
vkd3d_spirv_build_op2(&builder->function_stream, SpvOpSelectionMerge,
merge_block, selection_control);
}
static void vkd3d_spirv_build_op_branch(struct vkd3d_spirv_builder *builder, uint32_t label)
{
vkd3d_spirv_build_op1(&builder->function_stream, SpvOpBranch, label);
}
/* Branch weights are not supported. */
static void vkd3d_spirv_build_op_branch_conditional(struct vkd3d_spirv_builder *builder,
uint32_t condition, uint32_t true_label, uint32_t false_label)
{
vkd3d_spirv_build_op3(&builder->function_stream, SpvOpBranchConditional,
condition, true_label, false_label);
}
Józef Kucia
committed
static uint32_t vkd3d_spirv_build_op_iadd(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t operand0, uint32_t operand1)
{
return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
SpvOpIAdd, result_type, operand0, operand1);
}
static uint32_t vkd3d_spirv_build_op_isub(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t operand0, uint32_t operand1)
{
return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
SpvOpISub, result_type, operand0, operand1);
}
static uint32_t vkd3d_spirv_build_op_fnegate(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t operand)
{
return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
SpvOpFNegate, result_type, operand);
}
static uint32_t vkd3d_spirv_build_op_snegate(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t operand)
{
return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
SpvOpSNegate, result_type, operand);
}
static uint32_t vkd3d_spirv_build_op_and(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t operand0, uint32_t operand1)
{
return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
SpvOpBitwiseAnd, result_type, operand0, operand1);
}
static uint32_t vkd3d_spirv_build_op_bitcast(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t operand)
{
return vkd3d_spirv_build_op_tr1(builder, &builder->function_stream,
SpvOpBitcast, result_type, operand);
}
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
static uint32_t vkd3d_spirv_build_op_sampled_image(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t image_id, uint32_t sampler_id)
{
return vkd3d_spirv_build_op_tr2(builder, &builder->function_stream,
SpvOpSampledImage, result_type, image_id, sampler_id);
}
static uint32_t vkd3d_spirv_build_op_image_sample_implicit_lod(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t sampled_image_id, uint32_t coordinate_id,
uint32_t image_operands, const uint32_t *operands, unsigned int operand_count)
{
unsigned int i = 0, j;
uint32_t w[10];
w[i++] = sampled_image_id;
w[i++] = coordinate_id;
if (image_operands)
{
assert(i + 1 + operand_count <= ARRAY_SIZE(w));
w[i++] = image_operands;
for (j = 0; j < operand_count; ++j)
w[i++] = operands[j];
}
return vkd3d_spirv_build_op_trv(builder, &builder->function_stream,
SpvOpImageSampleImplicitLod, result_type, w, i);
}
static uint32_t vkd3d_spirv_build_op_glsl_std450_fabs(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t operand)
{
uint32_t glsl_std450_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
return vkd3d_spirv_build_op_ext_inst(builder, result_type, glsl_std450_id,
GLSLstd450FAbs, &operand, 1);
}
static uint32_t vkd3d_spirv_build_op_glsl_std450_nclamp(struct vkd3d_spirv_builder *builder,
uint32_t result_type, uint32_t x, uint32_t min, uint32_t max)
{
uint32_t glsl_std450_id = vkd3d_spirv_get_glsl_std450_instr_set(builder);
uint32_t operands[] = {x, min, max};
return vkd3d_spirv_build_op_ext_inst(builder, result_type, glsl_std450_id,
GLSLstd450FClamp, operands, ARRAY_SIZE(operands));
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 scalar_id;
if (component_count == 1)
switch (component_type)
case VKD3D_TYPE_VOID:
return vkd3d_spirv_get_op_type_void(builder);
break;
case VKD3D_TYPE_FLOAT:
return vkd3d_spirv_get_op_type_float(builder, 32);
break;
case VKD3D_TYPE_INT:
case VKD3D_TYPE_UINT:
return vkd3d_spirv_get_op_type_int(builder, 32, component_type == VKD3D_TYPE_INT);
break;
case VKD3D_TYPE_BOOL:
return vkd3d_spirv_get_op_type_bool(builder);
break;
default:
FIXME("Unhandled component type %#x.\n", component_type);
return 0;
else
{
assert(component_type != VKD3D_TYPE_VOID);
scalar_id = vkd3d_spirv_get_type_id(builder, component_type, 1);
return vkd3d_spirv_get_op_type_vector(builder, scalar_id, component_count);
}
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;
rb_init(&builder->declarations, vkd3d_spirv_declaration_compare);
Józef Kucia
committed
void_id = vkd3d_spirv_get_op_type_void(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,
Józef Kucia
committed
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));
}
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);
rb_destroy(&builder->declarations, vkd3d_spirv_declaration_free, NULL);
vkd3d_free(builder->iface);
}
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)
{
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
uint64_t capability_mask = builder->capability_mask;
struct vkd3d_spirv_stream stream;
uint32_t *code;
unsigned int i;
size_t size;
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;
}
if (builder->ext_instr_set_glsl_450)
vkd3d_spirv_build_op_ext_inst_import(&stream, builder->ext_instr_set_glsl_450, "GLSL.std.450");
vkd3d_spirv_build_op_memory_model(&stream, SpvAddressingModelLogical, SpvMemoryModelGLSL450);
vkd3d_spirv_build_op_entry_point(&stream, builder->execution_model, builder->main_function_id,
"main", builder->iface, builder->iface_element_count);
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;
struct vkd3d_symbol_constant
{
unsigned int component_count;
enum vkd3d_component_type component_type;
union
{
float f[VKD3D_VEC4_SIZE];
uint32_t u[VKD3D_VEC4_SIZE];
} value;
};
struct vkd3d_symbol_register
{
enum vkd3d_shader_register_type type;
unsigned int idx;
};
struct vkd3d_symbol_resource
{
unsigned int idx;
};
struct vkd3d_symbol
{
struct rb_entry entry;
enum
{
VKD3D_SYMBOL_REGISTER,
} type;
union
{
struct vkd3d_symbol_constant constant;
struct vkd3d_symbol_register reg;
struct vkd3d_symbol_resource resource;
} key;
uint32_t id;
union
{
SpvStorageClass storage_class;
struct
{
enum vkd3d_component_type sampled_type;
uint32_t type_id;
} resource;
} info;
};
static int vkd3d_symbol_compare(const void *key, const struct rb_entry *entry)
{
const struct vkd3d_symbol *a = key;
const struct vkd3d_symbol *b = RB_ENTRY_VALUE(entry, const struct vkd3d_symbol, entry);
if (a->type != b->type)
return a->type - b->type;
return memcmp(&a->key, &b->key, sizeof(a->key));
}
static void vkd3d_symbol_free(struct rb_entry *entry, void *context)
{
struct vkd3d_symbol *s = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
vkd3d_free(s);
}
static void vkd3d_symbol_make_constant(struct vkd3d_symbol *symbol,
enum vkd3d_component_type component_type, unsigned int component_count, const uint32_t *values)
{
symbol->type = VKD3D_SYMBOL_CONSTANT;
memset(&symbol->key, 0, sizeof(symbol->key));
symbol->key.constant.component_type = component_type;
symbol->key.constant.component_count = component_count;
memcpy(symbol->key.constant.value.u, values, sizeof(*values) * component_count);
}
static void vkd3d_symbol_make_register(struct vkd3d_symbol *symbol,
const struct vkd3d_shader_register *reg)
{
symbol->type = VKD3D_SYMBOL_REGISTER;
memset(&symbol->key, 0, sizeof(symbol->key));
symbol->key.reg.type = reg->type;
if (reg->type != VKD3DSPR_IMMCONSTBUFFER)
symbol->key.reg.idx = reg->idx[0].offset;
static void vkd3d_symbol_make_resource(struct vkd3d_symbol *symbol,
const struct vkd3d_shader_register *reg)
{
symbol->type = VKD3D_SYMBOL_RESOURCE;
memset(&symbol->key, 0, sizeof(symbol->key));
symbol->key.resource.idx = reg->idx[0].offset;
}
static struct vkd3d_symbol *vkd3d_symbol_dup(const struct vkd3d_symbol *symbol)
{
struct vkd3d_symbol *s;
if (!(s = vkd3d_malloc(sizeof(*s))))
return NULL;
return memcpy(s, symbol, sizeof(*s));
}
struct vkd3d_control_flow_info
{
uint32_t merge_block_id;
uint32_t else_block_id;
enum
{
VKD3D_BLOCK_MAIN,
VKD3D_BLOCK_IF,
VKD3D_BLOCK_ELSE,
VKD3D_BLOCK_NONE,
} current_block;
struct vkd3d_dxbc_compiler
{
struct vkd3d_spirv_builder spirv_builder;
uint32_t options;
struct rb_tree symbol_table;
uint32_t temp_id;
unsigned int temp_count;
enum vkd3d_shader_type shader_type;
unsigned int branch_id;
struct vkd3d_control_flow_info control_flow_info;
Józef Kucia
committed
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,
Józef Kucia
committed
const struct vkd3d_shader_signature *output_signature, uint32_t compiler_options)
{
struct vkd3d_dxbc_compiler *compiler;
if (!(compiler = vkd3d_malloc(sizeof(*compiler))))
return NULL;
memset(compiler, 0, sizeof(*compiler));
Józef Kucia
committed
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;
rb_init(&compiler->symbol_table, vkd3d_symbol_compare);
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
switch (shader_version->type)
{
case VKD3D_SHADER_TYPE_VERTEX:
vkd3d_spirv_set_execution_model(&compiler->spirv_builder, SpvExecutionModelVertex);
break;
case VKD3D_SHADER_TYPE_HULL:
vkd3d_spirv_set_execution_model(&compiler->spirv_builder, SpvExecutionModelTessellationControl);
break;
case VKD3D_SHADER_TYPE_DOMAIN:
vkd3d_spirv_set_execution_model(&compiler->spirv_builder, SpvExecutionModelTessellationEvaluation);
break;
case VKD3D_SHADER_TYPE_GEOMETRY:
vkd3d_spirv_set_execution_model(&compiler->spirv_builder, SpvExecutionModelGeometry);
break;
case VKD3D_SHADER_TYPE_PIXEL:
vkd3d_spirv_set_execution_model(&compiler->spirv_builder, SpvExecutionModelFragment);
break;
case VKD3D_SHADER_TYPE_COMPUTE:
vkd3d_spirv_set_execution_model(&compiler->spirv_builder, SpvExecutionModelGLCompute);
break;
default:
ERR("Invalid shader type %#x.\n", shader_version->type);
}
compiler->shader_type = shader_version->type;
Józef Kucia
committed
compiler->output_signature = output_signature;
return compiler;
}
static void vkd3d_dxbc_compiler_put_symbol(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_symbol *symbol)
{
struct vkd3d_symbol *s;
s = vkd3d_symbol_dup(symbol);
if (rb_put(&compiler->symbol_table, s, &s->entry) == -1)
{
ERR("Failed to insert symbol entry.\n");
vkd3d_free(s);
}
}
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
static uint32_t vkd3d_dxbc_compiler_get_constant(struct vkd3d_dxbc_compiler *compiler,
enum vkd3d_component_type component_type, unsigned int component_count, const uint32_t *values)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
uint32_t component_ids[VKD3D_VEC4_SIZE];
struct vkd3d_symbol constant;
struct rb_entry *entry;
unsigned int i;
assert(0 < component_count && component_count <= VKD3D_VEC4_SIZE);
vkd3d_symbol_make_constant(&constant, component_type, component_count, values);
if ((entry = rb_get(&compiler->symbol_table, &constant)))
return RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry)->id;
switch (component_type)
{
case VKD3D_TYPE_UINT:
case VKD3D_TYPE_INT:
case VKD3D_TYPE_FLOAT:
break;
default:
FIXME("Unhandled component_type %#x.\n", component_type);
return vkd3d_spirv_build_op_undef(builder, &builder->global_stream, type_id);
}
if (component_count == 1)
{
constant.id = vkd3d_spirv_build_op_constant(builder, type_id, *values);
}
else
{
for (i = 0; i < component_count; ++i)
component_ids[i] = vkd3d_dxbc_compiler_get_constant(compiler, component_type, 1, &values[i]);
constant.id = vkd3d_spirv_build_op_constant_composite(builder, type_id, component_ids, component_count);
}
vkd3d_dxbc_compiler_put_symbol(compiler, &constant);
return constant.id;
}
static uint32_t vkd3d_dxbc_compiler_get_constant_uint(struct vkd3d_dxbc_compiler *compiler,
uint32_t value)
{
return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_TYPE_UINT, 1, &value);
}
static uint32_t vkd3d_dxbc_compiler_get_constant_float(struct vkd3d_dxbc_compiler *compiler,
float value)
{
return vkd3d_dxbc_compiler_get_constant(compiler, VKD3D_TYPE_FLOAT, 1, (uint32_t *)&value);
}
Józef Kucia
committed
static bool vkd3d_dxbc_compiler_get_register_name(char *buffer, unsigned int buffer_size,
const struct vkd3d_shader_register *reg)
{
switch (reg->type)
{
case VKD3DSPR_RESOURCE:
snprintf(buffer, buffer_size, "t%u", reg->idx[0].offset);
break;
case VKD3DSPR_SAMPLER:
snprintf(buffer, buffer_size, "s%u", reg->idx[0].offset);
break;
case VKD3DSPR_CONSTBUFFER:
Józef Kucia
committed
snprintf(buffer, buffer_size, "cb%u_%u", reg->idx[0].offset, reg->idx[1].offset);
break;
case VKD3DSPR_INPUT:
Józef Kucia
committed
snprintf(buffer, buffer_size, "v%u", reg->idx[0].offset);
break;
case VKD3DSPR_OUTPUT:
case VKD3DSPR_COLOROUT:
Józef Kucia
committed
snprintf(buffer, buffer_size, "o%u", reg->idx[0].offset);
Józef Kucia
committed
snprintf(buffer, buffer_size, "vThreadID");
case VKD3DSPR_LOCALTHREADID:
snprintf(buffer, buffer_size, "vThreadIDInGroup");
break;
default:
FIXME("Unhandled register %#x.\n", reg->type);
Józef Kucia
committed
snprintf(buffer, buffer_size, "unrecognized_%#x", reg->type);
return false;
}
return true;
}
static void vkd3d_dxbc_compiler_emit_register_debug_name(struct vkd3d_spirv_builder *builder,
uint32_t id, const struct vkd3d_shader_register *reg)
{
char debug_name[256];
Józef Kucia
committed
if (vkd3d_dxbc_compiler_get_register_name(debug_name, ARRAY_SIZE(debug_name), reg))
vkd3d_spirv_build_op_name(builder, id, debug_name);
}
static uint32_t vkd3d_dxbc_compiler_emit_variable(struct vkd3d_dxbc_compiler *compiler,
struct vkd3d_spirv_stream *stream, SpvStorageClass storage_class,
enum vkd3d_component_type component_type, unsigned int component_count)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id;
type_id = vkd3d_spirv_get_type_id(builder, component_type, component_count);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, storage_class, type_id);
return vkd3d_spirv_build_op_variable(builder, stream, ptr_type_id, storage_class, 0);
static uint32_t vkd3d_dxbc_compiler_emit_undef(struct vkd3d_dxbc_compiler *compiler,
struct vkd3d_spirv_stream *stream, const struct vkd3d_shader_register *reg)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id;
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, SpvStorageClassPrivate, type_id);
return vkd3d_spirv_build_op_undef(builder, stream, ptr_type_id);
}
Józef Kucia
committed
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
static uint32_t vkd3d_dxbc_compiler_emit_load_src(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_src_param *src, DWORD write_mask);
static uint32_t vkd3d_dxbc_compiler_emit_register_addressing(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register_index *reg_index)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, addr_id;
if (!reg_index->rel_addr)
return vkd3d_dxbc_compiler_get_constant_uint(compiler, reg_index->offset);
addr_id = vkd3d_dxbc_compiler_emit_load_src(compiler, reg_index->rel_addr, VKD3DSP_WRITEMASK_0);
if (reg_index->offset)
{
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_UINT, 1);
addr_id = vkd3d_spirv_build_op_iadd(builder, type_id,
addr_id, vkd3d_dxbc_compiler_get_constant_uint(compiler, reg_index->offset));
}
return addr_id;
}
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
struct vkd3d_dxbc_register_info
{
uint32_t id;
SpvStorageClass storage_class;
};
static void vkd3d_dxbc_compiler_get_register_info(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, struct vkd3d_dxbc_register_info *register_info)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_symbol reg_symbol, *symbol;
struct rb_entry *entry;
assert(reg->type != VKD3DSPR_IMMCONST);
if (reg->idx[0].rel_addr || reg->idx[1].rel_addr)
FIXME("Relative indexing not implemented.\n");
if (reg->type == VKD3DSPR_TEMP)
{
assert(reg->idx[0].offset < compiler->temp_count);
register_info->id = compiler->temp_id + reg->idx[0].offset;
register_info->storage_class = SpvStorageClassFunction;
return;
}
vkd3d_symbol_make_register(®_symbol, reg);
entry = rb_get(&compiler->symbol_table, ®_symbol);
assert(entry);
symbol = RB_ENTRY_VALUE(entry, struct vkd3d_symbol, entry);
register_info->id = symbol->id;
register_info->storage_class = symbol->info.storage_class;
if (reg->type == VKD3DSPR_CONSTBUFFER)
{
uint32_t type_id, ptr_type_id;
uint32_t indexes[] =
{
vkd3d_dxbc_compiler_get_constant_uint(compiler, 0),
vkd3d_dxbc_compiler_get_constant_uint(compiler, reg->idx[1].offset),
};
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, register_info->storage_class, type_id);
register_info->id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
register_info->id, indexes, ARRAY_SIZE(indexes));
}
else if (reg->type == VKD3DSPR_IMMCONSTBUFFER)
{
Józef Kucia
committed
uint32_t indexes[] = {vkd3d_dxbc_compiler_emit_register_addressing(compiler, ®->idx[0])};
uint32_t type_id, ptr_type_id;
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, register_info->storage_class, type_id);
register_info->id = vkd3d_spirv_build_op_access_chain(builder, ptr_type_id,
register_info->id, indexes, ARRAY_SIZE(indexes));
}
}
static uint32_t vkd3d_dxbc_compiler_get_register_id(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_dxbc_register_info register_info;
switch (reg->type)
{
case VKD3DSPR_TEMP:
case VKD3DSPR_INPUT:
case VKD3DSPR_OUTPUT:
case VKD3DSPR_COLOROUT:
case VKD3DSPR_CONSTBUFFER:
vkd3d_dxbc_compiler_get_register_info(compiler, reg, ®ister_info);
return register_info.id;
case VKD3DSPR_IMMCONST:
ERR("Unexpected register type %#x.\n", reg->type);
return vkd3d_dxbc_compiler_emit_undef(compiler, &builder->global_stream, reg);
default:
FIXME("Unhandled register type %#x.\n", reg->type);
return vkd3d_dxbc_compiler_emit_undef(compiler, &builder->global_stream, reg);
}
}
Józef Kucia
committed
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
static uint32_t vkd3d_dxbc_compiler_emit_swizzle(struct vkd3d_dxbc_compiler *compiler,
uint32_t val_id, DWORD swizzle, DWORD write_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int i, component_idx, component_count;
uint32_t type_id, components[VKD3D_VEC4_SIZE];
if (swizzle == VKD3DSP_NOSWIZZLE && write_mask == VKD3DSP_WRITEMASK_ALL)
return val_id;
component_count = vkd3d_write_mask_component_count(write_mask);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, component_count);
if (component_count == 1)
{
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
return vkd3d_spirv_build_op_composite_extract(builder, type_id, val_id, &component_idx, 1);
}
for (i = 0, component_idx = 0; i < VKD3D_VEC4_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
components[component_idx++] = vkd3d_swizzle_get_component(swizzle, i);
}
return vkd3d_spirv_build_op_vector_shuffle(builder,
type_id, val_id, val_id, components, component_count);
}
static uint32_t vkd3d_dxbc_compiler_emit_load_constant(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
{
unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
uint32_t values[VKD3D_VEC4_SIZE];
unsigned int i, j;
assert(reg->type == VKD3DSPR_IMMCONST);
if (reg->immconst_type == VKD3D_IMMCONST_SCALAR)
assert(component_count == 1);
values[0] = *reg->u.immconst_data;
for (i = 0, j = 0; i < VKD3D_VEC4_SIZE; ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
values[j++] = reg->u.immconst_data[vkd3d_swizzle_get_component(swizzle, i)];
}
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
}
return vkd3d_dxbc_compiler_get_constant(compiler,
vkd3d_component_type_from_data_type(reg->data_type), component_count, values);
}
static uint32_t vkd3d_dxbc_compiler_emit_load_scalar(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id, indexes[1], chain_id, val_id;
struct vkd3d_dxbc_register_info reg_info;
unsigned int component_idx;
assert(reg->type != VKD3DSPR_IMMCONST);
assert(vkd3d_write_mask_component_count(write_mask) == 1);
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
component_idx = vkd3d_swizzle_get_component(swizzle, component_idx);
vkd3d_dxbc_compiler_get_register_info(compiler, reg, ®_info);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 1);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, reg_info.storage_class, type_id);
indexes[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
chain_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder,
ptr_type_id, reg_info.id, indexes, ARRAY_SIZE(indexes));
val_id = vkd3d_spirv_build_op_load(builder, type_id, chain_id, SpvMemoryAccessMaskNone);
if (reg->data_type != VKD3D_DATA_FLOAT)
{
type_id = vkd3d_spirv_get_type_id(builder,
vkd3d_component_type_from_data_type(reg->data_type), 1);
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
}
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_load_reg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD swizzle, DWORD write_mask)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
Józef Kucia
committed
uint32_t src_id, type_id, val_id;
unsigned int component_count;
if (reg->type == VKD3DSPR_IMMCONST)
return vkd3d_dxbc_compiler_emit_load_constant(compiler, reg, swizzle, write_mask);
component_count = vkd3d_write_mask_component_count(write_mask);
if (component_count == 1)
return vkd3d_dxbc_compiler_emit_load_scalar(compiler, reg, swizzle, write_mask);
src_id = vkd3d_dxbc_compiler_get_register_id(compiler, reg);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
val_id = vkd3d_spirv_build_op_load(builder, type_id, src_id, SpvMemoryAccessMaskNone);
Józef Kucia
committed
val_id = vkd3d_dxbc_compiler_emit_swizzle(compiler, val_id, swizzle, write_mask);
if (reg->data_type != VKD3D_DATA_FLOAT)
{
type_id = vkd3d_spirv_get_type_id(builder,
vkd3d_component_type_from_data_type(reg->data_type), component_count);
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
}
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_abs(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
if (reg->data_type == VKD3D_DATA_FLOAT)
{
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, component_count);
return vkd3d_spirv_build_op_glsl_std450_fabs(builder, type_id, val_id);
}
FIXME("Unhandled data type %#x.\n", reg->data_type);
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_neg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id;
type_id = vkd3d_spirv_get_type_id(builder,
vkd3d_component_type_from_data_type(reg->data_type), component_count);
if (reg->data_type == VKD3D_DATA_FLOAT)
return vkd3d_spirv_build_op_fnegate(builder, type_id, val_id);
else if (reg->data_type == VKD3D_DATA_INT)
return vkd3d_spirv_build_op_snegate(builder, type_id, val_id);
FIXME("Unhandled data type %#x.\n", reg->data_type);
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_src_modifier(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask,
enum vkd3d_shader_src_modifier modifier, uint32_t val_id)
{
switch (modifier)
{
case VKD3DSPSM_NONE:
break;
case VKD3DSPSM_NEG:
return vkd3d_dxbc_compiler_emit_neg(compiler, reg, write_mask, val_id);
case VKD3DSPSM_ABS:
return vkd3d_dxbc_compiler_emit_abs(compiler, reg, write_mask, val_id);
case VKD3DSPSM_ABSNEG:
val_id = vkd3d_dxbc_compiler_emit_abs(compiler, reg, write_mask, val_id);
return vkd3d_dxbc_compiler_emit_neg(compiler, reg, write_mask, val_id);
default:
FIXME("Unhandled src modifier %#x.\n", modifier);
break;
}
return val_id;
}
static uint32_t vkd3d_dxbc_compiler_emit_load_src(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_src_param *src, DWORD write_mask)
{
uint32_t val_id;
val_id = vkd3d_dxbc_compiler_emit_load_reg(compiler, &src->reg, src->swizzle, write_mask);
return vkd3d_dxbc_compiler_emit_src_modifier(compiler, &src->reg, write_mask, src->modifiers, val_id);
}
static void vkd3d_dxbc_compiler_emit_store_scalar(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, ptr_type_id, chain_id, index[1];
struct vkd3d_dxbc_register_info reg_info;
unsigned int component_idx;
assert(reg->type != VKD3DSPR_IMMCONST);
vkd3d_dxbc_compiler_get_register_info(compiler, reg, ®_info);
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, 1);
ptr_type_id = vkd3d_spirv_get_op_type_pointer(builder, reg_info.storage_class, type_id);
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
component_idx = vkd3d_write_mask_get_component_idx(write_mask);
index[0] = vkd3d_dxbc_compiler_get_constant_uint(compiler, component_idx);
chain_id = vkd3d_spirv_build_op_in_bounds_access_chain(builder,
ptr_type_id, reg_info.id, index, ARRAY_SIZE(index));
vkd3d_spirv_build_op_store(builder, chain_id, val_id, SpvMemoryAccessMaskNone);
}
static void vkd3d_dxbc_compiler_emit_store_reg(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int i, component_idx, component_count;
uint32_t components[VKD3D_VEC4_SIZE];
uint32_t reg_id;
assert(reg->type != VKD3DSPR_IMMCONST);
component_count = vkd3d_write_mask_component_count(write_mask);
if (reg->data_type != VKD3D_DATA_FLOAT)
{
uint32_t type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, component_count);
val_id = vkd3d_spirv_build_op_bitcast(builder, type_id, val_id);
}
if (component_count == 1)
return vkd3d_dxbc_compiler_emit_store_scalar(compiler, reg, write_mask, val_id);
reg_id = vkd3d_dxbc_compiler_get_register_id(compiler, reg);
if (component_count != VKD3D_VEC4_SIZE)
{
uint32_t type_id, reg_val_id;
type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
reg_val_id = vkd3d_spirv_build_op_load(builder, type_id, reg_id, SpvMemoryAccessMaskNone);
for (i = 0, component_idx = 0; i < ARRAY_SIZE(components); ++i)
{
if (write_mask & (VKD3DSP_WRITEMASK_0 << i))
components[i] = VKD3D_VEC4_SIZE + component_idx++;
else
components[i] = i;
}
val_id = vkd3d_spirv_build_op_vector_shuffle(builder,
type_id, reg_val_id, val_id, components, ARRAY_SIZE(components));
}
vkd3d_spirv_build_op_store(builder, reg_id, val_id, SpvMemoryAccessMaskNone);
}
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
static uint32_t vkd3d_dxbc_compiler_emit_sat(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_register *reg, DWORD write_mask, uint32_t val_id)
{
static const float zero[] = {0.0f, 0.0f, 0.0f, 0.0f};
static const float one[] = {1.0f, 1.0f, 1.0f, 1.0f};
unsigned int component_count = vkd3d_write_mask_component_count(write_mask);
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
uint32_t type_id, zero_id, one_id;
zero_id = vkd3d_dxbc_compiler_get_constant(compiler,
VKD3D_TYPE_FLOAT, component_count, (const uint32_t *)zero);
one_id = vkd3d_dxbc_compiler_get_constant(compiler,
VKD3D_TYPE_FLOAT, component_count, (const uint32_t *)one);
type_id = vkd3d_spirv_get_type_id(builder,
vkd3d_component_type_from_data_type(reg->data_type), component_count);
if (reg->data_type == VKD3D_DATA_FLOAT)
return vkd3d_spirv_build_op_glsl_std450_nclamp(builder, type_id, val_id, zero_id, one_id);
FIXME("Unhandled data type %#x.\n", reg->data_type);
return val_id;
}
static void vkd3d_dxbc_compiler_emit_store_dst(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_dst_param *dst, uint32_t val_id)
{
assert(!(dst->modifiers & ~VKD3DSPDM_SATURATE));
if (dst->modifiers & VKD3DSPDM_SATURATE)
val_id = vkd3d_dxbc_compiler_emit_sat(compiler, &dst->reg, dst->write_mask, val_id);
vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id);
}
static enum vkd3d_component_type vkd3d_component_type_for_register(enum vkd3d_shader_register_type reg_type,
enum vkd3d_shader_input_sysval_semantic sysval)
{
if (reg_type == VKD3DSPR_THREADID
|| reg_type == VKD3DSPR_LOCALTHREADID)
return VKD3D_TYPE_INT;
switch (sysval)
{
case VKD3D_SIV_NONE:
case VKD3D_SIV_POSITION:
return VKD3D_TYPE_FLOAT;
case VKD3D_SIV_VERTEX_ID:
return VKD3D_TYPE_INT;
default:
FIXME("Unhandled builtin (register type %#x, semantic %#x).\n", reg_type, sysval);
return VKD3D_TYPE_FLOAT;
}
}
static unsigned int vkd3d_component_count_for_register(enum vkd3d_shader_register_type reg_type,
Józef Kucia
committed
enum vkd3d_shader_input_sysval_semantic sysval)
{
/* The Vulkan spec says:
*
* "The variable decorated with GlobalInvocationId must be declared as a
* three-component vector of 32-bit integers."
*
* "The variable decorated with LocalInvocationId must be declared as a
* three-component vector of 32-bit integers."
if (reg_type == VKD3DSPR_THREADID
|| reg_type == VKD3DSPR_LOCALTHREADID)
Józef Kucia
committed
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
switch (sysval)
{
case VKD3D_SIV_NONE:
return 0;
case VKD3D_SIV_POSITION:
/* The Vulkan spec says:
*
* "The variable decorated with FragCoord must be declared as a
* four-component vector of 32-bit floating-point values."
*
* "Any variable decorated with Position must be declared as a
* four-component vector of 32-bit floating-point values."
*/
return 4;
case VKD3D_SIV_VERTEX_ID:
/* The Vulkan spec says:
*
* "The variable decorated with VertexIndex must be declared as a
* scalar 32-bit integer."
*/
return 1;
default:
FIXME("Unhandled builtin (register type %#x, semantic %#x).\n", reg_type, sysval);
Józef Kucia
committed
return 0;
}
}
static void vkd3d_dxbc_compiler_decorate_builtin(struct vkd3d_dxbc_compiler *compiler,
uint32_t target_id, enum vkd3d_shader_register_type reg_type,
enum vkd3d_shader_input_sysval_semantic sysval)
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
SpvBuiltIn builtin;
switch (sysval)
{
case VKD3D_SIV_POSITION:
if (compiler->shader_type == VKD3D_SHADER_TYPE_PIXEL)
builtin = SpvBuiltInFragCoord;
else
builtin = SpvBuiltInPosition;
break;
case VKD3D_SIV_VERTEX_ID:
builtin = SpvBuiltInVertexIndex;
break;
default:
if (reg_type == VKD3DSPR_THREADID)
{
builtin = SpvBuiltInGlobalInvocationId;
}
else if (reg_type == VKD3DSPR_LOCALTHREADID)
{
builtin = SpvBuiltInLocalInvocationId;
}
else
{
FIXME("Unhandled builtin (register type %#x, semantic %#x).\n", reg_type, sysval);
return;
}
break;
}
vkd3d_spirv_build_op_decorate1(builder, target_id, SpvDecorationBuiltIn, builtin);
}
static uint32_t vkd3d_dxbc_compiler_emit_input(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, input_component_count;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
enum vkd3d_component_type component_type;
uint32_t val_id = 0, input_id, var_id;
struct vkd3d_symbol reg_symbol;
SpvStorageClass storage_class;
Józef Kucia
committed
struct rb_entry *entry = NULL;
bool use_private_var = false;
component_idx = vkd3d_write_mask_get_component_idx(dst->write_mask);
Józef Kucia
committed
component_count = vkd3d_write_mask_component_count(dst->write_mask);
component_type = vkd3d_component_type_for_register(dst->reg.type, sysval);
/* vThreadIDInGroupFlattened is declared with no write mask in shader
* bytecode generated by fxc. */
if (!dst->write_mask)
component_count = 1;
if (!(input_component_count = vkd3d_component_count_for_register(dst->reg.type, sysval)))
Józef Kucia
committed
input_component_count = component_count;
assert(component_count <= input_component_count);
Józef Kucia
committed
storage_class = SpvStorageClassInput;
input_id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
Józef Kucia
committed
storage_class, component_type, input_component_count);
vkd3d_spirv_add_iface_variable(builder, input_id);
if (dst->reg.type == VKD3DSPR_THREADID || dst->reg.type == VKD3DSPR_LOCALTHREADID
|| sysval)
vkd3d_dxbc_compiler_decorate_builtin(compiler, input_id, dst->reg.type, sysval);
if (component_idx)
FIXME("Unhandled component index %u.\n", component_idx);
vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationLocation, dst->reg.idx[0].offset);
if (component_idx)
vkd3d_spirv_build_op_decorate1(builder, input_id, SpvDecorationComponent, component_idx);
}
if (component_type != VKD3D_TYPE_FLOAT)
{
Józef Kucia
committed
uint32_t float_type_id = vkd3d_spirv_get_type_id(builder, VKD3D_TYPE_FLOAT, input_component_count);
val_id = vkd3d_spirv_build_op_bitcast(builder, float_type_id, input_id);
use_private_var = true;
Józef Kucia
committed
else if (component_count != VKD3D_VEC4_SIZE)
Józef Kucia
committed
uint32_t type_id = vkd3d_spirv_get_type_id(builder, component_type, input_component_count);
val_id = vkd3d_spirv_build_op_load(builder, type_id, input_id, SpvMemoryAccessMaskNone);
use_private_var = true;
Józef Kucia
committed
vkd3d_symbol_make_register(®_symbol, &dst->reg);
if (!use_private_var)
{
var_id = input_id;
}
else if (!(entry = rb_get(&compiler->symbol_table, ®_symbol)))
{
storage_class = SpvStorageClassPrivate;
var_id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
storage_class, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
}
Józef Kucia
committed
if (!entry)
{
reg_symbol.id = var_id;
reg_symbol.info.storage_class = storage_class;
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
Józef Kucia
committed
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, &dst->reg);
}
if (use_private_var)
{
assert(val_id);
vkd3d_dxbc_compiler_emit_store_reg(compiler, &dst->reg, dst->write_mask, val_id);
return input_id;
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)
{
Józef Kucia
committed
unsigned int component_idx, component_count, output_component_count;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
Józef Kucia
committed
const struct vkd3d_shader_signature_element *signature_element;
const struct vkd3d_shader_register *reg = &dst->reg;
Józef Kucia
committed
const struct vkd3d_shader_signature *signature;
enum vkd3d_component_type component_type;
struct vkd3d_symbol reg_symbol;
SpvStorageClass storage_class;
Józef Kucia
committed
struct rb_entry *entry = NULL;
unsigned int signature_idx;
bool use_private_variable;
uint32_t id, var_id;
Józef Kucia
committed
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
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);
}
Józef Kucia
committed
storage_class = SpvStorageClassOutput;
id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->global_stream,
Józef Kucia
committed
storage_class, component_type, component_count);
vkd3d_spirv_add_iface_variable(builder, id);
if (sysval)
Józef Kucia
committed
{
vkd3d_dxbc_compiler_decorate_builtin(compiler, id, reg->type, sysval);
if (component_idx)
FIXME("Unhandled component index %u.\n", component_idx);
}
Józef Kucia
committed
{
vkd3d_spirv_build_op_decorate1(builder, id, SpvDecorationLocation, reg->idx[0].offset);
Józef Kucia
committed
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;
}
Józef Kucia
committed
if ((use_private_variable = component_type != VKD3D_TYPE_FLOAT || component_count != VKD3D_VEC4_SIZE))
storage_class = SpvStorageClassPrivate;
Józef Kucia
committed
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
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;
}
static void vkd3d_dxbc_compiler_emit_dcl_temps(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
unsigned int i;
Józef Kucia
committed
uint32_t id;
/* FIXME: Make sure that function variables are declared at the beginning
* of the first block in the function. Otherwise, we'll produce invalid
* SPIR-V code. */
assert(!compiler->temp_count);
compiler->temp_count = instruction->declaration.count;
for (i = 0; i < compiler->temp_count; ++i)
{
Józef Kucia
committed
id = vkd3d_dxbc_compiler_emit_variable(compiler, &builder->function_stream,
SpvStorageClassFunction, VKD3D_TYPE_FLOAT, VKD3D_VEC4_SIZE);
if (!i)
compiler->temp_id = id;
assert(id == compiler->temp_id + i);
vkd3d_spirv_build_op_name(builder, id, "r%u", i);
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
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_src_param *src = &instruction->declaration.src;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_symbol reg_symbol;
unsigned int cb_idx, cb_size;
assert(!(instruction->flags & ~VKD3DSI_INDEXED_DYNAMIC));
if (instruction->flags & VKD3DSI_INDEXED_DYNAMIC)
vkd3d_spirv_enable_capability(builder, SpvCapabilityUniformBufferArrayDynamicIndexing);
cb_idx = src->reg.idx[0].offset;
cb_size = src->reg.idx[1].offset;
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);
vkd3d_spirv_build_op_decorate1(builder, array_type_id, SpvDecorationArrayStride, 16);
struct_id = vkd3d_spirv_build_op_type_struct(builder, &array_type_id, 1);
vkd3d_spirv_build_op_decorate(builder, struct_id, SpvDecorationBlock, NULL, 0);
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);
var_id = vkd3d_spirv_build_op_variable(builder, &builder->global_stream,
pointer_type_id, SpvStorageClassUniform, 0);
vkd3d_spirv_build_op_decorate1(builder, var_id, SpvDecorationDescriptorSet, 0);
vkd3d_spirv_build_op_decorate1(builder, var_id, SpvDecorationBinding, cb_idx);
vkd3d_dxbc_compiler_emit_register_debug_name(builder, var_id, &src->reg);
vkd3d_symbol_make_register(®_symbol, &src->reg);
reg_symbol.id = var_id;
reg_symbol.info.storage_class = SpvStorageClassUniform;
vkd3d_dxbc_compiler_put_symbol(compiler, ®_symbol);
}
static void vkd3d_dxbc_compiler_emit_dcl_immediate_constant_buffer(struct vkd3d_dxbc_compiler *compiler,
const struct vkd3d_shader_instruction *instruction)
{
const struct vkd3d_shader_immediate_constant_buffer *icb = instruction->declaration.icb;
uint32_t *elements, length_id, type_id, const_id, ptr_type_id, icb_id;
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
struct vkd3d_shader_register reg;
struct vkd3d_symbol reg_symbol;
unsigned int i;
if (!(elements = vkd3d_calloc(icb->vec4_count, sizeof(*elements))))
return;
for (i = 0; i < icb->vec4_count; ++i)
elements[i] = vkd3d_dxbc_compiler_get_constant(compiler,
Loading
Loading full blame...