SpvId GLSL_std_450;
gl_shader_stage stage;
- int var_location;
SpvId ubos[128];
size_t num_ubos;
+ SpvId image_types[PIPE_MAX_SAMPLERS];
SpvId samplers[PIPE_MAX_SAMPLERS];
size_t num_samplers;
SpvId entry_ifaces[PIPE_MAX_SHADER_INPUTS * 4 + PIPE_MAX_SHADER_OUTPUTS * 4];
size_t num_blocks;
bool block_started;
SpvId loop_break, loop_cont;
+
+ SpvId front_face_var, instance_id_var, vertex_id_var;
};
static SpvId
-get_fvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
- const float values[]);
+get_fvec_constant(struct ntv_context *ctx, unsigned bit_size,
+ unsigned num_components, float value);
+
+static SpvId
+get_uvec_constant(struct ntv_context *ctx, unsigned bit_size,
+ unsigned num_components, uint32_t value);
static SpvId
-get_uvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
- const uint32_t values[]);
+get_ivec_constant(struct ntv_context *ctx, unsigned bit_size,
+ unsigned num_components, int32_t value);
static SpvId
emit_unop(struct ntv_context *ctx, SpvOp op, SpvId type, SpvId src);
return ctx->block_ids[block->index];
}
+static SpvId
+emit_float_const(struct ntv_context *ctx, int bit_size, float value)
+{
+ assert(bit_size == 32);
+ return spirv_builder_const_float(&ctx->builder, bit_size, value);
+}
+
+static SpvId
+emit_uint_const(struct ntv_context *ctx, int bit_size, uint32_t value)
+{
+ assert(bit_size == 32);
+ return spirv_builder_const_uint(&ctx->builder, bit_size, value);
+}
+
+static SpvId
+emit_int_const(struct ntv_context *ctx, int bit_size, int32_t value)
+{
+ assert(bit_size == 32);
+ return spirv_builder_const_int(&ctx->builder, bit_size, value);
+}
+
static SpvId
get_fvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
{
static SpvId
get_ivec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
{
- assert(bit_size == 32); // only 32-bit ints supported so far
+ assert(bit_size == 1 || bit_size == 32); // only 32-bit ints supported so far
- SpvId int_type = spirv_builder_type_int(&ctx->builder, bit_size);
+ SpvId int_type = spirv_builder_type_int(&ctx->builder, MAX2(bit_size, 32));
if (num_components > 1)
return spirv_builder_type_vector(&ctx->builder, int_type,
num_components);
static SpvId
get_uvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
{
- assert(bit_size == 32); // only 32-bit uints supported so far
+ assert(bit_size == 1 || bit_size == 32); // only 32-bit uints supported so far
- SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
+ SpvId uint_type = spirv_builder_type_uint(&ctx->builder, MAX2(bit_size, 32));
if (num_components > 1)
return spirv_builder_type_vector(&ctx->builder, uint_type,
num_components);
get_glsl_basetype(struct ntv_context *ctx, enum glsl_base_type type)
{
switch (type) {
+ case GLSL_TYPE_BOOL:
+ return spirv_builder_type_bool(&ctx->builder);
+
case GLSL_TYPE_FLOAT:
return spirv_builder_type_float(&ctx->builder, 32);
get_glsl_basetype(ctx, glsl_get_base_type(type)),
glsl_get_vector_elements(type));
+ if (glsl_type_is_array(type)) {
+ SpvId ret = spirv_builder_type_array(&ctx->builder,
+ get_glsl_type(ctx, glsl_get_array_element(type)),
+ emit_uint_const(ctx, 32, glsl_get_length(type)));
+ uint32_t stride = glsl_get_explicit_stride(type);
+ if (stride)
+ spirv_builder_emit_array_stride(&ctx->builder, ret, stride);
+ return ret;
+ }
+
+
unreachable("we shouldn't get here, I think...");
}
spirv_builder_emit_name(&ctx->builder, var_id, var->name);
if (ctx->stage == MESA_SHADER_FRAGMENT) {
- if (var->data.location >= VARYING_SLOT_VAR0 ||
- (var->data.location >= VARYING_SLOT_COL0 &&
- var->data.location <= VARYING_SLOT_TEX7)) {
+ if (var->data.location >= VARYING_SLOT_VAR0)
+ spirv_builder_emit_location(&ctx->builder, var_id,
+ var->data.location -
+ VARYING_SLOT_VAR0 +
+ VARYING_SLOT_TEX0);
+ else if ((var->data.location >= VARYING_SLOT_COL0 &&
+ var->data.location <= VARYING_SLOT_TEX7) ||
+ var->data.location == VARYING_SLOT_BFC0 ||
+ var->data.location == VARYING_SLOT_BFC1) {
spirv_builder_emit_location(&ctx->builder, var_id,
- ctx->var_location++);
+ var->data.location);
} else {
switch (var->data.location) {
case VARYING_SLOT_POS:
break;
default:
- unreachable("unknown varying slot");
+ debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
+ unreachable("unexpected varying slot");
}
}
} else {
if (ctx->stage == MESA_SHADER_VERTEX) {
- if (var->data.location >= VARYING_SLOT_VAR0 ||
- (var->data.location >= VARYING_SLOT_COL0 &&
- var->data.location <= VARYING_SLOT_TEX7)) {
+ if (var->data.location >= VARYING_SLOT_VAR0)
spirv_builder_emit_location(&ctx->builder, var_id,
- ctx->var_location++);
+ var->data.location -
+ VARYING_SLOT_VAR0 +
+ VARYING_SLOT_TEX0);
+ else if ((var->data.location >= VARYING_SLOT_COL0 &&
+ var->data.location <= VARYING_SLOT_TEX7) ||
+ var->data.location == VARYING_SLOT_BFC0 ||
+ var->data.location == VARYING_SLOT_BFC1) {
+ spirv_builder_emit_location(&ctx->builder, var_id,
+ var->data.location);
} else {
switch (var->data.location) {
case VARYING_SLOT_POS:
spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointSize);
break;
+ case VARYING_SLOT_CLIP_DIST0:
+ assert(glsl_type_is_array(var->type));
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInClipDistance);
+ break;
+
default:
- unreachable("unknown varying slot");
+ debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
+ unreachable("unexpected varying slot");
}
}
} else if (ctx->stage == MESA_SHADER_FRAGMENT) {
- switch (var->data.location) {
- case FRAG_RESULT_DEPTH:
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragDepth);
- break;
-
- default:
+ if (var->data.location >= FRAG_RESULT_DATA0)
spirv_builder_emit_location(&ctx->builder, var_id,
- var->data.driver_location);
+ var->data.location - FRAG_RESULT_DATA0);
+ else {
+ switch (var->data.location) {
+ case FRAG_RESULT_COLOR:
+ spirv_builder_emit_location(&ctx->builder, var_id, 0);
+ break;
+
+ case FRAG_RESULT_DEPTH:
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragDepth);
+ break;
+
+ default:
+ spirv_builder_emit_location(&ctx->builder, var_id,
+ var->data.driver_location);
+ }
}
}
return SpvDim1D;
case GLSL_SAMPLER_DIM_2D:
return SpvDim2D;
- case GLSL_SAMPLER_DIM_RECT:
- return SpvDimRect;
- case GLSL_SAMPLER_DIM_CUBE:
- return SpvDimCube;
case GLSL_SAMPLER_DIM_3D:
return SpvDim3D;
+ case GLSL_SAMPLER_DIM_CUBE:
+ return SpvDimCube;
+ case GLSL_SAMPLER_DIM_RECT:
+ return SpvDimRect;
+ case GLSL_SAMPLER_DIM_BUF:
+ return SpvDimBuffer;
+ case GLSL_SAMPLER_DIM_EXTERNAL:
+ return SpvDim2D; /* seems dodgy... */
case GLSL_SAMPLER_DIM_MS:
*is_ms = true;
return SpvDim2D;
static void
emit_sampler(struct ntv_context *ctx, struct nir_variable *var)
{
+ const struct glsl_type *type = glsl_without_array(var->type);
+
bool is_ms;
- SpvDim dimension = type_to_dim(glsl_get_sampler_dim(var->type), &is_ms);
- SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
- SpvId image_type = spirv_builder_type_image(&ctx->builder, float_type,
- dimension, false, glsl_sampler_type_is_array(var->type), is_ms, 1,
- SpvImageFormatUnknown);
+ SpvDim dimension = type_to_dim(glsl_get_sampler_dim(type), &is_ms);
+
+ SpvId result_type = get_glsl_basetype(ctx, glsl_get_sampler_result_type(type));
+ SpvId image_type = spirv_builder_type_image(&ctx->builder, result_type,
+ dimension, false,
+ glsl_sampler_type_is_array(type),
+ is_ms, 1,
+ SpvImageFormatUnknown);
SpvId sampled_type = spirv_builder_type_sampled_image(&ctx->builder,
image_type);
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassUniformConstant,
sampled_type);
- SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
- SpvStorageClassUniformConstant);
- if (var->name)
- spirv_builder_emit_name(&ctx->builder, var_id, var->name);
+ if (glsl_type_is_array(var->type)) {
+ for (int i = 0; i < glsl_get_length(var->type); ++i) {
+ SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
+ SpvStorageClassUniformConstant);
- assert(ctx->num_samplers < ARRAY_SIZE(ctx->samplers));
- ctx->samplers[ctx->num_samplers++] = var_id;
+ if (var->name) {
+ char element_name[100];
+ snprintf(element_name, sizeof(element_name), "%s_%d", var->name, i);
+ spirv_builder_emit_name(&ctx->builder, var_id, var->name);
+ }
- spirv_builder_emit_descriptor_set(&ctx->builder, var_id,
- var->data.descriptor_set);
- spirv_builder_emit_binding(&ctx->builder, var_id, var->data.binding);
+ assert(ctx->num_samplers < ARRAY_SIZE(ctx->image_types));
+ ctx->image_types[ctx->num_samplers] = image_type;
+
+ assert(ctx->num_samplers < ARRAY_SIZE(ctx->samplers));
+ ctx->samplers[ctx->num_samplers++] = var_id;
+
+ spirv_builder_emit_descriptor_set(&ctx->builder, var_id,
+ var->data.descriptor_set);
+ spirv_builder_emit_binding(&ctx->builder, var_id, var->data.binding);
+ }
+ } else {
+ SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
+ SpvStorageClassUniformConstant);
+
+ if (var->name)
+ spirv_builder_emit_name(&ctx->builder, var_id, var->name);
+
+ assert(ctx->num_samplers < ARRAY_SIZE(ctx->image_types));
+ ctx->image_types[ctx->num_samplers] = image_type;
+
+ assert(ctx->num_samplers < ARRAY_SIZE(ctx->samplers));
+ ctx->samplers[ctx->num_samplers++] = var_id;
+
+ spirv_builder_emit_descriptor_set(&ctx->builder, var_id,
+ var->data.descriptor_set);
+ spirv_builder_emit_binding(&ctx->builder, var_id, var->data.binding);
+ }
}
static void
{
uint32_t size = glsl_count_attribute_slots(var->type, false);
SpvId vec4_type = get_uvec_type(ctx, 32, 4);
- SpvId array_length = spirv_builder_const_uint(&ctx->builder, 32, size);
+ SpvId array_length = emit_uint_const(ctx, 32, size);
SpvId array_type = spirv_builder_type_array(&ctx->builder, vec4_type,
array_length);
spirv_builder_emit_array_stride(&ctx->builder, array_type, 16);
static void
emit_uniform(struct ntv_context *ctx, struct nir_variable *var)
{
- if (glsl_type_is_sampler(var->type))
- emit_sampler(ctx, var);
- else if (var->interface_type)
+ if (var->data.mode == nir_var_mem_ubo)
emit_ubo(ctx, var);
+ else {
+ assert(var->data.mode == nir_var_uniform);
+ if (glsl_type_is_sampler(glsl_without_array(var->type)))
+ emit_sampler(ctx, var);
+ }
}
static SpvId
return def;
int bit_size = nir_src_bit_size(alu->src[src].src);
+ assert(bit_size == 1 || bit_size == 32);
- SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
+ SpvId uint_type = spirv_builder_type_uint(&ctx->builder, MAX2(bit_size, 32));
if (used_channels == 1) {
uint32_t indices[] = { alu->src[src].swizzle[0] };
return spirv_builder_emit_composite_extract(&ctx->builder, uint_type,
ctx->defs[ssa->index] = result;
}
+static SpvId
+emit_select(struct ntv_context *ctx, SpvId type, SpvId cond,
+ SpvId if_true, SpvId if_false)
+{
+ return emit_triop(ctx, SpvOpSelect, type, cond, if_true, if_false);
+}
+
static SpvId
bvec_to_uvec(struct ntv_context *ctx, SpvId value, unsigned num_components)
{
SpvId otype = get_uvec_type(ctx, 32, num_components);
- uint32_t zeros[4] = { 0, 0, 0, 0 };
- uint32_t ones[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
- SpvId zero = get_uvec_constant(ctx, 32, num_components, zeros);
- SpvId one = get_uvec_constant(ctx, 32, num_components, ones);
- return emit_triop(ctx, SpvOpSelect, otype, value, one, zero);
+ SpvId zero = get_uvec_constant(ctx, 32, num_components, 0);
+ SpvId one = get_uvec_constant(ctx, 32, num_components, UINT32_MAX);
+ return emit_select(ctx, otype, value, one, zero);
}
static SpvId
uvec_to_bvec(struct ntv_context *ctx, SpvId value, unsigned num_components)
{
SpvId type = get_bvec_type(ctx, num_components);
-
- uint32_t zeros[NIR_MAX_VEC_COMPONENTS] = { 0 };
- SpvId zero = get_uvec_constant(ctx, 32, num_components, zeros);
-
+ SpvId zero = get_uvec_constant(ctx, 32, num_components, 0);
return emit_binop(ctx, SpvOpINotEqual, type, value, zero);
}
+static SpvId
+emit_bitcast(struct ntv_context *ctx, SpvId type, SpvId value)
+{
+ return emit_unop(ctx, SpvOpBitcast, type, value);
+}
+
static SpvId
bitcast_to_uvec(struct ntv_context *ctx, SpvId value, unsigned bit_size,
unsigned num_components)
{
SpvId type = get_uvec_type(ctx, bit_size, num_components);
- return emit_unop(ctx, SpvOpBitcast, type, value);
+ return emit_bitcast(ctx, type, value);
}
static SpvId
unsigned num_components)
{
SpvId type = get_ivec_type(ctx, bit_size, num_components);
- return emit_unop(ctx, SpvOpBitcast, type, value);
+ return emit_bitcast(ctx, type, value);
}
static SpvId
unsigned num_components)
{
SpvId type = get_fvec_type(ctx, bit_size, num_components);
- return emit_unop(ctx, SpvOpBitcast, type, value);
+ return emit_bitcast(ctx, type, value);
}
static void
}
static SpvId
-get_fvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
- const float values[])
+emit_builtin_triop(struct ntv_context *ctx, enum GLSLstd450 op, SpvId type,
+ SpvId src0, SpvId src1, SpvId src2)
+{
+ SpvId args[] = { src0, src1, src2 };
+ return spirv_builder_emit_ext_inst(&ctx->builder, type, ctx->GLSL_std_450,
+ op, args, ARRAY_SIZE(args));
+}
+
+static SpvId
+get_fvec_constant(struct ntv_context *ctx, unsigned bit_size,
+ unsigned num_components, float value)
{
assert(bit_size == 32);
- if (num_components > 1) {
- SpvId components[num_components];
- for (int i = 0; i < num_components; i++)
- components[i] = spirv_builder_const_float(&ctx->builder, bit_size,
- values[i]);
+ SpvId result = emit_float_const(ctx, bit_size, value);
+ if (num_components == 1)
+ return result;
- SpvId type = get_fvec_type(ctx, bit_size, num_components);
- return spirv_builder_const_composite(&ctx->builder, type, components,
- num_components);
- }
+ assert(num_components > 1);
+ SpvId components[num_components];
+ for (int i = 0; i < num_components; i++)
+ components[i] = result;
- assert(num_components == 1);
- return spirv_builder_const_float(&ctx->builder, bit_size, values[0]);
+ SpvId type = get_fvec_type(ctx, bit_size, num_components);
+ return spirv_builder_const_composite(&ctx->builder, type, components,
+ num_components);
}
static SpvId
-get_uvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
- const uint32_t values[])
+get_uvec_constant(struct ntv_context *ctx, unsigned bit_size,
+ unsigned num_components, uint32_t value)
{
assert(bit_size == 32);
- if (num_components > 1) {
- SpvId components[num_components];
- for (int i = 0; i < num_components; i++)
- components[i] = spirv_builder_const_uint(&ctx->builder, bit_size,
- values[i]);
+ SpvId result = emit_uint_const(ctx, bit_size, value);
+ if (num_components == 1)
+ return result;
- SpvId type = get_uvec_type(ctx, bit_size, num_components);
- return spirv_builder_const_composite(&ctx->builder, type, components,
- num_components);
- }
+ assert(num_components > 1);
+ SpvId components[num_components];
+ for (int i = 0; i < num_components; i++)
+ components[i] = result;
- assert(num_components == 1);
- return spirv_builder_const_uint(&ctx->builder, bit_size, values[0]);
+ SpvId type = get_uvec_type(ctx, bit_size, num_components);
+ return spirv_builder_const_composite(&ctx->builder, type, components,
+ num_components);
+}
+
+static SpvId
+get_ivec_constant(struct ntv_context *ctx, unsigned bit_size,
+ unsigned num_components, int32_t value)
+{
+ assert(bit_size == 32);
+
+ SpvId result = emit_int_const(ctx, bit_size, value);
+ if (num_components == 1)
+ return result;
+
+ assert(num_components > 1);
+ SpvId components[num_components];
+ for (int i = 0; i < num_components; i++)
+ components[i] = result;
+
+ SpvId type = get_ivec_type(ctx, bit_size, num_components);
+ return spirv_builder_const_composite(&ctx->builder, type, components,
+ num_components);
}
static inline unsigned
result = emit_unop(ctx, spirv_op, dest_type, src[0]); \
break;
+ UNOP(nir_op_ineg, SpvOpSNegate)
+ UNOP(nir_op_fneg, SpvOpFNegate)
+ UNOP(nir_op_fddx, SpvOpDPdx)
+ UNOP(nir_op_fddx_coarse, SpvOpDPdxCoarse)
+ UNOP(nir_op_fddx_fine, SpvOpDPdxFine)
+ UNOP(nir_op_fddy, SpvOpDPdy)
+ UNOP(nir_op_fddy_coarse, SpvOpDPdyCoarse)
+ UNOP(nir_op_fddy_fine, SpvOpDPdyFine)
+ UNOP(nir_op_f2i32, SpvOpConvertFToS)
+ UNOP(nir_op_f2u32, SpvOpConvertFToU)
+ UNOP(nir_op_i2f32, SpvOpConvertSToF)
+ UNOP(nir_op_u2f32, SpvOpConvertUToF)
+ UNOP(nir_op_inot, SpvOpNot)
+#undef UNOP
+
+ case nir_op_b2i32:
+ assert(nir_op_infos[alu->op].num_inputs == 1);
+ result = emit_select(ctx, dest_type, src[0],
+ get_ivec_constant(ctx, 32, num_components, 1),
+ get_ivec_constant(ctx, 32, num_components, 0));
+ break;
+
+ case nir_op_b2f32:
+ assert(nir_op_infos[alu->op].num_inputs == 1);
+ result = emit_select(ctx, dest_type, src[0],
+ get_fvec_constant(ctx, 32, num_components, 1),
+ get_fvec_constant(ctx, 32, num_components, 0));
+ break;
+
#define BUILTIN_UNOP(nir_op, spirv_op) \
case nir_op: \
assert(nir_op_infos[alu->op].num_inputs == 1); \
result = emit_builtin_unop(ctx, spirv_op, dest_type, src[0]); \
break;
- UNOP(nir_op_fneg, SpvOpFNegate)
- UNOP(nir_op_fddx, SpvOpDPdx)
- UNOP(nir_op_fddy, SpvOpDPdy)
-
+ BUILTIN_UNOP(nir_op_iabs, GLSLstd450SAbs)
BUILTIN_UNOP(nir_op_fabs, GLSLstd450FAbs)
BUILTIN_UNOP(nir_op_fsqrt, GLSLstd450Sqrt)
BUILTIN_UNOP(nir_op_frsq, GLSLstd450InverseSqrt)
BUILTIN_UNOP(nir_op_fsign, GLSLstd450FSign)
BUILTIN_UNOP(nir_op_fsin, GLSLstd450Sin)
BUILTIN_UNOP(nir_op_fcos, GLSLstd450Cos)
+#undef BUILTIN_UNOP
- case nir_op_frcp: {
+ case nir_op_frcp:
assert(nir_op_infos[alu->op].num_inputs == 1);
- float one[4] = { 1, 1, 1, 1 };
- src[1] = src[0];
- src[0] = get_fvec_constant(ctx, bit_size, num_components, one);
- result = emit_binop(ctx, SpvOpFDiv, dest_type, src[0], src[1]);
- }
+ result = emit_binop(ctx, SpvOpFDiv, dest_type,
+ get_fvec_constant(ctx, bit_size, num_components, 1),
+ src[0]);
+ break;
+
+ case nir_op_f2b1:
+ assert(nir_op_infos[alu->op].num_inputs == 1);
+ result = emit_binop(ctx, SpvOpFOrdNotEqual, dest_type, src[0],
+ get_fvec_constant(ctx,
+ nir_src_bit_size(alu->src[0].src),
+ num_components, 0));
break;
-#undef UNOP
-#undef BUILTIN_UNOP
#define BINOP(nir_op, spirv_op) \
case nir_op: \
result = emit_binop(ctx, spirv_op, dest_type, src[0], src[1]); \
break;
-#define BUILTIN_BINOP(nir_op, spirv_op) \
- case nir_op: \
- assert(nir_op_infos[alu->op].num_inputs == 2); \
- result = emit_builtin_binop(ctx, spirv_op, dest_type, src[0], src[1]); \
- break;
-
BINOP(nir_op_iadd, SpvOpIAdd)
BINOP(nir_op_isub, SpvOpISub)
BINOP(nir_op_imul, SpvOpIMul)
+ BINOP(nir_op_idiv, SpvOpSDiv)
+ BINOP(nir_op_udiv, SpvOpUDiv)
+ BINOP(nir_op_umod, SpvOpUMod)
BINOP(nir_op_fadd, SpvOpFAdd)
BINOP(nir_op_fsub, SpvOpFSub)
BINOP(nir_op_fmul, SpvOpFMul)
+ BINOP(nir_op_fdiv, SpvOpFDiv)
BINOP(nir_op_fmod, SpvOpFMod)
- BINOP(nir_op_flt, SpvOpFUnordLessThan)
- BINOP(nir_op_fge, SpvOpFUnordGreaterThanEqual)
+ BINOP(nir_op_ilt, SpvOpSLessThan)
+ BINOP(nir_op_ige, SpvOpSGreaterThanEqual)
+ BINOP(nir_op_ieq, SpvOpIEqual)
+ BINOP(nir_op_ine, SpvOpINotEqual)
+ BINOP(nir_op_uge, SpvOpUGreaterThanEqual)
+ BINOP(nir_op_flt, SpvOpFOrdLessThan)
+ BINOP(nir_op_fge, SpvOpFOrdGreaterThanEqual)
+ BINOP(nir_op_feq, SpvOpFOrdEqual)
+ BINOP(nir_op_fne, SpvOpFOrdNotEqual)
+ BINOP(nir_op_ishl, SpvOpShiftLeftLogical)
+ BINOP(nir_op_ishr, SpvOpShiftRightArithmetic)
+ BINOP(nir_op_ushr, SpvOpShiftRightLogical)
+ BINOP(nir_op_iand, SpvOpBitwiseAnd)
+ BINOP(nir_op_ior, SpvOpBitwiseOr)
+#undef BINOP
+
+#define BUILTIN_BINOP(nir_op, spirv_op) \
+ case nir_op: \
+ assert(nir_op_infos[alu->op].num_inputs == 2); \
+ result = emit_builtin_binop(ctx, spirv_op, dest_type, src[0], src[1]); \
+ break;
BUILTIN_BINOP(nir_op_fmin, GLSLstd450FMin)
BUILTIN_BINOP(nir_op_fmax, GLSLstd450FMax)
-
-#undef BINOP
#undef BUILTIN_BINOP
case nir_op_fdot2:
int num_components = nir_dest_num_components(alu->dest.dest);
SpvId bool_type = get_bvec_type(ctx, num_components);
- SpvId zero = spirv_builder_const_float(&ctx->builder, 32, 0.0f);
- SpvId one = spirv_builder_const_float(&ctx->builder, 32, 1.0f);
+ SpvId zero = emit_float_const(ctx, bit_size, 0.0f);
+ SpvId one = emit_float_const(ctx, bit_size, 1.0f);
if (num_components > 1) {
SpvId zero_comps[num_components], one_comps[num_components];
for (int i = 0; i < num_components; i++) {
}
result = emit_binop(ctx, op, bool_type, src[0], src[1]);
- result = emit_triop(ctx, SpvOpSelect, dest_type, result, one, zero);
+ result = emit_select(ctx, dest_type, result, one, zero);
}
break;
- case nir_op_fcsel: {
+ case nir_op_flrp:
assert(nir_op_infos[alu->op].num_inputs == 3);
- int num_components = nir_dest_num_components(alu->dest.dest);
- SpvId bool_type = get_bvec_type(ctx, num_components);
+ result = emit_builtin_triop(ctx, GLSLstd450FMix, dest_type,
+ src[0], src[1], src[2]);
+ break;
- float zero[4] = { 0, 0, 0, 0 };
- SpvId cmp = get_fvec_constant(ctx, nir_src_bit_size(alu->src[0].src),
- num_components, zero);
+ case nir_op_fcsel:
+ result = emit_binop(ctx, SpvOpFOrdGreaterThan,
+ get_bvec_type(ctx, num_components),
+ src[0],
+ get_fvec_constant(ctx,
+ nir_src_bit_size(alu->src[0].src),
+ num_components, 0));
+ result = emit_select(ctx, dest_type, result, src[1], src[2]);
+ break;
- result = emit_binop(ctx, SpvOpFOrdGreaterThan, bool_type, src[0], cmp);
- result = emit_triop(ctx, SpvOpSelect, dest_type, result, src[1], src[2]);
- }
+ case nir_op_bcsel:
+ assert(nir_op_infos[alu->op].num_inputs == 3);
+ result = emit_select(ctx, dest_type, src[0], src[1], src[2]);
+ break;
+
+ case nir_op_bany_fnequal2:
+ case nir_op_bany_fnequal3:
+ case nir_op_bany_fnequal4:
+ assert(nir_op_infos[alu->op].num_inputs == 2);
+ assert(alu_instr_src_components(alu, 0) ==
+ alu_instr_src_components(alu, 1));
+ result = emit_binop(ctx, SpvOpFOrdNotEqual,
+ get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+ src[0], src[1]);
+ result = emit_unop(ctx, SpvOpAny, dest_type, result);
+ break;
+
+ case nir_op_ball_fequal2:
+ case nir_op_ball_fequal3:
+ case nir_op_ball_fequal4:
+ assert(nir_op_infos[alu->op].num_inputs == 2);
+ assert(alu_instr_src_components(alu, 0) ==
+ alu_instr_src_components(alu, 1));
+ result = emit_binop(ctx, SpvOpFOrdEqual,
+ get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+ src[0], src[1]);
+ result = emit_unop(ctx, SpvOpAll, dest_type, result);
+ break;
+
+ case nir_op_bany_inequal2:
+ case nir_op_bany_inequal3:
+ case nir_op_bany_inequal4:
+ assert(nir_op_infos[alu->op].num_inputs == 2);
+ assert(alu_instr_src_components(alu, 0) ==
+ alu_instr_src_components(alu, 1));
+ result = emit_binop(ctx, SpvOpINotEqual,
+ get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+ src[0], src[1]);
+ result = emit_unop(ctx, SpvOpAny, dest_type, result);
+ break;
+
+ case nir_op_ball_iequal2:
+ case nir_op_ball_iequal3:
+ case nir_op_ball_iequal4:
+ assert(nir_op_infos[alu->op].num_inputs == 2);
+ assert(alu_instr_src_components(alu, 0) ==
+ alu_instr_src_components(alu, 1));
+ result = emit_binop(ctx, SpvOpIEqual,
+ get_bvec_type(ctx, alu_instr_src_components(alu, 0)),
+ src[0], src[1]);
+ result = emit_unop(ctx, SpvOpAll, dest_type, result);
break;
case nir_op_vec2:
static void
emit_load_const(struct ntv_context *ctx, nir_load_const_instr *load_const)
{
- uint32_t values[NIR_MAX_VEC_COMPONENTS];
- for (int i = 0; i < load_const->def.num_components; ++i)
- values[i] = load_const->value[i].u32;
+ unsigned bit_size = load_const->def.bit_size;
+ unsigned num_components = load_const->def.num_components;
+
+ SpvId constant;
+ if (num_components > 1) {
+ SpvId components[num_components];
+ SpvId type;
+ if (bit_size == 1) {
+ for (int i = 0; i < num_components; i++)
+ components[i] = spirv_builder_const_bool(&ctx->builder,
+ load_const->value[i].b);
+
+ type = get_bvec_type(ctx, num_components);
+ } else {
+ for (int i = 0; i < num_components; i++)
+ components[i] = emit_uint_const(ctx, bit_size,
+ load_const->value[i].u32);
+
+ type = get_uvec_type(ctx, bit_size, num_components);
+ }
+ constant = spirv_builder_const_composite(&ctx->builder, type,
+ components, num_components);
+ } else {
+ assert(num_components == 1);
+ if (bit_size == 1)
+ constant = spirv_builder_const_bool(&ctx->builder,
+ load_const->value[0].b);
+ else
+ constant = emit_uint_const(ctx, bit_size, load_const->value[0].u32);
+ }
+
+ if (bit_size == 1)
+ constant = bvec_to_uvec(ctx, constant, num_components);
- SpvId constant = get_uvec_constant(ctx, load_const->def.bit_size,
- load_const->def.num_components,
- values);
store_ssa_def_uint(ctx, &load_const->def, constant);
}
uvec4_type);
unsigned idx = const_offset->u32;
- SpvId member = spirv_builder_const_uint(&ctx->builder, 32, 0);
- SpvId offset = spirv_builder_const_uint(&ctx->builder, 32, idx);
+ SpvId member = emit_uint_const(ctx, 32, 0);
+ SpvId offset = emit_uint_const(ctx, 32, idx);
SpvId offsets[] = { member, offset };
SpvId ptr = spirv_builder_emit_access_chain(&ctx->builder, pointer_type,
ctx->ubos[0], offsets,
static void
emit_load_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
{
- nir_variable *var = nir_intrinsic_get_var(intr, 0);
- struct hash_entry *he = _mesa_hash_table_search(ctx->vars, var);
- assert(he);
- SpvId ptr = (SpvId)(intptr_t)he->data;
+ /* uint is a bit of a lie here; it's really just a pointer */
+ SpvId ptr = get_src_uint(ctx, intr->src);
- // SpvId ptr = get_src_uint(ctx, intr->src); /* uint is a bit of a lie here; it's really just a pointer */
+ nir_variable *var = nir_intrinsic_get_var(intr, 0);
SpvId result = spirv_builder_emit_load(&ctx->builder,
get_glsl_type(ctx, var->type),
ptr);
static void
emit_store_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
{
- nir_variable *var = nir_intrinsic_get_var(intr, 0);
- struct hash_entry *he = _mesa_hash_table_search(ctx->vars, var);
- assert(he);
- SpvId ptr = (SpvId)(intptr_t)he->data;
- // SpvId ptr = get_src_uint(ctx, &intr->src[0]); /* uint is a bit of a lie here; it's really just a pointer */
-
+ /* uint is a bit of a lie here; it's really just a pointer */
+ SpvId ptr = get_src_uint(ctx, &intr->src[0]);
SpvId src = get_src_uint(ctx, &intr->src[1]);
- SpvId result = emit_unop(ctx, SpvOpBitcast, get_glsl_type(ctx, var->type),
- src);
+
+ nir_variable *var = nir_intrinsic_get_var(intr, 0);
+ SpvId type = get_glsl_type(ctx, glsl_without_array(var->type));
+ SpvId result = emit_bitcast(ctx, type, src);
spirv_builder_emit_store(&ctx->builder, ptr, result);
}
+static SpvId
+create_builtin_var(struct ntv_context *ctx, SpvId var_type,
+ SpvStorageClass storage_class,
+ const char *name, SpvBuiltIn builtin)
+{
+ SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
+ storage_class,
+ var_type);
+ SpvId var = spirv_builder_emit_var(&ctx->builder, pointer_type,
+ storage_class);
+ spirv_builder_emit_name(&ctx->builder, var, name);
+ spirv_builder_emit_builtin(&ctx->builder, var, builtin);
+
+ assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
+ ctx->entry_ifaces[ctx->num_entry_ifaces++] = var;
+ return var;
+}
+
+static void
+emit_load_front_face(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+{
+ SpvId var_type = spirv_builder_type_bool(&ctx->builder);
+ if (!ctx->front_face_var)
+ ctx->front_face_var = create_builtin_var(ctx, var_type,
+ SpvStorageClassInput,
+ "gl_FrontFacing",
+ SpvBuiltInFrontFacing);
+
+ SpvId result = spirv_builder_emit_load(&ctx->builder, var_type,
+ ctx->front_face_var);
+ assert(1 == nir_dest_num_components(intr->dest));
+ result = bvec_to_uvec(ctx, result, 1);
+ store_dest_uint(ctx, &intr->dest, result);
+}
+
+static void
+emit_load_instance_id(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+{
+ SpvId var_type = spirv_builder_type_uint(&ctx->builder, 32);
+ if (!ctx->instance_id_var)
+ ctx->instance_id_var = create_builtin_var(ctx, var_type,
+ SpvStorageClassInput,
+ "gl_InstanceId",
+ SpvBuiltInInstanceIndex);
+
+ SpvId result = spirv_builder_emit_load(&ctx->builder, var_type,
+ ctx->instance_id_var);
+ assert(1 == nir_dest_num_components(intr->dest));
+ store_dest_uint(ctx, &intr->dest, result);
+}
+
+static void
+emit_load_vertex_id(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+{
+ SpvId var_type = spirv_builder_type_uint(&ctx->builder, 32);
+ if (!ctx->vertex_id_var)
+ ctx->vertex_id_var = create_builtin_var(ctx, var_type,
+ SpvStorageClassInput,
+ "gl_VertexID",
+ SpvBuiltInVertexIndex);
+
+ SpvId result = spirv_builder_emit_load(&ctx->builder, var_type,
+ ctx->vertex_id_var);
+ assert(1 == nir_dest_num_components(intr->dest));
+ store_dest_uint(ctx, &intr->dest, result);
+}
+
static void
emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr)
{
emit_store_deref(ctx, intr);
break;
+ case nir_intrinsic_load_front_face:
+ emit_load_front_face(ctx, intr);
+ break;
+
+ case nir_intrinsic_load_instance_id:
+ emit_load_instance_id(ctx, intr);
+ break;
+
+ case nir_intrinsic_load_vertex_id:
+ emit_load_vertex_id(ctx, intr);
+ break;
+
default:
fprintf(stderr, "emit_intrinsic: not implemented (%s)\n",
nir_intrinsic_infos[intr->intrinsic].name);
return bitcast_to_fvec(ctx, def, bit_size, num_components);
}
+static SpvId
+get_src_int(struct ntv_context *ctx, nir_src *src)
+{
+ SpvId def = get_src_uint(ctx, src);
+ unsigned num_components = nir_src_num_components(*src);
+ unsigned bit_size = nir_src_bit_size(*src);
+ return bitcast_to_ivec(ctx, def, bit_size, num_components);
+}
+
static void
emit_tex(struct ntv_context *ctx, nir_tex_instr *tex)
{
- assert(tex->op == nir_texop_tex);
- assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float);
+ assert(tex->op == nir_texop_tex ||
+ tex->op == nir_texop_txb ||
+ tex->op == nir_texop_txl ||
+ tex->op == nir_texop_txd ||
+ tex->op == nir_texop_txf ||
+ tex->op == nir_texop_txs);
assert(tex->texture_index == tex->sampler_index);
- bool has_proj = false, has_lod = false;
- SpvId coord = 0, proj, lod;
- unsigned coord_components;
+ SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0, dx = 0, dy = 0,
+ offset = 0;
+ unsigned coord_components = 0;
for (unsigned i = 0; i < tex->num_srcs; i++) {
switch (tex->src[i].src_type) {
case nir_tex_src_coord:
- coord = get_src_float(ctx, &tex->src[i].src);
+ if (tex->op == nir_texop_txf)
+ coord = get_src_int(ctx, &tex->src[i].src);
+ else
+ coord = get_src_float(ctx, &tex->src[i].src);
coord_components = nir_src_num_components(tex->src[i].src);
break;
case nir_tex_src_projector:
- has_proj = true;
- proj = get_src_float(ctx, &tex->src[i].src);
assert(nir_src_num_components(tex->src[i].src) == 1);
+ proj = get_src_float(ctx, &tex->src[i].src);
+ assert(proj != 0);
+ break;
+
+ case nir_tex_src_offset:
+ offset = get_src_int(ctx, &tex->src[i].src);
+ break;
+
+ case nir_tex_src_bias:
+ assert(tex->op == nir_texop_txb);
+ bias = get_src_float(ctx, &tex->src[i].src);
+ assert(bias != 0);
break;
case nir_tex_src_lod:
- has_lod = true;
- lod = get_src_float(ctx, &tex->src[i].src);
assert(nir_src_num_components(tex->src[i].src) == 1);
+ if (tex->op == nir_texop_txf ||
+ tex->op == nir_texop_txs)
+ lod = get_src_int(ctx, &tex->src[i].src);
+ else
+ lod = get_src_float(ctx, &tex->src[i].src);
+ assert(lod != 0);
+ break;
+
+ case nir_tex_src_comparator:
+ assert(nir_src_num_components(tex->src[i].src) == 1);
+ dref = get_src_float(ctx, &tex->src[i].src);
+ assert(dref != 0);
+ break;
+
+ case nir_tex_src_ddx:
+ dx = get_src_float(ctx, &tex->src[i].src);
+ assert(dx != 0);
+ break;
+
+ case nir_tex_src_ddy:
+ dy = get_src_float(ctx, &tex->src[i].src);
+ assert(dy != 0);
break;
default:
}
}
- if (!has_lod && ctx->stage != MESA_SHADER_FRAGMENT) {
- has_lod = true;
- lod = spirv_builder_const_float(&ctx->builder, 32, 0);
+ if (lod == 0 && ctx->stage != MESA_SHADER_FRAGMENT) {
+ lod = emit_float_const(ctx, 32, 0.0f);
+ assert(lod != 0);
}
- bool is_ms;
- SpvDim dimension = type_to_dim(tex->sampler_dim, &is_ms);
- SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
- SpvId image_type = spirv_builder_type_image(&ctx->builder, float_type,
- dimension, false, tex->is_array, is_ms, 1,
- SpvImageFormatUnknown);
+ SpvId image_type = ctx->image_types[tex->texture_index];
SpvId sampled_type = spirv_builder_type_sampled_image(&ctx->builder,
image_type);
SpvId dest_type = get_dest_type(ctx, &tex->dest, tex->dest_type);
- SpvId result;
- if (has_proj) {
+ if (tex->op == nir_texop_txs) {
+ SpvId image = spirv_builder_emit_image(&ctx->builder, image_type, load);
+ SpvId result = spirv_builder_emit_image_query_size(&ctx->builder,
+ dest_type, image,
+ lod);
+ store_dest(ctx, &tex->dest, result, tex->dest_type);
+ return;
+ }
+
+ if (proj && coord_components > 0) {
SpvId constituents[coord_components + 1];
- SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
- for (uint32_t i = 0; i < coord_components; ++i)
- constituents[i] = spirv_builder_emit_composite_extract(&ctx->builder,
- float_type,
- coord,
- &i, 1);
+ if (coord_components == 1)
+ constituents[0] = coord;
+ else {
+ assert(coord_components > 1);
+ SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
+ for (uint32_t i = 0; i < coord_components; ++i)
+ constituents[i] = spirv_builder_emit_composite_extract(&ctx->builder,
+ float_type,
+ coord,
+ &i, 1);
+ }
constituents[coord_components++] = proj;
SpvId vec_type = get_fvec_type(ctx, 32, coord_components);
- SpvId merged = spirv_builder_emit_composite_construct(&ctx->builder,
+ coord = spirv_builder_emit_composite_construct(&ctx->builder,
vec_type,
constituents,
coord_components);
+ }
- if (has_lod)
- result = spirv_builder_emit_image_sample_proj_explicit_lod(&ctx->builder,
- dest_type,
- load,
- merged,
- lod);
- else
- result = spirv_builder_emit_image_sample_proj_implicit_lod(&ctx->builder,
- dest_type,
- load,
- merged);
+ SpvId actual_dest_type = dest_type;
+ if (dref)
+ actual_dest_type = spirv_builder_type_float(&ctx->builder, 32);
+
+ SpvId result;
+ if (tex->op == nir_texop_txf) {
+ SpvId image = spirv_builder_emit_image(&ctx->builder, image_type, load);
+ result = spirv_builder_emit_image_fetch(&ctx->builder, dest_type,
+ image, coord, lod);
} else {
- if (has_lod)
- result = spirv_builder_emit_image_sample_explicit_lod(&ctx->builder,
- dest_type,
- load,
- coord, lod);
- else
- result = spirv_builder_emit_image_sample_implicit_lod(&ctx->builder,
- dest_type,
- load,
- coord);
+ result = spirv_builder_emit_image_sample(&ctx->builder,
+ actual_dest_type, load,
+ coord,
+ proj != 0,
+ lod, bias, dref, dx, dy,
+ offset);
}
+
spirv_builder_emit_decoration(&ctx->builder, result,
SpvDecorationRelaxedPrecision);
+ if (dref && nir_dest_num_components(tex->dest) > 1) {
+ SpvId components[4] = { result, result, result, result };
+ result = spirv_builder_emit_composite_construct(&ctx->builder,
+ dest_type,
+ components,
+ 4);
+ }
+
store_dest(ctx, &tex->dest, result, tex->dest_type);
}
}
static void
-emit_deref(struct ntv_context *ctx, nir_deref_instr *deref)
+emit_deref_var(struct ntv_context *ctx, nir_deref_instr *deref)
{
assert(deref->deref_type == nir_deref_type_var);
+ struct hash_entry *he = _mesa_hash_table_search(ctx->vars, deref->var);
+ assert(he);
+ SpvId result = (SpvId)(intptr_t)he->data;
+ /* uint is a bit of a lie here, it's really just an opaque type */
+ store_dest_uint(ctx, &deref->dest, result);
+}
+
+static void
+emit_deref_array(struct ntv_context *ctx, nir_deref_instr *deref)
+{
+ assert(deref->deref_type == nir_deref_type_array);
+ nir_variable *var = nir_deref_instr_get_variable(deref);
+
SpvStorageClass storage_class;
- switch (deref->var->data.mode) {
+ switch (var->data.mode) {
case nir_var_shader_in:
storage_class = SpvStorageClassInput;
break;
unreachable("Unsupported nir_variable_mode\n");
}
- struct hash_entry *he = _mesa_hash_table_search(ctx->vars, deref->var);
- assert(he);
+ SpvId index = get_src_uint(ctx, &deref->arr.index);
SpvId ptr_type = spirv_builder_type_pointer(&ctx->builder,
storage_class,
SpvId result = spirv_builder_emit_access_chain(&ctx->builder,
ptr_type,
- (SpvId)(intptr_t)he->data,
- NULL, 0);
+ get_src_uint(ctx, &deref->parent),
+ &index, 1);
/* uint is a bit of a lie here, it's really just an opaque type */
store_dest_uint(ctx, &deref->dest, result);
}
+static void
+emit_deref(struct ntv_context *ctx, nir_deref_instr *deref)
+{
+ switch (deref->deref_type) {
+ case nir_deref_type_var:
+ emit_deref_var(ctx, deref);
+ break;
+
+ case nir_deref_type_array:
+ emit_deref_array(ctx, deref);
+ break;
+
+ default:
+ unreachable("unexpected deref_type");
+ }
+}
+
static void
emit_block(struct ntv_context *ctx, struct nir_block *block)
{
unreachable("nir_instr_type_parallel_copy not supported");
break;
case nir_instr_type_deref:
- /* these are handled in emit_{load,store}_deref */
- /* emit_deref(ctx, nir_instr_as_deref(instr)); */
+ emit_deref(ctx, nir_instr_as_deref(instr));
break;
}
}
get_src_bool(struct ntv_context *ctx, nir_src *src)
{
SpvId def = get_src_uint(ctx, src);
- assert(nir_src_bit_size(*src) == 32);
+ assert(nir_src_bit_size(*src) == 1);
unsigned num_components = nir_src_num_components(*src);
return uvec_to_bvec(ctx, def, num_components);
}
unreachable("invalid stage");
}
+ // TODO: only enable when needed
+ if (s->info.stage == MESA_SHADER_FRAGMENT) {
+ spirv_builder_emit_cap(&ctx.builder, SpvCapabilitySampled1D);
+ spirv_builder_emit_cap(&ctx.builder, SpvCapabilityImageQuery);
+ spirv_builder_emit_cap(&ctx.builder, SpvCapabilityDerivativeControl);
+ }
+
ctx.stage = s->info.stage;
ctx.GLSL_std_450 = spirv_builder_import(&ctx.builder, "GLSL.std.450");
spirv_builder_emit_source(&ctx.builder, SpvSourceLanguageGLSL, 450);
nir_foreach_variable(var, &s->uniforms)
emit_uniform(&ctx, var);
- spirv_builder_emit_entry_point(&ctx.builder, exec_model, entry_point,
- "main", ctx.entry_ifaces,
- ctx.num_entry_ifaces);
- if (s->info.stage == MESA_SHADER_FRAGMENT)
+ if (s->info.stage == MESA_SHADER_FRAGMENT) {
spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
SpvExecutionModeOriginUpperLeft);
+ if (s->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH))
+ spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
+ SpvExecutionModeDepthReplacing);
+ }
spirv_builder_function(&ctx.builder, entry_point, type_void,
spirv_builder_return(&ctx.builder); // doesn't belong here, but whatevz
spirv_builder_function_end(&ctx.builder);
+ spirv_builder_emit_entry_point(&ctx.builder, exec_model, entry_point,
+ "main", ctx.entry_ifaces,
+ ctx.num_entry_ifaces);
+
size_t num_words = spirv_builder_get_num_words(&ctx.builder);
ret = CALLOC_STRUCT(spirv_shader);