1 /*------------------------------------------------------------------------- 2 * Vulkan Conformance Tests 3 * ------------------------ 4 * 5 * Copyright (c) 2017 Google 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 21 * \brief YCbCr Test Utilities 22 *//*--------------------------------------------------------------------*/ 23 24 #include "vktYCbCrUtil.hpp" 25 26 #include "vkQueryUtil.hpp" 27 #include "vkRefUtil.hpp" 28 #include "vkTypeUtil.hpp" 29 30 #include "tcuTextureUtil.hpp" 31 32 #include "deSTLUtil.hpp" 33 #include "deUniquePtr.hpp" 34 35 namespace vkt 36 { 37 namespace ycbcr 38 { 39 40 using namespace vk; 41 42 using de::MovePtr; 43 using tcu::UVec2; 44 using std::vector; 45 using std::string; 46 47 typedef de::SharedPtr<Allocation> AllocationSp; 48 typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp; 49 50 // MultiPlaneImageData 51 52 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size) 53 : m_format (format) 54 , m_description (getPlanarFormatDescription(format)) 55 , m_size (size) 56 { 57 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 58 { 59 const deUint32 planeW = size.x() / m_description.planes[planeNdx].widthDivisor; 60 const deUint32 planeH = size.y() / m_description.planes[planeNdx].heightDivisor; 61 const deUint32 planeSize = m_description.planes[planeNdx].elementSizeBytes * planeW * planeH; 62 63 m_planeData[planeNdx].resize(planeSize); 64 } 65 } 66 67 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other) 68 : m_format (other.m_format) 69 , m_description (other.m_description) 70 , m_size (other.m_size) 71 { 72 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 73 m_planeData[planeNdx] = other.m_planeData[planeNdx]; 74 } 75 76 MultiPlaneImageData::~MultiPlaneImageData (void) 77 { 78 } 79 80 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) 81 { 82 void* planePtrs[PlanarFormatDescription::MAX_PLANES]; 83 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES]; 84 85 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 86 { 87 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor; 88 89 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW; 90 planePtrs[planeNdx] = &m_planeData[planeNdx][0]; 91 } 92 93 return vk::getChannelAccess(m_description, 94 m_size, 95 planeRowPitches, 96 planePtrs, 97 channelNdx); 98 } 99 100 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const 101 { 102 const void* planePtrs[PlanarFormatDescription::MAX_PLANES]; 103 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES]; 104 105 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 106 { 107 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor; 108 109 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW; 110 planePtrs[planeNdx] = &m_planeData[planeNdx][0]; 111 } 112 113 return vk::getChannelAccess(m_description, 114 m_size, 115 planeRowPitches, 116 planePtrs, 117 channelNdx); 118 } 119 120 // Misc utilities 121 122 namespace 123 { 124 125 void allocateStagingBuffers (const DeviceInterface& vkd, 126 VkDevice device, 127 Allocator& allocator, 128 const MultiPlaneImageData& imageData, 129 vector<VkBufferSp>* buffers, 130 vector<AllocationSp>* allocations) 131 { 132 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) 133 { 134 const VkBufferCreateInfo bufferInfo = 135 { 136 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 137 DE_NULL, 138 (VkBufferCreateFlags)0u, 139 (VkDeviceSize)imageData.getPlaneSize(planeNdx), 140 VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT, 141 VK_SHARING_MODE_EXCLUSIVE, 142 0u, 143 (const deUint32*)DE_NULL, 144 }; 145 Move<VkBuffer> buffer (createBuffer(vkd, device, &bufferInfo)); 146 MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer), 147 MemoryRequirement::HostVisible|MemoryRequirement::Any)); 148 149 VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset())); 150 151 buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer))); 152 allocations->push_back(AllocationSp(allocation.release())); 153 } 154 } 155 156 void allocateAndWriteStagingBuffers (const DeviceInterface& vkd, 157 VkDevice device, 158 Allocator& allocator, 159 const MultiPlaneImageData& imageData, 160 vector<VkBufferSp>* buffers, 161 vector<AllocationSp>* allocations) 162 { 163 allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations); 164 165 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) 166 { 167 deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx)); 168 flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE); 169 } 170 } 171 172 void readStagingBuffers (MultiPlaneImageData* imageData, 173 const DeviceInterface& vkd, 174 VkDevice device, 175 const vector<AllocationSp>& allocations) 176 { 177 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx) 178 { 179 invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE); 180 deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx)); 181 } 182 } 183 184 } // anonymous 185 186 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling) 187 { 188 const bool disjoint = (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT_KHR) != 0; 189 const VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR* features = findStructure<VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR>(context.getDeviceFeatures2().pNext); 190 vector<string> reqExts; 191 192 reqExts.push_back("VK_KHR_sampler_ycbcr_conversion"); 193 194 if (disjoint) 195 { 196 reqExts.push_back("VK_KHR_bind_memory2"); 197 reqExts.push_back("VK_KHR_get_memory_requirements2"); 198 } 199 200 for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter) 201 { 202 if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), *extIter)) 203 TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str()); 204 } 205 206 if (!features || features->samplerYcbcrConversion == VK_FALSE) 207 TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported"); 208 209 { 210 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(), 211 context.getPhysicalDevice(), 212 format); 213 const VkFormatFeatureFlags featureFlags = tiling == VK_IMAGE_TILING_OPTIMAL 214 ? formatProperties.optimalTilingFeatures 215 : formatProperties.linearTilingFeatures; 216 217 if ((featureFlags & (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR | VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR)) == 0) 218 TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format"); 219 220 if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT_KHR) == 0)) 221 TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format"); 222 } 223 } 224 225 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData) 226 { 227 // \todo [pyry] Optimize, take into account bits that must be 0 228 229 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx) 230 { 231 const size_t planeSize = imageData->getPlaneSize(planeNdx); 232 deUint8* const planePtr = (deUint8*)imageData->getPlanePtr(planeNdx); 233 234 for (size_t ndx = 0; ndx < planeSize; ++ndx) 235 planePtr[ndx] = randomGen->getUint8(); 236 } 237 } 238 239 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal) 240 { 241 const PlanarFormatDescription& formatInfo = imageData->getDescription(); 242 243 // \todo [pyry] Optimize: no point in re-rendering source gradient for each channel. 244 245 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++) 246 { 247 if (formatInfo.hasChannelNdx(channelNdx)) 248 { 249 const tcu::PixelBufferAccess channelAccess = imageData->getChannelAccess(channelNdx); 250 tcu::TextureLevel tmpTexture (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), channelAccess.getWidth(), channelAccess.getHeight()); 251 const tcu::ConstPixelBufferAccess tmpAccess = tmpTexture.getAccess(); 252 253 tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal); 254 255 for (int y = 0; y < channelAccess.getHeight(); ++y) 256 for (int x = 0; x < channelAccess.getWidth(); ++x) 257 { 258 channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y); 259 } 260 } 261 } 262 } 263 264 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface& vkd, 265 VkDevice device, 266 Allocator& allocator, 267 VkImage image, 268 VkFormat format, 269 VkImageCreateFlags createFlags, 270 vk::MemoryRequirement requirement) 271 { 272 vector<AllocationSp> allocations; 273 274 if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT_KHR) != 0) 275 { 276 const deUint32 numPlanes = getPlaneCount(format); 277 278 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx) 279 { 280 const VkImageAspectFlagBits planeAspect = getPlaneAspect(planeNdx); 281 const VkMemoryRequirements reqs = getImagePlaneMemoryRequirements(vkd, device, image, planeAspect); 282 283 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release())); 284 285 bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect); 286 } 287 } 288 else 289 { 290 const VkMemoryRequirements reqs = getImageMemoryRequirements(vkd, device, image); 291 292 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release())); 293 294 VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset())); 295 } 296 297 return allocations; 298 } 299 300 void uploadImage (const DeviceInterface& vkd, 301 VkDevice device, 302 deUint32 queueFamilyNdx, 303 Allocator& allocator, 304 VkImage image, 305 const MultiPlaneImageData& imageData, 306 VkAccessFlags nextAccess, 307 VkImageLayout finalLayout) 308 { 309 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 310 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 311 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 312 vector<VkBufferSp> stagingBuffers; 313 vector<AllocationSp> stagingMemory; 314 315 const PlanarFormatDescription& formatDesc = imageData.getDescription(); 316 317 allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory); 318 319 { 320 const VkCommandBufferBeginInfo beginInfo = 321 { 322 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 323 DE_NULL, 324 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 325 (const VkCommandBufferInheritanceInfo*)DE_NULL 326 }; 327 328 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo)); 329 } 330 331 { 332 const VkImageMemoryBarrier preCopyBarrier = 333 { 334 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 335 DE_NULL, 336 (VkAccessFlags)0, 337 VK_ACCESS_TRANSFER_WRITE_BIT, 338 VK_IMAGE_LAYOUT_UNDEFINED, 339 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 340 VK_QUEUE_FAMILY_IGNORED, 341 VK_QUEUE_FAMILY_IGNORED, 342 image, 343 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 344 }; 345 346 vkd.cmdPipelineBarrier(*cmdBuffer, 347 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, 348 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 349 (VkDependencyFlags)0u, 350 0u, 351 (const VkMemoryBarrier*)DE_NULL, 352 0u, 353 (const VkBufferMemoryBarrier*)DE_NULL, 354 1u, 355 &preCopyBarrier); 356 } 357 358 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) 359 { 360 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 361 ? getPlaneAspect(planeNdx) 362 : VK_IMAGE_ASPECT_COLOR_BIT; 363 const deUint32 planeW = (formatDesc.numPlanes > 1) 364 ? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor 365 : imageData.getSize().x(); 366 const deUint32 planeH = (formatDesc.numPlanes > 1) 367 ? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor 368 : imageData.getSize().y(); 369 const VkBufferImageCopy copy = 370 { 371 0u, // bufferOffset 372 0u, // bufferRowLength 373 0u, // bufferImageHeight 374 { (VkImageAspectFlags)aspect, 0u, 0u, 1u }, 375 makeOffset3D(0u, 0u, 0u), 376 makeExtent3D(planeW, planeH, 1u), 377 }; 378 379 vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©); 380 } 381 382 { 383 const VkImageMemoryBarrier postCopyBarrier = 384 { 385 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 386 DE_NULL, 387 VK_ACCESS_TRANSFER_WRITE_BIT, 388 nextAccess, 389 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 390 finalLayout, 391 VK_QUEUE_FAMILY_IGNORED, 392 VK_QUEUE_FAMILY_IGNORED, 393 image, 394 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 395 }; 396 397 vkd.cmdPipelineBarrier(*cmdBuffer, 398 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 399 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 400 (VkDependencyFlags)0u, 401 0u, 402 (const VkMemoryBarrier*)DE_NULL, 403 0u, 404 (const VkBufferMemoryBarrier*)DE_NULL, 405 1u, 406 &postCopyBarrier); 407 } 408 409 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer)); 410 411 { 412 const Unique<VkFence> fence (createFence(vkd, device)); 413 const VkSubmitInfo submitInfo = 414 { 415 VK_STRUCTURE_TYPE_SUBMIT_INFO, 416 DE_NULL, 417 0u, 418 (const VkSemaphore*)DE_NULL, 419 (const VkPipelineStageFlags*)DE_NULL, 420 1u, 421 &*cmdBuffer, 422 0u, 423 (const VkSemaphore*)DE_NULL, 424 }; 425 426 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence)); 427 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull)); 428 } 429 } 430 431 void fillImageMemory (const vk::DeviceInterface& vkd, 432 vk::VkDevice device, 433 deUint32 queueFamilyNdx, 434 vk::VkImage image, 435 const std::vector<de::SharedPtr<vk::Allocation> >& allocations, 436 const MultiPlaneImageData& imageData, 437 vk::VkAccessFlags nextAccess, 438 vk::VkImageLayout finalLayout) 439 { 440 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 441 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 442 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 443 const PlanarFormatDescription& formatDesc = imageData.getDescription(); 444 445 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx) 446 { 447 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 448 ? getPlaneAspect(planeNdx) 449 : VK_IMAGE_ASPECT_COLOR_BIT; 450 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1 451 ? allocations[planeNdx] 452 : allocations[0]; 453 const size_t planeSize = imageData.getPlaneSize(planeNdx); 454 const deUint32 planeH = imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor; 455 const VkImageSubresource subresource = 456 { 457 aspect, 458 0u, 459 0u, 460 }; 461 VkSubresourceLayout layout; 462 463 vkd.getImageSubresourceLayout(device, image, &subresource, &layout); 464 465 for (deUint32 row = 0; row < planeH; ++row) 466 { 467 const size_t rowSize = planeSize / planeH; 468 void* const dstPtr = ((deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row; 469 const void* const srcPtr = ((const deUint8*)imageData.getPlanePtr(planeNdx)) + row * rowSize; 470 471 deMemcpy(dstPtr, srcPtr, rowSize); 472 } 473 flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE); 474 } 475 476 { 477 const VkCommandBufferBeginInfo beginInfo = 478 { 479 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 480 DE_NULL, 481 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 482 (const VkCommandBufferInheritanceInfo*)DE_NULL 483 }; 484 485 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo)); 486 } 487 488 489 { 490 const VkImageMemoryBarrier postCopyBarrier = 491 { 492 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 493 DE_NULL, 494 0u, 495 nextAccess, 496 VK_IMAGE_LAYOUT_PREINITIALIZED, 497 finalLayout, 498 VK_QUEUE_FAMILY_IGNORED, 499 VK_QUEUE_FAMILY_IGNORED, 500 image, 501 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 502 }; 503 504 vkd.cmdPipelineBarrier(*cmdBuffer, 505 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, 506 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 507 (VkDependencyFlags)0u, 508 0u, 509 (const VkMemoryBarrier*)DE_NULL, 510 0u, 511 (const VkBufferMemoryBarrier*)DE_NULL, 512 1u, 513 &postCopyBarrier); 514 } 515 516 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer)); 517 518 { 519 const Unique<VkFence> fence (createFence(vkd, device)); 520 const VkSubmitInfo submitInfo = 521 { 522 VK_STRUCTURE_TYPE_SUBMIT_INFO, 523 DE_NULL, 524 0u, 525 (const VkSemaphore*)DE_NULL, 526 (const VkPipelineStageFlags*)DE_NULL, 527 1u, 528 &*cmdBuffer, 529 0u, 530 (const VkSemaphore*)DE_NULL, 531 }; 532 533 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence)); 534 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull)); 535 } 536 } 537 538 void downloadImage (const DeviceInterface& vkd, 539 VkDevice device, 540 deUint32 queueFamilyNdx, 541 Allocator& allocator, 542 VkImage image, 543 MultiPlaneImageData* imageData, 544 VkAccessFlags prevAccess, 545 VkImageLayout initialLayout) 546 { 547 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 548 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 549 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 550 vector<VkBufferSp> stagingBuffers; 551 vector<AllocationSp> stagingMemory; 552 553 const PlanarFormatDescription& formatDesc = imageData->getDescription(); 554 555 allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory); 556 557 { 558 const VkCommandBufferBeginInfo beginInfo = 559 { 560 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 561 DE_NULL, 562 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 563 (const VkCommandBufferInheritanceInfo*)DE_NULL 564 }; 565 566 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo)); 567 } 568 569 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx) 570 { 571 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 572 ? getPlaneAspect(planeNdx) 573 : VK_IMAGE_ASPECT_COLOR_BIT; 574 { 575 const VkImageMemoryBarrier preCopyBarrier = 576 { 577 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 578 DE_NULL, 579 prevAccess, 580 VK_ACCESS_TRANSFER_READ_BIT, 581 initialLayout, 582 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 583 VK_QUEUE_FAMILY_IGNORED, 584 VK_QUEUE_FAMILY_IGNORED, 585 image, 586 { 587 aspect, 588 0u, 589 1u, 590 0u, 591 1u 592 } 593 }; 594 595 vkd.cmdPipelineBarrier(*cmdBuffer, 596 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 597 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 598 (VkDependencyFlags)0u, 599 0u, 600 (const VkMemoryBarrier*)DE_NULL, 601 0u, 602 (const VkBufferMemoryBarrier*)DE_NULL, 603 1u, 604 &preCopyBarrier); 605 } 606 { 607 const deUint32 planeW = (formatDesc.numPlanes > 1) 608 ? imageData->getSize().x() / formatDesc.planes[planeNdx].widthDivisor 609 : imageData->getSize().x(); 610 const deUint32 planeH = (formatDesc.numPlanes > 1) 611 ? imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor 612 : imageData->getSize().y(); 613 const VkBufferImageCopy copy = 614 { 615 0u, // bufferOffset 616 0u, // bufferRowLength 617 0u, // bufferImageHeight 618 { (VkImageAspectFlags)aspect, 0u, 0u, 1u }, 619 makeOffset3D(0u, 0u, 0u), 620 makeExtent3D(planeW, planeH, 1u), 621 }; 622 623 vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **stagingBuffers[planeNdx], 1u, ©); 624 } 625 { 626 const VkBufferMemoryBarrier postCopyBarrier = 627 { 628 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 629 DE_NULL, 630 VK_ACCESS_TRANSFER_WRITE_BIT, 631 VK_ACCESS_HOST_READ_BIT, 632 VK_QUEUE_FAMILY_IGNORED, 633 VK_QUEUE_FAMILY_IGNORED, 634 **stagingBuffers[planeNdx], 635 0u, 636 VK_WHOLE_SIZE 637 }; 638 639 vkd.cmdPipelineBarrier(*cmdBuffer, 640 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 641 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 642 (VkDependencyFlags)0u, 643 0u, 644 (const VkMemoryBarrier*)DE_NULL, 645 1u, 646 &postCopyBarrier, 647 0u, 648 (const VkImageMemoryBarrier*)DE_NULL); 649 } 650 } 651 652 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer)); 653 654 { 655 const Unique<VkFence> fence (createFence(vkd, device)); 656 const VkSubmitInfo submitInfo = 657 { 658 VK_STRUCTURE_TYPE_SUBMIT_INFO, 659 DE_NULL, 660 0u, 661 (const VkSemaphore*)DE_NULL, 662 (const VkPipelineStageFlags*)DE_NULL, 663 1u, 664 &*cmdBuffer, 665 0u, 666 (const VkSemaphore*)DE_NULL, 667 }; 668 669 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence)); 670 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull)); 671 } 672 673 readStagingBuffers(imageData, vkd, device, stagingMemory); 674 } 675 676 void readImageMemory (const vk::DeviceInterface& vkd, 677 vk::VkDevice device, 678 deUint32 queueFamilyNdx, 679 vk::VkImage image, 680 const std::vector<de::SharedPtr<vk::Allocation> >& allocations, 681 MultiPlaneImageData* imageData, 682 vk::VkAccessFlags prevAccess, 683 vk::VkImageLayout initialLayout) 684 { 685 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 686 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 687 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 688 const PlanarFormatDescription& formatDesc = imageData->getDescription(); 689 690 { 691 const VkCommandBufferBeginInfo beginInfo = 692 { 693 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 694 DE_NULL, 695 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, 696 (const VkCommandBufferInheritanceInfo*)DE_NULL 697 }; 698 699 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo)); 700 } 701 702 { 703 const VkImageMemoryBarrier preCopyBarrier = 704 { 705 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 706 DE_NULL, 707 prevAccess, 708 vk::VK_ACCESS_HOST_READ_BIT, 709 initialLayout, 710 VK_IMAGE_LAYOUT_GENERAL, 711 VK_QUEUE_FAMILY_IGNORED, 712 VK_QUEUE_FAMILY_IGNORED, 713 image, 714 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 715 }; 716 717 vkd.cmdPipelineBarrier(*cmdBuffer, 718 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, 719 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, 720 (VkDependencyFlags)0u, 721 0u, 722 (const VkMemoryBarrier*)DE_NULL, 723 0u, 724 (const VkBufferMemoryBarrier*)DE_NULL, 725 1u, 726 &preCopyBarrier); 727 } 728 729 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer)); 730 731 { 732 const Unique<VkFence> fence (createFence(vkd, device)); 733 const VkSubmitInfo submitInfo = 734 { 735 VK_STRUCTURE_TYPE_SUBMIT_INFO, 736 DE_NULL, 737 0u, 738 (const VkSemaphore*)DE_NULL, 739 (const VkPipelineStageFlags*)DE_NULL, 740 1u, 741 &*cmdBuffer, 742 0u, 743 (const VkSemaphore*)DE_NULL, 744 }; 745 746 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence)); 747 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull)); 748 } 749 750 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx) 751 { 752 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 753 ? getPlaneAspect(planeNdx) 754 : VK_IMAGE_ASPECT_COLOR_BIT; 755 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1 756 ? allocations[planeNdx] 757 : allocations[0]; 758 const size_t planeSize = imageData->getPlaneSize(planeNdx); 759 const deUint32 planeH = imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor; 760 const VkImageSubresource subresource = 761 { 762 aspect, 763 0u, 764 0u, 765 }; 766 VkSubresourceLayout layout; 767 768 vkd.getImageSubresourceLayout(device, image, &subresource, &layout); 769 770 invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE); 771 772 for (deUint32 row = 0; row < planeH; ++row) 773 { 774 const size_t rowSize = planeSize / planeH; 775 const void* const srcPtr = ((const deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row; 776 void* const dstPtr = ((deUint8*)imageData->getPlanePtr(planeNdx)) + row * rowSize; 777 778 deMemcpy(dstPtr, srcPtr, rowSize); 779 } 780 } 781 } 782 783 } // ycbcr 784 } // vkt 785