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 36void 37_mesa_spirv_module_reference(struct gl_spirv_module **dest, 38 struct gl_spirv_module *src) 39{ 40 struct gl_spirv_module *old = *dest; 41 42 if (old && p_atomic_dec_zero(&old->RefCount)) 43 free(old); 44 45 *dest = src; 46 47 if (src) 48 p_atomic_inc(&src->RefCount); 49} 50 51void 52_mesa_shader_spirv_data_reference(struct gl_shader_spirv_data **dest, 53 struct gl_shader_spirv_data *src) 54{ 55 struct gl_shader_spirv_data *old = *dest; 56 57 if (old && p_atomic_dec_zero(&old->RefCount)) { 58 _mesa_spirv_module_reference(&(*dest)->SpirVModule, NULL); 59 ralloc_free(old); 60 } 61 62 *dest = src; 63 64 if (src) 65 p_atomic_inc(&src->RefCount); 66} 67 68void 69_mesa_spirv_shader_binary(struct gl_context *ctx, 70 unsigned n, struct gl_shader **shaders, 71 const void* binary, size_t length) 72{ 73 struct gl_spirv_module *module; 74 struct gl_shader_spirv_data *spirv_data; 75 76 module = malloc(sizeof(*module) + length); 77 if (!module) { 78 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderBinary"); 79 return; 80 } 81 82 p_atomic_set(&module->RefCount, 0); 83 module->Length = length; 84 memcpy(&module->Binary[0], binary, length); 85 86 for (int i = 0; i < n; ++i) { 87 struct gl_shader *sh = shaders[i]; 88 89 spirv_data = rzalloc(NULL, struct gl_shader_spirv_data); 90 _mesa_shader_spirv_data_reference(&sh->spirv_data, spirv_data); 91 _mesa_spirv_module_reference(&spirv_data->SpirVModule, module); 92 93 sh->CompileStatus = COMPILE_FAILURE; 94 95 free((void *)sh->Source); 96 sh->Source = NULL; 97 free((void *)sh->FallbackSource); 98 sh->FallbackSource = NULL; 99 100 ralloc_free(sh->ir); 101 sh->ir = NULL; 102 ralloc_free(sh->symbols); 103 sh->symbols = NULL; 104 } 105} 106 107/** 108 * This is the equivalent to compiler/glsl/linker.cpp::link_shaders() 109 * but for SPIR-V programs. 110 * 111 * This method just creates the gl_linked_shader structs with a reference to 112 * the SPIR-V data collected during previous steps. 113 * 114 * The real linking happens later in the driver-specifc call LinkShader(). 115 * This is so backends can implement different linking strategies for 116 * SPIR-V programs. 117 */ 118void 119_mesa_spirv_link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) 120{ 121 prog->data->LinkStatus = LINKING_SUCCESS; 122 prog->data->Validated = false; 123 124 for (unsigned i = 0; i < prog->NumShaders; i++) { 125 struct gl_shader *shader = prog->Shaders[i]; 126 gl_shader_stage shader_type = shader->Stage; 127 128 /* We only support one shader per stage. The gl_spirv spec doesn't seem 129 * to prevent this, but the way the API is designed, requiring all shaders 130 * to be specialized with an entry point, makes supporting this quite 131 * undefined. 132 * 133 * TODO: Turn this into a proper error once the spec bug 134 * <https://gitlab.khronos.org/opengl/API/issues/58> is resolved. 135 */ 136 if (prog->_LinkedShaders[shader_type]) { 137 ralloc_strcat(&prog->data->InfoLog, 138 "\nError trying to link more than one SPIR-V shader " 139 "per stage.\n"); 140 prog->data->LinkStatus = LINKING_FAILURE; 141 return; 142 } 143 144 assert(shader->spirv_data); 145 146 struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader); 147 linked->Stage = shader_type; 148 149 /* Create program and attach it to the linked shader */ 150 struct gl_program *gl_prog = 151 ctx->Driver.NewProgram(ctx, shader_type, prog->Name, false); 152 if (!gl_prog) { 153 prog->data->LinkStatus = LINKING_FAILURE; 154 _mesa_delete_linked_shader(ctx, linked); 155 return; 156 } 157 158 _mesa_reference_shader_program_data(ctx, 159 &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 .caps = ctx->Const.SpirVCapabilities, 248 .ubo_addr_format = nir_address_format_32bit_index_offset, 249 .ssbo_addr_format = nir_address_format_32bit_index_offset, 250 251 /* TODO: Consider changing this to an address format that has the NULL 252 * pointer equals to 0. That might be a better format to play nice 253 * with certain code / code generators. 254 */ 255 .shared_addr_format = nir_address_format_32bit_offset, 256 257 }; 258 259 nir_shader *nir = 260 spirv_to_nir((const uint32_t *) &spirv_module->Binary[0], 261 spirv_module->Length / 4, 262 spec_entries, spirv_data->NumSpecializationConstants, 263 stage, entry_point_name, 264 &spirv_options, 265 options); 266 free(spec_entries); 267 268 assert(nir); 269 assert(nir->info.stage == stage); 270 271 nir->options = options; 272 273 nir->info.name = 274 ralloc_asprintf(nir, "SPIRV:%s:%d", 275 _mesa_shader_stage_to_abbrev(nir->info.stage), 276 prog->Name); 277 nir_validate_shader(nir, "after spirv_to_nir"); 278 279 nir->info.separate_shader = linked_shader->Program->info.separate_shader; 280 281 /* Convert some sysvals to input varyings. */ 282 const struct nir_lower_sysvals_to_varyings_options sysvals_to_varyings = { 283 .frag_coord = !ctx->Const.GLSLFragCoordIsSysVal, 284 .point_coord = !ctx->Const.GLSLPointCoordIsSysVal, 285 .front_face = !ctx->Const.GLSLFrontFacingIsSysVal, 286 }; 287 NIR_PASS_V(nir, nir_lower_sysvals_to_varyings, &sysvals_to_varyings); 288 289 /* We have to lower away local constant initializers right before we 290 * inline functions. That way they get properly initialized at the top 291 * of the function and not at the top of its caller. 292 */ 293 NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp); 294 NIR_PASS_V(nir, nir_lower_returns); 295 NIR_PASS_V(nir, nir_inline_functions); 296 NIR_PASS_V(nir, nir_copy_prop); 297 NIR_PASS_V(nir, nir_opt_deref); 298 299 /* Pick off the single entrypoint that we want */ 300 foreach_list_typed_safe(nir_function, func, node, &nir->functions) { 301 if (!func->is_entrypoint) 302 exec_node_remove(&func->node); 303 } 304 assert(exec_list_length(&nir->functions) == 1); 305 306 /* Now that we've deleted all but the main function, we can go ahead and 307 * lower the rest of the constant initializers. We do this here so that 308 * nir_remove_dead_variables and split_per_member_structs below see the 309 * corresponding stores. 310 */ 311 NIR_PASS_V(nir, nir_lower_variable_initializers, ~0); 312 313 /* Split member structs. We do this before lower_io_to_temporaries so that 314 * it doesn't lower system values to temporaries by accident. 315 */ 316 NIR_PASS_V(nir, nir_split_var_copies); 317 NIR_PASS_V(nir, nir_split_per_member_structs); 318 319 if (nir->info.stage == MESA_SHADER_VERTEX) 320 nir_remap_dual_slot_attributes(nir, &linked_shader->Program->DualSlotInputs); 321 322 NIR_PASS_V(nir, nir_lower_frexp); 323 324 return nir; 325} 326 327void GLAPIENTRY 328_mesa_SpecializeShaderARB(GLuint shader, 329 const GLchar *pEntryPoint, 330 GLuint numSpecializationConstants, 331 const GLuint *pConstantIndex, 332 const GLuint *pConstantValue) 333{ 334 GET_CURRENT_CONTEXT(ctx); 335 struct gl_shader *sh; 336 bool has_entry_point; 337 struct nir_spirv_specialization *spec_entries = NULL; 338 339 if (!ctx->Extensions.ARB_gl_spirv) { 340 _mesa_error(ctx, GL_INVALID_OPERATION, "glSpecializeShaderARB"); 341 return; 342 } 343 344 sh = _mesa_lookup_shader_err(ctx, shader, "glSpecializeShaderARB"); 345 if (!sh) 346 return; 347 348 if (!sh->spirv_data) { 349 _mesa_error(ctx, GL_INVALID_OPERATION, 350 "glSpecializeShaderARB(not SPIR-V)"); 351 return; 352 } 353 354 if (sh->CompileStatus) { 355 _mesa_error(ctx, GL_INVALID_OPERATION, 356 "glSpecializeShaderARB(already specialized)"); 357 return; 358 } 359 360 struct gl_shader_spirv_data *spirv_data = sh->spirv_data; 361 362 /* From the GL_ARB_gl_spirv spec: 363 * 364 * "The OpenGL API expects the SPIR-V module to have already been 365 * validated, and can return an error if it discovers anything invalid 366 * in the module. An invalid SPIR-V module is allowed to result in 367 * undefined behavior." 368 * 369 * However, the following errors still need to be detected (from the same 370 * spec): 371 * 372 * "INVALID_VALUE is generated if <pEntryPoint> does not name a valid 373 * entry point for <shader>. 374 * 375 * INVALID_VALUE is generated if any element of <pConstantIndex> 376 * refers to a specialization constant that does not exist in the 377 * shader module contained in <shader>." 378 * 379 * We cannot flag those errors a-priori because detecting them requires 380 * parsing the module. However, flagging them during specialization is okay, 381 * since it makes no difference in terms of application-visible state. 382 */ 383 spec_entries = calloc(sizeof(*spec_entries), numSpecializationConstants); 384 385 for (unsigned i = 0; i < numSpecializationConstants; ++i) { 386 spec_entries[i].id = pConstantIndex[i]; 387 spec_entries[i].value.u32 = pConstantValue[i]; 388 spec_entries[i].defined_on_module = false; 389 } 390 391 has_entry_point = 392 gl_spirv_validation((uint32_t *)&spirv_data->SpirVModule->Binary[0], 393 spirv_data->SpirVModule->Length / 4, 394 spec_entries, numSpecializationConstants, 395 sh->Stage, pEntryPoint); 396 397 /* See previous spec comment */ 398 if (!has_entry_point) { 399 _mesa_error(ctx, GL_INVALID_VALUE, 400 "glSpecializeShaderARB(\"%s\" is not a valid entry point" 401 " for shader)", pEntryPoint); 402 goto end; 403 } 404 405 for (unsigned i = 0; i < numSpecializationConstants; ++i) { 406 if (spec_entries[i].defined_on_module == false) { 407 _mesa_error(ctx, GL_INVALID_VALUE, 408 "glSpecializeShaderARB(constant \"%i\" does not exist " 409 "in shader)", spec_entries[i].id); 410 goto end; 411 } 412 } 413 414 spirv_data->SpirVEntryPoint = ralloc_strdup(spirv_data, pEntryPoint); 415 416 /* Note that we didn't make a real compilation of the module (spirv_to_nir), 417 * but just checked some error conditions. Real "compilation" will be done 418 * later, upon linking. 419 */ 420 sh->CompileStatus = COMPILE_SUCCESS; 421 422 spirv_data->NumSpecializationConstants = numSpecializationConstants; 423 spirv_data->SpecializationConstantsIndex = 424 rzalloc_array_size(spirv_data, sizeof(GLuint), 425 numSpecializationConstants); 426 spirv_data->SpecializationConstantsValue = 427 rzalloc_array_size(spirv_data, sizeof(GLuint), 428 numSpecializationConstants); 429 for (unsigned i = 0; i < numSpecializationConstants; ++i) { 430 spirv_data->SpecializationConstantsIndex[i] = pConstantIndex[i]; 431 spirv_data->SpecializationConstantsValue[i] = pConstantValue[i]; 432 } 433 434 end: 435 free(spec_entries); 436} 437