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