xref: /aosp_15_r20/external/deqp/external/vulkancts/framework/vulkan/vkShaderToSpirV.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
3  * --------------------
4  *
5  * Copyright (c) 2015 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Shading language (GLSL/HLSL) to SPIR-V.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkShaderToSpirV.hpp"
25 #include "deArrayUtil.hpp"
26 #include "deSingleton.h"
27 #include "deMemory.h"
28 #include "deClock.h"
29 #include "qpDebugOut.h"
30 
31 #include "SPIRV/GlslangToSpv.h"
32 #include "SPIRV/disassemble.h"
33 #include "SPIRV/SPVRemapper.h"
34 #include "SPIRV/doc.h"
35 #include "glslang/Include/InfoSink.h"
36 #include "glslang/Include/ShHandle.h"
37 #include "glslang/MachineIndependent/localintermediate.h"
38 #include "glslang/Public/ShaderLang.h"
39 
40 namespace vk
41 {
42 
43 using std::string;
44 using std::vector;
45 
46 namespace
47 {
48 
getGlslangStage(glu::ShaderType type)49 EShLanguage getGlslangStage(glu::ShaderType type)
50 {
51     static const EShLanguage stageMap[] = {
52         EShLangVertex,    EShLangFragment, EShLangGeometry, EShLangTessControl, EShLangTessEvaluation,
53         EShLangCompute,   EShLangRayGen,   EShLangAnyHit,   EShLangClosestHit,  EShLangMiss,
54         EShLangIntersect, EShLangCallable, EShLangTaskNV,   EShLangMeshNV,
55     };
56     return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
57 }
58 
59 static volatile deSingletonState s_glslangInitState = DE_SINGLETON_STATE_NOT_INITIALIZED;
60 
initGlslang(void *)61 void initGlslang(void *)
62 {
63     // Main compiler
64     glslang::InitializeProcess();
65 
66     // SPIR-V disassembly
67     spv::Parameterize();
68 }
69 
prepareGlslang(void)70 void prepareGlslang(void)
71 {
72     deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
73 }
74 
75 // \todo [2015-06-19 pyry] Specialize these per GLSL version
76 
77 // Fail compilation if more members are added to TLimits or TBuiltInResource
78 struct LimitsSizeHelper_s
79 {
80     bool m0, m1, m2, m3, m4, m5, m6, m7, m8;
81 };
82 struct BuiltInResourceSizeHelper_s
83 {
84     int m[102];
85     LimitsSizeHelper_s l;
86 };
87 
88 DE_STATIC_ASSERT(sizeof(TLimits) == sizeof(LimitsSizeHelper_s));
89 DE_STATIC_ASSERT(sizeof(TBuiltInResource) == sizeof(BuiltInResourceSizeHelper_s));
90 
getDefaultLimits(TLimits * limits)91 void getDefaultLimits(TLimits *limits)
92 {
93     limits->nonInductiveForLoops                 = true;
94     limits->whileLoops                           = true;
95     limits->doWhileLoops                         = true;
96     limits->generalUniformIndexing               = true;
97     limits->generalAttributeMatrixVectorIndexing = true;
98     limits->generalVaryingIndexing               = true;
99     limits->generalSamplerIndexing               = true;
100     limits->generalVariableIndexing              = true;
101     limits->generalConstantMatrixVectorIndexing  = true;
102 }
103 
getDefaultBuiltInResources(TBuiltInResource * builtin)104 void getDefaultBuiltInResources(TBuiltInResource *builtin)
105 {
106     getDefaultLimits(&builtin->limits);
107 
108     builtin->maxLights                                 = 32;
109     builtin->maxClipPlanes                             = 6;
110     builtin->maxTextureUnits                           = 32;
111     builtin->maxTextureCoords                          = 32;
112     builtin->maxVertexAttribs                          = 64;
113     builtin->maxVertexUniformComponents                = 4096;
114     builtin->maxVaryingFloats                          = 64;
115     builtin->maxVertexTextureImageUnits                = 32;
116     builtin->maxCombinedTextureImageUnits              = 80;
117     builtin->maxTextureImageUnits                      = 32;
118     builtin->maxFragmentUniformComponents              = 4096;
119     builtin->maxDrawBuffers                            = 32;
120     builtin->maxVertexUniformVectors                   = 128;
121     builtin->maxVaryingVectors                         = 8;
122     builtin->maxFragmentUniformVectors                 = 16;
123     builtin->maxVertexOutputVectors                    = 16;
124     builtin->maxFragmentInputVectors                   = 15;
125     builtin->minProgramTexelOffset                     = -8;
126     builtin->maxProgramTexelOffset                     = 7;
127     builtin->maxClipDistances                          = 8;
128     builtin->maxComputeWorkGroupCountX                 = 65535;
129     builtin->maxComputeWorkGroupCountY                 = 65535;
130     builtin->maxComputeWorkGroupCountZ                 = 65535;
131     builtin->maxComputeWorkGroupSizeX                  = 1024;
132     builtin->maxComputeWorkGroupSizeY                  = 1024;
133     builtin->maxComputeWorkGroupSizeZ                  = 64;
134     builtin->maxComputeUniformComponents               = 1024;
135     builtin->maxComputeTextureImageUnits               = 16;
136     builtin->maxComputeImageUniforms                   = 8;
137     builtin->maxComputeAtomicCounters                  = 8;
138     builtin->maxComputeAtomicCounterBuffers            = 1;
139     builtin->maxVaryingComponents                      = 60;
140     builtin->maxVertexOutputComponents                 = 64;
141     builtin->maxGeometryInputComponents                = 64;
142     builtin->maxGeometryOutputComponents               = 128;
143     builtin->maxFragmentInputComponents                = 128;
144     builtin->maxImageUnits                             = 8;
145     builtin->maxCombinedImageUnitsAndFragmentOutputs   = 8;
146     builtin->maxCombinedShaderOutputResources          = 8;
147     builtin->maxImageSamples                           = 0;
148     builtin->maxVertexImageUniforms                    = 0;
149     builtin->maxTessControlImageUniforms               = 0;
150     builtin->maxTessEvaluationImageUniforms            = 0;
151     builtin->maxGeometryImageUniforms                  = 0;
152     builtin->maxFragmentImageUniforms                  = 8;
153     builtin->maxCombinedImageUniforms                  = 8;
154     builtin->maxGeometryTextureImageUnits              = 16;
155     builtin->maxGeometryOutputVertices                 = 256;
156     builtin->maxGeometryTotalOutputComponents          = 1024;
157     builtin->maxGeometryUniformComponents              = 1024;
158     builtin->maxGeometryVaryingComponents              = 64;
159     builtin->maxTessControlInputComponents             = 128;
160     builtin->maxTessControlOutputComponents            = 128;
161     builtin->maxTessControlTextureImageUnits           = 16;
162     builtin->maxTessControlUniformComponents           = 1024;
163     builtin->maxTessControlTotalOutputComponents       = 4096;
164     builtin->maxTessEvaluationInputComponents          = 128;
165     builtin->maxTessEvaluationOutputComponents         = 128;
166     builtin->maxTessEvaluationTextureImageUnits        = 16;
167     builtin->maxTessEvaluationUniformComponents        = 1024;
168     builtin->maxTessPatchComponents                    = 120;
169     builtin->maxPatchVertices                          = 32;
170     builtin->maxTessGenLevel                           = 64;
171     builtin->maxViewports                              = 16;
172     builtin->maxVertexAtomicCounters                   = 0;
173     builtin->maxTessControlAtomicCounters              = 0;
174     builtin->maxTessEvaluationAtomicCounters           = 0;
175     builtin->maxGeometryAtomicCounters                 = 0;
176     builtin->maxFragmentAtomicCounters                 = 8;
177     builtin->maxCombinedAtomicCounters                 = 8;
178     builtin->maxAtomicCounterBindings                  = 1;
179     builtin->maxVertexAtomicCounterBuffers             = 0;
180     builtin->maxTessControlAtomicCounterBuffers        = 0;
181     builtin->maxTessEvaluationAtomicCounterBuffers     = 0;
182     builtin->maxGeometryAtomicCounterBuffers           = 0;
183     builtin->maxFragmentAtomicCounterBuffers           = 1;
184     builtin->maxCombinedAtomicCounterBuffers           = 1;
185     builtin->maxAtomicCounterBufferSize                = 16384;
186     builtin->maxTransformFeedbackBuffers               = 8;
187     builtin->maxTransformFeedbackInterleavedComponents = 16382;
188     builtin->maxCullDistances                          = 8;
189     builtin->maxCombinedClipAndCullDistances           = 8;
190     builtin->maxSamples                                = 4;
191     builtin->maxMeshOutputVerticesNV                   = 2048;
192     builtin->maxMeshOutputPrimitivesNV                 = 2048;
193     builtin->maxMeshWorkGroupSizeX_NV                  = 256;
194     builtin->maxMeshWorkGroupSizeY_NV                  = 1;
195     builtin->maxMeshWorkGroupSizeZ_NV                  = 1;
196     builtin->maxTaskWorkGroupSizeX_NV                  = 1024;
197     builtin->maxTaskWorkGroupSizeY_NV                  = 1;
198     builtin->maxTaskWorkGroupSizeZ_NV                  = 1;
199     builtin->maxMeshViewCountNV                        = 4;
200     builtin->maxMeshOutputVerticesEXT                  = 2048;
201     builtin->maxMeshOutputPrimitivesEXT                = 2048;
202     builtin->maxMeshWorkGroupSizeX_EXT                 = 256;
203     builtin->maxMeshWorkGroupSizeY_EXT                 = 256;
204     builtin->maxMeshWorkGroupSizeZ_EXT                 = 256;
205     builtin->maxTaskWorkGroupSizeX_EXT                 = 256;
206     builtin->maxTaskWorkGroupSizeY_EXT                 = 256;
207     builtin->maxTaskWorkGroupSizeZ_EXT                 = 256;
208     builtin->maxMeshViewCountEXT                       = 4;
209     builtin->maxDualSourceDrawBuffersEXT               = 1;
210 };
211 
getNumShaderStages(const std::vector<std::string> * sources)212 int getNumShaderStages(const std::vector<std::string> *sources)
213 {
214     int numShaderStages = 0;
215 
216     for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; ++shaderType)
217     {
218         if (!sources[shaderType].empty())
219             numShaderStages += 1;
220     }
221 
222     return numShaderStages;
223 }
224 
getShaderStageSource(const std::vector<std::string> * sources,const ShaderBuildOptions buildOptions,glu::ShaderType shaderType)225 std::string getShaderStageSource(const std::vector<std::string> *sources, const ShaderBuildOptions buildOptions,
226                                  glu::ShaderType shaderType)
227 {
228     if (sources[shaderType].size() != 1)
229         TCU_THROW(InternalError, "Linking multiple compilation units is not supported");
230 
231     if ((buildOptions.flags & ShaderBuildOptions::FLAG_USE_STORAGE_BUFFER_STORAGE_CLASS) != 0)
232     {
233         // Hack to inject #pragma right after first #version statement
234         std::string src  = sources[shaderType][0];
235         size_t injectPos = 0;
236 
237         if (de::beginsWith(src, "#version"))
238             injectPos = src.find('\n') + 1;
239 
240         src.insert(injectPos, "#pragma use_storage_buffer\n");
241 
242         return src;
243     }
244     else
245         return sources[shaderType][0];
246 }
247 
getCompileFlags(const ShaderBuildOptions & buildOpts,const ShaderLanguage shaderLanguage)248 EShMessages getCompileFlags(const ShaderBuildOptions &buildOpts, const ShaderLanguage shaderLanguage)
249 {
250     EShMessages flags = (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
251 
252     if ((buildOpts.flags & ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS) != 0)
253         flags = (EShMessages)(flags | EShMsgHlslOffsets);
254 
255     if (shaderLanguage == SHADER_LANGUAGE_HLSL)
256         flags = (EShMessages)(flags | EShMsgReadHlsl);
257 
258     return flags;
259 }
260 
261 } // namespace
262 
compileShaderToSpirV(const std::vector<std::string> * sources,const ShaderBuildOptions & buildOptions,const ShaderLanguage shaderLanguage,std::vector<uint32_t> * dst,glu::ShaderProgramInfo * buildInfo)263 bool compileShaderToSpirV(const std::vector<std::string> *sources, const ShaderBuildOptions &buildOptions,
264                           const ShaderLanguage shaderLanguage, std::vector<uint32_t> *dst,
265                           glu::ShaderProgramInfo *buildInfo)
266 {
267     TBuiltInResource builtinRes    = {};
268     const EShMessages compileFlags = getCompileFlags(buildOptions, shaderLanguage);
269 
270     if (buildOptions.targetVersion >= SPIRV_VERSION_LAST)
271         TCU_THROW(InternalError, "Unsupported SPIR-V target version");
272 
273     if (getNumShaderStages(sources) > 1)
274         TCU_THROW(InternalError, "Linking multiple shader stages into a single SPIR-V binary is not supported");
275 
276     prepareGlslang();
277     getDefaultBuiltInResources(&builtinRes);
278 
279     // \note Compiles only first found shader
280     for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
281     {
282         if (!sources[shaderType].empty())
283         {
284             const std::string &srcText    = getShaderStageSource(sources, buildOptions, (glu::ShaderType)shaderType);
285             const char *srcPtrs[]         = {srcText.c_str()};
286             const EShLanguage shaderStage = getGlslangStage(glu::ShaderType(shaderType));
287             glslang::TShader shader(shaderStage);
288             glslang::TProgram glslangProgram;
289 
290             shader.setStrings(srcPtrs, DE_LENGTH_OF_ARRAY(srcPtrs));
291 
292             switch (buildOptions.targetVersion)
293             {
294             case SPIRV_VERSION_1_0:
295                 shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10000);
296                 break;
297             case SPIRV_VERSION_1_1:
298                 shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10100);
299                 break;
300             case SPIRV_VERSION_1_2:
301                 shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10200);
302                 break;
303             case SPIRV_VERSION_1_3:
304                 shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10300);
305                 break;
306             case SPIRV_VERSION_1_4:
307                 shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10400);
308                 break;
309             case SPIRV_VERSION_1_5:
310                 shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10500);
311                 break;
312             case SPIRV_VERSION_1_6:
313                 shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10600);
314                 break;
315             default:
316                 TCU_THROW(InternalError, "Unsupported SPIR-V target version");
317             }
318 
319             glslangProgram.addShader(&shader);
320 
321             if (shaderLanguage == SHADER_LANGUAGE_HLSL)
322             {
323                 // Entry point assumed to be named main.
324                 shader.setEntryPoint("main");
325             }
326 
327             {
328                 const uint64_t compileStartTime = deGetMicroseconds();
329                 const int compileRes            = shader.parse(&builtinRes, 110, false, compileFlags);
330                 glu::ShaderInfo shaderBuildInfo;
331 
332                 shaderBuildInfo.type          = (glu::ShaderType)shaderType;
333                 shaderBuildInfo.source        = srcText;
334                 shaderBuildInfo.infoLog       = shader.getInfoLog(); // \todo [2015-07-13 pyry] Include debug log?
335                 shaderBuildInfo.compileTimeUs = deGetMicroseconds() - compileStartTime;
336                 shaderBuildInfo.compileOk     = (compileRes != 0);
337 
338                 buildInfo->shaders.push_back(shaderBuildInfo);
339             }
340 
341             DE_ASSERT(buildInfo->shaders.size() == 1);
342             if (buildInfo->shaders[0].compileOk)
343             {
344                 const uint64_t linkStartTime = deGetMicroseconds();
345                 const int linkRes            = glslangProgram.link(compileFlags);
346 
347                 buildInfo->program.infoLog =
348                     glslangProgram.getInfoLog(); // \todo [2015-11-05 scygan] Include debug log?
349                 buildInfo->program.linkOk     = (linkRes != 0);
350                 buildInfo->program.linkTimeUs = deGetMicroseconds() - linkStartTime;
351             }
352 
353             if (buildInfo->program.linkOk)
354             {
355                 const glslang::TIntermediate *const intermediate = glslangProgram.getIntermediate(shaderStage);
356                 glslang::GlslangToSpv(*intermediate, *dst);
357             }
358 
359             return buildInfo->program.linkOk;
360         }
361     }
362 
363     TCU_THROW(InternalError, "Can't compile empty program");
364 }
365 
compileGlslToSpirV(const GlslSource & program,std::vector<uint32_t> * dst,glu::ShaderProgramInfo * buildInfo)366 bool compileGlslToSpirV(const GlslSource &program, std::vector<uint32_t> *dst, glu::ShaderProgramInfo *buildInfo)
367 {
368     return compileShaderToSpirV(program.sources, program.buildOptions, program.shaderLanguage, dst, buildInfo);
369 }
370 
compileHlslToSpirV(const HlslSource & program,std::vector<uint32_t> * dst,glu::ShaderProgramInfo * buildInfo)371 bool compileHlslToSpirV(const HlslSource &program, std::vector<uint32_t> *dst, glu::ShaderProgramInfo *buildInfo)
372 {
373     return compileShaderToSpirV(program.sources, program.buildOptions, program.shaderLanguage, dst, buildInfo);
374 }
375 
stripSpirVDebugInfo(const size_t numSrcInstrs,const uint32_t * srcInstrs,std::vector<uint32_t> * dst)376 void stripSpirVDebugInfo(const size_t numSrcInstrs, const uint32_t *srcInstrs, std::vector<uint32_t> *dst)
377 {
378     spv::spirvbin_t remapper;
379     std::vector<std::string> whiteListStrings;
380 
381     // glslang operates in-place
382     dst->resize(numSrcInstrs);
383     std::copy(srcInstrs, srcInstrs + numSrcInstrs, dst->begin());
384     remapper.remap(*dst, whiteListStrings, spv::spirvbin_base_t::STRIP);
385 }
386 
387 } // namespace vk
388