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 #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
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
53 void checkGlSpirvSupported(deqp::Context& m_context)
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");
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");
62 #if defined DEQP_HAVE_GLSLANG
64 EShLanguage getGlslangStage(glu::ShaderType type)
66 static const EShLanguage stageMap[] = {
67 EShLangVertex, EShLangFragment, EShLangGeometry, EShLangTessControl, EShLangTessEvaluation, EShLangCompute,
70 return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
73 static volatile deSingletonState s_glslangInitState = DE_SINGLETON_STATE_NOT_INITIALIZED;
75 void initGlslang(void*)
78 glslang::InitializeProcess();
84 void prepareGlslang(void)
86 deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
89 void getDefaultLimits(TLimits* limits)
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;
102 void getDefaultBuiltInResources(TBuiltInResource* builtin)
104 getDefaultLimits(&builtin->limits);
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;
200 glslang::EShTargetLanguageVersion getSpirvTargetVersion(SpirvVersion version)
205 DE_FATAL("unhandled SPIRV target version");
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;
218 bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst, SpirvVersion version)
220 TBuiltInResource builtinRes;
223 getDefaultBuiltInResources(&builtinRes);
225 const EShLanguage shaderStage = getGlslangStage(type);
227 glslang::TShader shader(shaderStage);
228 glslang::TProgram program;
230 const char* src[] = { source.c_str() };
232 shader.setStrings(src, 1);
233 shader.setEnvTarget(glslang::EshTargetSpv, getSpirvTargetVersion(version));
234 program.addShader(&shader);
236 const int compileRes = shader.parse(&builtinRes, 100, false, EShMsgSpvRules);
239 const int linkRes = program.link(EShMsgSpvRules);
243 const glslang::TIntermediate* const intermediate = program.getIntermediate(shaderStage);
244 glslang::GlslangToSpv(*intermediate, *dst);
250 log << tcu::TestLog::Message << "Program linking error:\n"
251 << program.getInfoLog() << "\n"
254 << tcu::TestLog::EndMessage;
259 log << tcu::TestLog::Message << "Shader compilation error:\n"
260 << shader.getInfoLog() << "\n"
263 << tcu::TestLog::EndMessage;
269 #else // DEQP_HAVE_GLSLANG
271 bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst)
278 TCU_THROW(InternalError, "Glslang not available.");
283 #endif // DEQP_HAVE_GLSLANG
285 #if defined DEQP_HAVE_SPIRV_TOOLS
287 void consumer(spv_message_level_t, const char*, const spv_position_t&, const char* m)
289 std::cerr << "error: " << m << std::endl;
292 void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
294 spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
296 core.SetMessageConsumer(consumer);
298 if (!core.Assemble(src, &dst))
299 TCU_THROW(InternalError, "Failed to assemble Spir-V source.");
302 void spirvDisassemble(std::string& dst, const ShaderBinaryDataType& src)
304 spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
306 core.SetMessageConsumer(consumer);
308 if (!core.Disassemble(src, &dst))
309 TCU_THROW(InternalError, "Failed to disassemble Spir-V module.");
312 bool spirvValidate(ShaderBinaryDataType& dst, bool throwOnError)
314 spvtools::SpirvTools core(SPV_ENV_OPENGL_4_5);
317 core.SetMessageConsumer(consumer);
319 if (!core.Validate(dst))
322 TCU_THROW(InternalError, "Failed to validate Spir-V module.");
329 #else //DEQP_HAVE_SPIRV_TOOLS
331 void spirvAssemble(ShaderBinaryDataType& dst, const std::string& src)
336 TCU_THROW(InternalError, "Spirv-tools not available.");
339 void spirvDisassemble(std::string& dst, ShaderBinaryDataType& src)
344 TCU_THROW(InternalError, "Spirv-tools not available.");
347 bool spirvValidate(ShaderBinaryDataType& dst, bool throwOnError)
350 DE_UNREF(throwOnError);
352 TCU_THROW(InternalError, "Spirv-tools not available.");
355 #endif // DEQP_HAVE_SPIRV_TOOLS
357 ShaderBinary makeSpirV(tcu::TestLog& log, ShaderSource source, SpirvVersion version)
361 if (!spirvUtils::compileGlslToSpirV(log, source.source, source.shaderType, &binary.binary, version))
362 TCU_THROW(InternalError, "Failed to convert GLSL to Spir-V");
364 binary << source.shaderType << "main";
369 /** Verifying if GLSL to SpirV mapping was performed correctly
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
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.
379 bool verifyMappings(std::string glslSource, std::string spirVSource, SpirVMapping& mappings, bool anyOf)
381 std::vector<std::string> spirVSourceLines = de::splitString(spirVSource, '\n');
383 // Iterate through all glsl functions
384 for (SpirVMapping::iterator it = mappings.begin(); it != mappings.end(); it++)
386 int glslCodeCount = 0;
387 int spirVCodeCount = 0;
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;
393 // Count GLSL code occurrences in GLSL source
394 size_t codePosition = glslSource.find(glslCode);
395 while (codePosition != std::string::npos)
398 codePosition = glslSource.find(glslCode, codePosition + 1);
401 if (glslCodeCount > 0)
403 // Count all SpirV code variants occurrences in SpirV source
404 for (int s = 0; s < (signed)it->second.size(); ++s)
406 std::vector<std::string> spirVCodes = de::splitString(it->second[s], ' ');
408 for (int v = 0; v < (signed)spirVSourceLines.size(); ++v)
410 std::vector<std::string> spirVLineCodes = de::splitString(spirVSourceLines[v], ' ');
412 bool matchAll = true;
413 for (int j = 0; j < (signed)spirVCodes.size(); ++j)
416 for (int i = 0; i < (signed)spirVLineCodes.size(); ++i)
418 if (spirVLineCodes[i] == spirVCodes[j])
422 matchAll = matchAll && match;
430 // Check if both counts match
431 if (anyOf && (glslCodeCount > 0 && spirVCodeCount == 0))
433 else if (!anyOf && glslCodeCount != spirVCodeCount)
441 } // namespace spirvUtils