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 
ProgramBinary(ProgramFormat format,size_t binarySize,const deUint8 * binary)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 
isNativeSpirVBinaryEndianness(void)63 bool isNativeSpirVBinaryEndianness (void)
64 {
65 #if (DE_ENDIANNESS == SPIRV_BINARY_ENDIANNESS)
66 	return true;
67 #else
68 	return false;
69 #endif
70 }
71 
isSaneSpirVBinary(const ProgramBinary & binary)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 
createProgramBinaryFromSpirV(const vector<deUint32> & binary)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 
buildProgram(const glu::ProgramSources & program,ProgramFormat binaryFormat,glu::ShaderProgramInfo * buildInfo)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 
assembleProgram(const SpirVAsmSource & program,SpirVProgramInfo * buildInfo)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 
disassembleProgram(const ProgramBinary & program,std::ostream * dst)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 
validateProgram(const ProgramBinary & program,std::ostream * dst)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 
createShaderModule(const DeviceInterface & deviceInterface,VkDevice device,const ProgramBinary & binary,VkShaderModuleCreateFlags flags)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 
getGluShaderType(VkShaderStageFlagBits shaderStage)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 
getVkShaderStage(glu::ShaderType shaderType)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