1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file vktSparseResourcesBufferSparseBinding.cpp 21 * \brief Buffer Sparse Binding tests 22 *//*--------------------------------------------------------------------*/ 23 24#include "vktSparseResourcesBufferSparseBinding.hpp" 25#include "vktSparseResourcesTestsUtil.hpp" 26#include "vktSparseResourcesBase.hpp" 27#include "vktTestCaseUtil.hpp" 28 29#include "vkDefs.hpp" 30#include "vkRef.hpp" 31#include "vkRefUtil.hpp" 32#include "vkPlatform.hpp" 33#include "vkPrograms.hpp" 34#include "vkMemUtil.hpp" 35#include "vkBarrierUtil.hpp" 36#include "vkBuilderUtil.hpp" 37#include "vkImageUtil.hpp" 38#include "vkQueryUtil.hpp" 39#include "vkTypeUtil.hpp" 40#include "vkCmdUtil.hpp" 41 42#include "deUniquePtr.hpp" 43#include "deStringUtil.hpp" 44 45#include <string> 46#include <vector> 47 48using namespace vk; 49 50namespace vkt 51{ 52namespace sparse 53{ 54namespace 55{ 56 57class BufferSparseBindingCase : public TestCase 58{ 59public: 60 BufferSparseBindingCase (tcu::TestContext& testCtx, 61 const std::string& name, 62 const deUint32 bufferSize, 63 const bool useDeviceGroups); 64 65 TestInstance* createInstance (Context& context) const; 66 virtual void checkSupport (Context& context) const; 67 68private: 69 const deUint32 m_bufferSize; 70 const bool m_useDeviceGroups; 71}; 72 73BufferSparseBindingCase::BufferSparseBindingCase (tcu::TestContext& testCtx, 74 const std::string& name, 75 const deUint32 bufferSize, 76 const bool useDeviceGroups) 77 : TestCase (testCtx, name) 78 , m_bufferSize (bufferSize) 79 , m_useDeviceGroups (useDeviceGroups) 80{ 81} 82 83void BufferSparseBindingCase::checkSupport (Context& context) const 84{ 85 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SPARSE_BINDING); 86} 87 88class BufferSparseBindingInstance : public SparseResourcesBaseInstance 89{ 90public: 91 BufferSparseBindingInstance (Context& context, 92 const deUint32 bufferSize, 93 const bool useDeviceGroups); 94 95 tcu::TestStatus iterate (void); 96 97private: 98 const deUint32 m_bufferSize; 99 const deUint32 m_useDeviceGroups; 100}; 101 102BufferSparseBindingInstance::BufferSparseBindingInstance (Context& context, 103 const deUint32 bufferSize, 104 const bool useDeviceGroups) 105 106 : SparseResourcesBaseInstance (context, useDeviceGroups) 107 , m_bufferSize (bufferSize) 108 , m_useDeviceGroups (useDeviceGroups) 109{ 110} 111 112tcu::TestStatus BufferSparseBindingInstance::iterate (void) 113{ 114 const InstanceInterface& instance = m_context.getInstanceInterface(); 115 { 116 // Create logical device supporting both sparse and compute operations 117 QueueRequirementsVec queueRequirements; 118 queueRequirements.push_back(QueueRequirements(VK_QUEUE_SPARSE_BINDING_BIT, 1u)); 119 queueRequirements.push_back(QueueRequirements(VK_QUEUE_COMPUTE_BIT, 1u)); 120 121 createDeviceSupportingQueues(queueRequirements); 122 } 123 const vk::VkPhysicalDevice& physicalDevice = getPhysicalDevice(); 124 125 const DeviceInterface& deviceInterface = getDeviceInterface(); 126 const Queue& sparseQueue = getQueue(VK_QUEUE_SPARSE_BINDING_BIT, 0); 127 const Queue& computeQueue = getQueue(VK_QUEUE_COMPUTE_BIT, 0); 128 129 // Go through all physical devices 130 for (deUint32 physDevID = 0; physDevID < m_numPhysicalDevices; physDevID++) 131 { 132 const deUint32 firstDeviceID = physDevID; 133 const deUint32 secondDeviceID = (firstDeviceID + 1) % m_numPhysicalDevices; 134 135 VkBufferCreateInfo bufferCreateInfo; 136 137 bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; // VkStructureType sType; 138 bufferCreateInfo.pNext = DE_NULL; // const void* pNext; 139 bufferCreateInfo.flags = VK_BUFFER_CREATE_SPARSE_BINDING_BIT; // VkBufferCreateFlags flags; 140 bufferCreateInfo.size = m_bufferSize; // VkDeviceSize size; 141 bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | 142 VK_BUFFER_USAGE_TRANSFER_DST_BIT; // VkBufferUsageFlags usage; 143 bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; // VkSharingMode sharingMode; 144 bufferCreateInfo.queueFamilyIndexCount = 0u; // deUint32 queueFamilyIndexCount; 145 bufferCreateInfo.pQueueFamilyIndices = DE_NULL; // const deUint32* pQueueFamilyIndices; 146 147 const deUint32 queueFamilyIndices[] = { sparseQueue.queueFamilyIndex, computeQueue.queueFamilyIndex }; 148 149 if (sparseQueue.queueFamilyIndex != computeQueue.queueFamilyIndex) 150 { 151 bufferCreateInfo.sharingMode = VK_SHARING_MODE_CONCURRENT; // VkSharingMode sharingMode; 152 bufferCreateInfo.queueFamilyIndexCount = 2u; // deUint32 queueFamilyIndexCount; 153 bufferCreateInfo.pQueueFamilyIndices = queueFamilyIndices; // const deUint32* pQueueFamilyIndices; 154 } 155 156 // Create sparse buffer 157 const Unique<VkBuffer> sparseBuffer(createBuffer(deviceInterface, getDevice(), &bufferCreateInfo)); 158 159 // Create sparse buffer memory bind semaphore 160 const Unique<VkSemaphore> bufferMemoryBindSemaphore(createSemaphore(deviceInterface, getDevice())); 161 162 const VkMemoryRequirements bufferMemRequirement = getBufferMemoryRequirements(deviceInterface, getDevice(), *sparseBuffer); 163 164 if (bufferMemRequirement.size > getPhysicalDeviceProperties(instance, physicalDevice).limits.sparseAddressSpaceSize) 165 TCU_THROW(NotSupportedError, "Required memory size for sparse resources exceeds device limits"); 166 167 DE_ASSERT((bufferMemRequirement.size % bufferMemRequirement.alignment) == 0); 168 169 Move<VkDeviceMemory> sparseMemoryAllocation; 170 171 { 172 std::vector<VkSparseMemoryBind> sparseMemoryBinds; 173 const deUint32 numSparseBinds = static_cast<deUint32>(bufferMemRequirement.size / bufferMemRequirement.alignment); 174 const deUint32 memoryType = findMatchingMemoryType(instance, getPhysicalDevice(secondDeviceID), bufferMemRequirement, MemoryRequirement::Any); 175 176 if (memoryType == NO_MATCH_FOUND) 177 return tcu::TestStatus::fail("No matching memory type found"); 178 179 if (firstDeviceID != secondDeviceID) 180 { 181 VkPeerMemoryFeatureFlags peerMemoryFeatureFlags = (VkPeerMemoryFeatureFlags)0; 182 const deUint32 heapIndex = getHeapIndexForMemoryType(instance, getPhysicalDevice(secondDeviceID), memoryType); 183 deviceInterface.getDeviceGroupPeerMemoryFeatures(getDevice(), heapIndex, firstDeviceID, secondDeviceID, &peerMemoryFeatureFlags); 184 185 if (((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT) == 0) || 186 ((peerMemoryFeatureFlags & VK_PEER_MEMORY_FEATURE_COPY_DST_BIT) == 0)) 187 { 188 TCU_THROW(NotSupportedError, "Peer memory does not support COPY_SRC and COPY_DST"); 189 } 190 } 191 192 { 193 const VkMemoryAllocateInfo allocateInfo = 194 { 195 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // VkStructureType sType; 196 DE_NULL, // const void* pNext; 197 bufferMemRequirement.size, // VkDeviceSize allocationSize; 198 memoryType, // uint32_t memoryTypeIndex; 199 }; 200 201 sparseMemoryAllocation = allocateMemory(deviceInterface, getDevice(), &allocateInfo); 202 } 203 204 for (deUint32 sparseBindNdx = 0; sparseBindNdx < numSparseBinds; ++sparseBindNdx) 205 { 206 const VkSparseMemoryBind sparseMemoryBind = 207 { 208 bufferMemRequirement.alignment * sparseBindNdx, // VkDeviceSize resourceOffset; 209 bufferMemRequirement.alignment, // VkDeviceSize size; 210 *sparseMemoryAllocation, // VkDeviceMemory memory; 211 bufferMemRequirement.alignment * sparseBindNdx, // VkDeviceSize memoryOffset; 212 (VkSparseMemoryBindFlags)0, // VkSparseMemoryBindFlags flags; 213 }; 214 sparseMemoryBinds.push_back(sparseMemoryBind); 215 } 216 217 const VkSparseBufferMemoryBindInfo sparseBufferBindInfo = makeSparseBufferMemoryBindInfo(*sparseBuffer, numSparseBinds, &sparseMemoryBinds[0]); 218 219 const VkDeviceGroupBindSparseInfo devGroupBindSparseInfo = 220 { 221 VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO, //VkStructureType sType; 222 DE_NULL, //const void* pNext; 223 firstDeviceID, //deUint32 resourceDeviceIndex; 224 secondDeviceID, //deUint32 memoryDeviceIndex; 225 }; 226 227 const VkBindSparseInfo bindSparseInfo = 228 { 229 VK_STRUCTURE_TYPE_BIND_SPARSE_INFO, //VkStructureType sType; 230 m_useDeviceGroups ? &devGroupBindSparseInfo : DE_NULL, //const void* pNext; 231 0u, //deUint32 waitSemaphoreCount; 232 DE_NULL, //const VkSemaphore* pWaitSemaphores; 233 1u, //deUint32 bufferBindCount; 234 &sparseBufferBindInfo, //const VkSparseBufferMemoryBindInfo* pBufferBinds; 235 0u, //deUint32 imageOpaqueBindCount; 236 DE_NULL, //const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds; 237 0u, //deUint32 imageBindCount; 238 DE_NULL, //const VkSparseImageMemoryBindInfo* pImageBinds; 239 1u, //deUint32 signalSemaphoreCount; 240 &bufferMemoryBindSemaphore.get() //const VkSemaphore* pSignalSemaphores; 241 }; 242 243 // Submit sparse bind commands for execution 244 VK_CHECK(deviceInterface.queueBindSparse(sparseQueue.queueHandle, 1u, &bindSparseInfo, DE_NULL)); 245 } 246 247 // Create command buffer for transfer operations 248 const Unique<VkCommandPool> commandPool(makeCommandPool(deviceInterface, getDevice(), computeQueue.queueFamilyIndex)); 249 const Unique<VkCommandBuffer> commandBuffer(allocateCommandBuffer(deviceInterface, getDevice(), *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 250 251 // Start recording transfer commands 252 beginCommandBuffer(deviceInterface, *commandBuffer); 253 254 const VkBufferCreateInfo inputBufferCreateInfo = makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); 255 const Unique<VkBuffer> inputBuffer(createBuffer(deviceInterface, getDevice(), &inputBufferCreateInfo)); 256 const de::UniquePtr<Allocation> inputBufferAlloc(bindBuffer(deviceInterface, getDevice(), getAllocator(), *inputBuffer, MemoryRequirement::HostVisible)); 257 258 std::vector<deUint8> referenceData; 259 referenceData.resize(m_bufferSize); 260 261 for (deUint32 valueNdx = 0; valueNdx < m_bufferSize; ++valueNdx) 262 { 263 referenceData[valueNdx] = static_cast<deUint8>((valueNdx % bufferMemRequirement.alignment) + 1u); 264 } 265 266 deMemcpy(inputBufferAlloc->getHostPtr(), &referenceData[0], m_bufferSize); 267 268 flushAlloc(deviceInterface, getDevice(), *inputBufferAlloc); 269 270 { 271 const VkBufferMemoryBarrier inputBufferBarrier 272 = makeBufferMemoryBarrier(VK_ACCESS_HOST_WRITE_BIT, 273 VK_ACCESS_TRANSFER_READ_BIT, 274 *inputBuffer, 275 0u, 276 m_bufferSize); 277 278 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &inputBufferBarrier, 0u, DE_NULL); 279 } 280 281 { 282 const VkBufferCopy bufferCopy = makeBufferCopy(0u, 0u, m_bufferSize); 283 284 deviceInterface.cmdCopyBuffer(*commandBuffer, *inputBuffer, *sparseBuffer, 1u, &bufferCopy); 285 } 286 287 { 288 const VkBufferMemoryBarrier sparseBufferBarrier 289 = makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, 290 VK_ACCESS_TRANSFER_READ_BIT, 291 *sparseBuffer, 292 0u, 293 m_bufferSize); 294 295 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 1u, &sparseBufferBarrier, 0u, DE_NULL); 296 } 297 298 const VkBufferCreateInfo outputBufferCreateInfo = makeBufferCreateInfo(m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); 299 const Unique<VkBuffer> outputBuffer(createBuffer(deviceInterface, getDevice(), &outputBufferCreateInfo)); 300 const de::UniquePtr<Allocation> outputBufferAlloc(bindBuffer(deviceInterface, getDevice(), getAllocator(), *outputBuffer, MemoryRequirement::HostVisible)); 301 302 { 303 const VkBufferCopy bufferCopy = makeBufferCopy(0u, 0u, m_bufferSize); 304 305 deviceInterface.cmdCopyBuffer(*commandBuffer, *sparseBuffer, *outputBuffer, 1u, &bufferCopy); 306 } 307 308 { 309 const VkBufferMemoryBarrier outputBufferBarrier 310 = makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, 311 VK_ACCESS_HOST_READ_BIT, 312 *outputBuffer, 313 0u, 314 m_bufferSize); 315 316 deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &outputBufferBarrier, 0u, DE_NULL); 317 } 318 319 // End recording transfer commands 320 endCommandBuffer(deviceInterface, *commandBuffer); 321 322 const VkPipelineStageFlags waitStageBits[] = { VK_PIPELINE_STAGE_TRANSFER_BIT }; 323 324 // Submit transfer commands for execution and wait for completion 325 // In case of device groups, submit on the physical device with the resource 326 submitCommandsAndWait(deviceInterface, getDevice(), computeQueue.queueHandle, *commandBuffer, 1u, &bufferMemoryBindSemaphore.get(), 327 waitStageBits, 0, DE_NULL, m_useDeviceGroups, firstDeviceID); 328 329 // Retrieve data from output buffer to host memory 330 invalidateAlloc(deviceInterface, getDevice(), *outputBufferAlloc); 331 332 const deUint8* outputData = static_cast<const deUint8*>(outputBufferAlloc->getHostPtr()); 333 334 // Wait for sparse queue to become idle 335 deviceInterface.queueWaitIdle(sparseQueue.queueHandle); 336 337 // Compare output data with reference data 338 if (deMemCmp(&referenceData[0], outputData, m_bufferSize) != 0) 339 return tcu::TestStatus::fail("Failed"); 340 } 341 return tcu::TestStatus::pass("Passed"); 342} 343 344TestInstance* BufferSparseBindingCase::createInstance (Context& context) const 345{ 346 return new BufferSparseBindingInstance(context, m_bufferSize, m_useDeviceGroups); 347} 348 349} // anonymous ns 350 351void addBufferSparseBindingTests (tcu::TestCaseGroup* group, const bool useDeviceGroups) 352{ 353 group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_10", 1 << 10, useDeviceGroups)); 354 group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_12", 1 << 12, useDeviceGroups)); 355 group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_16", 1 << 16, useDeviceGroups)); 356 group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_17", 1 << 17, useDeviceGroups)); 357 group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_20", 1 << 20, useDeviceGroups)); 358 group->addChild(new BufferSparseBindingCase(group->getTestContext(), "buffer_size_2_24", 1 << 24, useDeviceGroups)); 359} 360 361} // sparse 362} // vkt 363