1 #ifndef _VKTSPVASMUTILS_HPP
2 #define _VKTSPVASMUTILS_HPP
3 /*-------------------------------------------------------------------------
4  * Vulkan Conformance Tests
5  * ------------------------
6  *
7  * Copyright (c) 2017 Google Inc.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Utilities for Vulkan SPIR-V assembly tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vkDefs.hpp"
27 #include "vkMemUtil.hpp"
28 #include "vkRef.hpp"
29 #include "vkTypeUtil.hpp"
30 #include "vktTestCase.hpp"
31 
32 #include "deMemory.h"
33 #include "deUniquePtr.hpp"
34 #include "deSharedPtr.hpp"
35 #include "deRandom.hpp"
36 #include "deFloat16.h"
37 
38 #include <string>
39 #include <vector>
40 
41 namespace vkt
42 {
43 namespace SpirVAssembly
44 {
45 
46 #define SPIRV_ASSEMBLY_TYPES																				\
47 	"%void = OpTypeVoid\n"																					\
48 	"%bool = OpTypeBool\n"																					\
49 																											\
50 	"%i32 = OpTypeInt 32 1\n"																				\
51 	"%u32 = OpTypeInt 32 0\n"																				\
52 																											\
53 	"%f32 = OpTypeFloat 32\n"																				\
54 	"%v2i32 = OpTypeVector %i32 2\n"																		\
55 	"%v2u32 = OpTypeVector %u32 2\n"																		\
56 	"%v2f32 = OpTypeVector %f32 2\n"																		\
57 	"%v3i32 = OpTypeVector %i32 3\n"																		\
58 	"%v3u32 = OpTypeVector %u32 3\n"																		\
59 	"%v3f32 = OpTypeVector %f32 3\n"																		\
60 	"%v4i32 = OpTypeVector %i32 4\n"																		\
61 	"%v4u32 = OpTypeVector %u32 4\n"																		\
62 	"%v4f32 = OpTypeVector %f32 4\n"																		\
63 	"%v4bool = OpTypeVector %bool 4\n"																		\
64 																											\
65 	"%v4f32_v4f32_function = OpTypeFunction %v4f32 %v4f32\n"									\
66 	"%bool_function = OpTypeFunction %bool\n"																\
67 	"%voidf = OpTypeFunction %void\n"																			\
68 																											\
69 	"%ip_f32 = OpTypePointer Input %f32\n"																	\
70 	"%ip_i32 = OpTypePointer Input %i32\n"																	\
71 	"%ip_u32 = OpTypePointer Input %u32\n"																	\
72 	"%ip_v2f32 = OpTypePointer Input %v2f32\n"																\
73 	"%ip_v2i32 = OpTypePointer Input %v2i32\n"																\
74 	"%ip_v2u32 = OpTypePointer Input %v2u32\n"																\
75 	"%ip_v3f32 = OpTypePointer Input %v3f32\n"																\
76 	"%ip_v4f32 = OpTypePointer Input %v4f32\n"																\
77 	"%ip_v4i32 = OpTypePointer Input %v4i32\n"																\
78 	"%ip_v4u32 = OpTypePointer Input %v4u32\n"																\
79 																											\
80 	"%op_f32 = OpTypePointer Output %f32\n"																	\
81 	"%op_i32 = OpTypePointer Output %i32\n"																	\
82 	"%op_u32 = OpTypePointer Output %u32\n"																	\
83 	"%op_v2f32 = OpTypePointer Output %v2f32\n"																\
84 	"%op_v2i32 = OpTypePointer Output %v2i32\n"																\
85 	"%op_v2u32 = OpTypePointer Output %v2u32\n"																\
86 	"%op_v4f32 = OpTypePointer Output %v4f32\n"																\
87 	"%op_v4i32 = OpTypePointer Output %v4i32\n"																\
88 	"%op_v4u32 = OpTypePointer Output %v4u32\n"																\
89 																											\
90 	"%fp_f32   = OpTypePointer Function %f32\n"																\
91 	"%fp_i32   = OpTypePointer Function %i32\n"																\
92 	"%fp_v4f32 = OpTypePointer Function %v4f32\n"															\
93 
94 #define SPIRV_ASSEMBLY_CONSTANTS																			\
95 	"%c_f32_1 = OpConstant %f32 1.0\n"																		\
96 	"%c_f32_0 = OpConstant %f32 0.0\n"																		\
97 	"%c_f32_0_5 = OpConstant %f32 0.5\n"																	\
98 	"%c_f32_n1  = OpConstant %f32 -1.\n"																	\
99 	"%c_f32_7 = OpConstant %f32 7.0\n"																		\
100 	"%c_f32_8 = OpConstant %f32 8.0\n"																		\
101 	"%c_i32_0 = OpConstant %i32 0\n"																		\
102 	"%c_i32_1 = OpConstant %i32 1\n"																		\
103 	"%c_i32_2 = OpConstant %i32 2\n"																		\
104 	"%c_i32_3 = OpConstant %i32 3\n"																		\
105 	"%c_i32_4 = OpConstant %i32 4\n"																		\
106 	"%c_u32_0 = OpConstant %u32 0\n"																		\
107 	"%c_u32_1 = OpConstant %u32 1\n"																		\
108 	"%c_u32_2 = OpConstant %u32 2\n"																		\
109 	"%c_u32_3 = OpConstant %u32 3\n"																		\
110 	"%c_u32_32 = OpConstant %u32 32\n"																		\
111 	"%c_u32_4 = OpConstant %u32 4\n"																		\
112 	"%c_u32_31_bits = OpConstant %u32 0x7FFFFFFF\n"															\
113 	"%c_v4f32_1_1_1_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_1 %c_f32_1 %c_f32_1\n"					\
114 	"%c_v4f32_1_0_0_1 = OpConstantComposite %v4f32 %c_f32_1 %c_f32_0 %c_f32_0 %c_f32_1\n"					\
115 	"%c_v4f32_0_5_0_5_0_5_0_5 = OpConstantComposite %v4f32 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5 %c_f32_0_5\n"	\
116 
117 #define SPIRV_ASSEMBLY_ARRAYS																				\
118 	"%a1f32 = OpTypeArray %f32 %c_u32_1\n"																	\
119 	"%a2f32 = OpTypeArray %f32 %c_u32_2\n"																	\
120 	"%a3v4f32 = OpTypeArray %v4f32 %c_u32_3\n"																\
121 	"%a4f32 = OpTypeArray %f32 %c_u32_4\n"																	\
122 	"%a32v4f32 = OpTypeArray %v4f32 %c_u32_32\n"															\
123 	"%ip_a3v4f32 = OpTypePointer Input %a3v4f32\n"															\
124 	"%ip_a32v4f32 = OpTypePointer Input %a32v4f32\n"														\
125 	"%op_a2f32 = OpTypePointer Output %a2f32\n"																\
126 	"%op_a3v4f32 = OpTypePointer Output %a3v4f32\n"															\
127 	"%op_a4f32 = OpTypePointer Output %a4f32\n"																\
128 
129 /*--------------------------------------------------------------------*//*!
130  * \brief Abstract class for an input/output storage buffer object
131  *//*--------------------------------------------------------------------*/
132 class BufferInterface
133 {
134 public:
~BufferInterface(void)135 	virtual				~BufferInterface	(void)				{}
136 
137 	virtual void		getBytes			(std::vector<deUint8>& bytes) const = 0;
138 	virtual void		getPackedBytes		(std::vector<deUint8>& bytes) const = 0;
139 	virtual size_t		getByteSize			(void) const = 0;
140 };
141 
142 typedef de::SharedPtr<BufferInterface>	BufferSp;
143 typedef de::MovePtr<vk::Allocation>		AllocationMp;
144 typedef de::SharedPtr<vk::Allocation>	AllocationSp;
145 
146 class Resource
147 {
148 public:
Resource(const BufferSp & buffer_,vk::VkDescriptorType descriptorType_=vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,void * userData_=NULL)149 	Resource(const BufferSp& buffer_, vk::VkDescriptorType descriptorType_ = vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, void* userData_ = NULL)
150 		: buffer(buffer_)
151 		, descriptorType(descriptorType_)
152 		, userData(userData_)
153 	{
154 	}
155 
getBuffer() const156 	virtual const BufferSp&			getBuffer			() const							{ return buffer; }
getBytes(std::vector<deUint8> & bytes) const157 	virtual void					getBytes			(std::vector<deUint8>& bytes) const	{ buffer->getBytes(bytes); }
getByteSize(void) const158 	virtual size_t					getByteSize			(void) const						{ return buffer->getByteSize(); }
159 
setDescriptorType(vk::VkDescriptorType type)160 	virtual void					setDescriptorType	(vk::VkDescriptorType type)		{ descriptorType = type; }
getDescriptorType() const161 	virtual vk::VkDescriptorType	getDescriptorType	()	const						{ return descriptorType; }
162 
setUserData(void * data)163 	virtual void					setUserData			(void* data)					{ userData = data; }
getUserData() const164 	virtual void*					getUserData			() const						{ return userData; }
165 
166 private:
167 	BufferSp				buffer;
168 	vk::VkDescriptorType	descriptorType;
169 	void*					userData;
170 };
171 
172 typedef bool (*VerifyIOFunc) (const std::vector<Resource>&		inputs,
173 							  const std::vector<AllocationSp>&	outputAllocations,
174 							  const std::vector<Resource>&		expectedOutputs,
175 							  tcu::TestLog&						log);
176 
177 struct SpecConstants
178 {
179 public:
SpecConstantsvkt::SpirVAssembly::SpecConstants180 							SpecConstants (void)
181 							{}
182 
emptyvkt::SpirVAssembly::SpecConstants183 	bool					empty (void) const
184 							{
185 								return valuesBuffer.empty();
186 							}
187 
getValuesCountvkt::SpirVAssembly::SpecConstants188 	size_t					getValuesCount (void) const
189 							{
190 								return sizesBuffer.size();
191 							}
192 
getValueSizevkt::SpirVAssembly::SpecConstants193 	size_t					getValueSize (const size_t valueIndex) const
194 							{
195 								return sizesBuffer[valueIndex];
196 							}
197 
getValuesBuffervkt::SpirVAssembly::SpecConstants198 	const void*				getValuesBuffer (void) const
199 							{
200 								if (valuesBuffer.size() == 0)
201 									return DE_NULL;
202 								else
203 									return static_cast<const void*>(&valuesBuffer[0]);
204 							}
205 
206 	template<typename T>
appendvkt::SpirVAssembly::SpecConstants207 	void					append (const T value)
208 							{
209 								append(&value, sizeof(value));
210 							}
211 
appendvkt::SpirVAssembly::SpecConstants212 	void					append (const void* buf, const size_t byteSize)
213 							{
214 								DE_ASSERT(byteSize > 0);
215 
216 								valuesBuffer.resize(valuesBuffer.size() + byteSize);
217 								deMemcpy(&valuesBuffer[valuesBuffer.size() - byteSize], buf, byteSize);
218 
219 								sizesBuffer.push_back(byteSize);
220 							}
221 
222 private:
223 	std::vector<deUint8>	valuesBuffer;
224 	std::vector<size_t>		sizesBuffer;
225 };
226 
227 enum Extension8BitStorageFeatureBits
228 {
229 	EXT8BITSTORAGEFEATURES_STORAGE_BUFFER			= (1u << 1),
230 	EXT8BITSTORAGEFEATURES_UNIFORM_STORAGE_BUFFER	= (1u << 2),
231 	EXT8BITSTORAGEFEATURES_PUSH_CONSTANT			= (1u << 3),
232 };
233 typedef deUint32 Extension8BitStorageFeatures;
234 
235 enum Extension16BitStorageFeatureBits
236 {
237 	EXT16BITSTORAGEFEATURES_UNIFORM_BUFFER_BLOCK	= (1u << 1),
238 	EXT16BITSTORAGEFEATURES_UNIFORM					= (1u << 2),
239 	EXT16BITSTORAGEFEATURES_PUSH_CONSTANT			= (1u << 3),
240 	EXT16BITSTORAGEFEATURES_INPUT_OUTPUT			= (1u << 4),
241 };
242 typedef deUint32 Extension16BitStorageFeatures;
243 
244 enum ExtensionVariablePointersFeaturesBits
245 {
246 	EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS_STORAGEBUFFER	= (1u << 1),
247 	EXTVARIABLEPOINTERSFEATURES_VARIABLE_POINTERS				= (1u << 2),
248 };
249 typedef deUint32 ExtensionVariablePointersFeatures;
250 
251 enum ExtensionFloat16Int8FeaturesBits
252 {
253 	EXTFLOAT16INT8FEATURES_FLOAT16	= (1u << 1),
254 	EXTFLOAT16INT8FEATURES_INT8		= (1u << 2),
255 };
256 typedef deUint32 ExtensionFloat16Int8Features;
257 typedef vk::VkPhysicalDeviceFloatControlsProperties ExtensionFloatControlsFeatures;
258 
259 enum ExtensionVulkanMemoryModelFeaturesBits
260 {
261 	EXTVULKANMEMORYMODELFEATURES_ENABLE							= (1u << 1),
262 	EXTVULKANMEMORYMODELFEATURES_DEVICESCOPE					= (1u << 2),
263 	EXTVULKANMEMORYMODELFEATURES_AVAILABILITYVISIBILITYCHAINS	= (1u << 3),
264 };
265 typedef deUint32 ExtensionVulkanMemoryModelFeatures;
266 
267 struct VulkanFeatures
268 {
269 	vk::VkPhysicalDeviceFeatures		coreFeatures;
270 	ExtensionFloat16Int8Features		extFloat16Int8;
271 	Extension8BitStorageFeatures		ext8BitStorage;
272 	Extension16BitStorageFeatures		ext16BitStorage;
273 	ExtensionVariablePointersFeatures	extVariablePointers;
274 	ExtensionVulkanMemoryModelFeatures	extVulkanMemoryModel;
275 	ExtensionFloatControlsFeatures		floatControlsProperties;
276 
277 
VulkanFeaturesvkt::SpirVAssembly::VulkanFeatures278 	VulkanFeatures				(void)
279 		: extFloat16Int8		(0)
280 		, ext8BitStorage		(0)
281 		, ext16BitStorage		(0)
282 		, extVariablePointers	(0)
283 		, extVulkanMemoryModel	(0)
284 	{
285 		deMemset(&coreFeatures, 0, sizeof(coreFeatures));
286 		deMemset(&floatControlsProperties, 0, sizeof(ExtensionFloatControlsFeatures));
287 		floatControlsProperties.denormBehaviorIndependence	= vk::VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR;
288 		floatControlsProperties.roundingModeIndependence	= vk::VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR;
289 	}
290 };
291 
292 struct VariableLocation
293 {
294 	deUint32 set;
295 	deUint32 binding;
296 
297 	// Returns a string representation of the structure suitable for test names.
298 	std::string toString() const ;
299 
300 	// Returns a string representation of the structure suitable for test descriptions.
301 	std::string toDescription() const;
302 };
303 
304 // Returns true if the given 8bit storage extension features in `toCheck` are all supported.
305 bool is8BitStorageFeaturesSupported (const Context&						context,
306 									  Extension8BitStorageFeatures		toCheck);
307 
308 // Returns true if the given 16bit storage extension features in `toCheck` are all supported.
309 bool isCoreFeaturesSupported (const Context&						context,
310 							  const vk::VkPhysicalDeviceFeatures&	toCheck,
311 							  const char**							missingFeature);
312 
313 // Returns true if the given 16bit storage extension features in `toCheck` are all supported.
314 bool is16BitStorageFeaturesSupported (const Context&				context,
315 									  Extension16BitStorageFeatures	toCheck);
316 
317 // Returns true if the given variable pointers extension features in `toCheck` are all supported.
318 bool isVariablePointersFeaturesSupported (const Context&					context,
319 										  ExtensionVariablePointersFeatures	toCheck);
320 
321 // Returns true if the given 16bit float/8bit int extension features in `toCheck` are all supported.
322 bool isFloat16Int8FeaturesSupported (const Context&					context,
323 									 ExtensionFloat16Int8Features	toCheck);
324 
325 // Returns true if the given Vulkan Memory Model extension features in `toCheck` are all supported.
326 bool isVulkanMemoryModelFeaturesSupported (const Context&						context,
327 										   ExtensionVulkanMemoryModelFeatures	toCheck);
328 
329 // Returns true if the given float controls features in `toCheck` are all supported.
330 bool isFloatControlsFeaturesSupported (const Context&							context,
331 									   const ExtensionFloatControlsFeatures&	toCheck);
332 
333 deUint32 getMinRequiredVulkanVersion (const vk::SpirvVersion version);
334 
335 std::string	getVulkanName (const deUint32 version);
336 
337 // Performs a bitwise copy of source to the destination type Dest.
338 template <typename Dest, typename Src>
bitwiseCast(Src source)339 Dest bitwiseCast (Src source)
340 {
341   Dest dest;
342   DE_STATIC_ASSERT(sizeof(source) == sizeof(dest));
343   deMemcpy(&dest, &source, sizeof(dest));
344   return dest;
345 }
346 
347 // Generate and return 64-bit integers.
348 //
349 // Expected count to be at least 16.
350 std::vector<deInt64> getInt64s (de::Random& rnd, const deUint32 count);
351 
352 // Generate and return 32-bit integers.
353 //
354 // Expected count to be at least 16.
355 std::vector<deInt32> getInt32s (de::Random& rnd, const deUint32 count);
356 
357 // Generate and return 16-bit integers.
358 //
359 // Expected count to be at least 8.
360 std::vector<deInt16> getInt16s (de::Random& rnd, const deUint32 count);
361 
362 // Generate and return 8-bit integers.
363 //
364 // Expected count to be at least 8.
365 std::vector<deInt8> getInt8s (de::Random& rnd, const deUint32 count);
366 
367 // Generate and return 64-bit floats
368 //
369 // The first 24 number pairs are manually picked, while the rest are randomly generated.
370 // Expected count to be at least 24 (numPicks).
371 std::vector<double> getFloat64s (de::Random& rnd, deUint32 count);
372 
373 // Generate and return 32-bit floats
374 //
375 // The first 24 number pairs are manually picked, while the rest are randomly generated.
376 // Expected count to be at least 24 (numPicks).
377 std::vector<float> getFloat32s (de::Random& rnd, deUint32 count);
378 
379 // Generate and return 16-bit floats and their corresponding 32-bit values.
380 //
381 // The first 14 number pairs are manually picked, while the rest are randomly generated.
382 // Expected count to be at least 14 (numPicks).
383 std::vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count);
384 
385 // Generate an OpCapability Shader line.
386 std::string getOpCapabilityShader();
387 
388 // Generate an unused Vertex entry point.
389 std::string getUnusedEntryPoint();
390 
391 // Generate unused decorations for an input/output buffer.
392 std::string getUnusedDecorations(const VariableLocation& location);
393 
394 // Generate unused types and constants, including a buffer type.
395 std::string getUnusedTypesAndConstants();
396 
397 // Generate the declaration of an unused buffer variable.
398 std::string getUnusedBuffer();
399 
400 // Generate the body of an unused function that uses the previous buffer.
401 std::string getUnusedFunctionBody();
402 
403 } // SpirVAssembly
404 } // vkt
405 
406 #endif // _VKTSPVASMUTILS_HPP
407