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
36 void
_mesa_spirv_module_reference(struct gl_spirv_module ** dest,struct gl_spirv_module * src)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
51 void
_mesa_shader_spirv_data_reference(struct gl_shader_spirv_data ** dest,struct gl_shader_spirv_data * src)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
68 void
_mesa_spirv_shader_binary(struct gl_context * ctx,unsigned n,struct gl_shader ** shaders,const void * binary,size_t length)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 */
118 void
_mesa_spirv_link_shaders(struct gl_context * ctx,struct gl_shader_program * prog)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
216 nir_shader *
_mesa_spirv_to_nir(struct gl_context * ctx,const struct gl_shader_program * prog,gl_shader_stage stage,const nir_shader_compiler_options * options)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 .frag_coord_is_sysval = ctx->Const.GLSLFragCoordIsSysVal,
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 /* We have to lower away local constant initializers right before we
282 * inline functions. That way they get properly initialized at the top
283 * of the function and not at the top of its caller.
284 */
285 NIR_PASS_V(nir, nir_lower_variable_initializers, nir_var_function_temp);
286 NIR_PASS_V(nir, nir_lower_returns);
287 NIR_PASS_V(nir, nir_inline_functions);
288 NIR_PASS_V(nir, nir_copy_prop);
289 NIR_PASS_V(nir, nir_opt_deref);
290
291 /* Pick off the single entrypoint that we want */
292 foreach_list_typed_safe(nir_function, func, node, &nir->functions) {
293 if (!func->is_entrypoint)
294 exec_node_remove(&func->node);
295 }
296 assert(exec_list_length(&nir->functions) == 1);
297
298 /* Now that we've deleted all but the main function, we can go ahead and
299 * lower the rest of the constant initializers. We do this here so that
300 * nir_remove_dead_variables and split_per_member_structs below see the
301 * corresponding stores.
302 */
303 NIR_PASS_V(nir, nir_lower_variable_initializers, ~0);
304
305 /* Split member structs. We do this before lower_io_to_temporaries so that
306 * it doesn't lower system values to temporaries by accident.
307 */
308 NIR_PASS_V(nir, nir_split_var_copies);
309 NIR_PASS_V(nir, nir_split_per_member_structs);
310
311 if (nir->info.stage == MESA_SHADER_VERTEX)
312 nir_remap_dual_slot_attributes(nir, &linked_shader->Program->DualSlotInputs);
313
314 NIR_PASS_V(nir, nir_lower_frexp);
315
316 return nir;
317 }
318
319 void GLAPIENTRY
_mesa_SpecializeShaderARB(GLuint shader,const GLchar * pEntryPoint,GLuint numSpecializationConstants,const GLuint * pConstantIndex,const GLuint * pConstantValue)320 _mesa_SpecializeShaderARB(GLuint shader,
321 const GLchar *pEntryPoint,
322 GLuint numSpecializationConstants,
323 const GLuint *pConstantIndex,
324 const GLuint *pConstantValue)
325 {
326 GET_CURRENT_CONTEXT(ctx);
327 struct gl_shader *sh;
328 bool has_entry_point;
329 struct nir_spirv_specialization *spec_entries = NULL;
330
331 if (!ctx->Extensions.ARB_gl_spirv) {
332 _mesa_error(ctx, GL_INVALID_OPERATION, "glSpecializeShaderARB");
333 return;
334 }
335
336 sh = _mesa_lookup_shader_err(ctx, shader, "glSpecializeShaderARB");
337 if (!sh)
338 return;
339
340 if (!sh->spirv_data) {
341 _mesa_error(ctx, GL_INVALID_OPERATION,
342 "glSpecializeShaderARB(not SPIR-V)");
343 return;
344 }
345
346 if (sh->CompileStatus) {
347 _mesa_error(ctx, GL_INVALID_OPERATION,
348 "glSpecializeShaderARB(already specialized)");
349 return;
350 }
351
352 struct gl_shader_spirv_data *spirv_data = sh->spirv_data;
353
354 /* From the GL_ARB_gl_spirv spec:
355 *
356 * "The OpenGL API expects the SPIR-V module to have already been
357 * validated, and can return an error if it discovers anything invalid
358 * in the module. An invalid SPIR-V module is allowed to result in
359 * undefined behavior."
360 *
361 * However, the following errors still need to be detected (from the same
362 * spec):
363 *
364 * "INVALID_VALUE is generated if <pEntryPoint> does not name a valid
365 * entry point for <shader>.
366 *
367 * INVALID_VALUE is generated if any element of <pConstantIndex>
368 * refers to a specialization constant that does not exist in the
369 * shader module contained in <shader>."
370 *
371 * We cannot flag those errors a-priori because detecting them requires
372 * parsing the module. However, flagging them during specialization is okay,
373 * since it makes no difference in terms of application-visible state.
374 */
375 spec_entries = calloc(sizeof(*spec_entries), numSpecializationConstants);
376
377 for (unsigned i = 0; i < numSpecializationConstants; ++i) {
378 spec_entries[i].id = pConstantIndex[i];
379 spec_entries[i].value.u32 = pConstantValue[i];
380 spec_entries[i].defined_on_module = false;
381 }
382
383 has_entry_point =
384 gl_spirv_validation((uint32_t *)&spirv_data->SpirVModule->Binary[0],
385 spirv_data->SpirVModule->Length / 4,
386 spec_entries, numSpecializationConstants,
387 sh->Stage, pEntryPoint);
388
389 /* See previous spec comment */
390 if (!has_entry_point) {
391 _mesa_error(ctx, GL_INVALID_VALUE,
392 "glSpecializeShaderARB(\"%s\" is not a valid entry point"
393 " for shader)", pEntryPoint);
394 goto end;
395 }
396
397 for (unsigned i = 0; i < numSpecializationConstants; ++i) {
398 if (spec_entries[i].defined_on_module == false) {
399 _mesa_error(ctx, GL_INVALID_VALUE,
400 "glSpecializeShaderARB(constant \"%i\" does not exist "
401 "in shader)", spec_entries[i].id);
402 goto end;
403 }
404 }
405
406 spirv_data->SpirVEntryPoint = ralloc_strdup(spirv_data, pEntryPoint);
407
408 /* Note that we didn't make a real compilation of the module (spirv_to_nir),
409 * but just checked some error conditions. Real "compilation" will be done
410 * later, upon linking.
411 */
412 sh->CompileStatus = COMPILE_SUCCESS;
413
414 spirv_data->NumSpecializationConstants = numSpecializationConstants;
415 spirv_data->SpecializationConstantsIndex =
416 rzalloc_array_size(spirv_data, sizeof(GLuint),
417 numSpecializationConstants);
418 spirv_data->SpecializationConstantsValue =
419 rzalloc_array_size(spirv_data, sizeof(GLuint),
420 numSpecializationConstants);
421 for (unsigned i = 0; i < numSpecializationConstants; ++i) {
422 spirv_data->SpecializationConstantsIndex[i] = pConstantIndex[i];
423 spirv_data->SpecializationConstantsValue[i] = pConstantValue[i];
424 }
425
426 end:
427 free(spec_entries);
428 }
429