1 /*------------------------------------------------------------------------ 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2017 The Khronos Group Inc. 6 * Copyright (c) 2017 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 Protected memory copy image to buffer tests 23 *//*--------------------------------------------------------------------*/ 24 25 #include "vktProtectedMemCopyImageToBufferTests.hpp" 26 27 #include "deRandom.hpp" 28 #include "tcuTestLog.hpp" 29 #include "tcuVector.hpp" 30 31 #include "vkPrograms.hpp" 32 #include "vktTestCase.hpp" 33 #include "vktTestGroupUtil.hpp" 34 #include "vkTypeUtil.hpp" 35 #include "vkBuilderUtil.hpp" 36 37 #include "vktProtectedMemContext.hpp" 38 #include "vktProtectedMemUtils.hpp" 39 #include "vktProtectedMemBufferValidator.hpp" 40 41 namespace vkt 42 { 43 namespace ProtectedMem 44 { 45 46 namespace 47 { 48 49 enum { 50 BUFFER_SIZE = 256, 51 RENDER_WIDTH = 8, 52 RENDER_HEIGHT = 8, 53 54 MAX_POSITION = BUFFER_SIZE / 4, 55 }; 56 57 template<typename T> 58 class CopyImageToBufferTestInstance : public ProtectedTestInstance 59 { 60 public: 61 CopyImageToBufferTestInstance (Context& ctx, 62 const vk::VkClearColorValue fillValue, 63 const BufferValidator<T>& validator, 64 const CmdBufferType cmdBufferType); 65 virtual tcu::TestStatus iterate (void); 66 67 private: 68 const vk::VkFormat m_imageFormat; 69 const vk::VkClearColorValue m_fillValue; 70 const BufferValidator<T>& m_validator; 71 const CmdBufferType m_cmdBufferType; 72 }; 73 74 75 template<typename T> 76 class CopyImageToBufferTestCase : public TestCase 77 { 78 public: 79 CopyImageToBufferTestCase (tcu::TestContext& testCtx, 80 const std::string& name, 81 vk::VkClearColorValue fillValue, 82 ValidationData<T> data, 83 CmdBufferType cmdBufferType) 84 : TestCase (testCtx, name, "Copy image to buffer.") 85 , m_fillValue (fillValue) 86 , m_validator (data) 87 , m_cmdBufferType (cmdBufferType) 88 { 89 } 90 91 virtual ~CopyImageToBufferTestCase (void) {} 92 virtual TestInstance* createInstance (Context& ctx) const 93 { 94 return new CopyImageToBufferTestInstance<T>(ctx, m_fillValue, m_validator, m_cmdBufferType); 95 } 96 virtual void initPrograms (vk::SourceCollections& programCollection) const 97 { 98 m_validator.initPrograms(programCollection); 99 } 100 private: 101 vk::VkClearColorValue m_fillValue; 102 BufferValidator<T> m_validator; 103 CmdBufferType m_cmdBufferType; 104 }; 105 106 template<typename T> 107 CopyImageToBufferTestInstance<T>::CopyImageToBufferTestInstance (Context& ctx, 108 const vk::VkClearColorValue fillValue, 109 const BufferValidator<T>& validator, 110 const CmdBufferType cmdBufferType) 111 : ProtectedTestInstance (ctx) 112 , m_imageFormat (vk::VK_FORMAT_R32G32B32A32_UINT) 113 , m_fillValue (fillValue) 114 , m_validator (validator) 115 , m_cmdBufferType (cmdBufferType) 116 { 117 } 118 119 template<typename T> 120 tcu::TestStatus CopyImageToBufferTestInstance<T>::iterate() 121 { 122 ProtectedContext& ctx (m_protectedContext); 123 const vk::DeviceInterface& vk = ctx.getDeviceInterface(); 124 const vk::VkDevice device = ctx.getDevice(); 125 const vk::VkQueue queue = ctx.getQueue(); 126 const deUint32 queueFamilyIndex = ctx.getQueueFamilyIndex(); 127 128 // Create image 129 de::MovePtr<vk::ImageWithMemory> colorImage = createImage2D(ctx, PROTECTION_ENABLED, queueFamilyIndex, 130 RENDER_WIDTH, RENDER_HEIGHT, 131 m_imageFormat, 132 vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT 133 | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT 134 | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT); 135 de::MovePtr<vk::BufferWithMemory> dstBuffer (makeBuffer(ctx, 136 PROTECTION_ENABLED, 137 queueFamilyIndex, 138 (deUint32)(BUFFER_SIZE * sizeof(deUint32)), 139 vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT 140 | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT, 141 vk::MemoryRequirement::Protected)); 142 143 vk::Unique<vk::VkCommandPool> cmdPool (makeCommandPool(vk, device, PROTECTION_ENABLED, queueFamilyIndex)); 144 vk::Unique<vk::VkCommandBuffer> cmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 145 vk::Unique<vk::VkCommandBuffer> secondaryCmdBuffer (vk::allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY)); 146 vk::VkCommandBuffer targetCmdBuffer = (m_cmdBufferType == CMD_BUFFER_SECONDARY) ? *secondaryCmdBuffer : *cmdBuffer; 147 148 // Begin cmd buffer 149 beginCommandBuffer(vk, *cmdBuffer); 150 151 if (m_cmdBufferType == CMD_BUFFER_SECONDARY) 152 { 153 // Begin secondary command buffer 154 const vk::VkCommandBufferInheritanceInfo secCmdBufInheritInfo = 155 { 156 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, 157 DE_NULL, 158 (vk::VkRenderPass)0u, // renderPass 159 0u, // subpass 160 (vk::VkFramebuffer)0u, // framebuffer 161 VK_FALSE, // occlusionQueryEnable 162 (vk::VkQueryControlFlags)0u, // queryFlags 163 (vk::VkQueryPipelineStatisticFlags)0u, // pipelineStatistics 164 }; 165 beginSecondaryCommandBuffer(vk, *secondaryCmdBuffer, secCmdBufInheritInfo); 166 } 167 168 // Start image barrier for source image. 169 { 170 const vk::VkImageMemoryBarrier startImgBarrier = 171 { 172 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType 173 DE_NULL, // const void* pNext 174 0, // VkAccessFlags srcAccessMask 175 vk::VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask 176 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout 177 vk::VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout newLayout 178 queueFamilyIndex, // uint32_t srcQueueFamilyIndex 179 queueFamilyIndex, // uint32_t dstQueueFamilyIndex 180 **colorImage, // VkImage image 181 { 182 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask 183 0u, // uint32_t baseMipLevel 184 1u, // uint32_t mipLevels 185 0u, // uint32_t baseArraySlice 186 1u, // uint32_t subresourceRange 187 } 188 }; 189 190 vk.cmdPipelineBarrier(targetCmdBuffer, 191 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 192 vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 193 (vk::VkDependencyFlags)0, 194 0, (const vk::VkMemoryBarrier*)DE_NULL, 195 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 196 1, &startImgBarrier); 197 } 198 199 // Image clear 200 const vk::VkImageSubresourceRange subresourceRange = 201 { 202 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask 203 0u, // uint32_t baseMipLevel 204 1u, // uint32_t levelCount 205 0u, // uint32_t baseArrayLayer 206 1u, // uint32_t layerCount 207 }; 208 209 vk.cmdClearColorImage(targetCmdBuffer, **colorImage, vk::VK_IMAGE_LAYOUT_GENERAL, &m_fillValue, 1, &subresourceRange); 210 211 // Image barrier to change accessMask to transfer read bit for source image. 212 { 213 const vk::VkImageMemoryBarrier initializeBarrier = 214 { 215 vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType 216 DE_NULL, // const void* pNext 217 vk::VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask 218 vk::VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask 219 vk::VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout oldLayout 220 vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout 221 queueFamilyIndex, // uint32_t srcQueueFamilyIndex 222 queueFamilyIndex, // uint32_t dstQueueFamilyIndex 223 **colorImage, // VkImage image 224 { 225 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask 226 0u, // uint32_t baseMipLevel 227 1u, // uint32_t mipLevels 228 0u, // uint32_t baseArraySlice 229 1u, // uint32_t subresourceRange 230 } 231 }; 232 233 vk.cmdPipelineBarrier(targetCmdBuffer, 234 vk::VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 235 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 236 (vk::VkDependencyFlags)0, 237 0, (const vk::VkMemoryBarrier*)DE_NULL, 238 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 239 1, &initializeBarrier); 240 } 241 242 // Start destination buffer barrier 243 { 244 const vk::VkBufferMemoryBarrier startBufferBarrier = 245 { 246 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType 247 DE_NULL, // const void* pNext 248 0, // VkAccessFlags srcAccessMask 249 vk::VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask 250 queueFamilyIndex, // uint32_t srcQueueFamilyIndex 251 queueFamilyIndex, // uint32_t dstQueueFamilyIndex 252 **dstBuffer, // VkBuffer buffer 253 0u, // VkDeviceSize offset 254 VK_WHOLE_SIZE, // VkDeviceSize size 255 }; 256 257 vk.cmdPipelineBarrier(targetCmdBuffer, 258 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 259 vk::VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 260 (vk::VkDependencyFlags)0, 261 0, (const vk::VkMemoryBarrier*)DE_NULL, 262 1, &startBufferBarrier, 263 0, (const vk::VkImageMemoryBarrier*)DE_NULL); 264 } 265 266 267 // Copy image to buffer 268 const vk::VkImageSubresourceLayers subresourceLayers = 269 { 270 vk::VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask 271 0u, // uint32_t mipLevel 272 0u, // uint32_t baseArrayLayer 273 1u, // uint32_t layerCount 274 }; 275 const vk::VkOffset3D nullOffset = {0u, 0u, 0u}; 276 const vk::VkExtent3D imageExtent = {(deUint32)RENDER_WIDTH, (deUint32)RENDER_HEIGHT, 1u}; 277 const vk::VkBufferImageCopy copyRegion = 278 { 279 0ull, // VkDeviceSize srcOffset; 280 0, // uint32_t bufferRowLength 281 0, // uint32_t bufferImageHeight 282 subresourceLayers, // VkImageSubresourceLayers imageSubresource 283 nullOffset, // VkOffset3D imageOffset 284 imageExtent, // VkExtent3D imageExtent 285 }; 286 vk.cmdCopyImageToBuffer(targetCmdBuffer, **colorImage, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **dstBuffer, 1u, ©Region); 287 288 { 289 const vk::VkBufferMemoryBarrier endBufferBarrier = 290 { 291 vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType 292 DE_NULL, // const void* pNext 293 vk::VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask 294 vk::VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask 295 queueFamilyIndex, // uint32_t srcQueueFamilyIndex 296 queueFamilyIndex, // uint32_t dstQueueFamilyIndex 297 **dstBuffer, // VkBuffer buffer 298 0u, // VkDeviceSize offset 299 VK_WHOLE_SIZE, // VkDeviceSize size 300 }; 301 vk.cmdPipelineBarrier(targetCmdBuffer, 302 vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 303 vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 304 (vk::VkDependencyFlags)0, 305 0, (const vk::VkMemoryBarrier*)DE_NULL, 306 1, &endBufferBarrier, 307 0, (const vk::VkImageMemoryBarrier*)DE_NULL); 308 } 309 310 if (m_cmdBufferType == CMD_BUFFER_SECONDARY) 311 { 312 VK_CHECK(vk.endCommandBuffer(*secondaryCmdBuffer)); 313 vk.cmdExecuteCommands(*cmdBuffer, 1u, &secondaryCmdBuffer.get()); 314 } 315 316 VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); 317 318 // Submit command buffer 319 const vk::Unique<vk::VkFence> fence (vk::createFence(vk, device)); 320 VK_CHECK(queueSubmit(ctx, PROTECTION_ENABLED, queue, *cmdBuffer, *fence, ~0ull)); 321 322 // Log out test data 323 ctx.getTestContext().getLog() 324 << tcu::TestLog::Message << "Fill value: " << m_fillValue << tcu::TestLog::EndMessage; 325 326 // Validate resulting buffer 327 if (m_validator.validateBuffer(ctx, **dstBuffer)) 328 return tcu::TestStatus::pass("Everything went OK"); 329 else 330 return tcu::TestStatus::fail("Something went really wrong"); 331 } 332 333 tcu::TestCaseGroup* createCopyImageToFloatBufferTests(tcu::TestContext& testCtx, CmdBufferType cmdBufferType) 334 { 335 struct { 336 const vk::VkClearColorValue fillValue; 337 const ValidationDataVec4 data; 338 } testData[] = { 339 { { { 0.0f, 0.0f, 0.0f, 0.0f } }, 340 { 341 { tcu::IVec4(0), tcu::IVec4(1), tcu::IVec4(3), tcu::IVec4(7) }, 342 { tcu::Vec4(0.0f), tcu::Vec4(0.0f), tcu::Vec4(0.0f), tcu::Vec4(0.0f) } 343 } 344 }, 345 { { { 1.0f, 1.0f, 1.0f, 1.0f } }, 346 { 347 { tcu::IVec4(2), tcu::IVec4(4), tcu::IVec4(16), tcu::IVec4(15) }, 348 { tcu::Vec4(1.0f), tcu::Vec4(1.0f), tcu::Vec4(1.0f), tcu::Vec4(1.0f) } 349 } 350 }, 351 { { { 0.24f, 0.24f, 0.24f, 0.24f } }, 352 { 353 { tcu::IVec4(3), tcu::IVec4(7), tcu::IVec4(17), tcu::IVec4(37) }, 354 { tcu::Vec4(0.24f), tcu::Vec4(0.24f), tcu::Vec4(0.24f), tcu::Vec4(0.24f) } 355 } 356 }, 357 { { { 0.68f, 0.68f, 0.68f, 0.68f } }, 358 { 359 { tcu::IVec4(7), tcu::IVec4(11), tcu::IVec4(21), tcu::IVec4(40) }, 360 { tcu::Vec4(0.68f), tcu::Vec4(0.68f), tcu::Vec4(0.68f), tcu::Vec4(0.68f) } 361 } 362 }, 363 { { { 0.92f, 0.92f, 0.92f, 0.92f } }, 364 { 365 { tcu::IVec4(5), tcu::IVec4(21), tcu::IVec4(40), tcu::IVec4(57) }, 366 { tcu::Vec4(0.92f), tcu::Vec4(0.92f), tcu::Vec4(0.92f), tcu::Vec4(0.92f) } 367 } 368 }, 369 { { { 0.49f, 0.49f, 0.49f, 0.49f } }, 370 { 371 { tcu::IVec4(23), tcu::IVec4(37), tcu::IVec4(51), tcu::IVec4(63) }, 372 { tcu::Vec4(0.49f), tcu::Vec4(0.49f), tcu::Vec4(0.49f), tcu::Vec4(0.49f) } 373 } 374 }, 375 }; 376 377 de::MovePtr<tcu::TestCaseGroup> copyStaticTests (new tcu::TestCaseGroup(testCtx, "static", "Copy Image to Buffer Tests with static input")); 378 379 for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(testData); ++ndx) 380 { 381 DE_ASSERT(testData[ndx].data.positions[0].x() < MAX_POSITION); 382 DE_ASSERT(testData[ndx].data.positions[1].x() < MAX_POSITION); 383 DE_ASSERT(testData[ndx].data.positions[2].x() < MAX_POSITION); 384 DE_ASSERT(testData[ndx].data.positions[3].x() < MAX_POSITION); 385 386 const std::string name = "copy_" + de::toString(ndx + 1); 387 copyStaticTests->addChild(new CopyImageToBufferTestCase<tcu::Vec4>(testCtx, name.c_str(), testData[ndx].fillValue, testData[ndx].data, cmdBufferType)); 388 } 389 390 /* Add a few randomized tests */ 391 de::MovePtr<tcu::TestCaseGroup> copyRandomTests (new tcu::TestCaseGroup(testCtx, "random", "Copy Image to Buffer Tests with random input")); 392 const int testCount = 10; 393 de::Random rnd (testCtx.getCommandLine().getBaseSeed()); 394 for (int ndx = 0; ndx < testCount; ++ndx) 395 { 396 const std::string name = "copy_" + de::toString(ndx + 1); 397 vk::VkClearValue clearValue = vk::makeClearValueColorF32( 398 rnd.getFloat(0.0, 1.0f), 399 rnd.getFloat(0.0, 1.0f), 400 rnd.getFloat(0.0, 1.0f), 401 rnd.getFloat(0.0, 1.0f)); 402 403 tcu::Vec4 refValue (clearValue.color.float32[0], clearValue.color.float32[1], clearValue.color.float32[2], clearValue.color.float32[3]); 404 ValidationDataVec4 data = 405 { 406 { tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1)), 407 tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1)), 408 tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1)), 409 tcu::IVec4(rnd.getInt(0, MAX_POSITION - 1)) }, 410 { refValue, refValue, refValue, refValue } 411 }; 412 413 DE_ASSERT(data.positions[0].x() < MAX_POSITION); 414 DE_ASSERT(data.positions[1].x() < MAX_POSITION); 415 DE_ASSERT(data.positions[2].x() < MAX_POSITION); 416 DE_ASSERT(data.positions[3].x() < MAX_POSITION); 417 418 copyRandomTests->addChild(new CopyImageToBufferTestCase<tcu::Vec4>(testCtx, name.c_str(), clearValue.color, data, cmdBufferType)); 419 } 420 421 std::string groupName = getCmdBufferTypeStr(cmdBufferType); 422 std::string groupDesc = "Copy Image to Buffer Tests with " + groupName + " command buffer"; 423 de::MovePtr<tcu::TestCaseGroup> copyTests (new tcu::TestCaseGroup(testCtx, groupName.c_str(), groupDesc.c_str())); 424 copyTests->addChild(copyStaticTests.release()); 425 copyTests->addChild(copyRandomTests.release()); 426 return copyTests.release(); 427 } 428 429 } // anonymous 430 431 tcu::TestCaseGroup* createCopyImageToFloatBufferTests (tcu::TestContext& testCtx) 432 { 433 de::MovePtr<tcu::TestCaseGroup> copyTests (new tcu::TestCaseGroup(testCtx, "copy_image_to_float_buffer", "Copy Image to Buffer Tests")); 434 435 copyTests->addChild(createCopyImageToFloatBufferTests(testCtx, CMD_BUFFER_PRIMARY)); 436 copyTests->addChild(createCopyImageToFloatBufferTests(testCtx, CMD_BUFFER_SECONDARY)); 437 438 return copyTests.release(); 439 } 440 441 } // ProtectedMem 442 } // vkt 443