diff options
author | Nicolai Hähnle <nicolai.haehnle@amd.com> | 2017-06-10 21:36:24 +0200 |
---|---|---|
committer | Nicolai Hähnle <nicolai.haehnle@amd.com> | 2017-07-13 13:27:39 +0200 |
commit | bd0b196a8986aca78fb79aeab8e8944183a3cc22 (patch) | |
tree | ef177aa0eb84723ce6db80484384f7d0fac79792 | |
parent | 6958273267c5905af90ccd52a454079aab11edbe (diff) |
mesa: implement glSpecializeShaderARB (WIP)
-rw-r--r-- | src/compiler/spirv/nir_spirv.h | 2 | ||||
-rw-r--r-- | src/mesa/main/glspirv.c | 94 |
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); } |