1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright 2017 Advanced Micro Devices, Inc.
3*61046927SAndroid Build Coastguard Worker *
4*61046927SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining a
5*61046927SAndroid Build Coastguard Worker * copy of this software and associated documentation files (the "Software"),
6*61046927SAndroid Build Coastguard Worker * to deal in the Software without restriction, including without limitation
7*61046927SAndroid Build Coastguard Worker * on the rights to use, copy, modify, merge, publish, distribute, sub
8*61046927SAndroid Build Coastguard Worker * license, and/or sell copies of the Software, and to permit persons to whom
9*61046927SAndroid Build Coastguard Worker * the Software is furnished to do so, subject to the following conditions:
10*61046927SAndroid Build Coastguard Worker *
11*61046927SAndroid Build Coastguard Worker * The above copyright notice and this permission notice (including the next
12*61046927SAndroid Build Coastguard Worker * paragraph) shall be included in all copies or substantial portions of the
13*61046927SAndroid Build Coastguard Worker * Software.
14*61046927SAndroid Build Coastguard Worker *
15*61046927SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*61046927SAndroid Build Coastguard Worker * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*61046927SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18*61046927SAndroid Build Coastguard Worker * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19*61046927SAndroid Build Coastguard Worker * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20*61046927SAndroid Build Coastguard Worker * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21*61046927SAndroid Build Coastguard Worker * USE OR OTHER DEALINGS IN THE SOFTWARE.
22*61046927SAndroid Build Coastguard Worker */
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #include "glspirv.h"
25*61046927SAndroid Build Coastguard Worker #include "errors.h"
26*61046927SAndroid Build Coastguard Worker #include "shaderobj.h"
27*61046927SAndroid Build Coastguard Worker #include "spirv_capabilities.h"
28*61046927SAndroid Build Coastguard Worker #include "mtypes.h"
29*61046927SAndroid Build Coastguard Worker
30*61046927SAndroid Build Coastguard Worker #include "compiler/nir/nir.h"
31*61046927SAndroid Build Coastguard Worker #include "compiler/spirv/nir_spirv.h"
32*61046927SAndroid Build Coastguard Worker #include "compiler/spirv/spirv_info.h"
33*61046927SAndroid Build Coastguard Worker
34*61046927SAndroid Build Coastguard Worker #include "program/program.h"
35*61046927SAndroid Build Coastguard Worker
36*61046927SAndroid Build Coastguard Worker #include "util/u_atomic.h"
37*61046927SAndroid Build Coastguard Worker #include "api_exec_decl.h"
38*61046927SAndroid Build Coastguard Worker
39*61046927SAndroid Build Coastguard Worker void
_mesa_spirv_module_reference(struct gl_spirv_module ** dest,struct gl_spirv_module * src)40*61046927SAndroid Build Coastguard Worker _mesa_spirv_module_reference(struct gl_spirv_module **dest,
41*61046927SAndroid Build Coastguard Worker struct gl_spirv_module *src)
42*61046927SAndroid Build Coastguard Worker {
43*61046927SAndroid Build Coastguard Worker struct gl_spirv_module *old = *dest;
44*61046927SAndroid Build Coastguard Worker
45*61046927SAndroid Build Coastguard Worker if (old && p_atomic_dec_zero(&old->RefCount))
46*61046927SAndroid Build Coastguard Worker free(old);
47*61046927SAndroid Build Coastguard Worker
48*61046927SAndroid Build Coastguard Worker *dest = src;
49*61046927SAndroid Build Coastguard Worker
50*61046927SAndroid Build Coastguard Worker if (src)
51*61046927SAndroid Build Coastguard Worker p_atomic_inc(&src->RefCount);
52*61046927SAndroid Build Coastguard Worker }
53*61046927SAndroid Build Coastguard Worker
54*61046927SAndroid Build Coastguard Worker void
_mesa_shader_spirv_data_reference(struct gl_shader_spirv_data ** dest,struct gl_shader_spirv_data * src)55*61046927SAndroid Build Coastguard Worker _mesa_shader_spirv_data_reference(struct gl_shader_spirv_data **dest,
56*61046927SAndroid Build Coastguard Worker struct gl_shader_spirv_data *src)
57*61046927SAndroid Build Coastguard Worker {
58*61046927SAndroid Build Coastguard Worker struct gl_shader_spirv_data *old = *dest;
59*61046927SAndroid Build Coastguard Worker
60*61046927SAndroid Build Coastguard Worker if (old && p_atomic_dec_zero(&old->RefCount)) {
61*61046927SAndroid Build Coastguard Worker _mesa_spirv_module_reference(&(*dest)->SpirVModule, NULL);
62*61046927SAndroid Build Coastguard Worker ralloc_free(old);
63*61046927SAndroid Build Coastguard Worker }
64*61046927SAndroid Build Coastguard Worker
65*61046927SAndroid Build Coastguard Worker *dest = src;
66*61046927SAndroid Build Coastguard Worker
67*61046927SAndroid Build Coastguard Worker if (src)
68*61046927SAndroid Build Coastguard Worker p_atomic_inc(&src->RefCount);
69*61046927SAndroid Build Coastguard Worker }
70*61046927SAndroid Build Coastguard Worker
71*61046927SAndroid Build Coastguard Worker void
_mesa_spirv_shader_binary(struct gl_context * ctx,unsigned n,struct gl_shader ** shaders,const void * binary,size_t length)72*61046927SAndroid Build Coastguard Worker _mesa_spirv_shader_binary(struct gl_context *ctx,
73*61046927SAndroid Build Coastguard Worker unsigned n, struct gl_shader **shaders,
74*61046927SAndroid Build Coastguard Worker const void* binary, size_t length)
75*61046927SAndroid Build Coastguard Worker {
76*61046927SAndroid Build Coastguard Worker struct gl_spirv_module *module;
77*61046927SAndroid Build Coastguard Worker struct gl_shader_spirv_data *spirv_data;
78*61046927SAndroid Build Coastguard Worker
79*61046927SAndroid Build Coastguard Worker /* From OpenGL 4.6 Core spec, "7.2 Shader Binaries" :
80*61046927SAndroid Build Coastguard Worker *
81*61046927SAndroid Build Coastguard Worker * "An INVALID_VALUE error is generated if the data pointed to by binary
82*61046927SAndroid Build Coastguard Worker * does not match the specified binaryformat."
83*61046927SAndroid Build Coastguard Worker *
84*61046927SAndroid Build Coastguard Worker * However, the ARB_gl_spirv spec, under issue #16 says:
85*61046927SAndroid Build Coastguard Worker *
86*61046927SAndroid Build Coastguard Worker * "ShaderBinary is expected to form an association between the SPIR-V
87*61046927SAndroid Build Coastguard Worker * module and likely would not parse the module as would be required to
88*61046927SAndroid Build Coastguard Worker * detect unsupported capabilities or other validation failures."
89*61046927SAndroid Build Coastguard Worker *
90*61046927SAndroid Build Coastguard Worker * Which specifies little to no validation requirements. Nevertheless, the
91*61046927SAndroid Build Coastguard Worker * two small checks below seem reasonable.
92*61046927SAndroid Build Coastguard Worker */
93*61046927SAndroid Build Coastguard Worker if (!binary || (length % 4) != 0) {
94*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_VALUE, "glShaderBinary");
95*61046927SAndroid Build Coastguard Worker return;
96*61046927SAndroid Build Coastguard Worker }
97*61046927SAndroid Build Coastguard Worker
98*61046927SAndroid Build Coastguard Worker module = malloc(sizeof(*module) + length);
99*61046927SAndroid Build Coastguard Worker if (!module) {
100*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderBinary");
101*61046927SAndroid Build Coastguard Worker return;
102*61046927SAndroid Build Coastguard Worker }
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker p_atomic_set(&module->RefCount, 0);
105*61046927SAndroid Build Coastguard Worker module->Length = length;
106*61046927SAndroid Build Coastguard Worker memcpy(&module->Binary[0], binary, length);
107*61046927SAndroid Build Coastguard Worker
108*61046927SAndroid Build Coastguard Worker for (int i = 0; i < n; ++i) {
109*61046927SAndroid Build Coastguard Worker struct gl_shader *sh = shaders[i];
110*61046927SAndroid Build Coastguard Worker
111*61046927SAndroid Build Coastguard Worker spirv_data = rzalloc(NULL, struct gl_shader_spirv_data);
112*61046927SAndroid Build Coastguard Worker _mesa_shader_spirv_data_reference(&sh->spirv_data, spirv_data);
113*61046927SAndroid Build Coastguard Worker _mesa_spirv_module_reference(&spirv_data->SpirVModule, module);
114*61046927SAndroid Build Coastguard Worker
115*61046927SAndroid Build Coastguard Worker sh->CompileStatus = COMPILE_FAILURE;
116*61046927SAndroid Build Coastguard Worker
117*61046927SAndroid Build Coastguard Worker free((void *)sh->Source);
118*61046927SAndroid Build Coastguard Worker sh->Source = NULL;
119*61046927SAndroid Build Coastguard Worker free((void *)sh->FallbackSource);
120*61046927SAndroid Build Coastguard Worker sh->FallbackSource = NULL;
121*61046927SAndroid Build Coastguard Worker
122*61046927SAndroid Build Coastguard Worker ralloc_free(sh->ir);
123*61046927SAndroid Build Coastguard Worker sh->ir = NULL;
124*61046927SAndroid Build Coastguard Worker ralloc_free(sh->symbols);
125*61046927SAndroid Build Coastguard Worker sh->symbols = NULL;
126*61046927SAndroid Build Coastguard Worker }
127*61046927SAndroid Build Coastguard Worker }
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker /**
130*61046927SAndroid Build Coastguard Worker * This is the equivalent to compiler/glsl/linker.cpp::link_shaders()
131*61046927SAndroid Build Coastguard Worker * but for SPIR-V programs.
132*61046927SAndroid Build Coastguard Worker *
133*61046927SAndroid Build Coastguard Worker * This method just creates the gl_linked_shader structs with a reference to
134*61046927SAndroid Build Coastguard Worker * the SPIR-V data collected during previous steps.
135*61046927SAndroid Build Coastguard Worker *
136*61046927SAndroid Build Coastguard Worker * The real linking happens later in the driver-specifc call LinkShader().
137*61046927SAndroid Build Coastguard Worker * This is so backends can implement different linking strategies for
138*61046927SAndroid Build Coastguard Worker * SPIR-V programs.
139*61046927SAndroid Build Coastguard Worker */
140*61046927SAndroid Build Coastguard Worker void
_mesa_spirv_link_shaders(struct gl_context * ctx,struct gl_shader_program * prog)141*61046927SAndroid Build Coastguard Worker _mesa_spirv_link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
142*61046927SAndroid Build Coastguard Worker {
143*61046927SAndroid Build Coastguard Worker prog->data->LinkStatus = LINKING_SUCCESS;
144*61046927SAndroid Build Coastguard Worker prog->data->Validated = false;
145*61046927SAndroid Build Coastguard Worker
146*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < prog->NumShaders; i++) {
147*61046927SAndroid Build Coastguard Worker struct gl_shader *shader = prog->Shaders[i];
148*61046927SAndroid Build Coastguard Worker gl_shader_stage shader_type = shader->Stage;
149*61046927SAndroid Build Coastguard Worker
150*61046927SAndroid Build Coastguard Worker /* We only support one shader per stage. The gl_spirv spec doesn't seem
151*61046927SAndroid Build Coastguard Worker * to prevent this, but the way the API is designed, requiring all shaders
152*61046927SAndroid Build Coastguard Worker * to be specialized with an entry point, makes supporting this quite
153*61046927SAndroid Build Coastguard Worker * undefined.
154*61046927SAndroid Build Coastguard Worker *
155*61046927SAndroid Build Coastguard Worker * TODO: Turn this into a proper error once the spec bug
156*61046927SAndroid Build Coastguard Worker * <https://gitlab.khronos.org/opengl/API/issues/58> is resolved.
157*61046927SAndroid Build Coastguard Worker */
158*61046927SAndroid Build Coastguard Worker if (prog->_LinkedShaders[shader_type]) {
159*61046927SAndroid Build Coastguard Worker ralloc_strcat(&prog->data->InfoLog,
160*61046927SAndroid Build Coastguard Worker "\nError trying to link more than one SPIR-V shader "
161*61046927SAndroid Build Coastguard Worker "per stage.\n");
162*61046927SAndroid Build Coastguard Worker prog->data->LinkStatus = LINKING_FAILURE;
163*61046927SAndroid Build Coastguard Worker return;
164*61046927SAndroid Build Coastguard Worker }
165*61046927SAndroid Build Coastguard Worker
166*61046927SAndroid Build Coastguard Worker assert(shader->spirv_data);
167*61046927SAndroid Build Coastguard Worker
168*61046927SAndroid Build Coastguard Worker struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader);
169*61046927SAndroid Build Coastguard Worker linked->Stage = shader_type;
170*61046927SAndroid Build Coastguard Worker
171*61046927SAndroid Build Coastguard Worker /* Create program and attach it to the linked shader */
172*61046927SAndroid Build Coastguard Worker struct gl_program *gl_prog =
173*61046927SAndroid Build Coastguard Worker ctx->Driver.NewProgram(ctx, shader_type, prog->Name, false);
174*61046927SAndroid Build Coastguard Worker if (!gl_prog) {
175*61046927SAndroid Build Coastguard Worker prog->data->LinkStatus = LINKING_FAILURE;
176*61046927SAndroid Build Coastguard Worker _mesa_delete_linked_shader(ctx, linked);
177*61046927SAndroid Build Coastguard Worker return;
178*61046927SAndroid Build Coastguard Worker }
179*61046927SAndroid Build Coastguard Worker
180*61046927SAndroid Build Coastguard Worker _mesa_reference_shader_program_data(&gl_prog->sh.data,
181*61046927SAndroid Build Coastguard Worker prog->data);
182*61046927SAndroid Build Coastguard Worker
183*61046927SAndroid Build Coastguard Worker /* Don't use _mesa_reference_program() just take ownership */
184*61046927SAndroid Build Coastguard Worker linked->Program = gl_prog;
185*61046927SAndroid Build Coastguard Worker
186*61046927SAndroid Build Coastguard Worker /* Reference the SPIR-V data from shader to the linked shader */
187*61046927SAndroid Build Coastguard Worker _mesa_shader_spirv_data_reference(&linked->spirv_data,
188*61046927SAndroid Build Coastguard Worker shader->spirv_data);
189*61046927SAndroid Build Coastguard Worker
190*61046927SAndroid Build Coastguard Worker prog->_LinkedShaders[shader_type] = linked;
191*61046927SAndroid Build Coastguard Worker prog->data->linked_stages |= 1 << shader_type;
192*61046927SAndroid Build Coastguard Worker }
193*61046927SAndroid Build Coastguard Worker
194*61046927SAndroid Build Coastguard Worker int last_vert_stage =
195*61046927SAndroid Build Coastguard Worker util_last_bit(prog->data->linked_stages &
196*61046927SAndroid Build Coastguard Worker ((1 << (MESA_SHADER_GEOMETRY + 1)) - 1));
197*61046927SAndroid Build Coastguard Worker
198*61046927SAndroid Build Coastguard Worker if (last_vert_stage)
199*61046927SAndroid Build Coastguard Worker prog->last_vert_prog = prog->_LinkedShaders[last_vert_stage - 1]->Program;
200*61046927SAndroid Build Coastguard Worker
201*61046927SAndroid Build Coastguard Worker /* Some shaders have to be linked with some other shaders present. */
202*61046927SAndroid Build Coastguard Worker if (!prog->SeparateShader) {
203*61046927SAndroid Build Coastguard Worker static const struct {
204*61046927SAndroid Build Coastguard Worker gl_shader_stage a, b;
205*61046927SAndroid Build Coastguard Worker } stage_pairs[] = {
206*61046927SAndroid Build Coastguard Worker { MESA_SHADER_GEOMETRY, MESA_SHADER_VERTEX },
207*61046927SAndroid Build Coastguard Worker { MESA_SHADER_TESS_EVAL, MESA_SHADER_VERTEX },
208*61046927SAndroid Build Coastguard Worker { MESA_SHADER_TESS_CTRL, MESA_SHADER_VERTEX },
209*61046927SAndroid Build Coastguard Worker { MESA_SHADER_TESS_CTRL, MESA_SHADER_TESS_EVAL },
210*61046927SAndroid Build Coastguard Worker };
211*61046927SAndroid Build Coastguard Worker
212*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < ARRAY_SIZE(stage_pairs); i++) {
213*61046927SAndroid Build Coastguard Worker gl_shader_stage a = stage_pairs[i].a;
214*61046927SAndroid Build Coastguard Worker gl_shader_stage b = stage_pairs[i].b;
215*61046927SAndroid Build Coastguard Worker if ((prog->data->linked_stages & ((1 << a) | (1 << b))) == (1 << a)) {
216*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&prog->data->InfoLog,
217*61046927SAndroid Build Coastguard Worker "%s shader must be linked with %s shader\n",
218*61046927SAndroid Build Coastguard Worker _mesa_shader_stage_to_string(a),
219*61046927SAndroid Build Coastguard Worker _mesa_shader_stage_to_string(b));
220*61046927SAndroid Build Coastguard Worker prog->data->LinkStatus = LINKING_FAILURE;
221*61046927SAndroid Build Coastguard Worker return;
222*61046927SAndroid Build Coastguard Worker }
223*61046927SAndroid Build Coastguard Worker }
224*61046927SAndroid Build Coastguard Worker }
225*61046927SAndroid Build Coastguard Worker
226*61046927SAndroid Build Coastguard Worker /* Compute shaders have additional restrictions. */
227*61046927SAndroid Build Coastguard Worker if ((prog->data->linked_stages & (1 << MESA_SHADER_COMPUTE)) &&
228*61046927SAndroid Build Coastguard Worker (prog->data->linked_stages & ~(1 << MESA_SHADER_COMPUTE))) {
229*61046927SAndroid Build Coastguard Worker ralloc_asprintf_append(&prog->data->InfoLog,
230*61046927SAndroid Build Coastguard Worker "Compute shaders may not be linked with any other "
231*61046927SAndroid Build Coastguard Worker "type of shader\n");
232*61046927SAndroid Build Coastguard Worker prog->data->LinkStatus = LINKING_FAILURE;
233*61046927SAndroid Build Coastguard Worker return;
234*61046927SAndroid Build Coastguard Worker }
235*61046927SAndroid Build Coastguard Worker }
236*61046927SAndroid Build Coastguard Worker
237*61046927SAndroid Build Coastguard Worker 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)238*61046927SAndroid Build Coastguard Worker _mesa_spirv_to_nir(struct gl_context *ctx,
239*61046927SAndroid Build Coastguard Worker const struct gl_shader_program *prog,
240*61046927SAndroid Build Coastguard Worker gl_shader_stage stage,
241*61046927SAndroid Build Coastguard Worker const nir_shader_compiler_options *options)
242*61046927SAndroid Build Coastguard Worker {
243*61046927SAndroid Build Coastguard Worker struct gl_linked_shader *linked_shader = prog->_LinkedShaders[stage];
244*61046927SAndroid Build Coastguard Worker assert (linked_shader);
245*61046927SAndroid Build Coastguard Worker
246*61046927SAndroid Build Coastguard Worker struct gl_shader_spirv_data *spirv_data = linked_shader->spirv_data;
247*61046927SAndroid Build Coastguard Worker assert(spirv_data);
248*61046927SAndroid Build Coastguard Worker
249*61046927SAndroid Build Coastguard Worker struct gl_spirv_module *spirv_module = spirv_data->SpirVModule;
250*61046927SAndroid Build Coastguard Worker assert (spirv_module != NULL);
251*61046927SAndroid Build Coastguard Worker
252*61046927SAndroid Build Coastguard Worker const char *entry_point_name = spirv_data->SpirVEntryPoint;
253*61046927SAndroid Build Coastguard Worker assert(entry_point_name);
254*61046927SAndroid Build Coastguard Worker
255*61046927SAndroid Build Coastguard Worker struct nir_spirv_specialization *spec_entries =
256*61046927SAndroid Build Coastguard Worker calloc(sizeof(*spec_entries),
257*61046927SAndroid Build Coastguard Worker spirv_data->NumSpecializationConstants);
258*61046927SAndroid Build Coastguard Worker
259*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < spirv_data->NumSpecializationConstants; ++i) {
260*61046927SAndroid Build Coastguard Worker spec_entries[i].id = spirv_data->SpecializationConstantsIndex[i];
261*61046927SAndroid Build Coastguard Worker spec_entries[i].value.u32 = spirv_data->SpecializationConstantsValue[i];
262*61046927SAndroid Build Coastguard Worker spec_entries[i].defined_on_module = false;
263*61046927SAndroid Build Coastguard Worker }
264*61046927SAndroid Build Coastguard Worker
265*61046927SAndroid Build Coastguard Worker struct spirv_capabilities spirv_caps;
266*61046927SAndroid Build Coastguard Worker _mesa_fill_supported_spirv_capabilities(&spirv_caps, &ctx->Const,
267*61046927SAndroid Build Coastguard Worker &ctx->Extensions);
268*61046927SAndroid Build Coastguard Worker
269*61046927SAndroid Build Coastguard Worker struct spirv_to_nir_options spirv_options = {
270*61046927SAndroid Build Coastguard Worker .environment = NIR_SPIRV_OPENGL,
271*61046927SAndroid Build Coastguard Worker .capabilities = &spirv_caps,
272*61046927SAndroid Build Coastguard Worker .subgroup_size = SUBGROUP_SIZE_UNIFORM,
273*61046927SAndroid Build Coastguard Worker .ubo_addr_format = nir_address_format_32bit_index_offset,
274*61046927SAndroid Build Coastguard Worker .ssbo_addr_format = nir_address_format_32bit_index_offset,
275*61046927SAndroid Build Coastguard Worker
276*61046927SAndroid Build Coastguard Worker /* TODO: Consider changing this to an address format that has the NULL
277*61046927SAndroid Build Coastguard Worker * pointer equals to 0. That might be a better format to play nice
278*61046927SAndroid Build Coastguard Worker * with certain code / code generators.
279*61046927SAndroid Build Coastguard Worker */
280*61046927SAndroid Build Coastguard Worker .shared_addr_format = nir_address_format_32bit_offset,
281*61046927SAndroid Build Coastguard Worker
282*61046927SAndroid Build Coastguard Worker };
283*61046927SAndroid Build Coastguard Worker
284*61046927SAndroid Build Coastguard Worker nir_shader *nir =
285*61046927SAndroid Build Coastguard Worker spirv_to_nir((const uint32_t *) &spirv_module->Binary[0],
286*61046927SAndroid Build Coastguard Worker spirv_module->Length / 4,
287*61046927SAndroid Build Coastguard Worker spec_entries, spirv_data->NumSpecializationConstants,
288*61046927SAndroid Build Coastguard Worker stage, entry_point_name,
289*61046927SAndroid Build Coastguard Worker &spirv_options,
290*61046927SAndroid Build Coastguard Worker options);
291*61046927SAndroid Build Coastguard Worker free(spec_entries);
292*61046927SAndroid Build Coastguard Worker
293*61046927SAndroid Build Coastguard Worker assert(nir);
294*61046927SAndroid Build Coastguard Worker assert(nir->info.stage == stage);
295*61046927SAndroid Build Coastguard Worker
296*61046927SAndroid Build Coastguard Worker nir->options = options;
297*61046927SAndroid Build Coastguard Worker
298*61046927SAndroid Build Coastguard Worker nir->info.name =
299*61046927SAndroid Build Coastguard Worker ralloc_asprintf(nir, "SPIRV:%s:%d",
300*61046927SAndroid Build Coastguard Worker _mesa_shader_stage_to_abbrev(nir->info.stage),
301*61046927SAndroid Build Coastguard Worker prog->Name);
302*61046927SAndroid Build Coastguard Worker nir_validate_shader(nir, "after spirv_to_nir");
303*61046927SAndroid Build Coastguard Worker
304*61046927SAndroid Build Coastguard Worker nir->info.separate_shader = linked_shader->Program->info.separate_shader;
305*61046927SAndroid Build Coastguard Worker
306*61046927SAndroid Build Coastguard Worker /* Convert some sysvals to input varyings. */
307*61046927SAndroid Build Coastguard Worker const struct nir_lower_sysvals_to_varyings_options sysvals_to_varyings = {
308*61046927SAndroid Build Coastguard Worker .frag_coord = !ctx->Const.GLSLFragCoordIsSysVal,
309*61046927SAndroid Build Coastguard Worker .point_coord = !ctx->Const.GLSLPointCoordIsSysVal,
310*61046927SAndroid Build Coastguard Worker .front_face = !ctx->Const.GLSLFrontFacingIsSysVal,
311*61046927SAndroid Build Coastguard Worker };
312*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_sysvals_to_varyings, &sysvals_to_varyings);
313*61046927SAndroid Build Coastguard Worker
314*61046927SAndroid Build Coastguard Worker /* We have to lower away local constant initializers right before we
315*61046927SAndroid Build Coastguard Worker * inline functions. That way they get properly initialized at the top
316*61046927SAndroid Build Coastguard Worker * of the function and not at the top of its caller.
317*61046927SAndroid Build Coastguard Worker */
318*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_variable_initializers, nir_var_function_temp);
319*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_returns);
320*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_inline_functions);
321*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_copy_prop);
322*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_opt_deref);
323*61046927SAndroid Build Coastguard Worker
324*61046927SAndroid Build Coastguard Worker /* Pick off the single entrypoint that we want */
325*61046927SAndroid Build Coastguard Worker nir_remove_non_entrypoints(nir);
326*61046927SAndroid Build Coastguard Worker
327*61046927SAndroid Build Coastguard Worker /* Now that we've deleted all but the main function, we can go ahead and
328*61046927SAndroid Build Coastguard Worker * lower the rest of the constant initializers. We do this here so that
329*61046927SAndroid Build Coastguard Worker * nir_remove_dead_variables and split_per_member_structs below see the
330*61046927SAndroid Build Coastguard Worker * corresponding stores.
331*61046927SAndroid Build Coastguard Worker */
332*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_variable_initializers, ~0);
333*61046927SAndroid Build Coastguard Worker
334*61046927SAndroid Build Coastguard Worker /* Split member structs. We do this before lower_io_to_temporaries so that
335*61046927SAndroid Build Coastguard Worker * it doesn't lower system values to temporaries by accident.
336*61046927SAndroid Build Coastguard Worker */
337*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_split_var_copies);
338*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_split_per_member_structs);
339*61046927SAndroid Build Coastguard Worker
340*61046927SAndroid Build Coastguard Worker if (nir->info.stage == MESA_SHADER_VERTEX &&
341*61046927SAndroid Build Coastguard Worker (!(nir->options->io_options & nir_io_glsl_lower_derefs) ||
342*61046927SAndroid Build Coastguard Worker !(nir->options->io_options & nir_io_glsl_opt_varyings)))
343*61046927SAndroid Build Coastguard Worker nir_remap_dual_slot_attributes(nir, &linked_shader->Program->DualSlotInputs);
344*61046927SAndroid Build Coastguard Worker
345*61046927SAndroid Build Coastguard Worker NIR_PASS(_, nir, nir_lower_frexp);
346*61046927SAndroid Build Coastguard Worker
347*61046927SAndroid Build Coastguard Worker return nir;
348*61046927SAndroid Build Coastguard Worker }
349*61046927SAndroid Build Coastguard Worker
350*61046927SAndroid Build Coastguard Worker void GLAPIENTRY
_mesa_SpecializeShaderARB(GLuint shader,const GLchar * pEntryPoint,GLuint numSpecializationConstants,const GLuint * pConstantIndex,const GLuint * pConstantValue)351*61046927SAndroid Build Coastguard Worker _mesa_SpecializeShaderARB(GLuint shader,
352*61046927SAndroid Build Coastguard Worker const GLchar *pEntryPoint,
353*61046927SAndroid Build Coastguard Worker GLuint numSpecializationConstants,
354*61046927SAndroid Build Coastguard Worker const GLuint *pConstantIndex,
355*61046927SAndroid Build Coastguard Worker const GLuint *pConstantValue)
356*61046927SAndroid Build Coastguard Worker {
357*61046927SAndroid Build Coastguard Worker GET_CURRENT_CONTEXT(ctx);
358*61046927SAndroid Build Coastguard Worker struct gl_shader *sh;
359*61046927SAndroid Build Coastguard Worker struct nir_spirv_specialization *spec_entries = NULL;
360*61046927SAndroid Build Coastguard Worker
361*61046927SAndroid Build Coastguard Worker if (!ctx->Extensions.ARB_gl_spirv) {
362*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION, "glSpecializeShaderARB");
363*61046927SAndroid Build Coastguard Worker return;
364*61046927SAndroid Build Coastguard Worker }
365*61046927SAndroid Build Coastguard Worker
366*61046927SAndroid Build Coastguard Worker sh = _mesa_lookup_shader_err(ctx, shader, "glSpecializeShaderARB");
367*61046927SAndroid Build Coastguard Worker if (!sh)
368*61046927SAndroid Build Coastguard Worker return;
369*61046927SAndroid Build Coastguard Worker
370*61046927SAndroid Build Coastguard Worker if (!sh->spirv_data) {
371*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION,
372*61046927SAndroid Build Coastguard Worker "glSpecializeShaderARB(not SPIR-V)");
373*61046927SAndroid Build Coastguard Worker return;
374*61046927SAndroid Build Coastguard Worker }
375*61046927SAndroid Build Coastguard Worker
376*61046927SAndroid Build Coastguard Worker if (sh->CompileStatus) {
377*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_OPERATION,
378*61046927SAndroid Build Coastguard Worker "glSpecializeShaderARB(already specialized)");
379*61046927SAndroid Build Coastguard Worker return;
380*61046927SAndroid Build Coastguard Worker }
381*61046927SAndroid Build Coastguard Worker
382*61046927SAndroid Build Coastguard Worker struct gl_shader_spirv_data *spirv_data = sh->spirv_data;
383*61046927SAndroid Build Coastguard Worker
384*61046927SAndroid Build Coastguard Worker /* From the GL_ARB_gl_spirv spec:
385*61046927SAndroid Build Coastguard Worker *
386*61046927SAndroid Build Coastguard Worker * "The OpenGL API expects the SPIR-V module to have already been
387*61046927SAndroid Build Coastguard Worker * validated, and can return an error if it discovers anything invalid
388*61046927SAndroid Build Coastguard Worker * in the module. An invalid SPIR-V module is allowed to result in
389*61046927SAndroid Build Coastguard Worker * undefined behavior."
390*61046927SAndroid Build Coastguard Worker *
391*61046927SAndroid Build Coastguard Worker * However, the following errors still need to be detected (from the same
392*61046927SAndroid Build Coastguard Worker * spec):
393*61046927SAndroid Build Coastguard Worker *
394*61046927SAndroid Build Coastguard Worker * "INVALID_VALUE is generated if <pEntryPoint> does not name a valid
395*61046927SAndroid Build Coastguard Worker * entry point for <shader>.
396*61046927SAndroid Build Coastguard Worker *
397*61046927SAndroid Build Coastguard Worker * INVALID_VALUE is generated if any element of <pConstantIndex>
398*61046927SAndroid Build Coastguard Worker * refers to a specialization constant that does not exist in the
399*61046927SAndroid Build Coastguard Worker * shader module contained in <shader>."
400*61046927SAndroid Build Coastguard Worker *
401*61046927SAndroid Build Coastguard Worker * We cannot flag those errors a-priori because detecting them requires
402*61046927SAndroid Build Coastguard Worker * parsing the module. However, flagging them during specialization is okay,
403*61046927SAndroid Build Coastguard Worker * since it makes no difference in terms of application-visible state.
404*61046927SAndroid Build Coastguard Worker */
405*61046927SAndroid Build Coastguard Worker spec_entries = calloc(sizeof(*spec_entries), numSpecializationConstants);
406*61046927SAndroid Build Coastguard Worker
407*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < numSpecializationConstants; ++i) {
408*61046927SAndroid Build Coastguard Worker spec_entries[i].id = pConstantIndex[i];
409*61046927SAndroid Build Coastguard Worker spec_entries[i].value.u32 = pConstantValue[i];
410*61046927SAndroid Build Coastguard Worker spec_entries[i].defined_on_module = false;
411*61046927SAndroid Build Coastguard Worker }
412*61046927SAndroid Build Coastguard Worker
413*61046927SAndroid Build Coastguard Worker enum spirv_verify_result r = spirv_verify_gl_specialization_constants(
414*61046927SAndroid Build Coastguard Worker (uint32_t *)&spirv_data->SpirVModule->Binary[0],
415*61046927SAndroid Build Coastguard Worker spirv_data->SpirVModule->Length / 4,
416*61046927SAndroid Build Coastguard Worker spec_entries, numSpecializationConstants,
417*61046927SAndroid Build Coastguard Worker sh->Stage, pEntryPoint);
418*61046927SAndroid Build Coastguard Worker
419*61046927SAndroid Build Coastguard Worker switch (r) {
420*61046927SAndroid Build Coastguard Worker case SPIRV_VERIFY_OK:
421*61046927SAndroid Build Coastguard Worker break;
422*61046927SAndroid Build Coastguard Worker case SPIRV_VERIFY_PARSER_ERROR:
423*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_VALUE,
424*61046927SAndroid Build Coastguard Worker "glSpecializeShaderARB(failed to parse entry point \"%s\""
425*61046927SAndroid Build Coastguard Worker " for shader)", pEntryPoint);
426*61046927SAndroid Build Coastguard Worker goto end;
427*61046927SAndroid Build Coastguard Worker case SPIRV_VERIFY_ENTRY_POINT_NOT_FOUND:
428*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_VALUE,
429*61046927SAndroid Build Coastguard Worker "glSpecializeShaderARB(could not find entry point \"%s\""
430*61046927SAndroid Build Coastguard Worker " for shader)", pEntryPoint);
431*61046927SAndroid Build Coastguard Worker goto end;
432*61046927SAndroid Build Coastguard Worker case SPIRV_VERIFY_UNKNOWN_SPEC_INDEX:
433*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < numSpecializationConstants; ++i) {
434*61046927SAndroid Build Coastguard Worker if (spec_entries[i].defined_on_module == false) {
435*61046927SAndroid Build Coastguard Worker _mesa_error(ctx, GL_INVALID_VALUE,
436*61046927SAndroid Build Coastguard Worker "glSpecializeShaderARB(constant \"%i\" does not exist "
437*61046927SAndroid Build Coastguard Worker "in shader)", spec_entries[i].id);
438*61046927SAndroid Build Coastguard Worker break;
439*61046927SAndroid Build Coastguard Worker }
440*61046927SAndroid Build Coastguard Worker }
441*61046927SAndroid Build Coastguard Worker goto end;
442*61046927SAndroid Build Coastguard Worker }
443*61046927SAndroid Build Coastguard Worker
444*61046927SAndroid Build Coastguard Worker spirv_data->SpirVEntryPoint = ralloc_strdup(spirv_data, pEntryPoint);
445*61046927SAndroid Build Coastguard Worker
446*61046927SAndroid Build Coastguard Worker /* Note that we didn't make a real compilation of the module (spirv_to_nir),
447*61046927SAndroid Build Coastguard Worker * but just checked some error conditions. Real "compilation" will be done
448*61046927SAndroid Build Coastguard Worker * later, upon linking.
449*61046927SAndroid Build Coastguard Worker */
450*61046927SAndroid Build Coastguard Worker sh->CompileStatus = COMPILE_SUCCESS;
451*61046927SAndroid Build Coastguard Worker
452*61046927SAndroid Build Coastguard Worker spirv_data->NumSpecializationConstants = numSpecializationConstants;
453*61046927SAndroid Build Coastguard Worker spirv_data->SpecializationConstantsIndex =
454*61046927SAndroid Build Coastguard Worker rzalloc_array_size(spirv_data, sizeof(GLuint),
455*61046927SAndroid Build Coastguard Worker numSpecializationConstants);
456*61046927SAndroid Build Coastguard Worker spirv_data->SpecializationConstantsValue =
457*61046927SAndroid Build Coastguard Worker rzalloc_array_size(spirv_data, sizeof(GLuint),
458*61046927SAndroid Build Coastguard Worker numSpecializationConstants);
459*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < numSpecializationConstants; ++i) {
460*61046927SAndroid Build Coastguard Worker spirv_data->SpecializationConstantsIndex[i] = pConstantIndex[i];
461*61046927SAndroid Build Coastguard Worker spirv_data->SpecializationConstantsValue[i] = pConstantValue[i];
462*61046927SAndroid Build Coastguard Worker }
463*61046927SAndroid Build Coastguard Worker
464*61046927SAndroid Build Coastguard Worker end:
465*61046927SAndroid Build Coastguard Worker free(spec_entries);
466*61046927SAndroid Build Coastguard Worker }
467