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 #include "vkCmdUtil.hpp" 30 31 #include "tcuTextureUtil.hpp" 32 #include "deMath.h" 33 #include "deFloat16.h" 34 #include "tcuVector.hpp" 35 #include "tcuVectorUtil.hpp" 36 37 #include "deSTLUtil.hpp" 38 #include "deUniquePtr.hpp" 39 40 namespace vkt 41 { 42 namespace ycbcr 43 { 44 45 using namespace vk; 46 47 using de::MovePtr; 48 using tcu::FloatFormat; 49 using tcu::Interval; 50 using tcu::IVec2; 51 using tcu::IVec4; 52 using tcu::UVec2; 53 using tcu::UVec4; 54 using tcu::Vec2; 55 using tcu::Vec4; 56 using std::vector; 57 using std::string; 58 59 typedef de::SharedPtr<Allocation> AllocationSp; 60 typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp; 61 62 // MultiPlaneImageData 63 64 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size) 65 : m_format (format) 66 , m_description (getPlanarFormatDescription(format)) 67 , m_size (size) 68 { 69 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 70 { 71 const deUint32 planeW = size.x() / m_description.planes[planeNdx].widthDivisor; 72 const deUint32 planeH = size.y() / m_description.planes[planeNdx].heightDivisor; 73 const deUint32 planeSize = m_description.planes[planeNdx].elementSizeBytes * planeW * planeH; 74 75 m_planeData[planeNdx].resize(planeSize); 76 } 77 } 78 79 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other) 80 : m_format (other.m_format) 81 , m_description (other.m_description) 82 , m_size (other.m_size) 83 { 84 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 85 m_planeData[planeNdx] = other.m_planeData[planeNdx]; 86 } 87 88 MultiPlaneImageData::~MultiPlaneImageData (void) 89 { 90 } 91 92 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) 93 { 94 void* planePtrs[PlanarFormatDescription::MAX_PLANES]; 95 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES]; 96 97 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 98 { 99 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor; 100 101 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW; 102 planePtrs[planeNdx] = &m_planeData[planeNdx][0]; 103 } 104 105 return vk::getChannelAccess(m_description, 106 m_size, 107 planeRowPitches, 108 planePtrs, 109 channelNdx); 110 } 111 112 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const 113 { 114 const void* planePtrs[PlanarFormatDescription::MAX_PLANES]; 115 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES]; 116 117 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx) 118 { 119 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor; 120 121 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW; 122 planePtrs[planeNdx] = &m_planeData[planeNdx][0]; 123 } 124 125 return vk::getChannelAccess(m_description, 126 m_size, 127 planeRowPitches, 128 planePtrs, 129 channelNdx); 130 } 131 132 // Misc utilities 133 134 namespace 135 { 136 137 void allocateStagingBuffers (const DeviceInterface& vkd, 138 VkDevice device, 139 Allocator& allocator, 140 const MultiPlaneImageData& imageData, 141 vector<VkBufferSp>* buffers, 142 vector<AllocationSp>* allocations) 143 { 144 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) 145 { 146 const VkBufferCreateInfo bufferInfo = 147 { 148 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 149 DE_NULL, 150 (VkBufferCreateFlags)0u, 151 (VkDeviceSize)imageData.getPlaneSize(planeNdx), 152 VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT, 153 VK_SHARING_MODE_EXCLUSIVE, 154 0u, 155 (const deUint32*)DE_NULL, 156 }; 157 Move<VkBuffer> buffer (createBuffer(vkd, device, &bufferInfo)); 158 MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer), 159 MemoryRequirement::HostVisible|MemoryRequirement::Any)); 160 161 VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset())); 162 163 buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer))); 164 allocations->push_back(AllocationSp(allocation.release())); 165 } 166 } 167 168 void allocateAndWriteStagingBuffers (const DeviceInterface& vkd, 169 VkDevice device, 170 Allocator& allocator, 171 const MultiPlaneImageData& imageData, 172 vector<VkBufferSp>* buffers, 173 vector<AllocationSp>* allocations) 174 { 175 allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations); 176 177 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) 178 { 179 deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx)); 180 flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE); 181 } 182 } 183 184 void readStagingBuffers (MultiPlaneImageData* imageData, 185 const DeviceInterface& vkd, 186 VkDevice device, 187 const vector<AllocationSp>& allocations) 188 { 189 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx) 190 { 191 invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE); 192 deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx)); 193 } 194 } 195 196 } // anonymous 197 198 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling) 199 { 200 const bool disjoint = (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0; 201 const VkPhysicalDeviceSamplerYcbcrConversionFeatures features = context.getSamplerYCbCrConversionFeatures(); 202 vector<string> reqExts; 203 204 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_sampler_ycbcr_conversion")) 205 reqExts.push_back("VK_KHR_sampler_ycbcr_conversion"); 206 207 if (disjoint) 208 { 209 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_bind_memory2")) 210 reqExts.push_back("VK_KHR_bind_memory2"); 211 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_get_memory_requirements2")) 212 reqExts.push_back("VK_KHR_get_memory_requirements2"); 213 } 214 215 for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter) 216 { 217 if (!isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), *extIter)) 218 TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str()); 219 } 220 221 if (features.samplerYcbcrConversion == VK_FALSE) 222 { 223 TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported"); 224 } 225 226 { 227 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(), 228 context.getPhysicalDevice(), 229 format); 230 const VkFormatFeatureFlags featureFlags = tiling == VK_IMAGE_TILING_OPTIMAL 231 ? formatProperties.optimalTilingFeatures 232 : formatProperties.linearTilingFeatures; 233 234 if ((featureFlags & (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0) 235 TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format"); 236 237 if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0)) 238 TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format"); 239 } 240 } 241 242 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData) 243 { 244 // \todo [pyry] Optimize, take into account bits that must be 0 245 246 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx) 247 { 248 const size_t planeSize = imageData->getPlaneSize(planeNdx); 249 deUint8* const planePtr = (deUint8*)imageData->getPlanePtr(planeNdx); 250 251 for (size_t ndx = 0; ndx < planeSize; ++ndx) 252 planePtr[ndx] = randomGen->getUint8(); 253 } 254 } 255 256 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal) 257 { 258 const PlanarFormatDescription& formatInfo = imageData->getDescription(); 259 260 // \todo [pyry] Optimize: no point in re-rendering source gradient for each channel. 261 262 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++) 263 { 264 if (formatInfo.hasChannelNdx(channelNdx)) 265 { 266 const tcu::PixelBufferAccess channelAccess = imageData->getChannelAccess(channelNdx); 267 tcu::TextureLevel tmpTexture (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), channelAccess.getWidth(), channelAccess.getHeight()); 268 const tcu::ConstPixelBufferAccess tmpAccess = tmpTexture.getAccess(); 269 270 tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal); 271 272 for (int y = 0; y < channelAccess.getHeight(); ++y) 273 for (int x = 0; x < channelAccess.getWidth(); ++x) 274 { 275 channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y); 276 } 277 } 278 } 279 } 280 281 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface& vkd, 282 VkDevice device, 283 Allocator& allocator, 284 VkImage image, 285 VkFormat format, 286 VkImageCreateFlags createFlags, 287 vk::MemoryRequirement requirement) 288 { 289 vector<AllocationSp> allocations; 290 291 if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0) 292 { 293 const deUint32 numPlanes = getPlaneCount(format); 294 295 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx) 296 { 297 const VkImageAspectFlagBits planeAspect = getPlaneAspect(planeNdx); 298 const VkMemoryRequirements reqs = getImagePlaneMemoryRequirements(vkd, device, image, planeAspect); 299 300 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release())); 301 302 bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect); 303 } 304 } 305 else 306 { 307 const VkMemoryRequirements reqs = getImageMemoryRequirements(vkd, device, image); 308 309 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release())); 310 311 VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset())); 312 } 313 314 return allocations; 315 } 316 317 void uploadImage (const DeviceInterface& vkd, 318 VkDevice device, 319 deUint32 queueFamilyNdx, 320 Allocator& allocator, 321 VkImage image, 322 const MultiPlaneImageData& imageData, 323 VkAccessFlags nextAccess, 324 VkImageLayout finalLayout) 325 { 326 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 327 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 328 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 329 vector<VkBufferSp> stagingBuffers; 330 vector<AllocationSp> stagingMemory; 331 332 const PlanarFormatDescription& formatDesc = imageData.getDescription(); 333 334 allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory); 335 336 beginCommandBuffer(vkd, *cmdBuffer); 337 338 { 339 const VkImageMemoryBarrier preCopyBarrier = 340 { 341 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 342 DE_NULL, 343 (VkAccessFlags)0, 344 VK_ACCESS_TRANSFER_WRITE_BIT, 345 VK_IMAGE_LAYOUT_UNDEFINED, 346 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 347 VK_QUEUE_FAMILY_IGNORED, 348 VK_QUEUE_FAMILY_IGNORED, 349 image, 350 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 351 }; 352 353 vkd.cmdPipelineBarrier(*cmdBuffer, 354 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, 355 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 356 (VkDependencyFlags)0u, 357 0u, 358 (const VkMemoryBarrier*)DE_NULL, 359 0u, 360 (const VkBufferMemoryBarrier*)DE_NULL, 361 1u, 362 &preCopyBarrier); 363 } 364 365 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx) 366 { 367 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 368 ? getPlaneAspect(planeNdx) 369 : VK_IMAGE_ASPECT_COLOR_BIT; 370 const deUint32 planeW = (formatDesc.numPlanes > 1) 371 ? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor 372 : imageData.getSize().x(); 373 const deUint32 planeH = (formatDesc.numPlanes > 1) 374 ? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor 375 : imageData.getSize().y(); 376 const VkBufferImageCopy copy = 377 { 378 0u, // bufferOffset 379 0u, // bufferRowLength 380 0u, // bufferImageHeight 381 { (VkImageAspectFlags)aspect, 0u, 0u, 1u }, 382 makeOffset3D(0u, 0u, 0u), 383 makeExtent3D(planeW, planeH, 1u), 384 }; 385 386 vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©); 387 } 388 389 { 390 const VkImageMemoryBarrier postCopyBarrier = 391 { 392 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 393 DE_NULL, 394 VK_ACCESS_TRANSFER_WRITE_BIT, 395 nextAccess, 396 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 397 finalLayout, 398 VK_QUEUE_FAMILY_IGNORED, 399 VK_QUEUE_FAMILY_IGNORED, 400 image, 401 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 402 }; 403 404 vkd.cmdPipelineBarrier(*cmdBuffer, 405 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 406 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 407 (VkDependencyFlags)0u, 408 0u, 409 (const VkMemoryBarrier*)DE_NULL, 410 0u, 411 (const VkBufferMemoryBarrier*)DE_NULL, 412 1u, 413 &postCopyBarrier); 414 } 415 416 endCommandBuffer(vkd, *cmdBuffer); 417 418 submitCommandsAndWait(vkd, device, queue, *cmdBuffer); 419 } 420 421 void fillImageMemory (const vk::DeviceInterface& vkd, 422 vk::VkDevice device, 423 deUint32 queueFamilyNdx, 424 vk::VkImage image, 425 const std::vector<de::SharedPtr<vk::Allocation> >& allocations, 426 const MultiPlaneImageData& imageData, 427 vk::VkAccessFlags nextAccess, 428 vk::VkImageLayout finalLayout) 429 { 430 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 431 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 432 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 433 const PlanarFormatDescription& formatDesc = imageData.getDescription(); 434 435 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx) 436 { 437 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 438 ? getPlaneAspect(planeNdx) 439 : VK_IMAGE_ASPECT_COLOR_BIT; 440 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1 441 ? allocations[planeNdx] 442 : allocations[0]; 443 const size_t planeSize = imageData.getPlaneSize(planeNdx); 444 const deUint32 planeH = imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor; 445 const VkImageSubresource subresource = 446 { 447 static_cast<vk::VkImageAspectFlags>(aspect), 448 0u, 449 0u, 450 }; 451 VkSubresourceLayout layout; 452 453 vkd.getImageSubresourceLayout(device, image, &subresource, &layout); 454 455 for (deUint32 row = 0; row < planeH; ++row) 456 { 457 const size_t rowSize = planeSize / planeH; 458 void* const dstPtr = ((deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row; 459 const void* const srcPtr = ((const deUint8*)imageData.getPlanePtr(planeNdx)) + row * rowSize; 460 461 deMemcpy(dstPtr, srcPtr, rowSize); 462 } 463 flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE); 464 } 465 466 beginCommandBuffer(vkd, *cmdBuffer); 467 468 { 469 const VkImageMemoryBarrier postCopyBarrier = 470 { 471 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 472 DE_NULL, 473 0u, 474 nextAccess, 475 VK_IMAGE_LAYOUT_PREINITIALIZED, 476 finalLayout, 477 VK_QUEUE_FAMILY_IGNORED, 478 VK_QUEUE_FAMILY_IGNORED, 479 image, 480 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 481 }; 482 483 vkd.cmdPipelineBarrier(*cmdBuffer, 484 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, 485 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 486 (VkDependencyFlags)0u, 487 0u, 488 (const VkMemoryBarrier*)DE_NULL, 489 0u, 490 (const VkBufferMemoryBarrier*)DE_NULL, 491 1u, 492 &postCopyBarrier); 493 } 494 495 endCommandBuffer(vkd, *cmdBuffer); 496 497 submitCommandsAndWait(vkd, device, queue, *cmdBuffer); 498 } 499 500 void downloadImage (const DeviceInterface& vkd, 501 VkDevice device, 502 deUint32 queueFamilyNdx, 503 Allocator& allocator, 504 VkImage image, 505 MultiPlaneImageData* imageData, 506 VkAccessFlags prevAccess, 507 VkImageLayout initialLayout) 508 { 509 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 510 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 511 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 512 vector<VkBufferSp> stagingBuffers; 513 vector<AllocationSp> stagingMemory; 514 515 const PlanarFormatDescription& formatDesc = imageData->getDescription(); 516 517 allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory); 518 519 beginCommandBuffer(vkd, *cmdBuffer); 520 521 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx) 522 { 523 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 524 ? getPlaneAspect(planeNdx) 525 : VK_IMAGE_ASPECT_COLOR_BIT; 526 { 527 const VkImageMemoryBarrier preCopyBarrier = 528 { 529 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 530 DE_NULL, 531 prevAccess, 532 VK_ACCESS_TRANSFER_READ_BIT, 533 initialLayout, 534 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, 535 VK_QUEUE_FAMILY_IGNORED, 536 VK_QUEUE_FAMILY_IGNORED, 537 image, 538 { 539 static_cast<vk::VkImageAspectFlags>(aspect), 540 0u, 541 1u, 542 0u, 543 1u 544 } 545 }; 546 547 vkd.cmdPipelineBarrier(*cmdBuffer, 548 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 549 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 550 (VkDependencyFlags)0u, 551 0u, 552 (const VkMemoryBarrier*)DE_NULL, 553 0u, 554 (const VkBufferMemoryBarrier*)DE_NULL, 555 1u, 556 &preCopyBarrier); 557 } 558 { 559 const deUint32 planeW = (formatDesc.numPlanes > 1) 560 ? imageData->getSize().x() / formatDesc.planes[planeNdx].widthDivisor 561 : imageData->getSize().x(); 562 const deUint32 planeH = (formatDesc.numPlanes > 1) 563 ? imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor 564 : imageData->getSize().y(); 565 const VkBufferImageCopy copy = 566 { 567 0u, // bufferOffset 568 0u, // bufferRowLength 569 0u, // bufferImageHeight 570 { (VkImageAspectFlags)aspect, 0u, 0u, 1u }, 571 makeOffset3D(0u, 0u, 0u), 572 makeExtent3D(planeW, planeH, 1u), 573 }; 574 575 vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, **stagingBuffers[planeNdx], 1u, ©); 576 } 577 { 578 const VkBufferMemoryBarrier postCopyBarrier = 579 { 580 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, 581 DE_NULL, 582 VK_ACCESS_TRANSFER_WRITE_BIT, 583 VK_ACCESS_HOST_READ_BIT, 584 VK_QUEUE_FAMILY_IGNORED, 585 VK_QUEUE_FAMILY_IGNORED, 586 **stagingBuffers[planeNdx], 587 0u, 588 VK_WHOLE_SIZE 589 }; 590 591 vkd.cmdPipelineBarrier(*cmdBuffer, 592 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT, 593 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, 594 (VkDependencyFlags)0u, 595 0u, 596 (const VkMemoryBarrier*)DE_NULL, 597 1u, 598 &postCopyBarrier, 599 0u, 600 (const VkImageMemoryBarrier*)DE_NULL); 601 } 602 } 603 604 endCommandBuffer(vkd, *cmdBuffer); 605 606 submitCommandsAndWait(vkd, device, queue, *cmdBuffer); 607 608 readStagingBuffers(imageData, vkd, device, stagingMemory); 609 } 610 611 void readImageMemory (const vk::DeviceInterface& vkd, 612 vk::VkDevice device, 613 deUint32 queueFamilyNdx, 614 vk::VkImage image, 615 const std::vector<de::SharedPtr<vk::Allocation> >& allocations, 616 MultiPlaneImageData* imageData, 617 vk::VkAccessFlags prevAccess, 618 vk::VkImageLayout initialLayout) 619 { 620 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u); 621 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx)); 622 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); 623 const PlanarFormatDescription& formatDesc = imageData->getDescription(); 624 625 beginCommandBuffer(vkd, *cmdBuffer); 626 627 { 628 const VkImageMemoryBarrier preCopyBarrier = 629 { 630 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 631 DE_NULL, 632 prevAccess, 633 vk::VK_ACCESS_HOST_READ_BIT, 634 initialLayout, 635 VK_IMAGE_LAYOUT_GENERAL, 636 VK_QUEUE_FAMILY_IGNORED, 637 VK_QUEUE_FAMILY_IGNORED, 638 image, 639 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } 640 }; 641 642 vkd.cmdPipelineBarrier(*cmdBuffer, 643 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 644 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT, 645 (VkDependencyFlags)0u, 646 0u, 647 (const VkMemoryBarrier*)DE_NULL, 648 0u, 649 (const VkBufferMemoryBarrier*)DE_NULL, 650 1u, 651 &preCopyBarrier); 652 } 653 654 endCommandBuffer(vkd, *cmdBuffer); 655 656 submitCommandsAndWait(vkd, device, queue, *cmdBuffer); 657 658 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx) 659 { 660 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1) 661 ? getPlaneAspect(planeNdx) 662 : VK_IMAGE_ASPECT_COLOR_BIT; 663 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1 664 ? allocations[planeNdx] 665 : allocations[0]; 666 const size_t planeSize = imageData->getPlaneSize(planeNdx); 667 const deUint32 planeH = imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor; 668 const VkImageSubresource subresource = 669 { 670 static_cast<vk::VkImageAspectFlags>(aspect), 671 0u, 672 0u, 673 }; 674 VkSubresourceLayout layout; 675 676 vkd.getImageSubresourceLayout(device, image, &subresource, &layout); 677 678 invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE); 679 680 for (deUint32 row = 0; row < planeH; ++row) 681 { 682 const size_t rowSize = planeSize / planeH; 683 const void* const srcPtr = ((const deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row; 684 void* const dstPtr = ((deUint8*)imageData->getPlanePtr(planeNdx)) + row * rowSize; 685 686 deMemcpy(dstPtr, srcPtr, rowSize); 687 } 688 } 689 } 690 691 // ChannelAccess utilities 692 namespace 693 { 694 695 //! Extend < 32b signed integer to 32b 696 inline deInt32 signExtend (deUint32 src, int bits) 697 { 698 const deUint32 signBit = 1u << (bits-1); 699 700 src |= ~((src & signBit) - 1); 701 702 return (deInt32)src; 703 } 704 705 deUint32 divRoundUp (deUint32 a, deUint32 b) 706 { 707 if (a % b == 0) 708 return a / b; 709 else 710 return (a / b) + 1; 711 } 712 713 // \todo Taken from tcuTexture.cpp 714 // \todo [2011-09-21 pyry] Move to tcutil? 715 template <typename T> 716 inline T convertSatRte (float f) 717 { 718 // \note Doesn't work for 64-bit types 719 DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64)); 720 DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0)); 721 722 deInt64 minVal = std::numeric_limits<T>::min(); 723 deInt64 maxVal = std::numeric_limits<T>::max(); 724 float q = deFloatFrac(f); 725 deInt64 intVal = (deInt64)(f-q); 726 727 // Rounding. 728 if (q == 0.5f) 729 { 730 if (intVal % 2 != 0) 731 intVal++; 732 } 733 else if (q > 0.5f) 734 intVal++; 735 // else Don't add anything 736 737 // Saturate. 738 intVal = de::max(minVal, de::min(maxVal, intVal)); 739 740 return (T)intVal; 741 } 742 743 } // anonymous 744 745 ChannelAccess::ChannelAccess (tcu::TextureChannelClass channelClass, 746 deUint8 channelSize, 747 const tcu::IVec3& size, 748 const tcu::IVec3& bitPitch, 749 void* data, 750 deUint32 bitOffset) 751 : m_channelClass (channelClass) 752 , m_channelSize (channelSize) 753 , m_size (size) 754 , m_bitPitch (bitPitch) 755 756 , m_data ((deUint8*)data + (bitOffset / 8)) 757 , m_bitOffset (bitOffset % 8) 758 { 759 } 760 761 deUint32 ChannelAccess::getChannelUint (const tcu::IVec3& pos) const 762 { 763 DE_ASSERT(pos[0] < m_size[0]); 764 DE_ASSERT(pos[1] < m_size[1]); 765 DE_ASSERT(pos[2] < m_size[2]); 766 767 const deInt32 bitOffset (m_bitOffset + tcu::dot(m_bitPitch, pos)); 768 const deUint8* const firstByte = ((const deUint8*)m_data) + (bitOffset / 8); 769 const deUint32 byteCount = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u); 770 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u); 771 const deUint32 offset = bitOffset % 8; 772 deUint32 bits = 0u; 773 774 deMemcpy(&bits, firstByte, byteCount); 775 776 return (bits >> offset) & mask; 777 } 778 779 void ChannelAccess::setChannel (const tcu::IVec3& pos, deUint32 x) 780 { 781 DE_ASSERT(pos[0] < m_size[0]); 782 DE_ASSERT(pos[1] < m_size[1]); 783 DE_ASSERT(pos[2] < m_size[2]); 784 785 const deInt32 bitOffset (m_bitOffset + tcu::dot(m_bitPitch, pos)); 786 deUint8* const firstByte = ((deUint8*)m_data) + (bitOffset / 8); 787 const deUint32 byteCount = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u); 788 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u); 789 const deUint32 offset = bitOffset % 8; 790 791 const deUint32 bits = (x & mask) << offset; 792 deUint32 oldBits = 0; 793 794 deMemcpy(&oldBits, firstByte, byteCount); 795 796 { 797 const deUint32 newBits = bits | (oldBits & (~(mask << offset))); 798 799 deMemcpy(firstByte, &newBits, byteCount); 800 } 801 } 802 803 float ChannelAccess::getChannel (const tcu::IVec3& pos) const 804 { 805 const deUint32 bits (getChannelUint(pos)); 806 807 switch (m_channelClass) 808 { 809 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 810 return (float)bits / (float)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u)); 811 812 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 813 return (float)bits; 814 815 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 816 return de::max(-1.0f, (float)signExtend(bits, m_channelSize) / (float)((0x1u << (m_channelSize - 1u)) - 1u)); 817 818 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 819 return (float)signExtend(bits, m_channelSize); 820 821 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 822 if (m_channelSize == 32) 823 return tcu::Float32(bits).asFloat(); 824 else 825 { 826 DE_FATAL("Float type not supported"); 827 return -1.0f; 828 } 829 830 default: 831 DE_FATAL("Unknown texture channel class"); 832 return -1.0f; 833 } 834 } 835 836 tcu::Interval ChannelAccess::getChannel (const tcu::FloatFormat& conversionFormat, 837 const tcu::IVec3& pos) const 838 { 839 const deUint32 bits (getChannelUint(pos)); 840 841 switch (m_channelClass) 842 { 843 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 844 return conversionFormat.roundOut(conversionFormat.roundOut((double)bits, false) 845 / conversionFormat.roundOut((double)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u)), false), false); 846 847 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 848 return conversionFormat.roundOut((double)bits, false); 849 850 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 851 { 852 const tcu::Interval result (conversionFormat.roundOut(conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false) 853 / conversionFormat.roundOut((double)((0x1u << (m_channelSize - 1u)) - 1u), false), false)); 854 855 return tcu::Interval(de::max(-1.0, result.lo()), de::max(-1.0, result.hi())); 856 } 857 858 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 859 return conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false); 860 861 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 862 if (m_channelSize == 32) 863 return conversionFormat.roundOut(tcu::Float32(bits).asFloat(), false); 864 else 865 { 866 DE_FATAL("Float type not supported"); 867 return tcu::Interval(); 868 } 869 870 default: 871 DE_FATAL("Unknown texture channel class"); 872 return tcu::Interval(); 873 } 874 } 875 876 void ChannelAccess::setChannel (const tcu::IVec3& pos, float x) 877 { 878 DE_ASSERT(pos[0] < m_size[0]); 879 DE_ASSERT(pos[1] < m_size[1]); 880 DE_ASSERT(pos[2] < m_size[2]); 881 882 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u); 883 884 switch (m_channelClass) 885 { 886 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 887 { 888 const deUint32 maxValue (mask); 889 const deUint32 value (de::min(maxValue, (deUint32)convertSatRte<deUint32>(x * (float)maxValue))); 890 setChannel(pos, value); 891 break; 892 } 893 894 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 895 { 896 const deInt32 range ((0x1u << (m_channelSize - 1u)) - 1u); 897 const deUint32 value ((deUint32)de::clamp<deInt32>(convertSatRte<deInt32>(x * (float)range), -range, range)); 898 setChannel(pos, value); 899 break; 900 } 901 902 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 903 { 904 const deUint32 maxValue (mask); 905 const deUint32 value (de::min(maxValue, (deUint32)x)); 906 setChannel(pos, value); 907 break; 908 } 909 910 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 911 { 912 const deInt32 minValue (-(deInt32)(1u << (m_channelSize - 1u))); 913 const deInt32 maxValue ((deInt32)((1u << (m_channelSize - 1u)) - 1u)); 914 const deUint32 value ((deUint32)de::clamp((deInt32)x, minValue, maxValue)); 915 setChannel(pos, value); 916 break; 917 } 918 919 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 920 { 921 if (m_channelSize == 32) 922 { 923 const deUint32 value = tcu::Float32(x).bits(); 924 setChannel(pos, value); 925 } 926 else 927 DE_FATAL("Float type not supported"); 928 break; 929 } 930 931 default: 932 DE_FATAL("Unknown texture channel class"); 933 } 934 } 935 936 ChannelAccess getChannelAccess (MultiPlaneImageData& data, 937 const vk::PlanarFormatDescription& formatInfo, 938 const UVec2& size, 939 int channelNdx) 940 { 941 DE_ASSERT(formatInfo.hasChannelNdx(channelNdx)); 942 943 const deUint32 planeNdx = formatInfo.channels[channelNdx].planeNdx; 944 const deUint32 valueOffsetBits = formatInfo.channels[channelNdx].offsetBits; 945 const deUint32 pixelStrideBytes = formatInfo.channels[channelNdx].strideBytes; 946 const deUint32 pixelStrideBits = pixelStrideBytes * 8; 947 const deUint8 sizeBits = formatInfo.channels[channelNdx].sizeBits; 948 949 DE_ASSERT(size.x() % formatInfo.planes[planeNdx].widthDivisor == 0); 950 DE_ASSERT(size.y() % formatInfo.planes[planeNdx].heightDivisor == 0); 951 952 deUint32 accessWidth = size.x() / formatInfo.planes[planeNdx].widthDivisor; 953 const deUint32 accessHeight = size.y() / formatInfo.planes[planeNdx].heightDivisor; 954 const deUint32 elementSizeBytes = formatInfo.planes[planeNdx].elementSizeBytes; 955 956 const deUint32 rowPitch = formatInfo.planes[planeNdx].elementSizeBytes * accessWidth; 957 const deUint32 rowPitchBits = rowPitch * 8; 958 959 if (pixelStrideBytes != elementSizeBytes) 960 { 961 DE_ASSERT(elementSizeBytes % pixelStrideBytes == 0); 962 accessWidth *= elementSizeBytes/pixelStrideBytes; 963 } 964 965 return ChannelAccess((tcu::TextureChannelClass)formatInfo.channels[channelNdx].type, sizeBits, tcu::IVec3(accessWidth, accessHeight, 1u), tcu::IVec3((int)pixelStrideBits, (int)rowPitchBits, 0), data.getPlanePtr(planeNdx), (deUint32)valueOffsetBits); 966 } 967 968 bool isXChromaSubsampled (vk::VkFormat format) 969 { 970 switch (format) 971 { 972 case vk::VK_FORMAT_G8B8G8R8_422_UNORM: 973 case vk::VK_FORMAT_B8G8R8G8_422_UNORM: 974 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 975 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 976 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: 977 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: 978 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: 979 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: 980 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: 981 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 982 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: 983 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: 984 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: 985 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: 986 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: 987 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: 988 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: 989 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: 990 case vk::VK_FORMAT_G16B16G16R16_422_UNORM: 991 case vk::VK_FORMAT_B16G16R16G16_422_UNORM: 992 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: 993 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: 994 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: 995 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: 996 return true; 997 998 default: 999 return false; 1000 } 1001 } 1002 1003 bool isYChromaSubsampled (vk::VkFormat format) 1004 { 1005 switch (format) 1006 { 1007 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 1008 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 1009 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: 1010 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 1011 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: 1012 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: 1013 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: 1014 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: 1015 return true; 1016 1017 default: 1018 return false; 1019 } 1020 } 1021 1022 bool areLsb6BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat) 1023 { 1024 if ((srcFormat == vk::VK_FORMAT_R10X6_UNORM_PACK16) || 1025 (dstFormat == vk::VK_FORMAT_R10X6_UNORM_PACK16) || 1026 (srcFormat == vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16) || 1027 (dstFormat == vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16) || 1028 (srcFormat == vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) || 1029 (dstFormat == vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16) || 1030 (srcFormat == vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) || 1031 (dstFormat == vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16) || 1032 (srcFormat == vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) || 1033 (dstFormat == vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16) || 1034 (srcFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16) || 1035 (dstFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16) || 1036 (srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) || 1037 (dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16) || 1038 (srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) || 1039 (dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16) || 1040 (srcFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16) || 1041 (dstFormat == vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16) || 1042 (srcFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16) || 1043 (dstFormat == vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16)) 1044 { 1045 return true; 1046 } 1047 1048 return false; 1049 } 1050 1051 bool areLsb4BitsDontCare(vk::VkFormat srcFormat, vk::VkFormat dstFormat) 1052 { 1053 if ((srcFormat == vk::VK_FORMAT_R12X4_UNORM_PACK16) || 1054 (dstFormat == vk::VK_FORMAT_R12X4_UNORM_PACK16) || 1055 (srcFormat == vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16) || 1056 (dstFormat == vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16) || 1057 (srcFormat == vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16) || 1058 (dstFormat == vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16) || 1059 (srcFormat == vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) || 1060 (dstFormat == vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16) || 1061 (srcFormat == vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) || 1062 (dstFormat == vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16) || 1063 (srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) || 1064 (dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16) || 1065 (srcFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16) || 1066 (dstFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16) || 1067 (srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) || 1068 (dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16) || 1069 (srcFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16) || 1070 (dstFormat == vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16) || 1071 (srcFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16) || 1072 (dstFormat == vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16)) 1073 { 1074 return true; 1075 } 1076 1077 return false; 1078 } 1079 1080 // \note Used for range expansion 1081 tcu::UVec4 getYCbCrBitDepth (vk::VkFormat format) 1082 { 1083 switch (format) 1084 { 1085 case vk::VK_FORMAT_G8B8G8R8_422_UNORM: 1086 case vk::VK_FORMAT_B8G8R8G8_422_UNORM: 1087 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 1088 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 1089 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: 1090 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: 1091 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: 1092 return tcu::UVec4(8, 8, 8, 0); 1093 1094 case vk::VK_FORMAT_R10X6_UNORM_PACK16: 1095 return tcu::UVec4(10, 0, 0, 0); 1096 1097 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16: 1098 return tcu::UVec4(10, 10, 0, 0); 1099 1100 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: 1101 return tcu::UVec4(10, 10, 10, 10); 1102 1103 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: 1104 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: 1105 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: 1106 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 1107 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: 1108 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: 1109 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: 1110 return tcu::UVec4(10, 10, 10, 0); 1111 1112 case vk::VK_FORMAT_R12X4_UNORM_PACK16: 1113 return tcu::UVec4(12, 0, 0, 0); 1114 1115 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16: 1116 return tcu::UVec4(12, 12, 0, 0); 1117 1118 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: 1119 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: 1120 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: 1121 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: 1122 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: 1123 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: 1124 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: 1125 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: 1126 return tcu::UVec4(12, 12, 12, 12); 1127 1128 case vk::VK_FORMAT_G16B16G16R16_422_UNORM: 1129 case vk::VK_FORMAT_B16G16R16G16_422_UNORM: 1130 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: 1131 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: 1132 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: 1133 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: 1134 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: 1135 return tcu::UVec4(16, 16, 16, 0); 1136 1137 default: 1138 return tcu::getTextureFormatBitDepth(vk::mapVkFormat(format)).cast<deUint32>(); 1139 } 1140 } 1141 1142 // \note Taken from explicit lod filtering tests 1143 tcu::FloatFormat getYCbCrFilteringPrecision (vk::VkFormat format) 1144 { 1145 const tcu::FloatFormat reallyLow (0, 0, 6, false, tcu::YES); 1146 const tcu::FloatFormat low (0, 0, 7, false, tcu::YES); 1147 const tcu::FloatFormat fp16 (-14, 15, 10, false); 1148 const tcu::FloatFormat fp32 (-126, 127, 23, true); 1149 1150 switch (format) 1151 { 1152 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16: 1153 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16: 1154 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16: 1155 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16: 1156 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16: 1157 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16: 1158 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16: 1159 return reallyLow; 1160 1161 case vk::VK_FORMAT_R8G8B8_UNORM: 1162 case vk::VK_FORMAT_B8G8R8_UNORM: 1163 case vk::VK_FORMAT_R8G8B8A8_UNORM: 1164 case vk::VK_FORMAT_B8G8R8A8_UNORM: 1165 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32: 1166 case vk::VK_FORMAT_G8B8G8R8_422_UNORM: 1167 case vk::VK_FORMAT_B8G8R8G8_422_UNORM: 1168 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 1169 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 1170 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: 1171 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: 1172 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: 1173 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32: 1174 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32: 1175 return low; 1176 1177 case vk::VK_FORMAT_R16G16B16_UNORM: 1178 case vk::VK_FORMAT_R16G16B16A16_UNORM: 1179 case vk::VK_FORMAT_R10X6_UNORM_PACK16: 1180 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16: 1181 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: 1182 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: 1183 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: 1184 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: 1185 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 1186 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: 1187 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: 1188 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: 1189 case vk::VK_FORMAT_R12X4_UNORM_PACK16: 1190 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16: 1191 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: 1192 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: 1193 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: 1194 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: 1195 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: 1196 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: 1197 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: 1198 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: 1199 case vk::VK_FORMAT_G16B16G16R16_422_UNORM: 1200 case vk::VK_FORMAT_B16G16R16G16_422_UNORM: 1201 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: 1202 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: 1203 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: 1204 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: 1205 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: 1206 return fp16; 1207 1208 default: 1209 DE_FATAL("Precision not defined for format"); 1210 return fp32; 1211 } 1212 } 1213 1214 // \note Taken from explicit lod filtering tests 1215 tcu::FloatFormat getYCbCrConversionPrecision (vk::VkFormat format) 1216 { 1217 const tcu::FloatFormat reallyLow (0, 0, 8, false, tcu::YES); 1218 const tcu::FloatFormat fp16 (-14, 15, 10, false); 1219 const tcu::FloatFormat fp32 (-126, 127, 23, true); 1220 1221 switch (format) 1222 { 1223 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16: 1224 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16: 1225 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16: 1226 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16: 1227 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16: 1228 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16: 1229 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16: 1230 return reallyLow; 1231 1232 case vk::VK_FORMAT_R8G8B8_UNORM: 1233 case vk::VK_FORMAT_B8G8R8_UNORM: 1234 case vk::VK_FORMAT_R8G8B8A8_UNORM: 1235 case vk::VK_FORMAT_B8G8R8A8_UNORM: 1236 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32: 1237 case vk::VK_FORMAT_G8B8G8R8_422_UNORM: 1238 case vk::VK_FORMAT_B8G8R8G8_422_UNORM: 1239 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 1240 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 1241 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: 1242 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: 1243 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: 1244 return reallyLow; 1245 1246 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32: 1247 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32: 1248 case vk::VK_FORMAT_R16G16B16_UNORM: 1249 case vk::VK_FORMAT_R16G16B16A16_UNORM: 1250 case vk::VK_FORMAT_R10X6_UNORM_PACK16: 1251 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16: 1252 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: 1253 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: 1254 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: 1255 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: 1256 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 1257 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: 1258 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: 1259 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: 1260 case vk::VK_FORMAT_R12X4_UNORM_PACK16: 1261 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16: 1262 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: 1263 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: 1264 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: 1265 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: 1266 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: 1267 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: 1268 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: 1269 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: 1270 case vk::VK_FORMAT_G16B16G16R16_422_UNORM: 1271 case vk::VK_FORMAT_B16G16R16G16_422_UNORM: 1272 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: 1273 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: 1274 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: 1275 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: 1276 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: 1277 return fp16; 1278 1279 default: 1280 DE_FATAL("Precision not defined for format"); 1281 return fp32; 1282 } 1283 } 1284 1285 deUint32 getYCbCrFormatChannelCount (vk::VkFormat format) 1286 { 1287 switch (format) 1288 { 1289 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16: 1290 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32: 1291 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32: 1292 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32: 1293 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16: 1294 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16: 1295 case vk::VK_FORMAT_B8G8R8A8_UNORM: 1296 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16: 1297 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16: 1298 case vk::VK_FORMAT_R16G16B16A16_UNORM: 1299 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16: 1300 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16: 1301 case vk::VK_FORMAT_R8G8B8A8_UNORM: 1302 return 4; 1303 1304 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: 1305 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16: 1306 case vk::VK_FORMAT_B16G16R16G16_422_UNORM: 1307 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16: 1308 case vk::VK_FORMAT_B8G8R8G8_422_UNORM: 1309 case vk::VK_FORMAT_B8G8R8_UNORM: 1310 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16: 1311 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16: 1312 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16: 1313 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16: 1314 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16: 1315 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16: 1316 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16: 1317 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16: 1318 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16: 1319 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16: 1320 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16: 1321 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16: 1322 case vk::VK_FORMAT_G16B16G16R16_422_UNORM: 1323 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM: 1324 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM: 1325 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM: 1326 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM: 1327 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM: 1328 case vk::VK_FORMAT_G8B8G8R8_422_UNORM: 1329 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: 1330 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: 1331 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: 1332 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM: 1333 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM: 1334 case vk::VK_FORMAT_R16G16B16_UNORM: 1335 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16: 1336 case vk::VK_FORMAT_R8G8B8_UNORM: 1337 return 3; 1338 1339 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16: 1340 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16: 1341 return 2; 1342 1343 case vk::VK_FORMAT_R10X6_UNORM_PACK16: 1344 case vk::VK_FORMAT_R12X4_UNORM_PACK16: 1345 return 1; 1346 1347 default: 1348 DE_FATAL("Unknown number of channels"); 1349 return -1; 1350 } 1351 } 1352 1353 // YCbCr color conversion utilities 1354 namespace 1355 { 1356 1357 tcu::Interval rangeExpandChroma (vk::VkSamplerYcbcrRange range, 1358 const tcu::FloatFormat& conversionFormat, 1359 const deUint32 bits, 1360 const tcu::Interval& sample) 1361 { 1362 const deUint32 values (0x1u << bits); 1363 1364 switch (range) 1365 { 1366 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL: 1367 return conversionFormat.roundOut(sample - conversionFormat.roundOut(tcu::Interval((double)(0x1u << (bits - 1u)) / (double)((0x1u << bits) - 1u)), false), false); 1368 1369 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW: 1370 { 1371 const tcu::Interval a (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false)); 1372 const tcu::Interval dividend (conversionFormat.roundOut(a - tcu::Interval((double)(128u * (0x1u << (bits - 8u)))), false)); 1373 const tcu::Interval divisor ((double)(224u * (0x1u << (bits - 8u)))); 1374 const tcu::Interval result (conversionFormat.roundOut(dividend / divisor, false)); 1375 1376 return result; 1377 } 1378 1379 default: 1380 DE_FATAL("Unknown YCbCrRange"); 1381 return tcu::Interval(); 1382 } 1383 } 1384 1385 tcu::Interval rangeExpandLuma (vk::VkSamplerYcbcrRange range, 1386 const tcu::FloatFormat& conversionFormat, 1387 const deUint32 bits, 1388 const tcu::Interval& sample) 1389 { 1390 const deUint32 values (0x1u << bits); 1391 1392 switch (range) 1393 { 1394 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL: 1395 return conversionFormat.roundOut(sample, false); 1396 1397 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW: 1398 { 1399 const tcu::Interval a (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false)); 1400 const tcu::Interval dividend (conversionFormat.roundOut(a - tcu::Interval((double)(16u * (0x1u << (bits - 8u)))), false)); 1401 const tcu::Interval divisor ((double)(219u * (0x1u << (bits - 8u)))); 1402 const tcu::Interval result (conversionFormat.roundOut(dividend / divisor, false)); 1403 1404 return result; 1405 } 1406 1407 default: 1408 DE_FATAL("Unknown YCbCrRange"); 1409 return tcu::Interval(); 1410 } 1411 } 1412 1413 tcu::Interval clampMaybe (const tcu::Interval& x, 1414 double min, 1415 double max) 1416 { 1417 tcu::Interval result = x; 1418 1419 DE_ASSERT(min <= max); 1420 1421 if (x.lo() < min) 1422 result = result | tcu::Interval(min); 1423 1424 if (x.hi() > max) 1425 result = result | tcu::Interval(max); 1426 1427 return result; 1428 } 1429 1430 void convertColor (vk::VkSamplerYcbcrModelConversion colorModel, 1431 vk::VkSamplerYcbcrRange range, 1432 const tcu::FloatFormat& conversionFormat, 1433 const tcu::UVec4& bitDepth, 1434 const tcu::Interval input[4], 1435 tcu::Interval output[4]) 1436 { 1437 switch (colorModel) 1438 { 1439 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY: 1440 { 1441 for (size_t ndx = 0; ndx < 4; ndx++) 1442 output[ndx] = input[ndx]; 1443 break; 1444 } 1445 1446 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY: 1447 { 1448 output[0] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]), -0.5, 0.5); 1449 output[1] = clampMaybe(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]), 0.0, 1.0); 1450 output[2] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]), -0.5, 0.5); 1451 output[3] = input[3]; 1452 break; 1453 } 1454 1455 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601: 1456 { 1457 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1])); 1458 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0])); 1459 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2])); 1460 1461 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0)); 1462 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5)); 1463 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5)); 1464 1465 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.402 * crClamped, false), false); 1466 output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.202008 / 0.587) * cbClamped, false), false) - conversionFormat.roundOut((0.419198 / 0.587) * crClamped, false), false); 1467 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.772 * cbClamped, false), false); 1468 output[3] = input[3]; 1469 break; 1470 } 1471 1472 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709: 1473 { 1474 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1])); 1475 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0])); 1476 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2])); 1477 1478 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0)); 1479 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5)); 1480 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5)); 1481 1482 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.5748 * crClamped, false), false); 1483 output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut((0.13397432 / 0.7152) * cbClamped, false), false) - conversionFormat.roundOut((0.33480248 / 0.7152) * crClamped, false), false); 1484 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8556 * cbClamped, false), false); 1485 output[3] = input[3]; 1486 break; 1487 } 1488 1489 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020: 1490 { 1491 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1])); 1492 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0])); 1493 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2])); 1494 1495 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0)); 1496 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5)); 1497 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5)); 1498 1499 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.4746 * crClamped, false), false); 1500 output[1] = conversionFormat.roundOut(conversionFormat.roundOut(yClamped - conversionFormat.roundOut(conversionFormat.roundOut(0.11156702 / 0.6780, false) * cbClamped, false), false) - conversionFormat.roundOut(conversionFormat.roundOut(0.38737742 / 0.6780, false) * crClamped, false), false); 1501 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8814 * cbClamped, false), false); 1502 output[3] = input[3]; 1503 break; 1504 } 1505 1506 default: 1507 DE_FATAL("Unknown YCbCrModel"); 1508 } 1509 1510 if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY) 1511 { 1512 for (int ndx = 0; ndx < 3; ndx++) 1513 output[ndx] = clampMaybe(output[ndx], 0.0, 1.0); 1514 } 1515 } 1516 1517 int mirror (int coord) 1518 { 1519 return coord >= 0 ? coord : -(1 + coord); 1520 } 1521 1522 int imod (int a, int b) 1523 { 1524 int m = a % b; 1525 return m < 0 ? m + b : m; 1526 } 1527 1528 tcu::Interval frac (const tcu::Interval& x) 1529 { 1530 if (x.hi() - x.lo() >= 1.0) 1531 return tcu::Interval(0.0, 1.0); 1532 else 1533 { 1534 const tcu::Interval ret (deFrac(x.lo()), deFrac(x.hi())); 1535 1536 return ret; 1537 } 1538 } 1539 1540 tcu::Interval calculateUV (const tcu::FloatFormat& coordFormat, 1541 const tcu::Interval& st, 1542 const int size) 1543 { 1544 return coordFormat.roundOut(coordFormat.roundOut(st, false) * tcu::Interval((double)size), false); 1545 } 1546 1547 tcu::IVec2 calculateNearestIJRange (const tcu::FloatFormat& coordFormat, 1548 const tcu::Interval& uv) 1549 { 1550 const tcu::Interval ij (coordFormat.roundOut(coordFormat.roundOut(uv, false) - tcu::Interval(0.5), false)); 1551 1552 return tcu::IVec2(deRoundToInt32(ij.lo() - coordFormat.ulp(ij.lo(), 1)), deRoundToInt32(ij.hi() + coordFormat.ulp(ij.hi(), 1))); 1553 } 1554 1555 // Calculate range of pixel coordinates that can be used as lower coordinate for linear sampling 1556 tcu::IVec2 calculateLinearIJRange (const tcu::FloatFormat& coordFormat, 1557 const tcu::Interval& uv) 1558 { 1559 const tcu::Interval ij (coordFormat.roundOut(uv - tcu::Interval(0.5), false)); 1560 1561 return tcu::IVec2(deFloorToInt32(ij.lo()), deFloorToInt32(ij.hi())); 1562 } 1563 1564 tcu::Interval calculateAB (const deUint32 subTexelPrecisionBits, 1565 const tcu::Interval& uv, 1566 int ij) 1567 { 1568 const deUint32 subdivisions = 0x1u << subTexelPrecisionBits; 1569 const tcu::Interval ab (frac((uv - 0.5) & tcu::Interval((double)ij, (double)(ij + 1)))); 1570 const tcu::Interval gridAB (ab * tcu::Interval(subdivisions)); 1571 const tcu::Interval rounded (de::max(deFloor(gridAB.lo()) / subdivisions, 0.0) , de::min(deCeil(gridAB.hi()) / subdivisions, 1.0)); 1572 1573 return rounded; 1574 } 1575 1576 tcu::Interval lookupWrapped (const ChannelAccess& access, 1577 const tcu::FloatFormat& conversionFormat, 1578 vk::VkSamplerAddressMode addressModeU, 1579 vk::VkSamplerAddressMode addressModeV, 1580 const tcu::IVec2& coord) 1581 { 1582 return access.getChannel(conversionFormat, 1583 tcu::IVec3(wrap(addressModeU, coord.x(), access.getSize().x()), wrap(addressModeV, coord.y(), access.getSize().y()), 0)); 1584 } 1585 1586 tcu::Interval linearInterpolate (const tcu::FloatFormat& filteringFormat, 1587 const tcu::Interval& a, 1588 const tcu::Interval& b, 1589 const tcu::Interval& p00, 1590 const tcu::Interval& p10, 1591 const tcu::Interval& p01, 1592 const tcu::Interval& p11) 1593 { 1594 const tcu::Interval p[4] = 1595 { 1596 p00, 1597 p10, 1598 p01, 1599 p11 1600 }; 1601 tcu::Interval result (0.0); 1602 1603 for (size_t ndx = 0; ndx < 4; ndx++) 1604 { 1605 const tcu::Interval weightA (filteringFormat.roundOut((ndx % 2) == 0 ? (1.0 - a) : a, false)); 1606 const tcu::Interval weightB (filteringFormat.roundOut((ndx / 2) == 0 ? (1.0 - b) : b, false)); 1607 const tcu::Interval weight (filteringFormat.roundOut(weightA * weightB, false)); 1608 1609 result = filteringFormat.roundOut(result + filteringFormat.roundOut(p[ndx] * weight, false), false); 1610 } 1611 1612 return result; 1613 } 1614 1615 tcu::Interval calculateImplicitChromaUV (const tcu::FloatFormat& coordFormat, 1616 vk::VkChromaLocation offset, 1617 const tcu::Interval& uv) 1618 { 1619 if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) 1620 return coordFormat.roundOut(0.5 * coordFormat.roundOut(uv + 0.5, false), false); 1621 else 1622 return coordFormat.roundOut(0.5 * uv, false); 1623 } 1624 1625 tcu::Interval linearSample (const ChannelAccess& access, 1626 const tcu::FloatFormat& conversionFormat, 1627 const tcu::FloatFormat& filteringFormat, 1628 vk::VkSamplerAddressMode addressModeU, 1629 vk::VkSamplerAddressMode addressModeV, 1630 const tcu::IVec2& coord, 1631 const tcu::Interval& a, 1632 const tcu::Interval& b) 1633 { 1634 return linearInterpolate(filteringFormat, a, b, 1635 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 0)), 1636 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 0)), 1637 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 1)), 1638 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 1))); 1639 } 1640 1641 tcu::Interval reconstructLinearXChromaSample (const tcu::FloatFormat& filteringFormat, 1642 const tcu::FloatFormat& conversionFormat, 1643 vk::VkChromaLocation offset, 1644 vk::VkSamplerAddressMode addressModeU, 1645 vk::VkSamplerAddressMode addressModeV, 1646 const ChannelAccess& access, 1647 int i, 1648 int j) 1649 { 1650 const int subI = divFloor(i, 2); 1651 1652 if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN) 1653 { 1654 if (i % 2 == 0) 1655 return lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)); 1656 else 1657 { 1658 const tcu::Interval a (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false)); 1659 const tcu::Interval b (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false)); 1660 1661 return filteringFormat.roundOut(a + b, false); 1662 } 1663 } 1664 else if (offset == vk::VK_CHROMA_LOCATION_MIDPOINT) 1665 { 1666 if (i % 2 == 0) 1667 { 1668 const tcu::Interval a (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI - 1, j)), false)); 1669 const tcu::Interval b (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false)); 1670 1671 return filteringFormat.roundOut(a + b, false); 1672 } 1673 else 1674 { 1675 const tcu::Interval a (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false)); 1676 const tcu::Interval b (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false)); 1677 1678 return filteringFormat.roundOut(a + b, false); 1679 } 1680 } 1681 else 1682 { 1683 DE_FATAL("Unknown sample location"); 1684 return tcu::Interval(); 1685 } 1686 } 1687 1688 tcu::Interval reconstructLinearXYChromaSample (const tcu::FloatFormat& filteringFormat, 1689 const tcu::FloatFormat& conversionFormat, 1690 vk::VkChromaLocation xOffset, 1691 vk::VkChromaLocation yOffset, 1692 vk::VkSamplerAddressMode addressModeU, 1693 vk::VkSamplerAddressMode addressModeV, 1694 const ChannelAccess& access, 1695 int i, 1696 int j) 1697 { 1698 const int subI = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN 1699 ? divFloor(i, 2) 1700 : (i % 2 == 0 ? divFloor(i, 2) - 1 : divFloor(i, 2)); 1701 const int subJ = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN 1702 ? divFloor(j, 2) 1703 : (j % 2 == 0 ? divFloor(j, 2) - 1 : divFloor(j, 2)); 1704 1705 const double a = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN 1706 ? (i % 2 == 0 ? 0.0 : 0.5) 1707 : (i % 2 == 0 ? 0.25 : 0.75); 1708 const double b = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN 1709 ? (j % 2 == 0 ? 0.0 : 0.5) 1710 : (j % 2 == 0 ? 0.25 : 0.75); 1711 1712 return linearInterpolate(filteringFormat, a, b, 1713 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ)), 1714 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ)), 1715 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ + 1)), 1716 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ + 1))); 1717 } 1718 1719 const ChannelAccess& swizzle (vk::VkComponentSwizzle swizzle, 1720 const ChannelAccess& identityPlane, 1721 const ChannelAccess& rPlane, 1722 const ChannelAccess& gPlane, 1723 const ChannelAccess& bPlane, 1724 const ChannelAccess& aPlane) 1725 { 1726 switch (swizzle) 1727 { 1728 case vk::VK_COMPONENT_SWIZZLE_IDENTITY: return identityPlane; 1729 case vk::VK_COMPONENT_SWIZZLE_R: return rPlane; 1730 case vk::VK_COMPONENT_SWIZZLE_G: return gPlane; 1731 case vk::VK_COMPONENT_SWIZZLE_B: return bPlane; 1732 case vk::VK_COMPONENT_SWIZZLE_A: return aPlane; 1733 1734 default: 1735 DE_FATAL("Unsupported swizzle"); 1736 return identityPlane; 1737 } 1738 } 1739 1740 } // anonymous 1741 1742 int wrap (vk::VkSamplerAddressMode addressMode, 1743 int coord, 1744 int size) 1745 { 1746 switch (addressMode) 1747 { 1748 case vk::VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT: 1749 return (size - 1) - mirror(imod(coord, 2 * size) - size); 1750 1751 case vk::VK_SAMPLER_ADDRESS_MODE_REPEAT: 1752 return imod(coord, size); 1753 1754 case vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE: 1755 return de::clamp(coord, 0, size - 1); 1756 1757 case vk::VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE: 1758 return de::clamp(mirror(coord), 0, size - 1); 1759 1760 default: 1761 DE_FATAL("Unknown wrap mode"); 1762 return ~0; 1763 } 1764 } 1765 1766 int divFloor (int a, int b) 1767 { 1768 if (a % b == 0) 1769 return a / b; 1770 else if (a > 0) 1771 return a / b; 1772 else 1773 return (a / b) - 1; 1774 } 1775 1776 void calculateBounds (const ChannelAccess& rPlane, 1777 const ChannelAccess& gPlane, 1778 const ChannelAccess& bPlane, 1779 const ChannelAccess& aPlane, 1780 const UVec4& bitDepth, 1781 const vector<Vec2>& sts, 1782 const FloatFormat& filteringFormat, 1783 const FloatFormat& conversionFormat, 1784 const deUint32 subTexelPrecisionBits, 1785 vk::VkFilter filter, 1786 vk::VkSamplerYcbcrModelConversion colorModel, 1787 vk::VkSamplerYcbcrRange range, 1788 vk::VkFilter chromaFilter, 1789 vk::VkChromaLocation xChromaOffset, 1790 vk::VkChromaLocation yChromaOffset, 1791 const vk::VkComponentMapping& componentMapping, 1792 bool explicitReconstruction, 1793 vk::VkSamplerAddressMode addressModeU, 1794 vk::VkSamplerAddressMode addressModeV, 1795 std::vector<Vec4>& minBounds, 1796 std::vector<Vec4>& maxBounds, 1797 std::vector<Vec4>& uvBounds, 1798 std::vector<IVec4>& ijBounds) 1799 { 1800 const FloatFormat highp (-126, 127, 23, true, 1801 tcu::MAYBE, // subnormals 1802 tcu::YES, // infinities 1803 tcu::MAYBE); // NaN 1804 const FloatFormat coordFormat (-32, 32, 16, true); 1805 const ChannelAccess& rAccess (swizzle(componentMapping.r, rPlane, rPlane, gPlane, bPlane, aPlane)); 1806 const ChannelAccess& gAccess (swizzle(componentMapping.g, gPlane, rPlane, gPlane, bPlane, aPlane)); 1807 const ChannelAccess& bAccess (swizzle(componentMapping.b, bPlane, rPlane, gPlane, bPlane, aPlane)); 1808 const ChannelAccess& aAccess (swizzle(componentMapping.a, aPlane, rPlane, gPlane, bPlane, aPlane)); 1809 1810 const bool subsampledX = gAccess.getSize().x() > rAccess.getSize().x(); 1811 const bool subsampledY = gAccess.getSize().y() > rAccess.getSize().y(); 1812 1813 minBounds.resize(sts.size(), Vec4(TCU_INFINITY)); 1814 maxBounds.resize(sts.size(), Vec4(-TCU_INFINITY)); 1815 1816 uvBounds.resize(sts.size(), Vec4(TCU_INFINITY, -TCU_INFINITY, TCU_INFINITY, -TCU_INFINITY)); 1817 ijBounds.resize(sts.size(), IVec4(0x7FFFFFFF, -1 -0x7FFFFFFF, 0x7FFFFFFF, -1 -0x7FFFFFFF)); 1818 1819 // Chroma plane sizes must match 1820 DE_ASSERT(rAccess.getSize() == bAccess.getSize()); 1821 1822 // Luma plane sizes must match 1823 DE_ASSERT(gAccess.getSize() == aAccess.getSize()); 1824 1825 // Luma plane size must match chroma plane or be twice as big 1826 DE_ASSERT(rAccess.getSize().x() == gAccess.getSize().x() || 2 * rAccess.getSize().x() == gAccess.getSize().x()); 1827 DE_ASSERT(rAccess.getSize().y() == gAccess.getSize().y() || 2 * rAccess.getSize().y() == gAccess.getSize().y()); 1828 1829 for (size_t ndx = 0; ndx < sts.size(); ndx++) 1830 { 1831 const Vec2 st (sts[ndx]); 1832 Interval bounds[4]; 1833 1834 const Interval u (calculateUV(coordFormat, st[0], gAccess.getSize().x())); 1835 const Interval v (calculateUV(coordFormat, st[1], gAccess.getSize().y())); 1836 1837 uvBounds[ndx][0] = (float)u.lo(); 1838 uvBounds[ndx][1] = (float)u.hi(); 1839 1840 uvBounds[ndx][2] = (float)v.lo(); 1841 uvBounds[ndx][3] = (float)v.hi(); 1842 1843 if (filter == vk::VK_FILTER_NEAREST) 1844 { 1845 const IVec2 iRange (calculateNearestIJRange(coordFormat, u)); 1846 const IVec2 jRange (calculateNearestIJRange(coordFormat, v)); 1847 1848 ijBounds[ndx][0] = iRange[0]; 1849 ijBounds[ndx][1] = iRange[1]; 1850 1851 ijBounds[ndx][2] = jRange[0]; 1852 ijBounds[ndx][3] = jRange[1]; 1853 1854 for (int j = jRange.x(); j <= jRange.y(); j++) 1855 for (int i = iRange.x(); i <= iRange.y(); i++) 1856 { 1857 const Interval gValue (lookupWrapped(gAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j))); 1858 const Interval aValue (lookupWrapped(aAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j))); 1859 1860 if (subsampledX || subsampledY) 1861 { 1862 if (explicitReconstruction) 1863 { 1864 if (chromaFilter == vk::VK_FILTER_NEAREST) 1865 { 1866 // Nearest, Reconstructed chroma with explicit nearest filtering 1867 const int subI = subsampledX ? i / 2 : i; 1868 const int subJ = subsampledY ? j / 2 : j; 1869 const Interval srcColor[] = 1870 { 1871 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)), 1872 gValue, 1873 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)), 1874 aValue 1875 }; 1876 Interval dstColor[4]; 1877 1878 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 1879 1880 for (size_t compNdx = 0; compNdx < 4; compNdx++) 1881 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 1882 } 1883 else if (chromaFilter == vk::VK_FILTER_LINEAR) 1884 { 1885 if (subsampledX && subsampledY) 1886 { 1887 // Nearest, Reconstructed both chroma samples with explicit linear filtering 1888 const Interval rValue (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j)); 1889 const Interval bValue (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j)); 1890 const Interval srcColor[] = 1891 { 1892 rValue, 1893 gValue, 1894 bValue, 1895 aValue 1896 }; 1897 Interval dstColor[4]; 1898 1899 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 1900 1901 for (size_t compNdx = 0; compNdx < 4; compNdx++) 1902 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 1903 } 1904 else if (subsampledX) 1905 { 1906 // Nearest, Reconstructed x chroma samples with explicit linear filtering 1907 const Interval rValue (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j)); 1908 const Interval bValue (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j)); 1909 const Interval srcColor[] = 1910 { 1911 rValue, 1912 gValue, 1913 bValue, 1914 aValue 1915 }; 1916 Interval dstColor[4]; 1917 1918 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 1919 1920 for (size_t compNdx = 0; compNdx < 4; compNdx++) 1921 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 1922 } 1923 else 1924 DE_FATAL("Unexpected chroma reconstruction"); 1925 } 1926 else 1927 DE_FATAL("Unknown filter"); 1928 } 1929 else 1930 { 1931 const Interval chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u); 1932 const Interval chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v); 1933 1934 if (chromaFilter == vk::VK_FILTER_NEAREST) 1935 { 1936 // Nearest, reconstructed chroma samples with implicit nearest filtering 1937 const IVec2 chromaIRange (subsampledX ? calculateNearestIJRange(coordFormat, chromaU) : IVec2(i, i)); 1938 const IVec2 chromaJRange (subsampledY ? calculateNearestIJRange(coordFormat, chromaV) : IVec2(j, j)); 1939 1940 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++) 1941 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++) 1942 { 1943 const Interval srcColor[] = 1944 { 1945 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)), 1946 gValue, 1947 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)), 1948 aValue 1949 }; 1950 Interval dstColor[4]; 1951 1952 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 1953 1954 for (size_t compNdx = 0; compNdx < 4; compNdx++) 1955 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 1956 } 1957 } 1958 else if (chromaFilter == vk::VK_FILTER_LINEAR) 1959 { 1960 // Nearest, reconstructed chroma samples with implicit linear filtering 1961 const IVec2 chromaIRange (subsampledX ? calculateLinearIJRange(coordFormat, chromaU) : IVec2(i, i)); 1962 const IVec2 chromaJRange (subsampledY ? calculateLinearIJRange(coordFormat, chromaV) : IVec2(j, j)); 1963 1964 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++) 1965 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++) 1966 { 1967 const Interval chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI)); 1968 const Interval chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ)); 1969 1970 const Interval srcColor[] = 1971 { 1972 linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB), 1973 gValue, 1974 linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB), 1975 aValue 1976 }; 1977 Interval dstColor[4]; 1978 1979 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 1980 1981 for (size_t compNdx = 0; compNdx < 4; compNdx++) 1982 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 1983 } 1984 } 1985 else 1986 DE_FATAL("Unknown filter"); 1987 } 1988 } 1989 else 1990 { 1991 // Linear, no chroma subsampling 1992 const Interval srcColor[] = 1993 { 1994 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)), 1995 gValue, 1996 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)), 1997 aValue 1998 }; 1999 Interval dstColor[4]; 2000 2001 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 2002 2003 for (size_t compNdx = 0; compNdx < 4; compNdx++) 2004 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 2005 } 2006 } 2007 } 2008 else if (filter == vk::VK_FILTER_LINEAR) 2009 { 2010 const IVec2 iRange (calculateLinearIJRange(coordFormat, u)); 2011 const IVec2 jRange (calculateLinearIJRange(coordFormat, v)); 2012 2013 ijBounds[ndx][0] = iRange[0]; 2014 ijBounds[ndx][1] = iRange[1]; 2015 2016 ijBounds[ndx][2] = jRange[0]; 2017 ijBounds[ndx][3] = jRange[1]; 2018 2019 for (int j = jRange.x(); j <= jRange.y(); j++) 2020 for (int i = iRange.x(); i <= iRange.y(); i++) 2021 { 2022 const Interval lumaA (calculateAB(subTexelPrecisionBits, u, i)); 2023 const Interval lumaB (calculateAB(subTexelPrecisionBits, v, j)); 2024 2025 const Interval gValue (linearSample(gAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB)); 2026 const Interval aValue (linearSample(aAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB)); 2027 2028 if (subsampledX || subsampledY) 2029 { 2030 if (explicitReconstruction) 2031 { 2032 if (chromaFilter == vk::VK_FILTER_NEAREST) 2033 { 2034 const Interval srcColor[] = 2035 { 2036 linearInterpolate(filteringFormat, lumaA, lumaB, 2037 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))), 2038 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))), 2039 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))), 2040 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))), 2041 gValue, 2042 linearInterpolate(filteringFormat, lumaA, lumaB, 2043 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))), 2044 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))), 2045 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))), 2046 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))), 2047 aValue 2048 }; 2049 Interval dstColor[4]; 2050 2051 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 2052 2053 for (size_t compNdx = 0; compNdx < 4; compNdx++) 2054 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 2055 } 2056 else if (chromaFilter == vk::VK_FILTER_LINEAR) 2057 { 2058 if (subsampledX && subsampledY) 2059 { 2060 // Linear, Reconstructed xx chroma samples with explicit linear filtering 2061 const Interval rValue (linearInterpolate(filteringFormat, lumaA, lumaB, 2062 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j), 2063 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j), 2064 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1), 2065 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1))); 2066 const Interval bValue (linearInterpolate(filteringFormat, lumaA, lumaB, 2067 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j), 2068 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j), 2069 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1), 2070 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1))); 2071 const Interval srcColor[] = 2072 { 2073 rValue, 2074 gValue, 2075 bValue, 2076 aValue 2077 }; 2078 Interval dstColor[4]; 2079 2080 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 2081 2082 for (size_t compNdx = 0; compNdx < 4; compNdx++) 2083 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 2084 2085 } 2086 else if (subsampledX) 2087 { 2088 // Linear, Reconstructed x chroma samples with explicit linear filtering 2089 const Interval rValue (linearInterpolate(filteringFormat, lumaA, lumaB, 2090 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j), 2091 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j), 2092 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1), 2093 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1))); 2094 const Interval bValue (linearInterpolate(filteringFormat, lumaA, lumaB, 2095 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j), 2096 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j), 2097 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1), 2098 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1))); 2099 const Interval srcColor[] = 2100 { 2101 rValue, 2102 gValue, 2103 bValue, 2104 aValue 2105 }; 2106 Interval dstColor[4]; 2107 2108 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 2109 2110 for (size_t compNdx = 0; compNdx < 4; compNdx++) 2111 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 2112 } 2113 else 2114 DE_FATAL("Unknown subsampling config"); 2115 } 2116 else 2117 DE_FATAL("Unknown chroma filter"); 2118 } 2119 else 2120 { 2121 const Interval chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u); 2122 const Interval chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v); 2123 2124 if (chromaFilter == vk::VK_FILTER_NEAREST) 2125 { 2126 const IVec2 chromaIRange (calculateNearestIJRange(coordFormat, chromaU)); 2127 const IVec2 chromaJRange (calculateNearestIJRange(coordFormat, chromaV)); 2128 2129 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++) 2130 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++) 2131 { 2132 const Interval srcColor[] = 2133 { 2134 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)), 2135 gValue, 2136 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)), 2137 aValue 2138 }; 2139 Interval dstColor[4]; 2140 2141 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 2142 2143 for (size_t compNdx = 0; compNdx < 4; compNdx++) 2144 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 2145 } 2146 } 2147 else if (chromaFilter == vk::VK_FILTER_LINEAR) 2148 { 2149 const IVec2 chromaIRange (calculateNearestIJRange(coordFormat, chromaU)); 2150 const IVec2 chromaJRange (calculateNearestIJRange(coordFormat, chromaV)); 2151 2152 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++) 2153 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++) 2154 { 2155 const Interval chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI)); 2156 const Interval chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ)); 2157 2158 const Interval rValue (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB)); 2159 const Interval bValue (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB)); 2160 2161 const Interval srcColor[] = 2162 { 2163 rValue, 2164 gValue, 2165 bValue, 2166 aValue 2167 }; 2168 Interval dstColor[4]; 2169 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 2170 2171 for (size_t compNdx = 0; compNdx < 4; compNdx++) 2172 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 2173 } 2174 } 2175 else 2176 DE_FATAL("Unknown chroma filter"); 2177 } 2178 } 2179 else 2180 { 2181 const Interval chromaA (lumaA); 2182 const Interval chromaB (lumaB); 2183 const Interval rValue (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB)); 2184 const Interval bValue (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB)); 2185 const Interval srcColor[] = 2186 { 2187 rValue, 2188 gValue, 2189 bValue, 2190 aValue 2191 }; 2192 Interval dstColor[4]; 2193 2194 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor); 2195 2196 for (size_t compNdx = 0; compNdx < 4; compNdx++) 2197 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false); 2198 } 2199 } 2200 } 2201 else 2202 DE_FATAL("Unknown filter"); 2203 2204 minBounds[ndx] = Vec4((float)bounds[0].lo(), (float)bounds[1].lo(), (float)bounds[2].lo(), (float)bounds[3].lo()); 2205 maxBounds[ndx] = Vec4((float)bounds[0].hi(), (float)bounds[1].hi(), (float)bounds[2].hi(), (float)bounds[3].hi()); 2206 } 2207 } 2208 2209 2210 } // ycbcr 2211 } // vkt 2212