xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/ycbcr/vktYCbCrViewTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2017 Google Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief YCbCr Image View Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktYCbCrViewTests.hpp"
25 #include "vktYCbCrUtil.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktShaderExecutor.hpp"
29 
30 #include "vkStrUtil.hpp"
31 #include "vkRef.hpp"
32 #include "vkRefUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 
39 #include "tcuTestLog.hpp"
40 #include "tcuVectorUtil.hpp"
41 
42 #include "deStringUtil.hpp"
43 #include "deSharedPtr.hpp"
44 #include "deUniquePtr.hpp"
45 #include "deRandom.hpp"
46 #include "deSTLUtil.hpp"
47 
48 #include <memory>
49 
50 namespace vkt
51 {
52 namespace ycbcr
53 {
54 namespace
55 {
56 
57 using namespace vk;
58 using namespace shaderexecutor;
59 
60 using de::MovePtr;
61 using de::UniquePtr;
62 using std::string;
63 using std::vector;
64 using tcu::IVec4;
65 using tcu::TestLog;
66 using tcu::UVec2;
67 using tcu::UVec4;
68 using tcu::Vec2;
69 using tcu::Vec4;
70 
71 // List of some formats compatible with formats listed in "Plane Format Compatibility Table".
72 const VkFormat s_compatible_formats[] = {
73     // 8-bit compatibility class
74     // Compatible format for VK_FORMAT_R8_UNORM
75     VK_FORMAT_R4G4_UNORM_PACK8,
76     VK_FORMAT_R8_UINT,
77     VK_FORMAT_R8_SINT,
78     // 16-bit compatibility class
79     // Compatible formats with VK_FORMAT_R8G8_UNORM, VK_FORMAT_R10X6_UNORM_PACK16, VK_FORMAT_R12X4_UNORM_PACK16 and VK_FORMAT_R16_UNORM
80     VK_FORMAT_R8G8_UNORM,
81     VK_FORMAT_R8G8_UINT,
82     VK_FORMAT_R10X6_UNORM_PACK16,
83     VK_FORMAT_R12X4_UNORM_PACK16,
84     VK_FORMAT_R16_UNORM,
85     VK_FORMAT_R16_UINT,
86     VK_FORMAT_R16_SINT,
87     VK_FORMAT_R4G4B4A4_UNORM_PACK16,
88     // 32-bit compatibility class
89     // Compatible formats for VK_FORMAT_R10X6G10X6_UNORM_2PACK16, VK_FORMAT_R12X4G12X4_UNORM_2PACK16 and VK_FORMAT_R16G16_UNORM
90     VK_FORMAT_R10X6G10X6_UNORM_2PACK16,
91     VK_FORMAT_R12X4G12X4_UNORM_2PACK16,
92     VK_FORMAT_R16G16_UNORM,
93     VK_FORMAT_R8G8B8A8_UNORM,
94     VK_FORMAT_R8G8B8A8_UINT,
95     VK_FORMAT_R32_UINT,
96 };
97 
formatsAreCompatible(const VkFormat format0,const VkFormat format1)98 inline bool formatsAreCompatible(const VkFormat format0, const VkFormat format1)
99 {
100     return format0 == format1 || mapVkFormat(format0).getPixelSize() == mapVkFormat(format1).getPixelSize();
101 }
102 
createTestImage(const DeviceInterface & vkd,VkDevice device,VkFormat format,const UVec2 & size,VkImageCreateFlags createFlags)103 Move<VkImage> createTestImage(const DeviceInterface &vkd, VkDevice device, VkFormat format, const UVec2 &size,
104                               VkImageCreateFlags createFlags)
105 {
106     const VkImageCreateInfo createInfo = {
107         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
108         DE_NULL,
109         createFlags,
110         VK_IMAGE_TYPE_2D,
111         format,
112         makeExtent3D(size.x(), size.y(), 1u),
113         1u, // mipLevels
114         1u, // arrayLayers
115         VK_SAMPLE_COUNT_1_BIT,
116         VK_IMAGE_TILING_OPTIMAL,
117         VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
118         VK_SHARING_MODE_EXCLUSIVE,
119         0u,
120         (const uint32_t *)DE_NULL,
121         VK_IMAGE_LAYOUT_UNDEFINED,
122     };
123 
124     return createImage(vkd, device, &createInfo);
125 }
126 
createImageView(const DeviceInterface & vkd,VkDevice device,VkImage image,VkFormat format,VkImageAspectFlagBits imageAspect,const VkSamplerYcbcrConversionInfo * samplerConversionInfo)127 Move<VkImageView> createImageView(const DeviceInterface &vkd, VkDevice device, VkImage image, VkFormat format,
128                                   VkImageAspectFlagBits imageAspect,
129                                   const VkSamplerYcbcrConversionInfo *samplerConversionInfo)
130 {
131     const VkImageViewCreateInfo viewInfo = {
132         VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
133         samplerConversionInfo,
134         (VkImageViewCreateFlags)0,
135         image,
136         VK_IMAGE_VIEW_TYPE_2D,
137         format,
138         {
139             VK_COMPONENT_SWIZZLE_IDENTITY,
140             VK_COMPONENT_SWIZZLE_IDENTITY,
141             VK_COMPONENT_SWIZZLE_IDENTITY,
142             VK_COMPONENT_SWIZZLE_IDENTITY,
143         },
144         {(VkImageAspectFlags)imageAspect, 0u, 1u, 0u, 1u},
145     };
146 
147     return createImageView(vkd, device, &viewInfo);
148 }
149 
150 // Descriptor layout for set 1:
151 // 0: Plane view bound as COMBINED_IMAGE_SAMPLER
152 // 1: "Whole" image bound as COMBINED_IMAGE_SAMPLER
153 //    + immutable sampler (required for color conversion)
154 
createDescriptorSetLayout(const DeviceInterface & vkd,VkDevice device,VkSampler conversionSampler)155 Move<VkDescriptorSetLayout> createDescriptorSetLayout(const DeviceInterface &vkd, VkDevice device,
156                                                       VkSampler conversionSampler)
157 {
158     const VkDescriptorSetLayoutBinding bindings[]    = {{0u, // binding
159                                                          VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
160                                                          1u, // descriptorCount
161                                                          VK_SHADER_STAGE_ALL, (const VkSampler *)DE_NULL},
162                                                         {1u, // binding
163                                                          VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
164                                                          1u, // descriptorCount
165                                                          VK_SHADER_STAGE_ALL, &conversionSampler}};
166     const VkDescriptorSetLayoutCreateInfo layoutInfo = {
167         VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
168         DE_NULL,
169         (VkDescriptorSetLayoutCreateFlags)0u,
170         DE_LENGTH_OF_ARRAY(bindings),
171         bindings,
172     };
173 
174     return createDescriptorSetLayout(vkd, device, &layoutInfo);
175 }
176 
createDescriptorPool(const DeviceInterface & vkd,VkDevice device,const uint32_t combinedSamplerDescriptorCount)177 Move<VkDescriptorPool> createDescriptorPool(const DeviceInterface &vkd, VkDevice device,
178                                             const uint32_t combinedSamplerDescriptorCount)
179 {
180     const VkDescriptorPoolSize poolSizes[] = {
181         {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u * combinedSamplerDescriptorCount},
182     };
183     const VkDescriptorPoolCreateInfo poolInfo = {
184         VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
185         DE_NULL,
186         (VkDescriptorPoolCreateFlags)VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
187         1u, // maxSets
188         DE_LENGTH_OF_ARRAY(poolSizes),
189         poolSizes,
190     };
191 
192     return createDescriptorPool(vkd, device, &poolInfo);
193 }
194 
createDescriptorSet(const DeviceInterface & vkd,VkDevice device,VkDescriptorPool descPool,VkDescriptorSetLayout descLayout,VkImageView planeView,VkSampler planeViewSampler,VkImageView wholeView,VkSampler wholeViewSampler)195 Move<VkDescriptorSet> createDescriptorSet(const DeviceInterface &vkd, VkDevice device, VkDescriptorPool descPool,
196                                           VkDescriptorSetLayout descLayout, VkImageView planeView,
197                                           VkSampler planeViewSampler, VkImageView wholeView, VkSampler wholeViewSampler)
198 {
199     Move<VkDescriptorSet> descSet;
200 
201     {
202         const VkDescriptorSetAllocateInfo allocInfo = {
203             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, DE_NULL, descPool, 1u, &descLayout,
204         };
205 
206         descSet = allocateDescriptorSet(vkd, device, &allocInfo);
207     }
208 
209     {
210         const VkDescriptorImageInfo imageInfo0        = {planeViewSampler, planeView,
211                                                          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
212         const VkDescriptorImageInfo imageInfo1        = {wholeViewSampler, wholeView,
213                                                          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
214         const VkWriteDescriptorSet descriptorWrites[] = {{
215                                                              VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
216                                                              DE_NULL,
217                                                              *descSet,
218                                                              0u, // dstBinding
219                                                              0u, // dstArrayElement
220                                                              1u, // descriptorCount
221                                                              VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
222                                                              &imageInfo0,
223                                                              (const VkDescriptorBufferInfo *)DE_NULL,
224                                                              (const VkBufferView *)DE_NULL,
225                                                          },
226                                                          {
227                                                              VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
228                                                              DE_NULL,
229                                                              *descSet,
230                                                              1u, // dstBinding
231                                                              0u, // dstArrayElement
232                                                              1u, // descriptorCount
233                                                              VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
234                                                              &imageInfo1,
235                                                              (const VkDescriptorBufferInfo *)DE_NULL,
236                                                              (const VkBufferView *)DE_NULL,
237                                                          }};
238 
239         vkd.updateDescriptorSets(device, DE_LENGTH_OF_ARRAY(descriptorWrites), descriptorWrites, 0u, DE_NULL);
240     }
241 
242     return descSet;
243 }
244 
executeImageBarrier(const DeviceInterface & vkd,VkDevice device,uint32_t queueFamilyNdx,VkPipelineStageFlags srcStage,VkPipelineStageFlags dstStage,const VkImageMemoryBarrier & barrier)245 void executeImageBarrier(const DeviceInterface &vkd, VkDevice device, uint32_t queueFamilyNdx,
246                          VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage,
247                          const VkImageMemoryBarrier &barrier)
248 {
249     const VkQueue queue = getDeviceQueue(vkd, device, queueFamilyNdx, 0u);
250     const Unique<VkCommandPool> cmdPool(createCommandPool(vkd, device, (VkCommandPoolCreateFlags)0, queueFamilyNdx));
251     const Unique<VkCommandBuffer> cmdBuffer(
252         allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
253 
254     beginCommandBuffer(vkd, *cmdBuffer);
255 
256     vkd.cmdPipelineBarrier(*cmdBuffer, srcStage, dstStage, (VkDependencyFlags)0u, 0u, (const VkMemoryBarrier *)DE_NULL,
257                            0u, (const VkBufferMemoryBarrier *)DE_NULL, 1u, &barrier);
258 
259     endCommandBuffer(vkd, *cmdBuffer);
260 
261     submitCommandsAndWait(vkd, device, queue, *cmdBuffer);
262 }
263 
264 struct TestParameters
265 {
266     enum ViewType
267     {
268         VIEWTYPE_IMAGE_VIEW = 0,
269         VIEWTYPE_MEMORY_ALIAS,
270 
271         VIEWTYPE_LAST
272     };
273 
274     ViewType viewType;
275     VkFormat format;
276     UVec2 size;
277     VkImageCreateFlags createFlags;
278     uint32_t planeNdx;
279     VkFormat planeCompatibleFormat;
280     glu::ShaderType shaderType;
281     bool isCompatibilityFormat;
282 
TestParametersvkt::ycbcr::__anon982c828d0111::TestParameters283     TestParameters(ViewType viewType_, VkFormat format_, const UVec2 &size_, VkImageCreateFlags createFlags_,
284                    uint32_t planeNdx_, VkFormat planeCompatibleFormat_, glu::ShaderType shaderType_,
285                    bool isCompatibilityFormat_)
286         : viewType(viewType_)
287         , format(format_)
288         , size(size_)
289         , createFlags(createFlags_)
290         , planeNdx(planeNdx_)
291         , planeCompatibleFormat(planeCompatibleFormat_)
292         , shaderType(shaderType_)
293         , isCompatibilityFormat(isCompatibilityFormat_)
294     {
295     }
296 
TestParametersvkt::ycbcr::__anon982c828d0111::TestParameters297     TestParameters(void)
298         : viewType(VIEWTYPE_LAST)
299         , format(VK_FORMAT_UNDEFINED)
300         , createFlags(0u)
301         , planeNdx(0u)
302         , planeCompatibleFormat(VK_FORMAT_UNDEFINED)
303         , shaderType(glu::SHADERTYPE_LAST)
304         , isCompatibilityFormat(false)
305     {
306     }
307 };
308 
getDataType(VkFormat f)309 static glu::DataType getDataType(VkFormat f)
310 {
311     if (isIntFormat(f))
312         return glu::TYPE_INT_VEC4;
313     else if (isUintFormat(f))
314         return glu::TYPE_UINT_VEC4;
315     else
316         return glu::TYPE_FLOAT_VEC4;
317 }
318 
getSamplerDecl(VkFormat f)319 static std::string getSamplerDecl(VkFormat f)
320 {
321     if (isIntFormat(f))
322         return "isampler2D";
323     else if (isUintFormat(f))
324         return "usampler2D";
325     else
326         return "sampler2D";
327 }
328 
getVecType(VkFormat f)329 static std::string getVecType(VkFormat f)
330 {
331     if (isIntFormat(f))
332         return "ivec4";
333     else if (isUintFormat(f))
334         return "uvec4";
335     else
336         return "vec4";
337 }
338 
getShaderSpec(const TestParameters & params)339 ShaderSpec getShaderSpec(const TestParameters &params)
340 {
341     ShaderSpec spec;
342 
343     spec.inputs.push_back(Symbol("texCoord", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
344     spec.outputs.push_back(Symbol("result0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
345     spec.outputs.push_back(
346         Symbol("result1", glu::VarType(getDataType(params.planeCompatibleFormat), glu::PRECISION_HIGHP)));
347 
348     const std::string sampler = getSamplerDecl(params.planeCompatibleFormat);
349     spec.globalDeclarations   = "layout(binding = 1, set = 1) uniform highp sampler2D u_image;\n"
350                                 "layout(binding = 0, set = 1) uniform highp " +
351                               sampler + " u_planeView;\n";
352 
353     spec.source = "result0 = texture(u_image, texCoord);\n"
354                   "result1 = " +
355                   getVecType(params.planeCompatibleFormat) + "(texture(u_planeView, texCoord));\n";
356 
357     return spec;
358 }
359 
generateLookupCoordinates(const UVec2 & imageSize,size_t numCoords,de::Random * rnd,vector<Vec2> * dst)360 void generateLookupCoordinates(const UVec2 &imageSize, size_t numCoords, de::Random *rnd, vector<Vec2> *dst)
361 {
362     dst->resize(numCoords);
363 
364     for (size_t coordNdx = 0; coordNdx < numCoords; ++coordNdx)
365     {
366         const uint32_t texelX = rnd->getUint32() % imageSize.x();
367         const uint32_t texelY = rnd->getUint32() % imageSize.y();
368         const float x         = ((float)texelX + 0.5f) / (float)imageSize.x();
369         const float y         = ((float)texelY + 0.5f) / (float)imageSize.y();
370 
371         (*dst)[coordNdx] = Vec2(x, y);
372     }
373 }
374 
checkImageFeatureSupport(Context & context,VkFormat format,VkFormatFeatureFlags req)375 void checkImageFeatureSupport(Context &context, VkFormat format, VkFormatFeatureFlags req)
376 {
377     const VkFormatProperties formatProperties =
378         getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), format);
379 
380     if (req & ~formatProperties.optimalTilingFeatures)
381         TCU_THROW(NotSupportedError, "Format doesn't support required features");
382 }
383 
checkSupport(Context & context,TestParameters params)384 void checkSupport(Context &context, TestParameters params)
385 {
386     checkImageSupport(context, params.format, params.createFlags);
387     checkImageFeatureSupport(context, params.format,
388                              VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
389                                  VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT);
390     checkImageFeatureSupport(context, params.planeCompatibleFormat,
391                              VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
392 }
393 
394 struct PixelSetter
395 {
~PixelSettervkt::ycbcr::__anon982c828d0111::PixelSetter396     virtual ~PixelSetter()
397     {
398     }
PixelSettervkt::ycbcr::__anon982c828d0111::PixelSetter399     PixelSetter(const tcu::PixelBufferAccess &access) : m_access(access)
400     {
401     }
402     virtual void setPixel(const tcu::Vec4 &rawValues, int x, int y, int z) const = 0;
403 
404 protected:
405     const tcu::PixelBufferAccess &m_access;
406 };
407 
408 struct FloatPixelSetter : public PixelSetter
409 {
FloatPixelSettervkt::ycbcr::__anon982c828d0111::FloatPixelSetter410     FloatPixelSetter(const tcu::PixelBufferAccess &access) : PixelSetter(access)
411     {
412     }
setPixelvkt::ycbcr::__anon982c828d0111::FloatPixelSetter413     void setPixel(const tcu::Vec4 &rawValues, int x, int y, int z) const override
414     {
415         m_access.setPixel(rawValues, x, y, z);
416     }
417 };
418 
419 struct UintPixelSetter : public PixelSetter
420 {
UintPixelSettervkt::ycbcr::__anon982c828d0111::UintPixelSetter421     UintPixelSetter(const tcu::PixelBufferAccess &access) : PixelSetter(access)
422     {
423     }
setPixelvkt::ycbcr::__anon982c828d0111::UintPixelSetter424     void setPixel(const tcu::Vec4 &rawValues, int x, int y, int z) const override
425     {
426         m_access.setPixel(rawValues.bitCast<uint32_t>(), x, y, z);
427     }
428 };
429 
430 struct IntPixelSetter : public PixelSetter
431 {
IntPixelSettervkt::ycbcr::__anon982c828d0111::IntPixelSetter432     IntPixelSetter(const tcu::PixelBufferAccess &access) : PixelSetter(access)
433     {
434     }
setPixelvkt::ycbcr::__anon982c828d0111::IntPixelSetter435     void setPixel(const tcu::Vec4 &rawValues, int x, int y, int z) const override
436     {
437         m_access.setPixel(rawValues.bitCast<int>(), x, y, z);
438     }
439 };
440 
getPixelSetter(const tcu::PixelBufferAccess & access,VkFormat format)441 std::unique_ptr<PixelSetter> getPixelSetter(const tcu::PixelBufferAccess &access, VkFormat format)
442 {
443     std::unique_ptr<PixelSetter> pixelSetterPtr;
444 
445     if (isIntFormat(format))
446         pixelSetterPtr.reset(new IntPixelSetter(access));
447     else if (isUintFormat(format))
448         pixelSetterPtr.reset(new UintPixelSetter(access));
449     else
450         pixelSetterPtr.reset(new FloatPixelSetter(access));
451 
452     return pixelSetterPtr;
453 }
454 
455 // When comparing data interpreted using two different formats, if one of the formats has padding bits, we must compare results
456 // using that format. Padding bits may not be preserved, so we can only compare results for bits which have meaning on both formats.
chooseComparisonFormat(VkFormat planeOriginalFormat,VkFormat planeCompatibleFormat)457 VkFormat chooseComparisonFormat(VkFormat planeOriginalFormat, VkFormat planeCompatibleFormat)
458 {
459     const bool isOriginalPadded   = isPaddedFormat(planeOriginalFormat);
460     const bool isCompatiblePadded = isPaddedFormat(planeCompatibleFormat);
461 
462     if (isOriginalPadded && isCompatiblePadded)
463     {
464         if (planeOriginalFormat == planeCompatibleFormat)
465             return planeOriginalFormat;
466 
467         // Try to see if they're a known format pair that can be compared.
468         const auto &fmt1 = (planeOriginalFormat < planeCompatibleFormat ? planeOriginalFormat : planeCompatibleFormat);
469         const auto &fmt2 = (planeOriginalFormat < planeCompatibleFormat ? planeCompatibleFormat : planeOriginalFormat);
470 
471         if (fmt1 == VK_FORMAT_R10X6_UNORM_PACK16 && fmt2 == VK_FORMAT_R12X4_UNORM_PACK16)
472             return fmt1;
473 
474         if (fmt1 == VK_FORMAT_R10X6G10X6_UNORM_2PACK16 && fmt2 == VK_FORMAT_R12X4G12X4_UNORM_2PACK16)
475             return fmt1;
476 
477         // We can't have padded formats on both sides unless they're the exact same formats or we know how to compare them.
478         DE_ASSERT(false);
479     }
480 
481     if (isCompatiblePadded)
482         return planeCompatibleFormat;
483     return planeOriginalFormat;
484 }
485 
testPlaneView(Context & context,TestParameters params)486 tcu::TestStatus testPlaneView(Context &context, TestParameters params)
487 {
488     de::Random randomGen(deInt32Hash((uint32_t)params.format) ^ deInt32Hash((uint32_t)params.planeNdx) ^
489                          deInt32Hash((uint32_t)params.shaderType));
490 
491     const InstanceInterface &vk = context.getInstanceInterface();
492     const DeviceInterface &vkd  = context.getDeviceInterface();
493     const VkDevice device       = context.getDevice();
494 
495     const VkFormat format                    = params.format;
496     const VkImageCreateFlags createFlags     = params.createFlags;
497     const PlanarFormatDescription formatInfo = getPlanarFormatDescription(format);
498     const UVec2 size                         = params.size;
499     const UVec2 planeExtent                  = getPlaneExtent(formatInfo, size, params.planeNdx, 0);
500     const Unique<VkImage> image(createTestImage(vkd, device, format, size, createFlags));
501     const Unique<VkImage> imageAlias(
502         (params.viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS) ?
503             createTestImage(vkd, device, params.planeCompatibleFormat, planeExtent, createFlags) :
504             Move<VkImage>());
505     const vector<AllocationSp> allocations(
506         allocateAndBindImageMemory(vkd, device, context.getDefaultAllocator(), *image, format, createFlags));
507 
508     if (imageAlias)
509     {
510         if ((createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0)
511         {
512             VkBindImagePlaneMemoryInfo planeInfo = {VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO, DE_NULL,
513                                                     VK_IMAGE_ASPECT_PLANE_0_BIT};
514 
515             VkBindImageMemoryInfo coreInfo = {
516                 VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO,
517                 &planeInfo,
518                 *imageAlias,
519                 allocations[params.planeNdx]->getMemory(),
520                 allocations[params.planeNdx]->getOffset(),
521             };
522 
523             VK_CHECK(vkd.bindImageMemory2(device, 1, &coreInfo));
524         }
525         else
526         {
527             VK_CHECK(vkd.bindImageMemory(device, *imageAlias, allocations[params.planeNdx]->getMemory(),
528                                          allocations[params.planeNdx]->getOffset()));
529         }
530     }
531 
532     const VkSamplerYcbcrConversionCreateInfo conversionInfo = {
533         VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
534         DE_NULL,
535         format,
536         VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
537         VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
538         {
539             VK_COMPONENT_SWIZZLE_IDENTITY,
540             VK_COMPONENT_SWIZZLE_IDENTITY,
541             VK_COMPONENT_SWIZZLE_IDENTITY,
542             VK_COMPONENT_SWIZZLE_IDENTITY,
543         },
544         VK_CHROMA_LOCATION_MIDPOINT,
545         VK_CHROMA_LOCATION_MIDPOINT,
546         VK_FILTER_NEAREST,
547         VK_FALSE, // forceExplicitReconstruction
548     };
549     const Unique<VkSamplerYcbcrConversion> conversion(createSamplerYcbcrConversion(vkd, device, &conversionInfo));
550     const VkSamplerYcbcrConversionInfo samplerConversionInfo = {
551         VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
552         DE_NULL,
553         *conversion,
554     };
555     const Unique<VkImageView> wholeView(
556         createImageView(vkd, device, *image, format, VK_IMAGE_ASPECT_COLOR_BIT, &samplerConversionInfo));
557     const Unique<VkImageView> planeView(
558         createImageView(vkd, device, !imageAlias ? *image : *imageAlias, params.planeCompatibleFormat,
559                         !imageAlias ? getPlaneAspect(params.planeNdx) : VK_IMAGE_ASPECT_COLOR_BIT, DE_NULL));
560 
561     const VkSamplerCreateInfo wholeSamplerInfo = {
562         VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
563         &samplerConversionInfo,
564         0u,
565         VK_FILTER_NEAREST,                       // magFilter
566         VK_FILTER_NEAREST,                       // minFilter
567         VK_SAMPLER_MIPMAP_MODE_NEAREST,          // mipmapMode
568         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeU
569         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeV
570         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeW
571         0.0f,                                    // mipLodBias
572         VK_FALSE,                                // anisotropyEnable
573         1.0f,                                    // maxAnisotropy
574         VK_FALSE,                                // compareEnable
575         VK_COMPARE_OP_ALWAYS,                    // compareOp
576         0.0f,                                    // minLod
577         0.0f,                                    // maxLod
578         VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
579         VK_FALSE,                                // unnormalizedCoords
580     };
581     const VkSamplerCreateInfo planeSamplerInfo = {
582         VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
583         DE_NULL,
584         0u,
585         VK_FILTER_NEAREST,                       // magFilter
586         VK_FILTER_NEAREST,                       // minFilter
587         VK_SAMPLER_MIPMAP_MODE_NEAREST,          // mipmapMode
588         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeU
589         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeV
590         VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,   // addressModeW
591         0.0f,                                    // mipLodBias
592         VK_FALSE,                                // anisotropyEnable
593         1.0f,                                    // maxAnisotropy
594         VK_FALSE,                                // compareEnable
595         VK_COMPARE_OP_ALWAYS,                    // compareOp
596         0.0f,                                    // minLod
597         0.0f,                                    // maxLod
598         VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // borderColor
599         VK_FALSE,                                // unnormalizedCoords
600     };
601 
602     uint32_t combinedSamplerDescriptorCount = 1;
603     {
604         const VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {
605             VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,        // sType;
606             DE_NULL,                                                      // pNext;
607             format,                                                       // format;
608             VK_IMAGE_TYPE_2D,                                             // type;
609             VK_IMAGE_TILING_OPTIMAL,                                      // tiling;
610             VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, // usage;
611             createFlags                                                   // flags;
612         };
613 
614         VkSamplerYcbcrConversionImageFormatProperties samplerYcbcrConversionImage = {};
615         samplerYcbcrConversionImage.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
616         samplerYcbcrConversionImage.pNext = DE_NULL;
617 
618         VkImageFormatProperties2 imageFormatProperties = {};
619         imageFormatProperties.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
620         imageFormatProperties.pNext                    = &samplerYcbcrConversionImage;
621 
622         VkResult result = vk.getPhysicalDeviceImageFormatProperties2(context.getPhysicalDevice(), &imageFormatInfo,
623                                                                      &imageFormatProperties);
624         if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
625             TCU_THROW(NotSupportedError, "Format not supported.");
626         VK_CHECK(result);
627         combinedSamplerDescriptorCount = samplerYcbcrConversionImage.combinedImageSamplerDescriptorCount;
628     }
629 
630     const Unique<VkSampler> wholeSampler(createSampler(vkd, device, &wholeSamplerInfo));
631     const Unique<VkSampler> planeSampler(createSampler(vkd, device, &planeSamplerInfo));
632 
633     const Unique<VkDescriptorSetLayout> descLayout(createDescriptorSetLayout(vkd, device, *wholeSampler));
634     const Unique<VkDescriptorPool> descPool(createDescriptorPool(vkd, device, combinedSamplerDescriptorCount));
635     const Unique<VkDescriptorSet> descSet(
636         createDescriptorSet(vkd, device, *descPool, *descLayout, *planeView, *planeSampler, *wholeView, *wholeSampler));
637 
638     MultiPlaneImageData imageData(format, size);
639 
640     // Prepare texture data
641     fillRandom(&randomGen, &imageData);
642 
643     if (imageAlias)
644     {
645         // Transition alias to right layout first
646         const VkImageMemoryBarrier initAliasBarrier = {VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
647                                                        DE_NULL,
648                                                        (VkAccessFlags)0,
649                                                        VK_ACCESS_SHADER_READ_BIT,
650                                                        VK_IMAGE_LAYOUT_UNDEFINED,
651                                                        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
652                                                        VK_QUEUE_FAMILY_IGNORED,
653                                                        VK_QUEUE_FAMILY_IGNORED,
654                                                        *imageAlias,
655                                                        {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
656 
657         executeImageBarrier(vkd, device, context.getUniversalQueueFamilyIndex(),
658                             (VkPipelineStageFlags)VK_PIPELINE_STAGE_HOST_BIT,
659                             (VkPipelineStageFlags)VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, initAliasBarrier);
660     }
661 
662     // Upload and prepare image
663     uploadImage(vkd, device, context.getUniversalQueueFamilyIndex(), context.getDefaultAllocator(), *image, imageData,
664                 (VkAccessFlags)VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
665 
666     {
667         const size_t numValues = 500;
668         vector<Vec2> texCoord(numValues);
669         vector<Vec4> resultWhole(numValues);
670         vector<Vec4> resultPlane(numValues);
671         vector<Vec4> referenceWhole(numValues);
672         vector<Vec4> referencePlane(numValues);
673         bool allOk = true;
674         Vec4 threshold(0.02f);
675 
676         generateLookupCoordinates(size, numValues, &randomGen, &texCoord);
677 
678         {
679             UniquePtr<ShaderExecutor> executor(
680                 createExecutor(context, params.shaderType, getShaderSpec(params), *descLayout));
681             const void *inputs[] = {texCoord[0].getPtr()};
682             void *outputs[]      = {resultWhole[0].getPtr(), resultPlane[0].getPtr()};
683 
684             executor->execute((int)numValues, inputs, outputs, *descSet);
685         }
686 
687         // Whole image sampling reference
688         for (uint32_t channelNdx = 0; channelNdx < 4; channelNdx++)
689         {
690             if (formatInfo.hasChannelNdx(channelNdx))
691             {
692                 const tcu::ConstPixelBufferAccess channelAccess = imageData.getChannelAccess(channelNdx);
693                 const tcu::Sampler refSampler                   = mapVkSampler(wholeSamplerInfo);
694                 const tcu::Texture2DView refTexView(1u, &channelAccess);
695 
696                 for (size_t ndx = 0; ndx < numValues; ++ndx)
697                 {
698                     const Vec2 &coord               = texCoord[ndx];
699                     referenceWhole[ndx][channelNdx] = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f)[0];
700                 }
701             }
702             else
703             {
704                 for (size_t ndx = 0; ndx < numValues; ++ndx)
705                     referenceWhole[ndx][channelNdx] = channelNdx == 3 ? 1.0f : 0.0f;
706             }
707         }
708 
709         // Compare whole image.
710         {
711             const vector<Vec4> &reference = referenceWhole;
712             const vector<Vec4> &result    = resultWhole;
713 
714             for (size_t ndx = 0; ndx < numValues; ++ndx)
715             {
716                 const Vec4 resultValue = result[ndx];
717                 if (boolAny(greaterThanEqual(abs(resultValue - reference[ndx]), threshold)))
718                 {
719                     context.getTestContext().getLog()
720                         << TestLog::Message << "ERROR: When sampling complete image at " << texCoord[ndx] << ": got "
721                         << result[ndx] << ", expected " << reference[ndx] << TestLog::EndMessage;
722                     allOk = false;
723                 }
724             }
725         }
726 
727         // Compare sampled plane.
728         {
729             const tcu::IVec3 resultSize(static_cast<int>(numValues), 1, 1);
730             const tcu::IVec3 origPlaneSize((int)planeExtent.x(), (int)planeExtent.y(), 1);
731 
732             // This is not the original *full* image format, but that of the specific plane we worked with (e.g. G10X6_etc becomes R10X6).
733             const auto planeOriginalFormat   = imageData.getDescription().planes[params.planeNdx].planeCompatibleFormat;
734             const auto planeCompatibleFormat = params.planeCompatibleFormat;
735             const auto tcuPlaneCompatibleFormat = mapVkFormat(params.planeCompatibleFormat);
736 
737             // We need to take the original image and the sampled results to a common ground for comparison.
738             // The common ground will be the padded format if it exists or the original format if it doesn't.
739             // The padded format is chosen as a priority because, if it exists, some bits may have been lost there.
740             const auto comparisonFormat    = chooseComparisonFormat(planeOriginalFormat, planeCompatibleFormat);
741             const auto tcuComparisonFormat = mapVkFormat(comparisonFormat);
742 
743             // Re-pack results into the plane-specific format. For that, we use the compatible format first to create an image.
744             tcu::TextureLevel repackedLevel(tcuPlaneCompatibleFormat, resultSize.x(), resultSize.y(), resultSize.z());
745             auto repackedCompatibleAccess = repackedLevel.getAccess();
746             const auto pixelSetter        = getPixelSetter(repackedCompatibleAccess, planeCompatibleFormat);
747 
748             // Note resultPlane, even if on the C++ side contains an array of Vec4 values, has actually received floats, int32_t or
749             // uint32_t values, depending on the underlying plane compatible format, when used as the ShaderExecutor output.
750             // What we achieve with the pixel setter is to reintepret those raw values as actual ints, uints or floats depending on
751             // the plane compatible format, and call the appropriate value-setting method of repackedCompatibleAccess.
752             for (size_t i = 0u; i < numValues; ++i)
753                 pixelSetter->setPixel(resultPlane[i], static_cast<int>(i), 0, 0);
754 
755             // Finally, we create an access to the same data with the comparison format for the plane.
756             const tcu::ConstPixelBufferAccess repackedAccess(tcuComparisonFormat, resultSize,
757                                                              repackedCompatibleAccess.getDataPtr());
758 
759             // Now we compare that access with the original texture values sampled in the comparison format.
760             const tcu::ConstPixelBufferAccess planeAccess(tcuComparisonFormat, origPlaneSize,
761                                                           imageData.getPlanePtr(params.planeNdx));
762             const tcu::Sampler refSampler = mapVkSampler(planeSamplerInfo);
763             const tcu::Texture2DView refTexView(1u, &planeAccess);
764 
765             for (size_t ndx = 0; ndx < numValues; ++ndx)
766             {
767                 const Vec2 &coord   = texCoord[ndx];
768                 const auto refValue = refTexView.sample(refSampler, coord.x(), coord.y(), 0.0f);
769                 const auto resValue = repackedAccess.getPixel(static_cast<int>(ndx), 0);
770 
771                 if (boolAny(greaterThanEqual(abs(resValue - refValue), threshold)))
772                 {
773                     context.getTestContext().getLog()
774                         << TestLog::Message << "ERROR: When sampling plane view at " << texCoord[ndx] << ": got "
775                         << resValue << ", expected " << refValue << TestLog::EndMessage;
776                     allOk = false;
777                 }
778             }
779         }
780 
781         if (allOk)
782             return tcu::TestStatus::pass("All samples passed");
783         else
784             return tcu::TestStatus::fail("Got invalid results");
785     }
786 }
787 
initPrograms(SourceCollections & dst,TestParameters params)788 void initPrograms(SourceCollections &dst, TestParameters params)
789 {
790     const ShaderSpec spec = getShaderSpec(params);
791 
792     generateSources(params.shaderType, spec, dst);
793 }
794 
addPlaneViewCase(tcu::TestCaseGroup * group,const TestParameters & params)795 void addPlaneViewCase(tcu::TestCaseGroup *group, const TestParameters &params)
796 {
797     std::ostringstream name;
798 
799     name << de::toLower(de::toString(params.format).substr(10));
800 
801     if ((params.viewType != TestParameters::VIEWTYPE_MEMORY_ALIAS) &&
802         ((params.createFlags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0))
803         name << "_disjoint";
804 
805     name << "_plane_" << params.planeNdx;
806 
807     if (params.isCompatibilityFormat)
808     {
809         name << "_compatible_format_" << de::toLower(de::toString(params.planeCompatibleFormat).substr(10));
810     }
811 
812     addFunctionCaseWithPrograms(group, name.str(), checkSupport, initPrograms, testPlaneView, params);
813 }
814 
populateViewTypeGroup(tcu::TestCaseGroup * group,TestParameters::ViewType viewType)815 void populateViewTypeGroup(tcu::TestCaseGroup *group, TestParameters::ViewType viewType)
816 {
817     const glu::ShaderType shaderType = glu::SHADERTYPE_FRAGMENT;
818     const UVec2 size(32, 58);
819     const VkImageCreateFlags baseFlags =
820         (VkImageCreateFlags)VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT |
821         (viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS ? (VkImageCreateFlags)VK_IMAGE_CREATE_ALIAS_BIT : 0u);
822 
823     auto addTests = [&](int formatNdx)
824     {
825         const VkFormat format    = (VkFormat)formatNdx;
826         const uint32_t numPlanes = getPlaneCount(format);
827 
828         if (numPlanes == 1)
829             return; // Plane views not possible
830 
831         for (int isDisjoint = 0; isDisjoint < 2; ++isDisjoint)
832         {
833             const VkImageCreateFlags flags =
834                 baseFlags | (isDisjoint == 1 ? (VkImageCreateFlags)VK_IMAGE_CREATE_DISJOINT_BIT : 0u);
835 
836             if ((viewType == TestParameters::VIEWTYPE_MEMORY_ALIAS) && ((flags & VK_IMAGE_CREATE_DISJOINT_BIT) == 0))
837                 continue; // Memory alias cases require disjoint planes
838 
839             for (uint32_t planeNdx = 0; planeNdx < numPlanes; ++planeNdx)
840             {
841                 const VkFormat planeFormat = getPlaneCompatibleFormat(format, planeNdx);
842                 // Add test case using image view with a format taken from the "Plane Format Compatibility Table"
843                 addPlaneViewCase(
844                     group, TestParameters(viewType, format, size, flags, planeNdx, planeFormat, shaderType, false));
845 
846                 // Add test cases using image view with a format that is compatible with the plane's format.
847                 // For example: VK_FORMAT_R4G4_UNORM_PACK8 is compatible with VK_FORMAT_R8_UNORM.
848                 for (const auto &compatibleFormat : s_compatible_formats)
849                 {
850                     if (compatibleFormat == planeFormat)
851                         continue;
852 
853                     if (!formatsAreCompatible(planeFormat, compatibleFormat))
854                         continue;
855 
856                     addPlaneViewCase(group, TestParameters(viewType, format, size, flags, planeNdx, compatibleFormat,
857                                                            shaderType, true));
858                 }
859             }
860         }
861     };
862 
863     for (int formatNdx = VK_YCBCR_FORMAT_FIRST; formatNdx < VK_YCBCR_FORMAT_LAST; formatNdx++)
864     {
865         addTests(formatNdx);
866     }
867 
868     for (int formatNdx = VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT; formatNdx < VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT;
869          formatNdx++)
870     {
871         addTests(formatNdx);
872     }
873 }
874 
populateViewGroup(tcu::TestCaseGroup * group)875 void populateViewGroup(tcu::TestCaseGroup *group)
876 {
877     // Plane View via VkImageView
878     addTestGroup(group, "image_view", populateViewTypeGroup, TestParameters::VIEWTYPE_IMAGE_VIEW);
879     // Plane View via Memory Aliasing
880     addTestGroup(group, "memory_alias", populateViewTypeGroup, TestParameters::VIEWTYPE_MEMORY_ALIAS);
881 }
882 
883 } // namespace
884 
createViewTests(tcu::TestContext & testCtx)885 tcu::TestCaseGroup *createViewTests(tcu::TestContext &testCtx)
886 {
887     return createTestGroup(testCtx, "plane_view", populateViewGroup);
888 }
889 
890 } // namespace ycbcr
891 
892 } // namespace vkt
893