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