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 		if (!compileGlslToSpirV(program, &binary, buildInfo))
    114 			TCU_THROW(InternalError, "Compiling GLSL to SPIR-V failed");
    115 
    116 		if (validateBinary)
    117 		{
    118 			std::ostringstream validationLog;
    119 
    120 			if (!validateSpirV(binary.size(), &binary[0], &validationLog))
    121 			{
    122 				buildInfo->program.linkOk 	 = false;
    123 				buildInfo->program.infoLog	+= "\n" + validationLog.str();
    124 
    125 				TCU_THROW(InternalError, "Validation failed for compiled SPIR-V binary");
    126 			}
    127 		}
    128 
    129 		return createProgramBinaryFromSpirV(binary);
    130 	}
    131 	else
    132 		TCU_THROW(NotSupportedError, "Unsupported program format");
    133 }
    134 
    135 ProgramBinary* assembleProgram (const SpirVAsmSource& program, SpirVProgramInfo* buildInfo)
    136 {
    137 	const bool			validateBinary		= VALIDATE_BINARIES;
    138 	vector<deUint32>	binary;
    139 
    140 	if (!assembleSpirV(&program, &binary, buildInfo))
    141 		TCU_THROW(InternalError, "Failed to assemble SPIR-V");
    142 
    143 	if (validateBinary)
    144 	{
    145 		std::ostringstream	validationLog;
    146 
    147 		if (!validateSpirV(binary.size(), &binary[0], &validationLog))
    148 		{
    149 			buildInfo->compileOk	 = false;
    150 			buildInfo->infoLog		+= "\n" + validationLog.str();
    151 
    152 			TCU_THROW(InternalError, "Validation failed for assembled SPIR-V binary");
    153 		}
    154 	}
    155 
    156 	return createProgramBinaryFromSpirV(binary);
    157 }
    158 
    159 void disassembleProgram (const ProgramBinary& program, std::ostream* dst)
    160 {
    161 	if (program.getFormat() == PROGRAM_FORMAT_SPIRV)
    162 	{
    163 		TCU_CHECK_INTERNAL(isSaneSpirVBinary(program));
    164 
    165 		if (isNativeSpirVBinaryEndianness())
    166 			disassembleSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst);
    167 		else
    168 			TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
    169 	}
    170 	else
    171 		TCU_THROW(NotSupportedError, "Unsupported program format");
    172 }
    173 
    174 bool validateProgram (const ProgramBinary& program, std::ostream* dst)
    175 {
    176 	if (program.getFormat() == PROGRAM_FORMAT_SPIRV)
    177 	{
    178 		if (!isSaneSpirVBinary(program))
    179 		{
    180 			*dst << "Binary doesn't look like SPIR-V at all";
    181 			return false;
    182 		}
    183 
    184 		if (isNativeSpirVBinaryEndianness())
    185 			return validateSpirV(program.getSize()/sizeof(deUint32), (const deUint32*)program.getBinary(), dst);
    186 		else
    187 			TCU_THROW(InternalError, "SPIR-V endianness translation not supported");
    188 	}
    189 	else
    190 		TCU_THROW(NotSupportedError, "Unsupported program format");
    191 }
    192 
    193 Move<VkShaderModule> createShaderModule (const DeviceInterface& deviceInterface, VkDevice device, const ProgramBinary& binary, VkShaderModuleCreateFlags flags)
    194 {
    195 	if (binary.getFormat() == PROGRAM_FORMAT_SPIRV)
    196 	{
    197 		const struct VkShaderModuleCreateInfo		shaderModuleInfo	=
    198 		{
    199 			VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
    200 			DE_NULL,
    201 			flags,
    202 			(deUintptr)binary.getSize(),
    203 			(const deUint32*)binary.getBinary(),
    204 		};
    205 
    206 		return createShaderModule(deviceInterface, device, &shaderModuleInfo);
    207 	}
    208 	else
    209 		TCU_THROW(NotSupportedError, "Unsupported program format");
    210 }
    211 
    212 glu::ShaderType getGluShaderType (VkShaderStageFlagBits shaderStage)
    213 {
    214 	switch (shaderStage)
    215 	{
    216 		case VK_SHADER_STAGE_VERTEX_BIT:					return glu::SHADERTYPE_VERTEX;
    217 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return glu::SHADERTYPE_TESSELLATION_CONTROL;
    218 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return glu::SHADERTYPE_TESSELLATION_EVALUATION;
    219 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return glu::SHADERTYPE_GEOMETRY;
    220 		case VK_SHADER_STAGE_FRAGMENT_BIT:					return glu::SHADERTYPE_FRAGMENT;
    221 		case VK_SHADER_STAGE_COMPUTE_BIT:					return glu::SHADERTYPE_COMPUTE;
    222 		default:
    223 			DE_FATAL("Unknown shader stage");
    224 			return glu::SHADERTYPE_LAST;
    225 	}
    226 }
    227 
    228 VkShaderStageFlagBits getVkShaderStage (glu::ShaderType shaderType)
    229 {
    230 	static const VkShaderStageFlagBits s_shaderStages[] =
    231 	{
    232 		VK_SHADER_STAGE_VERTEX_BIT,
    233 		VK_SHADER_STAGE_FRAGMENT_BIT,
    234 		VK_SHADER_STAGE_GEOMETRY_BIT,
    235 		VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
    236 		VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
    237 		VK_SHADER_STAGE_COMPUTE_BIT
    238 	};
    239 
    240 	return de::getSizedArrayElement<glu::SHADERTYPE_LAST>(s_shaderStages, shaderType);
    241 }
    242 
    243 } // vk
    244