1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright 2017 Advanced Micro Devices, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * on the rights to use, copy, modify, merge, publish, distribute, sub 8bf215546Sopenharmony_ci * license, and/or sell copies of the Software, and to permit persons to whom 9bf215546Sopenharmony_ci * the Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, 19bf215546Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20bf215546Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 21bf215546Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "glspirv.h" 25bf215546Sopenharmony_ci#include "errors.h" 26bf215546Sopenharmony_ci#include "shaderobj.h" 27bf215546Sopenharmony_ci#include "mtypes.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "compiler/nir/nir.h" 30bf215546Sopenharmony_ci#include "compiler/spirv/nir_spirv.h" 31bf215546Sopenharmony_ci 32bf215546Sopenharmony_ci#include "program/program.h" 33bf215546Sopenharmony_ci 34bf215546Sopenharmony_ci#include "util/u_atomic.h" 35bf215546Sopenharmony_ci#include "api_exec_decl.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_civoid 38bf215546Sopenharmony_ci_mesa_spirv_module_reference(struct gl_spirv_module **dest, 39bf215546Sopenharmony_ci struct gl_spirv_module *src) 40bf215546Sopenharmony_ci{ 41bf215546Sopenharmony_ci struct gl_spirv_module *old = *dest; 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci if (old && p_atomic_dec_zero(&old->RefCount)) 44bf215546Sopenharmony_ci free(old); 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci *dest = src; 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci if (src) 49bf215546Sopenharmony_ci p_atomic_inc(&src->RefCount); 50bf215546Sopenharmony_ci} 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_civoid 53bf215546Sopenharmony_ci_mesa_shader_spirv_data_reference(struct gl_shader_spirv_data **dest, 54bf215546Sopenharmony_ci struct gl_shader_spirv_data *src) 55bf215546Sopenharmony_ci{ 56bf215546Sopenharmony_ci struct gl_shader_spirv_data *old = *dest; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci if (old && p_atomic_dec_zero(&old->RefCount)) { 59bf215546Sopenharmony_ci _mesa_spirv_module_reference(&(*dest)->SpirVModule, NULL); 60bf215546Sopenharmony_ci ralloc_free(old); 61bf215546Sopenharmony_ci } 62bf215546Sopenharmony_ci 63bf215546Sopenharmony_ci *dest = src; 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_ci if (src) 66bf215546Sopenharmony_ci p_atomic_inc(&src->RefCount); 67bf215546Sopenharmony_ci} 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_civoid 70bf215546Sopenharmony_ci_mesa_spirv_shader_binary(struct gl_context *ctx, 71bf215546Sopenharmony_ci unsigned n, struct gl_shader **shaders, 72bf215546Sopenharmony_ci const void* binary, size_t length) 73bf215546Sopenharmony_ci{ 74bf215546Sopenharmony_ci struct gl_spirv_module *module; 75bf215546Sopenharmony_ci struct gl_shader_spirv_data *spirv_data; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci module = malloc(sizeof(*module) + length); 78bf215546Sopenharmony_ci if (!module) { 79bf215546Sopenharmony_ci _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderBinary"); 80bf215546Sopenharmony_ci return; 81bf215546Sopenharmony_ci } 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci p_atomic_set(&module->RefCount, 0); 84bf215546Sopenharmony_ci module->Length = length; 85bf215546Sopenharmony_ci memcpy(&module->Binary[0], binary, length); 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci for (int i = 0; i < n; ++i) { 88bf215546Sopenharmony_ci struct gl_shader *sh = shaders[i]; 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_ci spirv_data = rzalloc(NULL, struct gl_shader_spirv_data); 91bf215546Sopenharmony_ci _mesa_shader_spirv_data_reference(&sh->spirv_data, spirv_data); 92bf215546Sopenharmony_ci _mesa_spirv_module_reference(&spirv_data->SpirVModule, module); 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci sh->CompileStatus = COMPILE_FAILURE; 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci free((void *)sh->Source); 97bf215546Sopenharmony_ci sh->Source = NULL; 98bf215546Sopenharmony_ci free((void *)sh->FallbackSource); 99bf215546Sopenharmony_ci sh->FallbackSource = NULL; 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_ci ralloc_free(sh->ir); 102bf215546Sopenharmony_ci sh->ir = NULL; 103bf215546Sopenharmony_ci ralloc_free(sh->symbols); 104bf215546Sopenharmony_ci sh->symbols = NULL; 105bf215546Sopenharmony_ci } 106bf215546Sopenharmony_ci} 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci/** 109bf215546Sopenharmony_ci * This is the equivalent to compiler/glsl/linker.cpp::link_shaders() 110bf215546Sopenharmony_ci * but for SPIR-V programs. 111bf215546Sopenharmony_ci * 112bf215546Sopenharmony_ci * This method just creates the gl_linked_shader structs with a reference to 113bf215546Sopenharmony_ci * the SPIR-V data collected during previous steps. 114bf215546Sopenharmony_ci * 115bf215546Sopenharmony_ci * The real linking happens later in the driver-specifc call LinkShader(). 116bf215546Sopenharmony_ci * This is so backends can implement different linking strategies for 117bf215546Sopenharmony_ci * SPIR-V programs. 118bf215546Sopenharmony_ci */ 119bf215546Sopenharmony_civoid 120bf215546Sopenharmony_ci_mesa_spirv_link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) 121bf215546Sopenharmony_ci{ 122bf215546Sopenharmony_ci prog->data->LinkStatus = LINKING_SUCCESS; 123bf215546Sopenharmony_ci prog->data->Validated = false; 124bf215546Sopenharmony_ci 125bf215546Sopenharmony_ci for (unsigned i = 0; i < prog->NumShaders; i++) { 126bf215546Sopenharmony_ci struct gl_shader *shader = prog->Shaders[i]; 127bf215546Sopenharmony_ci gl_shader_stage shader_type = shader->Stage; 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci /* We only support one shader per stage. The gl_spirv spec doesn't seem 130bf215546Sopenharmony_ci * to prevent this, but the way the API is designed, requiring all shaders 131bf215546Sopenharmony_ci * to be specialized with an entry point, makes supporting this quite 132bf215546Sopenharmony_ci * undefined. 133bf215546Sopenharmony_ci * 134bf215546Sopenharmony_ci * TODO: Turn this into a proper error once the spec bug 135bf215546Sopenharmony_ci * <https://gitlab.khronos.org/opengl/API/issues/58> is resolved. 136bf215546Sopenharmony_ci */ 137bf215546Sopenharmony_ci if (prog->_LinkedShaders[shader_type]) { 138bf215546Sopenharmony_ci ralloc_strcat(&prog->data->InfoLog, 139bf215546Sopenharmony_ci "\nError trying to link more than one SPIR-V shader " 140bf215546Sopenharmony_ci "per stage.\n"); 141bf215546Sopenharmony_ci prog->data->LinkStatus = LINKING_FAILURE; 142bf215546Sopenharmony_ci return; 143bf215546Sopenharmony_ci } 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci assert(shader->spirv_data); 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader); 148bf215546Sopenharmony_ci linked->Stage = shader_type; 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci /* Create program and attach it to the linked shader */ 151bf215546Sopenharmony_ci struct gl_program *gl_prog = 152bf215546Sopenharmony_ci ctx->Driver.NewProgram(ctx, shader_type, prog->Name, false); 153bf215546Sopenharmony_ci if (!gl_prog) { 154bf215546Sopenharmony_ci prog->data->LinkStatus = LINKING_FAILURE; 155bf215546Sopenharmony_ci _mesa_delete_linked_shader(ctx, linked); 156bf215546Sopenharmony_ci return; 157bf215546Sopenharmony_ci } 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci _mesa_reference_shader_program_data(&gl_prog->sh.data, 160bf215546Sopenharmony_ci prog->data); 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_ci /* Don't use _mesa_reference_program() just take ownership */ 163bf215546Sopenharmony_ci linked->Program = gl_prog; 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci /* Reference the SPIR-V data from shader to the linked shader */ 166bf215546Sopenharmony_ci _mesa_shader_spirv_data_reference(&linked->spirv_data, 167bf215546Sopenharmony_ci shader->spirv_data); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci prog->_LinkedShaders[shader_type] = linked; 170bf215546Sopenharmony_ci prog->data->linked_stages |= 1 << shader_type; 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci int last_vert_stage = 174bf215546Sopenharmony_ci util_last_bit(prog->data->linked_stages & 175bf215546Sopenharmony_ci ((1 << (MESA_SHADER_GEOMETRY + 1)) - 1)); 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci if (last_vert_stage) 178bf215546Sopenharmony_ci prog->last_vert_prog = prog->_LinkedShaders[last_vert_stage - 1]->Program; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci /* Some shaders have to be linked with some other shaders present. */ 181bf215546Sopenharmony_ci if (!prog->SeparateShader) { 182bf215546Sopenharmony_ci static const struct { 183bf215546Sopenharmony_ci gl_shader_stage a, b; 184bf215546Sopenharmony_ci } stage_pairs[] = { 185bf215546Sopenharmony_ci { MESA_SHADER_GEOMETRY, MESA_SHADER_VERTEX }, 186bf215546Sopenharmony_ci { MESA_SHADER_TESS_EVAL, MESA_SHADER_VERTEX }, 187bf215546Sopenharmony_ci { MESA_SHADER_TESS_CTRL, MESA_SHADER_VERTEX }, 188bf215546Sopenharmony_ci { MESA_SHADER_TESS_CTRL, MESA_SHADER_TESS_EVAL }, 189bf215546Sopenharmony_ci }; 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(stage_pairs); i++) { 192bf215546Sopenharmony_ci gl_shader_stage a = stage_pairs[i].a; 193bf215546Sopenharmony_ci gl_shader_stage b = stage_pairs[i].b; 194bf215546Sopenharmony_ci if ((prog->data->linked_stages & ((1 << a) | (1 << b))) == (1 << a)) { 195bf215546Sopenharmony_ci ralloc_asprintf_append(&prog->data->InfoLog, 196bf215546Sopenharmony_ci "%s shader must be linked with %s shader\n", 197bf215546Sopenharmony_ci _mesa_shader_stage_to_string(a), 198bf215546Sopenharmony_ci _mesa_shader_stage_to_string(b)); 199bf215546Sopenharmony_ci prog->data->LinkStatus = LINKING_FAILURE; 200bf215546Sopenharmony_ci return; 201bf215546Sopenharmony_ci } 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci } 204bf215546Sopenharmony_ci 205bf215546Sopenharmony_ci /* Compute shaders have additional restrictions. */ 206bf215546Sopenharmony_ci if ((prog->data->linked_stages & (1 << MESA_SHADER_COMPUTE)) && 207bf215546Sopenharmony_ci (prog->data->linked_stages & ~(1 << MESA_SHADER_COMPUTE))) { 208bf215546Sopenharmony_ci ralloc_asprintf_append(&prog->data->InfoLog, 209bf215546Sopenharmony_ci "Compute shaders may not be linked with any other " 210bf215546Sopenharmony_ci "type of shader\n"); 211bf215546Sopenharmony_ci prog->data->LinkStatus = LINKING_FAILURE; 212bf215546Sopenharmony_ci return; 213bf215546Sopenharmony_ci } 214bf215546Sopenharmony_ci} 215bf215546Sopenharmony_ci 216bf215546Sopenharmony_cinir_shader * 217bf215546Sopenharmony_ci_mesa_spirv_to_nir(struct gl_context *ctx, 218bf215546Sopenharmony_ci const struct gl_shader_program *prog, 219bf215546Sopenharmony_ci gl_shader_stage stage, 220bf215546Sopenharmony_ci const nir_shader_compiler_options *options) 221bf215546Sopenharmony_ci{ 222bf215546Sopenharmony_ci struct gl_linked_shader *linked_shader = prog->_LinkedShaders[stage]; 223bf215546Sopenharmony_ci assert (linked_shader); 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_ci struct gl_shader_spirv_data *spirv_data = linked_shader->spirv_data; 226bf215546Sopenharmony_ci assert(spirv_data); 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci struct gl_spirv_module *spirv_module = spirv_data->SpirVModule; 229bf215546Sopenharmony_ci assert (spirv_module != NULL); 230bf215546Sopenharmony_ci 231bf215546Sopenharmony_ci const char *entry_point_name = spirv_data->SpirVEntryPoint; 232bf215546Sopenharmony_ci assert(entry_point_name); 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci struct nir_spirv_specialization *spec_entries = 235bf215546Sopenharmony_ci calloc(sizeof(*spec_entries), 236bf215546Sopenharmony_ci spirv_data->NumSpecializationConstants); 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci for (unsigned i = 0; i < spirv_data->NumSpecializationConstants; ++i) { 239bf215546Sopenharmony_ci spec_entries[i].id = spirv_data->SpecializationConstantsIndex[i]; 240bf215546Sopenharmony_ci spec_entries[i].value.u32 = spirv_data->SpecializationConstantsValue[i]; 241bf215546Sopenharmony_ci spec_entries[i].defined_on_module = false; 242bf215546Sopenharmony_ci } 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci const struct spirv_to_nir_options spirv_options = { 245bf215546Sopenharmony_ci .environment = NIR_SPIRV_OPENGL, 246bf215546Sopenharmony_ci .use_deref_buffer_array_length = true, 247bf215546Sopenharmony_ci .subgroup_size = SUBGROUP_SIZE_UNIFORM, 248bf215546Sopenharmony_ci .caps = ctx->Const.SpirVCapabilities, 249bf215546Sopenharmony_ci .ubo_addr_format = nir_address_format_32bit_index_offset, 250bf215546Sopenharmony_ci .ssbo_addr_format = nir_address_format_32bit_index_offset, 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci /* TODO: Consider changing this to an address format that has the NULL 253bf215546Sopenharmony_ci * pointer equals to 0. That might be a better format to play nice 254bf215546Sopenharmony_ci * with certain code / code generators. 255bf215546Sopenharmony_ci */ 256bf215546Sopenharmony_ci .shared_addr_format = nir_address_format_32bit_offset, 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci }; 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci nir_shader *nir = 261bf215546Sopenharmony_ci spirv_to_nir((const uint32_t *) &spirv_module->Binary[0], 262bf215546Sopenharmony_ci spirv_module->Length / 4, 263bf215546Sopenharmony_ci spec_entries, spirv_data->NumSpecializationConstants, 264bf215546Sopenharmony_ci stage, entry_point_name, 265bf215546Sopenharmony_ci &spirv_options, 266bf215546Sopenharmony_ci options); 267bf215546Sopenharmony_ci free(spec_entries); 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci assert(nir); 270bf215546Sopenharmony_ci assert(nir->info.stage == stage); 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci nir->options = options; 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci nir->info.name = 275bf215546Sopenharmony_ci ralloc_asprintf(nir, "SPIRV:%s:%d", 276bf215546Sopenharmony_ci _mesa_shader_stage_to_abbrev(nir->info.stage), 277bf215546Sopenharmony_ci prog->Name); 278bf215546Sopenharmony_ci nir_validate_shader(nir, "after spirv_to_nir"); 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci nir->info.separate_shader = linked_shader->Program->info.separate_shader; 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci /* Convert some sysvals to input varyings. */ 283bf215546Sopenharmony_ci const struct nir_lower_sysvals_to_varyings_options sysvals_to_varyings = { 284bf215546Sopenharmony_ci .frag_coord = !ctx->Const.GLSLFragCoordIsSysVal, 285bf215546Sopenharmony_ci .point_coord = !ctx->Const.GLSLPointCoordIsSysVal, 286bf215546Sopenharmony_ci .front_face = !ctx->Const.GLSLFrontFacingIsSysVal, 287bf215546Sopenharmony_ci }; 288bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_sysvals_to_varyings, &sysvals_to_varyings); 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci /* We have to lower away local constant initializers right before we 291bf215546Sopenharmony_ci * inline functions. That way they get properly initialized at the top 292bf215546Sopenharmony_ci * of the function and not at the top of its caller. 293bf215546Sopenharmony_ci */ 294bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp); 295bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_returns); 296bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_inline_functions); 297bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_copy_prop); 298bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_opt_deref); 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci /* Pick off the single entrypoint that we want */ 301bf215546Sopenharmony_ci nir_remove_non_entrypoints(nir); 302bf215546Sopenharmony_ci 303bf215546Sopenharmony_ci /* Now that we've deleted all but the main function, we can go ahead and 304bf215546Sopenharmony_ci * lower the rest of the constant initializers. We do this here so that 305bf215546Sopenharmony_ci * nir_remove_dead_variables and split_per_member_structs below see the 306bf215546Sopenharmony_ci * corresponding stores. 307bf215546Sopenharmony_ci */ 308bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_variable_initializers, ~0); 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci /* Split member structs. We do this before lower_io_to_temporaries so that 311bf215546Sopenharmony_ci * it doesn't lower system values to temporaries by accident. 312bf215546Sopenharmony_ci */ 313bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_split_var_copies); 314bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_split_per_member_structs); 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_ci if (nir->info.stage == MESA_SHADER_VERTEX) 317bf215546Sopenharmony_ci nir_remap_dual_slot_attributes(nir, &linked_shader->Program->DualSlotInputs); 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_ci NIR_PASS_V(nir, nir_lower_frexp); 320bf215546Sopenharmony_ci 321bf215546Sopenharmony_ci return nir; 322bf215546Sopenharmony_ci} 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_civoid GLAPIENTRY 325bf215546Sopenharmony_ci_mesa_SpecializeShaderARB(GLuint shader, 326bf215546Sopenharmony_ci const GLchar *pEntryPoint, 327bf215546Sopenharmony_ci GLuint numSpecializationConstants, 328bf215546Sopenharmony_ci const GLuint *pConstantIndex, 329bf215546Sopenharmony_ci const GLuint *pConstantValue) 330bf215546Sopenharmony_ci{ 331bf215546Sopenharmony_ci GET_CURRENT_CONTEXT(ctx); 332bf215546Sopenharmony_ci struct gl_shader *sh; 333bf215546Sopenharmony_ci bool has_entry_point; 334bf215546Sopenharmony_ci struct nir_spirv_specialization *spec_entries = NULL; 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci if (!ctx->Extensions.ARB_gl_spirv) { 337bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, "glSpecializeShaderARB"); 338bf215546Sopenharmony_ci return; 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci 341bf215546Sopenharmony_ci sh = _mesa_lookup_shader_err(ctx, shader, "glSpecializeShaderARB"); 342bf215546Sopenharmony_ci if (!sh) 343bf215546Sopenharmony_ci return; 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci if (!sh->spirv_data) { 346bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 347bf215546Sopenharmony_ci "glSpecializeShaderARB(not SPIR-V)"); 348bf215546Sopenharmony_ci return; 349bf215546Sopenharmony_ci } 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci if (sh->CompileStatus) { 352bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_OPERATION, 353bf215546Sopenharmony_ci "glSpecializeShaderARB(already specialized)"); 354bf215546Sopenharmony_ci return; 355bf215546Sopenharmony_ci } 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci struct gl_shader_spirv_data *spirv_data = sh->spirv_data; 358bf215546Sopenharmony_ci 359bf215546Sopenharmony_ci /* From the GL_ARB_gl_spirv spec: 360bf215546Sopenharmony_ci * 361bf215546Sopenharmony_ci * "The OpenGL API expects the SPIR-V module to have already been 362bf215546Sopenharmony_ci * validated, and can return an error if it discovers anything invalid 363bf215546Sopenharmony_ci * in the module. An invalid SPIR-V module is allowed to result in 364bf215546Sopenharmony_ci * undefined behavior." 365bf215546Sopenharmony_ci * 366bf215546Sopenharmony_ci * However, the following errors still need to be detected (from the same 367bf215546Sopenharmony_ci * spec): 368bf215546Sopenharmony_ci * 369bf215546Sopenharmony_ci * "INVALID_VALUE is generated if <pEntryPoint> does not name a valid 370bf215546Sopenharmony_ci * entry point for <shader>. 371bf215546Sopenharmony_ci * 372bf215546Sopenharmony_ci * INVALID_VALUE is generated if any element of <pConstantIndex> 373bf215546Sopenharmony_ci * refers to a specialization constant that does not exist in the 374bf215546Sopenharmony_ci * shader module contained in <shader>." 375bf215546Sopenharmony_ci * 376bf215546Sopenharmony_ci * We cannot flag those errors a-priori because detecting them requires 377bf215546Sopenharmony_ci * parsing the module. However, flagging them during specialization is okay, 378bf215546Sopenharmony_ci * since it makes no difference in terms of application-visible state. 379bf215546Sopenharmony_ci */ 380bf215546Sopenharmony_ci spec_entries = calloc(sizeof(*spec_entries), numSpecializationConstants); 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci for (unsigned i = 0; i < numSpecializationConstants; ++i) { 383bf215546Sopenharmony_ci spec_entries[i].id = pConstantIndex[i]; 384bf215546Sopenharmony_ci spec_entries[i].value.u32 = pConstantValue[i]; 385bf215546Sopenharmony_ci spec_entries[i].defined_on_module = false; 386bf215546Sopenharmony_ci } 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci has_entry_point = 389bf215546Sopenharmony_ci gl_spirv_validation((uint32_t *)&spirv_data->SpirVModule->Binary[0], 390bf215546Sopenharmony_ci spirv_data->SpirVModule->Length / 4, 391bf215546Sopenharmony_ci spec_entries, numSpecializationConstants, 392bf215546Sopenharmony_ci sh->Stage, pEntryPoint); 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci /* See previous spec comment */ 395bf215546Sopenharmony_ci if (!has_entry_point) { 396bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 397bf215546Sopenharmony_ci "glSpecializeShaderARB(\"%s\" is not a valid entry point" 398bf215546Sopenharmony_ci " for shader)", pEntryPoint); 399bf215546Sopenharmony_ci goto end; 400bf215546Sopenharmony_ci } 401bf215546Sopenharmony_ci 402bf215546Sopenharmony_ci for (unsigned i = 0; i < numSpecializationConstants; ++i) { 403bf215546Sopenharmony_ci if (spec_entries[i].defined_on_module == false) { 404bf215546Sopenharmony_ci _mesa_error(ctx, GL_INVALID_VALUE, 405bf215546Sopenharmony_ci "glSpecializeShaderARB(constant \"%i\" does not exist " 406bf215546Sopenharmony_ci "in shader)", spec_entries[i].id); 407bf215546Sopenharmony_ci goto end; 408bf215546Sopenharmony_ci } 409bf215546Sopenharmony_ci } 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci spirv_data->SpirVEntryPoint = ralloc_strdup(spirv_data, pEntryPoint); 412bf215546Sopenharmony_ci 413bf215546Sopenharmony_ci /* Note that we didn't make a real compilation of the module (spirv_to_nir), 414bf215546Sopenharmony_ci * but just checked some error conditions. Real "compilation" will be done 415bf215546Sopenharmony_ci * later, upon linking. 416bf215546Sopenharmony_ci */ 417bf215546Sopenharmony_ci sh->CompileStatus = COMPILE_SUCCESS; 418bf215546Sopenharmony_ci 419bf215546Sopenharmony_ci spirv_data->NumSpecializationConstants = numSpecializationConstants; 420bf215546Sopenharmony_ci spirv_data->SpecializationConstantsIndex = 421bf215546Sopenharmony_ci rzalloc_array_size(spirv_data, sizeof(GLuint), 422bf215546Sopenharmony_ci numSpecializationConstants); 423bf215546Sopenharmony_ci spirv_data->SpecializationConstantsValue = 424bf215546Sopenharmony_ci rzalloc_array_size(spirv_data, sizeof(GLuint), 425bf215546Sopenharmony_ci numSpecializationConstants); 426bf215546Sopenharmony_ci for (unsigned i = 0; i < numSpecializationConstants; ++i) { 427bf215546Sopenharmony_ci spirv_data->SpecializationConstantsIndex[i] = pConstantIndex[i]; 428bf215546Sopenharmony_ci spirv_data->SpecializationConstantsValue[i] = pConstantValue[i]; 429bf215546Sopenharmony_ci } 430bf215546Sopenharmony_ci 431bf215546Sopenharmony_ci end: 432bf215546Sopenharmony_ci free(spec_entries); 433bf215546Sopenharmony_ci} 434