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 41namespace vkt 42{ 43namespace 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 *//*--------------------------------------------------------------------*/ 132class BufferInterface 133{ 134public: 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 142typedef de::SharedPtr<BufferInterface> BufferSp; 143typedef de::MovePtr<vk::Allocation> AllocationMp; 144typedef de::SharedPtr<vk::Allocation> AllocationSp; 145 146class Resource 147{ 148public: 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 156 virtual const BufferSp& getBuffer () const { return buffer; } 157 virtual void getBytes (std::vector<deUint8>& bytes) const { buffer->getBytes(bytes); } 158 virtual size_t getByteSize (void) const { return buffer->getByteSize(); } 159 160 virtual void setDescriptorType (vk::VkDescriptorType type) { descriptorType = type; } 161 virtual vk::VkDescriptorType getDescriptorType () const { return descriptorType; } 162 163 virtual void setUserData (void* data) { userData = data; } 164 virtual void* getUserData () const { return userData; } 165 166private: 167 BufferSp buffer; 168 vk::VkDescriptorType descriptorType; 169 void* userData; 170}; 171 172typedef bool (*VerifyIOFunc) (const std::vector<Resource>& inputs, 173 const std::vector<AllocationSp>& outputAllocations, 174 const std::vector<Resource>& expectedOutputs, 175 tcu::TestLog& log); 176 177struct SpecConstants 178{ 179public: 180 SpecConstants (void) 181 {} 182 183 bool empty (void) const 184 { 185 return valuesBuffer.empty(); 186 } 187 188 size_t getValuesCount (void) const 189 { 190 return sizesBuffer.size(); 191 } 192 193 size_t getValueSize (const size_t valueIndex) const 194 { 195 return sizesBuffer[valueIndex]; 196 } 197 198 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> 207 void append (const T value) 208 { 209 append(&value, sizeof(value)); 210 } 211 212 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 222private: 223 std::vector<deUint8> valuesBuffer; 224 std::vector<size_t> sizesBuffer; 225}; 226 227struct VulkanFeatures 228{ 229 vk::VkPhysicalDeviceFeatures coreFeatures; 230 vk::VkPhysicalDeviceShaderFloat16Int8Features extFloat16Int8; 231 vk::VkPhysicalDevice8BitStorageFeatures ext8BitStorage; 232 vk::VkPhysicalDevice16BitStorageFeatures ext16BitStorage; 233 vk::VkPhysicalDeviceVariablePointersFeatures extVariablePointers; 234 vk::VkPhysicalDeviceVulkanMemoryModelFeatures extVulkanMemoryModel; 235#ifndef CTS_USES_VULKANSC 236 vk::VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR extIntegerDotProduct; 237#endif // CTS_USES_VULKANSC 238 vk::VkPhysicalDeviceFloatControlsProperties floatControlsProperties; 239 240 VulkanFeatures (void) 241 { 242 deMemset(&coreFeatures, 0, sizeof(coreFeatures)); 243 deMemset(&extFloat16Int8, 0, sizeof(vk::VkPhysicalDeviceShaderFloat16Int8Features)); 244 deMemset(&ext8BitStorage, 0, sizeof(vk::VkPhysicalDevice8BitStorageFeatures)); 245 deMemset(&ext16BitStorage, 0, sizeof(vk::VkPhysicalDevice16BitStorageFeatures)); 246 deMemset(&extVariablePointers, 0, sizeof(vk::VkPhysicalDeviceVariablePointersFeatures)); 247 deMemset(&extVulkanMemoryModel, 0, sizeof(vk::VkPhysicalDeviceVulkanMemoryModelFeatures)); 248#ifndef CTS_USES_VULKANSC 249 deMemset(&extIntegerDotProduct, 0, sizeof(vk::VkPhysicalDeviceShaderIntegerDotProductFeaturesKHR)); 250#endif // CTS_USES_VULKANSC 251 deMemset(&floatControlsProperties, 0, sizeof(vk::VkPhysicalDeviceFloatControlsProperties)); 252 floatControlsProperties.denormBehaviorIndependence = vk::VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE; 253 floatControlsProperties.roundingModeIndependence = vk::VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE; 254 } 255}; 256 257// Returns true if the whole VulkanFeatures is supported. If not, missingFeature will contain one feature that was missing. 258bool isVulkanFeaturesSupported(const Context& context, const VulkanFeatures& toCheck, const char** missingFeature); 259 260struct VariableLocation 261{ 262 deUint32 set; 263 deUint32 binding; 264 265 // Returns a string representation of the structure suitable for test names. 266 std::string toString() const ; 267 268 // Returns a string representation of the structure suitable for test descriptions. 269 std::string toDescription() const; 270}; 271 272// Returns true if the given float controls features in `toCheck` are all supported. 273bool isFloatControlsFeaturesSupported( const Context& context, 274 const vk::VkPhysicalDeviceFloatControlsProperties& toCheck, 275 const char** missingFeature); 276 277deUint32 getMinRequiredVulkanVersion (const vk::SpirvVersion version); 278 279std::string getVulkanName (const deUint32 version); 280 281// Performs a bitwise copy of source to the destination type Dest. 282template <typename Dest, typename Src> 283Dest bitwiseCast (Src source) 284{ 285 Dest dest; 286 DE_STATIC_ASSERT(sizeof(source) == sizeof(dest)); 287 deMemcpy(&dest, &source, sizeof(dest)); 288 return dest; 289} 290 291// Generate and return 64-bit integers. 292// 293// Expected count to be at least 16. 294std::vector<deInt64> getInt64s (de::Random& rnd, const deUint32 count); 295 296// Generate and return 32-bit integers. 297// 298// Expected count to be at least 16. 299std::vector<deInt32> getInt32s (de::Random& rnd, const deUint32 count); 300 301// Generate and return 16-bit integers. 302// 303// Expected count to be at least 8. 304std::vector<deInt16> getInt16s (de::Random& rnd, const deUint32 count); 305 306// Generate and return 8-bit integers. 307// 308// Expected count to be at least 8. 309std::vector<deInt8> getInt8s (de::Random& rnd, const deUint32 count); 310 311// Generate and return 64-bit floats 312// 313// If includeSpecialFloat16Values is false, random float64 that can be converted to float16 inf/nan/denormal must be excluded 314// since inf may be clamped, and nan/denormal be flushed without float control features. 315// And expected count to be at least 14 (numPicks). 316// Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated. 317// And expected count to be at least 24 (numPicks). 318std::vector<double> getFloat64s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values = DE_TRUE); 319 320// Generate and return 32-bit floats 321// 322// If includeSpecialFloat16Values is false, random float32 that can be converted to float16 inf/nan/denormal must be excluded 323// since inf may be clamped, and nan/denormal be flushed without float control features. 324// And expected count to be at least 14 (numPicks). 325// Otherwise, the first 24 number pairs are manually picked, while the rest are randomly generated. 326// And expected count to be at least 24 (numPicks). 327std::vector<float> getFloat32s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values = DE_TRUE); 328 329// Generate and return 16-bit floats 330// 331// If includeSpecialFloat16Values is false, float16 inf/nan/denormal must be excluded since inf may be clamped, 332// and nan/denormal be flushed without float control features. And expected count to be at least 6 (numPicks). 333// Otherwise, the first 14 number pairs are manually picked, while the rest are randomly generated. 334// And expected count to be at least 14 (numPicks). 335std::vector<deFloat16> getFloat16s (de::Random& rnd, deUint32 count, deBool includeSpecialFloat16Values = DE_TRUE); 336 337// Generate an OpCapability Shader line. 338std::string getOpCapabilityShader(); 339 340// Generate an unused Vertex entry point. 341std::string getUnusedEntryPoint(); 342 343// Generate unused decorations for an input/output buffer. 344std::string getUnusedDecorations(const VariableLocation& location); 345 346// Generate unused types and constants, including a buffer type. 347std::string getUnusedTypesAndConstants(); 348 349// Generate the declaration of an unused buffer variable. 350std::string getUnusedBuffer(); 351 352// Generate the body of an unused function that uses the previous buffer. 353std::string getUnusedFunctionBody(); 354 355} // SpirVAssembly 356} // vkt 357 358#endif // _VKTSPVASMUTILS_HPP 359