diff options
author | Nicolai Hähnle <[email protected]> | 2017-06-10 21:36:24 +0200 |
---|---|---|
committer | Alejandro Piñeiro <[email protected]> | 2018-03-30 09:14:56 +0200 |
commit | ba975140d3c99b60c63846c3c08bd158f7c95d42 (patch) | |
tree | a4a5d0e4ea588c61efc531d486967b1964313266 | |
parent | 9063bf7ad8a9175c4eddba5d06d887c507f6b5be (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]>
-rw-r--r-- | src/mesa/main/glspirv.c | 107 |
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); } |