1 /*-------------------------------------------------------------------------
2  * Vulkan CTS Framework
3  * --------------------
4  *
5  * Copyright (c) 2015 Google 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
21  * \brief GLSL to SPIR-V.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkGlslToSpirV.hpp"
25 #include "deArrayUtil.hpp"
26 #include "deMutex.hpp"
27 #include "deSingleton.h"
28 #include "deMemory.h"
29 #include "deClock.h"
30 #include "qpDebugOut.h"
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/Include/InfoSink.h"
37 #	include "glslang/Include/ShHandle.h"
38 #	include "glslang/MachineIndependent/localintermediate.h"
39 #	include "glslang/Public/ShaderLang.h"
40 #endif
41 
42 namespace vk
43 {
44 
45 using std::string;
46 using std::vector;
47 
48 #if defined(DEQP_HAVE_GLSLANG)
49 
50 namespace
51 {
52 
getGlslangStage(glu::ShaderType type)53 EShLanguage getGlslangStage (glu::ShaderType type)
54 {
55 	static const EShLanguage stageMap[] =
56 	{
57 		EShLangVertex,
58 		EShLangFragment,
59 		EShLangGeometry,
60 		EShLangTessControl,
61 		EShLangTessEvaluation,
62 		EShLangCompute,
63 	};
64 	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
65 }
66 
67 static volatile deSingletonState	s_glslangInitState	= DE_SINGLETON_STATE_NOT_INITIALIZED;
68 static de::Mutex					s_glslangLock;
69 
initGlslang(void *)70 void initGlslang (void*)
71 {
72 	// Main compiler
73 	glslang::InitializeProcess();
74 
75 	// SPIR-V disassembly
76 	spv::Parameterize();
77 }
78 
prepareGlslang(void)79 void prepareGlslang (void)
80 {
81 	deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
82 }
83 
84 // \todo [2015-06-19 pyry] Specialize these per GLSL version
85 
86 // Fail compilation if more members are added to TLimits or TBuiltInResource
87 struct LimitsSizeHelper_s			{ bool m0, m1, m2, m3, m4, m5, m6, m7, m8; };
88 struct BuiltInResourceSizeHelper_s	{ int m[83]; LimitsSizeHelper_s l; };
89 
90 DE_STATIC_ASSERT(sizeof(TLimits)			== sizeof(LimitsSizeHelper_s));
91 DE_STATIC_ASSERT(sizeof(TBuiltInResource)	== sizeof(BuiltInResourceSizeHelper_s));
92 
getDefaultLimits(TLimits * limits)93 void getDefaultLimits (TLimits* limits)
94 {
95 	limits->nonInductiveForLoops					= true;
96 	limits->whileLoops								= true;
97 	limits->doWhileLoops							= true;
98 	limits->generalUniformIndexing					= true;
99 	limits->generalAttributeMatrixVectorIndexing	= true;
100 	limits->generalVaryingIndexing					= true;
101 	limits->generalSamplerIndexing					= true;
102 	limits->generalVariableIndexing					= true;
103 	limits->generalConstantMatrixVectorIndexing		= true;
104 }
105 
getDefaultBuiltInResources(TBuiltInResource * builtin)106 void getDefaultBuiltInResources (TBuiltInResource* builtin)
107 {
108 	getDefaultLimits(&builtin->limits);
109 
110 	builtin->maxLights									= 32;
111 	builtin->maxClipPlanes								= 6;
112 	builtin->maxTextureUnits							= 32;
113 	builtin->maxTextureCoords							= 32;
114 	builtin->maxVertexAttribs							= 64;
115 	builtin->maxVertexUniformComponents					= 4096;
116 	builtin->maxVaryingFloats							= 64;
117 	builtin->maxVertexTextureImageUnits					= 32;
118 	builtin->maxCombinedTextureImageUnits				= 80;
119 	builtin->maxTextureImageUnits						= 32;
120 	builtin->maxFragmentUniformComponents				= 4096;
121 	builtin->maxDrawBuffers								= 32;
122 	builtin->maxVertexUniformVectors					= 128;
123 	builtin->maxVaryingVectors							= 8;
124 	builtin->maxFragmentUniformVectors					= 16;
125 	builtin->maxVertexOutputVectors						= 16;
126 	builtin->maxFragmentInputVectors					= 15;
127 	builtin->minProgramTexelOffset						= -8;
128 	builtin->maxProgramTexelOffset						= 7;
129 	builtin->maxClipDistances							= 8;
130 	builtin->maxComputeWorkGroupCountX					= 65535;
131 	builtin->maxComputeWorkGroupCountY					= 65535;
132 	builtin->maxComputeWorkGroupCountZ					= 65535;
133 	builtin->maxComputeWorkGroupSizeX					= 1024;
134 	builtin->maxComputeWorkGroupSizeY					= 1024;
135 	builtin->maxComputeWorkGroupSizeZ					= 64;
136 	builtin->maxComputeUniformComponents				= 1024;
137 	builtin->maxComputeTextureImageUnits				= 16;
138 	builtin->maxComputeImageUniforms					= 8;
139 	builtin->maxComputeAtomicCounters					= 8;
140 	builtin->maxComputeAtomicCounterBuffers				= 1;
141 	builtin->maxVaryingComponents						= 60;
142 	builtin->maxVertexOutputComponents					= 64;
143 	builtin->maxGeometryInputComponents					= 64;
144 	builtin->maxGeometryOutputComponents				= 128;
145 	builtin->maxFragmentInputComponents					= 128;
146 	builtin->maxImageUnits								= 8;
147 	builtin->maxCombinedImageUnitsAndFragmentOutputs	= 8;
148 	builtin->maxCombinedShaderOutputResources			= 8;
149 	builtin->maxImageSamples							= 0;
150 	builtin->maxVertexImageUniforms						= 0;
151 	builtin->maxTessControlImageUniforms				= 0;
152 	builtin->maxTessEvaluationImageUniforms				= 0;
153 	builtin->maxGeometryImageUniforms					= 0;
154 	builtin->maxFragmentImageUniforms					= 8;
155 	builtin->maxCombinedImageUniforms					= 8;
156 	builtin->maxGeometryTextureImageUnits				= 16;
157 	builtin->maxGeometryOutputVertices					= 256;
158 	builtin->maxGeometryTotalOutputComponents			= 1024;
159 	builtin->maxGeometryUniformComponents				= 1024;
160 	builtin->maxGeometryVaryingComponents				= 64;
161 	builtin->maxTessControlInputComponents				= 128;
162 	builtin->maxTessControlOutputComponents				= 128;
163 	builtin->maxTessControlTextureImageUnits			= 16;
164 	builtin->maxTessControlUniformComponents			= 1024;
165 	builtin->maxTessControlTotalOutputComponents		= 4096;
166 	builtin->maxTessEvaluationInputComponents			= 128;
167 	builtin->maxTessEvaluationOutputComponents			= 128;
168 	builtin->maxTessEvaluationTextureImageUnits			= 16;
169 	builtin->maxTessEvaluationUniformComponents			= 1024;
170 	builtin->maxTessPatchComponents						= 120;
171 	builtin->maxPatchVertices							= 32;
172 	builtin->maxTessGenLevel							= 64;
173 	builtin->maxViewports								= 16;
174 	builtin->maxVertexAtomicCounters					= 0;
175 	builtin->maxTessControlAtomicCounters				= 0;
176 	builtin->maxTessEvaluationAtomicCounters			= 0;
177 	builtin->maxGeometryAtomicCounters					= 0;
178 	builtin->maxFragmentAtomicCounters					= 8;
179 	builtin->maxCombinedAtomicCounters					= 8;
180 	builtin->maxAtomicCounterBindings					= 1;
181 	builtin->maxVertexAtomicCounterBuffers				= 0;
182 	builtin->maxTessControlAtomicCounterBuffers			= 0;
183 	builtin->maxTessEvaluationAtomicCounterBuffers		= 0;
184 	builtin->maxGeometryAtomicCounterBuffers			= 0;
185 	builtin->maxFragmentAtomicCounterBuffers			= 1;
186 	builtin->maxCombinedAtomicCounterBuffers			= 1;
187 	builtin->maxAtomicCounterBufferSize					= 16384;
188 	builtin->maxTransformFeedbackBuffers				= 4;
189 	builtin->maxTransformFeedbackInterleavedComponents	= 64;
190 	builtin->maxCullDistances							= 8;
191 	builtin->maxCombinedClipAndCullDistances			= 8;
192 	builtin->maxSamples									= 4;
193 };
194 
195 } // anonymous
196 
getNumShaderStages(const glu::ProgramSources & program)197 int getNumShaderStages (const glu::ProgramSources& program)
198 {
199 	int numShaderStages = 0;
200 
201 	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; ++shaderType)
202 	{
203 		if (!program.sources[shaderType].empty())
204 			numShaderStages += 1;
205 	}
206 
207 	return numShaderStages;
208 }
209 
compileGlslToSpirV(const glu::ProgramSources & program,std::vector<deUint32> * dst,glu::ShaderProgramInfo * buildInfo)210 bool compileGlslToSpirV (const glu::ProgramSources& program, std::vector<deUint32>* dst, glu::ShaderProgramInfo* buildInfo)
211 {
212 	TBuiltInResource	builtinRes;
213 
214 	if (getNumShaderStages(program) > 1)
215 		TCU_THROW(InternalError, "Linking multiple shader stages into a single SPIR-V binary is not supported");
216 
217 	prepareGlslang();
218 	getDefaultBuiltInResources(&builtinRes);
219 
220 	// \note Compiles only first found shader
221 	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
222 	{
223 		if (!program.sources[shaderType].empty())
224 		{
225 			const de::ScopedLock	compileLock			(s_glslangLock);
226 			const std::string&		srcText				= program.sources[shaderType][0];
227 			const char*				srcPtrs[]			= { srcText.c_str() };
228 			const int				srcLengths[]		= { (int)srcText.size() };
229 			const EShLanguage		shaderStage			= getGlslangStage(glu::ShaderType(shaderType));
230 			glslang::TShader		shader				(shaderStage);
231 			glslang::TProgram		program;
232 
233 			shader.setStrings(srcPtrs, DE_LENGTH_OF_ARRAY(srcPtrs));
234 			program.addShader(&shader);
235 
236 			{
237 				const deUint64	compileStartTime	= deGetMicroseconds();
238 				const int		compileRes			= shader.parse(&builtinRes, 110, false, (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules));
239 				glu::ShaderInfo	shaderBuildInfo;
240 
241 				shaderBuildInfo.type			= (glu::ShaderType)shaderType;
242 				shaderBuildInfo.source			= srcText;
243 				shaderBuildInfo.infoLog			= shader.getInfoLog(); // \todo [2015-07-13 pyry] Include debug log?
244 				shaderBuildInfo.compileTimeUs	= deGetMicroseconds()-compileStartTime;
245 				shaderBuildInfo.compileOk		= (compileRes != 0);
246 
247 				buildInfo->shaders.push_back(shaderBuildInfo);
248 			}
249 
250 			DE_ASSERT(buildInfo->shaders.size() == 1);
251 			if (buildInfo->shaders[0].compileOk)
252 			{
253 				const deUint64	linkStartTime	= deGetMicroseconds();
254 				const int		linkRes			= program.link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules));
255 
256 				buildInfo->program.infoLog		= program.getInfoLog(); // \todo [2015-11-05 scygan] Include debug log?
257 				buildInfo->program.linkOk		= (linkRes != 0);
258 				buildInfo->program.linkTimeUs	= deGetMicroseconds()-linkStartTime;
259 			}
260 
261 			if (buildInfo->program.linkOk)
262 			{
263 				const glslang::TIntermediate* const	intermediate	= program.getIntermediate(shaderStage);
264 				glslang::GlslangToSpv(*intermediate, *dst);
265 			}
266 
267 			return buildInfo->program.linkOk;
268 		}
269 	}
270 
271 	TCU_THROW(InternalError, "Can't compile empty program");
272 }
273 
274 #else // defined(DEQP_HAVE_GLSLANG)
275 
compileGlslToSpirV(const glu::ProgramSources &,std::vector<deUint32> *,glu::ShaderProgramInfo *)276 bool compileGlslToSpirV (const glu::ProgramSources&, std::vector<deUint32>*, glu::ShaderProgramInfo*)
277 {
278 	TCU_THROW(NotSupportedError, "GLSL to SPIR-V compilation not supported (DEQP_HAVE_GLSLANG not defined)");
279 }
280 
281 #endif // defined(DEQP_HAVE_GLSLANG)
282 
283 } // vk
284