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