summaryrefslogtreecommitdiffstats
path: root/src/mesa/main/glspirv.c
diff options
context:
space:
mode:
authorNicolai Hähnle <[email protected]>2017-06-10 21:36:24 +0200
committerAlejandro Piñeiro <[email protected]>2018-03-30 09:14:56 +0200
commitba975140d3c99b60c63846c3c08bd158f7c95d42 (patch)
treea4a5d0e4ea588c61efc531d486967b1964313266 /src/mesa/main/glspirv.c
parent9063bf7ad8a9175c4eddba5d06d887c507f6b5be (diff)
mesa: Implement glSpecializeShaderARB
v2: * Use gl_spirv_validation instead of spirv_to_nir. This method just validates the shader. The conversion to NIR will happen later, during linking. (Alejandro Piñeiro) * Use gl_shader_spirv_data struct to store the SPIR-V data. (Eduardo Lima) * Use the 'spirv_data' member to tell if the gl_shader is a SPIR-V shader, instead of a dedicated flag. (Timothy Arceri) Signed-off-by: Nicolai Hähnle <[email protected]> Signed-off-by: Alejandro Piñeiro <[email protected]> Signed-off-by: Eduardo Lima Mitev <[email protected]> Reviewed-by: Timothy Arceri <[email protected]>
Diffstat (limited to 'src/mesa/main/glspirv.c')
-rw-r--r--src/mesa/main/glspirv.c107
1 files changed, 105 insertions, 2 deletions
diff --git a/src/mesa/main/glspirv.c b/src/mesa/main/glspirv.c
index 03f761219be..b1185ca5fdf 100644
--- a/src/mesa/main/glspirv.c
+++ b/src/mesa/main/glspirv.c
@@ -23,6 +23,11 @@
#include "glspirv.h"
#include "errors.h"
+#include "shaderobj.h"
+
+#include "compiler/nir/nir.h"
+#include "compiler/spirv/nir_spirv.h"
+
#include "util/u_atomic.h"
void
@@ -106,7 +111,105 @@ _mesa_SpecializeShaderARB(GLuint shader,
const GLuint *pConstantValue)
{
GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader *sh;
+ bool has_entry_point;
+ struct nir_spirv_specialization *spec_entries = NULL;
+
+ if (!ctx->Extensions.ARB_gl_spirv) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glSpecializeShaderARB");
+ return;
+ }
+
+ sh = _mesa_lookup_shader_err(ctx, shader, "glSpecializeShaderARB");
+ if (!sh)
+ return;
+
+ if (!sh->spirv_data) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glSpecializeShaderARB(not SPIR-V)");
+ return;
+ }
+
+ if (sh->CompileStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glSpecializeShaderARB(already specialized)");
+ return;
+ }
+
+ struct gl_shader_spirv_data *spirv_data = sh->spirv_data;
+
+ /* From the GL_ARB_gl_spirv spec:
+ *
+ * "The OpenGL API expects the SPIR-V module to have already been
+ * validated, and can return an error if it discovers anything invalid
+ * in the module. An invalid SPIR-V module is allowed to result in
+ * undefined behavior."
+ *
+ * However, the following errors still need to be detected (from the same
+ * spec):
+ *
+ * "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>."
+ *
+ * We cannot flag those errors a-priori because detecting them requires
+ * parsing the module. However, flagging them during specialization is okay,
+ * since it makes no difference in terms of application-visible state.
+ */
+ spec_entries = calloc(sizeof(*spec_entries), numSpecializationConstants);
+
+ for (unsigned i = 0; i < numSpecializationConstants; ++i) {
+ spec_entries[i].id = pConstantIndex[i];
+ spec_entries[i].data32 = pConstantValue[i];
+ spec_entries[i].defined_on_module = false;
+ }
+
+ has_entry_point =
+ gl_spirv_validation((uint32_t *)&spirv_data->SpirVModule->Binary[0],
+ spirv_data->SpirVModule->Length / 4,
+ spec_entries, numSpecializationConstants,
+ sh->Stage, pEntryPoint);
+
+ /* See previous spec comment */
+ if (!has_entry_point) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glSpecializeShaderARB(\"%s\" is not a valid entry point"
+ " for shader)", pEntryPoint);
+ goto end;
+ }
+
+ for (unsigned i = 0; i < numSpecializationConstants; ++i) {
+ if (spec_entries[i].defined_on_module == false) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glSpecializeShaderARB(constant \"%i\" does not exist "
+ "in shader)", spec_entries[i].id);
+ goto end;
+ }
+ }
+
+ spirv_data->SpirVEntryPoint = ralloc_strdup(spirv_data, pEntryPoint);
+
+ /* Note that we didn't make a real compilation of the module (spirv_to_nir),
+ * but just checked some error conditions. Real "compilation" will be done
+ * later, upon linking.
+ */
+ sh->CompileStatus = COMPILE_SUCCESS;
+
+ spirv_data->NumSpecializationConstants = numSpecializationConstants;
+ spirv_data->SpecializationConstantsIndex =
+ rzalloc_array_size(spirv_data, sizeof(GLuint),
+ numSpecializationConstants);
+ spirv_data->SpecializationConstantsValue =
+ rzalloc_array_size(spirv_data, sizeof(GLuint),
+ numSpecializationConstants);
+ for (unsigned i = 0; i < numSpecializationConstants; ++i) {
+ spirv_data->SpecializationConstantsIndex[i] = pConstantIndex[i];
+ spirv_data->SpecializationConstantsValue[i] = pConstantValue[i];
+ }
- /* Just return GL_INVALID_OPERATION error while this is boilerplate */
- _mesa_error(ctx, GL_INVALID_OPERATION, "SpecializeShaderARB");
+ end:
+ free(spec_entries);
}