• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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[] = {
61 		EShLangVertex, EShLangFragment, EShLangGeometry, EShLangTessControl, EShLangTessEvaluation, EShLangCompute,
62 		EShLangRayGen, EShLangAnyHit, EShLangClosestHit, EShLangMiss, EShLangIntersect, EShLangCallable, EShLangTaskNV,
63 		EShLangMeshNV
64 	};
65 
66 	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
67 }
68 
69 static volatile deSingletonState s_glslangInitState = DE_SINGLETON_STATE_NOT_INITIALIZED;
70 
initGlslang(void *)71 void initGlslang(void*)
72 {
73 	// Main compiler
74 	glslang::InitializeProcess();
75 
76 	// SPIR-V disassembly
77 	spv::Parameterize();
78 }
79 
prepareGlslang(void)80 void prepareGlslang(void)
81 {
82 	deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
83 }
84 
getDefaultLimits(TLimits * limits)85 void getDefaultLimits(TLimits* limits)
86 {
87 	limits->nonInductiveForLoops				 = true;
88 	limits->whileLoops							 = true;
89 	limits->doWhileLoops						 = true;
90 	limits->generalUniformIndexing				 = true;
91 	limits->generalAttributeMatrixVectorIndexing = true;
92 	limits->generalVaryingIndexing				 = true;
93 	limits->generalSamplerIndexing				 = true;
94 	limits->generalVariableIndexing				 = true;
95 	limits->generalConstantMatrixVectorIndexing  = true;
96 }
97 
getDefaultBuiltInResources(TBuiltInResource * builtin)98 void getDefaultBuiltInResources(TBuiltInResource* builtin)
99 {
100 	getDefaultLimits(&builtin->limits);
101 
102 	builtin->maxLights								   = 32;
103 	builtin->maxClipPlanes							   = 6;
104 	builtin->maxTextureUnits						   = 32;
105 	builtin->maxTextureCoords						   = 32;
106 	builtin->maxVertexAttribs						   = 64;
107 	builtin->maxVertexUniformComponents				   = 4096;
108 	builtin->maxVaryingFloats						   = 64;
109 	builtin->maxVertexTextureImageUnits				   = 32;
110 	builtin->maxCombinedTextureImageUnits			   = 80;
111 	builtin->maxTextureImageUnits					   = 32;
112 	builtin->maxFragmentUniformComponents			   = 4096;
113 	builtin->maxDrawBuffers							   = 32;
114 	builtin->maxVertexUniformVectors				   = 128;
115 	builtin->maxVaryingVectors						   = 8;
116 	builtin->maxFragmentUniformVectors				   = 16;
117 	builtin->maxVertexOutputVectors					   = 16;
118 	builtin->maxFragmentInputVectors				   = 15;
119 	builtin->minProgramTexelOffset					   = -8;
120 	builtin->maxProgramTexelOffset					   = 7;
121 	builtin->maxClipDistances						   = 8;
122 	builtin->maxComputeWorkGroupCountX				   = 65535;
123 	builtin->maxComputeWorkGroupCountY				   = 65535;
124 	builtin->maxComputeWorkGroupCountZ				   = 65535;
125 	builtin->maxComputeWorkGroupSizeX				   = 1024;
126 	builtin->maxComputeWorkGroupSizeY				   = 1024;
127 	builtin->maxComputeWorkGroupSizeZ				   = 64;
128 	builtin->maxComputeUniformComponents			   = 1024;
129 	builtin->maxComputeTextureImageUnits			   = 16;
130 	builtin->maxComputeImageUniforms				   = 8;
131 	builtin->maxComputeAtomicCounters				   = 8;
132 	builtin->maxComputeAtomicCounterBuffers			   = 1;
133 	builtin->maxVaryingComponents					   = 60;
134 	builtin->maxVertexOutputComponents				   = 64;
135 	builtin->maxGeometryInputComponents				   = 64;
136 	builtin->maxGeometryOutputComponents			   = 128;
137 	builtin->maxFragmentInputComponents				   = 128;
138 	builtin->maxImageUnits							   = 8;
139 	builtin->maxCombinedImageUnitsAndFragmentOutputs   = 8;
140 	builtin->maxCombinedShaderOutputResources		   = 8;
141 	builtin->maxImageSamples						   = 0;
142 	builtin->maxVertexImageUniforms					   = 0;
143 	builtin->maxTessControlImageUniforms			   = 0;
144 	builtin->maxTessEvaluationImageUniforms			   = 0;
145 	builtin->maxGeometryImageUniforms				   = 0;
146 	builtin->maxFragmentImageUniforms				   = 8;
147 	builtin->maxCombinedImageUniforms				   = 8;
148 	builtin->maxGeometryTextureImageUnits			   = 16;
149 	builtin->maxGeometryOutputVertices				   = 256;
150 	builtin->maxGeometryTotalOutputComponents		   = 1024;
151 	builtin->maxGeometryUniformComponents			   = 1024;
152 	builtin->maxGeometryVaryingComponents			   = 64;
153 	builtin->maxTessControlInputComponents			   = 128;
154 	builtin->maxTessControlOutputComponents			   = 128;
155 	builtin->maxTessControlTextureImageUnits		   = 16;
156 	builtin->maxTessControlUniformComponents		   = 1024;
157 	builtin->maxTessControlTotalOutputComponents	   = 4096;
158 	builtin->maxTessEvaluationInputComponents		   = 128;
159 	builtin->maxTessEvaluationOutputComponents		   = 128;
160 	builtin->maxTessEvaluationTextureImageUnits		   = 16;
161 	builtin->maxTessEvaluationUniformComponents		   = 1024;
162 	builtin->maxTessPatchComponents					   = 120;
163 	builtin->maxPatchVertices						   = 32;
164 	builtin->maxTessGenLevel						   = 64;
165 	builtin->maxViewports							   = 16;
166 	builtin->maxVertexAtomicCounters				   = 0;
167 	builtin->maxTessControlAtomicCounters			   = 0;
168 	builtin->maxTessEvaluationAtomicCounters		   = 0;
169 	builtin->maxGeometryAtomicCounters				   = 0;
170 	builtin->maxFragmentAtomicCounters				   = 8;
171 	builtin->maxCombinedAtomicCounters				   = 8;
172 	builtin->maxAtomicCounterBindings				   = 1;
173 	builtin->maxVertexAtomicCounterBuffers			   = 0;
174 	builtin->maxTessControlAtomicCounterBuffers		   = 0;
175 	builtin->maxTessEvaluationAtomicCounterBuffers	 = 0;
176 	builtin->maxGeometryAtomicCounterBuffers		   = 0;
177 	builtin->maxFragmentAtomicCounterBuffers		   = 1;
178 	builtin->maxCombinedAtomicCounterBuffers		   = 1;
179 	builtin->maxAtomicCounterBufferSize				   = 16384;
180 	builtin->maxTransformFeedbackBuffers			   = 4;
181 	builtin->maxTransformFeedbackInterleavedComponents = 64;
182 	builtin->maxCullDistances						   = 8;
183 	builtin->maxCombinedClipAndCullDistances		   = 8;
184 	builtin->maxSamples								   = 4;
185 	builtin->maxMeshOutputVerticesNV				   = 256;
186 	builtin->maxMeshOutputPrimitivesNV				   = 256;
187 	builtin->maxMeshWorkGroupSizeX_NV				   = 32;
188 	builtin->maxMeshWorkGroupSizeY_NV				   = 1;
189 	builtin->maxMeshWorkGroupSizeZ_NV				   = 1;
190 	builtin->maxTaskWorkGroupSizeX_NV				   = 32;
191 	builtin->maxTaskWorkGroupSizeY_NV				   = 1;
192 	builtin->maxTaskWorkGroupSizeZ_NV				   = 1;
193 	builtin->maxMeshViewCountNV						   = 4;
194 	builtin->maxDualSourceDrawBuffersEXT			   = 1;
195 };
196 
getSpirvTargetVersion(SpirvVersion version)197 glslang::EShTargetLanguageVersion getSpirvTargetVersion(SpirvVersion version)
198 {
199     switch(version)
200     {
201     default:
202         DE_FATAL("unhandled SPIRV target version");
203         // fall-through
204     case SPIRV_VERSION_1_0:
205         return glslang::EShTargetSpv_1_0;
206     case SPIRV_VERSION_1_1:
207         return glslang::EShTargetSpv_1_1;
208     case SPIRV_VERSION_1_2:
209         return glslang::EShTargetSpv_1_2;
210     case SPIRV_VERSION_1_3:
211         return glslang::EShTargetSpv_1_3;
212     }
213 }
214 
compileGlslToSpirV(tcu::TestLog & log,std::string source,glu::ShaderType type,ShaderBinaryDataType * dst,SpirvVersion version)215 bool compileGlslToSpirV(tcu::TestLog& log, std::string source, glu::ShaderType type, ShaderBinaryDataType* dst, 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