1 /*-------------------------------------------------------------------------
2 * OpenGL Conformance Test Suite
3 * -----------------------------
5 * Copyright (c) 2017-2019 The Khronos Group Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * \file glcSpirvUtils.cpp
21 * \brief Utility functions for using Glslang and Spirv-tools to work with
23 */ /*-------------------------------------------------------------------*/
25 #include "glcSpirvUtils.hpp"
26 #include "deArrayUtil.hpp"
27 #include "deSingleton.h"
28 #include "deStringUtil.hpp"
29 #include "gluContextInfo.hpp"
30 #include "tcuTestLog.hpp"
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"
38 #include "spirv-tools/libspirv.hpp"
39 #include "spirv-tools/optimizer.hpp"
49 void checkGlSpirvSupported(deqp::Context& m_context)
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");
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");
58 EShLanguage getGlslangStage(glu::ShaderType type)
60 static const EShLanguage stageMap[] = {
61 EShLangVertex, EShLangFragment, EShLangGeometry, EShLangTessControl, EShLangTessEvaluation, EShLangCompute,
64 return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
67 static volatile deSingletonState s_glslangInitState = DE_SINGLETON_STATE_NOT_INITIALIZED;
69 void initGlslang(void*)
72 glslang::InitializeProcess();
78 void prepareGlslang(void)
80 deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
83 void getDefaultLimits(TLimits* limits)
85 limits->nonInductiveForLoops = true;
86 limits->whileLoops = true;
87 limits->doWhileLoops = true;
88 limits->generalUniformIndexing = true;
89 limits->generalAttributeMatrixVectorIndexing = true;
90 limits->generalVaryingIndexing = true;
91 limits->generalSamplerIndexing = true;
92 limits->generalVariableIndexing = true;
93 limits->generalConstantMatrixVectorIndexing = true;
96 void getDefaultBuiltInResources(TBuiltInResource* builtin)
98 getDefaultLimits(&builtin->limits);
100 builtin->maxLights = 32;
101 builtin->maxClipPlanes = 6;
102 builtin->maxTextureUnits = 32;
103 builtin->maxTextureCoords = 32;
104 builtin->maxVertexAttribs = 64;
105 builtin->maxVertexUniformComponents = 4096;
106 builtin->maxVaryingFloats = 64;
107 builtin->maxVertexTextureImageUnits = 32;
108 builtin->maxCombinedTextureImageUnits = 80;
109 builtin->maxTextureImageUnits = 32;
110 builtin->maxFragmentUniformComponents = 4096;
111 builtin->maxDrawBuffers = 32;
112 builtin->maxVertexUniformVectors = 128;
113 builtin->maxVaryingVectors = 8;
114 builtin->maxFragmentUniformVectors = 16;
115 builtin->maxVertexOutputVectors = 16;
116 builtin->maxFragmentInputVectors = 15;
117 builtin->minProgramTexelOffset = -8;
118 builtin->maxProgramTexelOffset = 7;
119 builtin->maxClipDistances = 8;
120 builtin->maxComputeWorkGroupCountX = 65535;
121 builtin->maxComputeWorkGroupCountY = 65535;
122 builtin->maxComputeWorkGroupCountZ = 65535;
123 builtin->maxComputeWorkGroupSizeX = 1024;
124 builtin->maxComputeWorkGroupSizeY = 1024;
125 builtin->maxComputeWorkGroupSizeZ = 64;
126 builtin->maxComputeUniformComponents = 1024;
127 builtin->maxComputeTextureImageUnits = 16;
128 builtin->maxComputeImageUniforms = 8;
129 builtin->maxComputeAtomicCounters = 8;
130 builtin->maxComputeAtomicCounterBuffers = 1;
131 builtin->maxVaryingComponents = 60;
132 builtin->maxVertexOutputComponents = 64;
133 builtin->maxGeometryInputComponents = 64;
134 builtin->maxGeometryOutputComponents = 128;
135 builtin->maxFragmentInputComponents = 128;
136 builtin->maxImageUnits = 8;
137 builtin->maxCombinedImageUnitsAndFragmentOutputs = 8;
138 builtin->maxCombinedShaderOutputResources = 8;
139 builtin->maxImageSamples = 0;
140 builtin->maxVertexImageUniforms = 0;
141 builtin->maxTessControlImageUniforms = 0;
142 builtin->maxTessEvaluationImageUniforms = 0;
143 builtin->maxGeometryImageUniforms = 0;
144 builtin->maxFragmentImageUniforms = 8;
145 builtin->maxCombinedImageUniforms = 8;
146 builtin->maxGeometryTextureImageUnits = 16;
147 builtin->maxGeometryOutputVertices = 256;
148 builtin->maxGeometryTotalOutputComponents = 1024;
149 builtin->maxGeometryUniformComponents = 1024;
150 builtin->maxGeometryVaryingComponents = 64;
151 builtin->maxTessControlInputComponents = 128;
152 builtin->maxTessControlOutputComponents = 128;
153 builtin->maxTessControlTextureImageUnits = 16;
154 builtin->maxTessControlUniformComponents = 1024;
155 builtin->maxTessControlTotalOutputComponents = 4096;
156 builtin->maxTessEvaluationInputComponents = 128;
157 builtin->maxTessEvaluationOutputComponents = 128;
158 builtin->maxTessEvaluationTextureImageUnits = 16;
159 builtin->maxTessEvaluationUniformComponents = 1024;
160 builtin->maxTessPatchComponents = 120;
161 builtin->maxPatchVertices = 32;
162 builtin->maxTessGenLevel = 64;
163 builtin->maxViewports = 16;
164 builtin->maxVertexAtomicCounters = 0;
165 builtin->maxTessControlAtomicCounters = 0;
166 builtin->maxTessEvaluationAtomicCounters = 0;
167 builtin->maxGeometryAtomicCounters = 0;
168 builtin->maxFragmentAtomicCounters = 8;
169 builtin->maxCombinedAtomicCounters = 8;
170 builtin->maxAtomicCounterBindings = 1;
171 builtin->maxVertexAtomicCounterBuffers = 0;
172 builtin->maxTessControlAtomicCounterBuffers = 0;
173 builtin->maxTessEvaluationAtomicCounterBuffers = 0;
174 builtin->maxGeometryAtomicCounterBuffers = 0;
175 builtin->maxFragmentAtomicCounterBuffers = 1;
176 builtin->maxCombinedAtomicCounterBuffers = 1;
177 builtin->maxAtomicCounterBufferSize = 16384;
178 builtin->maxTransformFeedbackBuffers = 4;
179 builtin->maxTransformFeedbackInterleavedComponents = 64;
180 builtin->maxCullDistances = 8;
181 builtin->maxCombinedClipAndCullDistances = 8;
182 builtin->maxSamples = 4;
183 builtin->maxMeshOutputVerticesNV = 256;
184 builtin->maxMeshOutputPrimitivesNV = 256;
185 builtin->maxMeshWorkGroupSizeX_NV = 32;
186 builtin->maxMeshWorkGroupSizeY_NV = 1;
187 builtin->maxMeshWorkGroupSizeZ_NV = 1;
188 builtin->maxTaskWorkGroupSizeX_NV = 32;
189 builtin->maxTaskWorkGroupSizeY_NV = 1;
190 builtin->maxTaskWorkGroupSizeZ_NV = 1;
191 builtin->maxMeshViewCountNV = 4;
192 builtin->maxDualSourceDrawBuffersEXT = 1;
195 glslang::EShTargetLanguageVersion getSpirvTargetVersion(SpirvVersion version)
200 DE_FATAL("unhandled SPIRV target version");
202 case SPIRV_VERSION_1_0:
203 return glslang::EShTargetSpv_1_0;
204 case SPIRV_VERSION_1_1:
205 return glslang::EShTargetSpv_1_1;
206 case SPIRV_VERSION_1_2:
207 return glslang::EShTargetSpv_1_2;
208 case SPIRV_VERSION_1_3:
209 return glslang::EShTargetSpv_1_3;
213 bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst, SpirvVersion version)
215 TBuiltInResource builtinRes;
218 getDefaultBuiltInResources(&builtinRes);
220 const EShLanguage shaderStage = getGlslangStage(type);
222 glslang::TShader shader(shaderStage);
223 glslang::TProgram program;
225 const char* src[] = { source.c_str() };
227 shader.setStrings(src, 1);
228 shader.setEnvTarget(glslang::EshTargetSpv, getSpirvTargetVersion(version));
229 program.addShader(&shader);
231 const int compileRes = shader.parse(&builtinRes, 100, false, EShMsgSpvRules);
234 const int linkRes = program.link(EShMsgSpvRules);
238 const glslang::TIntermediate* const intermediate = program.getIntermediate(shaderStage);
239 glslang::GlslangToSpv(*intermediate, *dst);
245 log << tcu::TestLog::Message << "Program linking error:\n"
246 << program.getInfoLog() << "\n"
249 << tcu::TestLog::EndMessage;
254 log << tcu::TestLog::Message << "Shader compilation error:\n"
255 << shader.getInfoLog() << "\n"
258 << tcu::TestLog::EndMessage;
264 void consumer(spv_message_level_t, const char*, const spv_position_t&, const char* m)
266 std::cerr << "error: " << m << std::endl;
269 void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
271 spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
273 core.SetMessageConsumer(consumer);
275 if (!core.Assemble(src, &dst))
276 TCU_THROW(InternalError, "Failed to assemble Spir-V source.");
279 void spirvDisassemble(std::string& dst, const ShaderBinaryDataType& src)
281 spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
283 core.SetMessageConsumer(consumer);
285 if (!core.Disassemble(src, &dst))
286 TCU_THROW(InternalError, "Failed to disassemble Spir-V module.");
289 bool spirvValidate(ShaderBinaryDataType& dst, bool throwOnError)
291 spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
294 core.SetMessageConsumer(consumer);
296 if (!core.Validate(dst))
299 TCU_THROW(InternalError, "Failed to validate Spir-V module.");
306 ShaderBinary makeSpirV(tcu::TestLog& log, ShaderSource source, SpirvVersion version)
310 if (!spirvUtils::compileGlslToSpirV(log, source.source, source.shaderType, &binary.binary, version))
311 TCU_THROW(InternalError, "Failed to convert GLSL to Spir-V");
313 binary << source.shaderType << "main";
318 /** Verifying if GLSL to SpirV mapping was performed correctly
320 * @param glslSource GLSL shader template
321 * @param spirVSource SpirV disassembled source
322 * @param mappings Glsl to SpirV mappings vector
323 * @param anyOf any occurence indicator
325 * @return true if GLSL code occurs as many times as all of SpirV code for each mapping if anyOf is false
326 * or true if SpirV code occurs at least once if GLSL code found, false otherwise.
328 bool verifyMappings(std::string glslSource, std::string spirVSource, SpirVMapping& mappings, bool anyOf)
330 std::vector<std::string> spirVSourceLines = de::splitString(spirVSource, '\n');
332 // Iterate through all glsl functions
333 for (SpirVMapping::iterator it = mappings.begin(); it != mappings.end(); it++)
335 int glslCodeCount = 0;
336 int spirVCodeCount = 0;
338 // To avoid finding functions with similar names (ie. "cos", "acos", "cosh")
339 // add characteristic characters that delimits finding results
340 std::string glslCode = it->first;
342 // Count GLSL code occurrences in GLSL source
343 size_t codePosition = glslSource.find(glslCode);
344 while (codePosition != std::string::npos)
347 codePosition = glslSource.find(glslCode, codePosition + 1);
350 if (glslCodeCount > 0)
352 // Count all SpirV code variants occurrences in SpirV source
353 for (int s = 0; s < (signed)it->second.size(); ++s)
355 std::vector<std::string> spirVCodes = de::splitString(it->second[s], ' ');
357 for (int v = 0; v < (signed)spirVSourceLines.size(); ++v)
359 std::vector<std::string> spirVLineCodes = de::splitString(spirVSourceLines[v], ' ');
361 bool matchAll = true;
362 for (int j = 0; j < (signed)spirVCodes.size(); ++j)
365 for (int i = 0; i < (signed)spirVLineCodes.size(); ++i)
367 if (spirVLineCodes[i] == spirVCodes[j])
371 matchAll = matchAll && match;
379 // Check if both counts match
380 if (anyOf && (glslCodeCount > 0 && spirVCodeCount == 0))
382 else if (!anyOf && glslCodeCount != spirVCodeCount)
390 } // namespace spirvUtils