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 		{
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 
assembleProgram(const SpirVAsmSource & program,SpirVProgramInfo * buildInfo)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 
disassembleProgram(const ProgramBinary & program,std::ostream * dst)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 
validateProgram(const ProgramBinary & program,std::ostream * dst)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 
createShaderModule(const DeviceInterface & deviceInterface,VkDevice device,const ProgramBinary & binary,VkShaderModuleCreateFlags flags)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 
getGluShaderType(VkShaderStageFlagBits shaderStage)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 
getVkShaderStage(glu::ShaderType shaderType)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