xref: /aosp_15_r20/external/mesa3d/src/compiler/spirv/gl_spirv.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © 2017 Intel Corporation
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  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * 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 NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  *
23  *
24  */
25 
26 #include "nir_spirv.h"
27 
28 #include "vtn_private.h"
29 #include "spirv_info.h"
30 
31 static bool
vtn_validate_preamble_instruction(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)32 vtn_validate_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
33                                   const uint32_t *w, unsigned count)
34 {
35    switch (opcode) {
36    case SpvOpString:
37    case SpvOpSource:
38    case SpvOpSourceExtension:
39    case SpvOpSourceContinued:
40    case SpvOpModuleProcessed:
41       /* We need this since vtn_foreach_instruction automatically handles
42        * OpLine / OpNoLine and relies on the SpvOpString from preamble being
43        * handled.
44        */
45       vtn_handle_debug_text(b, opcode, w, count);
46       break;
47 
48    case SpvOpExtension:
49    case SpvOpCapability:
50    case SpvOpExtInstImport:
51    case SpvOpMemoryModel:
52    case SpvOpName:
53    case SpvOpMemberName:
54    case SpvOpExecutionMode:
55    case SpvOpDecorationGroup:
56    case SpvOpMemberDecorate:
57    case SpvOpGroupDecorate:
58    case SpvOpGroupMemberDecorate:
59       break;
60 
61    case SpvOpEntryPoint:
62       vtn_handle_entry_point(b, w, count);
63       break;
64 
65    case SpvOpDecorate:
66       vtn_handle_decoration(b, opcode, w, count);
67       break;
68 
69    default:
70       return false; /* End of preamble */
71    }
72 
73    return true;
74 }
75 
76 static void
spec_constant_decoration_cb(struct vtn_builder * b,struct vtn_value * v,int member,const struct vtn_decoration * dec,void * data)77 spec_constant_decoration_cb(struct vtn_builder *b, struct vtn_value *v,
78                             int member, const struct vtn_decoration *dec,
79                             void *data)
80 {
81    vtn_assert(member == -1);
82    if (dec->decoration != SpvDecorationSpecId)
83       return;
84 
85    for (unsigned i = 0; i < b->num_specializations; i++) {
86       if (b->specializations[i].id == dec->operands[0]) {
87          b->specializations[i].defined_on_module = true;
88          return;
89       }
90    }
91 }
92 
93 static void
vtn_validate_handle_constant(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)94 vtn_validate_handle_constant(struct vtn_builder *b, SpvOp opcode,
95                              const uint32_t *w, unsigned count)
96 {
97    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant);
98 
99    switch (opcode) {
100    case SpvOpConstant:
101    case SpvOpConstantNull:
102    case SpvOpSpecConstantComposite:
103    case SpvOpConstantComposite:
104       /* Nothing to do here for gl_spirv needs */
105       break;
106 
107    case SpvOpConstantTrue:
108    case SpvOpConstantFalse:
109    case SpvOpSpecConstantTrue:
110    case SpvOpSpecConstantFalse:
111    case SpvOpSpecConstant:
112    case SpvOpSpecConstantOp:
113       vtn_foreach_decoration(b, val, spec_constant_decoration_cb, NULL);
114       break;
115 
116    case SpvOpConstantSampler:
117       vtn_fail("OpConstantSampler requires Kernel Capability");
118       break;
119 
120    default:
121       vtn_fail("Unhandled opcode");
122    }
123 }
124 
125 static bool
vtn_validate_handle_constant_instruction(struct vtn_builder * b,SpvOp opcode,const uint32_t * w,unsigned count)126 vtn_validate_handle_constant_instruction(struct vtn_builder *b, SpvOp opcode,
127                                          const uint32_t *w, unsigned count)
128 {
129    switch (opcode) {
130    case SpvOpSource:
131    case SpvOpSourceContinued:
132    case SpvOpSourceExtension:
133    case SpvOpExtension:
134    case SpvOpCapability:
135    case SpvOpExtInstImport:
136    case SpvOpMemoryModel:
137    case SpvOpEntryPoint:
138    case SpvOpExecutionMode:
139    case SpvOpString:
140    case SpvOpName:
141    case SpvOpMemberName:
142    case SpvOpDecorationGroup:
143    case SpvOpDecorate:
144    case SpvOpMemberDecorate:
145    case SpvOpGroupDecorate:
146    case SpvOpGroupMemberDecorate:
147       vtn_fail("Invalid opcode types and variables section");
148       break;
149 
150    case SpvOpTypeVoid:
151    case SpvOpTypeBool:
152    case SpvOpTypeInt:
153    case SpvOpTypeFloat:
154    case SpvOpTypeVector:
155    case SpvOpTypeMatrix:
156    case SpvOpTypeImage:
157    case SpvOpTypeSampler:
158    case SpvOpTypeSampledImage:
159    case SpvOpTypeArray:
160    case SpvOpTypeRuntimeArray:
161    case SpvOpTypeStruct:
162    case SpvOpTypeOpaque:
163    case SpvOpTypePointer:
164    case SpvOpTypeFunction:
165    case SpvOpTypeEvent:
166    case SpvOpTypeDeviceEvent:
167    case SpvOpTypeReserveId:
168    case SpvOpTypeQueue:
169    case SpvOpTypePipe:
170       /* We don't need to handle types */
171       break;
172 
173    case SpvOpConstantTrue:
174    case SpvOpConstantFalse:
175    case SpvOpConstant:
176    case SpvOpConstantComposite:
177    case SpvOpConstantSampler:
178    case SpvOpConstantNull:
179    case SpvOpSpecConstantTrue:
180    case SpvOpSpecConstantFalse:
181    case SpvOpSpecConstant:
182    case SpvOpSpecConstantComposite:
183    case SpvOpSpecConstantOp:
184       vtn_validate_handle_constant(b, opcode, w, count);
185       break;
186 
187    case SpvOpUndef:
188    case SpvOpVariable:
189       /* We don't need to handle them */
190       break;
191 
192    default:
193       return false; /* End of preamble */
194    }
195 
196    return true;
197 }
198 
199 /*
200  * Since OpenGL 4.6 you can use SPIR-V modules directly on OpenGL. One of the
201  * new methods, glSpecializeShader include some possible errors when trying to
202  * use it.
203  *
204  * From OpenGL 4.6, Section 7.2.1, "Shader Specialization":
205  *
206  * "void SpecializeShaderARB(uint shader,
207  *                           const char* pEntryPoint,
208  *                           uint numSpecializationConstants,
209  *                           const uint* pConstantIndex,
210  *                           const uint* pConstantValue);
211  * <skip>
212  *
213  * INVALID_VALUE is generated if <pEntryPoint> does not name a valid
214  * entry point for <shader>.
215  *
216  * An INVALID_VALUE error is generated if any element of pConstantIndex refers
217  * to a specialization constant that does not exist in the shader module
218  * contained in shader."
219  *
220  * We could do those checks on spirv_to_nir, but we are only interested on the
221  * full translation later, during linking. This method is a simplified version
222  * of spirv_to_nir, looking for only the checks needed by SpecializeShader.
223  *
224  * This method returns NULL if no entry point was found, and fill the
225  * nir_spirv_specialization field "defined_on_module" accordingly. Caller
226  * would need to trigger the specific errors.
227  *
228  */
229 enum spirv_verify_result
spirv_verify_gl_specialization_constants(const uint32_t * words,size_t word_count,struct nir_spirv_specialization * spec,unsigned num_spec,gl_shader_stage stage,const char * entry_point_name)230 spirv_verify_gl_specialization_constants(
231    const uint32_t *words, size_t word_count,
232    struct nir_spirv_specialization *spec, unsigned num_spec,
233    gl_shader_stage stage, const char *entry_point_name)
234 {
235    /* vtn_warn/vtn_log uses debug.func. Setting a null to prevent crash. Not
236     * need to print the warnings now, would be done later, on the real
237     * spirv_to_nir
238     */
239    const struct spirv_capabilities spirv_caps = { false, };
240    const struct spirv_to_nir_options options = {
241       .capabilities = &spirv_caps,
242       .debug.func = NULL,
243    };
244    const uint32_t *word_end = words + word_count;
245 
246    struct vtn_builder *b = vtn_create_builder(words, word_count,
247                                               stage, entry_point_name,
248                                               &options);
249 
250    if (b == NULL)
251       return false;
252 
253    /* See also _vtn_fail() */
254    if (vtn_setjmp(b->fail_jump)) {
255       ralloc_free(b);
256       return SPIRV_VERIFY_PARSER_ERROR;
257    }
258 
259    /* Skip the SPIR-V header, handled at vtn_create_builder */
260    words+= 5;
261 
262    /* Search entry point from preamble */
263    words = vtn_foreach_instruction(b, words, word_end,
264                                    vtn_validate_preamble_instruction);
265 
266    if (b->entry_point == NULL) {
267       ralloc_free(b);
268       return SPIRV_VERIFY_ENTRY_POINT_NOT_FOUND;
269    }
270 
271    b->specializations = spec;
272    b->num_specializations = num_spec;
273 
274    /* Handle constant instructions (we don't need to handle
275     * variables or types for gl_spirv)
276     */
277    words = vtn_foreach_instruction(b, words, word_end,
278                                    vtn_validate_handle_constant_instruction);
279 
280    ralloc_free(b);
281 
282    for (unsigned i = 0; i < num_spec; i++) {
283       if (!spec[i].defined_on_module)
284          return SPIRV_VERIFY_UNKNOWN_SPEC_INDEX;
285    }
286 
287    return SPIRV_VERIFY_OK;
288 }
289 
290