xref: /third_party/mesa3d/src/mesa/main/glspirv.c (revision bf215546)
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