summaryrefslogtreecommitdiffstats
path: root/src/compiler/spirv
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2018-12-15 08:31:51 -0600
committerJason Ekstrand <[email protected]>2019-01-08 00:38:30 +0000
commit5c3cb9c3ce3f9fb05c22536c30a68a7b09300642 (patch)
treebde031799ff13eeeb7020c0eea6f5f13db1b55cb /src/compiler/spirv
parente90b738f201e7281e2a4cf43eddd2d15eb942cce (diff)
spirv: Add error checking for Block and BufferBlock decorations
Variable pointers being well-defined across the block boundary requires a couple of very specific SPIR-V validation rules. Normally, we'd trust the validator to catch these but since CTS tests have been found in the wild which violate them, we'll carry our own checks. Reviewed-by: Alejandro PiƱeiro <[email protected]> Reviewed-by: Caio Marcelo de Oliveira Filho <[email protected]>
Diffstat (limited to 'src/compiler/spirv')
-rw-r--r--src/compiler/spirv/spirv_to_nir.c35
-rw-r--r--src/compiler/spirv/vtn_private.h1
-rw-r--r--src/compiler/spirv/vtn_variables.c17
3 files changed, 53 insertions, 0 deletions
diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index cf07eedd972..2968c735f32 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -563,6 +563,29 @@ struct member_decoration_ctx {
struct vtn_type *type;
};
+/**
+ * Returns true if the given type contains a struct decorated Block or
+ * BufferBlock
+ */
+static bool
+vtn_type_contains_block(struct vtn_builder *b, struct vtn_type *type)
+{
+ switch (type->base_type) {
+ case vtn_base_type_array:
+ return vtn_type_contains_block(b, type->array_element);
+ case vtn_base_type_struct:
+ if (type->block || type->buffer_block)
+ return true;
+ for (unsigned i = 0; i < type->length; i++) {
+ if (vtn_type_contains_block(b, type->members[i]))
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
/** Returns true if two types are "compatible", i.e. you can do an OpLoad,
* OpStore, or OpCopyMemory between them without breaking anything.
* Technically, the SPIR-V rules require the exact same type ID but this lets
@@ -1375,6 +1398,17 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
}
vtn_foreach_decoration(b, val, type_decoration_cb, NULL);
+
+ if (val->type->base_type == vtn_base_type_struct &&
+ (val->type->block || val->type->buffer_block)) {
+ for (unsigned i = 0; i < val->type->length; i++) {
+ vtn_fail_if(vtn_type_contains_block(b, val->type->members[i]),
+ "Block and BufferBlock decorations cannot decorate a "
+ "structure type that is nested at any level inside "
+ "another structure type decorated with Block or "
+ "BufferBlock.");
+ }
+ }
}
static nir_constant *
@@ -3598,6 +3632,7 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
case SpvCapabilityVariablePointersStorageBuffer:
case SpvCapabilityVariablePointers:
spv_check_supported(variable_pointers, cap);
+ b->variable_pointers = true;
break;
case SpvCapabilityStorageUniformBufferBlock16:
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index 35739255510..342d4b74d71 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -586,6 +586,7 @@ struct vtn_builder {
struct vtn_value *entry_point;
bool origin_upper_left;
bool pixel_center_integer;
+ bool variable_pointers;
struct vtn_function *func;
struct exec_list functions;
diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c
index c177952d7e1..7e80263abf3 100644
--- a/src/compiler/spirv/vtn_variables.c
+++ b/src/compiler/spirv/vtn_variables.c
@@ -1686,9 +1686,26 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val,
switch (mode) {
case vtn_variable_mode_ubo:
+ /* There's no other way to get vtn_variable_mode_ubo */
+ vtn_assert(without_array->block);
b->shader->info.num_ubos++;
break;
case vtn_variable_mode_ssbo:
+ if (storage_class == SpvStorageClassStorageBuffer &&
+ !without_array->block) {
+ if (b->variable_pointers) {
+ vtn_fail("Variables in the StorageBuffer storage class must "
+ "have a struct type with the Block decoration");
+ } else {
+ /* If variable pointers are not present, it's still malformed
+ * SPIR-V but we can parse it and do the right thing anyway.
+ * Since some of the 8-bit storage tests have bugs in this are,
+ * just make it a warning for now.
+ */
+ vtn_warn("Variables in the StorageBuffer storage class must "
+ "have a struct type with the Block decoration");
+ }
+ }
b->shader->info.num_ssbos++;
break;
case vtn_variable_mode_uniform: