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