#include "util/u_memory.h"
#include "util/hash_table.h"
+/* this consistently maps slots to a zero-indexed value to avoid wasting slots */
+static unsigned slot_pack_map[] = {
+ /* Position is builtin */
+ [VARYING_SLOT_POS] = UINT_MAX,
+ [VARYING_SLOT_COL0] = 0, /* input/output */
+ [VARYING_SLOT_COL1] = 1, /* input/output */
+ [VARYING_SLOT_FOGC] = 2, /* input/output */
+ /* TEX0-7 are translated to VAR0-7 by nir, so we don't need to reserve */
+ [VARYING_SLOT_TEX0] = UINT_MAX, /* input/output */
+ [VARYING_SLOT_TEX1] = UINT_MAX,
+ [VARYING_SLOT_TEX2] = UINT_MAX,
+ [VARYING_SLOT_TEX3] = UINT_MAX,
+ [VARYING_SLOT_TEX4] = UINT_MAX,
+ [VARYING_SLOT_TEX5] = UINT_MAX,
+ [VARYING_SLOT_TEX6] = UINT_MAX,
+ [VARYING_SLOT_TEX7] = UINT_MAX,
+
+ /* PointSize is builtin */
+ [VARYING_SLOT_PSIZ] = UINT_MAX,
+
+ [VARYING_SLOT_BFC0] = 3, /* output only */
+ [VARYING_SLOT_BFC1] = 4, /* output only */
+ [VARYING_SLOT_EDGE] = 5, /* output only */
+ [VARYING_SLOT_CLIP_VERTEX] = 6, /* output only */
+
+ /* ClipDistance is builtin */
+ [VARYING_SLOT_CLIP_DIST0] = UINT_MAX,
+ [VARYING_SLOT_CLIP_DIST1] = UINT_MAX,
+
+ /* CullDistance is builtin */
+ [VARYING_SLOT_CULL_DIST0] = UINT_MAX, /* input/output */
+ [VARYING_SLOT_CULL_DIST1] = UINT_MAX, /* never actually used */
+
+ /* PrimitiveId is builtin */
+ [VARYING_SLOT_PRIMITIVE_ID] = UINT_MAX,
+
+ /* Layer is builtin */
+ [VARYING_SLOT_LAYER] = UINT_MAX, /* input/output */
+
+ /* ViewportIndex is builtin */
+ [VARYING_SLOT_VIEWPORT] = UINT_MAX, /* input/output */
+
+ /* FrontFacing is builtin */
+ [VARYING_SLOT_FACE] = UINT_MAX,
+
+ /* PointCoord is builtin */
+ [VARYING_SLOT_PNTC] = UINT_MAX, /* input only */
+
+ /* TessLevelOuter is builtin */
+ [VARYING_SLOT_TESS_LEVEL_OUTER] = UINT_MAX,
+ /* TessLevelInner is builtin */
+ [VARYING_SLOT_TESS_LEVEL_INNER] = UINT_MAX,
+
+ [VARYING_SLOT_BOUNDING_BOX0] = 7, /* Only appears as TCS output. */
+ [VARYING_SLOT_BOUNDING_BOX1] = 8, /* Only appears as TCS output. */
+ [VARYING_SLOT_VIEW_INDEX] = 9, /* input/output */
+ [VARYING_SLOT_VIEWPORT_MASK] = 10, /* output only */
+};
+#define NTV_MIN_RESERVED_SLOTS 11
+
struct ntv_context {
struct spirv_builder builder;
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;
+ unsigned samplers_used : PIPE_MAX_SAMPLERS;
SpvId entry_ifaces[PIPE_MAX_SHADER_INPUTS * 4 + PIPE_MAX_SHADER_OUTPUTS * 4];
size_t num_entry_ifaces;
size_t num_regs;
struct hash_table *vars; /* nir_variable -> SpvId */
+ struct hash_table *so_outputs; /* pipe_stream_output -> SpvId */
+ unsigned outputs[VARYING_SLOT_MAX];
+ const struct glsl_type *so_output_gl_types[VARYING_SLOT_MAX];
+ SpvId so_output_types[VARYING_SLOT_MAX];
const SpvId *block_ids;
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_uvec_constant(struct ntv_context *ctx, unsigned bit_size,
unsigned num_components, uint32_t value);
+static SpvId
+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 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_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));
+ unsigned bit_size = MAX2(nir_dest_bit_size(*dest), 32);
+ return get_uvec_type(ctx, bit_size, nir_dest_num_components(*dest));
}
static SpvId
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);
unreachable("we shouldn't get here, I think...");
}
+#define HANDLE_EMIT_BUILTIN(SLOT, BUILTIN) \
+ case VARYING_SLOT_##SLOT: \
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltIn##BUILTIN); \
+ break
+
+
static void
emit_input(struct ntv_context *ctx, struct nir_variable *var)
{
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)) {
- spirv_builder_emit_location(&ctx->builder, var_id,
- ctx->var_location++);
- } else {
- switch (var->data.location) {
- case VARYING_SLOT_POS:
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInFragCoord);
- break;
+ unsigned slot = var->data.location;
+ switch (slot) {
+ HANDLE_EMIT_BUILTIN(POS, FragCoord);
+ HANDLE_EMIT_BUILTIN(PNTC, PointCoord);
+ HANDLE_EMIT_BUILTIN(LAYER, Layer);
+ HANDLE_EMIT_BUILTIN(PRIMITIVE_ID, PrimitiveId);
+ HANDLE_EMIT_BUILTIN(CLIP_DIST0, ClipDistance);
+ HANDLE_EMIT_BUILTIN(CULL_DIST0, CullDistance);
+ HANDLE_EMIT_BUILTIN(VIEWPORT, ViewportIndex);
+ HANDLE_EMIT_BUILTIN(FACE, FrontFacing);
- case VARYING_SLOT_PNTC:
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInPointCoord);
- break;
-
- default:
- debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
- unreachable("unexpected varying slot");
- }
+ default:
+ if (slot < VARYING_SLOT_VAR0) {
+ slot = slot_pack_map[slot];
+ if (slot == UINT_MAX)
+ debug_printf("unhandled varying slot: %s\n", gl_varying_slot_name(var->data.location));
+ } else
+ slot -= VARYING_SLOT_VAR0 - NTV_MIN_RESERVED_SLOTS;
+ assert(slot < VARYING_SLOT_VAR0);
+ spirv_builder_emit_location(&ctx->builder, var_id, slot);
}
} else {
spirv_builder_emit_location(&ctx->builder, var_id,
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)) {
- spirv_builder_emit_location(&ctx->builder, var_id,
- 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;
-
- case VARYING_SLOT_CLIP_DIST0:
- assert(glsl_type_is_array(var->type));
- spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInClipDistance);
- break;
+ unsigned slot = var->data.location;
+ switch (slot) {
+ HANDLE_EMIT_BUILTIN(POS, Position);
+ HANDLE_EMIT_BUILTIN(PSIZ, PointSize);
+ HANDLE_EMIT_BUILTIN(LAYER, Layer);
+ HANDLE_EMIT_BUILTIN(PRIMITIVE_ID, PrimitiveId);
+ HANDLE_EMIT_BUILTIN(CULL_DIST0, CullDistance);
+ HANDLE_EMIT_BUILTIN(VIEWPORT, ViewportIndex);
+ HANDLE_EMIT_BUILTIN(TESS_LEVEL_OUTER, TessLevelOuter);
+ HANDLE_EMIT_BUILTIN(TESS_LEVEL_INNER, TessLevelInner);
+
+ case VARYING_SLOT_CLIP_DIST0:
+ assert(glsl_type_is_array(var->type));
+ spirv_builder_emit_builtin(&ctx->builder, var_id, SpvBuiltInClipDistance);
+ /* this can be as large as 2x vec4, which requires 2 slots */
+ ctx->outputs[VARYING_SLOT_CLIP_DIST1] = var_id;
+ ctx->so_output_gl_types[VARYING_SLOT_CLIP_DIST1] = var->type;
+ ctx->so_output_types[VARYING_SLOT_CLIP_DIST1] = var_type;
+ break;
- default:
- debug_printf("unknown varying slot: %s\n", gl_varying_slot_name(var->data.location));
- unreachable("unexpected varying slot");
- }
+ default:
+ if (slot < VARYING_SLOT_VAR0) {
+ slot = slot_pack_map[slot];
+ if (slot == UINT_MAX)
+ debug_printf("unhandled varying slot: %s\n", gl_varying_slot_name(var->data.location));
+ } else
+ slot -= VARYING_SLOT_VAR0 - NTV_MIN_RESERVED_SLOTS;
+ assert(slot < VARYING_SLOT_VAR0);
+ spirv_builder_emit_location(&ctx->builder, var_id, slot);
+ /* non-builtins get location incremented by VARYING_SLOT_VAR0 in vtn, so
+ * use driver_location for non-builtins with defined slots to avoid overlap
+ */
}
+ ctx->outputs[var->data.location] = var_id;
+ ctx->so_output_gl_types[var->data.location] = var->type;
+ ctx->so_output_types[var->data.location] = var_type;
} else if (ctx->stage == MESA_SHADER_FRAGMENT) {
if (var->data.location >= FRAG_RESULT_DATA0)
spirv_builder_emit_location(&ctx->builder, var_id,
switch (var->data.location) {
case FRAG_RESULT_COLOR:
spirv_builder_emit_location(&ctx->builder, var_id, 0);
+ spirv_builder_emit_index(&ctx->builder, var_id, var->data.index);
break;
case FRAG_RESULT_DEPTH:
spirv_builder_emit_component(&ctx->builder, var_id,
var->data.location_frac);
+ switch (var->data.interpolation) {
+ case INTERP_MODE_NONE:
+ case INTERP_MODE_SMOOTH: /* XXX spirv doesn't seem to have anything for this */
+ break;
+ case INTERP_MODE_FLAT:
+ spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationFlat);
+ break;
+ case INTERP_MODE_EXPLICIT:
+ spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationExplicitInterpAMD);
+ break;
+ case INTERP_MODE_NOPERSPECTIVE:
+ spirv_builder_emit_decoration(&ctx->builder, var_id, SpvDecorationNoPerspective);
+ break;
+ default:
+ unreachable("unknown interpolation value");
+ }
+
_mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id);
assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces));
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 SpvDim2D;
+ 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;
return SpvDim2D;
}
+uint32_t
+zink_binding(gl_shader_stage stage, VkDescriptorType type, int index)
+{
+ if (stage == MESA_SHADER_NONE ||
+ stage >= MESA_SHADER_COMPUTE) {
+ unreachable("not supported");
+ } else {
+ uint32_t stage_offset = (uint32_t)stage * (PIPE_MAX_CONSTANT_BUFFERS +
+ PIPE_MAX_SHADER_SAMPLER_VIEWS);
+
+ switch (type) {
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ assert(index < PIPE_MAX_CONSTANT_BUFFERS);
+ return stage_offset + index;
+
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ assert(index < PIPE_MAX_SHADER_SAMPLER_VIEWS);
+ return stage_offset + PIPE_MAX_CONSTANT_BUFFERS + index;
+
+ default:
+ unreachable("unexpected type");
+ }
+ }
+}
+
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);
+ int index = var->data.binding + i;
+ assert(!(ctx->samplers_used & (1 << index)));
+ assert(!ctx->image_types[index]);
+ ctx->image_types[index] = image_type;
+ ctx->samplers[index] = var_id;
+ ctx->samplers_used |= 1 << index;
+
+ spirv_builder_emit_descriptor_set(&ctx->builder, var_id,
+ var->data.descriptor_set);
+ int binding = zink_binding(ctx->stage,
+ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ var->data.binding + i);
+ spirv_builder_emit_binding(&ctx->builder, var_id, 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);
+
+ int index = var->data.binding;
+ assert(!(ctx->samplers_used & (1 << index)));
+ assert(!ctx->image_types[index]);
+ ctx->image_types[index] = image_type;
+ ctx->samplers[index] = var_id;
+ ctx->samplers_used |= 1 << index;
+
+ spirv_builder_emit_descriptor_set(&ctx->builder, var_id,
+ var->data.descriptor_set);
+ int binding = zink_binding(ctx->stage,
+ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ var->data.binding);
+ spirv_builder_emit_binding(&ctx->builder, var_id, binding);
+ }
}
static void
spirv_builder_emit_descriptor_set(&ctx->builder, var_id,
var->data.descriptor_set);
- spirv_builder_emit_binding(&ctx->builder, var_id, var->data.binding);
+ int binding = zink_binding(ctx->stage,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ var->data.binding);
+ spirv_builder_emit_binding(&ctx->builder, var_id, binding);
}
static void
emit_ubo(ctx, var);
else {
assert(var->data.mode == nir_var_uniform);
- if (glsl_type_is_sampler(var->type))
+ if (glsl_type_is_sampler(glsl_without_array(var->type)))
emit_sampler(ctx, var);
}
}
static SpvId
-get_src_uint_ssa(struct ntv_context *ctx, const nir_ssa_def *ssa)
+get_src_ssa(struct ntv_context *ctx, const nir_ssa_def *ssa)
{
assert(ssa->index < ctx->num_defs);
assert(ctx->defs[ssa->index] != 0);
}
static SpvId
-get_src_uint_reg(struct ntv_context *ctx, const nir_reg_src *reg)
+get_src_reg(struct ntv_context *ctx, const nir_reg_src *reg)
{
assert(reg->reg);
assert(!reg->indirect);
}
static SpvId
-get_src_uint(struct ntv_context *ctx, nir_src *src)
+get_src(struct ntv_context *ctx, nir_src *src)
{
if (src->is_ssa)
- return get_src_uint_ssa(ctx, src->ssa);
+ return get_src_ssa(ctx, src->ssa);
else
- return get_src_uint_reg(ctx, &src->reg);
+ return get_src_reg(ctx, &src->reg);
}
static SpvId
-get_alu_src_uint(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
+get_alu_src_raw(struct ntv_context *ctx, nir_alu_instr *alu, unsigned src)
{
assert(!alu->src[src].negate);
assert(!alu->src[src].abs);
- SpvId def = get_src_uint(ctx, &alu->src[src].src);
+ SpvId def = get_src(ctx, &alu->src[src].src);
unsigned used_channels = 0;
bool need_swizzle = false;
return def;
int bit_size = nir_src_bit_size(alu->src[src].src);
- assert(bit_size == 32);
+ assert(bit_size == 1 || bit_size == 32);
+
+ SpvId raw_type = bit_size == 1 ? spirv_builder_type_bool(&ctx->builder) :
+ spirv_builder_type_uint(&ctx->builder, bit_size);
- SpvId uint_type = spirv_builder_type_uint(&ctx->builder, bit_size);
if (used_channels == 1) {
uint32_t indices[] = { alu->src[src].swizzle[0] };
- return spirv_builder_emit_composite_extract(&ctx->builder, uint_type,
+ return spirv_builder_emit_composite_extract(&ctx->builder, raw_type,
def, indices,
ARRAY_SIZE(indices));
} else if (live_channels == 1) {
- SpvId uvec_type = spirv_builder_type_vector(&ctx->builder, uint_type,
- used_channels);
+ SpvId raw_vec_type = spirv_builder_type_vector(&ctx->builder,
+ raw_type,
+ used_channels);
- SpvId constituents[NIR_MAX_VEC_COMPONENTS];
+ SpvId constituents[NIR_MAX_VEC_COMPONENTS] = {0};
for (unsigned i = 0; i < used_channels; ++i)
constituents[i] = def;
- return spirv_builder_emit_composite_construct(&ctx->builder, uvec_type,
+ return spirv_builder_emit_composite_construct(&ctx->builder,
+ raw_vec_type,
constituents,
used_channels);
} else {
- SpvId uvec_type = spirv_builder_type_vector(&ctx->builder, uint_type,
- used_channels);
+ SpvId raw_vec_type = spirv_builder_type_vector(&ctx->builder,
+ raw_type,
+ used_channels);
- uint32_t components[NIR_MAX_VEC_COMPONENTS];
+ uint32_t components[NIR_MAX_VEC_COMPONENTS] = {0};
size_t num_components = 0;
for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; i++) {
if (!nir_alu_instr_channel_used(alu, src, i))
components[num_components++] = alu->src[src].swizzle[i];
}
- return spirv_builder_emit_vector_shuffle(&ctx->builder, uvec_type,
- def, def, components, num_components);
+ return spirv_builder_emit_vector_shuffle(&ctx->builder, raw_vec_type,
+ def, def, components,
+ num_components);
}
}
static void
-store_ssa_def_uint(struct ntv_context *ctx, nir_ssa_def *ssa, SpvId result)
+store_ssa_def(struct ntv_context *ctx, nir_ssa_def *ssa, SpvId result)
{
assert(result != 0);
assert(ssa->index < ctx->num_defs);
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);
- 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)
{
}
static void
-store_dest_uint(struct ntv_context *ctx, nir_dest *dest, SpvId result)
+store_dest_raw(struct ntv_context *ctx, nir_dest *dest, SpvId result)
{
if (dest->is_ssa)
- store_ssa_def_uint(ctx, &dest->ssa, result);
+ store_ssa_def(ctx, &dest->ssa, result);
else
store_reg_def(ctx, &dest->reg, result);
}
-static void
+static SpvId
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;
+ if (bit_size != 1) {
+ switch (nir_alu_type_get_base_type(type)) {
+ case nir_type_bool:
+ assert("bool should have bit-size 1");
- case nir_type_uint:
- break; /* nothing to do! */
+ 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;
+ 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");
+ default:
+ unreachable("unsupported nir_alu_type");
+ }
}
- store_dest_uint(ctx, dest, result);
+ store_dest_raw(ctx, dest, result);
+ return result;
}
static SpvId
return spirv_builder_emit_unop(&ctx->builder, op, type, src);
}
+/* return the intended xfb output vec type based on base type and vector size */
+static SpvId
+get_output_type(struct ntv_context *ctx, unsigned register_index, unsigned num_components)
+{
+ const struct glsl_type *out_type = ctx->so_output_gl_types[register_index];
+ enum glsl_base_type base_type = glsl_get_base_type(out_type);
+ if (base_type == GLSL_TYPE_ARRAY)
+ base_type = glsl_get_base_type(glsl_without_array(out_type));
+
+ switch (base_type) {
+ case GLSL_TYPE_BOOL:
+ return get_bvec_type(ctx, num_components);
+
+ case GLSL_TYPE_FLOAT:
+ return get_fvec_type(ctx, 32, num_components);
+
+ case GLSL_TYPE_INT:
+ return get_ivec_type(ctx, 32, num_components);
+
+ case GLSL_TYPE_UINT:
+ return get_uvec_type(ctx, 32, num_components);
+
+ default:
+ break;
+ }
+ unreachable("unknown type");
+ return 0;
+}
+
+/* for streamout create new outputs, as streamout can be done on individual components,
+ from complete outputs, so we just can't use the created packed outputs */
+static void
+emit_so_info(struct ntv_context *ctx, unsigned max_output_location,
+ const struct pipe_stream_output_info *so_info, struct pipe_stream_output_info *local_so_info)
+{
+ for (unsigned i = 0; i < local_so_info->num_outputs; i++) {
+ struct pipe_stream_output so_output = local_so_info->output[i];
+ SpvId out_type = get_output_type(ctx, so_output.register_index, so_output.num_components);
+ SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder,
+ SpvStorageClassOutput,
+ out_type);
+ SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type,
+ SpvStorageClassOutput);
+ char name[10];
+
+ snprintf(name, 10, "xfb%d", i);
+ spirv_builder_emit_name(&ctx->builder, var_id, name);
+ spirv_builder_emit_offset(&ctx->builder, var_id, (so_output.dst_offset * 4));
+ spirv_builder_emit_xfb_buffer(&ctx->builder, var_id, so_output.output_buffer);
+ spirv_builder_emit_xfb_stride(&ctx->builder, var_id, so_info->stride[so_output.output_buffer] * 4);
+
+ /* output location is incremented by VARYING_SLOT_VAR0 for non-builtins in vtn,
+ * so we need to ensure that the new xfb location slot doesn't conflict with any previously-emitted
+ * outputs.
+ *
+ * if there's no previous outputs that take up user slots (VAR0+) then we can start right after the
+ * glsl builtin reserved slots, otherwise we start just after the adjusted user output slot
+ */
+ uint32_t location = NTV_MIN_RESERVED_SLOTS + i;
+ if (max_output_location >= VARYING_SLOT_VAR0)
+ location = max_output_location - VARYING_SLOT_VAR0 + 1 + i;
+ assert(location < VARYING_SLOT_VAR0);
+ spirv_builder_emit_location(&ctx->builder, var_id, location);
+
+ /* note: gl_ClipDistance[4] can the 0-indexed member of VARYING_SLOT_CLIP_DIST1 here,
+ * so this is still the 0 component
+ */
+ if (so_output.start_component)
+ spirv_builder_emit_component(&ctx->builder, var_id, so_output.start_component);
+
+ uint32_t *key = ralloc_size(NULL, sizeof(uint32_t));
+ *key = (uint32_t)so_output.register_index << 2 | so_output.start_component;
+ _mesa_hash_table_insert(ctx->so_outputs, key, (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_so_outputs(struct ntv_context *ctx,
+ const struct pipe_stream_output_info *so_info, struct pipe_stream_output_info *local_so_info)
+{
+ SpvId loaded_outputs[VARYING_SLOT_MAX] = {};
+ for (unsigned i = 0; i < local_so_info->num_outputs; i++) {
+ uint32_t components[NIR_MAX_VEC_COMPONENTS];
+ struct pipe_stream_output so_output = local_so_info->output[i];
+ uint32_t so_key = (uint32_t) so_output.register_index << 2 | so_output.start_component;
+ struct hash_entry *he = _mesa_hash_table_search(ctx->so_outputs, &so_key);
+ assert(he);
+ SpvId so_output_var_id = (SpvId)(intptr_t)he->data;
+
+ SpvId type = get_output_type(ctx, so_output.register_index, so_output.num_components);
+ SpvId output = ctx->outputs[so_output.register_index];
+ SpvId output_type = ctx->so_output_types[so_output.register_index];
+ const struct glsl_type *out_type = ctx->so_output_gl_types[so_output.register_index];
+
+ if (!loaded_outputs[so_output.register_index])
+ loaded_outputs[so_output.register_index] = spirv_builder_emit_load(&ctx->builder, output_type, output);
+ SpvId src = loaded_outputs[so_output.register_index];
+
+ SpvId result;
+
+ for (unsigned c = 0; c < so_output.num_components; c++) {
+ components[c] = so_output.start_component + c;
+ /* this is the second half of a 2 * vec4 array */
+ if (ctx->stage == MESA_SHADER_VERTEX && so_output.register_index == VARYING_SLOT_CLIP_DIST1)
+ components[c] += 4;
+ }
+
+ /* if we're emitting a scalar or the type we're emitting matches the output's original type and we're
+ * emitting the same number of components, then we can skip any sort of conversion here
+ */
+ if (glsl_type_is_scalar(out_type) || (type == output_type && glsl_get_length(out_type) == so_output.num_components))
+ result = src;
+ else {
+ /* OpCompositeExtract can only extract scalars for our use here */
+ if (so_output.num_components == 1) {
+ result = spirv_builder_emit_composite_extract(&ctx->builder, type, src, components, so_output.num_components);
+ } else if (glsl_type_is_vector(out_type)) {
+ /* OpVectorShuffle can select vector members into a differently-sized vector */
+ result = spirv_builder_emit_vector_shuffle(&ctx->builder, type,
+ src, src,
+ components, so_output.num_components);
+ result = emit_unop(ctx, SpvOpBitcast, type, result);
+ } else {
+ /* for arrays, we need to manually extract each desired member
+ * and re-pack them into the desired output type
+ */
+ for (unsigned c = 0; c < so_output.num_components; c++) {
+ uint32_t member[] = { so_output.start_component + c };
+ SpvId base_type = get_glsl_type(ctx, glsl_without_array(out_type));
+
+ if (ctx->stage == MESA_SHADER_VERTEX && so_output.register_index == VARYING_SLOT_CLIP_DIST1)
+ member[0] += 4;
+ components[c] = spirv_builder_emit_composite_extract(&ctx->builder, base_type, src, member, 1);
+ }
+ result = spirv_builder_emit_composite_construct(&ctx->builder, type, components, so_output.num_components);
+ }
+ }
+
+ spirv_builder_emit_store(&ctx->builder, so_output_var_id, result);
+ }
+}
+
static SpvId
emit_binop(struct ntv_context *ctx, SpvOp op, SpvId type,
SpvId src0, SpvId src1)
op, args, ARRAY_SIZE(args));
}
+static SpvId
+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)
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
alu_instr_src_components(const nir_alu_instr *instr, unsigned src)
{
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);
+ SpvId raw_value = get_alu_src_raw(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);
+ if (bit_size == 1)
+ return raw_value;
+ else {
+ switch (nir_alu_type_get_base_type(type)) {
+ case nir_type_bool:
+ unreachable("bool should have bit-size 1");
- case nir_type_int:
- return bitcast_to_ivec(ctx, uint_value, bit_size, num_components);
+ case nir_type_int:
+ return bitcast_to_ivec(ctx, raw_value, bit_size, num_components);
- case nir_type_uint:
- return uint_value;
+ case nir_type_uint:
+ return raw_value;
- case nir_type_float:
- return bitcast_to_fvec(ctx, uint_value, bit_size, num_components);
+ case nir_type_float:
+ return bitcast_to_fvec(ctx, raw_value, bit_size, num_components);
- default:
- unreachable("unknown nir_alu_type");
+ default:
+ unreachable("unknown nir_alu_type");
+ }
}
}
-static void
+static SpvId
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);
+ return store_dest(ctx, &alu->dest.dest, result,
+ nir_op_infos[alu->op].output_type);
}
static SpvId
unsigned num_components = nir_dest_num_components(*dest);
unsigned bit_size = nir_dest_bit_size(*dest);
+ if (bit_size == 1)
+ return get_bvec_type(ctx, num_components);
+
switch (nir_alu_type_get_base_type(type)) {
case nir_type_bool:
- return get_bvec_type(ctx, num_components);
+ unreachable("bool should have bit-size 1");
case nir_type_int:
return get_ivec_type(ctx, bit_size, num_components);
emit_alu(struct ntv_context *ctx, nir_alu_instr *alu)
{
SpvId src[nir_op_infos[alu->op].num_inputs];
- for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++)
+ unsigned in_bit_sizes[nir_op_infos[alu->op].num_inputs];
+ for (unsigned i = 0; i < nir_op_infos[alu->op].num_inputs; i++) {
src[i] = get_alu_src(ctx, alu, i);
+ in_bit_sizes[i] = nir_src_bit_size(alu->src[i].src);
+ }
SpvId dest_type = get_dest_type(ctx, &alu->dest.dest,
nir_op_infos[alu->op].output_type);
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_inot:
+ if (bit_size == 1)
+ result = emit_unop(ctx, SpvOpLogicalNot, dest_type, src[0]);
+ else
+ result = emit_unop(ctx, SpvOpNot, dest_type, src[0]);
+ break;
+
case nir_op_b2i32:
assert(nir_op_infos[alu->op].num_inputs == 1);
result = emit_select(ctx, dest_type, src[0],
- get_uvec_constant(ctx, 32, num_components, 1),
- get_uvec_constant(ctx, 32, num_components, 0));
+ get_ivec_constant(ctx, 32, num_components, 1),
+ get_ivec_constant(ctx, 32, num_components, 0));
break;
case nir_op_b2f32:
result = emit_builtin_unop(ctx, spirv_op, dest_type, src[0]); \
break;
+ BUILTIN_UNOP(nir_op_iabs, GLSLstd450SAbs)
BUILTIN_UNOP(nir_op_fabs, GLSLstd450FAbs)
BUILTIN_UNOP(nir_op_fsqrt, GLSLstd450Sqrt)
BUILTIN_UNOP(nir_op_frsq, GLSLstd450InverseSqrt)
nir_src_bit_size(alu->src[0].src),
num_components, 0));
break;
+ case nir_op_i2b1:
+ assert(nir_op_infos[alu->op].num_inputs == 1);
+ result = emit_binop(ctx, SpvOpINotEqual, dest_type, src[0],
+ get_ivec_constant(ctx,
+ nir_src_bit_size(alu->src[0].src),
+ num_components, 0));
+ break;
#define BINOP(nir_op, spirv_op) \
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_fmod, SpvOpFMod)
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_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 BINOP_LOG(nir_op, spv_op, spv_log_op) \
+ case nir_op: \
+ assert(nir_op_infos[alu->op].num_inputs == 2); \
+ if (nir_src_bit_size(alu->src[0].src) == 1) \
+ result = emit_binop(ctx, spv_log_op, dest_type, src[0], src[1]); \
+ else \
+ result = emit_binop(ctx, spv_op, dest_type, src[0], src[1]); \
+ break;
+
+ BINOP_LOG(nir_op_iand, SpvOpBitwiseAnd, SpvOpLogicalAnd)
+ BINOP_LOG(nir_op_ior, SpvOpBitwiseOr, SpvOpLogicalOr)
+ BINOP_LOG(nir_op_ieq, SpvOpIEqual, SpvOpLogicalEqual)
+ BINOP_LOG(nir_op_ine, SpvOpINotEqual, SpvOpLogicalNotEqual)
+#undef BINOP_LOG
+
#define BUILTIN_BINOP(nir_op, spirv_op) \
case nir_op: \
assert(nir_op_infos[alu->op].num_inputs == 2); \
BUILTIN_BINOP(nir_op_fmin, GLSLstd450FMin)
BUILTIN_BINOP(nir_op_fmax, GLSLstd450FMax)
+ BUILTIN_BINOP(nir_op_imin, GLSLstd450SMin)
+ BUILTIN_BINOP(nir_op_imax, GLSLstd450SMax)
+ BUILTIN_BINOP(nir_op_umin, GLSLstd450UMin)
+ BUILTIN_BINOP(nir_op_umax, GLSLstd450UMax)
#undef BUILTIN_BINOP
case nir_op_fdot2:
result = emit_binop(ctx, SpvOpDot, dest_type, src[0], src[1]);
break;
+ case nir_op_fdph:
+ unreachable("should already be lowered away");
+
case nir_op_seq:
case nir_op_sne:
case nir_op_slt:
}
break;
+ case nir_op_flrp:
+ assert(nir_op_infos[alu->op].num_inputs == 3);
+ result = emit_builtin_triop(ctx, GLSLstd450FMix, dest_type,
+ src[0], src[1], src[2]);
+ break;
+
case nir_op_fcsel:
result = emit_binop(ctx, SpvOpFOrdGreaterThan,
get_bvec_type(ctx, num_components),
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));
+ assert(in_bit_sizes[0] == in_bit_sizes[1]);
+ /* The type of Operand 1 and Operand 2 must be a scalar or vector of floating-point type. */
+ SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalNotEqual : SpvOpFOrdNotEqual;
+ result = emit_binop(ctx, op,
+ 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));
+ assert(in_bit_sizes[0] == in_bit_sizes[1]);
+ /* The type of Operand 1 and Operand 2 must be a scalar or vector of floating-point type. */
+ SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalEqual : SpvOpFOrdEqual;
+ result = emit_binop(ctx, op,
+ 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));
+ assert(in_bit_sizes[0] == in_bit_sizes[1]);
+ /* The type of Operand 1 and Operand 2 must be a scalar or vector of integer type. */
+ SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalNotEqual : SpvOpINotEqual;
+ result = emit_binop(ctx, op,
+ 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));
+ assert(in_bit_sizes[0] == in_bit_sizes[1]);
+ /* The type of Operand 1 and Operand 2 must be a scalar or vector of integer type. */
+ SpvOp op = in_bit_sizes[0] == 1 ? SpvOpLogicalEqual : SpvOpIEqual;
+ result = emit_binop(ctx, op,
+ 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:
case nir_op_vec3:
case nir_op_vec4: {
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];
- for (int i = 0; i < num_components; i++)
- components[i] = emit_uint_const(ctx, bit_size, values[i]);
+ 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);
- SpvId type = get_uvec_type(ctx, bit_size, num_components);
+ 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);
- constant = emit_uint_const(ctx, bit_size, values[0]);
+ 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);
}
- store_ssa_def_uint(ctx, &load_const->def, constant);
+ store_ssa_def(ctx, &load_const->def, constant);
}
static void
num_components);
}
- store_dest_uint(ctx, &intr->dest, result);
+ if (nir_dest_bit_size(intr->dest) == 1)
+ result = uvec_to_bvec(ctx, result, num_components);
+
+ store_dest(ctx, &intr->dest, result, nir_type_uint);
} else
unreachable("uniform-addressing not yet supported");
}
static void
emit_load_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
{
- /* 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(ctx, intr->src);
nir_variable *var = nir_intrinsic_get_var(intr, 0);
SpvId result = spirv_builder_emit_load(&ctx->builder,
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);
+ store_dest(ctx, &intr->dest, result, nir_type_uint);
}
static void
emit_store_deref(struct ntv_context *ctx, nir_intrinsic_instr *intr)
{
- /* 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 ptr = get_src(ctx, &intr->src[0]);
+ SpvId src = get_src(ctx, &intr->src[1]);
nir_variable *var = nir_intrinsic_get_var(intr, 0);
SpvId type = get_glsl_type(ctx, glsl_without_array(var->type));
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));
+ store_dest(ctx, &intr->dest, result, nir_type_bool);
+}
+
+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(ctx, &intr->dest, result, nir_type_uint);
+}
+
+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(ctx, &intr->dest, result, nir_type_uint);
+}
+
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);
SpvId type = get_uvec_type(ctx, undef->def.bit_size,
undef->def.num_components);
- store_ssa_def_uint(ctx, &undef->def,
- spirv_builder_emit_undef(&ctx->builder, type));
+ store_ssa_def(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);
+ SpvId def = get_src(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 SpvId
+get_src_int(struct ntv_context *ctx, nir_src *src)
+{
+ SpvId def = get_src(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 ||
tex->op == nir_texop_txb ||
- tex->op == nir_texop_txl);
- assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float);
+ tex->op == nir_texop_txl ||
+ tex->op == nir_texop_txd ||
+ tex->op == nir_texop_txf ||
+ tex->op == nir_texop_txf_ms ||
+ tex->op == nir_texop_txs);
assert(tex->texture_index == tex->sampler_index);
- SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0;
- unsigned coord_components;
+ SpvId coord = 0, proj = 0, bias = 0, lod = 0, dref = 0, dx = 0, dy = 0,
+ offset = 0, sample = 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 ||
+ tex->op == nir_texop_txf_ms)
+ 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;
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);
case nir_tex_src_lod:
assert(nir_src_num_components(tex->src[i].src) == 1);
- lod = get_src_float(ctx, &tex->src[i].src);
+ if (tex->op == nir_texop_txf ||
+ tex->op == nir_texop_txf_ms ||
+ 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_ms_index:
+ assert(nir_src_num_components(tex->src[i].src) == 1);
+ sample = get_src_int(ctx, &tex->src[i].src);
+ 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:
fprintf(stderr, "texture source: %d\n", tex->src[i].src_type);
unreachable("unknown texture source");
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);
- assert(tex->texture_index < ctx->num_samplers);
+ assert(ctx->samplers_used & (1u << tex->texture_index));
SpvId load = spirv_builder_emit_load(&ctx->builder, sampled_type,
ctx->samplers[tex->texture_index]);
SpvId dest_type = get_dest_type(ctx, &tex->dest, tex->dest_type);
- if (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];
if (coord_components == 1)
constituents[0] = coord;
SpvId actual_dest_type = dest_type;
if (dref)
- actual_dest_type = float_type;
+ actual_dest_type = spirv_builder_type_float(&ctx->builder, 32);
+
+ SpvId result;
+ if (tex->op == nir_texop_txf ||
+ tex->op == nir_texop_txf_ms) {
+ SpvId image = spirv_builder_emit_image(&ctx->builder, image_type, load);
+ result = spirv_builder_emit_image_fetch(&ctx->builder, dest_type,
+ image, coord, lod, sample);
+ } else {
+ result = spirv_builder_emit_image_sample(&ctx->builder,
+ actual_dest_type, load,
+ coord,
+ proj != 0,
+ lod, bias, dref, dx, dy,
+ offset);
+ }
- SpvId result = spirv_builder_emit_image_sample(&ctx->builder,
- actual_dest_type, load,
- coord,
- proj != 0,
- lod, bias, dref);
spirv_builder_emit_decoration(&ctx->builder, result,
SpvDecorationRelaxedPrecision);
- if (dref) {
+ 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,
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);
+ store_dest_raw(ctx, &deref->dest, result);
}
static void
unreachable("Unsupported nir_variable_mode\n");
}
- SpvId index = get_src_uint(ctx, &deref->arr.index);
+ SpvId index = get_src(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,
- get_src_uint(ctx, &deref->parent),
+ get_src(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);
+ store_dest(ctx, &deref->dest, result, nir_type_uint);
}
static void
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);
+ assert(nir_src_bit_size(*src) == 1);
+ return get_src(ctx, src);
}
static void
}
struct spirv_shader *
-nir_to_spirv(struct nir_shader *s)
+nir_to_spirv(struct nir_shader *s, const struct pipe_stream_output_info *so_info, struct pipe_stream_output_info *local_so_info)
{
struct spirv_shader *ret = NULL;
}
// TODO: only enable when needed
- if (s->info.stage == MESA_SHADER_FRAGMENT)
+ 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");
ctx.vars = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
+ ctx.so_outputs = _mesa_hash_table_create(NULL, _mesa_hash_u32,
+ _mesa_key_u32_equal);
+
nir_foreach_variable(var, &s->inputs)
emit_input(&ctx, var);
nir_foreach_variable(var, &s->outputs)
emit_output(&ctx, var);
+ if (so_info)
+ emit_so_info(&ctx, util_last_bit64(s->info.outputs_written), so_info, local_so_info);
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) {
spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
SpvExecutionModeOriginUpperLeft);
SpvExecutionModeDepthReplacing);
}
+ if (so_info && so_info->num_outputs) {
+ spirv_builder_emit_cap(&ctx.builder, SpvCapabilityTransformFeedback);
+ spirv_builder_emit_exec_mode(&ctx.builder, entry_point,
+ SpvExecutionModeXfb);
+ }
spirv_builder_function(&ctx.builder, entry_point, type_void,
SpvFunctionControlMaskNone,
free(ctx.defs);
+ if (so_info)
+ emit_so_outputs(&ctx, so_info, local_so_info);
+
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);
if (ctx.vars)
_mesa_hash_table_destroy(ctx.vars, NULL);
+ if (ctx.so_outputs)
+ _mesa_hash_table_destroy(ctx.so_outputs, NULL);
+
return NULL;
}