xref: /aosp_15_r20/external/deqp/external/openglcts/modules/common/glcSpirvUtils.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * OpenGL Conformance Test Suite
3  * -----------------------------
4  *
5  * Copyright (c) 2017-2019 The Khronos Group 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  glcSpirvUtils.cpp
21  * \brief Utility functions for using Glslang and Spirv-tools to work with
22  *  SPIR-V shaders.
23  */ /*-------------------------------------------------------------------*/
24 
25 #include "glcSpirvUtils.hpp"
26 #include "deArrayUtil.hpp"
27 #include "deSingleton.h"
28 #include "deStringUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "tcuTestLog.hpp"
31 
32 #include "SPIRV/GlslangToSpv.h"
33 #include "SPIRV/disassemble.h"
34 #include "SPIRV/doc.h"
35 #include "glslang/MachineIndependent/localintermediate.h"
36 #include "glslang/Public/ShaderLang.h"
37 
38 #include "spirv-tools/libspirv.hpp"
39 #include "spirv-tools/optimizer.hpp"
40 
41 using namespace glu;
42 
43 namespace glc
44 {
45 
46 namespace spirvUtils
47 {
48 
checkGlSpirvSupported(deqp::Context & m_context)49 void checkGlSpirvSupported(deqp::Context &m_context)
50 {
51     bool is_at_least_gl_46 = (glu::contextSupports(m_context.getRenderContext().getType(), glu::ApiType::core(4, 6)));
52     bool is_arb_gl_spirv   = m_context.getContextInfo().isExtensionSupported("GL_ARB_gl_spirv");
53 
54     if ((!is_at_least_gl_46) && (!is_arb_gl_spirv))
55         TCU_THROW(NotSupportedError, "GL 4.6 or GL_ARB_gl_spirv is not supported");
56 }
57 
getGlslangStage(glu::ShaderType type)58 EShLanguage getGlslangStage(glu::ShaderType type)
59 {
60     static const EShLanguage stageMap[] = {EShLangVertex,         EShLangFragment, EShLangGeometry,  EShLangTessControl,
61                                            EShLangTessEvaluation, EShLangCompute,  EShLangRayGen,    EShLangAnyHit,
62                                            EShLangClosestHit,     EShLangMiss,     EShLangIntersect, EShLangCallable,
63                                            EShLangTaskNV,         EShLangMeshNV};
64 
65     return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
66 }
67 
68 static volatile deSingletonState s_glslangInitState = DE_SINGLETON_STATE_NOT_INITIALIZED;
69 
initGlslang(void *)70 void initGlslang(void *)
71 {
72     // Main compiler
73     glslang::InitializeProcess();
74 
75     // SPIR-V disassembly
76     spv::Parameterize();
77 }
78 
prepareGlslang(void)79 void prepareGlslang(void)
80 {
81     deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
82 }
83 
getDefaultLimits(TLimits * limits)84 void getDefaultLimits(TLimits *limits)
85 {
86     limits->nonInductiveForLoops                 = true;
87     limits->whileLoops                           = true;
88     limits->doWhileLoops                         = true;
89     limits->generalUniformIndexing               = true;
90     limits->generalAttributeMatrixVectorIndexing = true;
91     limits->generalVaryingIndexing               = true;
92     limits->generalSamplerIndexing               = true;
93     limits->generalVariableIndexing              = true;
94     limits->generalConstantMatrixVectorIndexing  = true;
95 }
96 
getDefaultBuiltInResources(TBuiltInResource * builtin)97 void getDefaultBuiltInResources(TBuiltInResource *builtin)
98 {
99     getDefaultLimits(&builtin->limits);
100 
101     builtin->maxLights                                 = 32;
102     builtin->maxClipPlanes                             = 6;
103     builtin->maxTextureUnits                           = 32;
104     builtin->maxTextureCoords                          = 32;
105     builtin->maxVertexAttribs                          = 64;
106     builtin->maxVertexUniformComponents                = 4096;
107     builtin->maxVaryingFloats                          = 64;
108     builtin->maxVertexTextureImageUnits                = 32;
109     builtin->maxCombinedTextureImageUnits              = 80;
110     builtin->maxTextureImageUnits                      = 32;
111     builtin->maxFragmentUniformComponents              = 4096;
112     builtin->maxDrawBuffers                            = 32;
113     builtin->maxVertexUniformVectors                   = 128;
114     builtin->maxVaryingVectors                         = 8;
115     builtin->maxFragmentUniformVectors                 = 16;
116     builtin->maxVertexOutputVectors                    = 16;
117     builtin->maxFragmentInputVectors                   = 15;
118     builtin->minProgramTexelOffset                     = -8;
119     builtin->maxProgramTexelOffset                     = 7;
120     builtin->maxClipDistances                          = 8;
121     builtin->maxComputeWorkGroupCountX                 = 65535;
122     builtin->maxComputeWorkGroupCountY                 = 65535;
123     builtin->maxComputeWorkGroupCountZ                 = 65535;
124     builtin->maxComputeWorkGroupSizeX                  = 1024;
125     builtin->maxComputeWorkGroupSizeY                  = 1024;
126     builtin->maxComputeWorkGroupSizeZ                  = 64;
127     builtin->maxComputeUniformComponents               = 1024;
128     builtin->maxComputeTextureImageUnits               = 16;
129     builtin->maxComputeImageUniforms                   = 8;
130     builtin->maxComputeAtomicCounters                  = 8;
131     builtin->maxComputeAtomicCounterBuffers            = 1;
132     builtin->maxVaryingComponents                      = 60;
133     builtin->maxVertexOutputComponents                 = 64;
134     builtin->maxGeometryInputComponents                = 64;
135     builtin->maxGeometryOutputComponents               = 128;
136     builtin->maxFragmentInputComponents                = 128;
137     builtin->maxImageUnits                             = 8;
138     builtin->maxCombinedImageUnitsAndFragmentOutputs   = 8;
139     builtin->maxCombinedShaderOutputResources          = 8;
140     builtin->maxImageSamples                           = 0;
141     builtin->maxVertexImageUniforms                    = 0;
142     builtin->maxTessControlImageUniforms               = 0;
143     builtin->maxTessEvaluationImageUniforms            = 0;
144     builtin->maxGeometryImageUniforms                  = 0;
145     builtin->maxFragmentImageUniforms                  = 8;
146     builtin->maxCombinedImageUniforms                  = 8;
147     builtin->maxGeometryTextureImageUnits              = 16;
148     builtin->maxGeometryOutputVertices                 = 256;
149     builtin->maxGeometryTotalOutputComponents          = 1024;
150     builtin->maxGeometryUniformComponents              = 1024;
151     builtin->maxGeometryVaryingComponents              = 64;
152     builtin->maxTessControlInputComponents             = 128;
153     builtin->maxTessControlOutputComponents            = 128;
154     builtin->maxTessControlTextureImageUnits           = 16;
155     builtin->maxTessControlUniformComponents           = 1024;
156     builtin->maxTessControlTotalOutputComponents       = 4096;
157     builtin->maxTessEvaluationInputComponents          = 128;
158     builtin->maxTessEvaluationOutputComponents         = 128;
159     builtin->maxTessEvaluationTextureImageUnits        = 16;
160     builtin->maxTessEvaluationUniformComponents        = 1024;
161     builtin->maxTessPatchComponents                    = 120;
162     builtin->maxPatchVertices                          = 32;
163     builtin->maxTessGenLevel                           = 64;
164     builtin->maxViewports                              = 16;
165     builtin->maxVertexAtomicCounters                   = 0;
166     builtin->maxTessControlAtomicCounters              = 0;
167     builtin->maxTessEvaluationAtomicCounters           = 0;
168     builtin->maxGeometryAtomicCounters                 = 0;
169     builtin->maxFragmentAtomicCounters                 = 8;
170     builtin->maxCombinedAtomicCounters                 = 8;
171     builtin->maxAtomicCounterBindings                  = 1;
172     builtin->maxVertexAtomicCounterBuffers             = 0;
173     builtin->maxTessControlAtomicCounterBuffers        = 0;
174     builtin->maxTessEvaluationAtomicCounterBuffers     = 0;
175     builtin->maxGeometryAtomicCounterBuffers           = 0;
176     builtin->maxFragmentAtomicCounterBuffers           = 1;
177     builtin->maxCombinedAtomicCounterBuffers           = 1;
178     builtin->maxAtomicCounterBufferSize                = 16384;
179     builtin->maxTransformFeedbackBuffers               = 4;
180     builtin->maxTransformFeedbackInterleavedComponents = 64;
181     builtin->maxCullDistances                          = 8;
182     builtin->maxCombinedClipAndCullDistances           = 8;
183     builtin->maxSamples                                = 4;
184     builtin->maxMeshOutputVerticesNV                   = 256;
185     builtin->maxMeshOutputPrimitivesNV                 = 256;
186     builtin->maxMeshWorkGroupSizeX_NV                  = 32;
187     builtin->maxMeshWorkGroupSizeY_NV                  = 1;
188     builtin->maxMeshWorkGroupSizeZ_NV                  = 1;
189     builtin->maxTaskWorkGroupSizeX_NV                  = 32;
190     builtin->maxTaskWorkGroupSizeY_NV                  = 1;
191     builtin->maxTaskWorkGroupSizeZ_NV                  = 1;
192     builtin->maxMeshViewCountNV                        = 4;
193     builtin->maxDualSourceDrawBuffersEXT               = 1;
194 };
195 
getSpirvTargetVersion(SpirvVersion version)196 glslang::EShTargetLanguageVersion getSpirvTargetVersion(SpirvVersion version)
197 {
198     switch (version)
199     {
200     default:
201         DE_FATAL("unhandled SPIRV target version");
202         // fall-through
203     case SPIRV_VERSION_1_0:
204         return glslang::EShTargetSpv_1_0;
205     case SPIRV_VERSION_1_1:
206         return glslang::EShTargetSpv_1_1;
207     case SPIRV_VERSION_1_2:
208         return glslang::EShTargetSpv_1_2;
209     case SPIRV_VERSION_1_3:
210         return glslang::EShTargetSpv_1_3;
211     }
212 }
213 
compileGlslToSpirV(tcu::TestLog & log,std::string source,glu::ShaderType type,ShaderBinaryDataType * dst,SpirvVersion version)214 bool compileGlslToSpirV(tcu::TestLog &log, std::string source, glu::ShaderType type, ShaderBinaryDataType *dst,
215                         SpirvVersion version)
216 {
217     TBuiltInResource builtinRes;
218 
219     prepareGlslang();
220     getDefaultBuiltInResources(&builtinRes);
221 
222     const EShLanguage shaderStage = getGlslangStage(type);
223 
224     glslang::TShader shader(shaderStage);
225     glslang::TProgram program;
226 
227     const char *src[] = {source.c_str()};
228 
229     shader.setStrings(src, 1);
230     shader.setEnvTarget(glslang::EshTargetSpv, getSpirvTargetVersion(version));
231     program.addShader(&shader);
232 
233     const int compileRes = shader.parse(&builtinRes, 100, false, EShMsgSpvRules);
234     if (compileRes != 0)
235     {
236         const int linkRes = program.link(EShMsgSpvRules);
237 
238         if (linkRes != 0)
239         {
240             const glslang::TIntermediate *const intermediate = program.getIntermediate(shaderStage);
241             glslang::GlslangToSpv(*intermediate, *dst);
242 
243             return true;
244         }
245         else
246         {
247             log << tcu::TestLog::Message << "Program linking error:\n"
248                 << program.getInfoLog() << "\n"
249                 << "Source:\n"
250                 << source << "\n"
251                 << tcu::TestLog::EndMessage;
252         }
253     }
254     else
255     {
256         log << tcu::TestLog::Message << "Shader compilation error:\n"
257             << shader.getInfoLog() << "\n"
258             << "Source:\n"
259             << source << "\n"
260             << tcu::TestLog::EndMessage;
261     }
262 
263     return false;
264 }
265 
consumer(spv_message_level_t,const char *,const spv_position_t &,const char * m)266 void consumer(spv_message_level_t, const char *, const spv_position_t &, const char *m)
267 {
268     std::cerr << "error: " << m << std::endl;
269 }
270 
spirvAssemble(ShaderBinaryDataType & dst,const std::string & src)271 void spirvAssemble(ShaderBinaryDataType &dst, const std::string &src)
272 {
273     spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
274 
275     core.SetMessageConsumer(consumer);
276 
277     if (!core.Assemble(src, &dst))
278         TCU_THROW(InternalError, "Failed to assemble Spir-V source.");
279 }
280 
spirvDisassemble(std::string & dst,const ShaderBinaryDataType & src)281 void spirvDisassemble(std::string &dst, const ShaderBinaryDataType &src)
282 {
283     spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
284 
285     core.SetMessageConsumer(consumer);
286 
287     if (!core.Disassemble(src, &dst))
288         TCU_THROW(InternalError, "Failed to disassemble Spir-V module.");
289 }
290 
spirvValidate(ShaderBinaryDataType & dst,bool throwOnError)291 bool spirvValidate(ShaderBinaryDataType &dst, bool throwOnError)
292 {
293     spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
294 
295     if (throwOnError)
296         core.SetMessageConsumer(consumer);
297 
298     if (!core.Validate(dst))
299     {
300         if (throwOnError)
301             TCU_THROW(InternalError, "Failed to validate Spir-V module.");
302         return false;
303     }
304 
305     return true;
306 }
307 
makeSpirV(tcu::TestLog & log,ShaderSource source,SpirvVersion version)308 ShaderBinary makeSpirV(tcu::TestLog &log, ShaderSource source, SpirvVersion version)
309 {
310     ShaderBinary binary;
311 
312     if (!spirvUtils::compileGlslToSpirV(log, source.source, source.shaderType, &binary.binary, version))
313         TCU_THROW(InternalError, "Failed to convert GLSL to Spir-V");
314 
315     binary << source.shaderType << "main";
316 
317     return binary;
318 }
319 
320 /** Verifying if GLSL to SpirV mapping was performed correctly
321  *
322  * @param glslSource       GLSL shader template
323  * @param spirVSource      SpirV disassembled source
324  * @param mappings         Glsl to SpirV mappings vector
325  * @param anyOf            any occurence indicator
326  *
327  * @return true if GLSL code occurs as many times as all of SpirV code for each mapping if anyOf is false
328  *         or true if SpirV code occurs at least once if GLSL code found, false otherwise.
329  **/
verifyMappings(std::string glslSource,std::string spirVSource,SpirVMapping & mappings,bool anyOf)330 bool verifyMappings(std::string glslSource, std::string spirVSource, SpirVMapping &mappings, bool anyOf)
331 {
332     std::vector<std::string> spirVSourceLines = de::splitString(spirVSource, '\n');
333 
334     // Iterate through all glsl functions
335     for (SpirVMapping::iterator it = mappings.begin(); it != mappings.end(); it++)
336     {
337         int glslCodeCount  = 0;
338         int spirVCodeCount = 0;
339 
340         // To avoid finding functions with similar names (ie. "cos", "acos", "cosh")
341         // add characteristic characters that delimits finding results
342         std::string glslCode = it->first;
343 
344         // Count GLSL code occurrences in GLSL source
345         size_t codePosition = glslSource.find(glslCode);
346         while (codePosition != std::string::npos)
347         {
348             glslCodeCount++;
349             codePosition = glslSource.find(glslCode, codePosition + 1);
350         }
351 
352         if (glslCodeCount > 0)
353         {
354             // Count all SpirV code variants occurrences in SpirV source
355             for (int s = 0; s < (signed)it->second.size(); ++s)
356             {
357                 std::vector<std::string> spirVCodes = de::splitString(it->second[s], ' ');
358 
359                 for (int v = 0; v < (signed)spirVSourceLines.size(); ++v)
360                 {
361                     std::vector<std::string> spirVLineCodes = de::splitString(spirVSourceLines[v], ' ');
362 
363                     bool matchAll = true;
364                     for (int j = 0; j < (signed)spirVCodes.size(); ++j)
365                     {
366                         bool match = false;
367                         for (int i = 0; i < (signed)spirVLineCodes.size(); ++i)
368                         {
369                             if (spirVLineCodes[i] == spirVCodes[j])
370                                 match = true;
371                         }
372 
373                         matchAll = matchAll && match;
374                     }
375 
376                     if (matchAll)
377                         spirVCodeCount++;
378                 }
379             }
380 
381             // Check if both counts match
382             if (anyOf && (glslCodeCount > 0 && spirVCodeCount == 0))
383                 return false;
384             else if (!anyOf && glslCodeCount != spirVCodeCount)
385                 return false;
386         }
387     }
388 
389     return true;
390 }
391 
392 } // namespace spirvUtils
393 
394 } // namespace glc
395