Merge remote-tracking branch 'goog/upstream-vulkan-cts-next' into vulkan-cts-1.1...
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / ycbcr / vktYCbCrUtil.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief YCbCr Test Utilities
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktYCbCrUtil.hpp"
25
26 #include "vkQueryUtil.hpp"
27 #include "vkRefUtil.hpp"
28 #include "vkTypeUtil.hpp"
29
30 #include "tcuTextureUtil.hpp"
31 #include "deMath.h"
32 #include "deFloat16.h"
33 #include "tcuVector.hpp"
34 #include "tcuVectorUtil.hpp"
35
36 #include "deSTLUtil.hpp"
37 #include "deUniquePtr.hpp"
38
39 namespace vkt
40 {
41 namespace ycbcr
42 {
43
44 using namespace vk;
45
46 using de::MovePtr;
47 using tcu::FloatFormat;
48 using tcu::Interval;
49 using tcu::IVec2;
50 using tcu::IVec4;
51 using tcu::UVec2;
52 using tcu::UVec4;
53 using tcu::Vec2;
54 using tcu::Vec4;
55 using std::vector;
56 using std::string;
57
58 typedef de::SharedPtr<Allocation>                               AllocationSp;
59 typedef de::SharedPtr<vk::Unique<VkBuffer> >    VkBufferSp;
60
61 // MultiPlaneImageData
62
63 MultiPlaneImageData::MultiPlaneImageData (VkFormat format, const UVec2& size)
64         : m_format              (format)
65         , m_description (getPlanarFormatDescription(format))
66         , m_size                (size)
67 {
68         for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
69         {
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;
73
74                 m_planeData[planeNdx].resize(planeSize);
75         }
76 }
77
78 MultiPlaneImageData::MultiPlaneImageData (const MultiPlaneImageData& other)
79         : m_format              (other.m_format)
80         , m_description (other.m_description)
81         , m_size                (other.m_size)
82 {
83         for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
84                 m_planeData[planeNdx] = other.m_planeData[planeNdx];
85 }
86
87 MultiPlaneImageData::~MultiPlaneImageData (void)
88 {
89 }
90
91 tcu::PixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx)
92 {
93         void*           planePtrs[PlanarFormatDescription::MAX_PLANES];
94         deUint32        planeRowPitches[PlanarFormatDescription::MAX_PLANES];
95
96         for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
97         {
98                 const deUint32  planeW          = m_size.x() / m_description.planes[planeNdx].widthDivisor;
99
100                 planeRowPitches[planeNdx]       = m_description.planes[planeNdx].elementSizeBytes * planeW;
101                 planePtrs[planeNdx]                     = &m_planeData[planeNdx][0];
102         }
103
104         return vk::getChannelAccess(m_description,
105                                                                 m_size,
106                                                                 planeRowPitches,
107                                                                 planePtrs,
108                                                                 channelNdx);
109 }
110
111 tcu::ConstPixelBufferAccess MultiPlaneImageData::getChannelAccess (deUint32 channelNdx) const
112 {
113         const void*     planePtrs[PlanarFormatDescription::MAX_PLANES];
114         deUint32        planeRowPitches[PlanarFormatDescription::MAX_PLANES];
115
116         for (deUint32 planeNdx = 0; planeNdx < m_description.numPlanes; ++planeNdx)
117         {
118                 const deUint32  planeW          = m_size.x() / m_description.planes[planeNdx].widthDivisor;
119
120                 planeRowPitches[planeNdx]       = m_description.planes[planeNdx].elementSizeBytes * planeW;
121                 planePtrs[planeNdx]                     = &m_planeData[planeNdx][0];
122         }
123
124         return vk::getChannelAccess(m_description,
125                                                                 m_size,
126                                                                 planeRowPitches,
127                                                                 planePtrs,
128                                                                 channelNdx);
129 }
130
131 // Misc utilities
132
133 namespace
134 {
135
136 void allocateStagingBuffers (const DeviceInterface&                     vkd,
137                                                          VkDevice                                               device,
138                                                          Allocator&                                             allocator,
139                                                          const MultiPlaneImageData&             imageData,
140                                                          vector<VkBufferSp>*                    buffers,
141                                                          vector<AllocationSp>*                  allocations)
142 {
143         for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
144         {
145                 const VkBufferCreateInfo        bufferInfo      =
146                 {
147                         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
148                         DE_NULL,
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,
153                         0u,
154                         (const deUint32*)DE_NULL,
155                 };
156                 Move<VkBuffer>                          buffer          (createBuffer(vkd, device, &bufferInfo));
157                 MovePtr<Allocation>                     allocation      (allocator.allocate(getBufferMemoryRequirements(vkd, device, *buffer),
158                                                                                                                                         MemoryRequirement::HostVisible|MemoryRequirement::Any));
159
160                 VK_CHECK(vkd.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
161
162                 buffers->push_back(VkBufferSp(new Unique<VkBuffer>(buffer)));
163                 allocations->push_back(AllocationSp(allocation.release()));
164         }
165 }
166
167 void allocateAndWriteStagingBuffers (const DeviceInterface&             vkd,
168                                                                           VkDevice                                              device,
169                                                                           Allocator&                                    allocator,
170                                                                           const MultiPlaneImageData&    imageData,
171                                                                           vector<VkBufferSp>*                   buffers,
172                                                                           vector<AllocationSp>*                 allocations)
173 {
174         allocateStagingBuffers(vkd, device, allocator, imageData, buffers, allocations);
175
176         for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
177         {
178                 deMemcpy((*allocations)[planeNdx]->getHostPtr(), imageData.getPlanePtr(planeNdx), imageData.getPlaneSize(planeNdx));
179                 flushMappedMemoryRange(vkd, device, (*allocations)[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
180         }
181 }
182
183 void readStagingBuffers (MultiPlaneImageData*                   imageData,
184                                                  const DeviceInterface&                 vkd,
185                                                  VkDevice                                               device,
186                                                  const vector<AllocationSp>&    allocations)
187 {
188         for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
189         {
190                 invalidateMappedMemoryRange(vkd, device, allocations[planeNdx]->getMemory(), 0u, VK_WHOLE_SIZE);
191                 deMemcpy(imageData->getPlanePtr(planeNdx), allocations[planeNdx]->getHostPtr(), imageData->getPlaneSize(planeNdx));
192         }
193 }
194
195 } // anonymous
196
197 void checkImageSupport (Context& context, VkFormat format, VkImageCreateFlags createFlags, VkImageTiling tiling)
198 {
199         const bool                                                                                                      disjoint        = (createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0;
200         const VkPhysicalDeviceSamplerYcbcrConversionFeatures            features        = context.getSamplerYCbCrConversionFeatures();
201         vector<string>                                                                                          reqExts;
202
203         if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_sampler_ycbcr_conversion"))
204                 reqExts.push_back("VK_KHR_sampler_ycbcr_conversion");
205
206         if (disjoint)
207         {
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");
212         }
213
214         for (vector<string>::const_iterator extIter = reqExts.begin(); extIter != reqExts.end(); ++extIter)
215         {
216                 if (!isDeviceExtensionSupported(context.getUsedApiVersion(), context.getDeviceExtensions(), *extIter))
217                         TCU_THROW(NotSupportedError, (*extIter + " is not supported").c_str());
218         }
219
220         if (features.samplerYcbcrConversion == VK_FALSE)
221         {
222                 TCU_THROW(NotSupportedError, "samplerYcbcrConversion is not supported");
223         }
224
225         {
226                 const VkFormatProperties        formatProperties        = getPhysicalDeviceFormatProperties(context.getInstanceInterface(),
227                                                                                                                                                                                         context.getPhysicalDevice(),
228                                                                                                                                                                                         format);
229                 const VkFormatFeatureFlags      featureFlags            = tiling == VK_IMAGE_TILING_OPTIMAL
230                                                                                                                 ? formatProperties.optimalTilingFeatures
231                                                                                                                 : formatProperties.linearTilingFeatures;
232
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");
235
236                 if (disjoint && ((featureFlags & VK_FORMAT_FEATURE_DISJOINT_BIT) == 0))
237                         TCU_THROW(NotSupportedError, "Disjoint planes are not supported for format");
238         }
239 }
240
241 void fillRandom (de::Random* randomGen, MultiPlaneImageData* imageData)
242 {
243         // \todo [pyry] Optimize, take into account bits that must be 0
244
245         for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
246         {
247                 const size_t    planeSize       = imageData->getPlaneSize(planeNdx);
248                 deUint8* const  planePtr        = (deUint8*)imageData->getPlanePtr(planeNdx);
249
250                 for (size_t ndx = 0; ndx < planeSize; ++ndx)
251                         planePtr[ndx] = randomGen->getUint8();
252         }
253 }
254
255 void fillGradient (MultiPlaneImageData* imageData, const tcu::Vec4& minVal, const tcu::Vec4& maxVal)
256 {
257         const PlanarFormatDescription&  formatInfo      = imageData->getDescription();
258
259         // \todo [pyry] Optimize: no point in re-rendering source gradient for each channel.
260
261         for (deUint32 channelNdx = 0; channelNdx < 4; channelNdx++)
262         {
263                 if (formatInfo.hasChannelNdx(channelNdx))
264                 {
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();
268
269                         tcu::fillWithComponentGradients(tmpTexture, minVal, maxVal);
270
271                         for (int y = 0; y < channelAccess.getHeight(); ++y)
272                         for (int x = 0; x < channelAccess.getWidth(); ++x)
273                         {
274                                 channelAccess.setPixel(tcu::Vec4(tmpAccess.getPixel(x, y)[channelNdx]), x, y);
275                         }
276                 }
277         }
278 }
279
280 vector<AllocationSp> allocateAndBindImageMemory (const DeviceInterface& vkd,
281                                                                                                  VkDevice                               device,
282                                                                                                  Allocator&                             allocator,
283                                                                                                  VkImage                                image,
284                                                                                                  VkFormat                               format,
285                                                                                                  VkImageCreateFlags             createFlags,
286                                                                                                  vk::MemoryRequirement  requirement)
287 {
288         vector<AllocationSp> allocations;
289
290         if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
291         {
292                 const deUint32  numPlanes       = getPlaneCount(format);
293
294                 for (deUint32 planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
295                 {
296                         const VkImageAspectFlagBits     planeAspect     = getPlaneAspect(planeNdx);
297                         const VkMemoryRequirements      reqs            = getImagePlaneMemoryRequirements(vkd, device, image, planeAspect);
298
299                         allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
300
301                         bindImagePlaneMemory(vkd, device, image, allocations.back()->getMemory(), allocations.back()->getOffset(), planeAspect);
302                 }
303         }
304         else
305         {
306                 const VkMemoryRequirements      reqs    = getImageMemoryRequirements(vkd, device, image);
307
308                 allocations.push_back(AllocationSp(allocator.allocate(reqs, requirement).release()));
309
310                 VK_CHECK(vkd.bindImageMemory(device, image, allocations.back()->getMemory(), allocations.back()->getOffset()));
311         }
312
313         return allocations;
314 }
315
316 void uploadImage (const DeviceInterface&                vkd,
317                                   VkDevice                                              device,
318                                   deUint32                                              queueFamilyNdx,
319                                   Allocator&                                    allocator,
320                                   VkImage                                               image,
321                                   const MultiPlaneImageData&    imageData,
322                                   VkAccessFlags                                 nextAccess,
323                                   VkImageLayout                                 finalLayout)
324 {
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;
330
331         const PlanarFormatDescription&  formatDesc              = imageData.getDescription();
332
333         allocateAndWriteStagingBuffers(vkd, device, allocator, imageData, &stagingBuffers, &stagingMemory);
334
335         {
336                 const VkCommandBufferBeginInfo  beginInfo               =
337                 {
338                         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
339                         DE_NULL,
340                         (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
341                         (const VkCommandBufferInheritanceInfo*)DE_NULL
342                 };
343
344                 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
345         }
346
347         {
348                 const VkImageMemoryBarrier              preCopyBarrier  =
349                 {
350                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
351                         DE_NULL,
352                         (VkAccessFlags)0,
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,
358                         image,
359                         { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
360                 };
361
362                 vkd.cmdPipelineBarrier(*cmdBuffer,
363                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
364                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
365                                                                 (VkDependencyFlags)0u,
366                                                                 0u,
367                                                                 (const VkMemoryBarrier*)DE_NULL,
368                                                                 0u,
369                                                                 (const VkBufferMemoryBarrier*)DE_NULL,
370                                                                 1u,
371                                                                 &preCopyBarrier);
372         }
373
374         for (deUint32 planeNdx = 0; planeNdx < imageData.getDescription().numPlanes; ++planeNdx)
375         {
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    =
386                 {
387                         0u,             // bufferOffset
388                         0u,             // bufferRowLength
389                         0u,             // bufferImageHeight
390                         { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
391                         makeOffset3D(0u, 0u, 0u),
392                         makeExtent3D(planeW, planeH, 1u),
393                 };
394
395                 vkd.cmdCopyBufferToImage(*cmdBuffer, **stagingBuffers[planeNdx], image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &copy);
396         }
397
398         {
399                 const VkImageMemoryBarrier              postCopyBarrier =
400                 {
401                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
402                         DE_NULL,
403                         VK_ACCESS_TRANSFER_WRITE_BIT,
404                         nextAccess,
405                         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
406                         finalLayout,
407                         VK_QUEUE_FAMILY_IGNORED,
408                         VK_QUEUE_FAMILY_IGNORED,
409                         image,
410                         { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
411                 };
412
413                 vkd.cmdPipelineBarrier(*cmdBuffer,
414                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
415                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
416                                                                 (VkDependencyFlags)0u,
417                                                                 0u,
418                                                                 (const VkMemoryBarrier*)DE_NULL,
419                                                                 0u,
420                                                                 (const VkBufferMemoryBarrier*)DE_NULL,
421                                                                 1u,
422                                                                 &postCopyBarrier);
423         }
424
425         VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
426
427         {
428                 const Unique<VkFence>   fence           (createFence(vkd, device));
429                 const VkSubmitInfo              submitInfo      =
430                 {
431                         VK_STRUCTURE_TYPE_SUBMIT_INFO,
432                         DE_NULL,
433                         0u,
434                         (const VkSemaphore*)DE_NULL,
435                         (const VkPipelineStageFlags*)DE_NULL,
436                         1u,
437                         &*cmdBuffer,
438                         0u,
439                         (const VkSemaphore*)DE_NULL,
440                 };
441
442                 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
443                 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
444         }
445 }
446
447 void fillImageMemory (const vk::DeviceInterface&                                                        vkd,
448                                           vk::VkDevice                                                                                  device,
449                                           deUint32                                                                                              queueFamilyNdx,
450                                           vk::VkImage                                                                                   image,
451                                           const std::vector<de::SharedPtr<vk::Allocation> >&    allocations,
452                                           const MultiPlaneImageData&                                                    imageData,
453                                           vk::VkAccessFlags                                                                             nextAccess,
454                                           vk::VkImageLayout                                                                             finalLayout)
455 {
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();
460
461         for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
462         {
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]
468                                                                                                                 : allocations[0];
469                 const size_t                                            planeSize       = imageData.getPlaneSize(planeNdx);
470                 const deUint32                                          planeH          = imageData.getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
471                 const VkImageSubresource                        subresource     =
472                 {
473                         static_cast<vk::VkImageAspectFlags>(aspect),
474                         0u,
475                         0u,
476                 };
477                 VkSubresourceLayout                     layout;
478
479                 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
480
481                 for (deUint32 row = 0; row < planeH; ++row)
482                 {
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;
486
487                         deMemcpy(dstPtr, srcPtr, rowSize);
488                 }
489                 flushMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
490         }
491
492         {
493                 const VkCommandBufferBeginInfo  beginInfo               =
494                 {
495                         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
496                         DE_NULL,
497                         (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
498                         (const VkCommandBufferInheritanceInfo*)DE_NULL
499                 };
500
501                 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
502         }
503
504
505         {
506                 const VkImageMemoryBarrier              postCopyBarrier =
507                 {
508                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
509                         DE_NULL,
510                         0u,
511                         nextAccess,
512                         VK_IMAGE_LAYOUT_PREINITIALIZED,
513                         finalLayout,
514                         VK_QUEUE_FAMILY_IGNORED,
515                         VK_QUEUE_FAMILY_IGNORED,
516                         image,
517                         { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
518                 };
519
520                 vkd.cmdPipelineBarrier(*cmdBuffer,
521                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
522                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
523                                                                 (VkDependencyFlags)0u,
524                                                                 0u,
525                                                                 (const VkMemoryBarrier*)DE_NULL,
526                                                                 0u,
527                                                                 (const VkBufferMemoryBarrier*)DE_NULL,
528                                                                 1u,
529                                                                 &postCopyBarrier);
530         }
531
532         VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
533
534         {
535                 const Unique<VkFence>   fence           (createFence(vkd, device));
536                 const VkSubmitInfo              submitInfo      =
537                 {
538                         VK_STRUCTURE_TYPE_SUBMIT_INFO,
539                         DE_NULL,
540                         0u,
541                         (const VkSemaphore*)DE_NULL,
542                         (const VkPipelineStageFlags*)DE_NULL,
543                         1u,
544                         &*cmdBuffer,
545                         0u,
546                         (const VkSemaphore*)DE_NULL,
547                 };
548
549                 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
550                 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
551         }
552 }
553
554 void downloadImage (const DeviceInterface&      vkd,
555                                         VkDevice                                device,
556                                         deUint32                                queueFamilyNdx,
557                                         Allocator&                              allocator,
558                                         VkImage                                 image,
559                                         MultiPlaneImageData*    imageData,
560                                         VkAccessFlags                   prevAccess,
561                                         VkImageLayout                   initialLayout)
562 {
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;
568
569         const PlanarFormatDescription&  formatDesc              = imageData->getDescription();
570
571         allocateStagingBuffers(vkd, device, allocator, *imageData, &stagingBuffers, &stagingMemory);
572
573         {
574                 const VkCommandBufferBeginInfo  beginInfo               =
575                 {
576                         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
577                         DE_NULL,
578                         (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
579                         (const VkCommandBufferInheritanceInfo*)DE_NULL
580                 };
581
582                 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
583         }
584
585         for (deUint32 planeNdx = 0; planeNdx < imageData->getDescription().numPlanes; ++planeNdx)
586         {
587                 const VkImageAspectFlagBits     aspect  = (formatDesc.numPlanes > 1)
588                                                                                         ? getPlaneAspect(planeNdx)
589                                                                                         : VK_IMAGE_ASPECT_COLOR_BIT;
590                 {
591                         const VkImageMemoryBarrier              preCopyBarrier  =
592                         {
593                                 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
594                                 DE_NULL,
595                                 prevAccess,
596                                 VK_ACCESS_TRANSFER_READ_BIT,
597                                 initialLayout,
598                                 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
599                                 VK_QUEUE_FAMILY_IGNORED,
600                                 VK_QUEUE_FAMILY_IGNORED,
601                                 image,
602                                 {
603                                         static_cast<vk::VkImageAspectFlags>(aspect),
604                                         0u,
605                                         1u,
606                                         0u,
607                                         1u
608                                 }
609                         };
610
611                         vkd.cmdPipelineBarrier(*cmdBuffer,
612                                                                         (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
613                                                                         (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
614                                                                         (VkDependencyFlags)0u,
615                                                                         0u,
616                                                                         (const VkMemoryBarrier*)DE_NULL,
617                                                                         0u,
618                                                                         (const VkBufferMemoryBarrier*)DE_NULL,
619                                                                         1u,
620                                                                         &preCopyBarrier);
621                 }
622                 {
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    =
630                         {
631                                 0u,             // bufferOffset
632                                 0u,             // bufferRowLength
633                                 0u,             // bufferImageHeight
634                                 { (VkImageAspectFlags)aspect, 0u, 0u, 1u },
635                                 makeOffset3D(0u, 0u, 0u),
636                                 makeExtent3D(planeW, planeH, 1u),
637                         };
638
639                         vkd.cmdCopyImageToBuffer(*cmdBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, **stagingBuffers[planeNdx], 1u, &copy);
640                 }
641                 {
642                         const VkBufferMemoryBarrier             postCopyBarrier =
643                         {
644                                 VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
645                                 DE_NULL,
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],
651                                 0u,
652                                 VK_WHOLE_SIZE
653                         };
654
655                         vkd.cmdPipelineBarrier(*cmdBuffer,
656                                                                         (VkPipelineStageFlags)VK_PIPELINE_STAGE_TRANSFER_BIT,
657                                                                         (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
658                                                                         (VkDependencyFlags)0u,
659                                                                         0u,
660                                                                         (const VkMemoryBarrier*)DE_NULL,
661                                                                         1u,
662                                                                         &postCopyBarrier,
663                                                                         0u,
664                                                                         (const VkImageMemoryBarrier*)DE_NULL);
665                 }
666         }
667
668         VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
669
670         {
671                 const Unique<VkFence>   fence           (createFence(vkd, device));
672                 const VkSubmitInfo              submitInfo      =
673                 {
674                         VK_STRUCTURE_TYPE_SUBMIT_INFO,
675                         DE_NULL,
676                         0u,
677                         (const VkSemaphore*)DE_NULL,
678                         (const VkPipelineStageFlags*)DE_NULL,
679                         1u,
680                         &*cmdBuffer,
681                         0u,
682                         (const VkSemaphore*)DE_NULL,
683                 };
684
685                 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
686                 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
687         }
688
689         readStagingBuffers(imageData, vkd, device, stagingMemory);
690 }
691
692 void readImageMemory (const vk::DeviceInterface&                                                        vkd,
693                                           vk::VkDevice                                                                                  device,
694                                           deUint32                                                                                              queueFamilyNdx,
695                                           vk::VkImage                                                                                   image,
696                                           const std::vector<de::SharedPtr<vk::Allocation> >&    allocations,
697                                           MultiPlaneImageData*                                                                  imageData,
698                                           vk::VkAccessFlags                                                                             prevAccess,
699                                           vk::VkImageLayout                                                                             initialLayout)
700 {
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();
705
706         {
707                 const VkCommandBufferBeginInfo  beginInfo               =
708                 {
709                         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
710                         DE_NULL,
711                         (VkCommandBufferUsageFlags)VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
712                         (const VkCommandBufferInheritanceInfo*)DE_NULL
713                 };
714
715                 VK_CHECK(vkd.beginCommandBuffer(*cmdBuffer, &beginInfo));
716         }
717
718         {
719                 const VkImageMemoryBarrier              preCopyBarrier  =
720                 {
721                         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
722                         DE_NULL,
723                         prevAccess,
724                         vk::VK_ACCESS_HOST_READ_BIT,
725                         initialLayout,
726                         VK_IMAGE_LAYOUT_GENERAL,
727                         VK_QUEUE_FAMILY_IGNORED,
728                         VK_QUEUE_FAMILY_IGNORED,
729                         image,
730                         { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u }
731                 };
732
733                 vkd.cmdPipelineBarrier(*cmdBuffer,
734                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
735                                                                 (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
736                                                                 (VkDependencyFlags)0u,
737                                                                 0u,
738                                                                 (const VkMemoryBarrier*)DE_NULL,
739                                                                 0u,
740                                                                 (const VkBufferMemoryBarrier*)DE_NULL,
741                                                                 1u,
742                                                                 &preCopyBarrier);
743         }
744
745         VK_CHECK(vkd.endCommandBuffer(*cmdBuffer));
746
747         {
748                 const Unique<VkFence>   fence           (createFence(vkd, device));
749                 const VkSubmitInfo              submitInfo      =
750                 {
751                         VK_STRUCTURE_TYPE_SUBMIT_INFO,
752                         DE_NULL,
753                         0u,
754                         (const VkSemaphore*)DE_NULL,
755                         (const VkPipelineStageFlags*)DE_NULL,
756                         1u,
757                         &*cmdBuffer,
758                         0u,
759                         (const VkSemaphore*)DE_NULL,
760                 };
761
762                 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, *fence));
763                 VK_CHECK(vkd.waitForFences(device, 1u, &*fence, VK_TRUE, ~0ull));
764         }
765
766         for (deUint32 planeNdx = 0; planeNdx < formatDesc.numPlanes; ++planeNdx)
767         {
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]
773                                                                                                                 : allocations[0];
774                 const size_t                                            planeSize       = imageData->getPlaneSize(planeNdx);
775                 const deUint32                                          planeH          = imageData->getSize().y() / formatDesc.planes[planeNdx].heightDivisor;
776                 const VkImageSubresource                        subresource     =
777                 {
778                         static_cast<vk::VkImageAspectFlags>(aspect),
779                         0u,
780                         0u,
781                 };
782                 VkSubresourceLayout                     layout;
783
784                 vkd.getImageSubresourceLayout(device, image, &subresource, &layout);
785
786                 invalidateMappedMemoryRange(vkd, device, allocation->getMemory(), 0u, VK_WHOLE_SIZE);
787
788                 for (deUint32 row = 0; row < planeH; ++row)
789                 {
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;
793
794                         deMemcpy(dstPtr, srcPtr, rowSize);
795                 }
796         }
797 }
798
799 // ChannelAccess utilities
800 namespace
801 {
802
803 //! Extend < 32b signed integer to 32b
804 inline deInt32 signExtend (deUint32 src, int bits)
805 {
806         const deUint32 signBit = 1u << (bits-1);
807
808         src |= ~((src & signBit) - 1);
809
810         return (deInt32)src;
811 }
812
813 deUint32 divRoundUp (deUint32 a, deUint32 b)
814 {
815         if (a % b == 0)
816                 return a / b;
817         else
818                 return (a / b) + 1;
819 }
820
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)
825 {
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));
829
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);
834
835         // Rounding.
836         if (q == 0.5f)
837         {
838                 if (intVal % 2 != 0)
839                         intVal++;
840         }
841         else if (q > 0.5f)
842                 intVal++;
843         // else Don't add anything
844
845         // Saturate.
846         intVal = de::max(minVal, de::min(maxVal, intVal));
847
848         return (T)intVal;
849 }
850
851 } // anonymous
852
853 ChannelAccess::ChannelAccess (tcu::TextureChannelClass  channelClass,
854                                                           deUint8                                       channelSize,
855                                                           const tcu::IVec3&                     size,
856                                                           const tcu::IVec3&                     bitPitch,
857                                                           void*                                         data,
858                                                           deUint32                                      bitOffset)
859         : m_channelClass        (channelClass)
860         , m_channelSize         (channelSize)
861         , m_size                        (size)
862         , m_bitPitch            (bitPitch)
863
864         , m_data                        ((deUint8*)data + (bitOffset / 8))
865         , m_bitOffset           (bitOffset % 8)
866 {
867 }
868
869 deUint32 ChannelAccess::getChannelUint (const tcu::IVec3& pos) const
870 {
871         DE_ASSERT(pos[0] < m_size[0]);
872         DE_ASSERT(pos[1] < m_size[1]);
873         DE_ASSERT(pos[2] < m_size[2]);
874
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;
880         deUint32                                bits            = 0u;
881
882         deMemcpy(&bits, firstByte, byteCount);
883
884         return (bits >> offset) & mask;
885 }
886
887 void ChannelAccess::setChannel (const tcu::IVec3& pos, deUint32 x)
888 {
889         DE_ASSERT(pos[0] < m_size[0]);
890         DE_ASSERT(pos[1] < m_size[1]);
891         DE_ASSERT(pos[2] < m_size[2]);
892
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;
898
899         const deUint32  bits            = (x & mask) << offset;
900         deUint32                oldBits         = 0;
901
902         deMemcpy(&oldBits, firstByte, byteCount);
903
904         {
905                 const deUint32  newBits = bits | (oldBits & (~(mask << offset)));
906
907                 deMemcpy(firstByte, &newBits,  byteCount);
908         }
909 }
910
911 float ChannelAccess::getChannel (const tcu::IVec3& pos) const
912 {
913         const deUint32  bits    (getChannelUint(pos));
914
915         switch (m_channelClass)
916         {
917                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
918                         return (float)bits / (float)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u));
919
920                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
921                         return (float)bits;
922
923                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
924                         return de::max(-1.0f, (float)signExtend(bits, m_channelSize) / (float)((0x1u << (m_channelSize - 1u)) - 1u));
925
926                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
927                         return (float)signExtend(bits, m_channelSize);
928
929                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
930                         if (m_channelSize == 32)
931                                 return tcu::Float32(bits).asFloat();
932                         else
933                         {
934                                 DE_FATAL("Float type not supported");
935                                 return -1.0f;
936                         }
937
938                 default:
939                         DE_FATAL("Unknown texture channel class");
940                         return -1.0f;
941         }
942 }
943
944 tcu::Interval ChannelAccess::getChannel (const tcu::FloatFormat&        conversionFormat,
945                                                                                  const tcu::IVec3&                      pos) const
946 {
947         const deUint32  bits    (getChannelUint(pos));
948
949         switch (m_channelClass)
950         {
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);
954
955                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
956                         return conversionFormat.roundOut((double)bits, false);
957
958                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
959                 {
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));
962
963                         return tcu::Interval(de::max(-1.0, result.lo()), de::max(-1.0, result.hi()));
964                 }
965
966                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
967                         return conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false);
968
969                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
970                         if (m_channelSize == 32)
971                                 return conversionFormat.roundOut(tcu::Float32(bits).asFloat(), false);
972                         else
973                         {
974                                 DE_FATAL("Float type not supported");
975                                 return tcu::Interval();
976                         }
977
978                 default:
979                         DE_FATAL("Unknown texture channel class");
980                         return tcu::Interval();
981         }
982 }
983
984 void ChannelAccess::setChannel (const tcu::IVec3& pos, float x)
985 {
986         DE_ASSERT(pos[0] < m_size[0]);
987         DE_ASSERT(pos[1] < m_size[1]);
988         DE_ASSERT(pos[2] < m_size[2]);
989
990         const deUint32  mask    (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
991
992         switch (m_channelClass)
993         {
994                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
995                 {
996                         const deUint32  maxValue        (mask);
997                         const deUint32  value           (de::min(maxValue, (deUint32)convertSatRte<deUint32>(x * (float)maxValue)));
998                         setChannel(pos, value);
999                         break;
1000                 }
1001
1002                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
1003                 {
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);
1007                         break;
1008                 }
1009
1010                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
1011                 {
1012                         const deUint32  maxValue        (mask);
1013                         const deUint32  value           (de::min(maxValue, (deUint32)x));
1014                         setChannel(pos, value);
1015                         break;
1016                 }
1017
1018                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
1019                 {
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);
1024                         break;
1025                 }
1026
1027                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
1028                 {
1029                         if (m_channelSize == 32)
1030                         {
1031                                 const deUint32  value           = tcu::Float32(x).bits();
1032                                 setChannel(pos, value);
1033                         }
1034                         else
1035                                 DE_FATAL("Float type not supported");
1036                         break;
1037                 }
1038
1039                 default:
1040                         DE_FATAL("Unknown texture channel class");
1041         }
1042 }
1043
1044 ChannelAccess getChannelAccess (MultiPlaneImageData&                            data,
1045                                                                 const vk::PlanarFormatDescription&      formatInfo,
1046                                                                 const UVec2&                                            size,
1047                                                                 int                                                                     channelNdx)
1048 {
1049         DE_ASSERT(formatInfo.hasChannelNdx(channelNdx));
1050
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;
1056
1057         DE_ASSERT(size.x() % formatInfo.planes[planeNdx].widthDivisor == 0);
1058         DE_ASSERT(size.y() % formatInfo.planes[planeNdx].heightDivisor == 0);
1059
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;
1063
1064         const deUint32  rowPitch                        = formatInfo.planes[planeNdx].elementSizeBytes * accessWidth;
1065         const deUint32  rowPitchBits            = rowPitch * 8;
1066
1067         if (pixelStrideBytes != elementSizeBytes)
1068         {
1069                 DE_ASSERT(elementSizeBytes % pixelStrideBytes == 0);
1070                 accessWidth *= elementSizeBytes/pixelStrideBytes;
1071         }
1072
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);
1074 }
1075
1076 bool isXChromaSubsampled (vk::VkFormat format)
1077 {
1078         switch (format)
1079         {
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:
1104                         return true;
1105
1106                 default:
1107                         return false;
1108         }
1109 }
1110
1111 bool isYChromaSubsampled (vk::VkFormat format)
1112 {
1113         switch (format)
1114         {
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:
1123                         return true;
1124
1125                 default:
1126                         return false;
1127         }
1128 }
1129
1130 // \note Used for range expansion
1131 tcu::UVec4 getYCbCrBitDepth (vk::VkFormat format)
1132 {
1133         switch (format)
1134         {
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);
1143
1144                 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1145                         return tcu::UVec4(10, 0, 0, 0);
1146
1147                 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1148                         return tcu::UVec4(10, 10, 0, 0);
1149
1150                 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1151                         return tcu::UVec4(10, 10, 10, 10);
1152
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);
1161
1162                 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1163                         return tcu::UVec4(12, 0, 0, 0);
1164
1165                 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1166                         return tcu::UVec4(12, 12, 0, 0);
1167
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);
1177
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);
1186
1187                 default:
1188                         return tcu::getTextureFormatBitDepth(vk::mapVkFormat(format)).cast<deUint32>();
1189         }
1190 }
1191
1192 // \note Taken from explicit lod filtering tests
1193 tcu::FloatFormat getYCbCrFilteringPrecision (vk::VkFormat format)
1194 {
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);
1199
1200         switch (format)
1201         {
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:
1209                         return reallyLow;
1210
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:
1223                         return low;
1224
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:
1256                         return fp16;
1257
1258                 default:
1259                         DE_FATAL("Precision not defined for format");
1260                         return fp32;
1261         }
1262 }
1263
1264 // \note Taken from explicit lod filtering tests
1265 tcu::FloatFormat getYCbCrConversionPrecision (vk::VkFormat format)
1266 {
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);
1270
1271         switch (format)
1272         {
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:
1280                         return reallyLow;
1281
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:
1294                         return reallyLow;
1295
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:
1327                         return fp16;
1328
1329                 default:
1330                         DE_FATAL("Precision not defined for format");
1331                         return fp32;
1332         }
1333 }
1334
1335 deUint32 getYCbCrFormatChannelCount (vk::VkFormat format)
1336 {
1337         switch (format)
1338         {
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:
1352                         return 4;
1353
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:
1387                         return 3;
1388
1389                 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
1390                 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
1391                         return 2;
1392
1393                 case vk::VK_FORMAT_R10X6_UNORM_PACK16:
1394                 case vk::VK_FORMAT_R12X4_UNORM_PACK16:
1395                         return 1;
1396
1397                 default:
1398                         DE_FATAL("Unknown number of channels");
1399                         return -1;
1400         }
1401 }
1402
1403 // YCbCr color conversion utilities
1404 namespace
1405 {
1406
1407 tcu::Interval rangeExpandChroma (vk::VkSamplerYcbcrRange                range,
1408                                                                  const tcu::FloatFormat&                conversionFormat,
1409                                                                  const deUint32                                 bits,
1410                                                                  const tcu::Interval&                   sample)
1411 {
1412         const deUint32  values  (0x1u << bits);
1413
1414         switch (range)
1415         {
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);
1418
1419                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1420                 {
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));
1425
1426                         return result;
1427                 }
1428
1429                 default:
1430                         DE_FATAL("Unknown YCbCrRange");
1431                         return tcu::Interval();
1432         }
1433 }
1434
1435 tcu::Interval rangeExpandLuma (vk::VkSamplerYcbcrRange          range,
1436                                                            const tcu::FloatFormat&              conversionFormat,
1437                                                            const deUint32                               bits,
1438                                                            const tcu::Interval&                 sample)
1439 {
1440         const deUint32  values  (0x1u << bits);
1441
1442         switch (range)
1443         {
1444                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL:
1445                         return conversionFormat.roundOut(sample, false);
1446
1447                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW:
1448                 {
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));
1453
1454                         return result;
1455                 }
1456
1457                 default:
1458                         DE_FATAL("Unknown YCbCrRange");
1459                         return tcu::Interval();
1460         }
1461 }
1462
1463 tcu::Interval clampMaybe (const tcu::Interval&  x,
1464                                                   double                                min,
1465                                                   double                                max)
1466 {
1467         tcu::Interval result = x;
1468
1469         DE_ASSERT(min <= max);
1470
1471         if (x.lo() < min)
1472                 result = result | tcu::Interval(min);
1473
1474         if (x.hi() > max)
1475                 result = result | tcu::Interval(max);
1476
1477         return result;
1478 }
1479
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])
1486 {
1487         switch (colorModel)
1488         {
1489                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY:
1490                 {
1491                         for (size_t ndx = 0; ndx < 4; ndx++)
1492                                 output[ndx] = input[ndx];
1493                         break;
1494                 }
1495
1496                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY:
1497                 {
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];
1502                         break;
1503                 }
1504
1505                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601:
1506                 {
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]));
1510
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));
1514
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];
1519                         break;
1520                 }
1521
1522                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709:
1523                 {
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]));
1527
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));
1531
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];
1536                         break;
1537                 }
1538
1539                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020:
1540                 {
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]));
1544
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));
1548
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];
1553                         break;
1554                 }
1555
1556                 default:
1557                         DE_FATAL("Unknown YCbCrModel");
1558         }
1559
1560         if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY)
1561         {
1562                 for (int ndx = 0; ndx < 3; ndx++)
1563                         output[ndx] = clampMaybe(output[ndx], 0.0, 1.0);
1564         }
1565 }
1566
1567 int mirror (int coord)
1568 {
1569         return coord >= 0 ? coord : -(1 + coord);
1570 }
1571
1572 int imod (int a, int b)
1573 {
1574         int m = a % b;
1575         return m < 0 ? m + b : m;
1576 }
1577
1578 tcu::Interval frac (const tcu::Interval& x)
1579 {
1580         if (x.hi() - x.lo() >= 1.0)
1581                 return tcu::Interval(0.0, 1.0);
1582         else
1583         {
1584                 const tcu::Interval ret (deFrac(x.lo()), deFrac(x.hi()));
1585
1586                 return ret;
1587         }
1588 }
1589
1590 tcu::Interval calculateUV (const tcu::FloatFormat&      coordFormat,
1591                                                    const tcu::Interval&         st,
1592                                                    const int                            size)
1593 {
1594         return coordFormat.roundOut(coordFormat.roundOut(st, false) * tcu::Interval((double)size), false);
1595 }
1596
1597 tcu::IVec2 calculateNearestIJRange (const tcu::FloatFormat&     coordFormat,
1598                                                                     const tcu::Interval&        uv)
1599 {
1600         const tcu::Interval     ij      (coordFormat.roundOut(coordFormat.roundOut(uv, false) - tcu::Interval(0.5), false));
1601
1602         return tcu::IVec2(deRoundToInt32(ij.lo() - coordFormat.ulp(ij.lo(), 1)), deRoundToInt32(ij.hi() + coordFormat.ulp(ij.hi(), 1)));
1603 }
1604
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)
1608 {
1609         const tcu::Interval     ij      (coordFormat.roundOut(uv - tcu::Interval(0.5), false));
1610
1611         return tcu::IVec2(deFloorToInt32(ij.lo()), deFloorToInt32(ij.hi()));
1612 }
1613
1614 tcu::Interval calculateAB (const deUint32               subTexelPrecisionBits,
1615                                                    const tcu::Interval& uv,
1616                                                    int                                  ij)
1617 {
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));
1622
1623         return rounded;
1624 }
1625
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)
1631 {
1632         return access.getChannel(conversionFormat,
1633                                                          tcu::IVec3(wrap(addressModeU, coord.x(), access.getSize().x()), wrap(addressModeV, coord.y(), access.getSize().y()), 0));
1634 }
1635
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)
1643 {
1644         const tcu::Interval     p[4] =
1645         {
1646                 p00,
1647                 p10,
1648                 p01,
1649                 p11
1650         };
1651         tcu::Interval           result  (0.0);
1652
1653         for (size_t ndx = 0; ndx < 4; ndx++)
1654         {
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));
1658
1659                 result = filteringFormat.roundOut(result + filteringFormat.roundOut(p[ndx] * weight, false), false);
1660         }
1661
1662         return result;
1663 }
1664
1665 tcu::Interval calculateImplicitChromaUV (const tcu::FloatFormat&        coordFormat,
1666                                                                                  vk::VkChromaLocation           offset,
1667                                                                                  const tcu::Interval&           uv)
1668 {
1669         if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1670                 return coordFormat.roundOut(0.5 * coordFormat.roundOut(uv + 0.5, false), false);
1671         else
1672                 return coordFormat.roundOut(0.5 * uv, false);
1673 }
1674
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)
1683 {
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)));
1689 }
1690
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,
1697                                                                                           int                                           i,
1698                                                                                           int                                           j)
1699 {
1700         const int subI  = divFloor(i, 2);
1701
1702         if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN)
1703         {
1704                 if (i % 2 == 0)
1705                         return lookupWrapped(access, conversionFormat, addressModeU, addressModeV, tcu::IVec2(subI, j));
1706                 else
1707                 {
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));
1710
1711                         return filteringFormat.roundOut(a + b, false);
1712                 }
1713         }
1714         else if (offset == vk::VK_CHROMA_LOCATION_MIDPOINT)
1715         {
1716                 if (i % 2 == 0)
1717                 {
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));
1720
1721                         return filteringFormat.roundOut(a + b, false);
1722                 }
1723                 else
1724                 {
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));
1727
1728                         return filteringFormat.roundOut(a + b, false);
1729                 }
1730         }
1731         else
1732         {
1733                 DE_FATAL("Unknown sample location");
1734                 return tcu::Interval();
1735         }
1736 }
1737
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,
1745                                                                                   int                                                   i,
1746                                                                                   int                                                   j)
1747 {
1748         const int               subI    = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1749                                                         ? divFloor(i, 2)
1750                                                         : (i % 2 == 0 ? divFloor(i, 2) - 1 : divFloor(i, 2));
1751         const int               subJ    = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN
1752                                                         ? divFloor(j, 2)
1753                                                         : (j % 2 == 0 ? divFloor(j, 2) - 1 : divFloor(j, 2));
1754
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);
1761
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)));
1767 }
1768
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)
1775 {
1776         switch (swizzle)
1777         {
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;
1783
1784                 default:
1785                         DE_FATAL("Unsupported swizzle");
1786                         return identityPlane;
1787         }
1788 }
1789
1790 } // anonymous
1791
1792 int wrap (vk::VkSamplerAddressMode      addressMode,
1793                   int                                           coord,
1794                   int                                           size)
1795 {
1796         switch (addressMode)
1797         {
1798                 case vk::VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
1799                         return (size - 1) - mirror(imod(coord, 2 * size) - size);
1800
1801                 case vk::VK_SAMPLER_ADDRESS_MODE_REPEAT:
1802                         return imod(coord, size);
1803
1804                 case vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
1805                         return de::clamp(coord, 0, size - 1);
1806
1807                 case vk::VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
1808                         return de::clamp(mirror(coord), 0, size - 1);
1809
1810                 default:
1811                         DE_FATAL("Unknown wrap mode");
1812                         return ~0;
1813         }
1814 }
1815
1816 int divFloor (int a, int b)
1817 {
1818         if (a % b == 0)
1819                 return a / b;
1820         else if (a > 0)
1821                 return a / b;
1822         else
1823                 return (a / b) - 1;
1824 }
1825
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)
1849 {
1850         const FloatFormat               highp                   (-126, 127, 23, true,
1851                                                                                          tcu::MAYBE,    // subnormals
1852                                                                                          tcu::YES,              // infinities
1853                                                                                          tcu::MAYBE);   // NaN
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));
1859
1860         const bool                              subsampledX             = gAccess.getSize().x() > rAccess.getSize().x();
1861         const bool                              subsampledY             = gAccess.getSize().y() > rAccess.getSize().y();
1862
1863         minBounds.resize(sts.size(), Vec4(TCU_INFINITY));
1864         maxBounds.resize(sts.size(), Vec4(-TCU_INFINITY));
1865
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));
1868
1869         // Chroma plane sizes must match
1870         DE_ASSERT(rAccess.getSize() == bAccess.getSize());
1871
1872         // Luma plane sizes must match
1873         DE_ASSERT(gAccess.getSize() == aAccess.getSize());
1874
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());
1878
1879         for (size_t ndx = 0; ndx < sts.size(); ndx++)
1880         {
1881                 const Vec2      st              (sts[ndx]);
1882                 Interval        bounds[4];
1883
1884                 const Interval  u       (calculateUV(coordFormat, st[0], gAccess.getSize().x()));
1885                 const Interval  v       (calculateUV(coordFormat, st[1], gAccess.getSize().y()));
1886
1887                 uvBounds[ndx][0] = (float)u.lo();
1888                 uvBounds[ndx][1] = (float)u.hi();
1889
1890                 uvBounds[ndx][2] = (float)v.lo();
1891                 uvBounds[ndx][3] = (float)v.hi();
1892
1893                 if (filter == vk::VK_FILTER_NEAREST)
1894                 {
1895                         const IVec2     iRange  (calculateNearestIJRange(coordFormat, u));
1896                         const IVec2     jRange  (calculateNearestIJRange(coordFormat, v));
1897
1898                         ijBounds[ndx][0] = iRange[0];
1899                         ijBounds[ndx][1] = iRange[1];
1900
1901                         ijBounds[ndx][2] = jRange[0];
1902                         ijBounds[ndx][3] = jRange[1];
1903
1904                         for (int j = jRange.x(); j <= jRange.y(); j++)
1905                         for (int i = iRange.x(); i <= iRange.y(); i++)
1906                         {
1907                                 const Interval  gValue  (lookupWrapped(gAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1908                                 const Interval  aValue  (lookupWrapped(aAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1909
1910                                 if (subsampledX || subsampledY)
1911                                 {
1912                                         if (explicitReconstruction)
1913                                         {
1914                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
1915                                                 {
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[]      =
1920                                                         {
1921                                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1922                                                                 gValue,
1923                                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1924                                                                 aValue
1925                                                         };
1926                                                         Interval                dstColor[4];
1927
1928                                                         convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1929
1930                                                         for (size_t compNdx = 0; compNdx < 4; compNdx++)
1931                                                                 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1932                                                 }
1933                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1934                                                 {
1935                                                         if (subsampledX && subsampledY)
1936                                                         {
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[]      =
1941                                                                 {
1942                                                                         rValue,
1943                                                                         gValue,
1944                                                                         bValue,
1945                                                                         aValue
1946                                                                 };
1947                                                                 Interval                dstColor[4];
1948
1949                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1950
1951                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1952                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1953                                                         }
1954                                                         else if (subsampledX)
1955                                                         {
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[]      =
1960                                                                 {
1961                                                                         rValue,
1962                                                                         gValue,
1963                                                                         bValue,
1964                                                                         aValue
1965                                                                 };
1966                                                                 Interval                dstColor[4];
1967
1968                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1969
1970                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1971                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1972                                                         }
1973                                                         else
1974                                                                 DE_FATAL("Unexpected chroma reconstruction");
1975                                                 }
1976                                                 else
1977                                                         DE_FATAL("Unknown filter");
1978                                         }
1979                                         else
1980                                         {
1981                                                 const Interval  chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
1982                                                 const Interval  chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
1983
1984                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
1985                                                 {
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));
1989
1990                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1991                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
1992                                                         {
1993                                                                 const Interval  srcColor[]      =
1994                                                                 {
1995                                                                         lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1996                                                                         gValue,
1997                                                                         lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1998                                                                         aValue
1999                                                                 };
2000                                                                 Interval                dstColor[4];
2001
2002                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2003
2004                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2005                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2006                                                         }
2007                                                 }
2008                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2009                                                 {
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));
2013
2014                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2015                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2016                                                         {
2017                                                                 const Interval  chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
2018                                                                 const Interval  chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
2019
2020                                                                 const Interval  srcColor[]      =
2021                                                                 {
2022                                                                         linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
2023                                                                         gValue,
2024                                                                         linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
2025                                                                         aValue
2026                                                                 };
2027                                                                 Interval                dstColor[4];
2028
2029                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2030
2031                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2032                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2033                                                         }
2034                                                 }
2035                                                 else
2036                                                         DE_FATAL("Unknown filter");
2037                                         }
2038                                 }
2039                                 else
2040                                 {
2041                                         // Linear, no chroma subsampling
2042                                         const Interval  srcColor[]      =
2043                                         {
2044                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
2045                                                 gValue,
2046                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
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                         }
2057                 }
2058                 else if (filter == vk::VK_FILTER_LINEAR)
2059                 {
2060                         const IVec2     iRange  (calculateLinearIJRange(coordFormat, u));
2061                         const IVec2     jRange  (calculateLinearIJRange(coordFormat, v));
2062
2063                         ijBounds[ndx][0] = iRange[0];
2064                         ijBounds[ndx][1] = iRange[1];
2065
2066                         ijBounds[ndx][2] = jRange[0];
2067                         ijBounds[ndx][3] = jRange[1];
2068
2069                         for (int j = jRange.x(); j <= jRange.y(); j++)
2070                         for (int i = iRange.x(); i <= iRange.y(); i++)
2071                         {
2072                                 const Interval  lumaA           (calculateAB(subTexelPrecisionBits, u, i));
2073                                 const Interval  lumaB           (calculateAB(subTexelPrecisionBits, v, j));
2074
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));
2077
2078                                 if (subsampledX || subsampledY)
2079                                 {
2080                                         if (explicitReconstruction)
2081                                         {
2082                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
2083                                                 {
2084                                                         const Interval  srcColor[]      =
2085                                                         {
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)))),
2091                                                                 gValue,
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)))),
2097                                                                 aValue
2098                                                         };
2099                                                         Interval                dstColor[4];
2100
2101                                                         convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2102
2103                                                         for (size_t compNdx = 0; compNdx < 4; compNdx++)
2104                                                                 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2105                                                 }
2106                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2107                                                 {
2108                                                         if (subsampledX && subsampledY)
2109                                                         {
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[]      =
2122                                                                 {
2123                                                                         rValue,
2124                                                                         gValue,
2125                                                                         bValue,
2126                                                                         aValue
2127                                                                 };
2128                                                                 Interval                dstColor[4];
2129
2130                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2131
2132                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2133                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2134
2135                                                         }
2136                                                         else if (subsampledX)
2137                                                         {
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[]      =
2150                                                                 {
2151                                                                         rValue,
2152                                                                         gValue,
2153                                                                         bValue,
2154                                                                         aValue
2155                                                                 };
2156                                                                 Interval                dstColor[4];
2157
2158                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2159
2160                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2161                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2162                                                         }
2163                                                         else
2164                                                                 DE_FATAL("Unknown subsampling config");
2165                                                 }
2166                                                 else
2167                                                         DE_FATAL("Unknown chroma filter");
2168                                         }
2169                                         else
2170                                         {
2171                                                 const Interval  chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
2172                                                 const Interval  chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
2173
2174                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
2175                                                 {
2176                                                         const IVec2     chromaIRange    (calculateNearestIJRange(coordFormat, chromaU));
2177                                                         const IVec2     chromaJRange    (calculateNearestIJRange(coordFormat, chromaV));
2178
2179                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2180                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2181                                                         {
2182                                                                 const Interval  srcColor[]      =
2183                                                                 {
2184                                                                         lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2185                                                                         gValue,
2186                                                                         lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
2187                                                                         aValue
2188                                                                 };
2189                                                                 Interval        dstColor[4];
2190
2191                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2192
2193                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2194                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2195                                                         }
2196                                                 }
2197                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
2198                                                 {
2199                                                         const IVec2     chromaIRange    (calculateNearestIJRange(coordFormat, chromaU));
2200                                                         const IVec2     chromaJRange    (calculateNearestIJRange(coordFormat, chromaV));
2201
2202                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
2203                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.y(); chromaI++)
2204                                                         {
2205                                                                 const Interval  chromaA         (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
2206                                                                 const Interval  chromaB         (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
2207
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));
2210
2211                                                                 const Interval  srcColor[]      =
2212                                                                 {
2213                                                                         rValue,
2214                                                                         gValue,
2215                                                                         bValue,
2216                                                                         aValue
2217                                                                 };
2218                                                                 Interval                dstColor[4];
2219                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2220
2221                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
2222                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2223                                                         }
2224                                                 }
2225                                                 else
2226                                                         DE_FATAL("Unknown chroma filter");
2227                                         }
2228                                 }
2229                                 else
2230                                 {
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[]      =
2236                                         {
2237                                                 rValue,
2238                                                 gValue,
2239                                                 bValue,
2240                                                 aValue
2241                                         };
2242                                         Interval dstColor[4];
2243
2244                                         convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
2245
2246                                         for (size_t compNdx = 0; compNdx < 4; compNdx++)
2247                                                 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
2248                                 }
2249                         }
2250                 }
2251                 else
2252                         DE_FATAL("Unknown filter");
2253
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());
2256         }
2257 }
2258
2259
2260 } // ycbcr
2261 } // vkt