1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  *
6  * Copyright (c) 2022 Khronos Group
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */ /*!
21 * \file
22 * \brief Test for Image Compression control
23 */ /*--------------------------------------------------------------------*/
24 
25 #include <iostream>
26 #include <typeinfo>
27 
28 #include "tcuCommandLine.hpp"
29 #include "tcuDefs.hpp"
30 #include "tcuFunctionLibrary.hpp"
31 #include "tcuPlatform.hpp"
32 #include "tcuResultCollector.hpp"
33 #include "tcuTestCase.hpp"
34 #include "tcuTestLog.hpp"
35 
36 #include "vkApiVersion.hpp"
37 #include "vkDefs.hpp"
38 #include "vkPlatform.hpp"
39 
40 #include "vktApiVersionCheck.hpp"
41 #include "vktCustomInstancesDevices.hpp"
42 #include "vktExternalMemoryUtil.hpp"
43 #include "vktTestCase.hpp"
44 #include "vktTestCaseUtil.hpp"
45 #include "vktTestGroupUtil.hpp"
46 #include "wsi/vktNativeObjectsUtil.hpp"
47 
48 #include "vkDeviceUtil.hpp"
49 #include "vkImageUtil.hpp"
50 #include "vkQueryUtil.hpp"
51 #include "vkRefUtil.hpp"
52 #include "vkWsiUtil.hpp"
53 
54 #include "deString.h"
55 #include "deStringUtil.hpp"
56 
57 #include <map>
58 #include <vector>
59 
60 using namespace vk;
61 using namespace vk::wsi;
62 using namespace std;
63 
64 typedef vector<VkExtensionProperties> Extensions;
65 
66 namespace vkt
67 {
68 
69 namespace api
70 {
71 
72 struct TestParams
73 {
74     VkFormat format;
75     bool useExtension;
76     VkImageCompressionControlEXT control;
77     Type wsiType;
78 };
79 
checkImageCompressionControlSupport(Context & context,bool swapchain=false)80 static void checkImageCompressionControlSupport(Context &context, bool swapchain = false)
81 {
82     context.requireDeviceFunctionality("VK_EXT_image_compression_control");
83     vk::VkPhysicalDeviceImageCompressionControlFeaturesEXT imageCompressionControlFeatures    = initVulkanStructure();
84     vk::VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT imageCompressionSwapchain = initVulkanStructure();
85     vk::VkPhysicalDeviceFeatures2 features2 = initVulkanStructure(&imageCompressionControlFeatures);
86     if (swapchain)
87     {
88         context.requireDeviceFunctionality("VK_EXT_image_compression_control_swapchain");
89         imageCompressionControlFeatures.pNext = &imageCompressionSwapchain;
90     }
91 
92     context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
93 
94     if (!imageCompressionControlFeatures.imageCompressionControl)
95         TCU_THROW(NotSupportedError, "VK_EXT_image_compression_control Image "
96                                      "compression control feature not supported.");
97     if (swapchain && !imageCompressionSwapchain.imageCompressionControlSwapchain)
98         TCU_THROW(NotSupportedError, "VK_EXT_image_compression_control_swapchain Image "
99                                      "compression control feature for swapchains not supported.");
100 }
101 
validate(const InstanceInterface & vki,const DeviceInterface & vkd,tcu::ResultCollector & results,VkPhysicalDevice physicalDevice,VkDevice device,TestParams & testParams,VkImage image)102 static void validate(const InstanceInterface &vki, const DeviceInterface &vkd, tcu::ResultCollector &results,
103                      VkPhysicalDevice physicalDevice, VkDevice device, TestParams &testParams, VkImage image)
104 {
105     constexpr VkImageAspectFlags planeAspects[]{VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT,
106                                                 VK_IMAGE_ASPECT_PLANE_2_BIT};
107     const bool isYCbCr  = isYCbCrFormat(testParams.format);
108     const int numPlanes = isYCbCr ? getPlaneCount(testParams.format) : 1;
109     for (int planeIndex = 0; planeIndex < numPlanes; planeIndex++)
110     {
111         VkImageAspectFlags aspect = VK_IMAGE_ASPECT_COLOR_BIT;
112         if (isYCbCr)
113         {
114             aspect = planeAspects[planeIndex];
115         }
116 
117         VkImageCompressionPropertiesEXT compressionProperties = initVulkanStructure();
118         VkImageSubresource2EXT subresource                    = initVulkanStructure();
119         subresource.imageSubresource.aspectMask               = aspect;
120         VkSubresourceLayout2EXT subresourceLayout             = initVulkanStructure(&compressionProperties);
121         vkd.getImageSubresourceLayout2KHR(device, image, &subresource, &subresourceLayout);
122 
123         VkImageCompressionControlEXT compressionEnabled       = initVulkanStructure();
124         compressionEnabled.compressionControlPlaneCount       = testParams.control.compressionControlPlaneCount;
125         compressionEnabled.flags                              = testParams.control.flags;
126         VkImageCompressionFixedRateFlagsEXT fixedRateFlags[3] = {
127             VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT,
128             VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT,
129             VK_IMAGE_COMPRESSION_FIXED_RATE_FLAG_BITS_MAX_ENUM_EXT};
130 
131         if (compressionEnabled.compressionControlPlaneCount > 0)
132         {
133             compressionEnabled.pFixedRateFlags = fixedRateFlags;
134         }
135 
136         VkPhysicalDeviceImageFormatInfo2 formatInfo = initVulkanStructure(&compressionEnabled);
137         formatInfo.format                           = testParams.format;
138         formatInfo.type                             = VK_IMAGE_TYPE_2D;
139         formatInfo.tiling                           = VK_IMAGE_TILING_OPTIMAL;
140         formatInfo.usage                            = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
141 
142         VkImageCompressionPropertiesEXT compressionPropertiesSupported = initVulkanStructure();
143         VkImageFormatProperties2 properties2 = initVulkanStructure(&compressionPropertiesSupported);
144 
145         vki.getPhysicalDeviceImageFormatProperties2(physicalDevice, &formatInfo, &properties2);
146 
147         if (testParams.useExtension)
148         {
149             if ((compressionPropertiesSupported.imageCompressionFixedRateFlags &
150                  compressionProperties.imageCompressionFixedRateFlags) !=
151                 compressionProperties.imageCompressionFixedRateFlags)
152             {
153                 results.fail("Got image with fixed rate flags that are not supported "
154                              "in image format properties.");
155             }
156             if ((compressionPropertiesSupported.imageCompressionFlags & compressionProperties.imageCompressionFlags) !=
157                     compressionProperties.imageCompressionFlags &&
158                 compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT)
159             {
160                 results.fail("Got image with compression flags that are not supported "
161                              "in image format properties.");
162             }
163             if (testParams.control.flags == VK_IMAGE_COMPRESSION_DEFAULT_EXT &&
164                 compressionProperties.imageCompressionFixedRateFlags != 0)
165             {
166                 results.fail("Got lossy compression when DEFAULT compression was requested.");
167             }
168             if (testParams.control.flags == VK_IMAGE_COMPRESSION_DISABLED_EXT &&
169                 compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT)
170             {
171                 results.fail("Image compression not disabled.");
172             }
173             if (testParams.control.flags == VK_IMAGE_COMPRESSION_DISABLED_EXT &&
174                 compressionProperties.imageCompressionFixedRateFlags != 0)
175             {
176                 results.fail("Image compression disabled but got fixed rate flags.");
177             }
178             if (testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT &&
179                 !(compressionProperties.imageCompressionFlags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT ||
180                   compressionProperties.imageCompressionFlags == VK_IMAGE_COMPRESSION_DISABLED_EXT ||
181                   compressionProperties.imageCompressionFlags == VK_IMAGE_COMPRESSION_DEFAULT_EXT))
182             {
183                 results.fail("Explicit compression flags not returned for image "
184                              "creation with FIXED RATE DEFAULT.");
185             }
186 
187             if (testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT)
188             {
189                 uint32_t minRequestedRate = 1 << deCtz32(testParams.control.pFixedRateFlags[planeIndex]);
190                 uint32_t actualRate       = compressionProperties.imageCompressionFixedRateFlags;
191                 if (compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT &&
192                     compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DEFAULT_EXT)
193                 {
194 
195                     if (minRequestedRate > actualRate)
196                     {
197                         results.fail("Image created with less bpc than requested.");
198                     }
199                 }
200             }
201         }
202         else
203         {
204             if (compressionProperties.imageCompressionFixedRateFlags != VK_IMAGE_COMPRESSION_FIXED_RATE_NONE_EXT)
205             {
206                 results.fail("Fixed rate compression should not be enabled.");
207             }
208 
209             if (compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DISABLED_EXT &&
210                 compressionProperties.imageCompressionFlags != VK_IMAGE_COMPRESSION_DEFAULT_EXT)
211             {
212                 results.fail("Image compression should be default or not be enabled.");
213             }
214         }
215     }
216 }
217 
checkAhbImageSupport(const Context & context,const TestParams testParams,const uint32_t width,const uint32_t height,const VkImageUsageFlagBits vkUsage)218 static void checkAhbImageSupport(const Context &context, const TestParams testParams, const uint32_t width,
219                                  const uint32_t height, const VkImageUsageFlagBits vkUsage)
220 {
221     using namespace vkt::ExternalMemoryUtil;
222 
223     // Check android hardware buffer can be allocated for the format with usage.
224     AndroidHardwareBufferExternalApi *ahbApi = AndroidHardwareBufferExternalApi::getInstance();
225     if (!ahbApi)
226     {
227         TCU_THROW(NotSupportedError, "Platform doesn't support Android Hardware Buffer handles");
228     }
229     uint64_t ahbUsage = ahbApi->vkUsageToAhbUsage(vkUsage);
230     {
231         pt::AndroidHardwareBufferPtr ahb =
232             ahbApi->allocate(width, height, 1, ahbApi->vkFormatToAhbFormat(testParams.format), ahbUsage);
233         if (ahb.internal == DE_NULL)
234         {
235             TCU_THROW(NotSupportedError, "Android hardware buffer format not supported");
236         }
237     }
238 
239     // Check external memory supported.
240     const VkPhysicalDeviceExternalImageFormatInfoKHR external_image_format_info = {
241         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, &testParams.control,
242         VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID};
243 
244     const VkPhysicalDeviceImageFormatInfo2 info = {
245         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
246         &external_image_format_info,
247         testParams.format,
248         VK_IMAGE_TYPE_2D,
249         VK_IMAGE_TILING_OPTIMAL,
250         VK_IMAGE_USAGE_SAMPLED_BIT,
251         0,
252     };
253 
254     VkImageCompressionPropertiesEXT compressionPropertiesSupported = {
255         VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_PROPERTIES_EXT, DE_NULL, 0, 0};
256 
257     VkAndroidHardwareBufferUsageANDROID ahbUsageProperties = {VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID,
258                                                               &compressionPropertiesSupported, 0u};
259 
260     VkExternalImageFormatProperties externalProperties = {
261         VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, &ahbUsageProperties, {0u, 0u, 0u}};
262 
263     VkImageFormatProperties2 properties = {
264         VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, &externalProperties, {{0u, 0u, 0u}, 0u, 0u, 0u, 0u}};
265 
266     VkResult result = context.getInstanceInterface().getPhysicalDeviceImageFormatProperties2(
267         context.getPhysicalDevice(), &info, &properties);
268 
269     if (result == VK_ERROR_FORMAT_NOT_SUPPORTED)
270         TCU_THROW(NotSupportedError, "Format not supported");
271 
272     if ((externalProperties.externalMemoryProperties.externalMemoryFeatures &
273          VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) == 0)
274         TCU_THROW(NotSupportedError, "External handle type doesn't support exporting image");
275 
276     if ((externalProperties.externalMemoryProperties.externalMemoryFeatures &
277          VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT) == 0)
278         TCU_THROW(NotSupportedError, "External handle type requires dedicated allocation");
279 
280     if ((compressionPropertiesSupported.imageCompressionFlags == VK_IMAGE_COMPRESSION_DISABLED_EXT) &&
281         (testParams.control.flags != VK_IMAGE_COMPRESSION_DISABLED_EXT))
282     {
283         TCU_THROW(NotSupportedError, "Compression is disbaled, and other compression flags are not supported");
284     }
285 
286     if ((ahbUsageProperties.androidHardwareBufferUsage & ahbUsage) != ahbUsage)
287     {
288         TCU_THROW(NotSupportedError, "Android hardware buffer usage is not supported");
289     }
290 }
291 
ahbImageCreateTest(Context & context,TestParams testParams)292 static tcu::TestStatus ahbImageCreateTest(Context &context, TestParams testParams)
293 {
294     using namespace vkt::ExternalMemoryUtil;
295 
296     context.requireDeviceFunctionality("VK_ANDROID_external_memory_android_hardware_buffer");
297     context.requireDeviceFunctionality("VK_EXT_image_compression_control");
298 
299     const uint32_t width           = 32;
300     const uint32_t height          = 32;
301     uint32_t queueFamilyIndex      = context.getUniversalQueueFamilyIndex();
302     const vk::DeviceInterface &vkd = context.getDeviceInterface();
303     VkDevice device                = context.getDevice();
304     tcu::TestLog &log              = context.getTestContext().getLog();
305     tcu::ResultCollector results(log);
306     const VkImageUsageFlagBits vkUsage = VK_IMAGE_USAGE_SAMPLED_BIT;
307     const bool is_fixed_rate_ex        = testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
308     const uint32_t numPlanes           = isYCbCrFormat(testParams.format) ? getPlaneCount(testParams.format) : 1;
309 
310     testParams.control.compressionControlPlaneCount = is_fixed_rate_ex ? numPlanes : 0;
311 
312     VkImageCompressionFixedRateFlagsEXT planeFlags[3]{};
313 
314     for (unsigned i{}; i < (is_fixed_rate_ex ? 24u : 1u); i++)
315     {
316         planeFlags[0] ^= 3 << i;
317         planeFlags[1] ^= 5 << i;
318         planeFlags[2] ^= 7 << i;
319 
320         if (is_fixed_rate_ex)
321         {
322             testParams.control.compressionControlPlaneCount = numPlanes;
323             testParams.control.pFixedRateFlags              = planeFlags;
324         }
325 
326         const vk::VkExternalMemoryImageCreateInfo externalCreateInfo = {
327             vk::VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, &testParams.control,
328             VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID};
329         const vk::VkImageCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
330                                                   &externalCreateInfo,
331                                                   0,
332                                                   vk::VK_IMAGE_TYPE_2D,
333                                                   testParams.format,
334                                                   {
335                                                       width,
336                                                       height,
337                                                       1u,
338                                                   },
339                                                   1,
340                                                   1,
341                                                   vk::VK_SAMPLE_COUNT_1_BIT,
342                                                   VK_IMAGE_TILING_OPTIMAL,
343                                                   vkUsage,
344                                                   vk::VK_SHARING_MODE_EXCLUSIVE,
345                                                   1,
346                                                   &queueFamilyIndex,
347                                                   vk::VK_IMAGE_LAYOUT_UNDEFINED};
348 
349         checkAhbImageSupport(context, testParams, width, height, vkUsage);
350 
351         Move<VkImage> image                     = vk::createImage(vkd, device, &createInfo);
352         const VkMemoryRequirements requirements = ExternalMemoryUtil::getImageMemoryRequirements(
353             vkd, device, image.get(), VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID);
354         const uint32_t exportedMemoryTypeIndex(ExternalMemoryUtil::chooseMemoryType(requirements.memoryTypeBits));
355         Move<VkDeviceMemory> memory = ExternalMemoryUtil::allocateExportableMemory(
356             vkd, device, requirements.size, exportedMemoryTypeIndex,
357             VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, image.get());
358 
359         VK_CHECK(vkd.bindImageMemory(device, image.get(), memory.get(), 0u));
360         validate(context.getInstanceInterface(), context.getDeviceInterface(), results, context.getPhysicalDevice(),
361                  context.getDevice(), testParams, image.get());
362     }
363     return tcu::TestStatus(results.getResult(), results.getMessage());
364 }
365 
imageCreateTest(Context & context,TestParams testParams)366 static tcu::TestStatus imageCreateTest(Context &context, TestParams testParams)
367 {
368     checkImageCompressionControlSupport(context);
369     uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
370     const VkDevice device     = context.getDevice();
371     VkExtent3D extent         = {16, 16, 1};
372     tcu::TestLog &log         = context.getTestContext().getLog();
373     tcu::ResultCollector results(log);
374     const bool is_fixed_rate_ex = testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
375 
376     VkImageCompressionFixedRateFlagsEXT planeFlags[3]{};
377 
378     for (unsigned i{}; i < (is_fixed_rate_ex ? 24u : 1u); i++)
379     {
380         planeFlags[0] ^= 3 << i;
381         planeFlags[1] ^= 5 << i;
382         planeFlags[2] ^= 7 << i;
383 
384         if (is_fixed_rate_ex)
385         {
386             testParams.control.pFixedRateFlags = planeFlags;
387         }
388 
389         VkImageCreateInfo imageCreateInfo = {
390             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
391             DE_NULL,                             // const void*                  pNext;
392             0,                                   // VkImageCreateFlags   flags;
393             VK_IMAGE_TYPE_2D,                    // VkImageType
394             testParams.format,                   // VkFormat format;
395             extent,                              // VkExtent3D extent;
396             1u,                                  // uint32_t                             mipLevels;
397             1u,                                  // uint32_t arraySize;
398             VK_SAMPLE_COUNT_1_BIT,               // uint32_t samples;
399             VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling                tiling;
400             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, // VkImageUsageFlags    usage;
401             VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
402             1u,                                  // uint32_t                             queueFamilyCount;
403             &queueFamilyIndex,                   // const uint32_t* pQueueFamilyIndices;
404             VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
405         };
406 
407         if (testParams.useExtension)
408         {
409             imageCreateInfo.pNext = &testParams.control;
410         }
411 
412         checkImageSupport(context.getInstanceInterface(), context.getPhysicalDevice(), imageCreateInfo);
413 
414         Move<VkImage> image = createImage(context.getDeviceInterface(), device, &imageCreateInfo);
415 
416         validate(context.getInstanceInterface(), context.getDeviceInterface(), results, context.getPhysicalDevice(),
417                  context.getDevice(), testParams, image.get());
418     }
419     return tcu::TestStatus(results.getResult(), results.getMessage());
420 }
421 
addImageCompressionControlTests(tcu::TestCaseGroup * group,TestParams testParams)422 void addImageCompressionControlTests(tcu::TestCaseGroup *group, TestParams testParams)
423 {
424     const bool is_fixed_rate_ex = testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
425 
426     static const struct
427     {
428         VkFormat begin;
429         VkFormat end;
430     } s_formatRanges[] = {
431         // core formats
432         {(VkFormat)(VK_FORMAT_UNDEFINED + 1), VK_CORE_FORMAT_LAST},
433 
434         // YCbCr formats
435         {VK_FORMAT_G8B8G8R8_422_UNORM, (VkFormat)(VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM + 1)},
436 
437         // YCbCr extended formats
438         {VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT, (VkFormat)(VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT + 1)},
439     };
440 
441     for (int rangeNdx = 0; rangeNdx < DE_LENGTH_OF_ARRAY(s_formatRanges); ++rangeNdx)
442     {
443         const VkFormat rangeBegin = s_formatRanges[rangeNdx].begin;
444         const VkFormat rangeEnd   = s_formatRanges[rangeNdx].end;
445 
446         for (testParams.format = rangeBegin; testParams.format != rangeEnd;
447              testParams.format = (VkFormat)(testParams.format + 1))
448         {
449             if (isCompressedFormat(testParams.format))
450                 continue;
451 
452             const uint32_t numPlanes = isYCbCrFormat(testParams.format) ? getPlaneCount(testParams.format) : 1;
453             testParams.control.compressionControlPlaneCount = is_fixed_rate_ex ? numPlanes : 0;
454 
455             const char *const enumName = getFormatName(testParams.format);
456             const string caseName      = de::toLower(string(enumName).substr(10));
457             addFunctionCase(group, caseName, imageCreateTest, testParams);
458         }
459     }
460 }
461 
createInstanceWithWsi(Context & context,Type wsiType,const vector<string> extraExtensions,const VkAllocationCallbacks * pAllocator=DE_NULL)462 CustomInstance createInstanceWithWsi(Context &context, Type wsiType, const vector<string> extraExtensions,
463                                      const VkAllocationCallbacks *pAllocator = DE_NULL)
464 {
465     const uint32_t version    = context.getUsedApiVersion();
466     vector<string> extensions = extraExtensions;
467 
468     extensions.push_back("VK_KHR_surface");
469     extensions.push_back(getExtensionName(wsiType));
470     extensions.push_back("VK_KHR_get_surface_capabilities2");
471 
472     vector<string> instanceExtensions;
473     for (const auto &ext : extensions)
474     {
475         if (!context.isInstanceFunctionalitySupported(ext))
476             TCU_THROW(NotSupportedError, (ext + " is not supported").c_str());
477 
478         if (!isCoreInstanceExtension(version, ext))
479             instanceExtensions.push_back(ext);
480     }
481 
482     return vkt::createCustomInstanceWithExtensions(context, instanceExtensions, pAllocator);
483 }
484 struct InstanceHelper
485 {
486     const vector<VkExtensionProperties> supportedExtensions;
487     CustomInstance instance;
488     const InstanceDriver &vki;
489 
InstanceHelpervkt::api::InstanceHelper490     InstanceHelper(Context &context, Type wsiType, const VkAllocationCallbacks *pAllocator = DE_NULL)
491         : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
492         , instance(createInstanceWithWsi(context, wsiType, vector<string>(), pAllocator))
493         , vki(instance.getDriver())
494     {
495     }
496 
InstanceHelpervkt::api::InstanceHelper497     InstanceHelper(Context &context, Type wsiType, const vector<string> &extensions,
498                    const VkAllocationCallbacks *pAllocator = DE_NULL)
499         : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
500         , instance(createInstanceWithWsi(context, wsiType, extensions, pAllocator))
501         , vki(instance.getDriver())
502     {
503     }
504 };
505 
createDeviceWithWsi(const PlatformInterface & vkp,uint32_t apiVersion,VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const vector<string> & additionalExtensions,uint32_t queueFamilyIndex,bool validationEnabled,const VkAllocationCallbacks * pAllocator=DE_NULL)506 Move<VkDevice> createDeviceWithWsi(const PlatformInterface &vkp, uint32_t apiVersion, VkInstance instance,
507                                    const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
508                                    const Extensions &supportedExtensions, const vector<string> &additionalExtensions,
509                                    uint32_t queueFamilyIndex, bool validationEnabled,
510                                    const VkAllocationCallbacks *pAllocator = DE_NULL)
511 {
512     const float queuePriorities[]           = {1.0f};
513     const VkDeviceQueueCreateInfo queueInfo = {
514         VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
515         nullptr,
516         (VkDeviceQueueCreateFlags)0,
517         queueFamilyIndex,
518         DE_LENGTH_OF_ARRAY(queuePriorities),
519         &queuePriorities[0],
520     };
521 
522     vector<string> extensions;
523     extensions.push_back("VK_KHR_swapchain");
524     extensions.push_back("VK_EXT_image_compression_control");
525     extensions.push_back("VK_EXT_image_compression_control_swapchain");
526     extensions.insert(end(extensions), begin(additionalExtensions), end(additionalExtensions));
527 
528     for (const auto &extName : extensions)
529     {
530         if (!isCoreDeviceExtension(apiVersion, extName) &&
531             !isExtensionStructSupported(supportedExtensions, RequiredExtension(extName)))
532             TCU_THROW(NotSupportedError, extName + " is not supported");
533     }
534 
535     vk::VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT imageCompressionSwapchain = initVulkanStructure();
536     imageCompressionSwapchain.imageCompressionControlSwapchain                                = VK_TRUE;
537 
538     const VkPhysicalDeviceFeatures features = {};
539 
540     // Convert from std::vector<std::string> to std::vector<const char*>.
541     std::vector<const char *> extensionsChar;
542     extensionsChar.reserve(extensions.size());
543     std::transform(begin(extensions), end(extensions), std::back_inserter(extensionsChar),
544                    [](const std::string &s) { return s.c_str(); });
545 
546     const VkDeviceCreateInfo deviceParams = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
547                                              &imageCompressionSwapchain,
548                                              (VkDeviceCreateFlags)0,
549                                              1u,
550                                              &queueInfo,
551                                              0u,                                           // enabledLayerCount
552                                              nullptr,                                      // ppEnabledLayerNames
553                                              static_cast<uint32_t>(extensionsChar.size()), // enabledExtensionCount
554                                              extensionsChar.data(),                        // ppEnabledExtensionNames
555                                              &features};
556 
557     return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
558 }
559 
560 struct DeviceHelper
561 {
562     const VkPhysicalDevice physicalDevice;
563     const uint32_t queueFamilyIndex;
564     const Unique<VkDevice> device;
565     const DeviceDriver vkd;
566     const VkQueue queue;
567 
DeviceHelpervkt::api::DeviceHelper568     DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance,
569                  const vector<VkSurfaceKHR> &surface, const vector<string> &additionalExtensions = vector<string>(),
570                  const VkAllocationCallbacks *pAllocator = DE_NULL)
571         : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
572         , queueFamilyIndex(chooseQueueFamilyIndex(vki, physicalDevice, surface))
573         , device(createDeviceWithWsi(context.getPlatformInterface(), context.getUsedApiVersion(), instance, vki,
574                                      physicalDevice, enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL),
575                                      additionalExtensions, queueFamilyIndex,
576                                      context.getTestContext().getCommandLine().isValidationEnabled(), pAllocator))
577         , vkd(context.getPlatformInterface(), instance, *device, context.getUsedApiVersion(),
578               context.getTestContext().getCommandLine())
579         , queue(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
580     {
581     }
582 
583     // Single-surface shortcut.
DeviceHelpervkt::api::DeviceHelper584     DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance, VkSurfaceKHR surface,
585                  const vector<string> &additionalExtensions = vector<string>(),
586                  const VkAllocationCallbacks *pAllocator    = DE_NULL)
587         : DeviceHelper(context, vki, instance, vector<VkSurfaceKHR>(1u, surface), additionalExtensions, pAllocator)
588     {
589     }
590 };
swapchainCreateTest(Context & context,TestParams testParams)591 static tcu::TestStatus swapchainCreateTest(Context &context, TestParams testParams)
592 {
593     checkImageCompressionControlSupport(context, true);
594 
595     tcu::TestLog &log = context.getTestContext().getLog();
596     tcu::ResultCollector results(log);
597 
598     const InstanceHelper instHelper(context, testParams.wsiType);
599     const wsi::NativeObjects native(context, instHelper.supportedExtensions, testParams.wsiType);
600     const bool is_fixed_rate_ex = testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
601 
602     VkExtent2D extent2d = {16, 16};
603     VkImageCompressionFixedRateFlagsEXT planeFlags[3]{};
604 
605     for (unsigned i{}; i < (is_fixed_rate_ex ? 24u : 1u); i++)
606     {
607         planeFlags[0] ^= 3 << i;
608 
609         if (is_fixed_rate_ex)
610         {
611             testParams.control.pFixedRateFlags = planeFlags;
612         }
613 
614         const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, testParams.wsiType,
615                                                          native.getDisplay(), native.getWindow(),
616                                                          context.getTestContext().getCommandLine()));
617 
618         const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface, vector<string>());
619 
620         VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo = initVulkanStructure();
621         VkSurfaceCapabilities2KHR caps              = initVulkanStructure();
622         surfaceInfo.surface                         = surface.get();
623 
624         instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(devHelper.physicalDevice, &surfaceInfo, &caps);
625 
626         uint32_t numFormats;
627         instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(devHelper.physicalDevice, &surfaceInfo, &numFormats,
628                                                            nullptr);
629 
630         vector<VkSurfaceFormat2KHR> formats(numFormats);
631         VkImageCompressionPropertiesEXT *compressionProps = new VkImageCompressionPropertiesEXT[numFormats];
632         for (uint32_t j = 0; j < numFormats; ++j)
633         {
634             VkImageCompressionPropertiesEXT formatCompressionProps = initVulkanStructure();
635             VkSurfaceFormat2KHR surfaceFormat                      = initVulkanStructure();
636 
637             compressionProps[j] = formatCompressionProps;
638             formats[j]          = surfaceFormat;
639             formats[j].pNext    = &compressionProps[j];
640         }
641 
642         instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(devHelper.physicalDevice, &surfaceInfo, &numFormats,
643                                                            formats.data());
644 
645         uint32_t queueFamilyIndex = devHelper.queueFamilyIndex;
646 
647         for (uint32_t j = 0; j < numFormats; ++j)
648         {
649             VkSurfaceFormat2KHR format                          = formats[j];
650             testParams.format                                   = format.surfaceFormat.format;
651             VkImageCompressionFlagsEXT supportedCompressionMode = compressionProps[j].imageCompressionFlags;
652             VkImageCompressionFixedRateFlagsEXT supportedCompressionRate =
653                 compressionProps[j].imageCompressionFixedRateFlags;
654 
655             const uint32_t numPlanes = isYCbCrFormat(testParams.format) ? getPlaneCount(testParams.format) : 1;
656             testParams.control.compressionControlPlaneCount = is_fixed_rate_ex ? numPlanes : 0;
657 
658             // check that is format is compatible with selected compression mode/rate
659             if (((testParams.control.flags & supportedCompressionMode) == 0) ||
660                 (is_fixed_rate_ex && ((testParams.control.pFixedRateFlags[0] & supportedCompressionRate) == 0)))
661             {
662 
663                 // When testing fixed rate default, query returns fixed rate explicit flag - don't skip it unless compression rate
664                 //  is also zero
665                 if (!((testParams.control.flags == VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT) &&
666                       (supportedCompressionRate != 0)))
667                     TCU_THROW(NotSupportedError, "Swapchain compression control and format not compatible");
668             }
669 
670             if (is_fixed_rate_ex && (numPlanes >= 1))
671             {
672                 // only use compression rate that is supported
673                 testParams.control.pFixedRateFlags[0] =
674                     testParams.control.pFixedRateFlags[0] & supportedCompressionRate;
675             }
676 
677             VkSwapchainCreateInfoKHR swapchainInfo = initVulkanStructure();
678             swapchainInfo.surface                  = surface.get();
679             swapchainInfo.minImageCount            = caps.surfaceCapabilities.minImageCount;
680             swapchainInfo.imageFormat              = format.surfaceFormat.format;
681             swapchainInfo.imageColorSpace          = format.surfaceFormat.colorSpace;
682             swapchainInfo.imageExtent              = extent2d;
683             swapchainInfo.imageArrayLayers         = 1;
684             swapchainInfo.imageUsage               = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
685             swapchainInfo.imageSharingMode         = VK_SHARING_MODE_EXCLUSIVE;
686             swapchainInfo.queueFamilyIndexCount    = 1;
687             swapchainInfo.pQueueFamilyIndices      = &queueFamilyIndex;
688             swapchainInfo.preTransform             = caps.surfaceCapabilities.currentTransform;
689             swapchainInfo.compositeAlpha           = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
690             swapchainInfo.presentMode              = VK_PRESENT_MODE_FIFO_KHR;
691             swapchainInfo.clipped                  = VK_TRUE;
692 
693             swapchainInfo.pNext = &testParams.control;
694 
695             Move<VkSwapchainKHR> swapchain = createSwapchainKHR(devHelper.vkd, devHelper.device.get(), &swapchainInfo);
696 
697             uint32_t imageCount = 0;
698             devHelper.vkd.getSwapchainImagesKHR(devHelper.device.get(), swapchain.get(), &imageCount, nullptr);
699             vector<VkImage> images(imageCount);
700             devHelper.vkd.getSwapchainImagesKHR(devHelper.device.get(), swapchain.get(), &imageCount, images.data());
701 
702             validate(instHelper.vki, devHelper.vkd, results, devHelper.physicalDevice, devHelper.device.get(),
703                      testParams, images[0]);
704         }
705 
706         delete[] compressionProps;
707     }
708 
709     return tcu::TestStatus(results.getResult(), results.getMessage());
710 }
711 
addAhbCompressionControlTests(tcu::TestCaseGroup * group,TestParams testParams)712 void addAhbCompressionControlTests(tcu::TestCaseGroup *group, TestParams testParams)
713 {
714     // Ahb formats
715     static const vk::VkFormat ahbFormats[] = {VK_FORMAT_R8G8B8A8_UNORM,
716                                               VK_FORMAT_R8G8B8_UNORM,
717                                               VK_FORMAT_R5G6B5_UNORM_PACK16,
718                                               VK_FORMAT_R16G16B16A16_SFLOAT,
719                                               VK_FORMAT_A2B10G10R10_UNORM_PACK32,
720                                               VK_FORMAT_D16_UNORM,
721                                               VK_FORMAT_X8_D24_UNORM_PACK32,
722                                               VK_FORMAT_D24_UNORM_S8_UINT,
723                                               VK_FORMAT_D32_SFLOAT,
724                                               VK_FORMAT_D32_SFLOAT_S8_UINT,
725                                               VK_FORMAT_S8_UINT};
726 
727     for (int index = 0; index < DE_LENGTH_OF_ARRAY(ahbFormats); ++index)
728     {
729         testParams.format          = ahbFormats[index];
730         const char *const enumName = getFormatName(testParams.format);
731         const string caseName      = de::toLower(string(enumName).substr(10));
732         addFunctionCase(group, caseName, ahbImageCreateTest, testParams);
733     }
734 }
735 
createImageCompressionControlTests(tcu::TestContext & testCtx)736 tcu::TestCaseGroup *createImageCompressionControlTests(tcu::TestContext &testCtx)
737 {
738     // Test for image compression control.
739     de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "image_compression_control"));
740 
741     TestParams testParams{};
742     // Test creating images with compression control struct
743     tcu::TestCaseGroup *subgroup(new tcu::TestCaseGroup(testCtx, "create_image"));
744 
745     // Queries images created without compression control struct.
746     subgroup->addChild(createTestGroup(testCtx, "no_compression_control", addImageCompressionControlTests, testParams));
747 
748     testParams.useExtension  = true;
749     testParams.control       = initVulkanStructure();
750     testParams.control.flags = VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT;
751 
752     struct
753     {
754         const char *name;
755         VkImageCompressionFlagsEXT flag;
756     } constexpr compression_flags[] = {
757         {"default", VK_IMAGE_COMPRESSION_DEFAULT_EXT},
758         {"fixed_rate_default", VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT},
759         {"disabled", VK_IMAGE_COMPRESSION_DISABLED_EXT},
760         {"explicit", VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT},
761     };
762 
763     for (auto &flag : compression_flags)
764     {
765         testParams.control.flags = flag.flag;
766         // Queries images created with compression control struct.
767         subgroup->addChild(createTestGroup(testCtx, flag.name, addImageCompressionControlTests, testParams));
768     }
769     group->addChild(subgroup);
770 
771     // Test creating Android Hardware buffer with compression control struct
772     subgroup = new tcu::TestCaseGroup(testCtx, "android_hardware_buffer");
773 
774     for (auto &flag : compression_flags)
775     {
776         testParams.control.flags = flag.flag;
777         // Queries images created with compression control struct.
778         subgroup->addChild(createTestGroup(testCtx, flag.name, addAhbCompressionControlTests, testParams));
779     }
780 
781     group->addChild(subgroup);
782 
783     subgroup = new tcu::TestCaseGroup(testCtx, "swapchain");
784     for (int typeNdx = 0; typeNdx < vk::wsi::TYPE_LAST; ++typeNdx)
785     {
786         const vk::wsi::Type wsiType = (vk::wsi::Type)typeNdx;
787         testParams.wsiType          = wsiType;
788 
789         tcu::TestCaseGroup *wsi_subgroup(new tcu::TestCaseGroup(testCtx, getName(wsiType)));
790 
791         for (auto &flag : compression_flags)
792         {
793             testParams.control.flags = flag.flag;
794             addFunctionCase(wsi_subgroup, flag.name, swapchainCreateTest, testParams);
795         }
796         subgroup->addChild(wsi_subgroup);
797     }
798 
799     group->addChild(subgroup);
800 
801     return group.release();
802 }
803 
804 } // namespace api
805 
806 } // namespace vkt
807