vkGlslToSpirV.cpp revision 601a13635971626206a988077de52e8db405c419
1/*-------------------------------------------------------------------------
2 * Vulkan CTS Framework
3 * --------------------
4 *
5 * Copyright (c) 2015 Google Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and/or associated documentation files (the
9 * "Materials"), to deal in the Materials without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Materials, and to
12 * permit persons to whom the Materials are furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice(s) and this permission notice shall be
16 * included in all copies or substantial portions of the Materials.
17 *
18 * The Materials are Confidential Information as defined by the
19 * Khronos Membership Agreement until designated non-confidential by
20 * Khronos, at which point this condition clause shall be removed.
21 *
22 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
29 *
30 *//*!
31 * \file
32 * \brief GLSL to SPIR-V.
33 *//*--------------------------------------------------------------------*/
34
35#include "vkGlslToSpirV.hpp"
36#include "deArrayUtil.hpp"
37#include "deMemory.h"
38#include "deClock.h"
39#include "qpDebugOut.h"
40
41#if defined(DEQP_HAVE_GLSLANG)
42#	include "deSingleton.h"
43#	include "deMutex.hpp"
44
45#	include "SPIRV/GlslangToSpv.h"
46#	include "SPIRV/disassemble.h"
47#	include "SPIRV/GLSL450Lib.h"
48#	include "SPIRV/doc.h"
49#	include "glslang/Include/InfoSink.h"
50#	include "glslang/Include/ShHandle.h"
51#	include "glslang/MachineIndependent/localintermediate.h"
52#	include "glslang/Public/ShaderLang.h"
53
54// Required by SPIR-V disassembler
55const char* GlslStd450DebugNames[GLSL_STD_450::Count];
56
57#endif
58
59namespace vk
60{
61
62using std::string;
63using std::vector;
64
65#if defined(DEQP_HAVE_GLSLANG)
66
67namespace
68{
69
70EShLanguage getGlslangStage (glu::ShaderType type)
71{
72	static const EShLanguage stageMap[] =
73	{
74		EShLangVertex,
75		EShLangFragment,
76		EShLangGeometry,
77		EShLangTessControl,
78		EShLangTessEvaluation,
79		EShLangCompute,
80	};
81	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(stageMap, type);
82}
83
84static volatile deSingletonState	s_glslangInitState	= DE_SINGLETON_STATE_NOT_INITIALIZED;
85static de::Mutex					s_glslangLock;
86
87void initGlslang (void*)
88{
89	// Main compiler
90	ShInitialize();
91
92	// SPIR-V disassembly
93	spv::Parameterize();
94	GLSL_STD_450::GetDebugNames(GlslStd450DebugNames);
95}
96
97void prepareGlslang (void)
98{
99	deInitSingleton(&s_glslangInitState, initGlslang, DE_NULL);
100}
101
102class SpvGenerator : public TCompiler
103{
104public:
105	SpvGenerator (EShLanguage language, std::vector<deUint32>& dst, TInfoSink& infoSink)
106		: TCompiler	(language, infoSink)
107		, m_dst		(dst)
108	{
109	}
110
111	bool compile (TIntermNode* root, int version = 0, EProfile profile = ENoProfile)
112	{
113		glslang::TIntermediate intermediate(getLanguage(), version, profile);
114		intermediate.setTreeRoot(root);
115		glslang::GlslangToSpv(intermediate, m_dst);
116		return true;
117	}
118
119private:
120	std::vector<deUint32>&	m_dst;
121};
122
123// \todo [2015-06-19 pyry] Specialize these per GLSL version
124
125// Fail compilation if more members are added to TLimits or TBuiltInResource
126struct LimitsSizeHelper_s			{ bool m0, m1, m2, m3, m4, m5, m6, m7, m8; };
127struct BuiltInResourceSizeHelper_s	{ int m[83]; LimitsSizeHelper_s l; };
128
129DE_STATIC_ASSERT(sizeof(TLimits)			== sizeof(LimitsSizeHelper_s));
130DE_STATIC_ASSERT(sizeof(TBuiltInResource)	== sizeof(BuiltInResourceSizeHelper_s));
131
132void getDefaultLimits (TLimits* limits)
133{
134	limits->nonInductiveForLoops					= true;
135	limits->whileLoops								= true;
136	limits->doWhileLoops							= true;
137	limits->generalUniformIndexing					= true;
138	limits->generalAttributeMatrixVectorIndexing	= true;
139	limits->generalVaryingIndexing					= true;
140	limits->generalSamplerIndexing					= true;
141	limits->generalVariableIndexing					= true;
142	limits->generalConstantMatrixVectorIndexing		= true;
143}
144
145void getDefaultBuiltInResources (TBuiltInResource* builtin)
146{
147	getDefaultLimits(&builtin->limits);
148
149	builtin->maxLights									= 32;
150	builtin->maxClipPlanes								= 6;
151	builtin->maxTextureUnits							= 32;
152	builtin->maxTextureCoords							= 32;
153	builtin->maxVertexAttribs							= 64;
154	builtin->maxVertexUniformComponents					= 4096;
155	builtin->maxVaryingFloats							= 64;
156	builtin->maxVertexTextureImageUnits					= 32;
157	builtin->maxCombinedTextureImageUnits				= 80;
158	builtin->maxTextureImageUnits						= 32;
159	builtin->maxFragmentUniformComponents				= 4096;
160	builtin->maxDrawBuffers								= 32;
161	builtin->maxVertexUniformVectors					= 128;
162	builtin->maxVaryingVectors							= 8;
163	builtin->maxFragmentUniformVectors					= 16;
164	builtin->maxVertexOutputVectors						= 16;
165	builtin->maxFragmentInputVectors					= 15;
166	builtin->minProgramTexelOffset						= -8;
167	builtin->maxProgramTexelOffset						= 7;
168	builtin->maxClipDistances							= 8;
169	builtin->maxComputeWorkGroupCountX					= 65535;
170	builtin->maxComputeWorkGroupCountY					= 65535;
171	builtin->maxComputeWorkGroupCountZ					= 65535;
172	builtin->maxComputeWorkGroupSizeX					= 1024;
173	builtin->maxComputeWorkGroupSizeX					= 1024;
174	builtin->maxComputeWorkGroupSizeZ					= 64;
175	builtin->maxComputeUniformComponents				= 1024;
176	builtin->maxComputeTextureImageUnits				= 16;
177	builtin->maxComputeImageUniforms					= 8;
178	builtin->maxComputeAtomicCounters					= 8;
179	builtin->maxComputeAtomicCounterBuffers				= 1;
180	builtin->maxVaryingComponents						= 60;
181	builtin->maxVertexOutputComponents					= 64;
182	builtin->maxGeometryInputComponents					= 64;
183	builtin->maxGeometryOutputComponents				= 128;
184	builtin->maxFragmentInputComponents					= 128;
185	builtin->maxImageUnits								= 8;
186	builtin->maxCombinedImageUnitsAndFragmentOutputs	= 8;
187	builtin->maxCombinedShaderOutputResources			= 8;
188	builtin->maxImageSamples							= 0;
189	builtin->maxVertexImageUniforms						= 0;
190	builtin->maxTessControlImageUniforms				= 0;
191	builtin->maxTessEvaluationImageUniforms				= 0;
192	builtin->maxGeometryImageUniforms					= 0;
193	builtin->maxFragmentImageUniforms					= 8;
194	builtin->maxCombinedImageUniforms					= 8;
195	builtin->maxGeometryTextureImageUnits				= 16;
196	builtin->maxGeometryOutputVertices					= 256;
197	builtin->maxGeometryTotalOutputComponents			= 1024;
198	builtin->maxGeometryUniformComponents				= 1024;
199	builtin->maxGeometryVaryingComponents				= 64;
200	builtin->maxTessControlInputComponents				= 128;
201	builtin->maxTessControlOutputComponents				= 128;
202	builtin->maxTessControlTextureImageUnits			= 16;
203	builtin->maxTessControlUniformComponents			= 1024;
204	builtin->maxTessControlTotalOutputComponents		= 4096;
205	builtin->maxTessEvaluationInputComponents			= 128;
206	builtin->maxTessEvaluationOutputComponents			= 128;
207	builtin->maxTessEvaluationTextureImageUnits			= 16;
208	builtin->maxTessEvaluationUniformComponents			= 1024;
209	builtin->maxTessPatchComponents						= 120;
210	builtin->maxPatchVertices							= 32;
211	builtin->maxTessGenLevel							= 64;
212	builtin->maxViewports								= 16;
213	builtin->maxVertexAtomicCounters					= 0;
214	builtin->maxTessControlAtomicCounters				= 0;
215	builtin->maxTessEvaluationAtomicCounters			= 0;
216	builtin->maxGeometryAtomicCounters					= 0;
217	builtin->maxFragmentAtomicCounters					= 8;
218	builtin->maxCombinedAtomicCounters					= 8;
219	builtin->maxAtomicCounterBindings					= 1;
220	builtin->maxVertexAtomicCounterBuffers				= 0;
221	builtin->maxTessControlAtomicCounterBuffers			= 0;
222	builtin->maxTessEvaluationAtomicCounterBuffers		= 0;
223	builtin->maxGeometryAtomicCounterBuffers			= 0;
224	builtin->maxFragmentAtomicCounterBuffers			= 1;
225	builtin->maxCombinedAtomicCounterBuffers			= 1;
226	builtin->maxAtomicCounterBufferSize					= 16384;
227	builtin->maxTransformFeedbackBuffers				= 4;
228	builtin->maxTransformFeedbackInterleavedComponents	= 64;
229	builtin->maxCullDistances							= 8;
230	builtin->maxCombinedClipAndCullDistances			= 8;
231	builtin->maxSamples									= 4;
232};
233
234} // anonymous
235
236void glslToSpirV (const glu::ProgramSources& program, std::vector<deUint8>* dst, glu::ShaderProgramInfo* buildInfo)
237{
238	TBuiltInResource	builtinRes;
239
240	prepareGlslang();
241	getDefaultBuiltInResources(&builtinRes);
242
243	// \note Compiles only first found shader
244	for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
245	{
246		if (!program.sources[shaderType].empty())
247		{
248			de::ScopedLock		compileLock			(s_glslangLock);
249			const std::string&	srcText				= program.sources[shaderType][0];
250			const char*			srcPtrs[]			= { srcText.c_str() };
251			int					srcLengths[]		= { (int)srcText.size() };
252			vector<deUint32>	spvBlob;
253			TInfoSink			infoSink;
254			SpvGenerator		compiler			(getGlslangStage(glu::ShaderType(shaderType)), spvBlob, infoSink);
255			const deUint64		compileStartTime	= deGetMicroseconds();
256			const int			compileOk			= ShCompile(static_cast<ShHandle>(&compiler), srcPtrs, DE_LENGTH_OF_ARRAY(srcPtrs), srcLengths, EShOptNone, &builtinRes, 0);
257
258			{
259				glu::ShaderInfo	shaderBuildInfo;
260
261				shaderBuildInfo.type			= (glu::ShaderType)shaderType;
262				shaderBuildInfo.source			= srcText;
263				shaderBuildInfo.infoLog			= infoSink.info.c_str(); // \todo [2015-07-13 pyry] Include debug log?
264				shaderBuildInfo.compileTimeUs	= deGetMicroseconds()-compileStartTime;
265				shaderBuildInfo.compileOk		= (compileOk != 0);
266
267				buildInfo->shaders.push_back(shaderBuildInfo);
268			}
269
270			buildInfo->program.infoLog		= "(No linking performed)";
271			buildInfo->program.linkOk		= (compileOk != 0);
272			buildInfo->program.linkTimeUs	= 0;
273
274			if (compileOk == 0)
275				TCU_FAIL("Failed to compile shader");
276
277			dst->resize(spvBlob.size() * sizeof(deUint32));
278#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
279			deMemcpy(&(*dst)[0], &spvBlob[0], dst->size());
280#else
281#	error "Big-endian not supported"
282#endif
283
284			return;
285		}
286	}
287
288	TCU_THROW(InternalError, "Can't compile empty program");
289}
290
291void disassembleSpirV (size_t binarySize, const deUint8* binary, std::ostream* dst)
292{
293	std::vector<deUint32>	binForDisasm	(binarySize/4);
294
295	DE_ASSERT(binarySize%4 == 0);
296
297#if (DE_ENDIANNESS == DE_LITTLE_ENDIAN)
298	deMemcpy(&binForDisasm[0], binary, binarySize);
299#else
300#	error "Big-endian not supported"
301#endif
302
303	spv::Disassemble(*dst, binForDisasm);
304}
305
306#else // defined(DEQP_HAVE_GLSLANG)
307
308void glslToSpirV (const glu::ProgramSources&, std::vector<deUint8>*, glu::ShaderProgramInfo*)
309{
310	TCU_THROW(NotSupportedError, "GLSL to SPIR-V compilation not supported (DEQP_HAVE_GLSLANG not defined)");
311}
312
313void disassembleSpirV (size_t, const deUint8*, std::ostream*)
314{
315	TCU_THROW(NotSupportedError, "SPIR-V disassembling not supported (DEQP_HAVE_GLSLANG not defined)");
316}
317
318#endif
319
320} // vk
321