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 }
138
139 virtual void getBytes(std::vector<uint8_t> &bytes) const = 0;
140 virtual void getPackedBytes(std::vector<uint8_t> &bytes) const = 0;
141 virtual size_t getByteSize(void) const = 0;
142 };
143
144 typedef de::SharedPtr<BufferInterface> BufferSp;
145 typedef de::MovePtr<vk::Allocation> AllocationMp;
146 typedef de::SharedPtr<vk::Allocation> AllocationSp;
147
148 class Resource
149 {
150 public:
Resource(const BufferSp & buffer_,vk::VkDescriptorType descriptorType_=vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,void * userData_=NULL)151 Resource(const BufferSp &buffer_, vk::VkDescriptorType descriptorType_ = vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
152 void *userData_ = NULL)
153 : buffer(buffer_)
154 , descriptorType(descriptorType_)
155 , userData(userData_)
156 {
157 }
158
~Resource()159 virtual ~Resource()
160 {
161 }
162
getBuffer() const163 virtual const BufferSp &getBuffer() const
164 {
165 return buffer;
166 }
getBytes(std::vector<uint8_t> & bytes) const167 virtual void getBytes(std::vector<uint8_t> &bytes) const
168 {
169 buffer->getBytes(bytes);
170 }
getByteSize(void) const171 virtual size_t getByteSize(void) const
172 {
173 return buffer->getByteSize();
174 }
175
setDescriptorType(vk::VkDescriptorType type)176 virtual void setDescriptorType(vk::VkDescriptorType type)
177 {
178 descriptorType = type;
179 }
getDescriptorType() const180 virtual vk::VkDescriptorType getDescriptorType() const
181 {
182 return descriptorType;
183 }
184
setUserData(void * data)185 virtual void setUserData(void *data)
186 {
187 userData = data;
188 }
getUserData() const189 virtual void *getUserData() const
190 {
191 return userData;
192 }
193
194 private:
195 BufferSp buffer;
196 vk::VkDescriptorType descriptorType;
197 void *userData;
198 };
199
200 typedef bool (*VerifyIOFunc)(const std::vector<Resource> &inputs, const std::vector<AllocationSp> &outputAllocations,
201 const std::vector<Resource> &expectedOutputs, tcu::TestLog &log);
202
203 struct SpecConstants
204 {
205 public:
SpecConstantsvkt::SpirVAssembly::SpecConstants206 SpecConstants(void)
207 {
208 }
209
emptyvkt::SpirVAssembly::SpecConstants210 bool empty(void) const
211 {
212 return valuesBuffer.empty();
213 }
214
getValuesCountvkt::SpirVAssembly::SpecConstants215 size_t getValuesCount(void) const
216 {
217 return sizesBuffer.size();
218 }
219
getValueSizevkt::SpirVAssembly::SpecConstants220 size_t getValueSize(const size_t valueIndex) const
221 {
222 return sizesBuffer[valueIndex];
223 }
224
getValuesBuffervkt::SpirVAssembly::SpecConstants225 const void *getValuesBuffer(void) const
226 {
227 if (valuesBuffer.size() == 0)
228 return DE_NULL;
229 else
230 return static_cast<const void *>(&valuesBuffer[0]);
231 }
232
233 template <typename T>
appendvkt::SpirVAssembly::SpecConstants234 void append(const T value)
235 {
236 append(&value, sizeof(value));
237 }
238
appendvkt::SpirVAssembly::SpecConstants239 void append(const void *buf, const size_t byteSize)
240 {
241 DE_ASSERT(byteSize > 0);
242
243 valuesBuffer.resize(valuesBuffer.size() + byteSize);
244 deMemcpy(&valuesBuffer[valuesBuffer.size() - byteSize], buf, byteSize);
245
246 sizesBuffer.push_back(byteSize);
247 }
248
249 private:
250 std::vector<uint8_t> valuesBuffer;
251 std::vector<size_t> sizesBuffer;
252 };
253
254 struct VulkanFeatures
255 {
256 vk::VkPhysicalDeviceFeatures coreFeatures;
257 vk::VkPhysicalDeviceShaderFloat16Int8Features extFloat16Int8;
258 vk::VkPhysicalDevice8BitStorageFeatures ext8BitStorage;
259 vk::VkPhysicalDevice16BitStorageFeatures ext16BitStorage;
260 vk::VkPhysicalDeviceVariablePointersFeatures extVariablePointers;
261 vk::VkPhysicalDeviceVulkanMemoryModelFeatures extVulkanMemoryModel;
262 #ifndef CTS_USES_VULKANSC
263 vk::VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR extIntegerDotProduct;
264 vk::VkPhysicalDeviceShaderFloatControls2FeaturesKHR extFloatControls2;
265 #endif // CTS_USES_VULKANSC
266 vk::VkPhysicalDeviceFloatControlsProperties floatControlsProperties;
267
VulkanFeaturesvkt::SpirVAssembly::VulkanFeatures268 VulkanFeatures(void)
269 {
270 deMemset(&coreFeatures, 0, sizeof(coreFeatures));
271 deMemset(&extFloat16Int8, 0, sizeof(vk::VkPhysicalDeviceShaderFloat16Int8Features));
272 deMemset(&ext8BitStorage, 0, sizeof(vk::VkPhysicalDevice8BitStorageFeatures));
273 deMemset(&ext16BitStorage, 0, sizeof(vk::VkPhysicalDevice16BitStorageFeatures));
274 deMemset(&extVariablePointers, 0, sizeof(vk::VkPhysicalDeviceVariablePointersFeatures));
275 deMemset(&extVulkanMemoryModel, 0, sizeof(vk::VkPhysicalDeviceVulkanMemoryModelFeatures));
276 #ifndef CTS_USES_VULKANSC
277 deMemset(&extIntegerDotProduct, 0, sizeof(vk::VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR));
278 deMemset(&extFloatControls2, 0, sizeof(vk::VkPhysicalDeviceShaderFloatControls2FeaturesKHR));
279 #endif // CTS_USES_VULKANSC
280 deMemset(&floatControlsProperties, 0, sizeof(vk::VkPhysicalDeviceFloatControlsProperties));
281 floatControlsProperties.denormBehaviorIndependence = vk::VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE;
282 floatControlsProperties.roundingModeIndependence = vk::VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE;
283 }
284 };
285
286 // Returns true if the whole VulkanFeatures is supported. If not, missingFeature will contain one feature that was missing.
287 bool isVulkanFeaturesSupported(const Context &context, const VulkanFeatures &toCheck, const char **missingFeature);
288
289 struct VariableLocation
290 {
291 uint32_t set;
292 uint32_t binding;
293
294 // Returns a string representation of the structure suitable for test names.
295 std::string toString() const;
296
297 // Returns a string representation of the structure suitable for test descriptions.
298 std::string toDescription() const;
299 };
300
301 // Returns true if the given float controls features in `toCheck` are all supported.
302 bool isFloatControlsFeaturesSupported(const Context &context,
303 const vk::VkPhysicalDeviceFloatControlsProperties &toCheck,
304 const char **missingFeature);
305
306 uint32_t getMinRequiredVulkanVersion(const vk::SpirvVersion version);
307
308 std::string getVulkanName(const uint32_t version);
309
310 // Performs a bitwise copy of source to the destination type Dest.
311 template <typename Dest, typename Src>
bitwiseCast(Src source)312 Dest bitwiseCast(Src source)
313 {
314 Dest dest;
315 DE_STATIC_ASSERT(sizeof(source) == sizeof(dest));
316 deMemcpy(&dest, &source, sizeof(dest));
317 return dest;
318 }
319
320 // Generate and return 64-bit integers.
321 //
322 // Expected count to be at least 16.
323 std::vector<int64_t> getInt64s(de::Random &rnd, const uint32_t count);
324
325 // Generate and return 32-bit integers.
326 //
327 // Expected count to be at least 16.
328 std::vector<int32_t> getInt32s(de::Random &rnd, const uint32_t count);
329
330 // Generate and return 16-bit integers.
331 //
332 // Expected count to be at least 8.
333 std::vector<int16_t> getInt16s(de::Random &rnd, const uint32_t count);
334
335 // Generate and return 8-bit integers.
336 //
337 // Expected count to be at least 8.
338 std::vector<int8_t> getInt8s(de::Random &rnd, const uint32_t count);
339
340 // Generate and return 64-bit floats
341 //
342 // If includeSpecialFloat16Values is false, random float64 that can be converted to float16 inf/nan/denormal must be excluded
343 // since inf may be clamped, and nan/denormal be flushed without float control features.
344 // And expected count to be at least 14 (numPicks).
345 // Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated.
346 // And expected count to be at least 24 (numPicks).
347 std::vector<double> getFloat64s(de::Random &rnd, uint32_t count, bool includeSpecialFloat16Values = true);
348
349 // Generate and return 32-bit floats
350 //
351 // If includeSpecialFloat16Values is false, random float32 that can be converted to float16 inf/nan/denormal must be excluded
352 // since inf may be clamped, and nan/denormal be flushed without float control features.
353 // And expected count to be at least 14 (numPicks).
354 // Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated.
355 // And expected count to be at least 24 (numPicks).
356 std::vector<float> getFloat32s(de::Random &rnd, uint32_t count, bool includeSpecialFloat16Values = true);
357
358 // Generate and return 16-bit floats
359 //
360 // If includeSpecialFloat16Values is false, float16 inf/nan/denormal must be excluded since inf may be clamped,
361 // and nan/denormal be flushed without float control features. And expected count to be at least 6 (numPicks).
362 // Otherwise, the first 14 number pairs are manually picked, while the rest are randomly generated.
363 // And expected count to be at least 14 (numPicks).
364 std::vector<deFloat16> getFloat16s(de::Random &rnd, uint32_t count, bool includeSpecialFloat16Values = true);
365
366 // Generate an OpCapability Shader line.
367 std::string getOpCapabilityShader();
368
369 // Generate an unused Vertex entry point.
370 std::string getUnusedEntryPoint();
371
372 // Generate unused decorations for an input/output buffer.
373 std::string getUnusedDecorations(const VariableLocation &location);
374
375 // Generate unused types and constants, including a buffer type.
376 std::string getUnusedTypesAndConstants();
377
378 // Generate the declaration of an unused buffer variable.
379 std::string getUnusedBuffer();
380
381 // Generate the body of an unused function that uses the previous buffer.
382 std::string getUnusedFunctionBody();
383
384 } // namespace SpirVAssembly
385 } // namespace vkt
386
387 #endif // _VKTSPVASMUTILS_HPP
388