Path: blob/21.2-virgl/src/compiler/spirv/gl_spirv.c
4545 views
/*1* Copyright © 2017 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*22*23*/2425#include "nir_spirv.h"2627#include "vtn_private.h"28#include "spirv_info.h"2930static bool31vtn_validate_preamble_instruction(struct vtn_builder *b, SpvOp opcode,32const uint32_t *w, unsigned count)33{34switch (opcode) {35case SpvOpSource:36case SpvOpSourceExtension:37case SpvOpSourceContinued:38case SpvOpExtension:39case SpvOpCapability:40case SpvOpExtInstImport:41case SpvOpMemoryModel:42case SpvOpString:43case SpvOpName:44case SpvOpMemberName:45case SpvOpExecutionMode:46case SpvOpDecorationGroup:47case SpvOpMemberDecorate:48case SpvOpGroupDecorate:49case SpvOpGroupMemberDecorate:50break;5152case SpvOpEntryPoint:53vtn_handle_entry_point(b, w, count);54break;5556case SpvOpDecorate:57vtn_handle_decoration(b, opcode, w, count);58break;5960default:61return false; /* End of preamble */62}6364return true;65}6667static void68spec_constant_decoration_cb(struct vtn_builder *b, struct vtn_value *v,69int member, const struct vtn_decoration *dec,70void *data)71{72vtn_assert(member == -1);73if (dec->decoration != SpvDecorationSpecId)74return;7576for (unsigned i = 0; i < b->num_specializations; i++) {77if (b->specializations[i].id == dec->operands[0]) {78b->specializations[i].defined_on_module = true;79return;80}81}82}8384static void85vtn_validate_handle_constant(struct vtn_builder *b, SpvOp opcode,86const uint32_t *w, unsigned count)87{88struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant);8990switch (opcode) {91case SpvOpConstant:92case SpvOpConstantNull:93case SpvOpSpecConstantComposite:94case SpvOpConstantComposite:95/* Nothing to do here for gl_spirv needs */96break;9798case SpvOpConstantTrue:99case SpvOpConstantFalse:100case SpvOpSpecConstantTrue:101case SpvOpSpecConstantFalse:102case SpvOpSpecConstant:103case SpvOpSpecConstantOp:104vtn_foreach_decoration(b, val, spec_constant_decoration_cb, NULL);105break;106107case SpvOpConstantSampler:108vtn_fail("OpConstantSampler requires Kernel Capability");109break;110111default:112vtn_fail("Unhandled opcode");113}114}115116static bool117vtn_validate_handle_constant_instruction(struct vtn_builder *b, SpvOp opcode,118const uint32_t *w, unsigned count)119{120switch (opcode) {121case SpvOpSource:122case SpvOpSourceContinued:123case SpvOpSourceExtension:124case SpvOpExtension:125case SpvOpCapability:126case SpvOpExtInstImport:127case SpvOpMemoryModel:128case SpvOpEntryPoint:129case SpvOpExecutionMode:130case SpvOpString:131case SpvOpName:132case SpvOpMemberName:133case SpvOpDecorationGroup:134case SpvOpDecorate:135case SpvOpMemberDecorate:136case SpvOpGroupDecorate:137case SpvOpGroupMemberDecorate:138vtn_fail("Invalid opcode types and variables section");139break;140141case SpvOpTypeVoid:142case SpvOpTypeBool:143case SpvOpTypeInt:144case SpvOpTypeFloat:145case SpvOpTypeVector:146case SpvOpTypeMatrix:147case SpvOpTypeImage:148case SpvOpTypeSampler:149case SpvOpTypeSampledImage:150case SpvOpTypeArray:151case SpvOpTypeRuntimeArray:152case SpvOpTypeStruct:153case SpvOpTypeOpaque:154case SpvOpTypePointer:155case SpvOpTypeFunction:156case SpvOpTypeEvent:157case SpvOpTypeDeviceEvent:158case SpvOpTypeReserveId:159case SpvOpTypeQueue:160case SpvOpTypePipe:161/* We don't need to handle types */162break;163164case SpvOpConstantTrue:165case SpvOpConstantFalse:166case SpvOpConstant:167case SpvOpConstantComposite:168case SpvOpConstantSampler:169case SpvOpConstantNull:170case SpvOpSpecConstantTrue:171case SpvOpSpecConstantFalse:172case SpvOpSpecConstant:173case SpvOpSpecConstantComposite:174case SpvOpSpecConstantOp:175vtn_validate_handle_constant(b, opcode, w, count);176break;177178case SpvOpUndef:179case SpvOpVariable:180/* We don't need to handle them */181break;182183default:184return false; /* End of preamble */185}186187return true;188}189190/*191* Since OpenGL 4.6 you can use SPIR-V modules directly on OpenGL. One of the192* new methods, glSpecializeShader include some possible errors when trying to193* use it.194*195* From OpenGL 4.6, Section 7.2.1, "Shader Specialization":196*197* "void SpecializeShaderARB(uint shader,198* const char* pEntryPoint,199* uint numSpecializationConstants,200* const uint* pConstantIndex,201* const uint* pConstantValue);202* <skip>203*204* INVALID_VALUE is generated if <pEntryPoint> does not name a valid205* entry point for <shader>.206*207* An INVALID_VALUE error is generated if any element of pConstantIndex refers208* to a specialization constant that does not exist in the shader module209* contained in shader."210*211* We could do those checks on spirv_to_nir, but we are only interested on the212* full translation later, during linking. This method is a simplified version213* of spirv_to_nir, looking for only the checks needed by SpecializeShader.214*215* This method returns NULL if no entry point was found, and fill the216* nir_spirv_specialization field "defined_on_module" accordingly. Caller217* would need to trigger the specific errors.218*219*/220bool221gl_spirv_validation(const uint32_t *words, size_t word_count,222struct nir_spirv_specialization *spec, unsigned num_spec,223gl_shader_stage stage, const char *entry_point_name)224{225/* vtn_warn/vtn_log uses debug.func. Setting a null to prevent crash. Not226* need to print the warnings now, would be done later, on the real227* spirv_to_nir228*/229const struct spirv_to_nir_options options = { .debug.func = NULL};230const uint32_t *word_end = words + word_count;231232struct vtn_builder *b = vtn_create_builder(words, word_count,233stage, entry_point_name,234&options);235236if (b == NULL)237return false;238239/* See also _vtn_fail() */240if (vtn_setjmp(b->fail_jump)) {241ralloc_free(b);242return false;243}244245/* Skip the SPIR-V header, handled at vtn_create_builder */246words+= 5;247248/* Search entry point from preamble */249words = vtn_foreach_instruction(b, words, word_end,250vtn_validate_preamble_instruction);251252if (b->entry_point == NULL) {253ralloc_free(b);254return false;255}256257b->specializations = spec;258b->num_specializations = num_spec;259260/* Handle constant instructions (we don't need to handle261* variables or types for gl_spirv)262*/263words = vtn_foreach_instruction(b, words, word_end,264vtn_validate_handle_constant_instruction);265266ralloc_free(b);267268return true;269}270271272273