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