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