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