porting changes for OpenGL Subgroup tests
[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 4.6 or 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 glslang::EShTargetLanguageVersion getSpirvTargetVersion(SpirvVersion version)
201 {
202     switch(version)
203     {
204     default:
205         DE_FATAL("unhandled SPIRV target version");
206         // fall-through
207     case SPIRV_VERSION_1_0:
208         return glslang::EShTargetSpv_1_0;
209     case SPIRV_VERSION_1_1:
210         return glslang::EShTargetSpv_1_1;
211     case SPIRV_VERSION_1_2:
212         return glslang::EShTargetSpv_1_2;
213     case SPIRV_VERSION_1_3:
214         return glslang::EShTargetSpv_1_3;
215     }
216 }
217
218 bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst, SpirvVersion version)
219 {
220         TBuiltInResource builtinRes;
221
222         prepareGlslang();
223         getDefaultBuiltInResources(&builtinRes);
224
225         const EShLanguage shaderStage = getGlslangStage(type);
226
227         glslang::TShader  shader(shaderStage);
228         glslang::TProgram program;
229
230         const char* src[] = { source.c_str() };
231
232         shader.setStrings(src, 1);
233         shader.setEnvTarget(glslang::EshTargetSpv, getSpirvTargetVersion(version));
234         program.addShader(&shader);
235
236         const int compileRes = shader.parse(&builtinRes, 100, false, EShMsgSpvRules);
237         if (compileRes != 0)
238         {
239                 const int linkRes = program.link(EShMsgSpvRules);
240
241                 if (linkRes != 0)
242                 {
243                         const glslang::TIntermediate* const intermediate = program.getIntermediate(shaderStage);
244                         glslang::GlslangToSpv(*intermediate, *dst);
245
246                         return true;
247                 }
248                 else
249                 {
250                         log << tcu::TestLog::Message << "Program linking error:\n"
251                                 << program.getInfoLog() << "\n"
252                                 << "Source:\n"
253                                 << source << "\n"
254                                 << tcu::TestLog::EndMessage;
255                 }
256         }
257         else
258         {
259                 log << tcu::TestLog::Message << "Shader compilation error:\n"
260                         << shader.getInfoLog() << "\n"
261                         << "Source:\n"
262                         << source << "\n"
263                         << tcu::TestLog::EndMessage;
264         }
265
266         return false;
267 }
268
269 #else // DEQP_HAVE_GLSLANG
270
271 bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst)
272 {
273         DE_UNREF(log);
274         DE_UNREF(source);
275         DE_UNREF(type);
276         DE_UNREF(dst);
277
278         TCU_THROW(InternalError, "Glslang not available.");
279
280         return false;
281 }
282
283 #endif // DEQP_HAVE_GLSLANG
284
285 #if defined DEQP_HAVE_SPIRV_TOOLS
286
287 void consumer(spv_message_level_t, const char*, const spv_position_t&, const char* m)
288 {
289         std::cerr << "error: " << m << std::endl;
290 }
291
292 void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
293 {
294         spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
295
296         core.SetMessageConsumer(consumer);
297
298         if (!core.Assemble(src, &dst))
299                 TCU_THROW(InternalError, "Failed to assemble Spir-V source.");
300 }
301
302 void spirvDisassemble(std::string& dst, const ShaderBinaryDataType& src)
303 {
304         spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
305
306         core.SetMessageConsumer(consumer);
307
308         if (!core.Disassemble(src, &dst))
309                 TCU_THROW(InternalError, "Failed to disassemble Spir-V module.");
310 }
311
312 bool spirvValidate(ShaderBinaryDataType& dst, bool throwOnError)
313 {
314         spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
315
316         if (throwOnError)
317                 core.SetMessageConsumer(consumer);
318
319         if (!core.Validate(dst))
320         {
321                 if (throwOnError)
322                         TCU_THROW(InternalError, "Failed to validate Spir-V module.");
323                 return false;
324         }
325
326         return true;
327 }
328
329 #else //DEQP_HAVE_SPIRV_TOOLS
330
331 void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
332 {
333         DE_UNREF(dst);
334         DE_UNREF(src);
335
336         TCU_THROW(InternalError, "Spirv-tools not available.");
337 }
338
339 void spirvDisassemble(std::string& dst, ShaderBinaryDataType& src)
340 {
341         DE_UNREF(dst);
342         DE_UNREF(src);
343
344         TCU_THROW(InternalError, "Spirv-tools not available.");
345 }
346
347 bool spirvValidate(ShaderBinaryDataType& dst, bool throwOnError)
348 {
349         DE_UNREF(dst);
350         DE_UNREF(throwOnError);
351
352         TCU_THROW(InternalError, "Spirv-tools not available.");
353 }
354
355 #endif // DEQP_HAVE_SPIRV_TOOLS
356
357 ShaderBinary makeSpirV(tcu::TestLog& log, ShaderSource source, SpirvVersion version)
358 {
359         ShaderBinary binary;
360
361         if (!spirvUtils::compileGlslToSpirV(log, source.source, source.shaderType, &binary.binary, version))
362                 TCU_THROW(InternalError, "Failed to convert GLSL to Spir-V");
363
364         binary << source.shaderType << "main";
365
366         return binary;
367 }
368
369 /** Verifying if GLSL to SpirV mapping was performed correctly
370  *
371  * @param glslSource       GLSL shader template
372  * @param spirVSource      SpirV disassembled source
373  * @param mappings         Glsl to SpirV mappings vector
374  * @param anyOf            any occurence indicator
375  *
376  * @return true if GLSL code occurs as many times as all of SpirV code for each mapping if anyOf is false
377  *         or true if SpirV code occurs at least once if GLSL code found, false otherwise.
378  **/
379 bool verifyMappings(std::string glslSource, std::string spirVSource, SpirVMapping& mappings, bool anyOf)
380 {
381         std::vector<std::string> spirVSourceLines = de::splitString(spirVSource, '\n');
382
383         // Iterate through all glsl functions
384         for (SpirVMapping::iterator it = mappings.begin(); it != mappings.end(); it++)
385         {
386                 int glslCodeCount  = 0;
387                 int spirVCodeCount = 0;
388
389                 // To avoid finding functions with similar names (ie. "cos", "acos", "cosh")
390                 // add characteristic characters that delimits finding results
391                 std::string glslCode = it->first;
392
393                 // Count GLSL code occurrences in GLSL source
394                 size_t codePosition = glslSource.find(glslCode);
395                 while (codePosition != std::string::npos)
396                 {
397                         glslCodeCount++;
398                         codePosition = glslSource.find(glslCode, codePosition + 1);
399                 }
400
401                 if (glslCodeCount > 0)
402                 {
403                         // Count all SpirV code variants occurrences in SpirV source
404                         for (int s = 0; s < (signed)it->second.size(); ++s)
405                         {
406                                 std::vector<std::string> spirVCodes = de::splitString(it->second[s], ' ');
407
408                                 for (int v = 0; v < (signed)spirVSourceLines.size(); ++v)
409                                 {
410                                         std::vector<std::string> spirVLineCodes = de::splitString(spirVSourceLines[v], ' ');
411
412                                         bool matchAll = true;
413                                         for (int j = 0; j < (signed)spirVCodes.size(); ++j)
414                                         {
415                                                 bool match = false;
416                                                 for (int i = 0; i < (signed)spirVLineCodes.size(); ++i)
417                                                 {
418                                                         if (spirVLineCodes[i] == spirVCodes[j])
419                                                                 match = true;
420                                                 }
421
422                                                 matchAll = matchAll && match;
423                                         }
424
425                                         if (matchAll)
426                                                 spirVCodeCount++;
427                                 }
428                         }
429
430                         // Check if both counts match
431                         if (anyOf && (glslCodeCount > 0 && spirVCodeCount == 0))
432                                 return false;
433                         else if (!anyOf && glslCodeCount != spirVCodeCount)
434                                 return false;
435                 }
436         }
437
438         return true;
439 }
440
441 } // namespace spirvUtils
442
443 } // namespace glc