#include "util/u_math.h"
#include <stdio.h>
+#if UTIL_ARCH_BIG_ENDIAN
+#include <byteswap.h>
+#endif
void
vtn_log(struct vtn_builder *b, enum nir_spirv_debug_level level,
static void
vtn_push_image(struct vtn_builder *b, uint32_t value_id,
- nir_deref_instr *deref)
+ nir_deref_instr *deref, bool propagate_non_uniform)
{
struct vtn_type *type = vtn_get_value_type(b, value_id);
vtn_assert(type->base_type == vtn_base_type_image);
- vtn_push_nir_ssa(b, value_id, &deref->dest.ssa);
+ struct vtn_value *value = vtn_push_nir_ssa(b, value_id, &deref->dest.ssa);
+ value->propagated_non_uniform = propagate_non_uniform;
}
static nir_deref_instr *
static void
vtn_push_sampled_image(struct vtn_builder *b, uint32_t value_id,
- struct vtn_sampled_image si)
+ struct vtn_sampled_image si, bool propagate_non_uniform)
{
struct vtn_type *type = vtn_get_value_type(b, value_id);
vtn_assert(type->base_type == vtn_base_type_sampled_image);
- vtn_push_nir_ssa(b, value_id, vtn_sampled_image_to_nir_ssa(b, si));
+ struct vtn_value *value = vtn_push_nir_ssa(b, value_id,
+ vtn_sampled_image_to_nir_ssa(b, si));
+ value->propagated_non_uniform = propagate_non_uniform;
}
static struct vtn_sampled_image
return si;
}
-static char *
+static const char *
vtn_string_literal(struct vtn_builder *b, const uint32_t *words,
unsigned word_count, unsigned *words_used)
{
- char *dup = ralloc_strndup(b, (char *)words, word_count * sizeof(*words));
- if (words_used) {
- /* Ammount of space taken by the string (including the null) */
- unsigned len = strlen(dup) + 1;
- *words_used = DIV_ROUND_UP(len, sizeof(*words));
+ /* From the SPIR-V spec:
+ *
+ * "A string is interpreted as a nul-terminated stream of characters.
+ * The character set is Unicode in the UTF-8 encoding scheme. The UTF-8
+ * octets (8-bit bytes) are packed four per word, following the
+ * little-endian convention (i.e., the first octet is in the
+ * lowest-order 8 bits of the word). The final word contains the
+ * string’s nul-termination character (0), and all contents past the
+ * end of the string in the final word are padded with 0."
+ *
+ * On big-endian, we need to byte-swap.
+ */
+#if UTIL_ARCH_BIG_ENDIAN
+ {
+ uint32_t *copy = ralloc_array(b, uint32_t, word_count);
+ for (unsigned i = 0; i < word_count; i++)
+ copy[i] = bswap_32(words[i]);
+ words = copy;
}
- return dup;
+#endif
+
+ const char *str = (char *)words;
+ const char *end = memchr(str, 0, word_count * 4);
+ vtn_fail_if(end == NULL, "String is not null-terminated");
+
+ if (words_used)
+ *words_used = DIV_ROUND_UP(end - str + 1, sizeof(*words));
+
+ return str;
}
const uint32_t *
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);
+ const char *ext = vtn_string_literal(b, &w[2], count - 2, NULL);
if (strcmp(ext, "GLSL.std.450") == 0) {
val->ext_handler = vtn_handle_glsl450_instruction;
} else if ((strcmp(ext, "SPV_AMD_gcn_shader") == 0)
case SpvDecorationLinkageAttributes:
case SpvDecorationNoContraction:
case SpvDecorationInputAttachmentIndex:
+ case SpvDecorationCPacked:
vtn_warn("Decoration not allowed on struct members: %s",
spirv_decoration_to_string(dec->decoration));
break;
/* This is handled later by var_decoration_cb in vtn_variables.c */
break;
- case SpvDecorationCPacked:
- if (b->shader->info.stage != MESA_SHADER_KERNEL)
- vtn_warn("Decoration only allowed for CL-style kernels: %s",
- spirv_decoration_to_string(dec->decoration));
- else
- ctx->type->packed = true;
- break;
-
case SpvDecorationSaturatedConversion:
case SpvDecorationFuncParamAttr:
case SpvDecorationFPRoundingMode:
ctx->fields[member].type = ctx->type->members[member]->type;
}
+static void
+struct_packed_decoration_cb(struct vtn_builder *b,
+ struct vtn_value *val, int member,
+ const struct vtn_decoration *dec, void *void_ctx)
+{
+ vtn_assert(val->type->base_type == vtn_base_type_struct);
+ if (dec->decoration == SpvDecorationCPacked) {
+ if (b->shader->info.stage != MESA_SHADER_KERNEL) {
+ vtn_warn("Decoration only allowed for CL-style kernels: %s",
+ spirv_decoration_to_string(dec->decoration));
+ }
+ val->type->packed = true;
+ }
+}
+
static void
struct_block_decoration_cb(struct vtn_builder *b,
struct vtn_value *val, int member,
break;
case SpvDecorationCPacked:
- if (b->shader->info.stage != MESA_SHADER_KERNEL)
- vtn_warn("Decoration only allowed for CL-style kernels: %s",
- spirv_decoration_to_string(dec->decoration));
- else
- type->packed = true;
+ /* Handled when parsing a struct type, nothing to do here. */
break;
case SpvDecorationSaturatedConversion:
val->type->base_type = vtn_base_type_array;
val->type->array_element = array_element;
- if (b->shader->info.stage == MESA_SHADER_KERNEL)
- val->type->stride = glsl_get_cl_size(array_element->type);
vtn_foreach_decoration(b, val, array_stride_decoration_cb, NULL);
val->type->type = glsl_array_type(array_element->type, val->type->length,
};
}
- if (b->shader->info.stage == MESA_SHADER_KERNEL) {
- unsigned offset = 0;
- for (unsigned i = 0; i < num_fields; i++) {
- offset = align(offset, glsl_get_cl_alignment(fields[i].type));
- fields[i].offset = offset;
- offset += glsl_get_cl_size(fields[i].type);
- }
- }
+ vtn_foreach_decoration(b, val, struct_packed_decoration_cb, NULL);
struct member_decoration_ctx ctx = {
.num_fields = num_fields,
name ? name : "block");
} else {
val->type->type = glsl_struct_type(fields, num_fields,
- name ? name : "struct", false);
+ name ? name : "struct",
+ val->type->packed);
}
break;
}
/* Nothing to do. */
break;
}
-
- if (b->physical_ptrs) {
- switch (storage_class) {
- case SpvStorageClassFunction:
- case SpvStorageClassWorkgroup:
- case SpvStorageClassCrossWorkgroup:
- case SpvStorageClassUniformConstant:
- val->type->stride = align(glsl_get_cl_size(val->type->deref->type),
- glsl_get_cl_alignment(val->type->deref->type));
- break;
- default:
- break;
- }
- }
}
break;
}
.image = vtn_get_image(b, w[3]),
.sampler = vtn_get_sampler(b, w[4]),
};
- vtn_push_sampled_image(b, w[2], si);
+
+ enum gl_access_qualifier access = 0;
+ vtn_foreach_decoration(b, vtn_untyped_value(b, w[3]),
+ non_uniform_decoration_cb, &access);
+ vtn_foreach_decoration(b, vtn_untyped_value(b, w[4]),
+ non_uniform_decoration_cb, &access);
+
+ vtn_push_sampled_image(b, w[2], si, access & ACCESS_NON_UNIFORM);
return;
} else if (opcode == SpvOpImage) {
struct vtn_sampled_image si = vtn_get_sampled_image(b, w[3]);
- vtn_push_image(b, w[2], si.image);
+
+ enum gl_access_qualifier access = 0;
+ vtn_foreach_decoration(b, vtn_untyped_value(b, w[3]),
+ non_uniform_decoration_cb, &access);
+
+ vtn_push_image(b, w[2], si.image, access & ACCESS_NON_UNIFORM);
return;
}
case SpvOpFragmentMaskFetchAMD:
texop = nir_texop_fragment_mask_fetch;
+ dest_type = nir_type_uint;
break;
default:
enum gl_access_qualifier access = 0;
vtn_foreach_decoration(b, sampled_val, non_uniform_decoration_cb, &access);
+ if (sampled_val->propagated_non_uniform)
+ access |= ACCESS_NON_UNIFORM;
+
if (image && (access & ACCESS_NON_UNIFORM))
instr->texture_non_uniform = true;
fill_common_atomic_sources(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, nir_src *src)
{
+ const struct glsl_type *type = vtn_get_type(b, w[1])->type;
+ unsigned bit_size = glsl_get_bit_size(type);
+
switch (opcode) {
case SpvOpAtomicIIncrement:
- src[0] = nir_src_for_ssa(nir_imm_int(&b->nb, 1));
+ src[0] = nir_src_for_ssa(nir_imm_intN_t(&b->nb, 1, bit_size));
break;
case SpvOpAtomicIDecrement:
- src[0] = nir_src_for_ssa(nir_imm_int(&b->nb, -1));
+ src[0] = nir_src_for_ssa(nir_imm_intN_t(&b->nb, -1, bit_size));
break;
case SpvOpAtomicISub:
image.lod = nir_imm_int(&b->nb, 0);
}
- /* TODO: Volatile. */
+ if (operands & SpvImageOperandsVolatileTexelMask)
+ access |= ACCESS_VOLATILE;
break;
}
image.lod = nir_imm_int(&b->nb, 0);
}
- /* TODO: Volatile. */
+ if (operands & SpvImageOperandsVolatileTexelMask)
+ access |= ACCESS_VOLATILE;
break;
}
assert(nir_address_format_num_components(b->options->global_addr_format) == 1);
assert(nir_address_format_bit_size(b->options->shared_addr_format) == 32);
assert(nir_address_format_num_components(b->options->shared_addr_format) == 1);
- if (!b->options->constant_as_global) {
- assert(nir_address_format_bit_size(b->options->ubo_addr_format) == 32);
- assert(nir_address_format_num_components(b->options->ubo_addr_format) == 1);
- }
+ assert(nir_address_format_bit_size(b->options->constant_addr_format) == 32);
+ assert(nir_address_format_num_components(b->options->constant_addr_format) == 1);
break;
case SpvAddressingModelPhysical64:
vtn_fail_if(b->shader->info.stage != MESA_SHADER_KERNEL,
assert(nir_address_format_num_components(b->options->global_addr_format) == 1);
assert(nir_address_format_bit_size(b->options->shared_addr_format) == 64);
assert(nir_address_format_num_components(b->options->shared_addr_format) == 1);
- if (!b->options->constant_as_global) {
- assert(nir_address_format_bit_size(b->options->ubo_addr_format) == 64);
- assert(nir_address_format_num_components(b->options->ubo_addr_format) == 1);
- }
+ assert(nir_address_format_bit_size(b->options->constant_addr_format) == 64);
+ assert(nir_address_format_num_components(b->options->constant_addr_format) == 1);
break;
case SpvAddressingModelLogical:
vtn_fail_if(b->shader->info.stage == MESA_SHADER_KERNEL,
const char *func_name =
ralloc_asprintf(b->shader, "__wrapped_%s", entry_point->name);
- /* we shouldn't have any inputs yet */
- vtn_assert(!entry_point->shader->num_inputs);
vtn_assert(b->shader->info.stage == MESA_SHADER_KERNEL);
nir_function *main_entry_point = nir_function_create(b->shader, func_name);
in_var->type = param_type->type;
nir_shader_add_variable(b->nb.shader, in_var);
- b->nb.shader->num_inputs++;
/* we have to copy the entire variable into function memory */
if (is_by_val) {