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 Program utilities.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "vkPrograms.hpp"
     25 #include "vkGlslToSpirV.hpp"
     26 #include "vkSpirVAsm.hpp"
     27 #include "vkRefUtil.hpp"
     28 
     29 #include "tcuTestLog.hpp"
     30 
     31 #include "deArrayUtil.hpp"
     32 #include "deMemory.h"
     33 #include "deInt32.h"
     34 
     35 namespace vk
     36 {
     37 
     38 using std::string;
     39 using std::vector;
     40 using tcu::TestLog;
     41 
     42 #if defined(DE_DEBUG) && defined(DEQP_HAVE_SPIRV_TOOLS)
     43 #	define VALIDATE_BINARIES	true
     44 #else
     45 #	define VALIDATE_BINARIES	false
     46 #endif
     47 
     48 #define SPIRV_BINARY_ENDIANNESS DE_LITTLE_ENDIAN
     49 
     50 // ProgramBinary
     51 
     52 ProgramBinary::ProgramBinary (ProgramFormat format, size_t binarySize, const deUint8* binary)
     53 	: m_format	(format)
     54 	, m_binary	(binary, binary+binarySize)
     55 {
     56 }
     57 
     58 // Utils
     59 
     60 namespace
     61 {
     62 
     63 bool isNativeSpirVBinaryEndianness (void)
     64 {
     65 #if (DE_ENDIANNESS == SPIRV_BINARY_ENDIANNESS)
     66 	return true;
     67 #else
     68 	return false;
     69 #endif
     70 }
     71 
     72 bool isSaneSpirVBinary (const ProgramBinary& binary)
     73 {
     74 	const deUint32	spirvMagicWord	= 0x07230203;
     75 	const deUint32	spirvMagicBytes	= isNativeSpirVBinaryEndianness()
     76 									? spirvMagicWord
     77 									: deReverseBytes32(spirvMagicWord);
     78 
     79 	DE_ASSERT(binary.getFormat() == PROGRAM_FORMAT_SPIRV);
     80 
     81 	if (binary.getSize() % sizeof(deUint32) != 0)
     82 		return false;
     83 
     84 	if (binary.getSize() < sizeof(deUint32))
     85 		return false;
     86 
     87 	if (*(const deUint32*)binary.getBinary() != spirvMagicBytes)
     88 		return false;
     89 
     90 	return true;
     91 }
     92 
     93 ProgramBinary* createProgramBinaryFromSpirV (const vector<deUint32>& binary)
     94 {
     95 	DE_ASSERT(!binary.empty());
     96 
     97 	if (isNativeSpirVBinaryEndianness())
     98 		return new ProgramBinary(PROGRAM_FORMAT_SPIRV, binary.size()*sizeof(deUint32), (const deUint8*)&binary[0]);
     99 	else
    100 		TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
    101 }
    102 
    103 } // anonymous
    104 
    105 ProgramBinary* buildProgram (const glu::ProgramSources& program, ProgramFormat binaryFormat, glu::ShaderProgramInfo* buildInfo)
    106 {
    107 	const bool	validateBinary	= VALIDATE_BINARIES;
    108 
    109 	if (binaryFormat == PROGRAM_FORMAT_SPIRV)
    110 	{
    111 		vector<deUint32> binary;
    112 
    113 		{
    114 			vector<deUint32> nonStrippedBinary;
    115 
    116 			if (!compileGlslToSpirV(program, &nonStrippedBinary, buildInfo))
    117 				TCU_THROW(InternalError, "Compiling GLSL to SPIR-V failed");
    118 
    119 			TCU_CHECK_INTERNAL(!nonStrippedBinary.empty());
    120 			stripSpirVDebugInfo(nonStrippedBinary.size(), &nonStrippedBinary[0], &binary);
    121 			TCU_CHECK_INTERNAL(!binary.empty());
    122 		}
    123 
    124 		if (validateBinary)
    125 		{
    126 			std::ostringstream validationLog;
    127 
    128 			if (!validateSpirV(binary.size(), &binary[0], &validationLog))
    129 			{
    130 				buildInfo->program.linkOk	 = false;
    131 				buildInfo->program.infoLog	+= "\n" + validationLog.str();
    132 
    133 				TCU_THROW(InternalError, "Validation failed for compiled SPIR-V binary");
    134 			}
    135 		}
    136 
    137 		return createProgramBinaryFromSpirV(binary);
    138 	}
    139 	else
    140 		TCU_THROW(NotSupportedError, "Unsupported program format");
    141 }
    142 
    143 ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo)
    144 {
    145 	const bool			validateBinary		= VALIDATE_BINARIES;
    146 	vector<deUint32>	binary;
    147 
    148 	if (!assembleSpirV(&program, &binary, buildInfo))
    149 		TCU_THROW(InternalError, "Failed to assemble SPIR-V");
    150 
    151 	if (validateBinary)
    152 	{
    153 		std::ostringstream	validationLog;
    154 
    155 		if (!validateSpirV(binary.size(), &binary[0], &validationLog))
    156 		{
    157 			buildInfo->compileOk	 = false;
    158 			buildInfo->infoLog		+= "\n" + validationLog.str();
    159 
    160 			TCU_THROW(InternalError, "Validation failed for assembled SPIR-V binary");
    161 		}
    162 	}
    163 
    164 	return createProgramBinaryFromSpirV(binary);
    165 }
    166 
    167 void disassembleProgram (const ProgramBinary& program, std::ostream* dst)
    168 {
    169 	if (program.getFormat() == PROGRAM_FORMAT_SPIRV)
    170 	{
    171 		TCU_CHECK_INTERNAL(isSaneSpirVBinary(program));
    172 
    173 		if (isNativeSpirVBinaryEndianness())
    174 			disassembleSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst);
    175 		else
    176 			TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
    177 	}
    178 	else
    179 		TCU_THROW(NotSupportedError, "Unsupported program format");
    180 }
    181 
    182 bool validateProgram (const ProgramBinary& program, std::ostream* dst)
    183 {
    184 	if (program.getFormat() == PROGRAM_FORMAT_SPIRV)
    185 	{
    186 		if (!isSaneSpirVBinary(program))
    187 		{
    188 			*dst << "Binary doesn't look like SPIR-V at all";
    189 			return false;
    190 		}
    191 
    192 		if (isNativeSpirVBinaryEndianness())
    193 			return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst);
    194 		else
    195 			TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
    196 	}
    197 	else
    198 		TCU_THROW(NotSupportedError, "Unsupported program format");
    199 }
    200 
    201 Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags)
    202 {
    203 	if (binary.getFormat() == PROGRAM_FORMAT_SPIRV)
    204 	{
    205 		const struct VkShaderModuleCreateInfo		shaderModuleInfo	=
    206 		{
    207 			VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
    208 			DE_NULL,
    209 			flags,
    210 			(deUintptr)binary.getSize(),
    211 			(const deUint32*)binary.getBinary(),
    212 		};
    213 
    214 		return createShaderModule(deviceInterface, device, &shaderModuleInfo);
    215 	}
    216 	else
    217 		TCU_THROW(NotSupportedError, "Unsupported program format");
    218 }
    219 
    220 glu::ShaderType getGluShaderType (VkShaderStageFlagBits shaderStage)
    221 {
    222 	switch (shaderStage)
    223 	{
    224 		case VK_SHADER_STAGE_VERTEX_BIT:					return glu::SHADERTYPE_VERTEX;
    225 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return glu::SHADERTYPE_TESSELLATION_CONTROL;
    226 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return glu::SHADERTYPE_TESSELLATION_EVALUATION;
    227 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return glu::SHADERTYPE_GEOMETRY;
    228 		case VK_SHADER_STAGE_FRAGMENT_BIT:					return glu::SHADERTYPE_FRAGMENT;
    229 		case VK_SHADER_STAGE_COMPUTE_BIT:					return glu::SHADERTYPE_COMPUTE;
    230 		default:
    231 			DE_FATAL("Unknown shader stage");
    232 			return glu::SHADERTYPE_LAST;
    233 	}
    234 }
    235 
    236 VkShaderStageFlagBits getVkShaderStage (glu::ShaderType shaderType)
    237 {
    238 	static const VkShaderStageFlagBits s_shaderStages[] =
    239 	{
    240 		VK_SHADER_STAGE_VERTEX_BIT,
    241 		VK_SHADER_STAGE_FRAGMENT_BIT,
    242 		VK_SHADER_STAGE_GEOMETRY_BIT,
    243 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
    244 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
    245 		VK_SHADER_STAGE_COMPUTE_BIT
    246 	};
    247 
    248 	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(s_shaderStages, shaderType);
    249 }
    250 
    251 } // vk
    252