d5bee20e8edf62ffe5196e14ecb4b3233e8fd5bc
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / ycbcr / vktYCbCrConversionTests.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 Texture color conversion tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktYCbCrConversionTests.hpp"
25
26 #include "vktShaderExecutor.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktYCbCrUtil.hpp"
30
31 #include "vkImageUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkPrograms.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkQueryUtil.hpp"
37
38 #include "tcuInterval.hpp"
39 #include "tcuTestLog.hpp"
40 #include "tcuTexture.hpp"
41 #include "tcuTextureUtil.hpp"
42 #include "tcuVector.hpp"
43 #include "tcuVectorUtil.hpp"
44 #include "tcuFloatFormat.hpp"
45 #include "tcuFloat.hpp"
46
47 #include "deRandom.hpp"
48 #include "deSTLUtil.hpp"
49 #include "deSharedPtr.hpp"
50
51 #include "deMath.h"
52 #include "deFloat16.h"
53
54 #include <vector>
55 #include <iomanip>
56
57 // \todo When defined color conversion extension is not used and conversion is performed in the shader
58 // #define FAKE_COLOR_CONVERSION
59
60 using tcu::Vec2;
61 using tcu::Vec4;
62
63 using tcu::UVec2;
64 using tcu::UVec3;
65 using tcu::UVec4;
66
67 using tcu::IVec2;
68 using tcu::IVec3;
69 using tcu::IVec4;
70
71 using tcu::TestLog;
72 using tcu::Interval;
73 using tcu::FloatFormat;
74
75 using std::vector;
76 using std::string;
77
78 using namespace vkt::shaderexecutor;
79
80 namespace vkt
81 {
82 namespace ycbcr
83 {
84 namespace
85 {
86 typedef de::SharedPtr<vk::Unique<vk::VkBuffer> > VkBufferSp;
87 typedef de::SharedPtr<vk::Allocation> AllocationSp;
88
89 // \note Used for range expansion
90 UVec4 getBitDepth (vk::VkFormat format)
91 {
92         switch (format)
93         {
94                 case vk::VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
95                 case vk::VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
96                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
97                 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
98                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
99                 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
100                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
101                         return UVec4(8, 8, 8, 0);
102
103                 case vk::VK_FORMAT_R10X6_UNORM_PACK16_KHR:
104                         return UVec4(10, 0, 0, 0);
105
106                 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
107                         return UVec4(10, 10, 0, 0);
108
109                 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
110                         return UVec4(10, 10, 10, 10);
111
112                 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
113                 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
114                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
115                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
116                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
117                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
118                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
119                         return UVec4(10, 10, 10, 0);
120
121                 case vk::VK_FORMAT_R12X4_UNORM_PACK16_KHR:
122                         return UVec4(12, 0, 0, 0);
123
124                 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
125                         return UVec4(12, 12, 0, 0);
126
127                 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
128                 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
129                 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
130                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
131                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
132                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
133                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
134                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
135                         return UVec4(12, 12, 12, 12);
136
137                 case vk::VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
138                 case vk::VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
139                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
140                 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
141                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
142                 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
143                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
144                         return UVec4(16, 16, 16, 0);
145
146                 default:
147                         return tcu::getTextureFormatBitDepth(vk::mapVkFormat(format)).cast<deUint32>();
148         }
149 }
150
151 // \note Taken from explicit lod filtering tests
152 FloatFormat getFilteringPrecision (vk::VkFormat format)
153 {
154         const FloatFormat       reallyLow       (0, 0, 6, false, tcu::YES);
155         const FloatFormat       low                     (0, 0, 7, false, tcu::YES);
156         const FloatFormat       fp16            (-14, 15, 10, false);
157         const FloatFormat       fp32            (-126, 127, 23, true);
158
159         switch (format)
160         {
161                 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
162                 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
163                 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
164                 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
165                 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
166                 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
167                 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
168                         return reallyLow;
169
170                 case vk::VK_FORMAT_R8G8B8_UNORM:
171                 case vk::VK_FORMAT_B8G8R8_UNORM:
172                 case vk::VK_FORMAT_R8G8B8A8_UNORM:
173                 case vk::VK_FORMAT_B8G8R8A8_UNORM:
174                 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
175                 case vk::VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
176                 case vk::VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
177                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
178                 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
179                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
180                 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
181                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
182                         return low;
183
184                 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
185                 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
186                 case vk::VK_FORMAT_R16G16B16_UNORM:
187                 case vk::VK_FORMAT_R16G16B16A16_UNORM:
188                 case vk::VK_FORMAT_R10X6_UNORM_PACK16_KHR:
189                 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
190                 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
191                 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
192                 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
193                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
194                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
195                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
196                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
197                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
198                 case vk::VK_FORMAT_R12X4_UNORM_PACK16_KHR:
199                 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
200                 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
201                 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
202                 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
203                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
204                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
205                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
206                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
207                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
208                 case vk::VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
209                 case vk::VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
210                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
211                 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
212                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
213                 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
214                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
215                         return fp16;
216
217                 default:
218                         DE_FATAL("Precision not defined for format");
219                         return fp32;
220         }
221 }
222
223 // \note Taken from explicit lod filtering tests
224 FloatFormat getConversionPrecision (vk::VkFormat format)
225 {
226         const FloatFormat       reallyLow       (0, 0, 8, false, tcu::YES);
227         const FloatFormat       fp16            (-14, 15, 10, false);
228         const FloatFormat       fp32            (-126, 127, 23, true);
229
230         switch (format)
231         {
232                 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
233                 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
234                 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
235                 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
236                 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
237                 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
238                 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
239                         return reallyLow;
240
241                 case vk::VK_FORMAT_R8G8B8_UNORM:
242                 case vk::VK_FORMAT_B8G8R8_UNORM:
243                 case vk::VK_FORMAT_R8G8B8A8_UNORM:
244                 case vk::VK_FORMAT_B8G8R8A8_UNORM:
245                 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
246                 case vk::VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
247                 case vk::VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
248                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
249                 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
250                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
251                 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
252                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
253                         return reallyLow;
254
255                 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
256                 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
257                 case vk::VK_FORMAT_R16G16B16_UNORM:
258                 case vk::VK_FORMAT_R16G16B16A16_UNORM:
259                 case vk::VK_FORMAT_R10X6_UNORM_PACK16_KHR:
260                 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
261                 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
262                 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
263                 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
264                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
265                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
266                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
267                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
268                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
269                 case vk::VK_FORMAT_R12X4_UNORM_PACK16_KHR:
270                 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
271                 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
272                 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
273                 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
274                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
275                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
276                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
277                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
278                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
279                 case vk::VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
280                 case vk::VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
281                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
282                 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
283                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
284                 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
285                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
286                         return fp16;
287
288                 default:
289                         DE_FATAL("Precision not defined for format");
290                         return fp32;
291         }
292 }
293
294 class ChannelAccess
295 {
296 public:
297                                         ChannelAccess   (tcu::TextureChannelClass       channelClass,
298                                                                          deUint8                                        channelSize,
299                                                                          const IVec3&                           size,
300                                                                          const IVec3&                           bitPitch,
301                                                                          void*                                          data,
302                                                                          deUint32                                       bitOffset);
303
304         const IVec3&    getSize                 (void) const { return m_size; }
305         const IVec3&    getBitPitch             (void) const { return m_bitPitch; }
306         void*                   getDataPtr              (void) const { return m_data; }
307
308         Interval                getChannel              (const FloatFormat&     conversionFormat,
309                                                                          const IVec3&           pos) const;
310         deUint32                getChannelUint  (const IVec3& pos) const;
311         float                   getChannel              (const IVec3& pos) const;
312         void                    setChannel              (const IVec3& pos, deUint32 x);
313         void                    setChannel              (const IVec3& pos, float x);
314
315 private:
316         const tcu::TextureChannelClass  m_channelClass;
317         const deUint8                                   m_channelSize;
318         const IVec3                                             m_size;
319         const IVec3                                             m_bitPitch;
320         void* const                                             m_data;
321         const deInt32                                   m_bitOffset;
322
323 };
324
325 ChannelAccess::ChannelAccess (tcu::TextureChannelClass  channelClass,
326                                                           deUint8                                       channelSize,
327                                                           const IVec3&                          size,
328                                                           const IVec3&                          bitPitch,
329                                                           void*                                         data,
330                                                           deUint32                                      bitOffset)
331         : m_channelClass        (channelClass)
332         , m_channelSize         (channelSize)
333         , m_size                        (size)
334         , m_bitPitch            (bitPitch)
335
336         , m_data                        ((deUint8*)data + (bitOffset / 8))
337         , m_bitOffset           (bitOffset % 8)
338 {
339 }
340
341 //! Extend < 32b signed integer to 32b
342 inline deInt32 signExtend (deUint32 src, int bits)
343 {
344         const deUint32 signBit = 1u << (bits-1);
345
346         src |= ~((src & signBit) - 1);
347
348         return (deInt32)src;
349 }
350
351 deUint32 divRoundUp (deUint32 a, deUint32 b)
352 {
353         if (a % b == 0)
354                 return a / b;
355         else
356                 return (a / b) + 1;
357 }
358
359 deUint32 ChannelAccess::getChannelUint (const IVec3& pos) const
360 {
361         DE_ASSERT(pos[0] < m_size[0]);
362         DE_ASSERT(pos[1] < m_size[1]);
363         DE_ASSERT(pos[2] < m_size[2]);
364
365         const deInt32                   bitOffset       (m_bitOffset + tcu::dot(m_bitPitch, pos));
366         const deUint8* const    firstByte       = ((const deUint8*)m_data) + (bitOffset / 8);
367         const deUint32                  byteCount       = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
368         const deUint32                  mask            (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
369         const deUint32                  offset          = bitOffset % 8;
370         deUint32                                bits            = 0u;
371
372         deMemcpy(&bits, firstByte, byteCount);
373
374         return (bits >> offset) & mask;
375 }
376
377 void ChannelAccess::setChannel (const IVec3& pos, deUint32 x)
378 {
379         DE_ASSERT(pos[0] < m_size[0]);
380         DE_ASSERT(pos[1] < m_size[1]);
381         DE_ASSERT(pos[2] < m_size[2]);
382
383         const deInt32   bitOffset       (m_bitOffset + tcu::dot(m_bitPitch, pos));
384         deUint8* const  firstByte       = ((deUint8*)m_data) + (bitOffset / 8);
385         const deUint32  byteCount       = divRoundUp((bitOffset + m_channelSize) - 8u * (bitOffset / 8u), 8u);
386         const deUint32  mask            (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
387         const deUint32  offset          = bitOffset % 8;
388
389         const deUint32  bits            = (x & mask) << offset;
390         deUint32                oldBits         = 0;
391
392         deMemcpy(&oldBits, firstByte, byteCount);
393
394         {
395                 const deUint32  newBits = bits | (oldBits & (~(mask << offset)));
396
397                 deMemcpy(firstByte, &newBits,  byteCount);
398         }
399 }
400
401 float ChannelAccess::getChannel (const IVec3& pos) const
402 {
403         const deUint32  bits    (getChannelUint(pos));
404
405         switch (m_channelClass)
406         {
407                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
408                         return (float)bits / (float)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u));
409
410                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
411                         return (float)bits;
412
413                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
414                         return de::max(-1.0f, (float)signExtend(bits, m_channelSize) / (float)((0x1u << (m_channelSize - 1u)) - 1u));
415
416                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
417                         return (float)signExtend(bits, m_channelSize);
418
419                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
420                         if (m_channelSize == 32)
421                                 return tcu::Float32(bits).asFloat();
422                         else
423                         {
424                                 DE_FATAL("Float type not supported");
425                                 return -1.0f;
426                         }
427
428                 default:
429                         DE_FATAL("Unknown texture channel class");
430                         return -1.0f;
431         }
432 }
433
434 Interval ChannelAccess::getChannel (const FloatFormat&  conversionFormat,
435                                                                         const IVec3&            pos) const
436 {
437         const deUint32  bits    (getChannelUint(pos));
438
439         switch (m_channelClass)
440         {
441                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
442                         return conversionFormat.roundOut(conversionFormat.roundOut((double)bits, false)
443                                                                                         / conversionFormat.roundOut((double)(m_channelSize == 32 ? ~0x0u : ((0x1u << m_channelSize) - 1u)), false), false);
444
445                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
446                         return conversionFormat.roundOut((double)bits, false);
447
448                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
449                 {
450                         const Interval result (conversionFormat.roundOut(conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false)
451                                                                                                                         / conversionFormat.roundOut((double)((0x1u << (m_channelSize - 1u)) - 1u), false), false));
452
453                         return Interval(de::max(-1.0, result.lo()), de::max(-1.0, result.hi()));
454                 }
455
456                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
457                         return conversionFormat.roundOut((double)signExtend(bits, m_channelSize), false);
458
459                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
460                         if (m_channelSize == 32)
461                                 return conversionFormat.roundOut(tcu::Float32(bits).asFloat(), false);
462                         else
463                         {
464                                 DE_FATAL("Float type not supported");
465                                 return Interval();
466                         }
467
468                 default:
469                         DE_FATAL("Unknown texture channel class");
470                         return Interval();
471         }
472 }
473
474 // \todo Taken from tcuTexture.cpp
475 // \todo [2011-09-21 pyry] Move to tcutil?
476 template <typename T>
477 inline T convertSatRte (float f)
478 {
479         // \note Doesn't work for 64-bit types
480         DE_STATIC_ASSERT(sizeof(T) < sizeof(deUint64));
481         DE_STATIC_ASSERT((-3 % 2 != 0) && (-4 % 2 == 0));
482
483         deInt64 minVal  = std::numeric_limits<T>::min();
484         deInt64 maxVal  = std::numeric_limits<T>::max();
485         float   q               = deFloatFrac(f);
486         deInt64 intVal  = (deInt64)(f-q);
487
488         // Rounding.
489         if (q == 0.5f)
490         {
491                 if (intVal % 2 != 0)
492                         intVal++;
493         }
494         else if (q > 0.5f)
495                 intVal++;
496         // else Don't add anything
497
498         // Saturate.
499         intVal = de::max(minVal, de::min(maxVal, intVal));
500
501         return (T)intVal;
502 }
503
504 void ChannelAccess::setChannel (const IVec3& pos, float x)
505 {
506         DE_ASSERT(pos[0] < m_size[0]);
507         DE_ASSERT(pos[1] < m_size[1]);
508         DE_ASSERT(pos[2] < m_size[2]);
509
510         const deUint32  mask    (m_channelSize == 32u ? ~0x0u : (0x1u << m_channelSize) - 1u);
511
512         switch (m_channelClass)
513         {
514                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
515                 {
516                         const deUint32  maxValue        (mask);
517                         const deUint32  value           (de::min(maxValue, (deUint32)convertSatRte<deUint32>(x * (float)maxValue)));
518                         setChannel(pos, value);
519                         break;
520                 }
521
522                 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
523                 {
524                         const deInt32   range   ((0x1u << (m_channelSize - 1u)) - 1u);
525                         const deUint32  value   ((deUint32)de::clamp<deInt32>(convertSatRte<deInt32>(x * (float)range), -range, range));
526                         setChannel(pos, value);
527                         break;
528                 }
529
530                 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
531                 {
532                         const deUint32  maxValue        (mask);
533                         const deUint32  value           (de::min(maxValue, (deUint32)x));
534                         setChannel(pos, value);
535                         break;
536                 }
537
538                 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
539                 {
540                         const deInt32   minValue        (-(deInt32)(1u << (m_channelSize - 1u)));
541                         const deInt32   maxValue        ((deInt32)((1u << (m_channelSize - 1u)) - 1u));
542                         const deUint32  value           ((deUint32)de::clamp((deInt32)x, minValue, maxValue));
543                         setChannel(pos, value);
544                         break;
545                 }
546
547                 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
548                 {
549                         if (m_channelSize == 32)
550                         {
551                                 const deUint32  value           = tcu::Float32(x).bits();
552                                 setChannel(pos, value);
553                         }
554                         else
555                                 DE_FATAL("Float type not supported");
556                         break;
557                 }
558
559                 default:
560                         DE_FATAL("Unknown texture channel class");
561         }
562 }
563
564 ChannelAccess getChannelAccess (MultiPlaneImageData&                            data,
565                                                                 const vk::PlanarFormatDescription&      formatInfo,
566                                                                 const UVec2&                                            size,
567                                                                 int                                                                     channelNdx)
568 {
569         DE_ASSERT(formatInfo.hasChannelNdx(channelNdx));
570
571         const deUint32  planeNdx                        = formatInfo.channels[channelNdx].planeNdx;
572         const deUint32  valueOffsetBits         = formatInfo.channels[channelNdx].offsetBits;
573         const deUint32  pixelStrideBytes        = formatInfo.channels[channelNdx].strideBytes;
574         const deUint32  pixelStrideBits         = pixelStrideBytes * 8;
575         const deUint8   sizeBits                        = formatInfo.channels[channelNdx].sizeBits;
576
577         DE_ASSERT(size.x() % formatInfo.planes[planeNdx].widthDivisor == 0);
578         DE_ASSERT(size.y() % formatInfo.planes[planeNdx].heightDivisor == 0);
579
580         deUint32                accessWidth                     = size.x() / formatInfo.planes[planeNdx].widthDivisor;
581         const deUint32  accessHeight            = size.y() / formatInfo.planes[planeNdx].heightDivisor;
582         const deUint32  elementSizeBytes        = formatInfo.planes[planeNdx].elementSizeBytes;
583
584         const deUint32  rowPitch                        = formatInfo.planes[planeNdx].elementSizeBytes * accessWidth;
585         const deUint32  rowPitchBits            = rowPitch * 8;
586
587         if (pixelStrideBytes != elementSizeBytes)
588         {
589                 DE_ASSERT(elementSizeBytes % pixelStrideBytes == 0);
590                 accessWidth *= elementSizeBytes/pixelStrideBytes;
591         }
592
593         return ChannelAccess((tcu::TextureChannelClass)formatInfo.channels[channelNdx].type, sizeBits, IVec3(accessWidth, accessHeight, 1u), IVec3((int)pixelStrideBits, (int)rowPitchBits, 0), data.getPlanePtr(planeNdx), (deUint32)valueOffsetBits);
594 }
595
596 ShaderSpec createShaderSpec (void)
597 {
598         ShaderSpec spec;
599
600         spec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp sampler2D u_sampler;";
601
602         spec.inputs.push_back(Symbol("uv", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
603         spec.outputs.push_back(Symbol("o_color", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
604
605         spec.source = "o_color = texture(u_sampler, uv);\n";
606
607         return spec;
608 }
609
610 void genTexCoords (std::vector<Vec2>&   coords,
611                                    const UVec2&                 size)
612 {
613         for (deUint32 y = 0; y < size.y() + (size.y() / 2); y++)
614         for (deUint32 x = 0; x < size.x() + (size.x() / 2); x++)
615         {
616                 const float     fx      = (float)x;
617                 const float     fy      = (float)y;
618
619                 const float     fw      = (float)size.x();
620                 const float     fh      = (float)size.y();
621
622                 const float     s       = 1.5f * ((fx * 1.5f * fw + fx) / (1.5f * fw * 1.5f * fw)) - 0.25f;
623                 const float     t       = 1.5f * ((fy * 1.5f * fh + fy) / (1.5f * fh * 1.5f * fh)) - 0.25f;
624
625                 coords.push_back(Vec2(s, t));
626         }
627 }
628
629 Interval rangeExpandChroma (vk::VkSamplerYcbcrRangeKHR  range,
630                                                         const FloatFormat&                      conversionFormat,
631                                                         const deUint32                          bits,
632                                                         const Interval&                         sample)
633 {
634         const deUint32  values  (0x1u << bits);
635
636         switch (range)
637         {
638                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR:
639                         return conversionFormat.roundOut(sample - conversionFormat.roundOut(Interval((double)(0x1u << (bits - 1u)) / (double)((0x1u << bits) - 1u)), false), false);
640
641                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR:
642                 {
643                         const Interval  a                       (conversionFormat.roundOut(sample * Interval((double)(values - 1u)), false));
644                         const Interval  dividend        (conversionFormat.roundOut(a - Interval((double)(128u * (0x1u << (bits - 8u)))), false));
645                         const Interval  divisor         ((double)(224u * (0x1u << (bits - 8u))));
646                         const Interval  result          (conversionFormat.roundOut(dividend / divisor, false));
647
648                         return result;
649                 }
650
651                 default:
652                         DE_FATAL("Unknown YCbCrRange");
653                         return Interval();
654         }
655 }
656
657 Interval rangeExpandLuma (vk::VkSamplerYcbcrRangeKHR    range,
658                                                   const FloatFormat&                    conversionFormat,
659                                                   const deUint32                                bits,
660                                                   const Interval&                               sample)
661 {
662         const deUint32  values  (0x1u << bits);
663
664         switch (range)
665         {
666                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR:
667                         return conversionFormat.roundOut(sample, false);
668
669                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR:
670                 {
671                         const Interval  a                       (conversionFormat.roundOut(sample * Interval((double)(values - 1u)), false));
672                         const Interval  dividend        (conversionFormat.roundOut(a - Interval((double)(16u * (0x1u << (bits - 8u)))), false));
673                         const Interval  divisor         ((double)(219u * (0x1u << (bits - 8u))));
674                         const Interval  result          (conversionFormat.roundOut(dividend / divisor, false));
675
676                         return result;
677                 }
678
679                 default:
680                         DE_FATAL("Unknown YCbCrRange");
681                         return Interval();
682         }
683 }
684
685 Interval clampMaybe (const Interval&    x,
686                                          double                         min,
687                                          double                         max)
688 {
689         Interval result = x;
690
691         DE_ASSERT(min <= max);
692
693         if (x.lo() < min)
694                 result = result | Interval(min);
695
696         if (x.hi() > max)
697                 result = result | Interval(max);
698
699         return result;
700 }
701
702 void convertColor (vk::VkSamplerYcbcrModelConversionKHR colorModel,
703                                    vk::VkSamplerYcbcrRangeKHR                   range,
704                                    const FloatFormat&                                   conversionFormat,
705                                    const UVec4&                                                 bitDepth,
706                                    const Interval                                               input[4],
707                                    Interval                                                             output[4])
708 {
709         switch (colorModel)
710         {
711                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR:
712                 {
713                         for (size_t ndx = 0; ndx < 4; ndx++)
714                                 output[ndx] = input[ndx];
715                         break;
716                 }
717
718                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR:
719                 {
720                         output[0] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]), -0.5, 0.5);
721                         output[1] = clampMaybe(rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]), 0.0, 1.0);
722                         output[2] = clampMaybe(rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]), -0.5, 0.5);
723                         output[3] = input[3];
724                         break;
725                 }
726
727                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR:
728                 {
729                         const Interval  y                       (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
730                         const Interval  cr                      (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
731                         const Interval  cb                      (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
732
733                         const Interval  yClamped        (clampMaybe(y,   0.0, 1.0));
734                         const Interval  crClamped       (clampMaybe(cr, -0.5, 0.5));
735                         const Interval  cbClamped       (clampMaybe(cb, -0.5, 0.5));
736
737                         output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.402 * crClamped, false), false);
738                         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);
739                         output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.772 * cbClamped, false), false);
740                         output[3] = input[3];
741                         break;
742                 }
743
744                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR:
745                 {
746                         const Interval  y                       (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
747                         const Interval  cr                      (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
748                         const Interval  cb                      (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
749
750                         const Interval  yClamped        (clampMaybe(y,   0.0, 1.0));
751                         const Interval  crClamped       (clampMaybe(cr, -0.5, 0.5));
752                         const Interval  cbClamped       (clampMaybe(cb, -0.5, 0.5));
753
754                         output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.5748 * crClamped, false), false);
755                         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);
756                         output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8556 * cbClamped, false), false);
757                         output[3] = input[3];
758                         break;
759                 }
760
761                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR:
762                 {
763                         const Interval  y                       (rangeExpandLuma(range, conversionFormat, bitDepth[1], input[1]));
764                         const Interval  cr                      (rangeExpandChroma(range, conversionFormat, bitDepth[0], input[0]));
765                         const Interval  cb                      (rangeExpandChroma(range, conversionFormat, bitDepth[2], input[2]));
766
767                         const Interval  yClamped        (clampMaybe(y,   0.0, 1.0));
768                         const Interval  crClamped       (clampMaybe(cr, -0.5, 0.5));
769                         const Interval  cbClamped       (clampMaybe(cb, -0.5, 0.5));
770
771                         output[0] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.4746 * crClamped, false), false);
772                         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);
773                         output[2] = conversionFormat.roundOut(yClamped + conversionFormat.roundOut(1.8814 * cbClamped, false), false);
774                         output[3] = input[3];
775                         break;
776                 }
777
778                 default:
779                         DE_FATAL("Unknown YCbCrModel");
780         }
781
782         if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR)
783         {
784                 for (int ndx = 0; ndx < 3; ndx++)
785                         output[ndx] = clampMaybe(output[ndx], 0.0, 1.0);
786         }
787 }
788
789 int mirror (int coord)
790 {
791         return coord >= 0 ? coord : -(1 + coord);
792 }
793
794 int imod (int a, int b)
795 {
796         int m = a % b;
797         return m < 0 ? m + b : m;
798 }
799
800 int wrap (vk::VkSamplerAddressMode      addressMode,
801                   int                                           coord,
802                   int                                           size)
803 {
804         switch (addressMode)
805         {
806                 case vk::VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT:
807                         return (size - 1) - mirror(imod(coord, 2 * size) - size);
808
809                 case vk::VK_SAMPLER_ADDRESS_MODE_REPEAT:
810                         return imod(coord, size);
811
812                 case vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE:
813                         return de::clamp(coord, 0, size - 1);
814
815                 case vk::VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE:
816                         return de::clamp(mirror(coord), 0, size - 1);
817
818                 default:
819                         DE_FATAL("Unknown wrap mode");
820                         return ~0;
821         }
822 }
823
824 Interval frac (const Interval& x)
825 {
826         if (x.hi() - x.lo() >= 1.0)
827                 return Interval(0.0, 1.0);
828         else
829         {
830                 const Interval ret (deFrac(x.lo()), deFrac(x.hi()));
831
832                 return ret;
833         }
834 }
835
836 Interval calculateUV (const FloatFormat&        coordFormat,
837                                           const Interval&               st,
838                                           const int                             size)
839 {
840         return coordFormat.roundOut(coordFormat.roundOut(st, false) * Interval((double)size), false);
841 }
842
843 IVec2 calculateNearestIJRange (const FloatFormat&       coordFormat,
844                                                            const Interval&              uv)
845 {
846         const Interval  ij      (coordFormat.roundOut(coordFormat.roundOut(uv, false) - Interval(0.5), false));
847
848         return IVec2(deRoundToInt32(ij.lo() - coordFormat.ulp(ij.lo(), 1)), deRoundToInt32(ij.hi() + coordFormat.ulp(ij.hi(), 1)));
849 }
850
851 // Calculate range of pixel coordinates that can be used as lower coordinate for linear sampling
852 IVec2 calculateLinearIJRange (const FloatFormat&        coordFormat,
853                                                           const Interval&               uv)
854 {
855         const Interval  ij      (coordFormat.roundOut(uv - Interval(0.5), false));
856
857         return IVec2(deFloorToInt32(ij.lo()), deFloorToInt32(ij.hi()));
858 }
859
860 Interval calculateAB (const deUint32    subTexelPrecisionBits,
861                                           const Interval&       uv,
862                                           int                           ij)
863 {
864         const deUint32  subdivisions    = 0x1u << subTexelPrecisionBits;
865         const Interval  ab                              (frac((uv - 0.5) & Interval((double)ij, (double)(ij + 1))));
866         const Interval  gridAB                  (ab * Interval(subdivisions));
867         const Interval  rounded                 (de::max(deFloor(gridAB.lo()) / subdivisions, 0.0) , de::min(deCeil(gridAB.hi()) / subdivisions, 1.0));
868
869         return rounded;
870 }
871
872 Interval lookupWrapped (const ChannelAccess&            access,
873                                                 const FloatFormat&                      conversionFormat,
874                                                 vk::VkSamplerAddressMode        addressModeU,
875                                                 vk::VkSamplerAddressMode        addressModeV,
876                                                 const IVec2&                            coord)
877 {
878         return access.getChannel(conversionFormat, IVec3(wrap(addressModeU, coord.x(), access.getSize().x()), wrap(addressModeV, coord.y(), access.getSize().y()), 0));
879 }
880
881 Interval linearInterpolate (const FloatFormat&  filteringFormat,
882                                                         const Interval&         a,
883                                                         const Interval&         b,
884                                                         const Interval&         p00,
885                                                         const Interval&         p10,
886                                                         const Interval&         p01,
887                                                         const Interval&         p11)
888 {
889         const Interval p[4] =
890         {
891                 p00,
892                 p10,
893                 p01,
894                 p11
895         };
896         Interval        result  (0.0);
897
898         for (size_t ndx = 0; ndx < 4; ndx++)
899         {
900                 const Interval  weightA (filteringFormat.roundOut((ndx % 2) == 0 ? (1.0 - a) : a, false));
901                 const Interval  weightB (filteringFormat.roundOut((ndx / 2) == 0 ? (1.0 - b) : b, false));
902                 const Interval  weight  (filteringFormat.roundOut(weightA * weightB, false));
903
904                 result = filteringFormat.roundOut(result + filteringFormat.roundOut(p[ndx] * weight, false), false);
905         }
906
907         return result;
908 }
909
910 Interval calculateImplicitChromaUV (const FloatFormat&          coordFormat,
911                                                                         vk::VkChromaLocationKHR offset,
912                                                                         const Interval&                 uv)
913 {
914         if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR)
915                 return coordFormat.roundOut(0.5 * coordFormat.roundOut(uv + 0.5, false), false);
916         else
917                 return coordFormat.roundOut(0.5 * uv, false);
918 }
919
920 Interval linearSample (const ChannelAccess&             access,
921                                            const FloatFormat&           conversionFormat,
922                                            const FloatFormat&           filteringFormat,
923                                            vk::VkSamplerAddressMode     addressModeU,
924                                            vk::VkSamplerAddressMode     addressModeV,
925                                            const IVec2&                         coord,
926                                            const Interval&                      a,
927                                            const Interval&                      b)
928 {
929         return linearInterpolate(filteringFormat, a, b,
930                                                                         lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + IVec2(0, 0)),
931                                                                         lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + IVec2(1, 0)),
932                                                                         lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + IVec2(0, 1)),
933                                                                         lookupWrapped(access, conversionFormat, addressModeU, addressModeV, coord + IVec2(1, 1)));
934 }
935
936 int divFloor (int a, int b)
937 {
938         if (a % b == 0)
939                 return a / b;
940         else if (a > 0)
941                 return a / b;
942         else
943                 return (a / b) - 1;
944 }
945
946 Interval reconstructLinearXChromaSample (const FloatFormat&                     filteringFormat,
947                                                                                  const FloatFormat&                     conversionFormat,
948                                                                                  vk::VkChromaLocationKHR        offset,
949                                                                                  vk::VkSamplerAddressMode       addressModeU,
950                                                                                  vk::VkSamplerAddressMode       addressModeV,
951                                                                                  const ChannelAccess&           access,
952                                                                                  int                                            i,
953                                                                                  int                                            j)
954 {
955         const int subI  = divFloor(i, 2);
956
957         if (offset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR)
958         {
959                 if (i % 2 == 0)
960                         return lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI, j));
961                 else
962                 {
963                         const Interval  a       (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI, j)), false));
964                         const Interval  b       (filteringFormat.roundOut(0.5 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI + 1, j)), false));
965
966                         return filteringFormat.roundOut(a + b, false);
967                 }
968         }
969         else if (offset == vk::VK_CHROMA_LOCATION_MIDPOINT_KHR)
970         {
971                 if (i % 2 == 0)
972                 {
973                         const Interval  a       (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI - 1, j)), false));
974                         const Interval  b       (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI, j)), false));
975
976                         return filteringFormat.roundOut(a + b, false);
977                 }
978                 else
979                 {
980                         const Interval  a       (filteringFormat.roundOut(0.25 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI + 1, j)), false));
981                         const Interval  b       (filteringFormat.roundOut(0.75 * lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI, j)), false));
982
983                         return filteringFormat.roundOut(a + b, false);
984                 }
985         }
986         else
987         {
988                 DE_FATAL("Unknown sample location");
989                 return Interval();
990         }
991 }
992
993 Interval reconstructLinearXYChromaSample (const FloatFormat&                    filteringFormat,
994                                                                                   const FloatFormat&                    conversionFormat,
995                                                                                   vk::VkChromaLocationKHR               xOffset,
996                                                                                   vk::VkChromaLocationKHR               yOffset,
997                                                                                   vk::VkSamplerAddressMode              addressModeU,
998                                                                                   vk::VkSamplerAddressMode              addressModeV,
999                                                                                   const ChannelAccess&                  access,
1000                                                                                   int                                                   i,
1001                                                                                   int                                                   j)
1002 {
1003         const int               subI    = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR
1004                                                         ? divFloor(i, 2)
1005                                                         : (i % 2 == 0 ? divFloor(i, 2) - 1 : divFloor(i, 2));
1006         const int               subJ    = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR
1007                                                         ? divFloor(j, 2)
1008                                                         : (j % 2 == 0 ? divFloor(j, 2) - 1 : divFloor(j, 2));
1009
1010         const double    a               = xOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR
1011                                                         ? (i % 2 == 0 ? 0.0 : 0.5)
1012                                                         : (i % 2 == 0 ? 0.25 : 0.75);
1013         const double    b               = yOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR
1014                                                         ? (j % 2 == 0 ? 0.0 : 0.5)
1015                                                         : (j % 2 == 0 ? 0.25 : 0.75);
1016
1017         return linearInterpolate(filteringFormat, a, b,
1018                                                                 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1019                                                                 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI + 1, subJ)),
1020                                                                 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ + 1)),
1021                                                                 lookupWrapped(access, conversionFormat, addressModeU, addressModeV, IVec2(subI + 1, subJ + 1)));
1022 }
1023
1024 const ChannelAccess& swizzle (vk::VkComponentSwizzle    swizzle,
1025                                                           const ChannelAccess&          identityPlane,
1026                                                           const ChannelAccess&          rPlane,
1027                                                           const ChannelAccess&          gPlane,
1028                                                           const ChannelAccess&          bPlane,
1029                                                           const ChannelAccess&          aPlane)
1030 {
1031         switch (swizzle)
1032         {
1033                 case vk::VK_COMPONENT_SWIZZLE_IDENTITY: return identityPlane;
1034                 case vk::VK_COMPONENT_SWIZZLE_R:                return rPlane;
1035                 case vk::VK_COMPONENT_SWIZZLE_G:                return gPlane;
1036                 case vk::VK_COMPONENT_SWIZZLE_B:                return bPlane;
1037                 case vk::VK_COMPONENT_SWIZZLE_A:                return aPlane;
1038
1039                 default:
1040                         DE_FATAL("Unsupported swizzle");
1041                         return identityPlane;
1042         }
1043 }
1044
1045 void calculateBounds (const ChannelAccess&                                      rPlane,
1046                                           const ChannelAccess&                                  gPlane,
1047                                           const ChannelAccess&                                  bPlane,
1048                                           const ChannelAccess&                                  aPlane,
1049                                           const UVec4&                                                  bitDepth,
1050                                           const vector<Vec2>&                                   sts,
1051                                           const FloatFormat&                                    filteringFormat,
1052                                           const FloatFormat&                                    conversionFormat,
1053                                           const deUint32                                                subTexelPrecisionBits,
1054                                           vk::VkFilter                                                  filter,
1055                                           vk::VkSamplerYcbcrModelConversionKHR  colorModel,
1056                                           vk::VkSamplerYcbcrRangeKHR                    range,
1057                                           vk::VkFilter                                                  chromaFilter,
1058                                           vk::VkChromaLocationKHR                               xChromaOffset,
1059                                           vk::VkChromaLocationKHR                               yChromaOffset,
1060                                           const vk::VkComponentMapping&                 componentMapping,
1061                                           bool                                                                  explicitReconstruction,
1062                                           vk::VkSamplerAddressMode                              addressModeU,
1063                                           vk::VkSamplerAddressMode                              addressModeV,
1064                                           std::vector<Vec4>&                                    minBounds,
1065                                           std::vector<Vec4>&                                    maxBounds,
1066                                           std::vector<Vec4>&                                    uvBounds,
1067                                           std::vector<IVec4>&                                   ijBounds)
1068 {
1069         const FloatFormat               highp                   (-126, 127, 23, true,
1070                                                                                          tcu::MAYBE,    // subnormals
1071                                                                                          tcu::YES,              // infinities
1072                                                                                          tcu::MAYBE);   // NaN
1073         const FloatFormat               coordFormat             (-32, 32, 16, true);
1074         const ChannelAccess&    rAccess                 (swizzle(componentMapping.r, rPlane, rPlane, gPlane, bPlane, aPlane));
1075         const ChannelAccess&    gAccess                 (swizzle(componentMapping.g, gPlane, rPlane, gPlane, bPlane, aPlane));
1076         const ChannelAccess&    bAccess                 (swizzle(componentMapping.b, bPlane, rPlane, gPlane, bPlane, aPlane));
1077         const ChannelAccess&    aAccess                 (swizzle(componentMapping.a, aPlane, rPlane, gPlane, bPlane, aPlane));
1078
1079         const bool                              subsampledX             = gAccess.getSize().x() > rAccess.getSize().x();
1080         const bool                              subsampledY             = gAccess.getSize().y() > rAccess.getSize().y();
1081
1082         minBounds.resize(sts.size(), Vec4(TCU_INFINITY));
1083         maxBounds.resize(sts.size(), Vec4(-TCU_INFINITY));
1084
1085         uvBounds.resize(sts.size(), Vec4(TCU_INFINITY, -TCU_INFINITY, TCU_INFINITY, -TCU_INFINITY));
1086         ijBounds.resize(sts.size(), IVec4(0x7FFFFFFF, -1 -0x7FFFFFFF, 0x7FFFFFFF, -1 -0x7FFFFFFF));
1087
1088         // Chroma plane sizes must match
1089         DE_ASSERT(rAccess.getSize() == bAccess.getSize());
1090
1091         // Luma plane sizes must match
1092         DE_ASSERT(gAccess.getSize() == aAccess.getSize());
1093
1094         // Luma plane size must match chroma plane or be twice as big
1095         DE_ASSERT(rAccess.getSize().x() == gAccess.getSize().x() || 2 * rAccess.getSize().x() == gAccess.getSize().x());
1096         DE_ASSERT(rAccess.getSize().y() == gAccess.getSize().y() || 2 * rAccess.getSize().y() == gAccess.getSize().y());
1097
1098         for (size_t ndx = 0; ndx < sts.size(); ndx++)
1099         {
1100                 const Vec2      st              (sts[ndx]);
1101                 Interval        bounds[4];
1102
1103                 const Interval  u       (calculateUV(coordFormat, st[0], gAccess.getSize().x()));
1104                 const Interval  v       (calculateUV(coordFormat, st[1], gAccess.getSize().y()));
1105
1106                 uvBounds[ndx][0] = (float)u.lo();
1107                 uvBounds[ndx][1] = (float)u.hi();
1108
1109                 uvBounds[ndx][2] = (float)v.lo();
1110                 uvBounds[ndx][3] = (float)v.hi();
1111
1112                 if (filter == vk::VK_FILTER_NEAREST)
1113                 {
1114                         const IVec2     iRange  (calculateNearestIJRange(coordFormat, u));
1115                         const IVec2     jRange  (calculateNearestIJRange(coordFormat, v));
1116
1117                         ijBounds[ndx][0] = iRange[0];
1118                         ijBounds[ndx][1] = iRange[1];
1119
1120                         ijBounds[ndx][2] = jRange[0];
1121                         ijBounds[ndx][3] = jRange[1];
1122
1123                         for (int j = jRange.x(); j <= jRange.y(); j++)
1124                         for (int i = iRange.x(); i <= iRange.y(); i++)
1125                         {
1126                                 const Interval  gValue  (lookupWrapped(gAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1127                                 const Interval  aValue  (lookupWrapped(aAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)));
1128
1129                                 if (subsampledX || subsampledY)
1130                                 {
1131                                         if (explicitReconstruction)
1132                                         {
1133                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
1134                                                 {
1135                                                         // Nearest, Reconstructed chroma with explicit nearest filtering
1136                                                         const int               subI            = subsampledX ? i / 2 : i;
1137                                                         const int               subJ            = subsampledY ? j / 2 : j;
1138                                                         const Interval  srcColor[]      =
1139                                                         {
1140                                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1141                                                                 gValue,
1142                                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(subI, subJ)),
1143                                                                 aValue
1144                                                         };
1145                                                         Interval                dstColor[4];
1146
1147                                                         convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1148
1149                                                         for (size_t compNdx = 0; compNdx < 4; compNdx++)
1150                                                                 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1151                                                 }
1152                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1153                                                 {
1154                                                         if (subsampledX && subsampledY)
1155                                                         {
1156                                                                 // Nearest, Reconstructed both chroma samples with explicit linear filtering
1157                                                                 const Interval  rValue  (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1158                                                                 const Interval  bValue  (reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1159                                                                 const Interval  srcColor[]      =
1160                                                                 {
1161                                                                         rValue,
1162                                                                         gValue,
1163                                                                         bValue,
1164                                                                         aValue
1165                                                                 };
1166                                                                 Interval                dstColor[4];
1167
1168                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1169
1170                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1171                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1172                                                         }
1173                                                         else if (subsampledX)
1174                                                         {
1175                                                                 // Nearest, Reconstructed x chroma samples with explicit linear filtering
1176                                                                 const Interval  rValue  (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j));
1177                                                                 const Interval  bValue  (reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j));
1178                                                                 const Interval  srcColor[]      =
1179                                                                 {
1180                                                                         rValue,
1181                                                                         gValue,
1182                                                                         bValue,
1183                                                                         aValue
1184                                                                 };
1185                                                                 Interval                dstColor[4];
1186
1187                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1188
1189                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1190                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1191                                                         }
1192                                                         else
1193                                                                 DE_FATAL("Unexpected chroma reconstruction");
1194                                                 }
1195                                                 else
1196                                                         DE_FATAL("Unknown filter");
1197                                         }
1198                                         else
1199                                         {
1200                                                 const Interval  chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
1201                                                 const Interval  chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
1202
1203                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
1204                                                 {
1205                                                         // Nearest, reconstructed chroma samples with implicit nearest filtering
1206                                                         const IVec2     chromaIRange    (subsampledX ? calculateNearestIJRange(coordFormat, chromaU) : IVec2(i, i));
1207                                                         const IVec2     chromaJRange    (subsampledY ? calculateNearestIJRange(coordFormat, chromaV) : IVec2(j, j));
1208
1209                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1210                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
1211                                                         {
1212                                                                 const Interval  srcColor[]      =
1213                                                                 {
1214                                                                         lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1215                                                                         gValue,
1216                                                                         lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1217                                                                         aValue
1218                                                                 };
1219                                                                 Interval                dstColor[4];
1220
1221                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1222
1223                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1224                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1225                                                         }
1226                                                 }
1227                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1228                                                 {
1229                                                         // Nearest, reconstructed chroma samples with implicit linear filtering
1230                                                         const IVec2     chromaIRange    (subsampledX ? calculateLinearIJRange(coordFormat, chromaU) : IVec2(i, i));
1231                                                         const IVec2     chromaJRange    (subsampledY ? calculateLinearIJRange(coordFormat, chromaV) : IVec2(j, j));
1232
1233                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1234                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
1235                                                         {
1236                                                                 const Interval  chromaA (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
1237                                                                 const Interval  chromaB (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
1238
1239                                                                 const Interval  srcColor[]      =
1240                                                                 {
1241                                                                         linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
1242                                                                         gValue,
1243                                                                         linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB),
1244                                                                         aValue
1245                                                                 };
1246                                                                 Interval                dstColor[4];
1247
1248                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1249
1250                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1251                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1252                                                         }
1253                                                 }
1254                                                 else
1255                                                         DE_FATAL("Unknown filter");
1256                                         }
1257                                 }
1258                                 else
1259                                 {
1260                                         // Linear, no chroma subsampling
1261                                         const Interval  srcColor[]      =
1262                                         {
1263                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
1264                                                 gValue,
1265                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i, j)),
1266                                                 aValue
1267                                         };
1268                                         Interval dstColor[4];
1269
1270                                         convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1271
1272                                         for (size_t compNdx = 0; compNdx < 4; compNdx++)
1273                                                 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1274                                 }
1275                         }
1276                 }
1277                 else if (filter == vk::VK_FILTER_LINEAR)
1278                 {
1279                         const IVec2     iRange  (calculateLinearIJRange(coordFormat, u));
1280                         const IVec2     jRange  (calculateLinearIJRange(coordFormat, v));
1281
1282                         ijBounds[ndx][0] = iRange[0];
1283                         ijBounds[ndx][1] = iRange[1];
1284
1285                         ijBounds[ndx][2] = jRange[0];
1286                         ijBounds[ndx][3] = jRange[1];
1287
1288                         for (int j = jRange.x(); j <= jRange.y(); j++)
1289                         for (int i = iRange.x(); i <= iRange.y(); i++)
1290                         {
1291                                 const Interval  lumaA           (calculateAB(subTexelPrecisionBits, u, i));
1292                                 const Interval  lumaB           (calculateAB(subTexelPrecisionBits, v, j));
1293
1294                                 const Interval  gValue          (linearSample(gAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
1295                                 const Interval  aValue          (linearSample(aAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), lumaA, lumaB));
1296
1297                                 if (subsampledX || subsampledY)
1298                                 {
1299                                         if (explicitReconstruction)
1300                                         {
1301                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
1302                                                 {
1303                                                         const Interval  srcColor[]      =
1304                                                         {
1305                                                                 linearInterpolate(filteringFormat, lumaA, lumaB,
1306                                                                                                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
1307                                                                                                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
1308                                                                                                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
1309                                                                                                                                 lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
1310                                                                 gValue,
1311                                                                 linearInterpolate(filteringFormat, lumaA, lumaB,
1312                                                                                                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
1313                                                                                                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), j       / (subsampledY ? 2 : 1))),
1314                                                                                                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(i       / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1))),
1315                                                                                                                                 lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2((i + 1) / (subsampledX ? 2 : 1), (j + 1) / (subsampledY ? 2 : 1)))),
1316                                                                 aValue
1317                                                         };
1318                                                         Interval                dstColor[4];
1319
1320                                                         convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1321
1322                                                         for (size_t compNdx = 0; compNdx < 4; compNdx++)
1323                                                                 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1324                                                 }
1325                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1326                                                 {
1327                                                         if (subsampledX && subsampledY)
1328                                                         {
1329                                                                 // Linear, Reconstructed xx chroma samples with explicit linear filtering
1330                                                                 const Interval  rValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
1331                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i, j),
1332                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
1333                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
1334                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
1335                                                                 const Interval  bValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
1336                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i, j),
1337                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
1338                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
1339                                                                                                                                                         reconstructLinearXYChromaSample(filteringFormat, conversionFormat, xChromaOffset, yChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
1340                                                                 const Interval  srcColor[]      =
1341                                                                 {
1342                                                                         rValue,
1343                                                                         gValue,
1344                                                                         bValue,
1345                                                                         aValue
1346                                                                 };
1347                                                                 Interval                dstColor[4];
1348
1349                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1350
1351                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1352                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1353
1354                                                         }
1355                                                         else if (subsampledX)
1356                                                         {
1357                                                                 // Linear, Reconstructed x chroma samples with explicit linear filtering
1358                                                                 const Interval  rValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
1359                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i, j),
1360                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j),
1361                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i , j + 1),
1362                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, rAccess, i + 1, j + 1)));
1363                                                                 const Interval  bValue  (linearInterpolate(filteringFormat, lumaA, lumaB,
1364                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i, j),
1365                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j),
1366                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i , j + 1),
1367                                                                                                                                                         reconstructLinearXChromaSample(filteringFormat, conversionFormat, xChromaOffset, addressModeU, addressModeV, bAccess, i + 1, j + 1)));
1368                                                                 const Interval  srcColor[]      =
1369                                                                 {
1370                                                                         rValue,
1371                                                                         gValue,
1372                                                                         bValue,
1373                                                                         aValue
1374                                                                 };
1375                                                                 Interval                dstColor[4];
1376
1377                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1378
1379                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1380                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1381                                                         }
1382                                                         else
1383                                                                 DE_FATAL("Unknown subsampling config");
1384                                                 }
1385                                                 else
1386                                                         DE_FATAL("Unknown chroma filter");
1387                                         }
1388                                         else
1389                                         {
1390                                                 const Interval  chromaU (subsampledX ? calculateImplicitChromaUV(coordFormat, xChromaOffset, u) : u);
1391                                                 const Interval  chromaV (subsampledY ? calculateImplicitChromaUV(coordFormat, yChromaOffset, v) : v);
1392
1393                                                 if (chromaFilter == vk::VK_FILTER_NEAREST)
1394                                                 {
1395                                                         const IVec2     chromaIRange    (calculateNearestIJRange(coordFormat, chromaU));
1396                                                         const IVec2     chromaJRange    (calculateNearestIJRange(coordFormat, chromaV));
1397
1398                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1399                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
1400                                                         {
1401                                                                 const Interval  srcColor[]      =
1402                                                                 {
1403                                                                         lookupWrapped(rAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1404                                                                         gValue,
1405                                                                         lookupWrapped(bAccess, conversionFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ)),
1406                                                                         aValue
1407                                                                 };
1408                                                                 Interval        dstColor[4];
1409
1410                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1411
1412                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1413                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1414                                                         }
1415                                                 }
1416                                                 else if (chromaFilter == vk::VK_FILTER_LINEAR)
1417                                                 {
1418                                                         const IVec2     chromaIRange    (calculateNearestIJRange(coordFormat, chromaU));
1419                                                         const IVec2     chromaJRange    (calculateNearestIJRange(coordFormat, chromaV));
1420
1421                                                         for (int chromaJ = chromaJRange.x(); chromaJ <= chromaJRange.y(); chromaJ++)
1422                                                         for (int chromaI = chromaIRange.x(); chromaI <= chromaIRange.x(); chromaI++)
1423                                                         {
1424                                                                 const Interval  chromaA         (calculateAB(subTexelPrecisionBits, chromaU, chromaI));
1425                                                                 const Interval  chromaB         (calculateAB(subTexelPrecisionBits, chromaV, chromaJ));
1426
1427                                                                 const Interval  rValue          (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
1428                                                                 const Interval  bValue          (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(chromaI, chromaJ), chromaA, chromaB));
1429
1430                                                                 const Interval  srcColor[]      =
1431                                                                 {
1432                                                                         rValue,
1433                                                                         gValue,
1434                                                                         bValue,
1435                                                                         aValue
1436                                                                 };
1437                                                                 Interval                dstColor[4];
1438                                                                 convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1439
1440                                                                 for (size_t compNdx = 0; compNdx < 4; compNdx++)
1441                                                                         bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1442                                                         }
1443                                                 }
1444                                                 else
1445                                                         DE_FATAL("Unknown chroma filter");
1446                                         }
1447                                 }
1448                                 else
1449                                 {
1450                                         const Interval  chromaA         (lumaA);
1451                                         const Interval  chromaB         (lumaB);
1452                                         const Interval  rValue          (linearSample(rAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
1453                                         const Interval  bValue          (linearSample(bAccess, conversionFormat, filteringFormat, addressModeU, addressModeV, IVec2(i, j), chromaA, chromaB));
1454                                         const Interval  srcColor[]      =
1455                                         {
1456                                                 rValue,
1457                                                 gValue,
1458                                                 bValue,
1459                                                 aValue
1460                                         };
1461                                         Interval dstColor[4];
1462
1463                                         convertColor(colorModel, range, conversionFormat, bitDepth, srcColor, dstColor);
1464
1465                                         for (size_t compNdx = 0; compNdx < 4; compNdx++)
1466                                                 bounds[compNdx] |= highp.roundOut(dstColor[compNdx], false);
1467                                 }
1468                         }
1469                 }
1470                 else
1471                         DE_FATAL("Unknown filter");
1472
1473                 minBounds[ndx] = Vec4((float)bounds[0].lo(), (float)bounds[1].lo(), (float)bounds[2].lo(), (float)bounds[3].lo());
1474                 maxBounds[ndx] = Vec4((float)bounds[0].hi(), (float)bounds[1].hi(), (float)bounds[2].hi(), (float)bounds[3].hi());
1475         }
1476 }
1477
1478 struct TestConfig
1479 {
1480         TestConfig      (glu::ShaderType                                                shaderType_,
1481                                  vk::VkFormat                                                   format_,
1482                                  vk::VkImageTiling                                              imageTiling_,
1483                                  vk::VkFilter                                                   textureFilter_,
1484                                  vk::VkSamplerAddressMode                               addressModeU_,
1485                                  vk::VkSamplerAddressMode                               addressModeV_,
1486
1487                                  vk::VkFilter                                                   chromaFilter_,
1488                                  vk::VkChromaLocationKHR                                xChromaOffset_,
1489                                  vk::VkChromaLocationKHR                                yChromaOffset_,
1490                                  bool                                                                   explicitReconstruction_,
1491                                  bool                                                                   disjoint_,
1492
1493                                  vk::VkSamplerYcbcrRangeKHR                             colorRange_,
1494                                  vk::VkSamplerYcbcrModelConversionKHR   colorModel_,
1495                                  vk::VkComponentMapping                                 componentMapping_)
1496                 : shaderType                            (shaderType_)
1497                 , format                                        (format_)
1498                 , imageTiling                           (imageTiling_)
1499                 , textureFilter                         (textureFilter_)
1500                 , addressModeU                          (addressModeU_)
1501                 , addressModeV                          (addressModeV_)
1502
1503                 , chromaFilter                          (chromaFilter_)
1504                 , xChromaOffset                         (xChromaOffset_)
1505                 , yChromaOffset                         (yChromaOffset_)
1506                 , explicitReconstruction        (explicitReconstruction_)
1507                 , disjoint                                      (disjoint_)
1508
1509                 , colorRange                            (colorRange_)
1510                 , colorModel                            (colorModel_)
1511                 , componentMapping                      (componentMapping_)
1512         {
1513         }
1514
1515         glu::ShaderType                                                 shaderType;
1516         vk::VkFormat                                                    format;
1517         vk::VkImageTiling                                               imageTiling;
1518         vk::VkFilter                                                    textureFilter;
1519         vk::VkSamplerAddressMode                                addressModeU;
1520         vk::VkSamplerAddressMode                                addressModeV;
1521
1522         vk::VkFilter                                                    chromaFilter;
1523         vk::VkChromaLocationKHR                                 xChromaOffset;
1524         vk::VkChromaLocationKHR                                 yChromaOffset;
1525         bool                                                                    explicitReconstruction;
1526         bool                                                                    disjoint;
1527
1528         vk::VkSamplerYcbcrRangeKHR                              colorRange;
1529         vk::VkSamplerYcbcrModelConversionKHR    colorModel;
1530         vk::VkComponentMapping                                  componentMapping;
1531 };
1532
1533 vk::Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout (const vk::DeviceInterface&       vkd,
1534                                                                                                                            vk::VkDevice                                 device,
1535                                                                                                                            vk::VkSampler                                sampler)
1536 {
1537         const vk::VkDescriptorSetLayoutBinding          layoutBindings[]        =
1538         {
1539                 {
1540                         0u,
1541                         vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1542                         1u,
1543                         vk::VK_SHADER_STAGE_ALL,
1544                         &sampler
1545                 }
1546         };
1547         const vk::VkDescriptorSetLayoutCreateInfo       layoutCreateInfo        =
1548         {
1549                 vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
1550                 DE_NULL,
1551
1552                 0u,
1553                 DE_LENGTH_OF_ARRAY(layoutBindings),
1554                 layoutBindings
1555         };
1556
1557         return vk::createDescriptorSetLayout(vkd, device, &layoutCreateInfo);
1558 }
1559
1560 vk::Move<vk::VkDescriptorPool> createDescriptorPool (const vk::DeviceInterface& vkd,
1561                                                                                                          vk::VkDevice                           device)
1562 {
1563         const vk::VkDescriptorPoolSize                  poolSizes[]                                     =
1564         {
1565                 { vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1u, }
1566         };
1567         const vk::VkDescriptorPoolCreateInfo    descriptorPoolCreateInfo        =
1568         {
1569                 vk::VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
1570                 DE_NULL,
1571                 vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
1572
1573                 1u,
1574                 DE_LENGTH_OF_ARRAY(poolSizes),
1575                 poolSizes
1576         };
1577
1578         return createDescriptorPool(vkd, device, &descriptorPoolCreateInfo);
1579 }
1580
1581 vk::Move<vk::VkDescriptorSet> createDescriptorSet (const vk::DeviceInterface&   vkd,
1582                                                                                                    vk::VkDevice                                 device,
1583                                                                                                    vk::VkDescriptorPool                 descriptorPool,
1584                                                                                                    vk::VkDescriptorSetLayout    layout,
1585                                                                                                    vk::VkSampler                                sampler,
1586                                                                                                    vk::VkImageView                              imageView)
1587 {
1588         const vk::VkDescriptorSetAllocateInfo           descriptorSetAllocateInfo       =
1589         {
1590                 vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
1591                 DE_NULL,
1592
1593                 descriptorPool,
1594                 1u,
1595                 &layout
1596         };
1597         vk::Move<vk::VkDescriptorSet>   descriptorSet   (vk::allocateDescriptorSet(vkd, device, &descriptorSetAllocateInfo));
1598         const vk::VkDescriptorImageInfo imageInfo               =
1599         {
1600                 sampler,
1601                 imageView,
1602                 vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
1603         };
1604
1605         {
1606                 const vk::VkWriteDescriptorSet  writes[]        =
1607                 {
1608                         {
1609                                 vk::VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
1610                                 DE_NULL,
1611
1612                                 *descriptorSet,
1613                                 0u,
1614                                 0u,
1615                                 1u,
1616                                 vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
1617                                 &imageInfo,
1618                                 DE_NULL,
1619                                 DE_NULL
1620                         }
1621                 };
1622
1623                 vkd.updateDescriptorSets(device, DE_LENGTH_OF_ARRAY(writes), writes, 0u, DE_NULL);
1624         }
1625
1626         return descriptorSet;
1627 }
1628
1629 vk::Move<vk::VkSampler> createSampler (const vk::DeviceInterface&               vkd,
1630                                                                            vk::VkDevice                                         device,
1631                                                                            vk::VkFilter                                         textureFilter,
1632                                                                            vk::VkSamplerAddressMode                     addressModeU,
1633                                                                            vk::VkSamplerAddressMode                     addressModeV,
1634                                                                            vk::VkSamplerYcbcrConversionKHR      conversion)
1635 {
1636 #if !defined(FAKE_COLOR_CONVERSION)
1637         const vk::VkSamplerYcbcrConversionInfoKHR       samplerConversionInfo   =
1638         {
1639                 vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR,
1640                 DE_NULL,
1641                 conversion
1642         };
1643 #else
1644         DE_UNREF(conversion);
1645 #endif
1646         const vk::VkSamplerCreateInfo   createInfo      =
1647         {
1648                 vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
1649 #if !defined(FAKE_COLOR_CONVERSION)
1650                 &samplerConversionInfo,
1651 #else
1652                 DE_NULL,
1653 #endif
1654
1655                 0u,
1656                 textureFilter,
1657                 textureFilter,
1658                 vk::VK_SAMPLER_MIPMAP_MODE_NEAREST,
1659                 addressModeU,
1660                 addressModeV,
1661                 vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
1662                 0.0f,
1663                 VK_FALSE,
1664                 1.0f,
1665                 VK_FALSE,
1666                 vk::VK_COMPARE_OP_ALWAYS,
1667                 0.0f,
1668                 0.0f,
1669                 vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,
1670                 VK_FALSE,
1671         };
1672
1673         return createSampler(vkd, device, &createInfo);
1674 }
1675
1676 vk::Move<vk::VkImage> createImage (const vk::DeviceInterface&   vkd,
1677                                                                    vk::VkDevice                                 device,
1678                                                                    vk::VkFormat                                 format,
1679                                                                    const UVec2&                                 size,
1680                                                                    bool                                                 disjoint,
1681                                                                    vk::VkImageTiling                    tiling)
1682 {
1683         const vk::VkImageCreateInfo createInfo =
1684         {
1685                 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1686                 DE_NULL,
1687                 disjoint ? (vk::VkImageCreateFlags)vk::VK_IMAGE_CREATE_DISJOINT_BIT_KHR : (vk::VkImageCreateFlags)0u,
1688
1689                 vk::VK_IMAGE_TYPE_2D,
1690                 format,
1691                 vk::makeExtent3D(size.x(), size.y(), 1u),
1692                 1u,
1693                 1u,
1694                 vk::VK_SAMPLE_COUNT_1_BIT,
1695                 tiling,
1696                 vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT | vk::VK_IMAGE_USAGE_SAMPLED_BIT,
1697                 vk::VK_SHARING_MODE_EXCLUSIVE,
1698                 0u,
1699                 (const deUint32*)DE_NULL,
1700                 vk::VK_IMAGE_LAYOUT_UNDEFINED,
1701         };
1702
1703         return vk::createImage(vkd, device, &createInfo);
1704 }
1705
1706 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface&           vkd,
1707                                                                                    vk::VkDevice                                         device,
1708                                                                                    vk::VkImage                                          image,
1709                                                                                    vk::VkFormat                                         format,
1710                                                                                    vk::VkSamplerYcbcrConversionKHR      conversion)
1711 {
1712 #if !defined(FAKE_COLOR_CONVERSION)
1713         const vk::VkSamplerYcbcrConversionInfoKHR       conversionInfo  =
1714         {
1715                 vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR,
1716                 DE_NULL,
1717                 conversion
1718         };
1719 #else
1720         DE_UNREF(conversion);
1721 #endif
1722         const vk::VkImageViewCreateInfo                         viewInfo                =
1723         {
1724                 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
1725 #if defined(FAKE_COLOR_CONVERSION)
1726                 DE_NULL,
1727 #else
1728                 &conversionInfo,
1729 #endif
1730                 (vk::VkImageViewCreateFlags)0,
1731
1732                 image,
1733                 vk::VK_IMAGE_VIEW_TYPE_2D,
1734                 format,
1735                 {
1736                         vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1737                         vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1738                         vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1739                         vk::VK_COMPONENT_SWIZZLE_IDENTITY,
1740                 },
1741                 { vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },
1742         };
1743
1744         return vk::createImageView(vkd, device, &viewInfo);
1745 }
1746
1747 vk::Move<vk::VkSamplerYcbcrConversionKHR> createConversion (const vk::DeviceInterface&                          vkd,
1748                                                                                                                         vk::VkDevice                                                    device,
1749                                                                                                                         vk::VkFormat                                                    format,
1750                                                                                                                         vk::VkSamplerYcbcrModelConversionKHR    colorModel,
1751                                                                                                                         vk::VkSamplerYcbcrRangeKHR                              colorRange,
1752                                                                                                                         vk::VkChromaLocationKHR                                 xChromaOffset,
1753                                                                                                                         vk::VkChromaLocationKHR                                 yChromaOffset,
1754                                                                                                                         vk::VkFilter                                                    chromaFilter,
1755                                                                                                                         const vk::VkComponentMapping&                   componentMapping,
1756                                                                                                                         bool                                                                    explicitReconstruction)
1757 {
1758         const vk::VkSamplerYcbcrConversionCreateInfoKHR conversionInfo  =
1759         {
1760                 vk::VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR,
1761                 DE_NULL,
1762
1763                 format,
1764                 colorModel,
1765                 colorRange,
1766                 componentMapping,
1767                 xChromaOffset,
1768                 yChromaOffset,
1769                 chromaFilter,
1770                 explicitReconstruction ? VK_TRUE : VK_FALSE
1771         };
1772
1773         return vk::createSamplerYcbcrConversionKHR(vkd, device, &conversionInfo);
1774 }
1775
1776 void evalShader (Context&                                                               context,
1777                                  glu::ShaderType                                                shaderType,
1778                                  const MultiPlaneImageData&                             imageData,
1779                                  const UVec2&                                                   size,
1780                                  vk::VkFormat                                                   format,
1781                                  vk::VkImageTiling                                              imageTiling,
1782                                  bool                                                                   disjoint,
1783                                  vk::VkFilter                                                   textureFilter,
1784                                  vk::VkSamplerAddressMode                               addressModeU,
1785                                  vk::VkSamplerAddressMode                               addressModeV,
1786                                  vk::VkSamplerYcbcrModelConversionKHR   colorModel,
1787                                  vk::VkSamplerYcbcrRangeKHR                             colorRange,
1788                                  vk::VkChromaLocationKHR                                xChromaOffset,
1789                                  vk::VkChromaLocationKHR                                yChromaOffset,
1790                                  vk::VkFilter                                                   chromaFilter,
1791                                  const vk::VkComponentMapping&                  componentMapping,
1792                                  bool                                                                   explicitReconstruction,
1793                                  const vector<Vec2>&                                    sts,
1794                                  vector<Vec4>&                                                  results)
1795 {
1796         const vk::DeviceInterface&                                                      vkd                                     (context.getDeviceInterface());
1797         const vk::VkDevice                                                                      device                          (context.getDevice());
1798 #if !defined(FAKE_COLOR_CONVERSION)
1799         const vk::Unique<vk::VkSamplerYcbcrConversionKHR>       conversion                      (createConversion(vkd, device, format, colorModel, colorRange, xChromaOffset, yChromaOffset, chromaFilter, componentMapping, explicitReconstruction));
1800         const vk::Unique<vk::VkSampler>                                         sampler                         (createSampler(vkd, device, textureFilter, addressModeU, addressModeV, *conversion));
1801 #else
1802         DE_UNREF(colorModel);
1803         DE_UNREF(colorRange);
1804         DE_UNREF(xChromaOffset);
1805         DE_UNREF(yChromaOffset);
1806         DE_UNREF(chromaFilter);
1807         DE_UNREF(explicitReconstruction);
1808         DE_UNREF(componentMapping);
1809         DE_UNREF(createConversion);
1810         const vk::Unique<vk::VkSampler>                                         sampler                         (createSampler(vkd, device, textureFilter, addressModeU, addressModeV, (vk::VkSamplerYcbcrConversionKHR)0u));
1811 #endif
1812         const vk::Unique<vk::VkImage>                                           image                           (createImage(vkd, device, format, size, disjoint, imageTiling));
1813         const vk::MemoryRequirement                                                     memoryRequirement       (imageTiling == vk::VK_IMAGE_TILING_OPTIMAL
1814                                                                                                                                                         ? vk::MemoryRequirement::Any
1815                                                                                                                                                         : vk::MemoryRequirement::HostVisible);
1816         const vk::VkImageCreateFlags                                            createFlags                     (disjoint ? vk::VK_IMAGE_CREATE_DISJOINT_BIT_KHR : (vk::VkImageCreateFlagBits)0u);
1817         const vector<AllocationSp>                                                      imageMemory                     (allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags, memoryRequirement));
1818 #if defined(FAKE_COLOR_CONVERSION)
1819         const vk::Unique<vk::VkImageView>                                       imageView                       (createImageView(vkd, device, *image, format, (vk::VkSamplerYcbcrConversionKHR)0));
1820 #else
1821         const vk::Unique<vk::VkImageView>                                       imageView                       (createImageView(vkd, device, *image, format, *conversion));
1822 #endif
1823
1824         const vk::Unique<vk::VkDescriptorSetLayout>                     layout                          (createDescriptorSetLayout(vkd, device, *sampler));
1825         const vk::Unique<vk::VkDescriptorPool>                          descriptorPool          (createDescriptorPool(vkd, device));
1826         const vk::Unique<vk::VkDescriptorSet>                           descriptorSet           (createDescriptorSet(vkd, device, *descriptorPool, *layout, *sampler, *imageView));
1827
1828         const ShaderSpec                                                                        spec                            (createShaderSpec());
1829         const de::UniquePtr<ShaderExecutor>                                     executor                        (createExecutor(context, shaderType, spec, *layout));
1830
1831         if (imageTiling == vk::VK_IMAGE_TILING_OPTIMAL)
1832                 uploadImage(vkd, device, context.getUniversalQueueFamilyIndex(), context.getDefaultAllocator(), *image, imageData, vk::VK_ACCESS_SHADER_READ_BIT, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1833         else
1834                 fillImageMemory(vkd, device, context.getUniversalQueueFamilyIndex(), *image, imageMemory, imageData, vk::VK_ACCESS_SHADER_READ_BIT, vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1835
1836         results.resize(sts.size());
1837
1838         {
1839                 const void* const       inputs[]        =
1840                 {
1841                         &sts[0]
1842                 };
1843                 void* const                     outputs[]       =
1844                 {
1845                         &results[0]
1846                 };
1847
1848                 executor->execute((int)sts.size(), inputs, outputs, *descriptorSet);
1849         }
1850 }
1851
1852 bool isXChromaSubsampled (vk::VkFormat format)
1853 {
1854         switch (format)
1855         {
1856                 case vk::VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
1857                 case vk::VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
1858                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
1859                 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
1860                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
1861                 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
1862                 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
1863                 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
1864                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
1865                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
1866                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
1867                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
1868                 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
1869                 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
1870                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
1871                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
1872                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
1873                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
1874                 case vk::VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
1875                 case vk::VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
1876                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
1877                 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
1878                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
1879                 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
1880                         return true;
1881
1882                 default:
1883                         return false;
1884         }
1885 }
1886
1887 bool isYChromaSubsampled (vk::VkFormat format)
1888 {
1889         switch (format)
1890         {
1891                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
1892                 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
1893                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
1894                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
1895                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
1896                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
1897                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
1898                 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
1899                         return true;
1900
1901                 default:
1902                         return false;
1903         }
1904 }
1905
1906 void logTestCaseInfo (TestLog& log, const TestConfig& config)
1907 {
1908         log << TestLog::Message << "ShaderType: " << config.shaderType << TestLog::EndMessage;
1909         log << TestLog::Message << "Format: "  << config.format << TestLog::EndMessage;
1910         log << TestLog::Message << "ImageTiling: " << config.imageTiling << TestLog::EndMessage;
1911         log << TestLog::Message << "TextureFilter: " << config.textureFilter << TestLog::EndMessage;
1912         log << TestLog::Message << "AddressModeU: " << config.addressModeU << TestLog::EndMessage;
1913         log << TestLog::Message << "AddressModeV: " << config.addressModeV << TestLog::EndMessage;
1914         log << TestLog::Message << "ChromaFilter: " << config.chromaFilter << TestLog::EndMessage;
1915         log << TestLog::Message << "XChromaOffset: " << config.xChromaOffset << TestLog::EndMessage;
1916         log << TestLog::Message << "YChromaOffset: " << config.yChromaOffset << TestLog::EndMessage;
1917         log << TestLog::Message << "ExplicitReconstruction: " << (config.explicitReconstruction ? "true" : "false") << TestLog::EndMessage;
1918         log << TestLog::Message << "Disjoint: " << (config.explicitReconstruction ? "true" : "false") << TestLog::EndMessage;
1919         log << TestLog::Message << "ColorRange: " << config.colorRange << TestLog::EndMessage;
1920         log << TestLog::Message << "ColorModel: " << config.colorModel << TestLog::EndMessage;
1921         log << TestLog::Message << "ComponentMapping: " << config.componentMapping << TestLog::EndMessage;
1922 }
1923
1924
1925 tcu::TestStatus textureConversionTest (Context& context, const TestConfig config)
1926 {
1927         const FloatFormat       filteringPrecision              (getFilteringPrecision(config.format));
1928         const FloatFormat       conversionPrecision             (getConversionPrecision(config.format));
1929         const deUint32          subTexelPrecisionBits   (vk::getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits.subTexelPrecisionBits);
1930         const tcu::UVec4        bitDepth                                (getBitDepth(config.format));
1931         const UVec2                     size                                    (isXChromaSubsampled(config.format) ? 12 : 7,
1932                                                                                                  isYChromaSubsampled(config.format) ?  8 : 13);
1933         TestLog&                        log                                             (context.getTestContext().getLog());
1934         bool                            explicitReconstruction  = config.explicitReconstruction;
1935         bool                            isOk                                    = true;
1936
1937         logTestCaseInfo(log, config);
1938
1939 #if !defined(FAKE_COLOR_CONVERSION)
1940         if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), string("VK_KHR_sampler_ycbcr_conversion")))
1941                 TCU_THROW(NotSupportedError, "Extension VK_KHR_sampler_ycbcr_conversion not supported");
1942
1943         try
1944         {
1945                 const vk::VkFormatProperties    properties      (vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), config.format));
1946                 const vk::VkFormatFeatureFlags  features        (config.imageTiling == vk::VK_IMAGE_TILING_OPTIMAL
1947                                                                                                         ? properties.optimalTilingFeatures
1948                                                                                                         : properties.linearTilingFeatures);
1949
1950                 if ((features & (vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR | vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR)) == 0)
1951                         TCU_THROW(NotSupportedError, "Format doesn't support YCbCr conversions");
1952
1953                 if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) == 0)
1954                         TCU_THROW(NotSupportedError, "Format doesn't support sampling");
1955
1956                 if (config.textureFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR) == 0))
1957                         TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
1958
1959                 if (config.chromaFilter == vk::VK_FILTER_LINEAR && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR) == 0))
1960                         TCU_THROW(NotSupportedError, "Format doesn't support YCbCr linear chroma reconstruction");
1961
1962                 if (config.chromaFilter != config.textureFilter && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR) == 0))
1963                         TCU_THROW(NotSupportedError, "Format doesn't support different chroma and texture filters");
1964
1965                 if (config.explicitReconstruction && ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR) == 0))
1966                         TCU_THROW(NotSupportedError, "Format doesn't support explicit chroma reconstruction");
1967
1968                 if (config.disjoint && ((features & vk::VK_FORMAT_FEATURE_DISJOINT_BIT_KHR) == 0))
1969                         TCU_THROW(NotSupportedError, "Format doesn't disjoint planes");
1970
1971                 if (isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR) == 0))
1972                         TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
1973
1974                 if (isXChromaSubsampled(config.format) && (config.xChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT_KHR) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR) == 0))
1975                         TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
1976
1977                 if (isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR) && ((features & vk::VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR) == 0))
1978                         TCU_THROW(NotSupportedError, "Format doesn't support cosited chroma samples");
1979
1980                 if (isYChromaSubsampled(config.format) && (config.yChromaOffset == vk::VK_CHROMA_LOCATION_MIDPOINT_KHR) && ((features & vk::VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR) == 0))
1981                         TCU_THROW(NotSupportedError, "Format doesn't support midpoint chroma samples");
1982
1983                 if ((features & vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR) != 0)
1984                         explicitReconstruction = true;
1985
1986                 log << TestLog::Message << "FormatFeatures: " << vk::getFormatFeatureFlagsStr(features) << TestLog::EndMessage;
1987         }
1988         catch (const vk::Error& err)
1989         {
1990                 if (err.getError() == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
1991                         TCU_THROW(NotSupportedError, "Format not supported");
1992
1993                 throw;
1994         }
1995 #endif
1996
1997         {
1998                 const vk::PlanarFormatDescription       planeInfo                       (vk::getPlanarFormatDescription(config.format));
1999                 MultiPlaneImageData                                     src                                     (config.format, size);
2000
2001                 deUint32                                                        nullAccessData          (0u);
2002                 ChannelAccess                                           nullAccess                      (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, IVec3(size.x(), size.y(), 1), IVec3(0, 0, 0), &nullAccessData, 0u);
2003                 deUint32                                                        nullAccessAlphaData     (~0u);
2004                 ChannelAccess                                           nullAccessAlpha         (tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT, 1u, IVec3(size.x(), size.y(), 1), IVec3(0, 0, 0), &nullAccessAlphaData, 0u);
2005                 ChannelAccess                                           rChannelAccess          (planeInfo.hasChannelNdx(0) ? getChannelAccess(src, planeInfo, size, 0) : nullAccess);
2006                 ChannelAccess                                           gChannelAccess          (planeInfo.hasChannelNdx(1) ? getChannelAccess(src, planeInfo, size, 1) : nullAccess);
2007                 ChannelAccess                                           bChannelAccess          (planeInfo.hasChannelNdx(2) ? getChannelAccess(src, planeInfo, size, 2) : nullAccess);
2008                 ChannelAccess                                           aChannelAccess          (planeInfo.hasChannelNdx(3) ? getChannelAccess(src, planeInfo, size, 3) : nullAccessAlpha);
2009
2010                 vector<Vec2>                                            sts;
2011                 vector<Vec4>                                            results;
2012                 vector<Vec4>                                            minBounds;
2013                 vector<Vec4>                                            maxBounds;
2014                 vector<Vec4>                                            uvBounds;
2015                 vector<IVec4>                                           ijBounds;
2016
2017                 for (deUint32 planeNdx = 0; planeNdx < planeInfo.numPlanes; planeNdx++)
2018                         deMemset(src.getPlanePtr(planeNdx), 0u, src.getPlaneSize(planeNdx));
2019
2020                 // \todo Limit values to only values that produce defined values using selected colorRange and colorModel? The verification code handles those cases already correctly.
2021                 if (planeInfo.hasChannelNdx(0))
2022                 {
2023                         for (int y = 0; y < rChannelAccess.getSize().y(); y++)
2024                         for (int x = 0; x < rChannelAccess.getSize().x(); x++)
2025                                 rChannelAccess.setChannel(IVec3(x, y, 0), (float)x / (float)rChannelAccess.getSize().x());
2026                 }
2027
2028                 if (planeInfo.hasChannelNdx(1))
2029                 {
2030                         for (int y = 0; y < gChannelAccess.getSize().y(); y++)
2031                         for (int x = 0; x < gChannelAccess.getSize().x(); x++)
2032                                 gChannelAccess.setChannel(IVec3(x, y, 0), (float)y / (float)gChannelAccess.getSize().y());
2033                 }
2034
2035                 if (planeInfo.hasChannelNdx(2))
2036                 {
2037                         for (int y = 0; y < bChannelAccess.getSize().y(); y++)
2038                         for (int x = 0; x < bChannelAccess.getSize().x(); x++)
2039                                 bChannelAccess.setChannel(IVec3(x, y, 0), (float)(x + y) / (float)(bChannelAccess.getSize().x() + bChannelAccess.getSize().y()));
2040                 }
2041
2042                 if (planeInfo.hasChannelNdx(3))
2043                 {
2044                         for (int y = 0; y < aChannelAccess.getSize().y(); y++)
2045                         for (int x = 0; x < aChannelAccess.getSize().x(); x++)
2046                                 aChannelAccess.setChannel(IVec3(x, y, 0), (float)(x * y) / (float)(aChannelAccess.getSize().x() * aChannelAccess.getSize().y()));
2047                 }
2048
2049                 genTexCoords(sts, size);
2050
2051                 calculateBounds(rChannelAccess, gChannelAccess, bChannelAccess, aChannelAccess, bitDepth, sts, filteringPrecision, conversionPrecision, subTexelPrecisionBits, config.textureFilter, config.colorModel, config.colorRange, config.chromaFilter, config.xChromaOffset, config.yChromaOffset, config.componentMapping, explicitReconstruction, config.addressModeU, config.addressModeV, minBounds, maxBounds, uvBounds, ijBounds);
2052
2053                 if (vk::isYCbCrFormat(config.format))
2054                 {
2055                         tcu::TextureLevel       rImage  (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), rChannelAccess.getSize().x(), rChannelAccess.getSize().y());
2056                         tcu::TextureLevel       gImage  (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), gChannelAccess.getSize().x(), gChannelAccess.getSize().y());
2057                         tcu::TextureLevel       bImage  (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), bChannelAccess.getSize().x(), bChannelAccess.getSize().y());
2058                         tcu::TextureLevel       aImage  (tcu::TextureFormat(tcu::TextureFormat::R, tcu::TextureFormat::FLOAT), aChannelAccess.getSize().x(), aChannelAccess.getSize().y());
2059
2060                         for (int y = 0; y < (int)rChannelAccess.getSize().y(); y++)
2061                         for (int x = 0; x < (int)rChannelAccess.getSize().x(); x++)
2062                                 rImage.getAccess().setPixel(Vec4(rChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
2063
2064                         for (int y = 0; y < (int)gChannelAccess.getSize().y(); y++)
2065                         for (int x = 0; x < (int)gChannelAccess.getSize().x(); x++)
2066                                 gImage.getAccess().setPixel(Vec4(gChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
2067
2068                         for (int y = 0; y < (int)bChannelAccess.getSize().y(); y++)
2069                         for (int x = 0; x < (int)bChannelAccess.getSize().x(); x++)
2070                                 bImage.getAccess().setPixel(Vec4(bChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
2071
2072                         for (int y = 0; y < (int)aChannelAccess.getSize().y(); y++)
2073                         for (int x = 0; x < (int)aChannelAccess.getSize().x(); x++)
2074                                 aImage.getAccess().setPixel(Vec4(aChannelAccess.getChannel(IVec3(x, y, 0))), x, y);
2075
2076                         {
2077                                 const Vec4      scale   (1.0f);
2078                                 const Vec4      bias    (0.0f);
2079
2080                                 log << TestLog::Image("SourceImageR", "SourceImageR", rImage.getAccess(), scale, bias);
2081                                 log << TestLog::Image("SourceImageG", "SourceImageG", gImage.getAccess(), scale, bias);
2082                                 log << TestLog::Image("SourceImageB", "SourceImageB", bImage.getAccess(), scale, bias);
2083                                 log << TestLog::Image("SourceImageA", "SourceImageA", aImage.getAccess(), scale, bias);
2084                         }
2085                 }
2086                 else
2087                 {
2088                         tcu::TextureLevel       srcImage        (vk::mapVkFormat(config.format), size.x(), size.y());
2089
2090                         for (int y = 0; y < (int)size.y(); y++)
2091                         for (int x = 0; x < (int)size.x(); x++)
2092                         {
2093                                 const IVec3 pos (x, y, 0);
2094                                 srcImage.getAccess().setPixel(Vec4(rChannelAccess.getChannel(pos), gChannelAccess.getChannel(pos), bChannelAccess.getChannel(pos), aChannelAccess.getChannel(pos)), x, y);
2095                         }
2096
2097                         log << TestLog::Image("SourceImage", "SourceImage", srcImage.getAccess());
2098                 }
2099
2100                 evalShader(context, config.shaderType, src, size, config.format, config.imageTiling, config.disjoint, config.textureFilter, config.addressModeU, config.addressModeV, config.colorModel, config.colorRange, config.xChromaOffset, config.yChromaOffset, config.chromaFilter, config.componentMapping, config.explicitReconstruction, sts, results);
2101
2102                 {
2103                         tcu::TextureLevel       minImage        (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x() + (size.x() / 2), size.y() + (size.y() / 2));
2104                         tcu::TextureLevel       maxImage        (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x() + (size.x() / 2), size.y() + (size.y() / 2));
2105                         tcu::TextureLevel       resImage        (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::FLOAT), size.x() + (size.x() / 2), size.y() + (size.y() / 2));
2106
2107                         for (int y = 0; y < (int)(size.y() + (size.y() / 2)); y++)
2108                         for (int x = 0; x < (int)(size.x() + (size.x() / 2)); x++)
2109                         {
2110                                 const int ndx = x + y * (int)(size.x() + (size.x() / 2));
2111                                 minImage.getAccess().setPixel(minBounds[ndx], x, y);
2112                                 maxImage.getAccess().setPixel(maxBounds[ndx], x, y);
2113                         }
2114
2115                         for (int y = 0; y < (int)(size.y() + (size.y() / 2)); y++)
2116                         for (int x = 0; x < (int)(size.x() + (size.x() / 2)); x++)
2117                         {
2118                                 const int ndx = x + y * (int)(size.x() + (size.x() / 2));
2119                                 resImage.getAccess().setPixel(results[ndx], x, y);
2120                         }
2121
2122                         {
2123                                 const Vec4      scale   (1.0f);
2124                                 const Vec4      bias    (0.0f);
2125
2126                                 log << TestLog::Image("MinBoundImage", "MinBoundImage", minImage.getAccess(), scale, bias);
2127                                 log << TestLog::Image("MaxBoundImage", "MaxBoundImage", maxImage.getAccess(), scale, bias);
2128                                 log << TestLog::Image("ResultImage", "ResultImage", resImage.getAccess(), scale, bias);
2129                         }
2130                 }
2131
2132                 size_t errorCount = 0;
2133
2134                 for (size_t ndx = 0; ndx < sts.size(); ndx++)
2135                 {
2136                         if (tcu::boolAny(tcu::lessThan(results[ndx], minBounds[ndx])) || tcu::boolAny(tcu::greaterThan(results[ndx], maxBounds[ndx])))
2137                         {
2138                                 log << TestLog::Message << "Fail: " << sts[ndx] << " " << results[ndx] << TestLog::EndMessage;
2139                                 log << TestLog::Message << "  Min : " << minBounds[ndx] << TestLog::EndMessage;
2140                                 log << TestLog::Message << "  Max : " << maxBounds[ndx] << TestLog::EndMessage;
2141                                 log << TestLog::Message << "  Threshold: " << (maxBounds[ndx] - minBounds[ndx]) << TestLog::EndMessage;
2142                                 log << TestLog::Message << "  UMin : " << uvBounds[ndx][0] << TestLog::EndMessage;
2143                                 log << TestLog::Message << "  UMax : " << uvBounds[ndx][1] << TestLog::EndMessage;
2144                                 log << TestLog::Message << "  VMin : " << uvBounds[ndx][2] << TestLog::EndMessage;
2145                                 log << TestLog::Message << "  VMax : " << uvBounds[ndx][3] << TestLog::EndMessage;
2146                                 log << TestLog::Message << "  IMin : " << ijBounds[ndx][0] << TestLog::EndMessage;
2147                                 log << TestLog::Message << "  IMax : " << ijBounds[ndx][1] << TestLog::EndMessage;
2148                                 log << TestLog::Message << "  JMin : " << ijBounds[ndx][2] << TestLog::EndMessage;
2149                                 log << TestLog::Message << "  JMax : " << ijBounds[ndx][3] << TestLog::EndMessage;
2150
2151                                 if (isXChromaSubsampled(config.format))
2152                                 {
2153                                         log << TestLog::Message << "  LumaAlphaValues : " << TestLog::EndMessage;
2154                                         log << TestLog::Message << "    Offset : (" << ijBounds[ndx][0] << ", " << ijBounds[ndx][2] << ")" << TestLog::EndMessage;
2155
2156                                         for (deInt32 j = ijBounds[ndx][2]; j <= ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++)
2157                                         {
2158                                                 const deInt32           wrappedJ        = wrap(config.addressModeV, j, gChannelAccess.getSize().y());
2159                                                 bool                            first           = true;
2160                                                 std::ostringstream      line;
2161
2162                                                 for (deInt32 i = ijBounds[ndx][0]; i <= ijBounds[ndx][1] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); i++)
2163                                                 {
2164                                                         const deInt32   wrappedI        = wrap(config.addressModeU, i, gChannelAccess.getSize().x());
2165
2166                                                         if (!first)
2167                                                         {
2168                                                                 line << ", ";
2169                                                                 first = false;
2170                                                         }
2171
2172                                                         line << "(" << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
2173                                                                 << ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0)) << ")";
2174                                                 }
2175                                                 log << TestLog::Message << "    " << line.str() << TestLog::EndMessage;
2176                                         }
2177
2178                                         {
2179                                                 const IVec2 chromaIRange        (divFloor(ijBounds[ndx][0], 2) - 1, divFloor(ijBounds[ndx][1] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1);
2180                                                 const IVec2 chromaJRange        (isYChromaSubsampled(config.format)
2181                                                                                                         ? IVec2(divFloor(ijBounds[ndx][2], 2) - 1, divFloor(ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0), 2) + 1)
2182                                                                                                         : IVec2(ijBounds[ndx][2], ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0)));
2183
2184                                                 log << TestLog::Message << "  ChromaValues : " << TestLog::EndMessage;
2185                                                 log << TestLog::Message << "    Offset : (" << chromaIRange[0] << ", " << chromaJRange[0] << ")" << TestLog::EndMessage;
2186
2187                                                 for (deInt32 j = chromaJRange[0]; j <= chromaJRange[1]; j++)
2188                                                 {
2189                                                         const deInt32           wrappedJ        = wrap(config.addressModeV, j, rChannelAccess.getSize().y());
2190                                                         bool                            first           = true;
2191                                                         std::ostringstream      line;
2192
2193                                                         for (deInt32 i = chromaIRange[0]; i <= chromaIRange[1]; i++)
2194                                                         {
2195                                                                 const deInt32   wrappedI        = wrap(config.addressModeU, i, rChannelAccess.getSize().x());
2196
2197                                                                 if (!first)
2198                                                                 {
2199                                                                         line << ", ";
2200                                                                         first = false;
2201                                                                 }
2202
2203                                                                 line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
2204                                                                         << ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0)) << ")";
2205                                                         }
2206                                                         log << TestLog::Message << "    " << line.str() << TestLog::EndMessage;
2207                                                 }
2208                                         }
2209                                 }
2210                                 else
2211                                 {
2212                                         log << TestLog::Message << "  Values : " << TestLog::EndMessage;
2213                                         log << TestLog::Message << "    Offset : (" << ijBounds[ndx][0] << ", " << ijBounds[ndx][2] << ")" << TestLog::EndMessage;
2214
2215                                         for (deInt32 j = ijBounds[ndx][2]; j <= ijBounds[ndx][3] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); j++)
2216                                         {
2217                                                 const deInt32           wrappedJ        = wrap(config.addressModeV, j, rChannelAccess.getSize().y());
2218                                                 bool                            first           = true;
2219                                                 std::ostringstream      line;
2220
2221                                                 for (deInt32 i = ijBounds[ndx][0]; i <= ijBounds[ndx][1] + (config.textureFilter == vk::VK_FILTER_LINEAR ? 1 : 0); i++)
2222                                                 {
2223                                                         const deInt32   wrappedI        = wrap(config.addressModeU, i, rChannelAccess.getSize().x());
2224
2225                                                         if (!first)
2226                                                         {
2227                                                                 line << ", ";
2228                                                                 first = false;
2229                                                         }
2230
2231                                                         line << "(" << std::setfill(' ') << std::setw(5) << rChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
2232                                                                 << ", " << std::setfill(' ') << std::setw(5) << gChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
2233                                                                 << ", " << std::setfill(' ') << std::setw(5) << bChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0))
2234                                                                 << ", " << std::setfill(' ') << std::setw(5) << aChannelAccess.getChannelUint(IVec3(wrappedI, wrappedJ, 0)) << ")";
2235                                                 }
2236                                                 log << TestLog::Message << "    " << line.str() << TestLog::EndMessage;
2237                                         }
2238                                 }
2239
2240                                 errorCount++;
2241                                 isOk = false;
2242
2243                                 if (errorCount > 30)
2244                                 {
2245                                         log << TestLog::Message << "Encountered " << errorCount << " errors. Omitting rest of the per result logs." << TestLog::EndMessage;
2246                                         break;
2247                                 }
2248                         }
2249                 }
2250         }
2251
2252         if (isOk)
2253                 return tcu::TestStatus::pass("Pass");
2254         else
2255                 return tcu::TestStatus::fail("Result comparison failed");
2256 }
2257
2258 #if defined(FAKE_COLOR_CONVERSION)
2259 const char* swizzleToCompName (const char* identity, vk::VkComponentSwizzle swizzle)
2260 {
2261         switch (swizzle)
2262         {
2263                 case vk::VK_COMPONENT_SWIZZLE_IDENTITY: return identity;
2264                 case vk::VK_COMPONENT_SWIZZLE_R:                return "r";
2265                 case vk::VK_COMPONENT_SWIZZLE_G:                return "g";
2266                 case vk::VK_COMPONENT_SWIZZLE_B:                return "b";
2267                 case vk::VK_COMPONENT_SWIZZLE_A:                return "a";
2268                 default:
2269                         DE_FATAL("Unsupported swizzle");
2270                         return DE_NULL;
2271         }
2272 }
2273 #endif
2274
2275 void createTestShaders (vk::SourceCollections& dst, TestConfig config)
2276 {
2277 #if !defined(FAKE_COLOR_CONVERSION)
2278         const ShaderSpec spec (createShaderSpec());
2279
2280         generateSources(config.shaderType, spec, dst);
2281 #else
2282         const UVec4     bits    (getBitDepth(config.format));
2283         ShaderSpec      spec;
2284
2285         spec.globalDeclarations = "layout(set=" + de::toString((int)EXTRA_RESOURCES_DESCRIPTOR_SET_INDEX) + ", binding=0) uniform highp sampler2D u_sampler;";
2286
2287         spec.inputs.push_back(Symbol("uv", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
2288         spec.outputs.push_back(Symbol("o_color", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
2289
2290         std::ostringstream      source;
2291
2292         source << "highp vec4 inputColor = texture(u_sampler, uv);\n";
2293
2294         source << "highp float r = inputColor." << swizzleToCompName("r", config.componentMapping.r) << ";\n";
2295         source << "highp float g = inputColor." << swizzleToCompName("g", config.componentMapping.g) << ";\n";
2296         source << "highp float b = inputColor." << swizzleToCompName("b", config.componentMapping.b) << ";\n";
2297         source << "highp float a = inputColor." << swizzleToCompName("a", config.componentMapping.a) << ";\n";
2298
2299         switch (config.colorRange)
2300         {
2301                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR:
2302                         source << "highp float cr = r - (float(" << (0x1u << (bits[0] - 0x1u)) << ") / float(" << ((0x1u << bits[0]) - 1u) << "));\n";
2303                         source << "highp float y  = g;\n";
2304                         source << "highp float cb = b - (float(" << (0x1u << (bits[2] - 0x1u)) << ") / float(" << ((0x1u << bits[2]) - 1u) << "));\n";
2305                         break;
2306
2307                 case vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR:
2308                         source << "highp float cr = (r * float(" << ((0x1u << bits[0]) - 1u) << ") - float(" << (128u * (0x1u << (bits[0] - 8))) << ")) / float(" << (224u * (0x1u << (bits[0] - 8))) << ");\n";
2309                         source << "highp float y  = (g * float(" << ((0x1u << bits[1]) - 1u) << ") - float(" << (16u * (0x1u << (bits[1] - 8))) << ")) / float(" << (219u * (0x1u << (bits[1] - 8))) << ");\n";
2310                         source << "highp float cb = (b * float(" << ((0x1u << bits[2]) - 1u) << ") - float(" << (128u * (0x1u << (bits[2] - 8))) << ")) / float(" << (224u * (0x1u << (bits[2] - 8))) << ");\n";
2311                         break;
2312
2313                 default:
2314                         DE_FATAL("Unknown color range");
2315         }
2316
2317         source << "highp vec4 color;\n";
2318
2319         switch (config.colorModel)
2320         {
2321                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR:
2322                         source << "color = vec4(r, g, b, a);\n";
2323                         break;
2324
2325                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR:
2326                         source << "color = vec4(cr, y, cb, a);\n";
2327                         break;
2328
2329                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR:
2330                         source << "color = vec4(y + 1.402 * cr, y - float(" << (0.202008 / 0.587) << ") * cb - float(" << (0.419198 / 0.587) << ") * cr, y + 1.772 * cb, a);\n";
2331                         break;
2332
2333                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR:
2334                         source << "color = vec4(y + 1.5748 * cr, y - float(" << (0.13397432 / 0.7152) << ") * cb - float(" << (0.33480248 / 0.7152) << ") * cr, y + 1.8556 * cb, a);\n";
2335                         break;
2336
2337                 case vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR:
2338                         source << "color = vec4(y + 1.4746 * cr, (y - float(" << (0.11156702 / 0.6780) << ") * cb) - float(" << (0.38737742 / 0.6780) << ") * cr, y + 1.8814 * cb, a);\n";
2339                         break;
2340
2341                 default:
2342                         DE_FATAL("Unknown color model");
2343         };
2344
2345         source << "o_color = color;\n";
2346
2347         spec.source = source.str();
2348         generateSources(config.shaderType, spec, dst);
2349 #endif
2350 }
2351
2352 deUint32 getFormatChannelCount (vk::VkFormat format)
2353 {
2354         switch (format)
2355         {
2356                 case vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16:
2357                 case vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32:
2358                 case vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32:
2359                 case vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32:
2360                 case vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16:
2361                 case vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16:
2362                 case vk::VK_FORMAT_B8G8R8A8_UNORM:
2363                 case vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
2364                 case vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
2365                 case vk::VK_FORMAT_R16G16B16A16_UNORM:
2366                 case vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16:
2367                 case vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16:
2368                 case vk::VK_FORMAT_R8G8B8A8_UNORM:
2369                         return 4;
2370
2371                 case vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
2372                 case vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
2373                 case vk::VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
2374                 case vk::VK_FORMAT_B5G6R5_UNORM_PACK16:
2375                 case vk::VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
2376                 case vk::VK_FORMAT_B8G8R8_UNORM:
2377                 case vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
2378                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
2379                 case vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
2380                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
2381                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
2382                 case vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
2383                 case vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
2384                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
2385                 case vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
2386                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
2387                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
2388                 case vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
2389                 case vk::VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
2390                 case vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
2391                 case vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
2392                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
2393                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
2394                 case vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
2395                 case vk::VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
2396                 case vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
2397                 case vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
2398                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
2399                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
2400                 case vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
2401                 case vk::VK_FORMAT_R16G16B16_UNORM:
2402                 case vk::VK_FORMAT_R5G6B5_UNORM_PACK16:
2403                 case vk::VK_FORMAT_R8G8B8_UNORM:
2404                         return 3;
2405
2406                 case vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
2407                 case vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
2408                         return 2;
2409
2410                 case vk::VK_FORMAT_R10X6_UNORM_PACK16_KHR:
2411                 case vk::VK_FORMAT_R12X4_UNORM_PACK16_KHR:
2412                         return 1;
2413
2414                 default:
2415                         DE_FATAL("Unknown number of channels");
2416                         return -1;
2417         }
2418 }
2419
2420 struct RangeNamePair
2421 {
2422         const char*                                     name;
2423         vk::VkSamplerYcbcrRangeKHR      value;
2424 };
2425
2426
2427 struct ChromaLocationNamePair
2428 {
2429         const char*                             name;
2430         vk::VkChromaLocationKHR value;
2431 };
2432
2433 void initTests (tcu::TestCaseGroup* testGroup)
2434 {
2435         const vk::VkFormat noChromaSubsampledFormats[] =
2436         {
2437                 vk::VK_FORMAT_R4G4B4A4_UNORM_PACK16,
2438                 vk::VK_FORMAT_B4G4R4A4_UNORM_PACK16,
2439                 vk::VK_FORMAT_R5G6B5_UNORM_PACK16,
2440                 vk::VK_FORMAT_B5G6R5_UNORM_PACK16,
2441                 vk::VK_FORMAT_R5G5B5A1_UNORM_PACK16,
2442                 vk::VK_FORMAT_B5G5R5A1_UNORM_PACK16,
2443                 vk::VK_FORMAT_A1R5G5B5_UNORM_PACK16,
2444                 vk::VK_FORMAT_R8G8B8_UNORM,
2445                 vk::VK_FORMAT_B8G8R8_UNORM,
2446                 vk::VK_FORMAT_R8G8B8A8_UNORM,
2447                 vk::VK_FORMAT_B8G8R8A8_UNORM,
2448                 vk::VK_FORMAT_A8B8G8R8_UNORM_PACK32,
2449                 vk::VK_FORMAT_A2R10G10B10_UNORM_PACK32,
2450                 vk::VK_FORMAT_A2B10G10R10_UNORM_PACK32,
2451                 vk::VK_FORMAT_R16G16B16_UNORM,
2452                 vk::VK_FORMAT_R16G16B16A16_UNORM,
2453                 vk::VK_FORMAT_R10X6_UNORM_PACK16_KHR,
2454                 vk::VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR,
2455                 vk::VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR,
2456                 vk::VK_FORMAT_R12X4_UNORM_PACK16_KHR,
2457                 vk::VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR,
2458                 vk::VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR,
2459                 vk::VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR,
2460                 vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR,
2461                 vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR,
2462                 vk::VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR
2463         };
2464         const vk::VkFormat xChromaSubsampledFormats[] =
2465         {
2466                 vk::VK_FORMAT_G8B8G8R8_422_UNORM_KHR,
2467                 vk::VK_FORMAT_B8G8R8G8_422_UNORM_KHR,
2468                 vk::VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR,
2469                 vk::VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR,
2470
2471                 vk::VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR,
2472                 vk::VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR,
2473                 vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR,
2474                 vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR,
2475                 vk::VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR,
2476                 vk::VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR,
2477                 vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR,
2478                 vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR,
2479                 vk::VK_FORMAT_G16B16G16R16_422_UNORM_KHR,
2480                 vk::VK_FORMAT_B16G16R16G16_422_UNORM_KHR,
2481                 vk::VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR,
2482                 vk::VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR,
2483         };
2484         const vk::VkFormat xyChromaSubsampledFormats[] =
2485         {
2486                 vk::VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR,
2487                 vk::VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR,
2488                 vk::VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR,
2489                 vk::VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR,
2490                 vk::VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR,
2491                 vk::VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR,
2492                 vk::VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR,
2493                 vk::VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR,
2494         };
2495         const struct
2496         {
2497                 const char* const                                                       name;
2498                 const vk::VkSamplerYcbcrModelConversionKHR      value;
2499         } colorModels[] =
2500         {
2501                 { "rgb_identity",       vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR          },
2502                 { "ycbcr_identity",     vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR        },
2503                 { "ycbcr_709",          vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR                     },
2504                 { "ycbcr_601",          vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR                     },
2505                 { "ycbcr_2020",         vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR            }
2506         };
2507         const RangeNamePair colorRanges[]       =
2508         {
2509                 { "itu_full",           vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR         },
2510                 { "itu_narrow",         vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR       }
2511         };
2512         const ChromaLocationNamePair chromaLocations[] =
2513         {
2514                 { "cosited",            vk::VK_CHROMA_LOCATION_COSITED_EVEN_KHR },
2515                 { "midpoint",           vk::VK_CHROMA_LOCATION_MIDPOINT_KHR             }
2516         };
2517         const struct
2518         {
2519                 const char* const       name;
2520                 vk::VkFilter            value;
2521         } textureFilters[] =
2522         {
2523                 { "linear",                     vk::VK_FILTER_LINEAR    },
2524                 { "nearest",            vk::VK_FILTER_NEAREST   }
2525         };
2526         // Used by the chroma reconstruction tests
2527         const vk::VkSamplerYcbcrModelConversionKHR      defaultColorModel               (vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR);
2528         const vk::VkSamplerYcbcrRangeKHR                        defaultColorRange               (vk::VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR);
2529         const vk::VkComponentMapping                            identitySwizzle                 =
2530         {
2531                 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
2532                 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
2533                 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
2534                 vk::VK_COMPONENT_SWIZZLE_IDENTITY
2535         };
2536         const vk::VkComponentMapping                            swappedChromaSwizzle    =
2537         {
2538                 vk::VK_COMPONENT_SWIZZLE_B,
2539                 vk::VK_COMPONENT_SWIZZLE_IDENTITY,
2540                 vk::VK_COMPONENT_SWIZZLE_R,
2541                 vk::VK_COMPONENT_SWIZZLE_IDENTITY
2542         };
2543         const glu::ShaderType                                           shaderTypes[]                   =
2544         {
2545                 glu::SHADERTYPE_VERTEX,
2546                 glu::SHADERTYPE_FRAGMENT,
2547                 glu::SHADERTYPE_COMPUTE
2548         };
2549         const struct
2550         {
2551                 const char*                     name;
2552                 vk::VkImageTiling       value;
2553         }                                                                                       imageTilings[]                  =
2554         {
2555                 { "tiling_linear",      vk::VK_IMAGE_TILING_LINEAR },
2556                 { "tiling_optimal",     vk::VK_IMAGE_TILING_OPTIMAL }
2557         };
2558         tcu::TestContext&                                                       testCtx                                 (testGroup->getTestContext());
2559         de::Random                                                                      rng                                             (1978765638u);
2560
2561         // Test formats without chroma reconstruction
2562         for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(noChromaSubsampledFormats); formatNdx++)
2563         {
2564                 const vk::VkFormat                              format          (noChromaSubsampledFormats[formatNdx]);
2565                 const std::string                               formatName      (de::toLower(std::string(getFormatName(format)).substr(10)));
2566                 de::MovePtr<tcu::TestCaseGroup> formatGroup     (new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
2567
2568                 for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
2569                 {
2570                         const char* const                                                       colorModelName  (colorModels[modelNdx].name);
2571                         const vk::VkSamplerYcbcrModelConversionKHR      colorModel              (colorModels[modelNdx].value);
2572
2573                         if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR && getFormatChannelCount(format) < 3)
2574                                 continue;
2575
2576                         de::MovePtr<tcu::TestCaseGroup>                         colorModelGroup (new tcu::TestCaseGroup(testCtx, colorModelName, ("Tests for color model " + string(colorModelName)).c_str()));
2577
2578                         if (colorModel == vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR)
2579                         {
2580                                 for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
2581                                 {
2582                                         const char* const                                       textureFilterName       (textureFilters[textureFilterNdx].name);
2583                                         const vk::VkFilter                                      textureFilter           (textureFilters[textureFilterNdx].value);
2584
2585                                         for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2586                                         {
2587                                                 const vk::VkImageTiling                         tiling                          (imageTilings[tilingNdx].value);
2588                                                 const char* const                                       tilingName                      (imageTilings[tilingNdx].name);
2589                                                 const glu::ShaderType                           shaderType                      (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2590                                                 const vk::VkSamplerYcbcrRangeKHR        colorRange                      (rng.choose<RangeNamePair, const RangeNamePair*>(DE_ARRAY_BEGIN(colorRanges), DE_ARRAY_END(colorRanges)).value);
2591                                                 const vk::VkChromaLocationKHR           chromaLocation          (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2592
2593                                                 const TestConfig                                        config                          (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2594                                                                                                                                                                         textureFilter, chromaLocation, chromaLocation, false, false,
2595                                                                                                                                                                         colorRange, colorModel, identitySwizzle);
2596
2597                                                 addFunctionCaseWithPrograms(colorModelGroup.get(), std::string(textureFilterName) + "_" + tilingName, "", createTestShaders, textureConversionTest, config);
2598                                         }
2599                                 }
2600                         }
2601                         else
2602                         {
2603                                 for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
2604                                 {
2605                                         const char* const                                       colorRangeName  (colorRanges[rangeNdx].name);
2606                                         const vk::VkSamplerYcbcrRangeKHR        colorRange              (colorRanges[rangeNdx].value);
2607
2608                                         // Narrow range doesn't really work with formats that have less than 8 bits
2609                                         if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR)
2610                                         {
2611                                                 const UVec4     bitDepth        (getBitDepth(format));
2612
2613                                                 if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
2614                                                         continue;
2615                                         }
2616
2617                                         de::MovePtr<tcu::TestCaseGroup>         colorRangeGroup (new tcu::TestCaseGroup(testCtx, colorRangeName, ("Tests for color range " + string(colorRangeName)).c_str()));
2618
2619                                         for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
2620                                         {
2621                                                 const char* const                               textureFilterName       (textureFilters[textureFilterNdx].name);
2622                                                 const vk::VkFilter                              textureFilter           (textureFilters[textureFilterNdx].value);
2623
2624                                                 for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2625                                                 {
2626                                                         const vk::VkImageTiling                 tiling                          (imageTilings[tilingNdx].value);
2627                                                         const char* const                               tilingName                      (imageTilings[tilingNdx].name);
2628                                                         const glu::ShaderType                   shaderType                      (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2629                                                         const vk::VkChromaLocationKHR   chromaLocation          (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2630                                                         const TestConfig                                config                          (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2631                                                                                                                                                                         textureFilter, chromaLocation, chromaLocation, false, false,
2632                                                                                                                                                                         colorRange, colorModel, identitySwizzle);
2633
2634                                                         addFunctionCaseWithPrograms(colorRangeGroup.get(), std::string(textureFilterName) + "_" + tilingName, "", createTestShaders, textureConversionTest, config);
2635                                                 }
2636                                         }
2637
2638                                         colorModelGroup->addChild(colorRangeGroup.release());
2639                                 }
2640                         }
2641
2642                         formatGroup->addChild(colorModelGroup.release());
2643                 }
2644
2645                 testGroup->addChild(formatGroup.release());
2646         }
2647
2648         // Test formats with x chroma reconstruction
2649         for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(xChromaSubsampledFormats); formatNdx++)
2650         {
2651                 const vk::VkFormat                              format          (xChromaSubsampledFormats[formatNdx]);
2652                 const std::string                               formatName      (de::toLower(std::string(getFormatName(format)).substr(10)));
2653                 de::MovePtr<tcu::TestCaseGroup> formatGroup     (new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
2654
2655                 // Color conversion tests
2656                 {
2657                         de::MovePtr<tcu::TestCaseGroup> conversionGroup (new tcu::TestCaseGroup(testCtx, "color_conversion", ""));
2658
2659                         for (size_t xChromaOffsetNdx = 0; xChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); xChromaOffsetNdx++)
2660                         {
2661                                 const char* const                               xChromaOffsetName       (chromaLocations[xChromaOffsetNdx].name);
2662                                 const vk::VkChromaLocationKHR   xChromaOffset           (chromaLocations[xChromaOffsetNdx].value);
2663
2664                                 for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
2665                                 {
2666                                         const char* const                                                       colorModelName  (colorModels[modelNdx].name);
2667                                         const vk::VkSamplerYcbcrModelConversionKHR      colorModel              (colorModels[modelNdx].value);
2668
2669                                         if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR && getFormatChannelCount(format) < 3)
2670                                                 continue;
2671
2672
2673                                         if (colorModel == vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR)
2674                                         {
2675                                                 for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2676                                                 {
2677                                                         const vk::VkImageTiling                         tiling                  (imageTilings[tilingNdx].value);
2678                                                         const char* const                                       tilingName              (imageTilings[tilingNdx].name);
2679                                                         const vk::VkSamplerYcbcrRangeKHR        colorRange              (rng.choose<RangeNamePair, const RangeNamePair*>(DE_ARRAY_BEGIN(colorRanges), DE_ARRAY_END(colorRanges)).value);
2680                                                         const glu::ShaderType                           shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2681                                                         const vk::VkChromaLocationKHR           yChromaOffset   (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2682                                                         const TestConfig                                        config                  (shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2683                                                                                                                                                                  vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, false, false,
2684                                                                                                                                                                  colorRange, colorModel, identitySwizzle);
2685
2686                                                         addFunctionCaseWithPrograms(conversionGroup.get(), std::string(colorModelName) + "_" + tilingName + "_" + xChromaOffsetName, "", createTestShaders, textureConversionTest, config);
2687                                                 }
2688                                         }
2689                                         else
2690                                         {
2691                                                 for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
2692                                                 {
2693                                                         const char* const                                       colorRangeName  (colorRanges[rangeNdx].name);
2694                                                         const vk::VkSamplerYcbcrRangeKHR        colorRange              (colorRanges[rangeNdx].value);
2695
2696                                                         // Narrow range doesn't really work with formats that have less than 8 bits
2697                                                         if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR)
2698                                                         {
2699                                                                 const UVec4     bitDepth        (getBitDepth(format));
2700
2701                                                                 if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
2702                                                                         continue;
2703                                                         }
2704
2705                                                         for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2706                                                         {
2707                                                                 const vk::VkImageTiling                 tiling                  (imageTilings[tilingNdx].value);
2708                                                                 const char* const                               tilingName              (imageTilings[tilingNdx].name);
2709                                                                 const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2710                                                                 const vk::VkChromaLocationKHR   yChromaOffset   (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2711                                                                 const TestConfig                                config                  (shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2712                                                                                                                                                                 vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, false, false,
2713                                                                                                                                                                 colorRange, colorModel, identitySwizzle);
2714
2715                                                                 addFunctionCaseWithPrograms(conversionGroup.get(), (string(colorModelName) + "_" + colorRangeName + "_" + tilingName + "_" + xChromaOffsetName).c_str(), "", createTestShaders, textureConversionTest, config);
2716                                                         }
2717                                                 }
2718                                         }
2719                                 }
2720                         }
2721
2722                         formatGroup->addChild(conversionGroup.release());
2723                 }
2724
2725                 // Chroma reconstruction tests
2726                 {
2727                         de::MovePtr<tcu::TestCaseGroup> reconstrucGroup (new tcu::TestCaseGroup(testCtx, "chroma_reconstruction", ""));
2728
2729                         for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
2730                         {
2731                                 const char* const                               textureFilterName       (textureFilters[textureFilterNdx].name);
2732                                 const vk::VkFilter                              textureFilter           (textureFilters[textureFilterNdx].value);
2733                                 de::MovePtr<tcu::TestCaseGroup> textureFilterGroup      (new tcu::TestCaseGroup(testCtx, textureFilterName, textureFilterName));
2734
2735                                 for (size_t explicitReconstructionNdx = 0; explicitReconstructionNdx < 2; explicitReconstructionNdx++)
2736                                 {
2737                                         const bool      explicitReconstruction  (explicitReconstructionNdx == 1);
2738
2739                                         for (size_t disjointNdx = 0; disjointNdx < 2; disjointNdx++)
2740                                         {
2741                                                 const bool      disjoint        (disjointNdx == 1);
2742
2743                                                 for (size_t xChromaOffsetNdx = 0; xChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); xChromaOffsetNdx++)
2744                                                 {
2745                                                         const vk::VkChromaLocationKHR   xChromaOffset           (chromaLocations[xChromaOffsetNdx].value);
2746                                                         const char* const                               xChromaOffsetName       (chromaLocations[xChromaOffsetNdx].name);
2747
2748                                                         for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2749                                                         {
2750                                                                 const vk::VkImageTiling tiling          (imageTilings[tilingNdx].value);
2751                                                                 const char* const               tilingName      (imageTilings[tilingNdx].name);
2752
2753                                                                 {
2754                                                                         const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2755                                                                         const vk::VkChromaLocationKHR   yChromaOffset   (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2756                                                                         const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2757                                                                                                                                                                                 vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2758                                                                                                                                                                                 defaultColorRange, defaultColorModel, identitySwizzle);
2759
2760                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", createTestShaders, textureConversionTest, config);
2761                                                                 }
2762
2763                                                                 {
2764                                                                         const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2765                                                                         const vk::VkChromaLocationKHR   yChromaOffset   (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2766                                                                         const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2767                                                                                                                                                                                 vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2768                                                                                                                                                                                 defaultColorRange, defaultColorModel, swappedChromaSwizzle);
2769
2770                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", createTestShaders, textureConversionTest, config);
2771                                                                 }
2772
2773                                                                 if (!explicitReconstruction)
2774                                                                 {
2775                                                                         {
2776                                                                                 const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2777                                                                                 const vk::VkChromaLocationKHR   yChromaOffset   (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2778                                                                                 const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2779                                                                                                                                                                                         vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2780                                                                                                                                                                                         defaultColorRange, defaultColorModel, identitySwizzle);
2781
2782                                                                                 addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", createTestShaders, textureConversionTest, config);
2783                                                                         }
2784
2785                                                                         {
2786                                                                                 const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2787                                                                                 const vk::VkChromaLocationKHR   yChromaOffset   (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2788                                                                                 const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2789                                                                                                                                                                                         vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2790                                                                                                                                                                                         defaultColorRange, defaultColorModel, swappedChromaSwizzle);
2791
2792                                                                                 addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", createTestShaders, textureConversionTest, config);
2793                                                                         }
2794                                                                 }
2795                                                         }
2796                                                 }
2797
2798                                                 if (explicitReconstruction)
2799                                                 {
2800                                                         for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2801                                                         {
2802                                                                 const vk::VkImageTiling tiling          (imageTilings[tilingNdx].value);
2803                                                                 const char* const               tilingName      (imageTilings[tilingNdx].name);
2804                                                                 {
2805                                                                         const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2806                                                                         const vk::VkChromaLocationKHR   chromaLocation  (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2807                                                                         const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2808                                                                                                                                                                                 vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
2809                                                                                                                                                                                 defaultColorRange, defaultColorModel, identitySwizzle);
2810
2811                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", createTestShaders, textureConversionTest, config);
2812                                                                 }
2813
2814                                                                 {
2815                                                                         const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2816                                                                         const vk::VkChromaLocationKHR   chromaLocation  (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2817                                                                         const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2818                                                                                                                                                                                 vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
2819                                                                                                                                                                                 defaultColorRange, defaultColorModel, swappedChromaSwizzle);
2820
2821                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", createTestShaders, textureConversionTest, config);
2822                                                                 }
2823                                                         }
2824                                                 }
2825                                         }
2826                                 }
2827
2828                                 reconstrucGroup->addChild(textureFilterGroup.release());
2829                         }
2830
2831                         formatGroup->addChild(reconstrucGroup.release());
2832                 }
2833
2834                 testGroup->addChild(formatGroup.release());
2835         }
2836
2837         // Test formats with xy chroma reconstruction
2838         for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(xyChromaSubsampledFormats); formatNdx++)
2839         {
2840                 const vk::VkFormat                              format          (xyChromaSubsampledFormats[formatNdx]);
2841                 const std::string                               formatName      (de::toLower(std::string(getFormatName(format)).substr(10)));
2842                 de::MovePtr<tcu::TestCaseGroup> formatGroup     (new tcu::TestCaseGroup(testCtx, formatName.c_str(), ("Tests for color conversion using format " + formatName).c_str()));
2843
2844                 // Color conversion tests
2845                 {
2846                         de::MovePtr<tcu::TestCaseGroup> conversionGroup (new tcu::TestCaseGroup(testCtx, "color_conversion", ""));
2847
2848                         for (size_t chromaOffsetNdx = 0; chromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); chromaOffsetNdx++)
2849                         {
2850                                 const char* const                               chromaOffsetName        (chromaLocations[chromaOffsetNdx].name);
2851                                 const vk::VkChromaLocationKHR   chromaOffset            (chromaLocations[chromaOffsetNdx].value);
2852
2853                                 for (size_t modelNdx = 0; modelNdx < DE_LENGTH_OF_ARRAY(colorModels); modelNdx++)
2854                                 {
2855                                         const char* const                                                       colorModelName  (colorModels[modelNdx].name);
2856                                         const vk::VkSamplerYcbcrModelConversionKHR      colorModel              (colorModels[modelNdx].value);
2857
2858                                         if (colorModel != vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR && getFormatChannelCount(format) < 3)
2859                                                 continue;
2860
2861                                         if (colorModel == vk::VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR)
2862                                         {
2863                                                 for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2864                                                 {
2865                                                         const vk::VkImageTiling                         tiling                  (imageTilings[tilingNdx].value);
2866                                                         const char* const                                       tilingName              (imageTilings[tilingNdx].name);
2867                                                         const vk::VkSamplerYcbcrRangeKHR        colorRange              (rng.choose<RangeNamePair, const RangeNamePair*>(DE_ARRAY_BEGIN(colorRanges), DE_ARRAY_END(colorRanges)).value);
2868                                                         const glu::ShaderType                           shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2869                                                         const TestConfig                                        config                  (shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2870                                                                                                                                                                  vk::VK_FILTER_NEAREST, chromaOffset, chromaOffset, false, false,
2871                                                                                                                                                                  colorRange, colorModel, identitySwizzle);
2872
2873                                                         addFunctionCaseWithPrograms(conversionGroup.get(), std::string(colorModelName) + "_" + tilingName + "_" + chromaOffsetName, "", createTestShaders, textureConversionTest, config);
2874                                                 }
2875                                         }
2876                                         else
2877                                         {
2878                                                 for (size_t rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(colorRanges); rangeNdx++)
2879                                                 {
2880                                                         const char* const                                       colorRangeName  (colorRanges[rangeNdx].name);
2881                                                         const vk::VkSamplerYcbcrRangeKHR        colorRange              (colorRanges[rangeNdx].value);
2882
2883                                                         // Narrow range doesn't really work with formats that have less than 8 bits
2884                                                         if (colorRange == vk::VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR)
2885                                                         {
2886                                                                 const UVec4     bitDepth        (getBitDepth(format));
2887
2888                                                                 if (bitDepth[0] < 8 || bitDepth[1] < 8 || bitDepth[2] < 8)
2889                                                                         continue;
2890                                                         }
2891
2892                                                         for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2893                                                         {
2894                                                                 const vk::VkImageTiling                 tiling                  (imageTilings[tilingNdx].value);
2895                                                                 const char* const                               tilingName              (imageTilings[tilingNdx].name);
2896                                                                 const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2897                                                                 const TestConfig                                config                  (shaderType, format, tiling, vk::VK_FILTER_NEAREST, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2898                                                                                                                                                                         vk::VK_FILTER_NEAREST, chromaOffset, chromaOffset, false, false,
2899                                                                                                                                                                         colorRange, colorModel, identitySwizzle);
2900
2901                                                                 addFunctionCaseWithPrograms(conversionGroup.get(), (string(colorModelName) + "_" + colorRangeName + "_" + tilingName + "_" + chromaOffsetName).c_str(), "", createTestShaders, textureConversionTest, config);
2902                                                         }
2903                                                 }
2904                                         }
2905                                 }
2906                         }
2907
2908                         formatGroup->addChild(conversionGroup.release());
2909                 }
2910
2911                 // Chroma reconstruction tests
2912                 {
2913                         de::MovePtr<tcu::TestCaseGroup> reconstrucGroup (new tcu::TestCaseGroup(testCtx, "chroma_reconstruction", ""));
2914
2915                         for (size_t textureFilterNdx = 0; textureFilterNdx < DE_LENGTH_OF_ARRAY(textureFilters); textureFilterNdx++)
2916                         {
2917                                 const char* const                               textureFilterName       (textureFilters[textureFilterNdx].name);
2918                                 const vk::VkFilter                              textureFilter           (textureFilters[textureFilterNdx].value);
2919                                 de::MovePtr<tcu::TestCaseGroup> textureFilterGroup      (new tcu::TestCaseGroup(testCtx, textureFilterName, textureFilterName));
2920
2921                                 for (size_t explicitReconstructionNdx = 0; explicitReconstructionNdx < 2; explicitReconstructionNdx++)
2922                                 {
2923                                         const bool      explicitReconstruction  (explicitReconstructionNdx == 1);
2924
2925                                         for (size_t disjointNdx = 0; disjointNdx < 2; disjointNdx++)
2926                                         {
2927                                                 const bool      disjoint        (disjointNdx == 1);
2928
2929                                                 for (size_t xChromaOffsetNdx = 0; xChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); xChromaOffsetNdx++)
2930                                                 for (size_t yChromaOffsetNdx = 0; yChromaOffsetNdx < DE_LENGTH_OF_ARRAY(chromaLocations); yChromaOffsetNdx++)
2931                                                 {
2932                                                         const vk::VkChromaLocationKHR   xChromaOffset           (chromaLocations[xChromaOffsetNdx].value);
2933                                                         const char* const                               xChromaOffsetName       (chromaLocations[xChromaOffsetNdx].name);
2934
2935                                                         const vk::VkChromaLocationKHR   yChromaOffset           (chromaLocations[yChromaOffsetNdx].value);
2936                                                         const char* const                               yChromaOffsetName       (chromaLocations[yChromaOffsetNdx].name);
2937
2938                                                         for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2939                                                         {
2940                                                                 const vk::VkImageTiling tiling          (imageTilings[tilingNdx].value);
2941                                                                 const char* const               tilingName      (imageTilings[tilingNdx].name);
2942                                                                 {
2943                                                                         const glu::ShaderType   shaderType      (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2944                                                                         const TestConfig                config          (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2945                                                                                                                                                         vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2946                                                                                                                                                         defaultColorRange, defaultColorModel, identitySwizzle);
2947
2948                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", createTestShaders, textureConversionTest, config);
2949                                                                 }
2950
2951                                                                 {
2952                                                                         const glu::ShaderType   shaderType      (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2953                                                                         const TestConfig                config          (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2954                                                                                                                                                         vk::VK_FILTER_LINEAR, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2955                                                                                                                                                         defaultColorRange, defaultColorModel, swappedChromaSwizzle);
2956
2957                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string(explicitReconstruction ? "explicit_linear_" : "default_linear_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", createTestShaders, textureConversionTest, config);
2958                                                                 }
2959
2960                                                                 if (!explicitReconstruction)
2961                                                                 {
2962                                                                         {
2963                                                                                 const glu::ShaderType   shaderType      (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2964                                                                                 const TestConfig                config          (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2965                                                                                                                                                                 vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2966                                                                                                                                                                 defaultColorRange, defaultColorModel, identitySwizzle);
2967
2968                                                                                 addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", createTestShaders, textureConversionTest, config);
2969                                                                         }
2970
2971                                                                         {
2972                                                                                 const glu::ShaderType   shaderType      (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2973                                                                                 const TestConfig                config          (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2974                                                                                                                                                                 vk::VK_FILTER_NEAREST, xChromaOffset, yChromaOffset, explicitReconstruction, disjoint,
2975                                                                                                                                                                 defaultColorRange, defaultColorModel, swappedChromaSwizzle);
2976
2977                                                                                 addFunctionCaseWithPrograms(textureFilterGroup.get(), string("default_nearest_") + xChromaOffsetName + "_" + yChromaOffsetName + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", createTestShaders, textureConversionTest, config);
2978                                                                         }
2979                                                                 }
2980                                                         }
2981                                                 }
2982
2983                                                 if (explicitReconstruction)
2984                                                 {
2985                                                         for (size_t tilingNdx = 0; tilingNdx < DE_LENGTH_OF_ARRAY(imageTilings); tilingNdx++)
2986                                                         {
2987                                                                 const vk::VkImageTiling tiling          (imageTilings[tilingNdx].value);
2988                                                                 const char* const               tilingName      (imageTilings[tilingNdx].name);
2989                                                                 {
2990                                                                         const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
2991                                                                         const vk::VkChromaLocationKHR   chromaLocation  (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
2992                                                                         const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
2993                                                                                                                                                                                 vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
2994                                                                                                                                                                                 defaultColorRange, defaultColorModel, identitySwizzle);
2995
2996                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : ""), "", createTestShaders, textureConversionTest, config);
2997                                                                 }
2998
2999                                                                 {
3000                                                                         const glu::ShaderType                   shaderType              (rng.choose<glu::ShaderType>(DE_ARRAY_BEGIN(shaderTypes), DE_ARRAY_END(shaderTypes)));
3001                                                                         const vk::VkChromaLocationKHR   chromaLocation  (rng.choose<ChromaLocationNamePair, const ChromaLocationNamePair*>(DE_ARRAY_BEGIN(chromaLocations), DE_ARRAY_END(chromaLocations)).value);
3002                                                                         const TestConfig                                config                  (shaderType, format, tiling, textureFilter, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
3003                                                                                                                                                                                 vk::VK_FILTER_NEAREST, chromaLocation, chromaLocation, explicitReconstruction, disjoint,
3004                                                                                                                                                                                 defaultColorRange, defaultColorModel, swappedChromaSwizzle);
3005
3006                                                                         addFunctionCaseWithPrograms(textureFilterGroup.get(), string("explicit_nearest") + "_" + tilingName + (disjoint ? "_disjoint" : "") + "_swapped_chroma", "", createTestShaders, textureConversionTest, config);
3007                                                                 }
3008                                                         }
3009                                                 }
3010                                         }
3011                                 }
3012
3013                                 reconstrucGroup->addChild(textureFilterGroup.release());
3014                         }
3015
3016                         formatGroup->addChild(reconstrucGroup.release());
3017                 }
3018
3019                 testGroup->addChild(formatGroup.release());
3020         }
3021 }
3022
3023 } // anonymous
3024
3025 tcu::TestCaseGroup* createConversionTests (tcu::TestContext& testCtx)
3026 {
3027         return createTestGroup(testCtx, "conversion", "Sampler YCbCr Conversion Tests", initTests);
3028 }
3029
3030 } // ycbcr
3031 } // vkt