1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2015 The Khronos Group Inc. 6 * Copyright (c) 2015 Samsung Electronics Co., Ltd. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 *//*! 21 * \file 22 * \brief Vulkan Buffers Tests 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktApiBufferTests.hpp" 26 27 #include "deStringUtil.hpp" 28 #include "gluVarType.hpp" 29 #include "tcuTestLog.hpp" 30 #include "vkPrograms.hpp" 31 #include "vkQueryUtil.hpp" 32 #include "vkRefUtil.hpp" 33 #include "vkPlatform.hpp" 34 #include "vktTestCase.hpp" 35 36 namespace vkt 37 { 38 namespace api 39 { 40 namespace 41 { 42 using namespace vk; 43 44 struct BufferCaseParameters 45 { 46 VkBufferUsageFlags usage; 47 VkBufferCreateFlags flags; 48 VkSharingMode sharingMode; 49 }; 50 51 class BufferTestInstance : public TestInstance 52 { 53 public: 54 BufferTestInstance (Context& ctx, 55 BufferCaseParameters testCase) 56 : TestInstance (ctx) 57 , m_testCase (testCase) 58 , m_sparseContext (createSparseContext()) 59 {} 60 virtual tcu::TestStatus iterate (void); 61 tcu::TestStatus bufferCreateAndAllocTest (VkDeviceSize size); 62 63 private: 64 BufferCaseParameters m_testCase; 65 66 private: 67 // Custom context for sparse cases 68 struct SparseContext 69 { 70 SparseContext (Move<VkDevice>& device, const deUint32 queueFamilyIndex, const InstanceInterface& interface) 71 : m_device (device) 72 , m_queueFamilyIndex (queueFamilyIndex) 73 , m_deviceInterface (interface, *m_device) 74 {} 75 76 Unique<VkDevice> m_device; 77 const deUint32 m_queueFamilyIndex; 78 DeviceDriver m_deviceInterface; 79 }; 80 81 de::UniquePtr<SparseContext> m_sparseContext; 82 83 // Wrapper functions around m_context calls to support sparse cases. 84 VkPhysicalDevice getPhysicalDevice (void) const 85 { 86 // Same in sparse and regular case 87 return m_context.getPhysicalDevice(); 88 } 89 90 VkDevice getDevice (void) const 91 { 92 if (m_sparseContext) 93 return *(m_sparseContext->m_device); 94 95 return m_context.getDevice(); 96 } 97 98 const InstanceInterface& getInstanceInterface (void) const 99 { 100 // Same in sparse and regular case 101 return m_context.getInstanceInterface(); 102 } 103 104 const DeviceInterface& getDeviceInterface (void) const 105 { 106 if (m_sparseContext) 107 return m_sparseContext->m_deviceInterface; 108 109 return m_context.getDeviceInterface(); 110 } 111 112 deUint32 getUniversalQueueFamilyIndex (void) const 113 { 114 if (m_sparseContext) 115 return m_sparseContext->m_queueFamilyIndex; 116 117 return m_context.getUniversalQueueFamilyIndex(); 118 } 119 120 static deUint32 findQueueFamilyIndexWithCaps (const InstanceInterface& vkInstance, VkPhysicalDevice physicalDevice, VkQueueFlags requiredCaps) 121 { 122 const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(vkInstance, physicalDevice); 123 124 for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++) 125 { 126 if ((queueProps[queueNdx].queueFlags & requiredCaps) == requiredCaps) 127 return (deUint32)queueNdx; 128 } 129 130 TCU_THROW(NotSupportedError, "No matching queue found"); 131 } 132 133 // Create the sparseContext 134 SparseContext* createSparseContext (void) const 135 { 136 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) || 137 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) || 138 (m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) 139 { 140 const InstanceInterface& vk = getInstanceInterface(); 141 const VkPhysicalDevice physicalDevice = getPhysicalDevice(); 142 const VkPhysicalDeviceFeatures deviceFeatures = getPhysicalDeviceFeatures(vk, physicalDevice); 143 144 const deUint32 queueIndex = findQueueFamilyIndexWithCaps(vk, physicalDevice, VK_QUEUE_GRAPHICS_BIT|VK_QUEUE_SPARSE_BINDING_BIT); 145 146 VkDeviceQueueCreateInfo queueInfo; 147 VkDeviceCreateInfo deviceInfo; 148 const float queuePriority = 1.0f; 149 150 deMemset(&queueInfo, 0, sizeof(queueInfo)); 151 deMemset(&deviceInfo, 0, sizeof(deviceInfo)); 152 153 queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 154 queueInfo.pNext = DE_NULL; 155 queueInfo.flags = (VkDeviceQueueCreateFlags)0u; 156 queueInfo.queueFamilyIndex = queueIndex; 157 queueInfo.queueCount = 1u; 158 queueInfo.pQueuePriorities = &queuePriority; 159 160 deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 161 deviceInfo.pNext = DE_NULL; 162 deviceInfo.queueCreateInfoCount = 1u; 163 deviceInfo.pQueueCreateInfos = &queueInfo; 164 deviceInfo.enabledExtensionCount = 0u; 165 deviceInfo.ppEnabledExtensionNames = DE_NULL; 166 deviceInfo.enabledLayerCount = 0u; 167 deviceInfo.ppEnabledLayerNames = DE_NULL; 168 deviceInfo.pEnabledFeatures = &deviceFeatures; 169 170 Move<VkDevice> device = createDevice(vk, physicalDevice, &deviceInfo); 171 172 return new SparseContext(device, queueIndex, vk); 173 } 174 175 return DE_NULL; 176 } 177 }; 178 179 class BuffersTestCase : public TestCase 180 { 181 public: 182 BuffersTestCase (tcu::TestContext& testCtx, 183 const std::string& name, 184 const std::string& description, 185 BufferCaseParameters testCase) 186 : TestCase(testCtx, name, description) 187 , m_testCase(testCase) 188 {} 189 190 virtual ~BuffersTestCase (void) {} 191 virtual TestInstance* createInstance (Context& ctx) const 192 { 193 tcu::TestLog& log = m_testCtx.getLog(); 194 log << tcu::TestLog::Message << getBufferUsageFlagsStr(m_testCase.usage) << tcu::TestLog::EndMessage; 195 return new BufferTestInstance(ctx, m_testCase); 196 } 197 198 private: 199 BufferCaseParameters m_testCase; 200 }; 201 202 inline VkDeviceSize alignDeviceSize (VkDeviceSize val, VkDeviceSize align) 203 { 204 DE_ASSERT(deIsPowerOfTwo64(align)); 205 DE_ASSERT(val + align >= val); // crash on overflow 206 return (val + align - 1) & ~(align - 1); 207 } 208 209 tcu::TestStatus BufferTestInstance::bufferCreateAndAllocTest (VkDeviceSize size) 210 { 211 const VkPhysicalDevice vkPhysicalDevice = getPhysicalDevice(); 212 const InstanceInterface& vkInstance = getInstanceInterface(); 213 const VkDevice vkDevice = getDevice(); 214 const DeviceInterface& vk = getDeviceInterface(); 215 const deUint32 queueFamilyIndex = getUniversalQueueFamilyIndex(); 216 const VkPhysicalDeviceMemoryProperties memoryProperties = getPhysicalDeviceMemoryProperties(vkInstance, vkPhysicalDevice); 217 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vkInstance, vkPhysicalDevice).limits; 218 Move<VkBuffer> buffer; 219 Move<VkDeviceMemory> memory; 220 VkMemoryRequirements memReqs; 221 222 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) != 0) 223 size = std::min(size, limits.sparseAddressSpaceSize); 224 225 // Create the test buffer and a memory allocation for it 226 { 227 // Create a minimal buffer first to get the supported memory types 228 VkBufferCreateInfo bufferParams = 229 { 230 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; 231 DE_NULL, // const void* pNext; 232 m_testCase.flags, // VkBufferCreateFlags flags; 233 1u, // VkDeviceSize size; 234 m_testCase.usage, // VkBufferUsageFlags usage; 235 m_testCase.sharingMode, // VkSharingMode sharingMode; 236 1u, // uint32_t queueFamilyIndexCount; 237 &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices; 238 }; 239 240 buffer = createBuffer(vk, vkDevice, &bufferParams); 241 vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs); 242 243 const deUint32 heapTypeIndex = (deUint32)deCtz32(memReqs.memoryTypeBits); 244 const VkMemoryType memoryType = memoryProperties.memoryTypes[heapTypeIndex]; 245 const VkMemoryHeap memoryHeap = memoryProperties.memoryHeaps[memoryType.heapIndex]; 246 const VkDeviceSize maxBufferSize = alignDeviceSize(memoryHeap.size >> 1, memReqs.alignment); 247 const deUint32 shrinkBits = 4; // number of bits to shift when reducing the size with each iteration 248 249 size = std::min(size, maxBufferSize); 250 251 while (*memory == DE_NULL) 252 { 253 // Create the buffer 254 { 255 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY; 256 VkBuffer rawBuffer = DE_NULL; 257 258 bufferParams.size = size; 259 buffer = Move<VkBuffer>(); // free the previous buffer, if any 260 result = vk.createBuffer(vkDevice, &bufferParams, (VkAllocationCallbacks*)DE_NULL, &rawBuffer); 261 262 if (result != VK_SUCCESS) 263 { 264 size = alignDeviceSize(size >> shrinkBits, memReqs.alignment); 265 266 if (size == 0 || bufferParams.size == memReqs.alignment) 267 return tcu::TestStatus::fail("Buffer creation failed! (" + de::toString(getResultName(result)) + ")"); 268 269 continue; // didn't work, try with a smaller buffer 270 } 271 272 buffer = Move<VkBuffer>(check<VkBuffer>(rawBuffer), Deleter<VkBuffer>(vk, vkDevice, DE_NULL)); 273 } 274 275 vk.getBufferMemoryRequirements(vkDevice, *buffer, &memReqs); // get the proper size requirement 276 277 if (size > memReqs.size) 278 { 279 std::ostringstream errorMsg; 280 errorMsg << "Requied memory size (" << memReqs.size << " bytes) smaller than the buffer's size (" << size << " bytes)!"; 281 return tcu::TestStatus::fail(errorMsg.str()); 282 } 283 284 // Allocate the memory 285 { 286 VkResult result = VK_ERROR_OUT_OF_HOST_MEMORY; 287 VkDeviceMemory rawMemory = DE_NULL; 288 289 const VkMemoryAllocateInfo memAlloc = 290 { 291 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType; 292 NULL, // const void* pNext; 293 memReqs.size, // VkDeviceSize allocationSize; 294 heapTypeIndex, // uint32_t memoryTypeIndex; 295 }; 296 297 result = vk.allocateMemory(vkDevice, &memAlloc, (VkAllocationCallbacks*)DE_NULL, &rawMemory); 298 299 if (result != VK_SUCCESS) 300 { 301 size = alignDeviceSize(size >> shrinkBits, memReqs.alignment); 302 303 if (size == 0 || memReqs.size == memReqs.alignment) 304 return tcu::TestStatus::fail("Unable to allocate " + de::toString(memReqs.size) + " bytes of memory"); 305 306 continue; // didn't work, try with a smaller allocation (and a smaller buffer) 307 } 308 309 memory = Move<VkDeviceMemory>(check<VkDeviceMemory>(rawMemory), Deleter<VkDeviceMemory>(vk, vkDevice, DE_NULL)); 310 } 311 } // while 312 } 313 314 // Bind the memory 315 if ((m_testCase.flags & (VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT)) != 0) 316 { 317 VkQueue queue = DE_NULL; 318 319 vk.getDeviceQueue(vkDevice, queueFamilyIndex, 0, &queue); 320 321 const VkSparseMemoryBind sparseMemoryBind = 322 { 323 0, // VkDeviceSize resourceOffset; 324 memReqs.size, // VkDeviceSize size; 325 *memory, // VkDeviceMemory memory; 326 0, // VkDeviceSize memoryOffset; 327 0 // VkSparseMemoryBindFlags flags; 328 }; 329 330 const VkSparseBufferMemoryBindInfo sparseBufferMemoryBindInfo = 331 { 332 *buffer, // VkBuffer buffer; 333 1u, // deUint32 bindCount; 334 &sparseMemoryBind // const VkSparseMemoryBind* pBinds; 335 }; 336 337 const VkBindSparseInfo bindSparseInfo = 338 { 339 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, // VkStructureType sType; 340 DE_NULL, // const void* pNext; 341 0, // deUint32 waitSemaphoreCount; 342 DE_NULL, // const VkSemaphore* pWaitSemaphores; 343 1u, // deUint32 bufferBindCount; 344 &sparseBufferMemoryBindInfo, // const VkSparseBufferMemoryBindInfo* pBufferBinds; 345 0, // deUint32 imageOpaqueBindCount; 346 DE_NULL, // const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; 347 0, // deUint32 imageBindCount; 348 DE_NULL, // const VkSparseImageMemoryBindInfo* pImageBinds; 349 0, // deUint32 signalSemaphoreCount; 350 DE_NULL, // const VkSemaphore* pSignalSemaphores; 351 }; 352 353 const VkFenceCreateInfo fenceParams = 354 { 355 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType; 356 DE_NULL, // const void* pNext; 357 0u // VkFenceCreateFlags flags; 358 }; 359 360 const vk::Unique<vk::VkFence> fence(vk::createFence(vk, vkDevice, &fenceParams)); 361 362 if (vk.queueBindSparse(queue, 1, &bindSparseInfo, *fence) != VK_SUCCESS) 363 return tcu::TestStatus::fail("Bind sparse buffer memory failed! (requested memory size: " + de::toString(size) + ")"); 364 365 VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), VK_TRUE, ~(0ull) /* infinity */)); 366 } 367 else 368 { 369 if (vk.bindBufferMemory(vkDevice, *buffer, *memory, 0) != VK_SUCCESS) 370 return tcu::TestStatus::fail("Bind buffer memory failed! (requested memory size: " + de::toString(size) + ")"); 371 } 372 373 return tcu::TestStatus::pass("Pass"); 374 } 375 376 tcu::TestStatus BufferTestInstance::iterate (void) 377 { 378 const VkPhysicalDeviceFeatures& physicalDeviceFeatures = getPhysicalDeviceFeatures(getInstanceInterface(), getPhysicalDevice()); 379 380 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT ) && !physicalDeviceFeatures.sparseBinding) 381 TCU_THROW(NotSupportedError, "Sparse bindings feature is not supported"); 382 383 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT ) && !physicalDeviceFeatures.sparseResidencyBuffer) 384 TCU_THROW(NotSupportedError, "Sparse buffer residency feature is not supported"); 385 386 if ((m_testCase.flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT ) && !physicalDeviceFeatures.sparseResidencyAliased) 387 TCU_THROW(NotSupportedError, "Sparse aliased residency feature is not supported"); 388 389 const VkDeviceSize testSizes[] = 390 { 391 1, 392 1181, 393 15991, 394 16384, 395 ~0ull, // try to exercise a very large buffer too (will be clamped to a sensible size later) 396 }; 397 398 for (int i = 0; i < DE_LENGTH_OF_ARRAY(testSizes); ++i) 399 { 400 const tcu::TestStatus testStatus = bufferCreateAndAllocTest(testSizes[i]); 401 402 if (testStatus.getCode() != QP_TEST_RESULT_PASS) 403 return testStatus; 404 } 405 406 return tcu::TestStatus::pass("Pass"); 407 } 408 409 } // anonymous 410 411 tcu::TestCaseGroup* createBufferTests (tcu::TestContext& testCtx) 412 { 413 const VkBufferUsageFlags bufferUsageModes[] = 414 { 415 VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 416 VK_BUFFER_USAGE_TRANSFER_DST_BIT, 417 VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, 418 VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, 419 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, 420 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, 421 VK_BUFFER_USAGE_INDEX_BUFFER_BIT, 422 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 423 VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT 424 }; 425 426 // \note SPARSE_RESIDENCY and SPARSE_ALIASED have to be used together with the SPARSE_BINDING flag. 427 const VkBufferCreateFlags bufferCreateFlags[] = 428 { 429 0, 430 VK_BUFFER_CREATE_SPARSE_BINDING_BIT, 431 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT, 432 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, 433 VK_BUFFER_CREATE_SPARSE_BINDING_BIT | VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT | VK_BUFFER_CREATE_SPARSE_ALIASED_BIT, 434 }; 435 436 de::MovePtr<tcu::TestCaseGroup> buffersTests (new tcu::TestCaseGroup(testCtx, "buffer", "Buffer Tests")); 437 438 const deUint32 maximumValueOfBufferUsageFlags = (1u << (DE_LENGTH_OF_ARRAY(bufferUsageModes) - 1)) - 1u; 439 440 for (deUint32 bufferCreateFlagsNdx = 0u; bufferCreateFlagsNdx < DE_LENGTH_OF_ARRAY(bufferCreateFlags); bufferCreateFlagsNdx++) 441 for (deUint32 combinedBufferUsageFlags = 1u; combinedBufferUsageFlags <= maximumValueOfBufferUsageFlags; combinedBufferUsageFlags++) 442 { 443 const BufferCaseParameters testParams = 444 { 445 combinedBufferUsageFlags, 446 bufferCreateFlags[bufferCreateFlagsNdx], 447 VK_SHARING_MODE_EXCLUSIVE 448 }; 449 std::ostringstream testName; 450 std::ostringstream testDescription; 451 testName << "create_buffer_" << combinedBufferUsageFlags << "_" << testParams.flags; 452 testDescription << "vkCreateBuffer test " << combinedBufferUsageFlags << " " << testParams.flags; 453 buffersTests->addChild(new BuffersTestCase(testCtx, testName.str(), testDescription.str(), testParams)); 454 } 455 456 return buffersTests.release(); 457 } 458 459 } // api 460 } // vk 461