Home | History | Annotate | Download | only in vulkan
      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