[Mesa-dev] [PATCH 15/24] nir/spirv: add gl_spirv_validation method
Eduardo Lima Mitev
elima at igalia.com
Wed Nov 15 13:22:18 UTC 2017
From: Alejandro PiƱeiro <apinheiro at igalia.com>
ARB_gl_spirv adds the ability to use SPIR-V binaries, and a new
method, glSpecializeShader. From OpenGL 4.6 spec, section 7.2.1
"Shader Specialization", error table:
INVALID_VALUE is generated if <pEntryPoint> does not name a valid
entry point for <shader>.
INVALID_VALUE is generated if any element of <pConstantIndex>
refers to a specialization constant that does not exist in the
shader module contained in <shader>.""
But we are not really interested on creating the nir shader at that
point, and adding nir structures on the gl_program, so at that point
we are just interested on the error checking.
So we add a new method focused on just checking those errors. It still
needs to parse the binary, but skips what it is not needed, and
doesn't create the nir shader.
---
src/compiler/spirv/nir_spirv.h | 5 ++
src/compiler/spirv/spirv_to_nir.c | 156 +++++++++++++++++++++++++++++++++++---
2 files changed, 151 insertions(+), 10 deletions(-)
diff --git a/src/compiler/spirv/nir_spirv.h b/src/compiler/spirv/nir_spirv.h
index d975254047a..f3ca26e590c 100644
--- a/src/compiler/spirv/nir_spirv.h
+++ b/src/compiler/spirv/nir_spirv.h
@@ -40,6 +40,7 @@ struct nir_spirv_specialization {
uint32_t data32;
uint64_t data64;
};
+ bool defined_on_module;
};
struct nir_spirv_supported_capabilities {
@@ -54,6 +55,10 @@ struct nir_spirv_supported_capabilities {
bool variable_pointers;
};
+bool gl_spirv_validation(const uint32_t *words, size_t word_count,
+ struct nir_spirv_specialization *spec, unsigned num_spec,
+ gl_shader_stage stage, const char *entry_point_name);
+
nir_function *spirv_to_nir(const uint32_t *words, size_t word_count,
struct nir_spirv_specialization *specializations,
unsigned num_specializations,
diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c
index 6034228ed36..fea3ad7b09d 100644
--- a/src/compiler/spirv/spirv_to_nir.c
+++ b/src/compiler/spirv/spirv_to_nir.c
@@ -1031,6 +1031,7 @@ spec_constant_decoration_cb(struct vtn_builder *b, struct vtn_value *v,
const_value->data64 = b->specializations[i].data64;
else
const_value->data32 = b->specializations[i].data32;
+ b->specializations[i].defined_on_module = true;
return;
}
}
@@ -1065,6 +1066,11 @@ handle_workgroup_size_decoration_cb(struct vtn_builder *b,
const struct vtn_decoration *dec,
void *data)
{
+ /* This can happens if we are gl_spirv_validation. We can return safely, as
+ * we don't need the workgroup info for such validation. */
+ if (b->shader == NULL)
+ return;
+
assert(member == -1);
if (dec->decoration != SpvDecorationBuiltIn ||
dec->literals[0] != SpvBuiltInWorkgroupSize)
@@ -2848,6 +2854,49 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
return true;
}
+/*
+ * gl_spirv validation. Just need to check for the entry point.
+ */
+static bool
+vtn_validate_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count)
+{
+ switch (opcode) {
+ /* The following opcodes are not needed for gl_spirv, so we can skip
+ * them.
+ */
+ case SpvOpSource:
+ case SpvOpSourceExtension:
+ case SpvOpSourceContinued:
+ case SpvOpExtension:
+ case SpvOpCapability:
+ case SpvOpExtInstImport:
+ case SpvOpMemoryModel:
+ case SpvOpString:
+ case SpvOpName:
+ case SpvOpMemberName:
+ case SpvOpExecutionMode:
+ case SpvOpDecorationGroup:
+ case SpvOpMemberDecorate:
+ case SpvOpGroupDecorate:
+ case SpvOpGroupMemberDecorate:
+ break;
+
+ case SpvOpEntryPoint:
+ vtn_handle_preamble_instruction(b, opcode, w, count);
+ break;
+
+ case SpvOpDecorate:
+ vtn_handle_decoration(b, opcode, w, count);
+ break;
+
+ default:
+ return false; /* End of preamble */
+ }
+
+ return true;
+}
+
static void
vtn_handle_execution_mode(struct vtn_builder *b, struct vtn_value *entry_point,
const struct vtn_decoration *mode, void *data)
@@ -3056,6 +3105,22 @@ vtn_handle_variable_or_type_instruction(struct vtn_builder *b, SpvOp opcode,
}
static bool
+vtn_handle_constant_or_type_instruction(struct vtn_builder *b, SpvOp opcode,
+ const uint32_t *w, unsigned count)
+{
+ switch (opcode) {
+ case SpvOpUndef:
+ case SpvOpVariable:
+ break;
+
+ default:
+ return vtn_handle_variable_or_type_instruction(b, opcode, w, count);
+ }
+
+ return true;
+}
+
+static bool
vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
@@ -3309,15 +3374,10 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
return true;
}
-nir_function *
-spirv_to_nir(const uint32_t *words, size_t word_count,
- struct nir_spirv_specialization *spec, unsigned num_spec,
- gl_shader_stage stage, const char *entry_point_name,
- const struct nir_spirv_supported_capabilities *cap,
- const nir_shader_compiler_options *options)
+static struct vtn_builder*
+common_initialization(const uint32_t *words, size_t word_count,
+ gl_shader_stage stage, const char *entry_point_name)
{
- const uint32_t *word_end = words + word_count;
-
/* Handle the SPIR-V header (first 4 dwords) */
assert(word_count > 5);
@@ -3327,8 +3387,6 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
unsigned value_id_bound = words[3];
assert(words[4] == 0);
- words+= 5;
-
/* Initialize the stn_builder object */
struct vtn_builder *b = rzalloc(NULL, struct vtn_builder);
b->value_id_bound = value_id_bound;
@@ -3336,6 +3394,84 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
exec_list_make_empty(&b->functions);
b->entry_point_stage = stage;
b->entry_point_name = entry_point_name;
+
+ return b;
+}
+
+/*
+ * Since OpenGL 4.6 you can use SPIR-V modules directly on OpenGL. One of the
+ * new methods, glSpecializeShader include some possible errors when trying to
+ * use it. From OpenGL 4.6, Section 7.2.1, "Shader Specialization":
+ *
+ * "void SpecializeShaderARB(uint shader,
+ * const char* pEntryPoint,
+ * uint numSpecializationConstants,
+ * const uint* pConstantIndex,
+ * const uint* pConstantVaulue);
+ * <skip>
+ *
+ * INVALID_VALUE is generated if <pEntryPoint> does not name a valid
+ * entry point for <shader>.
+ *
+ * An INVALID_VALUE error is generated if any element of pConstantIndex refers
+ * to a specialization constant that does not exist in the shader module
+ * contained in shader."
+ *
+ * We could do those checks on spirv_to_nir, but we are only interested on the
+ * full translation later, during linking. This method is a simplified version
+ * of spirv_to_nir, looking for only the checks needed by SpecializeShader.
+ *
+ * This method returns NULL if no entry point was found, and fill the
+ * nir_spirv_specialization field "defined_on_module" accordingly. Caller
+ * would need to trigger the specific errors.
+ *
+ */
+bool
+gl_spirv_validation(const uint32_t *words, size_t word_count,
+ struct nir_spirv_specialization *spec, unsigned num_spec,
+ gl_shader_stage stage, const char *entry_point_name)
+{
+ const uint32_t *word_end = words + word_count;
+
+ struct vtn_builder *b = common_initialization(words, word_count,
+ stage, entry_point_name);
+ words+= 5;
+
+ /* Search entry point from preamble */
+ words = vtn_foreach_instruction(b, words, word_end,
+ vtn_validate_preamble_instruction);
+
+ if (b->entry_point == NULL) {
+ ralloc_free(b);
+ return false;
+ }
+
+ b->specializations = spec;
+ b->num_specializations = num_spec;
+
+ /* Handle type, and constant instructions (we don't need to handle
+ * variables for gl_spirv)
+ */
+ words = vtn_foreach_instruction(b, words, word_end,
+ vtn_handle_constant_or_type_instruction);
+
+ ralloc_free(b);
+
+ return true;
+}
+
+nir_function *
+spirv_to_nir(const uint32_t *words, size_t word_count,
+ struct nir_spirv_specialization *spec, unsigned num_spec,
+ gl_shader_stage stage, const char *entry_point_name,
+ const struct nir_spirv_supported_capabilities *cap,
+ const nir_shader_compiler_options *options)
+{
+ const uint32_t *word_end = words + word_count;
+
+ struct vtn_builder *b = common_initialization(words, word_count,
+ stage, entry_point_name);
+ words+= 5;
b->cap = cap;
/* Handle all the preamble instructions */
--
2.11.0
More information about the mesa-dev
mailing list