1/*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2016 The Khronos Group Inc. 6 * Copyright (c) 2016 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 Fill Buffer Tests 23 *//*--------------------------------------------------------------------*/ 24 25#include "vktApiFillBufferTests.hpp" 26#include "vktApiBufferAndImageAllocationUtil.hpp" 27 28#include "deStringUtil.hpp" 29#include "deUniquePtr.hpp" 30#include "vkImageUtil.hpp" 31#include "vkMemUtil.hpp" 32#include "vktTestCase.hpp" 33#include "vktTestCaseUtil.hpp" 34#include "vkQueryUtil.hpp" 35#include "vkRefUtil.hpp" 36#include "tcuImageCompare.hpp" 37#include "tcuTexture.hpp" 38#include "tcuTextureUtil.hpp" 39#include "tcuVectorType.hpp" 40#include "deSharedPtr.hpp" 41 42namespace vkt 43{ 44 45namespace api 46{ 47 48using namespace vk; 49 50namespace 51{ 52 53struct TestParams 54{ 55 enum 56 { 57 TEST_DATA_SIZE = 256 58 }; 59 60 VkDeviceSize dstSize; 61 VkDeviceSize dstOffset; 62 VkDeviceSize size; 63 deUint32 testData[TEST_DATA_SIZE]; 64 de::SharedPtr<IBufferAllocator> bufferAllocator; 65}; 66 67class FillBufferTestInstance : public vkt::TestInstance 68{ 69public: 70 FillBufferTestInstance (Context& context, 71 TestParams testParams); 72 virtual tcu::TestStatus iterate (void); 73protected: 74 const TestParams m_params; 75 76 Move<VkCommandPool> m_cmdPool; 77 Move<VkCommandBuffer> m_cmdBuffer; 78 Move<VkFence> m_fence; 79 de::MovePtr<tcu::TextureLevel> m_destinationTextureLevel; 80 de::MovePtr<tcu::TextureLevel> m_expectedTextureLevel; 81 82 VkCommandBufferBeginInfo m_cmdBufferBeginInfo; 83 84 Move<VkBuffer> m_destination; 85 de::MovePtr<Allocation> m_destinationBufferAlloc; 86 87 void generateBuffer (tcu::PixelBufferAccess buffer, 88 int width, 89 int height, 90 int depth = 1); 91 virtual void generateExpectedResult (void); 92 void uploadBuffer (tcu::ConstPixelBufferAccess 93 bufferAccess, 94 const Allocation& bufferAlloc); 95 virtual tcu::TestStatus checkTestResult (tcu::ConstPixelBufferAccess 96 result); 97 deUint32 calculateSize (tcu::ConstPixelBufferAccess 98 src) const 99 { 100 return src.getWidth() * src.getHeight() * src.getDepth() * tcu::getPixelSize(src.getFormat()); 101 } 102}; 103 104 FillBufferTestInstance::FillBufferTestInstance 105 (Context& context, 106 TestParams testParams) 107 : vkt::TestInstance (context) 108 , m_params (testParams) 109{ 110 const DeviceInterface& vk = context.getDeviceInterface(); 111 const VkDevice vkDevice = context.getDevice(); 112 const deUint32 queueFamilyIndex = context.getUniversalQueueFamilyIndex(); 113 Allocator& memAlloc = context.getDefaultAllocator(); 114 115 // Create command pool 116 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex); 117 118 // Create command buffer 119 m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); 120 121 // Create fence 122 m_fence = createFence(vk, vkDevice); 123 124 testParams.bufferAllocator->createTestBuffer(m_params.dstSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, context, memAlloc, m_destination, MemoryRequirement::HostVisible, m_destinationBufferAlloc); 125} 126 127tcu::TestStatus FillBufferTestInstance::iterate (void) 128{ 129 const int dstLevelWidth = (int)(m_params.dstSize / 4); 130 m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1)); 131 132 generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1); 133 134 generateExpectedResult(); 135 136 uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc); 137 138 const DeviceInterface& vk = m_context.getDeviceInterface(); 139 const VkDevice vkDevice = m_context.getDevice(); 140 const VkQueue queue = m_context.getUniversalQueue(); 141 142 const VkBufferMemoryBarrier dstBufferBarrier = 143 { 144 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; 145 DE_NULL, // const void* pNext; 146 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; 147 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; 148 VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; 149 VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; 150 *m_destination, // VkBuffer buffer; 151 0u, // VkDeviceSize offset; 152 m_params.dstOffset // VkDeviceSize size; 153 }; 154 155 const VkCommandBufferBeginInfo cmdBufferBeginInfo = 156 { 157 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; 158 DE_NULL, // const void* pNext; 159 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; 160 (const VkCommandBufferInheritanceInfo*)DE_NULL, 161 }; 162 163 VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); 164 vk.cmdFillBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData[0]); 165 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL); 166 VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); 167 168 const VkSubmitInfo submitInfo = 169 { 170 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; 171 DE_NULL, // const void* pNext; 172 0u, // deUint32 waitSemaphoreCount; 173 DE_NULL, // const VkSemaphore* pWaitSemaphores; 174 (const VkPipelineStageFlags*)DE_NULL, 175 1u, // deUint32 commandBufferCount; 176 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; 177 0u, // deUint32 signalSemaphoreCount; 178 DE_NULL // const VkSemaphore* pSignalSemaphores; 179 }; 180 181 VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get())); 182 VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence)); 183 VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */)); 184 185 // Read buffer data 186 de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1)); 187 invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset(), m_params.dstOffset); 188 tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr())); 189 190 return checkTestResult(resultLevel->getAccess()); 191} 192 193void FillBufferTestInstance::generateBuffer 194 (tcu::PixelBufferAccess buffer, 195 int width, 196 int height, 197 int depth) 198{ 199 for (int z = 0; z < depth; z++) 200 { 201 for (int y = 0; y < height; y++) 202 { 203 for (int x = 0; x < width; x++) 204 buffer.setPixel(tcu::UVec4(x, y, z, 255), x, y, z); 205 } 206 } 207} 208 209void FillBufferTestInstance::uploadBuffer 210 (tcu::ConstPixelBufferAccess 211 bufferAccess, 212 const Allocation& bufferAlloc) 213{ 214 const DeviceInterface& vk = m_context.getDeviceInterface(); 215 const VkDevice vkDevice = m_context.getDevice(); 216 const deUint32 bufferSize = calculateSize(bufferAccess); 217 218 // Write buffer data 219 deMemcpy(bufferAlloc.getHostPtr(), bufferAccess.getDataPtr(), bufferSize); 220 flushMappedMemoryRange(vk, vkDevice, bufferAlloc.getMemory(), bufferAlloc.getOffset(), bufferSize); 221} 222 223tcu::TestStatus FillBufferTestInstance::checkTestResult 224 (tcu::ConstPixelBufferAccess 225 result) 226{ 227 const tcu::ConstPixelBufferAccess 228 expected = m_expectedTextureLevel->getAccess(); 229 const tcu::UVec4 threshold (0, 0, 0, 0); 230 231 if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparsion", expected, result, threshold, tcu::COMPARE_LOG_RESULT)) 232 { 233 return tcu::TestStatus::fail("Fill and Update Buffer test"); 234 } 235 236 return tcu::TestStatus::pass("Fill and Update Buffer test"); 237} 238 239void FillBufferTestInstance::generateExpectedResult 240 (void) 241{ 242 const tcu::ConstPixelBufferAccess 243 dst = m_destinationTextureLevel->getAccess(); 244 245 m_expectedTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth())); 246 tcu::copy(m_expectedTextureLevel->getAccess(), dst); 247 248 deUint32* currentPtr = (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4; 249 deUint32* endPtr = currentPtr + m_params.size / 4; 250 251 while (currentPtr < endPtr) 252 { 253 *currentPtr = m_params.testData[0]; 254 currentPtr++; 255 } 256} 257 258class FillBufferTestCase : public vkt::TestCase 259{ 260public: 261 FillBufferTestCase (tcu::TestContext& testCtx, 262 const std::string& name, 263 const std::string& description, 264 const TestParams params) 265 : vkt::TestCase (testCtx, name, description) 266 , m_params (params) 267 {} 268 269 virtual TestInstance* createInstance (Context& context) const 270 { 271 return static_cast<TestInstance*>(new FillBufferTestInstance(context, m_params)); 272 } 273private: 274 const TestParams m_params; 275}; 276 277// Update Buffer 278 279class UpdateBufferTestInstance : public FillBufferTestInstance 280{ 281public: 282 UpdateBufferTestInstance (Context& context, 283 TestParams testParams) 284 : FillBufferTestInstance (context, testParams) 285 {} 286 virtual tcu::TestStatus iterate (void); 287 288protected: 289 virtual void generateExpectedResult (void); 290}; 291 292tcu::TestStatus UpdateBufferTestInstance::iterate (void) 293{ 294 const int dstLevelWidth = (int)(m_params.dstSize / 4); 295 m_destinationTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(mapVkFormat(VK_FORMAT_R8G8B8A8_UINT), dstLevelWidth, 1)); 296 297 generateBuffer(m_destinationTextureLevel->getAccess(), dstLevelWidth, 1, 1); 298 299 generateExpectedResult(); 300 301 uploadBuffer(m_destinationTextureLevel->getAccess(), *m_destinationBufferAlloc); 302 303 const DeviceInterface& vk = m_context.getDeviceInterface(); 304 const VkDevice vkDevice = m_context.getDevice(); 305 const VkQueue queue = m_context.getUniversalQueue(); 306 307 const VkBufferMemoryBarrier dstBufferBarrier = 308 { 309 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; 310 DE_NULL, // const void* pNext; 311 VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; 312 VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; 313 VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; 314 VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; 315 *m_destination, // VkBuffer buffer; 316 0u, // VkDeviceSize offset; 317 m_params.dstOffset // VkDeviceSize size; 318 }; 319 320 const VkCommandBufferBeginInfo cmdBufferBeginInfo = 321 { 322 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, // VkStructureType sType; 323 DE_NULL, // const void* pNext; 324 VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, // VkCommandBufferUsageFlags flags; 325 (const VkCommandBufferInheritanceInfo*)DE_NULL, 326 }; 327 328 VK_CHECK(vk.beginCommandBuffer(*m_cmdBuffer, &cmdBufferBeginInfo)); 329 vk.cmdUpdateBuffer(*m_cmdBuffer, *m_destination, m_params.dstOffset, m_params.size, m_params.testData); 330 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1, &dstBufferBarrier, 0, (const VkImageMemoryBarrier*)DE_NULL); 331 VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer)); 332 333 const VkSubmitInfo submitInfo = 334 { 335 VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType; 336 DE_NULL, // const void* pNext; 337 0u, // deUint32 waitSemaphoreCount; 338 DE_NULL, // const VkSemaphore* pWaitSemaphores; 339 (const VkPipelineStageFlags*)DE_NULL, 340 1u, // deUint32 commandBufferCount; 341 &m_cmdBuffer.get(), // const VkCommandBuffer* pCommandBuffers; 342 0u, // deUint32 signalSemaphoreCount; 343 DE_NULL // const VkSemaphore* pSignalSemaphores; 344 }; 345 346 VK_CHECK(vk.resetFences(vkDevice, 1, &m_fence.get())); 347 VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *m_fence)); 348 VK_CHECK(vk.waitForFences(vkDevice, 1, &m_fence.get(), true, ~(0ull) /* infinity */)); 349 350 // Read buffer data 351 de::MovePtr<tcu::TextureLevel> resultLevel (new tcu::TextureLevel(m_destinationTextureLevel->getAccess().getFormat(), dstLevelWidth, 1)); 352 invalidateMappedMemoryRange(vk, vkDevice, m_destinationBufferAlloc->getMemory(), m_destinationBufferAlloc->getOffset(), m_params.dstOffset); 353 tcu::copy(*resultLevel, tcu::ConstPixelBufferAccess(resultLevel->getFormat(), resultLevel->getSize(), m_destinationBufferAlloc->getHostPtr())); 354 355 return checkTestResult(resultLevel->getAccess()); 356} 357 358void UpdateBufferTestInstance::generateExpectedResult 359 (void) 360{ 361 const tcu::ConstPixelBufferAccess 362 dst = m_destinationTextureLevel->getAccess(); 363 364 m_expectedTextureLevel = de::MovePtr<tcu::TextureLevel>(new tcu::TextureLevel(dst.getFormat(), dst.getWidth(), dst.getHeight(), dst.getDepth())); 365 tcu::copy(m_expectedTextureLevel->getAccess(), dst); 366 367 deUint32* currentPtr = (deUint32*) m_expectedTextureLevel->getAccess().getDataPtr() + m_params.dstOffset / 4; 368 369 deMemcpy(currentPtr, m_params.testData, (size_t)m_params.size); 370} 371 372class UpdateBufferTestCase : public vkt::TestCase 373{ 374public: 375 UpdateBufferTestCase (tcu::TestContext& testCtx, 376 const std::string& name, 377 const std::string& description, 378 const TestParams params) 379 : vkt::TestCase (testCtx, name, description) 380 , m_params (params) 381 {} 382 383 virtual TestInstance* createInstance (Context& context) const 384 { 385 return (TestInstance*) new UpdateBufferTestInstance(context, m_params); 386 } 387private: 388 TestParams m_params; 389}; 390 391} // anonymous 392 393tcu::TestCaseGroup* createFillAndUpdateBufferTests (tcu::TestContext& testCtx) 394{ 395 const de::SharedPtr<IBufferAllocator> 396 bufferAllocators[] = 397 { 398 de::SharedPtr<BufferSuballocation>(new BufferSuballocation()), 399 de::SharedPtr<BufferDedicatedAllocation>(new BufferDedicatedAllocation()) 400 }; 401 402 de::MovePtr<tcu::TestCaseGroup> fillAndUpdateBufferTests (new tcu::TestCaseGroup(testCtx, "fill_and_update_buffer", "Fill and Update Buffer Tests")); 403 tcu::TestCaseGroup* bufferViewAllocationGroupTests[] 404 = 405 { 406 new tcu::TestCaseGroup(testCtx, "suballocation", "BufferView Fill and Update Tests for Suballocated Objects"), 407 new tcu::TestCaseGroup(testCtx, "dedicated_alloc", "BufferView Fill and Update Tests for Dedicatedly Allocated Objects") 408 }; 409 for (deUint32 subgroupNdx = 0u; subgroupNdx < DE_LENGTH_OF_ARRAY(bufferViewAllocationGroupTests); ++subgroupNdx) 410 { 411 if (bufferViewAllocationGroupTests[subgroupNdx] == DE_NULL) 412 { 413 TCU_THROW(InternalError, "Could not create test subgroup."); 414 } 415 fillAndUpdateBufferTests->addChild(bufferViewAllocationGroupTests[subgroupNdx]); 416 } 417 TestParams params; 418 params.dstSize = TestParams::TEST_DATA_SIZE; 419 420 421 for (deUint32 buffersAllocationNdx = 0u; buffersAllocationNdx < DE_LENGTH_OF_ARRAY(bufferAllocators); ++buffersAllocationNdx) 422 { 423 DE_ASSERT(params.dstSize <= TestParams::TEST_DATA_SIZE); 424 deMemset(params.testData, 0xFFu, (size_t)params.dstSize); 425 params.bufferAllocator = bufferAllocators[buffersAllocationNdx]; 426 const deUint32 testCaseGroupNdx = buffersAllocationNdx; 427 tcu::TestCaseGroup* currentTestsGroup = bufferViewAllocationGroupTests[testCaseGroupNdx]; 428 429 { 430 const std::string description ("whole buffer"); 431 const std::string testName ("buffer_whole"); 432 433 params.dstOffset = 0; 434 params.size = params.dstSize; 435 436 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params)); 437 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params)); 438 } 439 440 { 441 const std::string description ("first word in buffer"); 442 const std::string testName ("buffer_first_one"); 443 444 params.dstOffset = 0; 445 params.size = 4; 446 447 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params)); 448 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params)); 449 } 450 451 { 452 const std::string description ("second word in buffer"); 453 const std::string testName ("buffer_second_one"); 454 455 params.dstOffset = 4; 456 params.size = 4; 457 458 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params)); 459 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params)); 460 } 461 462 { 463 const std::string description ("buffer second part"); 464 const std::string testName ("buffer_second_part"); 465 466 params.dstOffset = params.dstSize / 2; 467 params.size = params.dstSize / 2; 468 469 currentTestsGroup->addChild(new FillBufferTestCase(testCtx, "fill_" + testName, "Fill " + description, params)); 470 currentTestsGroup->addChild(new UpdateBufferTestCase(testCtx, "update_" + testName, "Update " + description, params)); 471 } 472 } 473 474 return fillAndUpdateBufferTests.release(); 475} 476 477} // api 478} // vkt 479