mesa/glspirv: pick off the only entry point we need
[mesa.git] / src / mesa / main / glspirv.c
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
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
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
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 assert(length >= 0);
77
78 module = malloc(sizeof(*module) + length);
79 if (!module) {
80 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderBinary");
81 return;
82 }
83
84 p_atomic_set(&module->RefCount, 0);
85 module->Length = length;
86 memcpy(&module->Binary[0], binary, length);
87
88 for (int i = 0; i < n; ++i) {
89 struct gl_shader *sh = shaders[i];
90
91 spirv_data = rzalloc(NULL, struct gl_shader_spirv_data);
92 _mesa_shader_spirv_data_reference(&sh->spirv_data, spirv_data);
93 _mesa_spirv_module_reference(&spirv_data->SpirVModule, module);
94
95 sh->CompileStatus = COMPILE_FAILURE;
96
97 free((void *)sh->Source);
98 sh->Source = NULL;
99 free((void *)sh->FallbackSource);
100 sh->FallbackSource = NULL;
101
102 ralloc_free(sh->ir);
103 sh->ir = NULL;
104 ralloc_free(sh->symbols);
105 sh->symbols = NULL;
106 }
107 }
108
109 /**
110 * This is the equivalent to compiler/glsl/linker.cpp::link_shaders()
111 * but for SPIR-V programs.
112 *
113 * This method just creates the gl_linked_shader structs with a reference to
114 * the SPIR-V data collected during previous steps.
115 *
116 * The real linking happens later in the driver-specifc call LinkShader().
117 * This is so backends can implement different linking strategies for
118 * SPIR-V programs.
119 */
120 void
121 _mesa_spirv_link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
122 {
123 prog->data->LinkStatus = LINKING_SUCCESS;
124 prog->data->Validated = false;
125
126 for (unsigned i = 0; i < prog->NumShaders; i++) {
127 struct gl_shader *shader = prog->Shaders[i];
128 gl_shader_stage shader_type = shader->Stage;
129
130 /* We only support one shader per stage. The gl_spirv spec doesn't seem
131 * to prevent this, but the way the API is designed, requiring all shaders
132 * to be specialized with an entry point, makes supporting this quite
133 * undefined.
134 *
135 * TODO: Turn this into a proper error once the spec bug
136 * <https://gitlab.khronos.org/opengl/API/issues/58> is resolved.
137 */
138 if (prog->_LinkedShaders[shader_type]) {
139 ralloc_strcat(&prog->data->InfoLog,
140 "\nError trying to link more than one SPIR-V shader "
141 "per stage.\n");
142 prog->data->LinkStatus = LINKING_FAILURE;
143 return;
144 }
145
146 assert(shader->spirv_data);
147
148 struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader);
149 linked->Stage = shader_type;
150
151 /* Create program and attach it to the linked shader */
152 struct gl_program *gl_prog =
153 ctx->Driver.NewProgram(ctx,
154 _mesa_shader_stage_to_program(shader_type),
155 prog->Name, false);
156 if (!gl_prog) {
157 prog->data->LinkStatus = LINKING_FAILURE;
158 _mesa_delete_linked_shader(ctx, linked);
159 return;
160 }
161
162 _mesa_reference_shader_program_data(ctx,
163 &gl_prog->sh.data,
164 prog->data);
165
166 /* Don't use _mesa_reference_program() just take ownership */
167 linked->Program = gl_prog;
168
169 /* Reference the SPIR-V data from shader to the linked shader */
170 _mesa_shader_spirv_data_reference(&linked->spirv_data,
171 shader->spirv_data);
172
173 prog->_LinkedShaders[shader_type] = linked;
174 prog->data->linked_stages |= 1 << shader_type;
175 }
176
177 int last_vert_stage =
178 util_last_bit(prog->data->linked_stages &
179 ((1 << (MESA_SHADER_GEOMETRY + 1)) - 1));
180
181 if (last_vert_stage)
182 prog->last_vert_prog = prog->_LinkedShaders[last_vert_stage - 1]->Program;
183 }
184
185 static void
186 nir_compute_double_inputs(nir_shader *shader,
187 const nir_shader_compiler_options *options)
188 {
189 nir_foreach_variable(var, &shader->inputs) {
190 if (glsl_type_is_dual_slot(glsl_without_array(var->type))) {
191 for (uint i = 0; i < glsl_count_attribute_slots(var->type, true); i++) {
192 uint64_t bitfield = BITFIELD64_BIT(var->data.location + i);
193 shader->info.vs.double_inputs |= bitfield;
194 }
195 }
196 }
197 }
198
199 nir_shader *
200 _mesa_spirv_to_nir(struct gl_context *ctx,
201 const struct gl_shader_program *prog,
202 gl_shader_stage stage,
203 const nir_shader_compiler_options *options)
204 {
205 nir_shader *nir = NULL;
206
207 struct gl_linked_shader *linked_shader = prog->_LinkedShaders[stage];
208 assert (linked_shader);
209
210 struct gl_shader_spirv_data *spirv_data = linked_shader->spirv_data;
211 assert(spirv_data);
212
213 struct gl_spirv_module *spirv_module = spirv_data->SpirVModule;
214 assert (spirv_module != NULL);
215
216 const char *entry_point_name = spirv_data->SpirVEntryPoint;
217 assert(entry_point_name);
218
219 struct nir_spirv_specialization *spec_entries =
220 calloc(sizeof(*spec_entries),
221 spirv_data->NumSpecializationConstants);
222
223 for (unsigned i = 0; i < spirv_data->NumSpecializationConstants; ++i) {
224 spec_entries[i].id = spirv_data->SpecializationConstantsIndex[i];
225 spec_entries[i].data32 = spirv_data->SpecializationConstantsValue[i];
226 spec_entries[i].defined_on_module = false;
227 }
228
229 const struct spirv_to_nir_options spirv_options = {
230 .lower_workgroup_access_to_offsets = true,
231 .caps = ctx->Const.SpirVCapabilities
232 };
233
234 nir_function *entry_point =
235 spirv_to_nir((const uint32_t *) &spirv_module->Binary[0],
236 spirv_module->Length / 4,
237 spec_entries, spirv_data->NumSpecializationConstants,
238 stage, entry_point_name,
239 &spirv_options,
240 options);
241 free(spec_entries);
242
243 assert (entry_point);
244 nir = entry_point->shader;
245 assert(nir->info.stage == stage);
246
247 nir->options = options;
248
249 nir->info.name =
250 ralloc_asprintf(nir, "SPIRV:%s:%d",
251 _mesa_shader_stage_to_abbrev(nir->info.stage),
252 prog->Name);
253 nir_validate_shader(nir);
254
255 /* We have to lower away local constant initializers right before we
256 * inline functions. That way they get properly initialized at the top
257 * of the function and not at the top of its caller.
258 */
259 NIR_PASS_V(nir, nir_lower_constant_initializers, nir_var_local);
260 NIR_PASS_V(nir, nir_lower_returns);
261 NIR_PASS_V(nir, nir_inline_functions);
262 NIR_PASS_V(nir, nir_copy_prop);
263
264 /* Pick off the single entrypoint that we want */
265 foreach_list_typed_safe(nir_function, func, node, &nir->functions) {
266 if (func != entry_point)
267 exec_node_remove(&func->node);
268 }
269 assert(exec_list_length(&nir->functions) == 1);
270 entry_point->name = ralloc_strdup(entry_point, "main");
271
272 /* Split member structs. We do this before lower_io_to_temporaries so that
273 * it doesn't lower system values to temporaries by accident.
274 */
275 NIR_PASS_V(nir, nir_split_var_copies);
276 NIR_PASS_V(nir, nir_split_per_member_structs);
277
278 if (nir->info.stage == MESA_SHADER_VERTEX) {
279 nir_compute_double_inputs(nir, options);
280 nir_remap_attributes(nir, options);
281 }
282
283 return nir;
284 }
285
286 void GLAPIENTRY
287 _mesa_SpecializeShaderARB(GLuint shader,
288 const GLchar *pEntryPoint,
289 GLuint numSpecializationConstants,
290 const GLuint *pConstantIndex,
291 const GLuint *pConstantValue)
292 {
293 GET_CURRENT_CONTEXT(ctx);
294 struct gl_shader *sh;
295 bool has_entry_point;
296 struct nir_spirv_specialization *spec_entries = NULL;
297
298 if (!ctx->Extensions.ARB_gl_spirv) {
299 _mesa_error(ctx, GL_INVALID_OPERATION, "glSpecializeShaderARB");
300 return;
301 }
302
303 sh = _mesa_lookup_shader_err(ctx, shader, "glSpecializeShaderARB");
304 if (!sh)
305 return;
306
307 if (!sh->spirv_data) {
308 _mesa_error(ctx, GL_INVALID_OPERATION,
309 "glSpecializeShaderARB(not SPIR-V)");
310 return;
311 }
312
313 if (sh->CompileStatus) {
314 _mesa_error(ctx, GL_INVALID_OPERATION,
315 "glSpecializeShaderARB(already specialized)");
316 return;
317 }
318
319 struct gl_shader_spirv_data *spirv_data = sh->spirv_data;
320
321 /* From the GL_ARB_gl_spirv spec:
322 *
323 * "The OpenGL API expects the SPIR-V module to have already been
324 * validated, and can return an error if it discovers anything invalid
325 * in the module. An invalid SPIR-V module is allowed to result in
326 * undefined behavior."
327 *
328 * However, the following errors still need to be detected (from the same
329 * spec):
330 *
331 * "INVALID_VALUE is generated if <pEntryPoint> does not name a valid
332 * entry point for <shader>.
333 *
334 * INVALID_VALUE is generated if any element of <pConstantIndex>
335 * refers to a specialization constant that does not exist in the
336 * shader module contained in <shader>."
337 *
338 * We cannot flag those errors a-priori because detecting them requires
339 * parsing the module. However, flagging them during specialization is okay,
340 * since it makes no difference in terms of application-visible state.
341 */
342 spec_entries = calloc(sizeof(*spec_entries), numSpecializationConstants);
343
344 for (unsigned i = 0; i < numSpecializationConstants; ++i) {
345 spec_entries[i].id = pConstantIndex[i];
346 spec_entries[i].data32 = pConstantValue[i];
347 spec_entries[i].defined_on_module = false;
348 }
349
350 has_entry_point =
351 gl_spirv_validation((uint32_t *)&spirv_data->SpirVModule->Binary[0],
352 spirv_data->SpirVModule->Length / 4,
353 spec_entries, numSpecializationConstants,
354 sh->Stage, pEntryPoint);
355
356 /* See previous spec comment */
357 if (!has_entry_point) {
358 _mesa_error(ctx, GL_INVALID_VALUE,
359 "glSpecializeShaderARB(\"%s\" is not a valid entry point"
360 " for shader)", pEntryPoint);
361 goto end;
362 }
363
364 for (unsigned i = 0; i < numSpecializationConstants; ++i) {
365 if (spec_entries[i].defined_on_module == false) {
366 _mesa_error(ctx, GL_INVALID_VALUE,
367 "glSpecializeShaderARB(constant \"%i\" does not exist "
368 "in shader)", spec_entries[i].id);
369 goto end;
370 }
371 }
372
373 spirv_data->SpirVEntryPoint = ralloc_strdup(spirv_data, pEntryPoint);
374
375 /* Note that we didn't make a real compilation of the module (spirv_to_nir),
376 * but just checked some error conditions. Real "compilation" will be done
377 * later, upon linking.
378 */
379 sh->CompileStatus = COMPILE_SUCCESS;
380
381 spirv_data->NumSpecializationConstants = numSpecializationConstants;
382 spirv_data->SpecializationConstantsIndex =
383 rzalloc_array_size(spirv_data, sizeof(GLuint),
384 numSpecializationConstants);
385 spirv_data->SpecializationConstantsValue =
386 rzalloc_array_size(spirv_data, sizeof(GLuint),
387 numSpecializationConstants);
388 for (unsigned i = 0; i < numSpecializationConstants; ++i) {
389 spirv_data->SpecializationConstantsIndex[i] = pConstantIndex[i];
390 spirv_data->SpecializationConstantsValue[i] = pConstantValue[i];
391 }
392
393 end:
394 free(spec_entries);
395 }