#include "nir.h"
#include "pipe/p_state.h"
#include "util/u_memory.h"
+#include "util/hash_table.h"
struct ntv_context {
struct spirv_builder builder;
SpvId GLSL_std_450;
gl_shader_stage stage;
- SpvId inputs[PIPE_MAX_SHADER_INPUTS][4];
- SpvId outputs[PIPE_MAX_SHADER_OUTPUTS][4];
+ int var_location;
SpvId ubos[128];
size_t num_ubos;
SpvId *defs;
size_t num_defs;
+
+ SpvId *regs;
+ size_t num_regs;
+
+ struct hash_table *vars; /* nir_variable -> SpvId */
+
+ const SpvId *block_ids;
+ size_t num_blocks;
+ bool block_started;
+ SpvId loop_break, loop_cont;
};
+static SpvId
+get_fvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
+ const float values[]);
+
+static SpvId
+get_uvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
+ const uint32_t values[]);
+
+static SpvId
+emit_unop(struct ntv_context *ctx, SpvOp op, SpvId type, SpvId src);
+
+static SpvId
+emit_binop(struct ntv_context *ctx, SpvOp op, SpvId type,
+ SpvId src0, SpvId src1);
+
+static SpvId
+emit_triop(struct ntv_context *ctx, SpvOp op, SpvId type,
+ SpvId src0, SpvId src1, SpvId src2);
+
static SpvId
get_bvec_type(struct ntv_context *ctx, int num_components)
{
return bool_type;
}
+static SpvId
+block_label(struct ntv_context *ctx, nir_block *block)
+{
+ assert(block->index < ctx->num_blocks);
+ return ctx->block_ids[block->index];
+}
+
static SpvId
get_fvec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
{
}
static SpvId
-get_dest_type(struct ntv_context *ctx, nir_dest *dest)
+get_ivec_type(struct ntv_context *ctx, unsigned bit_size, unsigned num_components)
{
- return get_fvec_type(ctx, nir_dest_bit_size(*dest),
+ assert(bit_size == 32); // only 32-bit ints supported so far
+
+ SpvId int_type = spirv_builder_type_int(&ctx->builder, bit_size);
+ if (num_components > 1)
+ return spirv_builder_type_vector(&ctx->builder, int_type,
+ num_components);
+
+ assert(num_components == 1);
+ return int_type;
+}
+
+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
+
+ SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
+ if (num_components > 1)
+ return spirv_builder_type_vector(&ctx->builder, uint_type,
+ num_components);
+
+ assert(num_components == 1);
+ return uint_type;
+}
+
+static SpvId
+get_dest_uvec_type(struct ntv_context *ctx, nir_dest *dest)
+{
+ return get_uvec_type(ctx, nir_dest_bit_size(*dest),
nir_dest_num_components(*dest));
}
static void
emit_input(struct ntv_context *ctx, struct nir_variable *var)
{
- SpvId vec_type = get_glsl_type(ctx, var->type);
+ SpvId var_type = get_glsl_type(ctx, var->type);
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassInput,
- vec_type);
+ var_type);
SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
SpvStorageClassInput);
spirv_builder_emit_name(&ctx->builder, var_id, var->name);
if (ctx->stage == MESA_SHADER_FRAGMENT) {
- switch (var->data.location) {
- case VARYING_SLOT_POS:
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragCoord);
- break;
-
- case VARYING_SLOT_PNTC:
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointCoord);
- break;
-
- default:
+ if (var->data.location >= VARYING_SLOT_VAR0 ||
+ (var->data.location >= VARYING_SLOT_COL0 &&
+ var->data.location <= VARYING_SLOT_TEX7)) {
spirv_builder_emit_location(&ctx->builder, var_id,
- var->data.driver_location);
- break;
+ ctx->var_location++);
+ } else {
+ switch (var->data.location) {
+ case VARYING_SLOT_POS:
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragCoord);
+ break;
+
+ case VARYING_SLOT_PNTC:
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointCoord);
+ break;
+
+ default:
+ unreachable("unknown varying slot");
+ }
}
} else {
spirv_builder_emit_location(&ctx->builder, var_id,
if (var->data.interpolation == INTERP_MODE_FLAT)
spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationFlat);
- assert(var->data.driver_location < PIPE_MAX_SHADER_INPUTS);
- assert(var->data.location_frac < 4);
- assert(ctx->inputs[var->data.driver_location][var->data.location_frac] == 0);
- ctx->inputs[var->data.driver_location][var->data.location_frac] = var_id;
+ _mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id);
assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
ctx->entry_ifaces[ctx->num_entry_ifaces++] = var_id;
static void
emit_output(struct ntv_context *ctx, struct nir_variable *var)
{
- SpvId vec_type = get_glsl_type(ctx, var->type);
+ SpvId var_type = get_glsl_type(ctx, var->type);
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassOutput,
- vec_type);
+ var_type);
SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
SpvStorageClassOutput);
if (var->name)
if (ctx->stage == MESA_SHADER_VERTEX) {
- switch (var->data.location) {
- case VARYING_SLOT_POS:
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPosition);
- break;
-
- case VARYING_SLOT_PSIZ:
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointSize);
- break;
-
- default:
+ if (var->data.location >= VARYING_SLOT_VAR0 ||
+ (var->data.location >= VARYING_SLOT_COL0 &&
+ var->data.location <= VARYING_SLOT_TEX7)) {
spirv_builder_emit_location(&ctx->builder, var_id,
- var->data.driver_location - 1);
+ ctx->var_location++);
+ } else {
+ switch (var->data.location) {
+ case VARYING_SLOT_POS:
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPosition);
+ break;
+
+ case VARYING_SLOT_PSIZ:
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointSize);
+ break;
+
+ default:
+ unreachable("unknown varying slot");
+ }
}
} else if (ctx->stage == MESA_SHADER_FRAGMENT) {
switch (var->data.location) {
spirv_builder_emit_component(&ctx->builder, var_id,
var->data.location_frac);
- assert(var->data.driver_location < PIPE_MAX_SHADER_INPUTS);
- assert(var->data.location_frac < 4);
- assert(ctx->outputs[var->data.driver_location][var->data.location_frac] == 0);
- ctx->outputs[var->data.driver_location][var->data.location_frac] = var_id;
+ _mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id);
assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
ctx->entry_ifaces[ctx->num_entry_ifaces++] = var_id;
emit_ubo(struct ntv_context *ctx, struct nir_variable *var)
{
uint32_t size = glsl_count_attribute_slots(var->type, false);
- SpvId vec4_type = get_fvec_type(ctx, 32, 4);
+ SpvId vec4_type = get_uvec_type(ctx, 32, 4);
SpvId array_length = spirv_builder_const_uint(&ctx->builder, 32, size);
SpvId array_type = spirv_builder_type_array(&ctx->builder, vec4_type,
array_length);
}
static SpvId
-get_src(struct ntv_context *ctx, nir_src *src)
+get_src_uint_ssa(struct ntv_context *ctx, const nir_ssa_def *ssa)
{
- assert(src->is_ssa);
- assert(src->ssa->index < ctx->num_defs);
- assert(ctx->defs[src->ssa->index] != 0);
- return ctx->defs[src->ssa->index];
+ assert(ssa->index < ctx->num_defs);
+ assert(ctx->defs[ssa->index] != 0);
+ return ctx->defs[ssa->index];
}
static SpvId
-get_alu_src(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
+get_var_from_reg(struct ntv_context *ctx, nir_register *reg)
+{
+ assert(reg->index < ctx->num_regs);
+ assert(ctx->regs[reg->index] != 0);
+ return ctx->regs[reg->index];
+}
+
+static SpvId
+get_src_uint_reg(struct ntv_context *ctx, const nir_reg_src *reg)
+{
+ assert(reg->reg);
+ assert(!reg->indirect);
+ assert(!reg->base_offset);
+
+ SpvId var = get_var_from_reg(ctx, reg->reg);
+ SpvId type = get_uvec_type(ctx, reg->reg->bit_size, reg->reg->num_components);
+ return spirv_builder_emit_load(&ctx->builder, type, var);
+}
+
+static SpvId
+get_src_uint(struct ntv_context *ctx, nir_src *src)
+{
+ if (src->is_ssa)
+ return get_src_uint_ssa(ctx, src->ssa);
+ else
+ return get_src_uint_reg(ctx, &src->reg);
+}
+
+static SpvId
+get_alu_src_uint(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
{
assert(!alu->src[src].negate);
assert(!alu->src[src].abs);
- SpvId def = get_src(ctx, &alu->src[src].src);
+ SpvId def = get_src_uint(ctx, &alu->src[src].src);
unsigned used_channels = 0;
bool need_swizzle = false;
int bit_size = nir_src_bit_size(alu->src[src].src);
+ SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
if (used_channels == 1) {
- SpvId result_type = spirv_builder_type_float(&ctx->builder, bit_size);
uint32_t indices[] = { alu->src[src].swizzle[0] };
- return spirv_builder_emit_composite_extract(&ctx->builder, result_type,
+ return spirv_builder_emit_composite_extract(&ctx->builder, uint_type,
def, indices,
ARRAY_SIZE(indices));
} else if (live_channels == 1) {
- SpvId type = get_fvec_type(ctx, bit_size, used_channels);
+ SpvId uvec_type = spirv_builder_type_vector(&ctx->builder, uint_type,
+ used_channels);
SpvId constituents[NIR_MAX_VEC_COMPONENTS];
for (unsigned i = 0; i < used_channels; ++i)
constituents[i] = def;
- return spirv_builder_emit_composite_construct(&ctx->builder, type,
+ return spirv_builder_emit_composite_construct(&ctx->builder, uvec_type,
constituents,
used_channels);
} else {
+ SpvId uvec_type = spirv_builder_type_vector(&ctx->builder, uint_type,
+ used_channels);
+
uint32_t components[NIR_MAX_VEC_COMPONENTS];
size_t num_components = 0;
for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; i++) {
components[num_components++] = alu->src[src].swizzle[i];
}
- SpvId vecType = get_fvec_type(ctx, bit_size, used_channels);
- return spirv_builder_emit_vector_shuffle(&ctx->builder, vecType,
+ return spirv_builder_emit_vector_shuffle(&ctx->builder, uvec_type,
def, def, components, num_components);
}
}
static void
-store_ssa_def(struct ntv_context *ctx, nir_ssa_def *ssa, SpvId result)
+store_ssa_def_uint(struct ntv_context *ctx, nir_ssa_def *ssa, SpvId result)
{
assert(result != 0);
assert(ssa->index < ctx->num_defs);
ctx->defs[ssa->index] = result;
}
+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);
+}
+
+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);
+
+ return emit_binop(ctx, SpvOpINotEqual, type, value, zero);
+}
+
+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);
+}
+
+static SpvId
+bitcast_to_ivec(struct ntv_context *ctx, SpvId value, unsigned bit_size,
+ unsigned num_components)
+{
+ SpvId type = get_ivec_type(ctx, bit_size, num_components);
+ return emit_unop(ctx, SpvOpBitcast, type, value);
+}
+
+static SpvId
+bitcast_to_fvec(struct ntv_context *ctx, SpvId value, unsigned bit_size,
+ unsigned num_components)
+{
+ SpvId type = get_fvec_type(ctx, bit_size, num_components);
+ return emit_unop(ctx, SpvOpBitcast, type, value);
+}
+
static void
-store_dest(struct ntv_context *ctx, nir_dest *dest, SpvId result)
+store_reg_def(struct ntv_context *ctx, nir_reg_dest *reg, SpvId result)
{
- assert(dest->is_ssa);
- store_ssa_def(ctx, &dest->ssa, result);
+ SpvId var = get_var_from_reg(ctx, reg->reg);
+ assert(var);
+ spirv_builder_emit_store(&ctx->builder, var, result);
}
static void
-store_alu_result(struct ntv_context *ctx, nir_alu_dest *dest, SpvId result)
+store_dest_uint(struct ntv_context *ctx, nir_dest *dest, SpvId result)
{
- assert(!dest->saturate);
- return store_dest(ctx, &dest->dest, result);
+ if (dest->is_ssa)
+ store_ssa_def_uint(ctx, &dest->ssa, result);
+ else
+ store_reg_def(ctx, &dest->reg, result);
+}
+
+static void
+store_dest(struct ntv_context *ctx, nir_dest *dest, SpvId result, nir_alu_type type)
+{
+ unsigned num_components = nir_dest_num_components(*dest);
+ unsigned bit_size = nir_dest_bit_size(*dest);
+
+ switch (nir_alu_type_get_base_type(type)) {
+ case nir_type_bool:
+ assert(bit_size == 1);
+ result = bvec_to_uvec(ctx, result, num_components);
+ break;
+
+ case nir_type_uint:
+ break; /* nothing to do! */
+
+ case nir_type_int:
+ case nir_type_float:
+ result = bitcast_to_uvec(ctx, result, bit_size, num_components);
+ break;
+
+ default:
+ unreachable("unsupported nir_alu_type");
+ }
+
+ store_dest_uint(ctx, dest, result);
}
static SpvId
static SpvId
get_fvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
- float values[])
+ const float values[])
{
assert(bit_size == 32);
return spirv_builder_const_float(&ctx->builder, bit_size, values[0]);
}
+static SpvId
+get_uvec_constant(struct ntv_context *ctx, int bit_size, int num_components,
+ const uint32_t values[])
+{
+ 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 type = get_uvec_type(ctx, bit_size, num_components);
+ return spirv_builder_const_composite(&ctx->builder, type, components,
+ num_components);
+ }
+
+ assert(num_components == 1);
+ return spirv_builder_const_uint(&ctx->builder, bit_size, values[0]);
+}
+
+static inline unsigned
+alu_instr_src_components(const nir_alu_instr *instr, unsigned src)
+{
+ if (nir_op_infos[instr->op].input_sizes[src] > 0)
+ return nir_op_infos[instr->op].input_sizes[src];
+
+ if (instr->dest.dest.is_ssa)
+ return instr->dest.dest.ssa.num_components;
+ else
+ return instr->dest.dest.reg.reg->num_components;
+}
+
+static SpvId
+get_alu_src(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
+{
+ SpvId uint_value = get_alu_src_uint(ctx, alu, src);
+
+ unsigned num_components = alu_instr_src_components(alu, src);
+ unsigned bit_size = nir_src_bit_size(alu->src[src].src);
+ nir_alu_type type = nir_op_infos[alu->op].input_types[src];
+
+ switch (nir_alu_type_get_base_type(type)) {
+ case nir_type_bool:
+ assert(bit_size == 1);
+ return uvec_to_bvec(ctx, uint_value, num_components);
+
+ case nir_type_int:
+ return bitcast_to_ivec(ctx, uint_value, bit_size, num_components);
+
+ case nir_type_uint:
+ return uint_value;
+
+ case nir_type_float:
+ return bitcast_to_fvec(ctx, uint_value, bit_size, num_components);
+
+ default:
+ unreachable("unknown nir_alu_type");
+ }
+}
+
+static void
+store_alu_result(struct ntv_context *ctx, nir_alu_instr *alu, SpvId result)
+{
+ assert(!alu->dest.saturate);
+ return store_dest(ctx, &alu->dest.dest, result, nir_op_infos[alu->op].output_type);
+}
+
+static SpvId
+get_dest_type(struct ntv_context *ctx, nir_dest *dest, nir_alu_type type)
+{
+ unsigned num_components = nir_dest_num_components(*dest);
+ unsigned bit_size = nir_dest_bit_size(*dest);
+
+ switch (nir_alu_type_get_base_type(type)) {
+ case nir_type_bool:
+ return get_bvec_type(ctx, num_components);
+
+ case nir_type_int:
+ return get_ivec_type(ctx, bit_size, num_components);
+
+ case nir_type_uint:
+ return get_uvec_type(ctx, bit_size, num_components);
+
+ case nir_type_float:
+ return get_fvec_type(ctx, bit_size, num_components);
+
+ default:
+ unreachable("unsupported nir_alu_type");
+ }
+}
+
static void
emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
{
for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++)
src[i] = get_alu_src(ctx, alu, i);
- SpvId dest_type = get_dest_type(ctx, &alu->dest.dest);
+ SpvId dest_type = get_dest_type(ctx, &alu->dest.dest,
+ nir_op_infos[alu->op].output_type);
+ unsigned bit_size = nir_dest_bit_size(alu->dest.dest);
+ unsigned num_components = nir_dest_num_components(alu->dest.dest);
SpvId result = 0;
switch (alu->op) {
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, nir_dest_bit_size(alu->dest.dest),
- nir_dest_num_components(alu->dest.dest),
- one);
+ src[0] = get_fvec_constant(ctx, bit_size, num_components, one);
result = emit_binop(ctx, SpvOpFDiv, dest_type, src[0], src[1]);
}
break;
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_fadd, SpvOpFAdd)
BINOP(nir_op_fsub, SpvOpFSub)
BINOP(nir_op_fmul, SpvOpFMul)
+ BINOP(nir_op_fmod, SpvOpFMod)
BINOP(nir_op_flt, SpvOpFUnordLessThan)
BINOP(nir_op_fge, SpvOpFUnordGreaterThanEqual)
return;
}
- store_alu_result(ctx, &alu->dest, result);
+ store_alu_result(ctx, alu, result);
}
static void
emit_load_const(struct ntv_context *ctx, nir_load_const_instr *load_const)
{
- float values[NIR_MAX_VEC_COMPONENTS];
+ uint32_t values[NIR_MAX_VEC_COMPONENTS];
for (int i = 0; i < load_const->def.num_components; ++i)
- values[i] = load_const->value[i].f32;
+ values[i] = load_const->value[i].u32;
- SpvId constant = get_fvec_constant(ctx, load_const->def.bit_size,
- load_const->def.num_components,
- values);
- store_ssa_def(ctx, &load_const->def, constant);
-}
-
-static void
-emit_load_input(struct ntv_context *ctx, nir_intrinsic_instr *intr)
-{
- nir_const_value *const_offset = nir_src_as_const_value(intr->src[0]);
- if (const_offset) {
- SpvId type = get_dest_type(ctx, &intr->dest);
-
- int driver_location = (int)nir_intrinsic_base(intr) + const_offset->u32;
- assert(driver_location < PIPE_MAX_SHADER_INPUTS);
- int location_frac = nir_intrinsic_component(intr);
- assert(location_frac < 4);
-
- SpvId ptr = ctx->inputs[driver_location][location_frac];
- assert(ptr > 0);
-
- store_dest(ctx, &intr->dest, spirv_builder_emit_load(&ctx->builder, type, ptr));
- } else
- unreachable("input-addressing not yet supported");
+ 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);
}
static void
nir_const_value *const_offset = nir_src_as_const_value(intr->src[1]);
if (const_offset) {
- SpvId vec4_type = get_fvec_type(ctx, 32, 4);
+ SpvId uvec4_type = get_uvec_type(ctx, 32, 4);
SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
SpvStorageClassUniform,
- vec4_type);
+ uvec4_type);
unsigned idx = const_offset->u32;
SpvId member = spirv_builder_const_uint(&ctx->builder, 32, 0);
SpvId ptr = spirv_builder_emit_access_chain(&ctx->builder, pointer_type,
ctx->ubos[0], offsets,
ARRAY_SIZE(offsets));
- SpvId result = spirv_builder_emit_load(&ctx->builder, vec4_type, ptr);
+ SpvId result = spirv_builder_emit_load(&ctx->builder, uvec4_type, ptr);
- SpvId type = get_dest_type(ctx, &intr->dest);
+ SpvId type = get_dest_uvec_type(ctx, &intr->dest);
unsigned num_components = nir_dest_num_components(intr->dest);
if (num_components == 1) {
uint32_t components[] = { 0 };
1);
} else if (num_components < 4) {
SpvId constituents[num_components];
- SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
+ SpvId uint_type = spirv_builder_type_uint(&ctx->builder, 32);
for (uint32_t i = 0; i < num_components; ++i)
constituents[i] = spirv_builder_emit_composite_extract(&ctx->builder,
- float_type,
+ uint_type,
result, &i,
1);
num_components);
}
- store_dest(ctx, &intr->dest, result);
+ store_dest_uint(ctx, &intr->dest, result);
} else
unreachable("uniform-addressing not yet supported");
}
static void
-emit_store_output(struct ntv_context *ctx, nir_intrinsic_instr *intr)
+emit_discard(struct ntv_context *ctx, nir_intrinsic_instr *intr)
{
- nir_const_value *const_offset = nir_src_as_const_value(intr->src[1]);
- if (const_offset) {
- int driver_location = (int)nir_intrinsic_base(intr) + const_offset->u32;
- assert(driver_location < PIPE_MAX_SHADER_OUTPUTS);
- int location_frac = nir_intrinsic_component(intr);
- assert(location_frac < 4);
+ assert(ctx->block_started);
+ spirv_builder_emit_kill(&ctx->builder);
+ /* discard is weird in NIR, so let's just create an unreachable block after
+ it and hope that the vulkan driver will DCE any instructinos in it. */
+ spirv_builder_label(&ctx->builder, spirv_builder_new_id(&ctx->builder));
+}
- SpvId ptr = ctx->outputs[driver_location][location_frac];
- assert(ptr > 0);
+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;
+
+ // SpvId ptr = get_src_uint(ctx, intr->src); /* uint is a bit of a lie here; it's really just a pointer */
+ SpvId result = spirv_builder_emit_load(&ctx->builder,
+ get_glsl_type(ctx, var->type),
+ ptr);
+ unsigned num_components = nir_dest_num_components(intr->dest);
+ unsigned bit_size = nir_dest_bit_size(intr->dest);
+ result = bitcast_to_uvec(ctx, result, bit_size, num_components);
+ store_dest_uint(ctx, &intr->dest, result);
+}
- SpvId src = get_src(ctx, &intr->src[0]);
- spirv_builder_emit_store(&ctx->builder, ptr, src);
- } else
- unreachable("output-addressing not yet supported");
+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 */
+
+ SpvId src = get_src_uint(ctx, &intr->src[1]);
+ SpvId result = emit_unop(ctx, SpvOpBitcast, get_glsl_type(ctx, var->type),
+ src);
+ spirv_builder_emit_store(&ctx->builder, ptr, result);
}
static void
emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr)
{
switch (intr->intrinsic) {
- case nir_intrinsic_load_input:
- emit_load_input(ctx, intr);
- break;
-
case nir_intrinsic_load_ubo:
emit_load_ubo(ctx, intr);
break;
- case nir_intrinsic_store_output:
- emit_store_output(ctx, intr);
+ case nir_intrinsic_discard:
+ emit_discard(ctx, intr);
+ break;
+
+ case nir_intrinsic_load_deref:
+ emit_load_deref(ctx, intr);
+ break;
+
+ case nir_intrinsic_store_deref:
+ emit_store_deref(ctx, intr);
break;
default:
static void
emit_undef(struct ntv_context *ctx, nir_ssa_undef_instr *undef)
{
- SpvId type = get_fvec_type(ctx, undef->def.bit_size,
+ SpvId type = get_uvec_type(ctx, undef->def.bit_size,
undef->def.num_components);
- store_ssa_def(ctx, &undef->def,
- spirv_builder_emit_undef(&ctx->builder, type));
+ store_ssa_def_uint(ctx, &undef->def,
+ spirv_builder_emit_undef(&ctx->builder, type));
+}
+
+static SpvId
+get_src_float(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_fvec(ctx, def, bit_size, num_components);
}
static void
assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float);
assert(tex->texture_index == tex->sampler_index);
- bool has_proj = false;
- SpvId coord = 0, proj;
- unsigned coord_size;
+ bool has_proj = false, has_lod = false;
+ SpvId coord = 0, proj, lod;
+ unsigned coord_components;
for (unsigned i = 0; i < tex->num_srcs; i++) {
switch (tex->src[i].src_type) {
case nir_tex_src_coord:
- coord = get_src(ctx, &tex->src[i].src);
- coord_size = nir_src_num_components(tex->src[i].src);
+ 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(ctx, &tex->src[i].src);
+ proj = get_src_float(ctx, &tex->src[i].src);
+ assert(nir_src_num_components(tex->src[i].src) == 1);
+ 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);
break;
default:
}
}
+ if (!has_lod && ctx->stage != MESA_SHADER_FRAGMENT) {
+ has_lod = true;
+ lod = spirv_builder_const_float(&ctx->builder, 32, 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 load = spirv_builder_emit_load(&ctx->builder, sampled_type,
ctx->samplers[tex->texture_index]);
- SpvId dest_type = get_dest_type(ctx, &tex->dest);
+ SpvId dest_type = get_dest_type(ctx, &tex->dest, tex->dest_type);
SpvId result;
if (has_proj) {
- SpvId constituents[coord_size + 1];
+ SpvId constituents[coord_components + 1];
SpvId float_type = spirv_builder_type_float(&ctx->builder, 32);
- for (uint32_t i = 0; i < coord_size; ++i)
+ 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_size++] = proj;
+ constituents[coord_components++] = proj;
- SpvId vec_type = get_fvec_type(ctx, 32, coord_size);
+ SpvId vec_type = get_fvec_type(ctx, 32, coord_components);
SpvId merged = spirv_builder_emit_composite_construct(&ctx->builder,
vec_type,
constituents,
- coord_size);
-
- result = spirv_builder_emit_image_sample_proj_implicit_lod(&ctx->builder,
- dest_type,
- load,
- merged);
- } else
- result = spirv_builder_emit_image_sample_implicit_lod(&ctx->builder,
- dest_type, load,
- coord);
+ 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);
+ } 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);
+ }
spirv_builder_emit_decoration(&ctx->builder, result,
SpvDecorationRelaxedPrecision);
- store_dest(ctx, &tex->dest, result);
+ store_dest(ctx, &tex->dest, result, tex->dest_type);
+}
+
+static void
+start_block(struct ntv_context *ctx, SpvId label)
+{
+ /* terminate previous block if needed */
+ if (ctx->block_started)
+ spirv_builder_emit_branch(&ctx->builder, label);
+
+ /* start new block */
+ spirv_builder_label(&ctx->builder, label);
+ ctx->block_started = true;
+}
+
+static void
+branch(struct ntv_context *ctx, SpvId label)
+{
+ assert(ctx->block_started);
+ spirv_builder_emit_branch(&ctx->builder, label);
+ ctx->block_started = false;
+}
+
+static void
+branch_conditional(struct ntv_context *ctx, SpvId condition, SpvId then_id,
+ SpvId else_id)
+{
+ assert(ctx->block_started);
+ spirv_builder_emit_branch_conditional(&ctx->builder, condition,
+ then_id, else_id);
+ ctx->block_started = false;
+}
+
+static void
+emit_jump(struct ntv_context *ctx, nir_jump_instr *jump)
+{
+ switch (jump->type) {
+ case nir_jump_break:
+ assert(ctx->loop_break);
+ branch(ctx, ctx->loop_break);
+ break;
+
+ case nir_jump_continue:
+ assert(ctx->loop_cont);
+ branch(ctx, ctx->loop_cont);
+ break;
+
+ default:
+ unreachable("Unsupported jump type\n");
+ }
+}
+
+static void
+emit_deref(struct ntv_context *ctx, nir_deref_instr *deref)
+{
+ assert(deref->deref_type == nir_deref_type_var);
+
+ SpvStorageClass storage_class;
+ switch (deref->var->data.mode) {
+ case nir_var_shader_in:
+ storage_class = SpvStorageClassInput;
+ break;
+
+ case nir_var_shader_out:
+ storage_class = SpvStorageClassOutput;
+ break;
+
+ default:
+ unreachable("Unsupported nir_variable_mode\n");
+ }
+
+ struct hash_entry *he = _mesa_hash_table_search(ctx->vars, deref->var);
+ assert(he);
+
+ SpvId ptr_type = spirv_builder_type_pointer(&ctx->builder,
+ storage_class,
+ get_glsl_type(ctx, deref->type));
+
+ SpvId result = spirv_builder_emit_access_chain(&ctx->builder,
+ ptr_type,
+ (SpvId)(intptr_t)he->data,
+ NULL, 0);
+ /* 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_block(struct ntv_context *ctx, struct nir_block *block)
{
+ start_block(ctx, block_label(ctx, block));
nir_foreach_instr(instr, block) {
switch (instr->type) {
case nir_instr_type_alu:
unreachable("nir_instr_type_phi not supported");
break;
case nir_instr_type_jump:
- unreachable("nir_instr_type_jump not supported");
+ emit_jump(ctx, nir_instr_as_jump(instr));
break;
case nir_instr_type_call:
unreachable("nir_instr_type_call not supported");
unreachable("nir_instr_type_parallel_copy not supported");
break;
case nir_instr_type_deref:
- unreachable("nir_instr_type_deref not supported");
+ /* these are handled in emit_{load,store}_deref */
+ /* emit_deref(ctx, nir_instr_as_deref(instr)); */
break;
}
}
}
+static void
+emit_cf_list(struct ntv_context *ctx, struct exec_list *list);
+
+static SpvId
+get_src_bool(struct ntv_context *ctx, nir_src *src)
+{
+ SpvId def = get_src_uint(ctx, src);
+ assert(nir_src_bit_size(*src) == 32);
+ unsigned num_components = nir_src_num_components(*src);
+ return uvec_to_bvec(ctx, def, num_components);
+}
+
+static void
+emit_if(struct ntv_context *ctx, nir_if *if_stmt)
+{
+ SpvId condition = get_src_bool(ctx, &if_stmt->condition);
+
+ SpvId header_id = spirv_builder_new_id(&ctx->builder);
+ SpvId then_id = block_label(ctx, nir_if_first_then_block(if_stmt));
+ SpvId endif_id = spirv_builder_new_id(&ctx->builder);
+ SpvId else_id = endif_id;
+
+ bool has_else = !exec_list_is_empty(&if_stmt->else_list);
+ if (has_else) {
+ assert(nir_if_first_else_block(if_stmt)->index < ctx->num_blocks);
+ else_id = block_label(ctx, nir_if_first_else_block(if_stmt));
+ }
+
+ /* create a header-block */
+ start_block(ctx, header_id);
+ spirv_builder_emit_selection_merge(&ctx->builder, endif_id,
+ SpvSelectionControlMaskNone);
+ branch_conditional(ctx, condition, then_id, else_id);
+
+ emit_cf_list(ctx, &if_stmt->then_list);
+
+ if (has_else) {
+ if (ctx->block_started)
+ branch(ctx, endif_id);
+
+ emit_cf_list(ctx, &if_stmt->else_list);
+ }
+
+ start_block(ctx, endif_id);
+}
+
+static void
+emit_loop(struct ntv_context *ctx, nir_loop *loop)
+{
+ SpvId header_id = spirv_builder_new_id(&ctx->builder);
+ SpvId begin_id = block_label(ctx, nir_loop_first_block(loop));
+ SpvId break_id = spirv_builder_new_id(&ctx->builder);
+ SpvId cont_id = spirv_builder_new_id(&ctx->builder);
+
+ /* create a header-block */
+ start_block(ctx, header_id);
+ spirv_builder_loop_merge(&ctx->builder, break_id, cont_id, SpvLoopControlMaskNone);
+ branch(ctx, begin_id);
+
+ SpvId save_break = ctx->loop_break;
+ SpvId save_cont = ctx->loop_cont;
+ ctx->loop_break = break_id;
+ ctx->loop_cont = cont_id;
+
+ emit_cf_list(ctx, &loop->body);
+
+ ctx->loop_break = save_break;
+ ctx->loop_cont = save_cont;
+
+ branch(ctx, cont_id);
+ start_block(ctx, cont_id);
+ branch(ctx, header_id);
+
+ start_block(ctx, break_id);
+}
+
static void
emit_cf_list(struct ntv_context *ctx, struct exec_list *list)
{
break;
case nir_cf_node_if:
- unreachable("nir_cf_node_if not supported");
+ emit_if(ctx, nir_cf_node_as_if(node));
break;
case nir_cf_node_loop:
- unreachable("nir_cf_node_loop not supported");
+ emit_loop(ctx, nir_cf_node_as_loop(node));
break;
case nir_cf_node_function:
SpvId type_main = spirv_builder_type_function(&ctx.builder, type_void,
NULL, 0);
SpvId entry_point = spirv_builder_new_id(&ctx.builder);
- SpvId label = spirv_builder_new_id(&ctx.builder);
spirv_builder_emit_name(&ctx.builder, entry_point, "main");
+ ctx.vars = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
+ _mesa_key_pointer_equal);
+
nir_foreach_variable(var, &s->inputs)
emit_input(&ctx, var);
spirv_builder_function(&ctx.builder, entry_point, type_void,
SpvFunctionControlMaskNone,
type_main);
- spirv_builder_label(&ctx.builder, label);
nir_function_impl *entry = nir_shader_get_entrypoint(s);
+ nir_metadata_require(entry, nir_metadata_block_index);
ctx.defs = (SpvId *)malloc(sizeof(SpvId) * entry->ssa_alloc);
if (!ctx.defs)
goto fail;
ctx.num_defs = entry->ssa_alloc;
+ nir_index_local_regs(entry);
+ ctx.regs = malloc(sizeof(SpvId) * entry->reg_alloc);
+ if (!ctx.regs)
+ goto fail;
+ ctx.num_regs = entry->reg_alloc;
+
+ SpvId *block_ids = (SpvId *)malloc(sizeof(SpvId) * entry->num_blocks);
+ if (!block_ids)
+ goto fail;
+
+ for (int i = 0; i < entry->num_blocks; ++i)
+ block_ids[i] = spirv_builder_new_id(&ctx.builder);
+
+ ctx.block_ids = block_ids;
+ ctx.num_blocks = entry->num_blocks;
+
+ /* emit a block only for the variable declarations */
+ start_block(&ctx, spirv_builder_new_id(&ctx.builder));
+ foreach_list_typed(nir_register, reg, node, &entry->registers) {
+ SpvId type = get_uvec_type(&ctx, reg->bit_size, reg->num_components);
+ SpvId pointer_type = spirv_builder_type_pointer(&ctx.builder,
+ SpvStorageClassFunction,
+ type);
+ SpvId var = spirv_builder_emit_var(&ctx.builder, pointer_type,
+ SpvStorageClassFunction);
+
+ ctx.regs[reg->index] = var;
+ }
+
emit_cf_list(&ctx, &entry->body);
+
free(ctx.defs);
spirv_builder_return(&ctx.builder); // doesn't belong here, but whatevz
if (ret)
spirv_shader_delete(ret);
+ if (ctx.vars)
+ _mesa_hash_table_destroy(ctx.vars, NULL);
+
return NULL;
}