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