• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Shading language (GLSL/HLSL) to SPIR-V.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkShaderToSpirV.hpp"
25 #include "deArrayUtil.hpp"
26 #include "deSingleton.h"
27 #include "deMemory.h"
28 #include "deClock.h"
29 #include "qpDebugOut.h"
30 
31 #include "SPIRV/GlslangToSpv.h"
32 #include "SPIRV/disassemble.h"
33 #include "SPIRV/SPVRemapper.h"
34 #include "SPIRV/doc.h"
35 #include "glslang/Include/InfoSink.h"
36 #include "glslang/Include/ShHandle.h"
37 #include "glslang/MachineIndependent/localintermediate.h"
38 #include "glslang/Public/ShaderLang.h"
39 
40 namespace vk
41 {
42 
43 using std::string;
44 using std::vector;
45 
46 namespace
47 {
48 
getGlslangStage(glu::ShaderType type)49 EShLanguage getGlslangStage (glu::ShaderType type)
50 {
51 	static const EShLanguage stageMap[] =
52 	{
53 		EShLangVertex,
54 		EShLangFragment,
55 		EShLangGeometry,
56 		EShLangTessControl,
57 		EShLangTessEvaluation,
58 		EShLangCompute,
59 		EShLangRayGen,
60 		EShLangAnyHit,
61 		EShLangClosestHit,
62 		EShLangMiss,
63 		EShLangIntersect,
64 		EShLangCallable,
65 		EShLangTaskNV,
66 		EShLangMeshNV,
67 	};
68 	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
69 }
70 
71 static volatile deSingletonState	s_glslangInitState	= DE_SINGLETON_STATE_NOT_INITIALIZED;
72 
initGlslang(void *)73 void initGlslang (void*)
74 {
75 	// Main compiler
76 	glslang::InitializeProcess();
77 
78 	// SPIR-V disassembly
79 	spv::Parameterize();
80 }
81 
prepareGlslang(void)82 void prepareGlslang (void)
83 {
84 	deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
85 }
86 
87 // \todo [2015-06-19 pyry] Specialize these per GLSL version
88 
89 // Fail compilation if more members are added to TLimits or TBuiltInResource
90 struct LimitsSizeHelper_s			{ bool m0, m1, m2, m3, m4, m5, m6, m7, m8; };
91 struct BuiltInResourceSizeHelper_s	{ int m[102]; LimitsSizeHelper_s l; };
92 
93 DE_STATIC_ASSERT(sizeof(TLimits)			== sizeof(LimitsSizeHelper_s));
94 DE_STATIC_ASSERT(sizeof(TBuiltInResource)	== sizeof(BuiltInResourceSizeHelper_s));
95 
getDefaultLimits(TLimits * limits)96 void getDefaultLimits (TLimits* limits)
97 {
98 	limits->nonInductiveForLoops					= true;
99 	limits->whileLoops								= true;
100 	limits->doWhileLoops							= true;
101 	limits->generalUniformIndexing					= true;
102 	limits->generalAttributeMatrixVectorIndexing	= true;
103 	limits->generalVaryingIndexing					= true;
104 	limits->generalSamplerIndexing					= true;
105 	limits->generalVariableIndexing					= true;
106 	limits->generalConstantMatrixVectorIndexing		= true;
107 }
108 
getDefaultBuiltInResources(TBuiltInResource * builtin)109 void getDefaultBuiltInResources (TBuiltInResource* builtin)
110 {
111 	getDefaultLimits(&builtin->limits);
112 
113 	builtin->maxLights									= 32;
114 	builtin->maxClipPlanes								= 6;
115 	builtin->maxTextureUnits							= 32;
116 	builtin->maxTextureCoords							= 32;
117 	builtin->maxVertexAttribs							= 64;
118 	builtin->maxVertexUniformComponents					= 4096;
119 	builtin->maxVaryingFloats							= 64;
120 	builtin->maxVertexTextureImageUnits					= 32;
121 	builtin->maxCombinedTextureImageUnits				= 80;
122 	builtin->maxTextureImageUnits						= 32;
123 	builtin->maxFragmentUniformComponents				= 4096;
124 	builtin->maxDrawBuffers								= 32;
125 	builtin->maxVertexUniformVectors					= 128;
126 	builtin->maxVaryingVectors							= 8;
127 	builtin->maxFragmentUniformVectors					= 16;
128 	builtin->maxVertexOutputVectors						= 16;
129 	builtin->maxFragmentInputVectors					= 15;
130 	builtin->minProgramTexelOffset						= -8;
131 	builtin->maxProgramTexelOffset						= 7;
132 	builtin->maxClipDistances							= 8;
133 	builtin->maxComputeWorkGroupCountX					= 65535;
134 	builtin->maxComputeWorkGroupCountY					= 65535;
135 	builtin->maxComputeWorkGroupCountZ					= 65535;
136 	builtin->maxComputeWorkGroupSizeX					= 1024;
137 	builtin->maxComputeWorkGroupSizeY					= 1024;
138 	builtin->maxComputeWorkGroupSizeZ					= 64;
139 	builtin->maxComputeUniformComponents				= 1024;
140 	builtin->maxComputeTextureImageUnits				= 16;
141 	builtin->maxComputeImageUniforms					= 8;
142 	builtin->maxComputeAtomicCounters					= 8;
143 	builtin->maxComputeAtomicCounterBuffers				= 1;
144 	builtin->maxVaryingComponents						= 60;
145 	builtin->maxVertexOutputComponents					= 64;
146 	builtin->maxGeometryInputComponents					= 64;
147 	builtin->maxGeometryOutputComponents				= 128;
148 	builtin->maxFragmentInputComponents					= 128;
149 	builtin->maxImageUnits								= 8;
150 	builtin->maxCombinedImageUnitsAndFragmentOutputs	= 8;
151 	builtin->maxCombinedShaderOutputResources			= 8;
152 	builtin->maxImageSamples							= 0;
153 	builtin->maxVertexImageUniforms						= 0;
154 	builtin->maxTessControlImageUniforms				= 0;
155 	builtin->maxTessEvaluationImageUniforms				= 0;
156 	builtin->maxGeometryImageUniforms					= 0;
157 	builtin->maxFragmentImageUniforms					= 8;
158 	builtin->maxCombinedImageUniforms					= 8;
159 	builtin->maxGeometryTextureImageUnits				= 16;
160 	builtin->maxGeometryOutputVertices					= 256;
161 	builtin->maxGeometryTotalOutputComponents			= 1024;
162 	builtin->maxGeometryUniformComponents				= 1024;
163 	builtin->maxGeometryVaryingComponents				= 64;
164 	builtin->maxTessControlInputComponents				= 128;
165 	builtin->maxTessControlOutputComponents				= 128;
166 	builtin->maxTessControlTextureImageUnits			= 16;
167 	builtin->maxTessControlUniformComponents			= 1024;
168 	builtin->maxTessControlTotalOutputComponents		= 4096;
169 	builtin->maxTessEvaluationInputComponents			= 128;
170 	builtin->maxTessEvaluationOutputComponents			= 128;
171 	builtin->maxTessEvaluationTextureImageUnits			= 16;
172 	builtin->maxTessEvaluationUniformComponents			= 1024;
173 	builtin->maxTessPatchComponents						= 120;
174 	builtin->maxPatchVertices							= 32;
175 	builtin->maxTessGenLevel							= 64;
176 	builtin->maxViewports								= 16;
177 	builtin->maxVertexAtomicCounters					= 0;
178 	builtin->maxTessControlAtomicCounters				= 0;
179 	builtin->maxTessEvaluationAtomicCounters			= 0;
180 	builtin->maxGeometryAtomicCounters					= 0;
181 	builtin->maxFragmentAtomicCounters					= 8;
182 	builtin->maxCombinedAtomicCounters					= 8;
183 	builtin->maxAtomicCounterBindings					= 1;
184 	builtin->maxVertexAtomicCounterBuffers				= 0;
185 	builtin->maxTessControlAtomicCounterBuffers			= 0;
186 	builtin->maxTessEvaluationAtomicCounterBuffers		= 0;
187 	builtin->maxGeometryAtomicCounterBuffers			= 0;
188 	builtin->maxFragmentAtomicCounterBuffers			= 1;
189 	builtin->maxCombinedAtomicCounterBuffers			= 1;
190 	builtin->maxAtomicCounterBufferSize					= 16384;
191 	builtin->maxTransformFeedbackBuffers				= 8;
192 	builtin->maxTransformFeedbackInterleavedComponents	= 16382;
193 	builtin->maxCullDistances							= 8;
194 	builtin->maxCombinedClipAndCullDistances			= 8;
195 	builtin->maxSamples									= 4;
196 	builtin->maxMeshOutputVerticesNV					= 2048;
197 	builtin->maxMeshOutputPrimitivesNV					= 2048;
198 	builtin->maxMeshWorkGroupSizeX_NV					= 256;
199 	builtin->maxMeshWorkGroupSizeY_NV					= 1;
200 	builtin->maxMeshWorkGroupSizeZ_NV					= 1;
201 	builtin->maxTaskWorkGroupSizeX_NV					= 1024;
202 	builtin->maxTaskWorkGroupSizeY_NV					= 1;
203 	builtin->maxTaskWorkGroupSizeZ_NV					= 1;
204 	builtin->maxMeshViewCountNV							= 4;
205 	builtin->maxMeshOutputVerticesEXT					= 2048;
206 	builtin->maxMeshOutputPrimitivesEXT					= 2048;
207 	builtin->maxMeshWorkGroupSizeX_EXT					= 256;
208 	builtin->maxMeshWorkGroupSizeY_EXT					= 256;
209 	builtin->maxMeshWorkGroupSizeZ_EXT					= 256;
210 	builtin->maxTaskWorkGroupSizeX_EXT					= 256;
211 	builtin->maxTaskWorkGroupSizeY_EXT					= 256;
212 	builtin->maxTaskWorkGroupSizeZ_EXT					= 256;
213 	builtin->maxMeshViewCountEXT						= 4;
214 	builtin->maxDualSourceDrawBuffersEXT				= 1;
215 };
216 
getNumShaderStages(const std::vector<std::string> * sources)217 int getNumShaderStages (const std::vector<std::string>* sources)
218 {
219 	int numShaderStages = 0;
220 
221 	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; ++shaderType)
222 	{
223 		if (!sources[shaderType].empty())
224 			numShaderStages += 1;
225 	}
226 
227 	return numShaderStages;
228 }
229 
getShaderStageSource(const std::vector<std::string> * sources,const ShaderBuildOptions buildOptions,glu::ShaderType shaderType)230 std::string getShaderStageSource (const std::vector<std::string>* sources, const ShaderBuildOptions buildOptions, glu::ShaderType shaderType)
231 {
232 	if (sources[shaderType].size() != 1)
233 		TCU_THROW(InternalError, "Linking multiple compilation units is not supported");
234 
235 	if ((buildOptions.flags & ShaderBuildOptions::FLAG_USE_STORAGE_BUFFER_STORAGE_CLASS) != 0)
236 	{
237 		// Hack to inject #pragma right after first #version statement
238 		std::string src			= sources[shaderType][0];
239 		size_t		injectPos	= 0;
240 
241 		if (de::beginsWith(src, "#version"))
242 			injectPos = src.find('\n') + 1;
243 
244 		src.insert(injectPos, "#pragma use_storage_buffer\n");
245 
246 		return src;
247 	}
248 	else
249 		return sources[shaderType][0];
250 }
251 
getCompileFlags(const ShaderBuildOptions & buildOpts,const ShaderLanguage shaderLanguage)252 EShMessages getCompileFlags (const ShaderBuildOptions& buildOpts, const ShaderLanguage shaderLanguage)
253 {
254 	EShMessages		flags	= (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules);
255 
256 	if ((buildOpts.flags & ShaderBuildOptions::FLAG_ALLOW_RELAXED_OFFSETS) != 0)
257 		flags = (EShMessages)(flags | EShMsgHlslOffsets);
258 
259 	if (shaderLanguage == SHADER_LANGUAGE_HLSL)
260 		flags = (EShMessages)(flags | EShMsgReadHlsl);
261 
262 	return flags;
263 }
264 
265 } // anonymous
266 
compileShaderToSpirV(const std::vector<std::string> * sources,const ShaderBuildOptions & buildOptions,const ShaderLanguage shaderLanguage,std::vector<deUint32> * dst,glu::ShaderProgramInfo * buildInfo)267 bool compileShaderToSpirV (const std::vector<std::string>* sources, const ShaderBuildOptions& buildOptions, const ShaderLanguage shaderLanguage, std::vector<deUint32>* dst, glu::ShaderProgramInfo* buildInfo)
268 {
269 	TBuiltInResource	builtinRes = {};
270 	const EShMessages	compileFlags	= getCompileFlags(buildOptions, shaderLanguage);
271 
272 	if (buildOptions.targetVersion >= SPIRV_VERSION_LAST)
273 		TCU_THROW(InternalError, "Unsupported SPIR-V target version");
274 
275 	if (getNumShaderStages(sources) > 1)
276 		TCU_THROW(InternalError, "Linking multiple shader stages into a single SPIR-V binary is not supported");
277 
278 	prepareGlslang();
279 	getDefaultBuiltInResources(&builtinRes);
280 
281 	// \note Compiles only first found shader
282 	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
283 	{
284 		if (!sources[shaderType].empty())
285 		{
286 			const std::string&		srcText				= getShaderStageSource(sources, buildOptions, (glu::ShaderType)shaderType);
287 			const char*				srcPtrs[]			= { srcText.c_str() };
288 			const EShLanguage		shaderStage			= getGlslangStage(glu::ShaderType(shaderType));
289 			glslang::TShader		shader				(shaderStage);
290 			glslang::TProgram		glslangProgram;
291 
292 			shader.setStrings(srcPtrs, DE_LENGTH_OF_ARRAY(srcPtrs));
293 
294 			switch ( buildOptions.targetVersion )
295 			{
296 			case SPIRV_VERSION_1_0:
297 				shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10000);
298 				break;
299 			case SPIRV_VERSION_1_1:
300 				shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10100);
301 				break;
302 			case SPIRV_VERSION_1_2:
303 				shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10200);
304 				break;
305 			case SPIRV_VERSION_1_3:
306 				shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10300);
307 				break;
308 			case SPIRV_VERSION_1_4:
309 				shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10400);
310 				break;
311 			case SPIRV_VERSION_1_5:
312 				shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10500);
313 				break;
314 			case SPIRV_VERSION_1_6:
315 				shader.setEnvTarget(glslang::EshTargetSpv, (glslang::EShTargetLanguageVersion)0x10600);
316 				break;
317 			default:
318 				TCU_THROW(InternalError, "Unsupported SPIR-V target version");
319 			}
320 
321 			glslangProgram.addShader(&shader);
322 
323 			if (shaderLanguage == SHADER_LANGUAGE_HLSL)
324 			{
325 				// Entry point assumed to be named main.
326 				shader.setEntryPoint("main");
327 			}
328 
329 			{
330 				const deUint64	compileStartTime	= deGetMicroseconds();
331 				const int		compileRes			= shader.parse(&builtinRes, 110, false, compileFlags);
332 				glu::ShaderInfo	shaderBuildInfo;
333 
334 				shaderBuildInfo.type			= (glu::ShaderType)shaderType;
335 				shaderBuildInfo.source			= srcText;
336 				shaderBuildInfo.infoLog			= shader.getInfoLog(); // \todo [2015-07-13 pyry] Include debug log?
337 				shaderBuildInfo.compileTimeUs	= deGetMicroseconds()-compileStartTime;
338 				shaderBuildInfo.compileOk		= (compileRes != 0);
339 
340 				buildInfo->shaders.push_back(shaderBuildInfo);
341 			}
342 
343 			DE_ASSERT(buildInfo->shaders.size() == 1);
344 			if (buildInfo->shaders[0].compileOk)
345 			{
346 				const deUint64	linkStartTime	= deGetMicroseconds();
347 				const int		linkRes			= glslangProgram.link(compileFlags);
348 
349 				buildInfo->program.infoLog		= glslangProgram.getInfoLog(); // \todo [2015-11-05 scygan] Include debug log?
350 				buildInfo->program.linkOk		= (linkRes != 0);
351 				buildInfo->program.linkTimeUs	= deGetMicroseconds()-linkStartTime;
352 			}
353 
354 			if (buildInfo->program.linkOk)
355 			{
356 				const glslang::TIntermediate* const	intermediate	= glslangProgram.getIntermediate(shaderStage);
357 				glslang::GlslangToSpv(*intermediate, *dst);
358 			}
359 
360 			return buildInfo->program.linkOk;
361 		}
362 	}
363 
364 	TCU_THROW(InternalError, "Can't compile empty program");
365 }
366 
compileGlslToSpirV(const GlslSource & program,std::vector<deUint32> * dst,glu::ShaderProgramInfo * buildInfo)367 bool compileGlslToSpirV (const GlslSource& program, std::vector<deUint32>* dst, glu::ShaderProgramInfo* buildInfo)
368 {
369 	return compileShaderToSpirV(program.sources, program.buildOptions, program.shaderLanguage, dst, buildInfo);
370 }
371 
compileHlslToSpirV(const HlslSource & program,std::vector<deUint32> * dst,glu::ShaderProgramInfo * buildInfo)372 bool compileHlslToSpirV (const HlslSource& program, std::vector<deUint32>* dst, glu::ShaderProgramInfo* buildInfo)
373 {
374 	return compileShaderToSpirV(program.sources, program.buildOptions, program.shaderLanguage, dst, buildInfo);
375 }
376 
stripSpirVDebugInfo(const size_t numSrcInstrs,const deUint32 * srcInstrs,std::vector<deUint32> * dst)377 void stripSpirVDebugInfo (const size_t numSrcInstrs, const deUint32* srcInstrs, std::vector<deUint32>* dst)
378 {
379 	spv::spirvbin_t remapper;
380 	std::vector<std::string> whiteListStrings;
381 
382 	// glslang operates in-place
383 	dst->resize(numSrcInstrs);
384 	std::copy(srcInstrs, srcInstrs+numSrcInstrs, dst->begin());
385 	remapper.remap(*dst, whiteListStrings, spv::spirvbin_base_t::STRIP);
386 }
387 
388 } // vk
389