vtn_handle_extension(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
+ const char *ext = (const char *)&w[2];
switch (opcode) {
case SpvOpExtInstImport: {
struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_extension);
- if (strcmp((const char *)&w[2], "GLSL.std.450") == 0) {
+ if (strcmp(ext, "GLSL.std.450") == 0) {
val->ext_handler = vtn_handle_glsl450_instruction;
- } else if ((strcmp((const char *)&w[2], "SPV_AMD_gcn_shader") == 0)
+ } else if ((strcmp(ext, "SPV_AMD_gcn_shader") == 0)
&& (b->options && b->options->caps.gcn_shader)) {
val->ext_handler = vtn_handle_amd_gcn_shader_instruction;
- } else if ((strcmp((const char *)&w[2], "SPV_AMD_shader_trinary_minmax") == 0)
+ } else if ((strcmp(ext, "SPV_AMD_shader_trinary_minmax") == 0)
&& (b->options && b->options->caps.trinary_minmax)) {
val->ext_handler = vtn_handle_amd_shader_trinary_minmax_instruction;
} else {
- vtn_fail("Unsupported extension");
+ vtn_fail("Unsupported extension: %s", ext);
}
break;
}
case SpvOpDecorate:
case SpvOpMemberDecorate:
+ case SpvOpDecorateStringGOOGLE:
+ case SpvOpMemberDecorateStringGOOGLE:
case SpvOpExecutionMode: {
struct vtn_value *val = vtn_untyped_value(b, target);
struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
switch (opcode) {
case SpvOpDecorate:
+ case SpvOpDecorateStringGOOGLE:
dec->scope = VTN_DEC_DECORATION;
break;
case SpvOpMemberDecorate:
+ case SpvOpMemberDecorateStringGOOGLE:
dec->scope = VTN_DEC_STRUCT_MEMBER0 + *(w++);
vtn_fail_if(dec->scope < VTN_DEC_STRUCT_MEMBER0, /* overflow */
"Member argument of OpMemberDecorate too large");
}
static void
+vtn_handle_access_qualifier(struct vtn_builder *b, struct vtn_type *type,
+ int member, enum gl_access_qualifier access)
+{
+ type->members[member] = vtn_type_copy(b, type->members[member]);
+ type = type->members[member];
+
+ type->access |= access;
+}
+
+static void
struct_member_decoration_cb(struct vtn_builder *b,
struct vtn_value *val, int member,
const struct vtn_decoration *dec, void *void_ctx)
assert(member < ctx->num_fields);
switch (dec->decoration) {
+ case SpvDecorationRelaxedPrecision:
+ case SpvDecorationUniform:
+ break; /* FIXME: Do nothing with this for now. */
case SpvDecorationNonWritable:
+ vtn_handle_access_qualifier(b, ctx->type, member, ACCESS_NON_WRITEABLE);
+ break;
case SpvDecorationNonReadable:
- case SpvDecorationRelaxedPrecision:
+ vtn_handle_access_qualifier(b, ctx->type, member, ACCESS_NON_READABLE);
+ break;
case SpvDecorationVolatile:
+ vtn_handle_access_qualifier(b, ctx->type, member, ACCESS_VOLATILE);
+ break;
case SpvDecorationCoherent:
- case SpvDecorationUniform:
- break; /* FIXME: Do nothing with this for now. */
+ vtn_handle_access_qualifier(b, ctx->type, member, ACCESS_COHERENT);
+ break;
case SpvDecorationNoPerspective:
ctx->fields[member].interpolation = INTERP_MODE_NOPERSPECTIVE;
break;
spirv_decoration_to_string(dec->decoration));
break;
+ case SpvDecorationHlslSemanticGOOGLE:
+ /* HLSL semantic decorations can safely be ignored by the driver. */
+ break;
+
default:
vtn_fail("Unhandled decoration");
}
case SpvDecorationNonWritable:
case SpvDecorationNonReadable:
case SpvDecorationUniform:
- case SpvDecorationStream:
case SpvDecorationLocation:
case SpvDecorationComponent:
case SpvDecorationOffset:
case SpvDecorationXfbBuffer:
case SpvDecorationXfbStride:
+ case SpvDecorationHlslSemanticGOOGLE:
vtn_warn("Decoration only allowed for struct members: %s",
spirv_decoration_to_string(dec->decoration));
break;
+ case SpvDecorationStream:
+ /* We don't need to do anything here, as stream is filled up when
+ * aplying the decoration to a variable, just check that if it is not a
+ * struct member, it should be a struct.
+ */
+ vtn_assert(type->base_type == vtn_base_type_struct);
+ break;
+
case SpvDecorationRelaxedPrecision:
case SpvDecorationSpecId:
case SpvDecorationInvariant:
spirv_op_to_string(opcode), elem_count, val->type->length);
nir_constant **elems = ralloc_array(b, nir_constant *, elem_count);
- for (unsigned i = 0; i < elem_count; i++)
- elems[i] = vtn_value(b, w[i + 3], vtn_value_type_constant)->constant;
+ for (unsigned i = 0; i < elem_count; i++) {
+ struct vtn_value *val = vtn_untyped_value(b, w[i + 3]);
+
+ if (val->value_type == vtn_value_type_constant) {
+ elems[i] = val->constant;
+ } else {
+ vtn_fail_if(val->value_type != vtn_value_type_undef,
+ "only constants or undefs allowed for "
+ "SpvOpConstantComposite");
+ /* to make it easier, just insert a NULL constant for now */
+ elems[i] = vtn_null_constant(b, val->type->type);
+ }
+ }
switch (val->type->base_type) {
case vtn_base_type_vector: {
nir_const_value src[4];
for (unsigned i = 0; i < count - 4; i++) {
- nir_constant *c =
- vtn_value(b, w[4 + i], vtn_value_type_constant)->constant;
+ struct vtn_value *src_val =
+ vtn_value(b, w[4 + i], vtn_value_type_constant);
+
+ /* If this is an unsized source, pull the bit size from the
+ * source; otherwise, we'll use the bit size from the destination.
+ */
+ if (!nir_alu_type_get_type_size(nir_op_infos[op].input_types[i]))
+ bit_size = glsl_get_bit_size(src_val->type->type);
unsigned j = swap ? 1 - i : i;
- src[j] = c->values[0];
+ src[j] = src_val->constant->values[0];
+ }
+
+ /* fix up fixed size sources */
+ switch (op) {
+ case nir_op_ishl:
+ case nir_op_ishr:
+ case nir_op_ushr: {
+ if (bit_size == 32)
+ break;
+ for (unsigned i = 0; i < num_components; ++i) {
+ switch (bit_size) {
+ case 64: src[1].u32[i] = src[1].u64[i]; break;
+ case 16: src[1].u32[i] = src[1].u16[i]; break;
+ case 8: src[1].u32[i] = src[1].u8[i]; break;
+ }
+ }
+ break;
+ }
+ default:
+ break;
}
val->constant->values[0] =
vtn_foreach_decoration(b, val, handle_workgroup_size_decoration_cb, NULL);
}
-static void
-vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,
- const uint32_t *w, unsigned count)
-{
- struct vtn_type *res_type = vtn_value(b, w[1], vtn_value_type_type)->type;
- struct vtn_function *vtn_callee =
- vtn_value(b, w[3], vtn_value_type_function)->func;
- struct nir_function *callee = vtn_callee->impl->function;
-
- vtn_callee->referenced = true;
-
- nir_call_instr *call = nir_call_instr_create(b->nb.shader, callee);
-
- unsigned param_idx = 0;
-
- nir_deref_instr *ret_deref = NULL;
- struct vtn_type *ret_type = vtn_callee->type->return_type;
- if (ret_type->base_type != vtn_base_type_void) {
- nir_variable *ret_tmp =
- nir_local_variable_create(b->nb.impl, ret_type->type, "return_tmp");
- ret_deref = nir_build_deref_var(&b->nb, ret_tmp);
- call->params[param_idx++] = nir_src_for_ssa(&ret_deref->dest.ssa);
- }
-
- for (unsigned i = 0; i < vtn_callee->type->length; i++) {
- struct vtn_type *arg_type = vtn_callee->type->params[i];
- unsigned arg_id = w[4 + i];
-
- if (arg_type->base_type == vtn_base_type_sampled_image) {
- struct vtn_sampled_image *sampled_image =
- vtn_value(b, arg_id, vtn_value_type_sampled_image)->sampled_image;
-
- call->params[param_idx++] =
- nir_src_for_ssa(&sampled_image->image->deref->dest.ssa);
- call->params[param_idx++] =
- nir_src_for_ssa(&sampled_image->sampler->deref->dest.ssa);
- } else if (arg_type->base_type == vtn_base_type_pointer ||
- arg_type->base_type == vtn_base_type_image ||
- arg_type->base_type == vtn_base_type_sampler) {
- struct vtn_pointer *pointer =
- vtn_value(b, arg_id, vtn_value_type_pointer)->pointer;
- call->params[param_idx++] =
- nir_src_for_ssa(vtn_pointer_to_ssa(b, pointer));
- } else {
- /* This is a regular SSA value and we need a temporary */
- nir_variable *tmp =
- nir_local_variable_create(b->nb.impl, arg_type->type, "arg_tmp");
- nir_deref_instr *tmp_deref = nir_build_deref_var(&b->nb, tmp);
- vtn_local_store(b, vtn_ssa_value(b, arg_id), tmp_deref);
- call->params[param_idx++] = nir_src_for_ssa(&tmp_deref->dest.ssa);
- }
- }
- assert(param_idx == call->num_params);
-
- nir_builder_instr_insert(&b->nb, &call->instr);
-
- if (ret_type->base_type == vtn_base_type_void) {
- vtn_push_value(b, w[2], vtn_value_type_undef);
- } else {
- vtn_push_ssa(b, w[2], res_type, vtn_local_load(b, ret_deref));
- }
-}
-
struct vtn_ssa_value *
vtn_create_ssa_value(struct vtn_builder *b, const struct glsl_type *type)
{
case nir_texop_txl:
case nir_texop_txd:
case nir_texop_tg4:
+ case nir_texop_lod:
/* These operations require a sampler */
p->src = nir_src_for_ssa(&sampler->dest.ssa);
p->src_type = nir_tex_src_sampler_deref;
case nir_texop_txf:
case nir_texop_txf_ms:
case nir_texop_txs:
- case nir_texop_lod:
case nir_texop_query_levels:
case nir_texop_texture_samples:
case nir_texop_samples_identical:
return nir_swizzle(&b->nb, coord->def, swizzle, 4, false);
}
+static nir_ssa_def *
+expand_to_vec4(nir_builder *b, nir_ssa_def *value)
+{
+ if (value->num_components == 4)
+ return value;
+
+ unsigned swiz[4];
+ for (unsigned i = 0; i < 4; i++)
+ swiz[i] = i < value->num_components ? i : 0;
+ return nir_swizzle(b, value, swiz, 4, false);
+}
+
static void
vtn_handle_image(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
/* The image coordinate is always 4 components but we may not have that
* many. Swizzle to compensate.
*/
- unsigned swiz[4];
- for (unsigned i = 0; i < 4; i++)
- swiz[i] = i < image.coord->num_components ? i : 0;
- intrin->src[1] = nir_src_for_ssa(nir_swizzle(&b->nb, image.coord,
- swiz, 4, false));
+ intrin->src[1] = nir_src_for_ssa(expand_to_vec4(&b->nb, image.coord));
intrin->src[2] = nir_src_for_ssa(image.sample);
}
case SpvOpImageRead:
break;
case SpvOpAtomicStore:
- intrin->src[3] = nir_src_for_ssa(vtn_ssa_value(b, w[4])->def);
- break;
- case SpvOpImageWrite:
- intrin->src[3] = nir_src_for_ssa(vtn_ssa_value(b, w[3])->def);
+ case SpvOpImageWrite: {
+ const uint32_t value_id = opcode == SpvOpAtomicStore ? w[4] : w[3];
+ nir_ssa_def *value = vtn_ssa_value(b, value_id)->def;
+ /* nir_intrinsic_image_deref_store always takes a vec4 value */
+ assert(op == nir_intrinsic_image_deref_store);
+ intrin->num_components = 4;
+ intrin->src[3] = nir_src_for_ssa(expand_to_vec4(&b->nb, value));
break;
+ }
case SpvOpAtomicCompareExchange:
case SpvOpAtomicIIncrement:
vtn_fail("Invalid image opcode");
}
- if (opcode != SpvOpImageWrite) {
+ if (opcode != SpvOpImageWrite && opcode != SpvOpAtomicStore) {
struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type;
- unsigned dest_components = nir_intrinsic_dest_components(intrin);
- if (intrin->intrinsic == nir_intrinsic_image_deref_size) {
- dest_components = intrin->num_components =
- glsl_get_vector_elements(type->type);
- }
+ unsigned dest_components = glsl_get_vector_elements(type->type);
+ intrin->num_components = nir_intrinsic_infos[op].dest_components;
+ if (intrin->num_components == 0)
+ intrin->num_components = dest_components;
nir_ssa_dest_init(&intrin->instr, &intrin->dest,
- dest_components, 32, NULL);
+ intrin->num_components, 32, NULL);
nir_builder_instr_insert(&b->nb, &intrin->instr);
+ nir_ssa_def *result = &intrin->dest.ssa;
+ if (intrin->num_components != dest_components)
+ result = nir_channels(&b->nb, result, (1 << dest_components) - 1);
+
val->ssa = vtn_create_ssa_value(b, type->type);
- val->ssa->def = &intrin->dest.ssa;
+ val->ssa->def = result;
} else {
nir_builder_instr_insert(&b->nb, &intrin->instr);
}
nir_ssa_def *
vtn_vector_extract(struct vtn_builder *b, nir_ssa_def *src, unsigned index)
{
- unsigned swiz[4] = { index };
- return nir_swizzle(&b->nb, src, swiz, 1, false);
+ return nir_channel(&b->nb, src, index);
}
nir_ssa_def *
return &vec->dest.dest.ssa;
}
+static nir_ssa_def *
+nir_ieq_imm(nir_builder *b, nir_ssa_def *x, uint64_t i)
+{
+ return nir_ieq(b, x, nir_imm_intN_t(b, i, x->bit_size));
+}
+
nir_ssa_def *
vtn_vector_extract_dynamic(struct vtn_builder *b, nir_ssa_def *src,
nir_ssa_def *index)
{
nir_ssa_def *dest = vtn_vector_extract(b, src, 0);
for (unsigned i = 1; i < src->num_components; i++)
- dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)),
+ dest = nir_bcsel(&b->nb, nir_ieq_imm(&b->nb, index, i),
vtn_vector_extract(b, src, i), dest);
return dest;
{
nir_ssa_def *dest = vtn_vector_insert(b, src, insert, 0);
for (unsigned i = 1; i < src->num_components; i++)
- dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)),
+ dest = nir_bcsel(&b->nb, nir_ieq_imm(&b->nb, index, i),
vtn_vector_insert(b, src, insert, i), dest);
return dest;
unsigned elems = count - 3;
assume(elems >= 1);
if (glsl_type_is_vector_or_scalar(type)) {
- nir_ssa_def *srcs[4];
+ nir_ssa_def *srcs[NIR_MAX_VEC_COMPONENTS];
for (unsigned i = 0; i < elems; i++)
srcs[i] = vtn_ssa_value(b, w[3 + i])->def;
val->ssa->def =
switch (opcode) {
case SpvOpEmitStreamVertex:
- case SpvOpEndStreamPrimitive:
- nir_intrinsic_set_stream_id(intrin, w[1]);
+ case SpvOpEndStreamPrimitive: {
+ unsigned stream = vtn_constant_value(b, w[1])->values[0].u32[0];
+ nir_intrinsic_set_stream_id(intrin, stream);
break;
+ }
+
default:
break;
}
case SpvCapabilityStorageImageExtendedFormats:
break;
- case SpvCapabilityGeometryStreams:
case SpvCapabilityLinkage:
case SpvCapabilityVector16:
case SpvCapabilityFloat16Buffer:
case SpvCapabilityInt8:
case SpvCapabilitySparseResidency:
case SpvCapabilityMinLod:
- case SpvCapabilityTransformFeedback:
vtn_warn("Unsupported SPIR-V capability: %s",
spirv_capability_to_string(cap));
break;
spv_check_supported(int16, cap);
break;
+ case SpvCapabilityTransformFeedback:
+ spv_check_supported(transform_feedback, cap);
+ break;
+
+ case SpvCapabilityGeometryStreams:
+ spv_check_supported(geometry_streams, cap);
+ break;
+
case SpvCapabilityAddresses:
case SpvCapabilityKernel:
case SpvCapabilityImageBasic:
spv_check_supported(stencil_export, cap);
break;
+ case SpvCapabilitySampleMaskPostDepthCoverage:
+ spv_check_supported(post_depth_coverage, cap);
+ break;
+
default:
vtn_fail("Unhandled capability");
}
case SpvOpMemberDecorate:
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
+ case SpvOpDecorateStringGOOGLE:
+ case SpvOpMemberDecorateStringGOOGLE:
vtn_handle_decoration(b, opcode, w, count);
break;
b->shader->info.fs.early_fragment_tests = true;
break;
+ case SpvExecutionModePostDepthCoverage:
+ vtn_assert(b->shader->info.stage == MESA_SHADER_FRAGMENT);
+ b->shader->info.fs.post_depth_coverage = true;
+ break;
+
case SpvExecutionModeInvocations:
vtn_assert(b->shader->info.stage == MESA_SHADER_GEOMETRY);
b->shader->info.gs.invocations = MAX2(1, mode->literals[0]);
vtn_assert(b->shader->info.stage == MESA_SHADER_GEOMETRY);
b->shader->info.gs.vertices_in =
vertices_in_from_spv_execution_mode(b, mode->exec_mode);
+ b->shader->info.gs.input_primitive =
+ gl_primitive_from_spv_execution_mode(b, mode->exec_mode);
}
break;
break;
case SpvExecutionModeXfb:
- vtn_fail("Unhandled execution mode");
+ b->shader->info.has_transform_feedback_varyings = true;
break;
case SpvExecutionModeVecTypeHint:
case SpvOpMemberDecorate:
case SpvOpGroupDecorate:
case SpvOpGroupMemberDecorate:
+ case SpvOpDecorateStringGOOGLE:
+ case SpvOpMemberDecorateStringGOOGLE:
vtn_fail("Invalid opcode types and variables section");
break;