summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/spirv/nir_spirv.h2
-rw-r--r--src/mesa/main/glspirv.c94
2 files changed, 95 insertions, 1 deletions
diff --git a/src/compiler/spirv/nir_spirv.h b/src/compiler/spirv/nir_spirv.h
index 7f16866b49..34658fbfff 100644
--- a/src/compiler/spirv/nir_spirv.h
+++ b/src/compiler/spirv/nir_spirv.h
@@ -28,7 +28,7 @@
#ifndef _NIR_SPIRV_H_
#define _NIR_SPIRV_H_
-#include "nir/nir.h"
+#include "compiler/nir/nir.h"
#ifdef __cplusplus
extern "C" {
diff --git a/src/mesa/main/glspirv.c b/src/mesa/main/glspirv.c
index e75286aeb7..a789a20335 100644
--- a/src/mesa/main/glspirv.c
+++ b/src/mesa/main/glspirv.c
@@ -24,6 +24,10 @@
#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"
@@ -96,4 +100,94 @@ _mesa_SpecializeShaderARB(GLuint shader,
const GLuint *pConstantIndex,
const GLuint *pConstantValue)
{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_shader *sh;
+ nir_shader *nir;
+ nir_function *entry_point;
+
+ 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->SpirVBinary) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glSpecializeShaderARB(not SPIR-V)");
+ return;
+ }
+
+ if (sh->CompileStatus) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glSpecializeShaderARB(already specialized)");
+ return;
+ }
+
+ /* 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.
+ */
+ {
+ struct nir_spirv_specialization *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];
+ }
+
+ entry_point = spirv_to_nir((uint32_t *)&sh->SpirVModule->Binary[0],
+ sh->SpirVModule->Length / 4,
+ spec_entries, numSpecializationConstants,
+ sh->Stage, pEntryPoint,
+ ctx->Const.SpirVExtensions,
+ ctx->Const.SpirVNIROptions);
+ nir = entry_point->shader;
+ assert(nir->stage == sh->Stage);
+
+ nir->info.stage = nir->stage;
+ nir->info.name = ralloc_asprintf(nir, "SPIRV:%s:%d",
+ _mesa_shader_stage_to_abbrev(nir->stage),
+ sh->Name);
+
+ nir_validate_shader(nir);
+
+ free(spec_entries);
+ }
+
+ /* TODO: Perform some common optimizations already here, to avoid re-doing
+ * them each time the shader is linked.
+ */
+
+ /* TODO: Clone to cleanup memory (can only be done after inlining). */
+ sh->nir = nir;
+ sh->nir_entry = entry_point;
+ ralloc_steal(sh, sh->nir);
+
+ sh->CompileStatus = compile_success;
+
+ /* Disable the shader disk cache for SPIR-V shaders for now. */
+ memset(sh->sha1, 0, sizeof(sh->sha1));
+
+ _mesa_spirv_module_reference(&sh->SpirVModule, NULL);
}