1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2017 Google Inc.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief YCbCr Test Utilities
22 *//*--------------------------------------------------------------------*/
24 #include "vktYCbCrUtil.hpp"
26 #include "vkQueryUtil.hpp"
27 #include "vkRefUtil.hpp"
28 #include "vkTypeUtil.hpp"
30 #include "tcuTextureUtil.hpp"
32 #include "deFloat16.h"
33 #include "tcuVector.hpp"
34 #include "tcuVectorUtil.hpp"
36 #include "deSTLUtil.hpp"
37 #include "deUniquePtr.hpp"
47 using tcu::FloatFormat;
58 typedef de::SharedPtr<Allocation> AllocationSp;
59 typedef de::SharedPtr<vk::Unique<VkBuffer> > VkBufferSp;
61 // MultiPlaneImageData
63 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size)
65 , m_description (getPlanarFormatDescription(format))
68 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
70 const deUint32 planeW = size.x() / m_description.planes[planeNdx].widthDivisor;
71 const deUint32 planeH = size.y() / m_description.planes[planeNdx].heightDivisor;
72 const deUint32 planeSize = m_description.planes[planeNdx].elementSizeBytes * planeW * planeH;
74 m_planeData[planeNdx].resize(planeSize);
78 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other)
79 : m_format (other.m_format)
80 , m_description (other.m_description)
81 , m_size (other.m_size)
83 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
84 m_planeData[planeNdx] = other.m_planeData[planeNdx];
87 MultiPlaneImageData::~MultiPlaneImageData (void)
91 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx)
93 void* planePtrs[PlanarFormatDescription::MAX_PLANES];
94 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES];
96 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
98 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor;
100 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW;
101 planePtrs[planeNdx] = &m_planeData[planeNdx][0];
104 return vk::getChannelAccess(m_description,
111 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const
113 const void* planePtrs[PlanarFormatDescription::MAX_PLANES];
114 deUint32 planeRowPitches[PlanarFormatDescription::MAX_PLANES];
116 for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
118 const deUint32 planeW = m_size.x() / m_description.planes[planeNdx].widthDivisor;
120 planeRowPitches[planeNdx] = m_description.planes[planeNdx].elementSizeBytes * planeW;
121 planePtrs[planeNdx] = &m_planeData[planeNdx][0];
124 return vk::getChannelAccess(m_description,
136 void allocateStagingBuffers (const DeviceInterface& vkd,
138 Allocator& allocator,
139 const MultiPlaneImageData& imageData,
140 vector<VkBufferSp>* buffers,
141 vector<AllocationSp>* allocations)
143 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
145 const VkBufferCreateInfo bufferInfo =
147 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
149 (VkBufferCreateFlags)0u,
150 (VkDeviceSize)imageData.getPlaneSize(planeNdx),
151 VK_BUFFER_USAGE_TRANSFER_SRC_BIT|VK_BUFFER_USAGE_TRANSFER_DST_BIT,
152 VK_SHARING_MODE_EXCLUSIVE,
154 (const deUint32*)DE_NULL,
156 Move<VkBuffer> buffer (createBuffer(vkd, device, &bufferInfo));
157 MovePtr<Allocation> allocation (allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer),
158 MemoryRequirement::HostVisible|MemoryRequirement::Any));
160 VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
162 buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer)));
163 allocations->push_back(AllocationSp(allocation.release()));
167 void allocateAndWriteStagingBuffers (const DeviceInterface& vkd,
169 Allocator& allocator,
170 const MultiPlaneImageData& imageData,
171 vector<VkBufferSp>* buffers,
172 vector<AllocationSp>* allocations)
174 allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations);
176 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
178 deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
179 flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
183 void readStagingBuffers (MultiPlaneImageData* imageData,
184 const DeviceInterface& vkd,
186 const vector<AllocationSp>& allocations)
188 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
190 invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
191 deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx));
197 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling)
199 const bool disjoint = (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0;
200 const VkPhysicalDeviceSamplerYcbcrConversionFeatures features = context.getSamplerYCbCrConversionFeatures();
201 vector<string> reqExts;
203 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_sampler_ycbcr_conversion"))
204 reqExts.push_back("VK_KHR_sampler_ycbcr_conversion");
208 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_bind_memory2"))
209 reqExts.push_back("VK_KHR_bind_memory2");
210 if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_get_memory_requirements2"))
211 reqExts.push_back("VK_KHR_get_memory_requirements2");
214 for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter)
216 if (!isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), *extIter))
217 TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str());
220 if (features.samplerYcbcrConversion == VK_FALSE)
222 TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported");
226 const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
227 context.getPhysicalDevice(),
229 const VkFormatFeatureFlags featureFlags = tiling == VK_IMAGE_TILING_OPTIMAL
230 ? formatProperties.optimalTilingFeatures
231 : formatProperties.linearTilingFeatures;
233 if ((featureFlags & (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT | VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT)) == 0)
234 TCU_THROW(NotSupportedError, "YCbCr conversion is not supported for format");
236 if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
237 TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format");
241 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData)
243 // \todo [pyry] Optimize, take into account bits that must be 0
245 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
247 const size_t planeSize = imageData->getPlaneSize(planeNdx);
248 deUint8* const planePtr = (deUint8*)imageData->getPlanePtr(planeNdx);
250 for (size_t ndx = 0; ndx < planeSize; ++ndx)
251 planePtr[ndx] = randomGen->getUint8();
255 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal)
257 const PlanarFormatDescription& formatInfo = imageData->getDescription();
259 // \todo [pyry] Optimize: no point in re-rendering source gradient for each channel.
261 for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
263 if (formatInfo.hasChannelNdx(channelNdx))
265 const tcu::PixelBufferAccess channelAccess = imageData->getChannelAccess(channelNdx);
266 tcu::TextureLevel tmpTexture (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), channelAccess.getWidth(), channelAccess.getHeight());
267 const tcu::ConstPixelBufferAccess tmpAccess = tmpTexture.getAccess();
269 tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal);
271 for (int y = 0; y < channelAccess.getHeight(); ++y)
272 for (int x = 0; x < channelAccess.getWidth(); ++x)
274 channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y);
280 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface& vkd,
282 Allocator& allocator,
285 VkImageCreateFlags createFlags,
286 vk::MemoryRequirement requirement)
288 vector<AllocationSp> allocations;
290 if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
292 const deUint32 numPlanes = getPlaneCount(format);
294 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
296 const VkImageAspectFlagBits planeAspect = getPlaneAspect(planeNdx);
297 const VkMemoryRequirements reqs = getImagePlaneMemoryRequirements(vkd, device, image, planeAspect);
299 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
301 bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect);
306 const VkMemoryRequirements reqs = getImageMemoryRequirements(vkd, device, image);
308 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
310 VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset()));
316 void uploadImage (const DeviceInterface& vkd,
318 deUint32 queueFamilyNdx,
319 Allocator& allocator,
321 const MultiPlaneImageData& imageData,
322 VkAccessFlags nextAccess,
323 VkImageLayout finalLayout)
325 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
326 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
327 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
328 vector<VkBufferSp> stagingBuffers;
329 vector<AllocationSp> stagingMemory;
331 const PlanarFormatDescription& formatDesc = imageData.getDescription();
333 allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory);
336 const VkCommandBufferBeginInfo beginInfo =
338 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
340 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
341 (const VkCommandBufferInheritanceInfo*)DE_NULL
344 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
348 const VkImageMemoryBarrier preCopyBarrier =
350 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
353 VK_ACCESS_TRANSFER_WRITE_BIT,
354 VK_IMAGE_LAYOUT_UNDEFINED,
355 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
356 VK_QUEUE_FAMILY_IGNORED,
357 VK_QUEUE_FAMILY_IGNORED,
359 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
362 vkd.cmdPipelineBarrier(*cmdBuffer,
363 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
364 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
365 (VkDependencyFlags)0u,
367 (const VkMemoryBarrier*)DE_NULL,
369 (const VkBufferMemoryBarrier*)DE_NULL,
374 for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
376 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
377 ? getPlaneAspect(planeNdx)
378 : VK_IMAGE_ASPECT_COLOR_BIT;
379 const deUint32 planeW = (formatDesc.numPlanes > 1)
380 ? imageData.getSize().x() / formatDesc.planes[planeNdx].widthDivisor
381 : imageData.getSize().x();
382 const deUint32 planeH = (formatDesc.numPlanes > 1)
383 ? imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor
384 : imageData.getSize().y();
385 const VkBufferImageCopy copy =
388 0u, // bufferRowLength
389 0u, // bufferImageHeight
390 { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
391 makeOffset3D(0u, 0u, 0u),
392 makeExtent3D(planeW, planeH, 1u),
395 vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, ©);
399 const VkImageMemoryBarrier postCopyBarrier =
401 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
403 VK_ACCESS_TRANSFER_WRITE_BIT,
405 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
407 VK_QUEUE_FAMILY_IGNORED,
408 VK_QUEUE_FAMILY_IGNORED,
410 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
413 vkd.cmdPipelineBarrier(*cmdBuffer,
414 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
415 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
416 (VkDependencyFlags)0u,
418 (const VkMemoryBarrier*)DE_NULL,
420 (const VkBufferMemoryBarrier*)DE_NULL,
425 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
428 const Unique<VkFence> fence (createFence(vkd, device));
429 const VkSubmitInfo submitInfo =
431 VK_STRUCTURE_TYPE_SUBMIT_INFO,
434 (const VkSemaphore*)DE_NULL,
435 (const VkPipelineStageFlags*)DE_NULL,
439 (const VkSemaphore*)DE_NULL,
442 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
443 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
447 void fillImageMemory (const vk::DeviceInterface& vkd,
449 deUint32 queueFamilyNdx,
451 const std::vector<de::SharedPtr<vk::Allocation> >& allocations,
452 const MultiPlaneImageData& imageData,
453 vk::VkAccessFlags nextAccess,
454 vk::VkImageLayout finalLayout)
456 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
457 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
458 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
459 const PlanarFormatDescription& formatDesc = imageData.getDescription();
461 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
463 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
464 ? getPlaneAspect(planeNdx)
465 : VK_IMAGE_ASPECT_COLOR_BIT;
466 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1
467 ? allocations[planeNdx]
469 const size_t planeSize = imageData.getPlaneSize(planeNdx);
470 const deUint32 planeH = imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
471 const VkImageSubresource subresource =
473 static_cast<vk::VkImageAspectFlags>(aspect),
477 VkSubresourceLayout layout;
479 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
481 for (deUint32 row = 0; row < planeH; ++row)
483 const size_t rowSize = planeSize / planeH;
484 void* const dstPtr = ((deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
485 const void* const srcPtr = ((const deUint8*)imageData.getPlanePtr(planeNdx)) + row * rowSize;
487 deMemcpy(dstPtr, srcPtr, rowSize);
489 flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
493 const VkCommandBufferBeginInfo beginInfo =
495 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
497 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
498 (const VkCommandBufferInheritanceInfo*)DE_NULL
501 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
506 const VkImageMemoryBarrier postCopyBarrier =
508 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
512 VK_IMAGE_LAYOUT_PREINITIALIZED,
514 VK_QUEUE_FAMILY_IGNORED,
515 VK_QUEUE_FAMILY_IGNORED,
517 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
520 vkd.cmdPipelineBarrier(*cmdBuffer,
521 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
522 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
523 (VkDependencyFlags)0u,
525 (const VkMemoryBarrier*)DE_NULL,
527 (const VkBufferMemoryBarrier*)DE_NULL,
532 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
535 const Unique<VkFence> fence (createFence(vkd, device));
536 const VkSubmitInfo submitInfo =
538 VK_STRUCTURE_TYPE_SUBMIT_INFO,
541 (const VkSemaphore*)DE_NULL,
542 (const VkPipelineStageFlags*)DE_NULL,
546 (const VkSemaphore*)DE_NULL,
549 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
550 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
554 void downloadImage (const DeviceInterface& vkd,
556 deUint32 queueFamilyNdx,
557 Allocator& allocator,
559 MultiPlaneImageData* imageData,
560 VkAccessFlags prevAccess,
561 VkImageLayout initialLayout)
563 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
564 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
565 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
566 vector<VkBufferSp> stagingBuffers;
567 vector<AllocationSp> stagingMemory;
569 const PlanarFormatDescription& formatDesc = imageData->getDescription();
571 allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory);
574 const VkCommandBufferBeginInfo beginInfo =
576 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
578 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
579 (const VkCommandBufferInheritanceInfo*)DE_NULL
582 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
585 for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
587 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
588 ? getPlaneAspect(planeNdx)
589 : VK_IMAGE_ASPECT_COLOR_BIT;
591 const VkImageMemoryBarrier preCopyBarrier =
593 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
596 VK_ACCESS_TRANSFER_READ_BIT,
598 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
599 VK_QUEUE_FAMILY_IGNORED,
600 VK_QUEUE_FAMILY_IGNORED,
603 static_cast<vk::VkImageAspectFlags>(aspect),
611 vkd.cmdPipelineBarrier(*cmdBuffer,
612 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
613 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
614 (VkDependencyFlags)0u,
616 (const VkMemoryBarrier*)DE_NULL,
618 (const VkBufferMemoryBarrier*)DE_NULL,
623 const deUint32 planeW = (formatDesc.numPlanes > 1)
624 ? imageData->getSize().x() / formatDesc.planes[planeNdx].widthDivisor
625 : imageData->getSize().x();
626 const deUint32 planeH = (formatDesc.numPlanes > 1)
627 ? imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor
628 : imageData->getSize().y();
629 const VkBufferImageCopy copy =
632 0u, // bufferRowLength
633 0u, // bufferImageHeight
634 { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
635 makeOffset3D(0u, 0u, 0u),
636 makeExtent3D(planeW, planeH, 1u),
639 vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **stagingBuffers[planeNdx], 1u, ©);
642 const VkBufferMemoryBarrier postCopyBarrier =
644 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
646 VK_ACCESS_TRANSFER_WRITE_BIT,
647 VK_ACCESS_HOST_READ_BIT,
648 VK_QUEUE_FAMILY_IGNORED,
649 VK_QUEUE_FAMILY_IGNORED,
650 **stagingBuffers[planeNdx],
655 vkd.cmdPipelineBarrier(*cmdBuffer,
656 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
657 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
658 (VkDependencyFlags)0u,
660 (const VkMemoryBarrier*)DE_NULL,
664 (const VkImageMemoryBarrier*)DE_NULL);
668 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
671 const Unique<VkFence> fence (createFence(vkd, device));
672 const VkSubmitInfo submitInfo =
674 VK_STRUCTURE_TYPE_SUBMIT_INFO,
677 (const VkSemaphore*)DE_NULL,
678 (const VkPipelineStageFlags*)DE_NULL,
682 (const VkSemaphore*)DE_NULL,
685 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
686 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
689 readStagingBuffers(imageData, vkd, device, stagingMemory);
692 void readImageMemory (const vk::DeviceInterface& vkd,
694 deUint32 queueFamilyNdx,
696 const std::vector<de::SharedPtr<vk::Allocation> >& allocations,
697 MultiPlaneImageData* imageData,
698 vk::VkAccessFlags prevAccess,
699 vk::VkImageLayout initialLayout)
701 const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
702 const Unique<VkCommandPool> cmdPool (createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
703 const Unique<VkCommandBuffer> cmdBuffer (allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
704 const PlanarFormatDescription& formatDesc = imageData->getDescription();
707 const VkCommandBufferBeginInfo beginInfo =
709 VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
711 (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
712 (const VkCommandBufferInheritanceInfo*)DE_NULL
715 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
719 const VkImageMemoryBarrier preCopyBarrier =
721 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
724 vk::VK_ACCESS_HOST_READ_BIT,
726 VK_IMAGE_LAYOUT_GENERAL,
727 VK_QUEUE_FAMILY_IGNORED,
728 VK_QUEUE_FAMILY_IGNORED,
730 { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
733 vkd.cmdPipelineBarrier(*cmdBuffer,
734 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
735 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
736 (VkDependencyFlags)0u,
738 (const VkMemoryBarrier*)DE_NULL,
740 (const VkBufferMemoryBarrier*)DE_NULL,
745 VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
748 const Unique<VkFence> fence (createFence(vkd, device));
749 const VkSubmitInfo submitInfo =
751 VK_STRUCTURE_TYPE_SUBMIT_INFO,
754 (const VkSemaphore*)DE_NULL,
755 (const VkPipelineStageFlags*)DE_NULL,
759 (const VkSemaphore*)DE_NULL,
762 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
763 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
766 for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
768 const VkImageAspectFlagBits aspect = (formatDesc.numPlanes > 1)
769 ? getPlaneAspect(planeNdx)
770 : VK_IMAGE_ASPECT_COLOR_BIT;
771 const de::SharedPtr<Allocation>& allocation = allocations.size() > 1
772 ? allocations[planeNdx]
774 const size_t planeSize = imageData->getPlaneSize(planeNdx);
775 const deUint32 planeH = imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
776 const VkImageSubresource subresource =
778 static_cast<vk::VkImageAspectFlags>(aspect),
782 VkSubresourceLayout layout;
784 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
786 invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
788 for (deUint32 row = 0; row < planeH; ++row)
790 const size_t rowSize = planeSize / planeH;
791 const void* const srcPtr = ((const deUint8*)allocation->getHostPtr()) + layout.offset + layout.rowPitch * row;
792 void* const dstPtr = ((deUint8*)imageData->getPlanePtr(planeNdx)) + row * rowSize;
794 deMemcpy(dstPtr, srcPtr, rowSize);
799 // ChannelAccess utilities
803 //! Extend < 32b signed integer to 32b
804 inline deInt32 signExtend (deUint32 src, int bits)
806 const deUint32 signBit = 1u << (bits-1);
808 src |= ~((src & signBit) - 1);
813 deUint32 divRoundUp (deUint32 a, deUint32 b)
821 // \todo Taken from tcuTexture.cpp
822 // \todo [2011-09-21 pyry] Move to tcutil?
823 template <typename T>
824 inline T convertSatRte (float f)
826 // \note Doesn't work for 64-bit types
827 DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
828 DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
830 deInt64 minVal = std::numeric_limits<T>::min();
831 deInt64 maxVal = std::numeric_limits<T>::max();
832 float q = deFloatFrac(f);
833 deInt64 intVal = (deInt64)(f-q);
843 // else Don't add anything
846 intVal = de::max(minVal, de::min(maxVal, intVal));
853 ChannelAccess::ChannelAccess (tcu::TextureChannelClass channelClass,
855 const tcu::IVec3& size,
856 const tcu::IVec3& bitPitch,
859 : m_channelClass (channelClass)
860 , m_channelSize (channelSize)
862 , m_bitPitch (bitPitch)
864 , m_data ((deUint8*)data + (bitOffset / 8))
865 , m_bitOffset (bitOffset % 8)
869 deUint32 ChannelAccess::getChannelUint (const tcu::IVec3& pos) const
871 DE_ASSERT(pos[0] < m_size[0]);
872 DE_ASSERT(pos[1] < m_size[1]);
873 DE_ASSERT(pos[2] < m_size[2]);
875 const deInt32 bitOffset (m_bitOffset + tcu::dot(m_bitPitch, pos));
876 const deUint8* const firstByte = ((const deUint8*)m_data) + (bitOffset / 8);
877 const deUint32 byteCount = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
878 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
879 const deUint32 offset = bitOffset % 8;
882 deMemcpy(&bits, firstByte, byteCount);
884 return (bits >> offset) & mask;
887 void ChannelAccess::setChannel (const tcu::IVec3& pos, deUint32 x)
889 DE_ASSERT(pos[0] < m_size[0]);
890 DE_ASSERT(pos[1] < m_size[1]);
891 DE_ASSERT(pos[2] < m_size[2]);
893 const deInt32 bitOffset (m_bitOffset + tcu::dot(m_bitPitch, pos));
894 deUint8* const firstByte = ((deUint8*)m_data) + (bitOffset / 8);
895 const deUint32 byteCount = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
896 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
897 const deUint32 offset = bitOffset % 8;
899 const deUint32 bits = (x & mask) << offset;
900 deUint32 oldBits = 0;
902 deMemcpy(&oldBits, firstByte, byteCount);
905 const deUint32 newBits = bits | (oldBits & (~(mask << offset)));
907 deMemcpy(firstByte, &newBits, byteCount);
911 float ChannelAccess::getChannel (const tcu::IVec3& pos) const
913 const deUint32 bits (getChannelUint(pos));
915 switch (m_channelClass)
917 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
918 return (float)bits / (float)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u));
920 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
923 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
924 return de::max(-1.0f, (float)signExtend(bits, m_channelSize) / (float)((0x1u << (m_channelSize - 1u)) - 1u));
926 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
927 return (float)signExtend(bits, m_channelSize);
929 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
930 if (m_channelSize == 32)
931 return tcu::Float32(bits).asFloat();
934 DE_FATAL("Float type not supported");
939 DE_FATAL("Unknown texture channel class");
944 tcu::Interval ChannelAccess::getChannel (const tcu::FloatFormat& conversionFormat,
945 const tcu::IVec3& pos) const
947 const deUint32 bits (getChannelUint(pos));
949 switch (m_channelClass)
951 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
952 return conversionFormat.roundOut(conversionFormat.roundOut((double)bits, false)
953 / conversionFormat.roundOut((double)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u)), false), false);
955 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
956 return conversionFormat.roundOut((double)bits, false);
958 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
960 const tcu::Interval result (conversionFormat.roundOut(conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false)
961 / conversionFormat.roundOut((double)((0x1u << (m_channelSize - 1u)) - 1u), false), false));
963 return tcu::Interval(de::max(-1.0, result.lo()), de::max(-1.0, result.hi()));
966 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
967 return conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false);
969 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
970 if (m_channelSize == 32)
971 return conversionFormat.roundOut(tcu::Float32(bits).asFloat(), false);
974 DE_FATAL("Float type not supported");
975 return tcu::Interval();
979 DE_FATAL("Unknown texture channel class");
980 return tcu::Interval();
984 void ChannelAccess::setChannel (const tcu::IVec3& pos, float x)
986 DE_ASSERT(pos[0] < m_size[0]);
987 DE_ASSERT(pos[1] < m_size[1]);
988 DE_ASSERT(pos[2] < m_size[2]);
990 const deUint32 mask (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
992 switch (m_channelClass)
994 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
996 const deUint32 maxValue (mask);
997 const deUint32 value (de::min(maxValue, (deUint32)convertSatRte<deUint32>(x * (float)maxValue)));
998 setChannel(pos, value);
1002 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1004 const deInt32 range ((0x1u << (m_channelSize - 1u)) - 1u);
1005 const deUint32 value ((deUint32)de::clamp<deInt32>(convertSatRte<deInt32>(x * (float)range), -range, range));
1006 setChannel(pos, value);
1010 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1012 const deUint32 maxValue (mask);
1013 const deUint32 value (de::min(maxValue, (deUint32)x));
1014 setChannel(pos, value);
1018 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1020 const deInt32 minValue (-(deInt32)(1u << (m_channelSize - 1u)));
1021 const deInt32 maxValue ((deInt32)((1u << (m_channelSize - 1u)) - 1u));
1022 const deUint32 value ((deUint32)de::clamp((deInt32)x, minValue, maxValue));
1023 setChannel(pos, value);
1027 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1029 if (m_channelSize == 32)
1031 const deUint32 value = tcu::Float32(x).bits();
1032 setChannel(pos, value);
1035 DE_FATAL("Float type not supported");
1040 DE_FATAL("Unknown texture channel class");
1044 ChannelAccess getChannelAccess (MultiPlaneImageData& data,
1045 const vk::PlanarFormatDescription& formatInfo,
1049 DE_ASSERT(formatInfo.hasChannelNdx(channelNdx));
1051 const deUint32 planeNdx = formatInfo.channels[channelNdx].planeNdx;
1052 const deUint32 valueOffsetBits = formatInfo.channels[channelNdx].offsetBits;
1053 const deUint32 pixelStrideBytes = formatInfo.channels[channelNdx].strideBytes;
1054 const deUint32 pixelStrideBits = pixelStrideBytes * 8;
1055 const deUint8 sizeBits = formatInfo.channels[channelNdx].sizeBits;
1057 DE_ASSERT(size.x() % formatInfo.planes[planeNdx].widthDivisor == 0);
1058 DE_ASSERT(size.y() % formatInfo.planes[planeNdx].heightDivisor == 0);
1060 deUint32 accessWidth = size.x() / formatInfo.planes[planeNdx].widthDivisor;
1061 const deUint32 accessHeight = size.y() / formatInfo.planes[planeNdx].heightDivisor;
1062 const deUint32 elementSizeBytes = formatInfo.planes[planeNdx].elementSizeBytes;
1064 const deUint32 rowPitch = formatInfo.planes[planeNdx].elementSizeBytes * accessWidth;
1065 const deUint32 rowPitchBits = rowPitch * 8;
1067 if (pixelStrideBytes != elementSizeBytes)
1069 DE_ASSERT(elementSizeBytes % pixelStrideBytes == 0);
1070 accessWidth *= elementSizeBytes/pixelStrideBytes;
1073 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);
1076 bool isXChromaSubsampled (vk::VkFormat format)
1080 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1081 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1082 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1083 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1084 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1085 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1086 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1087 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1088 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1089 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1090 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1091 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1092 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1093 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1094 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1095 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1096 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1097 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1098 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1099 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1100 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1101 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1102 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1103 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1111 bool isYChromaSubsampled (vk::VkFormat format)
1115 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1116 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1117 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1118 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1119 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1120 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1121 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1122 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1130 // \note Used for range expansion
1131 tcu::UVec4 getYCbCrBitDepth (vk::VkFormat format)
1135 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1136 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1137 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1138 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1139 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1140 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1141 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1142 return tcu::UVec4(8, 8, 8, 0);
1144 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1145 return tcu::UVec4(10, 0, 0, 0);
1147 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1148 return tcu::UVec4(10, 10, 0, 0);
1150 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1151 return tcu::UVec4(10, 10, 10, 10);
1153 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1154 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1155 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1156 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1157 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1158 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1159 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1160 return tcu::UVec4(10, 10, 10, 0);
1162 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1163 return tcu::UVec4(12, 0, 0, 0);
1165 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1166 return tcu::UVec4(12, 12, 0, 0);
1168 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1169 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1170 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1171 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1172 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1173 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1174 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1175 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1176 return tcu::UVec4(12, 12, 12, 12);
1178 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1179 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1180 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1181 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1182 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1183 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1184 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1185 return tcu::UVec4(16, 16, 16, 0);
1188 return tcu::getTextureFormatBitDepth(vk::mapVkFormat(format)).cast<deUint32>();
1192 // \note Taken from explicit lod filtering tests
1193 tcu::FloatFormat getYCbCrFilteringPrecision (vk::VkFormat format)
1195 const tcu::FloatFormat reallyLow (0, 0, 6, false, tcu::YES);
1196 const tcu::FloatFormat low (0, 0, 7, false, tcu::YES);
1197 const tcu::FloatFormat fp16 (-14, 15, 10, false);
1198 const tcu::FloatFormat fp32 (-126, 127, 23, true);
1202 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1203 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1204 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1205 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1206 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1207 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1208 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1211 case vk::VK_FORMAT_R8G8B8_UNORM:
1212 case vk::VK_FORMAT_B8G8R8_UNORM:
1213 case vk::VK_FORMAT_R8G8B8A8_UNORM:
1214 case vk::VK_FORMAT_B8G8R8A8_UNORM:
1215 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1216 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1217 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1218 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1219 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1220 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1221 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1222 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1225 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1226 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1227 case vk::VK_FORMAT_R16G16B16_UNORM:
1228 case vk::VK_FORMAT_R16G16B16A16_UNORM:
1229 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1230 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1231 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1232 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1233 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1234 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1235 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1236 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1237 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1238 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1239 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1240 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1241 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1242 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1243 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1244 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1245 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1246 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1247 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1248 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1249 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1250 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1251 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1252 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1253 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1254 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1255 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1259 DE_FATAL("Precision not defined for format");
1264 // \note Taken from explicit lod filtering tests
1265 tcu::FloatFormat getYCbCrConversionPrecision (vk::VkFormat format)
1267 const tcu::FloatFormat reallyLow (0, 0, 8, false, tcu::YES);
1268 const tcu::FloatFormat fp16 (-14, 15, 10, false);
1269 const tcu::FloatFormat fp32 (-126, 127, 23, true);
1273 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1274 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1275 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1276 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1277 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1278 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1279 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1282 case vk::VK_FORMAT_R8G8B8_UNORM:
1283 case vk::VK_FORMAT_B8G8R8_UNORM:
1284 case vk::VK_FORMAT_R8G8B8A8_UNORM:
1285 case vk::VK_FORMAT_B8G8R8A8_UNORM:
1286 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1287 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1288 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1289 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1290 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1291 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1292 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1293 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1296 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1297 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1298 case vk::VK_FORMAT_R16G16B16_UNORM:
1299 case vk::VK_FORMAT_R16G16B16A16_UNORM:
1300 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1301 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1302 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1303 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1304 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1305 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1306 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1307 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1308 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1309 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1310 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1311 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1312 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1313 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1314 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1315 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1316 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1317 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1318 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1319 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1320 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1321 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1322 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1323 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1324 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1325 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1326 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1330 DE_FATAL("Precision not defined for format");
1335 deUint32 getYCbCrFormatChannelCount (vk::VkFormat format)
1339 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
1340 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
1341 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
1342 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
1343 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
1344 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
1345 case vk::VK_FORMAT_B8G8R8A8_UNORM:
1346 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1347 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1348 case vk::VK_FORMAT_R16G16B16A16_UNORM:
1349 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
1350 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
1351 case vk::VK_FORMAT_R8G8B8A8_UNORM:
1354 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1355 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1356 case vk::VK_FORMAT_B16G16R16G16_422_UNORM:
1357 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
1358 case vk::VK_FORMAT_B8G8R8G8_422_UNORM:
1359 case vk::VK_FORMAT_B8G8R8_UNORM:
1360 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1361 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1362 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1363 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1364 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1365 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1366 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1367 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1368 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1369 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1370 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1371 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1372 case vk::VK_FORMAT_G16B16G16R16_422_UNORM:
1373 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
1374 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
1375 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
1376 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
1377 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
1378 case vk::VK_FORMAT_G8B8G8R8_422_UNORM:
1379 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
1380 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
1381 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
1382 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
1383 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
1384 case vk::VK_FORMAT_R16G16B16_UNORM:
1385 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
1386 case vk::VK_FORMAT_R8G8B8_UNORM:
1389 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1390 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1393 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1394 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1398 DE_FATAL("Unknown number of channels");
1403 // YCbCr color conversion utilities
1407 tcu::Interval rangeExpandChroma (vk::VkSamplerYcbcrRange range,
1408 const tcu::FloatFormat& conversionFormat,
1409 const deUint32 bits,
1410 const tcu::Interval& sample)
1412 const deUint32 values (0x1u << bits);
1416 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
1417 return conversionFormat.roundOut(sample - conversionFormat.roundOut(tcu::Interval((double)(0x1u << (bits - 1u)) / (double)((0x1u << bits) - 1u)), false), false);
1419 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1421 const tcu::Interval a (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
1422 const tcu::Interval dividend (conversionFormat.roundOut(a - tcu::Interval((double)(128u * (0x1u << (bits - 8u)))), false));
1423 const tcu::Interval divisor ((double)(224u * (0x1u << (bits - 8u))));
1424 const tcu::Interval result (conversionFormat.roundOut(dividend / divisor, false));
1430 DE_FATAL("Unknown YCbCrRange");
1431 return tcu::Interval();
1435 tcu::Interval rangeExpandLuma (vk::VkSamplerYcbcrRange range,
1436 const tcu::FloatFormat& conversionFormat,
1437 const deUint32 bits,
1438 const tcu::Interval& sample)
1440 const deUint32 values (0x1u << bits);
1444 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
1445 return conversionFormat.roundOut(sample, false);
1447 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1449 const tcu::Interval a (conversionFormat.roundOut(sample * tcu::Interval((double)(values - 1u)), false));
1450 const tcu::Interval dividend (conversionFormat.roundOut(a - tcu::Interval((double)(16u * (0x1u << (bits - 8u)))), false));
1451 const tcu::Interval divisor ((double)(219u * (0x1u << (bits - 8u))));
1452 const tcu::Interval result (conversionFormat.roundOut(dividend / divisor, false));
1458 DE_FATAL("Unknown YCbCrRange");
1459 return tcu::Interval();
1463 tcu::Interval clampMaybe (const tcu::Interval& x,
1467 tcu::Interval result = x;
1469 DE_ASSERT(min <= max);
1472 result = result | tcu::Interval(min);
1475 result = result | tcu::Interval(max);
1480 void convertColor (vk::VkSamplerYcbcrModelConversion colorModel,
1481 vk::VkSamplerYcbcrRange range,
1482 const tcu::FloatFormat& conversionFormat,
1483 const tcu::UVec4& bitDepth,
1484 const tcu::Interval input[4],
1485 tcu::Interval output[4])
1489 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:
1491 for (size_t ndx = 0; ndx < 4; ndx++)
1492 output[ndx] = input[ndx];
1496 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:
1498 output[0] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]), -0.5, 0.5);
1499 output[1] = clampMaybe(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]), 0.0, 1.0);
1500 output[2] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]), -0.5, 0.5);
1501 output[3] = input[3];
1505 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:
1507 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1508 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1509 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1511 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0));
1512 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5));
1513 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5));
1515 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.402 * crClamped, false), false);
1516 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);
1517 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.772 * cbClamped, false), false);
1518 output[3] = input[3];
1522 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:
1524 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1525 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1526 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1528 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0));
1529 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5));
1530 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5));
1532 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.5748 * crClamped, false), false);
1533 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);
1534 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8556 * cbClamped, false), false);
1535 output[3] = input[3];
1539 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:
1541 const tcu::Interval y (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
1542 const tcu::Interval cr (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
1543 const tcu::Interval cb (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
1545 const tcu::Interval yClamped (clampMaybe(y, 0.0, 1.0));
1546 const tcu::Interval crClamped (clampMaybe(cr, -0.5, 0.5));
1547 const tcu::Interval cbClamped (clampMaybe(cb, -0.5, 0.5));
1549 output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.4746 * crClamped, false), false);
1550 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);
1551 output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8814 * cbClamped, false), false);
1552 output[3] = input[3];
1557 DE_FATAL("Unknown YCbCrModel");
1560 if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY)
1562 for (int ndx = 0; ndx < 3; ndx++)
1563 output[ndx] = clampMaybe(output[ndx], 0.0, 1.0);
1567 int mirror (int coord)
1569 return coord >= 0 ? coord : -(1 + coord);
1572 int imod (int a, int b)
1575 return m < 0 ? m + b : m;
1578 tcu::Interval frac (const tcu::Interval& x)
1580 if (x.hi() - x.lo() >= 1.0)
1581 return tcu::Interval(0.0, 1.0);
1584 const tcu::Interval ret (deFrac(x.lo()), deFrac(x.hi()));
1590 tcu::Interval calculateUV (const tcu::FloatFormat& coordFormat,
1591 const tcu::Interval& st,
1594 return coordFormat.roundOut(coordFormat.roundOut(st, false) * tcu::Interval((double)size), false);
1597 tcu::IVec2 calculateNearestIJRange (const tcu::FloatFormat& coordFormat,
1598 const tcu::Interval& uv)
1600 const tcu::Interval ij (coordFormat.roundOut(coordFormat.roundOut(uv, false) - tcu::Interval(0.5), false));
1602 return tcu::IVec2(deRoundToInt32(ij.lo() - coordFormat.ulp(ij.lo(), 1)), deRoundToInt32(ij.hi() + coordFormat.ulp(ij.hi(), 1)));
1605 // Calculate range of pixel coordinates that can be used as lower coordinate for linear sampling
1606 tcu::IVec2 calculateLinearIJRange (const tcu::FloatFormat& coordFormat,
1607 const tcu::Interval& uv)
1609 const tcu::Interval ij (coordFormat.roundOut(uv - tcu::Interval(0.5), false));
1611 return tcu::IVec2(deFloorToInt32(ij.lo()), deFloorToInt32(ij.hi()));
1614 tcu::Interval calculateAB (const deUint32 subTexelPrecisionBits,
1615 const tcu::Interval& uv,
1618 const deUint32 subdivisions = 0x1u << subTexelPrecisionBits;
1619 const tcu::Interval ab (frac((uv - 0.5) & tcu::Interval((double)ij, (double)(ij + 1))));
1620 const tcu::Interval gridAB (ab * tcu::Interval(subdivisions));
1621 const tcu::Interval rounded (de::max(deFloor(gridAB.lo()) / subdivisions, 0.0) , de::min(deCeil(gridAB.hi()) / subdivisions, 1.0));
1626 tcu::Interval lookupWrapped (const ChannelAccess& access,
1627 const tcu::FloatFormat& conversionFormat,
1628 vk::VkSamplerAddressMode addressModeU,
1629 vk::VkSamplerAddressMode addressModeV,
1630 const tcu::IVec2& coord)
1632 return access.getChannel(conversionFormat,
1633 tcu::IVec3(wrap(addressModeU, coord.x(), access.getSize().x()), wrap(addressModeV, coord.y(), access.getSize().y()), 0));
1636 tcu::Interval linearInterpolate (const tcu::FloatFormat& filteringFormat,
1637 const tcu::Interval& a,
1638 const tcu::Interval& b,
1639 const tcu::Interval& p00,
1640 const tcu::Interval& p10,
1641 const tcu::Interval& p01,
1642 const tcu::Interval& p11)
1644 const tcu::Interval p[4] =
1651 tcu::Interval result (0.0);
1653 for (size_t ndx = 0; ndx < 4; ndx++)
1655 const tcu::Interval weightA (filteringFormat.roundOut((ndx % 2) == 0 ? (1.0 - a) : a, false));
1656 const tcu::Interval weightB (filteringFormat.roundOut((ndx / 2) == 0 ? (1.0 - b) : b, false));
1657 const tcu::Interval weight (filteringFormat.roundOut(weightA * weightB, false));
1659 result = filteringFormat.roundOut(result + filteringFormat.roundOut(p[ndx] * weight, false), false);
1665 tcu::Interval calculateImplicitChromaUV (const tcu::FloatFormat& coordFormat,
1666 vk::VkChromaLocation offset,
1667 const tcu::Interval& uv)
1669 if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1670 return coordFormat.roundOut(0.5 * coordFormat.roundOut(uv + 0.5, false), false);
1672 return coordFormat.roundOut(0.5 * uv, false);
1675 tcu::Interval linearSample (const ChannelAccess& access,
1676 const tcu::FloatFormat& conversionFormat,
1677 const tcu::FloatFormat& filteringFormat,
1678 vk::VkSamplerAddressMode addressModeU,
1679 vk::VkSamplerAddressMode addressModeV,
1680 const tcu::IVec2& coord,
1681 const tcu::Interval& a,
1682 const tcu::Interval& b)
1684 return linearInterpolate(filteringFormat, a, b,
1685 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 0)),
1686 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 0)),
1687 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(0, 1)),
1688 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + tcu::IVec2(1, 1)));
1691 tcu::Interval reconstructLinearXChromaSample (const tcu::FloatFormat& filteringFormat,
1692 const tcu::FloatFormat& conversionFormat,
1693 vk::VkChromaLocation offset,
1694 vk::VkSamplerAddressMode addressModeU,
1695 vk::VkSamplerAddressMode addressModeV,
1696 const ChannelAccess& access,
1700 const int subI = divFloor(i, 2);
1702 if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1705 return lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j));
1708 const tcu::Interval a (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1709 const tcu::Interval b (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
1711 return filteringFormat.roundOut(a + b, false);
1714 else if (offset == vk::VK_CHROMA_LOCATION_MIDPOINT)
1718 const tcu::Interval a (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI - 1, j)), false));
1719 const tcu::Interval b (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1721 return filteringFormat.roundOut(a + b, false);
1725 const tcu::Interval a (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, j)), false));
1726 const tcu::Interval b (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j)), false));
1728 return filteringFormat.roundOut(a + b, false);
1733 DE_FATAL("Unknown sample location");
1734 return tcu::Interval();
1738 tcu::Interval reconstructLinearXYChromaSample (const tcu::FloatFormat& filteringFormat,
1739 const tcu::FloatFormat& conversionFormat,
1740 vk::VkChromaLocation xOffset,
1741 vk::VkChromaLocation yOffset,
1742 vk::VkSamplerAddressMode addressModeU,
1743 vk::VkSamplerAddressMode addressModeV,
1744 const ChannelAccess& access,
1748 const int subI = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1750 : (i % 2 == 0 ? divFloor(i, 2) - 1 : divFloor(i, 2));
1751 const int subJ = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1753 : (j % 2 == 0 ? divFloor(j, 2) - 1 : divFloor(j, 2));
1755 const double a = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1756 ? (i % 2 == 0 ? 0.0 : 0.5)
1757 : (i % 2 == 0 ? 0.25 : 0.75);
1758 const double b = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1759 ? (j % 2 == 0 ? 0.0 : 0.5)
1760 : (j % 2 == 0 ? 0.25 : 0.75);
1762 return linearInterpolate(filteringFormat, a, b,
1763 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ)),
1764 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ)),
1765 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, subJ + 1)),
1766 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI + 1, subJ + 1)));
1769 const ChannelAccess& swizzle (vk::VkComponentSwizzle swizzle,
1770 const ChannelAccess& identityPlane,
1771 const ChannelAccess& rPlane,
1772 const ChannelAccess& gPlane,
1773 const ChannelAccess& bPlane,
1774 const ChannelAccess& aPlane)
1778 case vk::VK_COMPONENT_SWIZZLE_IDENTITY: return identityPlane;
1779 case vk::VK_COMPONENT_SWIZZLE_R: return rPlane;
1780 case vk::VK_COMPONENT_SWIZZLE_G: return gPlane;
1781 case vk::VK_COMPONENT_SWIZZLE_B: return bPlane;
1782 case vk::VK_COMPONENT_SWIZZLE_A: return aPlane;
1785 DE_FATAL("Unsupported swizzle");
1786 return identityPlane;
1792 int wrap (vk::VkSamplerAddressMode addressMode,
1796 switch (addressMode)
1798 case vk::VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
1799 return (size - 1) - mirror(imod(coord, 2 * size) - size);
1801 case vk::VK_SAMPLER_ADDRESS_MODE_REPEAT:
1802 return imod(coord, size);
1804 case vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1805 return de::clamp(coord, 0, size - 1);
1807 case vk::VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
1808 return de::clamp(mirror(coord), 0, size - 1);
1811 DE_FATAL("Unknown wrap mode");
1816 int divFloor (int a, int b)
1826 void calculateBounds (const ChannelAccess& rPlane,
1827 const ChannelAccess& gPlane,
1828 const ChannelAccess& bPlane,
1829 const ChannelAccess& aPlane,
1830 const UVec4& bitDepth,
1831 const vector<Vec2>& sts,
1832 const FloatFormat& filteringFormat,
1833 const FloatFormat& conversionFormat,
1834 const deUint32 subTexelPrecisionBits,
1835 vk::VkFilter filter,
1836 vk::VkSamplerYcbcrModelConversion colorModel,
1837 vk::VkSamplerYcbcrRange range,
1838 vk::VkFilter chromaFilter,
1839 vk::VkChromaLocation xChromaOffset,
1840 vk::VkChromaLocation yChromaOffset,
1841 const vk::VkComponentMapping& componentMapping,
1842 bool explicitReconstruction,
1843 vk::VkSamplerAddressMode addressModeU,
1844 vk::VkSamplerAddressMode addressModeV,
1845 std::vector<Vec4>& minBounds,
1846 std::vector<Vec4>& maxBounds,
1847 std::vector<Vec4>& uvBounds,
1848 std::vector<IVec4>& ijBounds)
1850 const FloatFormat highp (-126, 127, 23, true,
1851 tcu::MAYBE, // subnormals
1852 tcu::YES, // infinities
1854 const FloatFormat coordFormat (-32, 32, 16, true);
1855 const ChannelAccess& rAccess (swizzle(componentMapping.r, rPlane, rPlane, gPlane, bPlane, aPlane));
1856 const ChannelAccess& gAccess (swizzle(componentMapping.g, gPlane, rPlane, gPlane, bPlane, aPlane));
1857 const ChannelAccess& bAccess (swizzle(componentMapping.b, bPlane, rPlane, gPlane, bPlane, aPlane));
1858 const ChannelAccess& aAccess (swizzle(componentMapping.a, aPlane, rPlane, gPlane, bPlane, aPlane));
1860 const bool subsampledX = gAccess.getSize().x() > rAccess.getSize().x();
1861 const bool subsampledY = gAccess.getSize().y() > rAccess.getSize().y();
1863 minBounds.resize(sts.size(), Vec4(TCU_INFINITY));
1864 maxBounds.resize(sts.size(), Vec4(-TCU_INFINITY));
1866 uvBounds.resize(sts.size(), Vec4(TCU_INFINITY, -TCU_INFINITY, TCU_INFINITY, -TCU_INFINITY));
1867 ijBounds.resize(sts.size(), IVec4(0x7FFFFFFF, -1 -0x7FFFFFFF, 0x7FFFFFFF, -1 -0x7FFFFFFF));
1869 // Chroma plane sizes must match
1870 DE_ASSERT(rAccess.getSize() == bAccess.getSize());
1872 // Luma plane sizes must match
1873 DE_ASSERT(gAccess.getSize() == aAccess.getSize());
1875 // Luma plane size must match chroma plane or be twice as big
1876 DE_ASSERT(rAccess.getSize().x() == gAccess.getSize().x() || 2 * rAccess.getSize().x() == gAccess.getSize().x());
1877 DE_ASSERT(rAccess.getSize().y() == gAccess.getSize().y() || 2 * rAccess.getSize().y() == gAccess.getSize().y());
1879 for (size_t ndx = 0; ndx < sts.size(); ndx++)
1881 const Vec2 st (sts[ndx]);
1884 const Interval u (calculateUV(coordFormat, st[0], gAccess.getSize().x()));
1885 const Interval v (calculateUV(coordFormat, st[1], gAccess.getSize().y()));
1887 uvBounds[ndx][0] = (float)u.lo();
1888 uvBounds[ndx][1] = (float)u.hi();
1890 uvBounds[ndx][2] = (float)v.lo();
1891 uvBounds[ndx][3] = (float)v.hi();
1893 if (filter == vk::VK_FILTER_NEAREST)
1895 const IVec2 iRange (calculateNearestIJRange(coordFormat, u));
1896 const IVec2 jRange (calculateNearestIJRange(coordFormat, v));
1898 ijBounds[ndx][0] = iRange[0];
1899 ijBounds[ndx][1] = iRange[1];
1901 ijBounds[ndx][2] = jRange[0];
1902 ijBounds[ndx][3] = jRange[1];
1904 for (int j = jRange.x(); j <= jRange.y(); j++)
1905 for (int i = iRange.x(); i <= iRange.y(); i++)
1907 const Interval gValue (lookupWrapped(gAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1908 const Interval aValue (lookupWrapped(aAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1910 if (subsampledX || subsampledY)
1912 if (explicitReconstruction)
1914 if (chromaFilter == vk::VK_FILTER_NEAREST)
1916 // Nearest, Reconstructed chroma with explicit nearest filtering
1917 const int subI = subsampledX ? i / 2 : i;
1918 const int subJ = subsampledY ? j / 2 : j;
1919 const Interval srcColor[] =
1921 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1923 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1926 Interval dstColor[4];
1928 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1930 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1931 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1933 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1935 if (subsampledX && subsampledY)
1937 // Nearest, Reconstructed both chroma samples with explicit linear filtering
1938 const Interval rValue (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1939 const Interval bValue (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1940 const Interval srcColor[] =
1947 Interval dstColor[4];
1949 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1951 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1952 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1954 else if (subsampledX)
1956 // Nearest, Reconstructed x chroma samples with explicit linear filtering
1957 const Interval rValue (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1958 const Interval bValue (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1959 const Interval srcColor[] =
1966 Interval dstColor[4];
1968 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1970 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1971 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1974 DE_FATAL("Unexpected chroma reconstruction");
1977 DE_FATAL("Unknown filter");
1981 const Interval chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
1982 const Interval chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
1984 if (chromaFilter == vk::VK_FILTER_NEAREST)
1986 // Nearest, reconstructed chroma samples with implicit nearest filtering
1987 const IVec2 chromaIRange (subsampledX ? calculateNearestIJRange(coordFormat, chromaU) : IVec2(i, i));
1988 const IVec2 chromaJRange (subsampledY ? calculateNearestIJRange(coordFormat, chromaV) : IVec2(j, j));
1990 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1991 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
1993 const Interval srcColor[] =
1995 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1997 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2000 Interval dstColor[4];
2002 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2004 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2005 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2008 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2010 // Nearest, reconstructed chroma samples with implicit linear filtering
2011 const IVec2 chromaIRange (subsampledX ? calculateLinearIJRange(coordFormat, chromaU) : IVec2(i, i));
2012 const IVec2 chromaJRange (subsampledY ? calculateLinearIJRange(coordFormat, chromaV) : IVec2(j, j));
2014 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2015 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2017 const Interval chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
2018 const Interval chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
2020 const Interval srcColor[] =
2022 linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
2024 linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
2027 Interval dstColor[4];
2029 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2031 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2032 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2036 DE_FATAL("Unknown filter");
2041 // Linear, no chroma subsampling
2042 const Interval srcColor[] =
2044 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
2046 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
2049 Interval dstColor[4];
2051 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2053 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2054 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2058 else if (filter == vk::VK_FILTER_LINEAR)
2060 const IVec2 iRange (calculateLinearIJRange(coordFormat, u));
2061 const IVec2 jRange (calculateLinearIJRange(coordFormat, v));
2063 ijBounds[ndx][0] = iRange[0];
2064 ijBounds[ndx][1] = iRange[1];
2066 ijBounds[ndx][2] = jRange[0];
2067 ijBounds[ndx][3] = jRange[1];
2069 for (int j = jRange.x(); j <= jRange.y(); j++)
2070 for (int i = iRange.x(); i <= iRange.y(); i++)
2072 const Interval lumaA (calculateAB(subTexelPrecisionBits, u, i));
2073 const Interval lumaB (calculateAB(subTexelPrecisionBits, v, j));
2075 const Interval gValue (linearSample(gAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
2076 const Interval aValue (linearSample(aAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
2078 if (subsampledX || subsampledY)
2080 if (explicitReconstruction)
2082 if (chromaFilter == vk::VK_FILTER_NEAREST)
2084 const Interval srcColor[] =
2086 linearInterpolate(filteringFormat, lumaA, lumaB,
2087 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2088 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2089 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
2090 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
2092 linearInterpolate(filteringFormat, lumaA, lumaB,
2093 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2094 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j / (subsampledY ? 2 : 1))),
2095 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
2096 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
2099 Interval dstColor[4];
2101 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2103 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2104 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2106 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2108 if (subsampledX && subsampledY)
2110 // Linear, Reconstructed xx chroma samples with explicit linear filtering
2111 const Interval rValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2112 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j),
2113 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
2114 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
2115 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
2116 const Interval bValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2117 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j),
2118 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
2119 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
2120 reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
2121 const Interval srcColor[] =
2128 Interval dstColor[4];
2130 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2132 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2133 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2136 else if (subsampledX)
2138 // Linear, Reconstructed x chroma samples with explicit linear filtering
2139 const Interval rValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2140 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j),
2141 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
2142 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
2143 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
2144 const Interval bValue (linearInterpolate(filteringFormat, lumaA, lumaB,
2145 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j),
2146 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
2147 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
2148 reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
2149 const Interval srcColor[] =
2156 Interval dstColor[4];
2158 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2160 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2161 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2164 DE_FATAL("Unknown subsampling config");
2167 DE_FATAL("Unknown chroma filter");
2171 const Interval chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
2172 const Interval chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
2174 if (chromaFilter == vk::VK_FILTER_NEAREST)
2176 const IVec2 chromaIRange (calculateNearestIJRange(coordFormat, chromaU));
2177 const IVec2 chromaJRange (calculateNearestIJRange(coordFormat, chromaV));
2179 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2180 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2182 const Interval srcColor[] =
2184 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2186 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2189 Interval dstColor[4];
2191 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2193 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2194 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2197 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2199 const IVec2 chromaIRange (calculateNearestIJRange(coordFormat, chromaU));
2200 const IVec2 chromaJRange (calculateNearestIJRange(coordFormat, chromaV));
2202 for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2203 for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2205 const Interval chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
2206 const Interval chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
2208 const Interval rValue (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
2209 const Interval bValue (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
2211 const Interval srcColor[] =
2218 Interval dstColor[4];
2219 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2221 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2222 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2226 DE_FATAL("Unknown chroma filter");
2231 const Interval chromaA (lumaA);
2232 const Interval chromaB (lumaB);
2233 const Interval rValue (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
2234 const Interval bValue (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
2235 const Interval srcColor[] =
2242 Interval dstColor[4];
2244 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2246 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2247 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2252 DE_FATAL("Unknown filter");
2254 minBounds[ndx] = Vec4((float)bounds[0].lo(), (float)bounds[1].lo(), (float)bounds[2].lo(), (float)bounds[3].lo());
2255 maxBounds[ndx] = Vec4((float)bounds[0].hi(), (float)bounds[1].hi(), (float)bounds[2].hi(), (float)bounds[3].hi());