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