xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/wsi/vktWsiColorSpaceTests.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 VkSwapchain Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktWsiSwapchainTests.hpp"
25 
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vktCustomInstancesDevices.hpp"
29 #include "vktNativeObjectsUtil.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkPlatform.hpp"
33 #include "vkStrUtil.hpp"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkMemUtil.hpp"
38 #include "vkDeviceUtil.hpp"
39 #include "vkPrograms.hpp"
40 #include "vkTypeUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkWsiPlatform.hpp"
43 #include "vkWsiUtil.hpp"
44 #include "vkAllocationCallbackUtil.hpp"
45 #include "vkCmdUtil.hpp"
46 #include "vkObjUtil.hpp"
47 #include "tcuSurface.hpp"
48 #include "vkImageUtil.hpp"
49 
50 #include "tcuTestLog.hpp"
51 #include "tcuFormatUtil.hpp"
52 #include "tcuPlatform.hpp"
53 #include "tcuResultCollector.hpp"
54 #include "tcuCommandLine.hpp"
55 
56 #include "deUniquePtr.hpp"
57 #include "deStringUtil.hpp"
58 #include "deArrayUtil.hpp"
59 #include "deSharedPtr.hpp"
60 
61 #include <limits>
62 
63 namespace vkt
64 {
65 namespace wsi
66 {
67 
68 namespace
69 {
70 
71 using namespace vk;
72 using namespace vk::wsi;
73 
74 using tcu::Maybe;
75 using tcu::TestLog;
76 using tcu::UVec2;
77 
78 using de::MovePtr;
79 using de::UniquePtr;
80 
81 using std::string;
82 using std::vector;
83 
84 typedef vector<VkExtensionProperties> Extensions;
85 
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)86 void checkAllSupported(const Extensions &supportedExtensions, const vector<string> &requiredExtensions)
87 {
88     for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
89          requiredExtName != requiredExtensions.end(); ++requiredExtName)
90     {
91         if (!isExtensionStructSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
92             TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
93     }
94 }
95 
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,Type wsiType,const VkAllocationCallbacks * pAllocator=DE_NULL)96 CustomInstance createInstanceWithWsi(Context &context, const Extensions &supportedExtensions, Type wsiType,
97                                      const VkAllocationCallbacks *pAllocator = DE_NULL)
98 {
99     vector<string> extensions;
100 
101     extensions.push_back("VK_KHR_surface");
102     extensions.push_back(getExtensionName(wsiType));
103     if (isDisplaySurface(wsiType))
104         extensions.push_back("VK_KHR_display");
105 
106     // VK_EXT_swapchain_colorspace adds new surface formats. Driver can enumerate
107     // the formats regardless of whether VK_EXT_swapchain_colorspace was enabled,
108     // but using them without enabling the extension is not allowed. Thus we have
109     // two options:
110     //
111     // 1) Filter out non-core formats to stay within valid usage.
112     //
113     // 2) Enable VK_EXT_swapchain colorspace if advertised by the driver.
114     //
115     // We opt for (2) as it provides basic coverage for the extension as a bonus.
116     if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_swapchain_colorspace")))
117         extensions.push_back("VK_EXT_swapchain_colorspace");
118 
119     checkAllSupported(supportedExtensions, extensions);
120 
121     return createCustomInstanceWithExtensions(context, extensions, pAllocator);
122 }
123 
getDeviceFeaturesForWsi(void)124 VkPhysicalDeviceFeatures getDeviceFeaturesForWsi(void)
125 {
126     VkPhysicalDeviceFeatures features;
127     deMemset(&features, 0, sizeof(features));
128     return features;
129 }
130 
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const uint32_t queueFamilyIndex,const VkAllocationCallbacks * pAllocator,bool validationEnabled)131 Move<VkDevice> createDeviceWithWsi(const vk::PlatformInterface &vkp, vk::VkInstance instance,
132                                    const InstanceInterface &vki, VkPhysicalDevice physicalDevice,
133                                    const Extensions &supportedExtensions, const uint32_t queueFamilyIndex,
134                                    const VkAllocationCallbacks *pAllocator, bool validationEnabled)
135 {
136     const float queuePriorities[]              = {1.0f};
137     const VkDeviceQueueCreateInfo queueInfos[] = {{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, DE_NULL,
138                                                    (VkDeviceQueueCreateFlags)0, queueFamilyIndex,
139                                                    DE_LENGTH_OF_ARRAY(queuePriorities), &queuePriorities[0]}};
140     const VkPhysicalDeviceFeatures features    = getDeviceFeaturesForWsi();
141     vector<const char *> extensions;
142 
143     if (!isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_KHR_swapchain")))
144         TCU_THROW(NotSupportedError, "VK_KHR_swapchain is not supported");
145     extensions.push_back("VK_KHR_swapchain");
146 
147     if (isExtensionStructSupported(supportedExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
148         extensions.push_back("VK_EXT_hdr_metadata");
149 
150     VkDeviceCreateInfo deviceParams = {VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
151                                        DE_NULL,
152                                        (VkDeviceCreateFlags)0,
153                                        DE_LENGTH_OF_ARRAY(queueInfos),
154                                        &queueInfos[0],
155                                        0u,      // enabledLayerCount
156                                        DE_NULL, // ppEnabledLayerNames
157                                        (uint32_t)extensions.size(),
158                                        extensions.empty() ? DE_NULL : &extensions[0],
159                                        &features};
160 
161     return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
162 }
163 
164 struct InstanceHelper
165 {
166     const vector<VkExtensionProperties> supportedExtensions;
167     const CustomInstance instance;
168     const InstanceDriver &vki;
169 
InstanceHelpervkt::wsi::__anond46467fd0111::InstanceHelper170     InstanceHelper(Context &context, Type wsiType, const VkAllocationCallbacks *pAllocator = DE_NULL)
171         : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), DE_NULL))
172         , instance(createInstanceWithWsi(context, supportedExtensions, wsiType, pAllocator))
173         , vki(instance.getDriver())
174     {
175     }
176 };
177 
178 struct DeviceHelper
179 {
180     const VkPhysicalDevice physicalDevice;
181     const uint32_t queueFamilyIndex;
182     const Unique<VkDevice> device;
183     const DeviceDriver vkd;
184     const VkQueue queue;
185 
DeviceHelpervkt::wsi::__anond46467fd0111::DeviceHelper186     DeviceHelper(Context &context, const InstanceInterface &vki, VkInstance instance, VkSurfaceKHR surface,
187                  const VkAllocationCallbacks *pAllocator = DE_NULL)
188         : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
189         , queueFamilyIndex(chooseQueueFamilyIndex(vki, physicalDevice, surface))
190         , device(createDeviceWithWsi(context.getPlatformInterface(), instance, vki, physicalDevice,
191                                      enumerateDeviceExtensionProperties(vki, physicalDevice, DE_NULL), queueFamilyIndex,
192                                      pAllocator, context.getTestContext().getCommandLine().isValidationEnabled()))
193         , vkd(context.getPlatformInterface(), instance, *device, context.getUsedApiVersion(),
194               context.getTestContext().getCommandLine())
195         , queue(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
196     {
197     }
198 };
199 
200 enum TestDimension
201 {
202     TEST_DIMENSION_MIN_IMAGE_COUNT = 0, //!< Test all supported image counts
203     TEST_DIMENSION_IMAGE_FORMAT,        //!< Test all supported formats
204     TEST_DIMENSION_IMAGE_EXTENT,        //!< Test various (supported) extents
205     TEST_DIMENSION_IMAGE_ARRAY_LAYERS,
206     TEST_DIMENSION_IMAGE_USAGE,
207     TEST_DIMENSION_IMAGE_SHARING_MODE,
208     TEST_DIMENSION_PRE_TRANSFORM,
209     TEST_DIMENSION_COMPOSITE_ALPHA,
210     TEST_DIMENSION_PRESENT_MODE,
211     TEST_DIMENSION_CLIPPED,
212 
213     TEST_DIMENSION_LAST
214 };
215 
216 struct TestParameters
217 {
218     Type wsiType;
219     TestDimension dimension;
220 
TestParametersvkt::wsi::__anond46467fd0111::TestParameters221     TestParameters(Type wsiType_, TestDimension dimension_) : wsiType(wsiType_), dimension(dimension_)
222     {
223     }
224 
TestParametersvkt::wsi::__anond46467fd0111::TestParameters225     TestParameters(void) : wsiType(TYPE_LAST), dimension(TEST_DIMENSION_LAST)
226     {
227     }
228 };
229 
230 struct GroupParameters
231 {
232     typedef FunctionInstance1<TestParameters>::Function Function;
233 
234     Type wsiType;
235     Function function;
236 
GroupParametersvkt::wsi::__anond46467fd0111::GroupParameters237     GroupParameters(Type wsiType_, Function function_) : wsiType(wsiType_), function(function_)
238     {
239     }
240 
GroupParametersvkt::wsi::__anond46467fd0111::GroupParameters241     GroupParameters(void) : wsiType(TYPE_LAST), function((Function)DE_NULL)
242     {
243     }
244 };
245 
getBasicSwapchainParameters(Type wsiType,const InstanceInterface & vki,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkSurfaceFormatKHR surfaceFormat,const tcu::UVec2 & desiredSize,uint32_t desiredImageCount,VkColorSpaceKHR desiredColorspace=VK_COLOR_SPACE_MAX_ENUM_KHR)246 VkSwapchainCreateInfoKHR getBasicSwapchainParameters(Type wsiType, const InstanceInterface &vki,
247                                                      VkPhysicalDevice physicalDevice, VkSurfaceKHR surface,
248                                                      VkSurfaceFormatKHR surfaceFormat, const tcu::UVec2 &desiredSize,
249                                                      uint32_t desiredImageCount,
250                                                      VkColorSpaceKHR desiredColorspace = VK_COLOR_SPACE_MAX_ENUM_KHR)
251 {
252     bool setColorspaceManually = desiredColorspace != VK_COLOR_SPACE_MAX_ENUM_KHR;
253 
254     const VkSurfaceCapabilitiesKHR capabilities  = getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
255     const PlatformProperties &platformProperties = getPlatformProperties(wsiType);
256     const VkSurfaceCapabilitiesKHR surfaceCapabilities =
257         getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
258 
259     // Check that the device has at least one supported alpha compositing mode
260     // and pick the first supported mode to be used.
261     vk::VkCompositeAlphaFlagsKHR alpha = 0;
262     for (uint32_t i = 1u; i <= surfaceCapabilities.supportedCompositeAlpha; i <<= 1u)
263     {
264         if ((i & surfaceCapabilities.supportedCompositeAlpha) != 0)
265         {
266             alpha = i;
267             break;
268         }
269     }
270     if (alpha == 0)
271         TCU_THROW(NotSupportedError, "No supported composite alphas available.");
272 
273     const VkSurfaceTransformFlagBitsKHR transform =
274         (capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
275             VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
276             capabilities.currentTransform;
277     const VkSwapchainCreateInfoKHR parameters = {
278         VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
279         DE_NULL,
280         (VkSwapchainCreateFlagsKHR)0,
281         surface,
282         de::clamp(desiredImageCount, capabilities.minImageCount,
283                   capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
284                                                    capabilities.minImageCount + desiredImageCount),
285         surfaceFormat.format,
286         (setColorspaceManually ? desiredColorspace : surfaceFormat.colorSpace),
287         (platformProperties.swapchainExtent == PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
288              capabilities.currentExtent :
289              vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
290         1u, // imageArrayLayers
291         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
292         VK_SHARING_MODE_EXCLUSIVE,
293         0u,
294         (const uint32_t *)DE_NULL,
295         transform,
296         static_cast<VkCompositeAlphaFlagBitsKHR>(alpha),
297         VK_PRESENT_MODE_FIFO_KHR,
298         VK_FALSE,         // clipped
299         (VkSwapchainKHR)0 // oldSwapchain
300     };
301 
302     return parameters;
303 }
304 
305 typedef de::SharedPtr<Unique<VkCommandBuffer>> CommandBufferSp;
306 typedef de::SharedPtr<Unique<VkFence>> FenceSp;
307 typedef de::SharedPtr<Unique<VkSemaphore>> SemaphoreSp;
308 
createFences(const DeviceInterface & vkd,const VkDevice device,size_t numFences)309 vector<FenceSp> createFences(const DeviceInterface &vkd, const VkDevice device, size_t numFences)
310 {
311     vector<FenceSp> fences(numFences);
312 
313     for (size_t ndx = 0; ndx < numFences; ++ndx)
314         fences[ndx] = FenceSp(new Unique<VkFence>(createFence(vkd, device)));
315 
316     return fences;
317 }
318 
createSemaphores(const DeviceInterface & vkd,const VkDevice device,size_t numSemaphores)319 vector<SemaphoreSp> createSemaphores(const DeviceInterface &vkd, const VkDevice device, size_t numSemaphores)
320 {
321     vector<SemaphoreSp> semaphores(numSemaphores);
322 
323     for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
324         semaphores[ndx] = SemaphoreSp(new Unique<VkSemaphore>(createSemaphore(vkd, device)));
325 
326     return semaphores;
327 }
328 
allocateCommandBuffers(const DeviceInterface & vkd,const VkDevice device,const VkCommandPool commandPool,const VkCommandBufferLevel level,const size_t numCommandBuffers)329 vector<CommandBufferSp> allocateCommandBuffers(const DeviceInterface &vkd, const VkDevice device,
330                                                const VkCommandPool commandPool, const VkCommandBufferLevel level,
331                                                const size_t numCommandBuffers)
332 {
333     vector<CommandBufferSp> buffers(numCommandBuffers);
334 
335     for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
336         buffers[ndx] =
337             CommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
338 
339     return buffers;
340 }
341 
getPixel(const DeviceInterface & vkd,const VkDevice device,const VkQueue queue,const VkCommandPool & commandPool,Allocator & allocator,const tcu::UVec2 size,const tcu::TextureFormat textureFormat,const VkImage * image)342 tcu::Vec4 getPixel(const DeviceInterface &vkd, const VkDevice device, const VkQueue queue,
343                    const VkCommandPool &commandPool, Allocator &allocator, const tcu::UVec2 size,
344                    const tcu::TextureFormat textureFormat, const VkImage *image)
345 {
346     Move<VkCommandBuffer> commandBuffer;
347     Move<VkBuffer> resultBuffer;
348     de::MovePtr<Allocation> resultBufferMemory;
349 
350     commandBuffer = allocateCommandBuffer(vkd, device, commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
351 
352     // Result Buffer
353     {
354         const VkDeviceSize bufferSize       = textureFormat.getPixelSize() * size.x() * size.y();
355         const VkBufferCreateInfo createInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
356 
357         resultBuffer = createBuffer(vkd, device, &createInfo);
358         resultBufferMemory =
359             allocator.allocate(getBufferMemoryRequirements(vkd, device, *resultBuffer), MemoryRequirement::HostVisible);
360 
361         VK_CHECK(vkd.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(),
362                                       resultBufferMemory->getOffset()));
363     }
364 
365     beginCommandBuffer(vkd, *commandBuffer, 0u);
366     {
367         copyImageToBuffer(vkd, *commandBuffer, *image, *resultBuffer, tcu::IVec2(size.x(), size.y()),
368                           VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
369     }
370     endCommandBuffer(vkd, *commandBuffer);
371     submitCommandsAndWait(vkd, device, queue, commandBuffer.get());
372 
373     invalidateMappedMemoryRange(vkd, device, resultBufferMemory->getMemory(), 0, VK_WHOLE_SIZE);
374 
375     tcu::ConstPixelBufferAccess resultAccess(textureFormat, tcu::IVec3(size.x(), size.y(), 1),
376                                              resultBufferMemory->getHostPtr());
377 
378     return (resultAccess.getPixel(128, 128));
379 }
380 
basicExtensionTest(Context & context,Type wsiType)381 tcu::TestStatus basicExtensionTest(Context &context, Type wsiType)
382 {
383     const tcu::UVec2 desiredSize(256, 256);
384     const InstanceHelper instHelper(context, wsiType);
385     const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
386     const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
387                                                      native.getWindow(), context.getTestContext().getCommandLine()));
388     const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
389 
390     if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(),
391                       "VK_EXT_swapchain_colorspace"))
392         TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
393 
394     const vector<VkSurfaceFormatKHR> formats =
395         getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
396 
397     bool found = false;
398     for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
399     {
400         if (curFmt->colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
401         {
402             found = true;
403             break;
404         }
405     }
406     if (!found)
407     {
408         TCU_THROW(NotSupportedError,
409                   "VK_EXT_swapchain_colorspace supported, but no non-SRGB_NONLINEAR_KHR surface formats found.");
410     }
411     return tcu::TestStatus::pass("Extension tests succeeded");
412 }
413 
414 struct TestParams
415 {
416     Type wsiType;
417     VkFormat format;
418 };
419 
420 // Create swapchain with multiple images on different colorspaces and compare pixels on those images.
colorspaceCompareTest(Context & context,TestParams params)421 tcu::TestStatus colorspaceCompareTest(Context &context, TestParams params)
422 {
423     if (!context.isInstanceFunctionalitySupported("VK_EXT_swapchain_colorspace"))
424         TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
425 
426     const tcu::UVec2 desiredSize(256, 256);
427     const InstanceHelper instHelper(context, params.wsiType);
428     const NativeObjects native(context, instHelper.supportedExtensions, params.wsiType, tcu::just(desiredSize));
429     const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, params.wsiType,
430                                                      native.getDisplay(), native.getWindow(),
431                                                      context.getTestContext().getCommandLine()));
432     const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
433 
434     const vector<VkSurfaceFormatKHR> queriedFormats =
435         getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
436 
437     vector<vk::VkColorSpaceKHR> supportedColorSpaces;
438     for (const auto &queriedFormat : queriedFormats)
439     {
440         if (queriedFormat.format == params.format)
441         {
442             supportedColorSpaces.push_back(queriedFormat.colorSpace);
443         }
444     }
445 
446     // Not supported if there's no color spaces for the format.
447     if (supportedColorSpaces.size() < 2)
448         TCU_THROW(NotSupportedError, "Format not supported");
449 
450     // Surface format is used to create the swapchain.
451     VkSurfaceFormatKHR surfaceFormat = {
452         params.format,             // format
453         supportedColorSpaces.at(0) // colorSpace
454     };
455 
456     tcu::Vec4 referenceColorspacePixel;
457     const tcu::TextureFormat textureFormat = vk::mapVkFormat(surfaceFormat.format);
458     const DeviceInterface &vkd             = devHelper.vkd;
459     const VkDevice device                  = *devHelper.device;
460     SimpleAllocator allocator(vkd, device,
461                               getPhysicalDeviceMemoryProperties(instHelper.vki, context.getPhysicalDevice()));
462 
463     for (size_t colorspaceNdx = 0; colorspaceNdx < supportedColorSpaces.size(); ++colorspaceNdx)
464     {
465         const VkSwapchainCreateInfoKHR swapchainInfo =
466             getBasicSwapchainParameters(params.wsiType, instHelper.vki, devHelper.physicalDevice, *surface,
467                                         surfaceFormat, desiredSize, 2, supportedColorSpaces[colorspaceNdx]);
468         const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, device, &swapchainInfo));
469         const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
470         const vector<VkExtensionProperties> deviceExtensions(
471             enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
472 
473         const WsiTriangleRenderer renderer(
474             vkd, device, allocator, context.getBinaryCollection(), true, swapchainImages, swapchainImages,
475             swapchainInfo.imageFormat, tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
476 
477         const Move<VkCommandPool> commandPool(createCommandPool(
478             vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
479         const Move<VkSemaphore> imageReadySemaphore        = createSemaphore(vkd, device);
480         const Move<VkSemaphore> renderingCompleteSemaphore = createSemaphore(vkd, device);
481         const Move<VkCommandBuffer> commandBuffer =
482             allocateCommandBuffer(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
483 
484         try
485         {
486             uint32_t imageNdx = ~0u;
487 
488             {
489                 const VkResult acquireResult =
490                     vkd.acquireNextImageKHR(device, *swapchain, std::numeric_limits<uint64_t>::max(),
491                                             imageReadySemaphore.get(), DE_NULL, &imageNdx);
492 
493                 if (acquireResult == VK_SUBOPTIMAL_KHR)
494                 {
495                     context.getTestContext().getLog()
496                         << TestLog::Message << "Got " << acquireResult << TestLog::EndMessage;
497                 }
498                 else
499                 {
500                     VK_CHECK(acquireResult);
501                 }
502             }
503 
504             TCU_CHECK((size_t)imageNdx < swapchainImages.size());
505 
506             {
507                 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
508                 const VkSubmitInfo submitInfo           = {VK_STRUCTURE_TYPE_SUBMIT_INFO,
509                                                            DE_NULL,
510                                                            0u,
511                                                            &imageReadySemaphore.get(),
512                                                            &waitDstStage,
513                                                            1u,
514                                                            &commandBuffer.get(),
515                                                            1u,
516                                                            &renderingCompleteSemaphore.get()};
517                 const VkPresentInfoKHR presentInfo      = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
518                                                            DE_NULL,
519                                                            1u,
520                                                            &renderingCompleteSemaphore.get(),
521                                                            1u,
522                                                            &swapchain.get(),
523                                                            &imageNdx,
524                                                            (VkResult *)DE_NULL};
525 
526                 renderer.recordFrame(commandBuffer.get(), imageNdx, 0);
527                 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, DE_NULL));
528                 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
529             }
530 
531             // Set reference pixelBufferAccess for comparison.
532             if (colorspaceNdx == 0)
533             {
534                 referenceColorspacePixel = getPixel(vkd, device, devHelper.queue, commandPool.get(), allocator,
535                                                     desiredSize, textureFormat, &swapchainImages[imageNdx]);
536                 continue;
537             }
538 
539             // Compare pixels from images to make sure the colorspace makes no difference.
540             if (referenceColorspacePixel == getPixel(vkd, device, devHelper.queue, commandPool.get(), allocator,
541                                                      desiredSize, textureFormat, &swapchainImages[imageNdx]))
542                 continue;
543             else
544             {
545                 VK_CHECK(vkd.deviceWaitIdle(device));
546                 return tcu::TestStatus::fail("Colorspace comparison test failed");
547             }
548         }
549         catch (...)
550         {
551             // Make sure device is idle before destroying resources
552             vkd.deviceWaitIdle(device);
553             throw;
554         }
555     }
556 
557     VK_CHECK(vkd.deviceWaitIdle(device));
558     return tcu::TestStatus::pass("Colorspace comparison test succeeded");
559 }
560 
surfaceFormatRenderTest(Context & context,Type wsiType,const InstanceHelper & instHelper,const DeviceHelper & devHelper,VkSurfaceKHR surface,VkSurfaceFormatKHR curFmt,bool checkHdr=false)561 tcu::TestStatus surfaceFormatRenderTest(Context &context, Type wsiType, const InstanceHelper &instHelper,
562                                         const DeviceHelper &devHelper, VkSurfaceKHR surface, VkSurfaceFormatKHR curFmt,
563                                         bool checkHdr = false)
564 {
565     const tcu::UVec2 desiredSize(256, 256);
566     const DeviceInterface &vkd = devHelper.vkd;
567     const VkDevice device      = *devHelper.device;
568     SimpleAllocator allocator(vkd, device, getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
569 
570     const VkSwapchainCreateInfoKHR swapchainInfo =
571         getBasicSwapchainParameters(wsiType, instHelper.vki, devHelper.physicalDevice, surface, curFmt, desiredSize, 2);
572     const Unique<VkSwapchainKHR> swapchain(createSwapchainKHR(vkd, device, &swapchainInfo));
573     const vector<VkImage> swapchainImages = getSwapchainImages(vkd, device, *swapchain);
574     const vector<VkExtensionProperties> deviceExtensions(
575         enumerateDeviceExtensionProperties(instHelper.vki, devHelper.physicalDevice, DE_NULL));
576 
577     if (checkHdr && !isExtensionStructSupported(deviceExtensions, RequiredExtension("VK_EXT_hdr_metadata")))
578         TCU_THROW(NotSupportedError, "Extension VK_EXT_hdr_metadata not supported");
579 
580     const WsiTriangleRenderer renderer(vkd, device, allocator, context.getBinaryCollection(), true, swapchainImages,
581                                        swapchainImages, swapchainInfo.imageFormat,
582                                        tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
583 
584     const Unique<VkCommandPool> commandPool(
585         createCommandPool(vkd, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
586 
587     const size_t maxQueuedFrames = swapchainImages.size() * 2;
588 
589     // We need to keep hold of fences from vkAcquireNextImageKHR to actually
590     // limit number of frames we allow to be queued.
591     const vector<FenceSp> imageReadyFences(createFences(vkd, device, maxQueuedFrames));
592 
593     // We need maxQueuedFrames+1 for imageReadySemaphores pool as we need to pass
594     // the semaphore in same time as the fence we use to meter rendering.
595     const vector<SemaphoreSp> imageReadySemaphores(createSemaphores(vkd, device, maxQueuedFrames + 1));
596 
597     // For rest we simply need maxQueuedFrames as we will wait for image
598     // from frameNdx-maxQueuedFrames to become available to us, guaranteeing that
599     // previous uses must have completed.
600     const vector<SemaphoreSp> renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames));
601     const vector<CommandBufferSp> commandBuffers(
602         allocateCommandBuffers(vkd, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames));
603 
604     try
605     {
606         const uint32_t numFramesToRender = 60;
607 
608         for (uint32_t frameNdx = 0; frameNdx < numFramesToRender; ++frameNdx)
609         {
610             const VkFence imageReadyFence         = **imageReadyFences[frameNdx % imageReadyFences.size()];
611             const VkSemaphore imageReadySemaphore = **imageReadySemaphores[frameNdx % imageReadySemaphores.size()];
612             uint32_t imageNdx                     = ~0u;
613 
614             if (frameNdx >= maxQueuedFrames)
615                 VK_CHECK(
616                     vkd.waitForFences(device, 1u, &imageReadyFence, VK_TRUE, std::numeric_limits<uint64_t>::max()));
617 
618             VK_CHECK(vkd.resetFences(device, 1, &imageReadyFence));
619 
620             {
621                 const VkResult acquireResult =
622                     vkd.acquireNextImageKHR(device, *swapchain, std::numeric_limits<uint64_t>::max(),
623                                             imageReadySemaphore, (vk::VkFence)0, &imageNdx);
624 
625                 if (acquireResult == VK_SUBOPTIMAL_KHR)
626                     context.getTestContext().getLog() << TestLog::Message << "Got " << acquireResult << " at frame "
627                                                       << frameNdx << TestLog::EndMessage;
628                 else
629                     VK_CHECK(acquireResult);
630             }
631 
632             TCU_CHECK((size_t)imageNdx < swapchainImages.size());
633 
634             {
635                 const VkSemaphore renderingCompleteSemaphore =
636                     **renderingCompleteSemaphores[frameNdx % renderingCompleteSemaphores.size()];
637                 const VkCommandBuffer commandBuffer     = **commandBuffers[frameNdx % commandBuffers.size()];
638                 const VkPipelineStageFlags waitDstStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
639                 const VkSubmitInfo submitInfo           = {VK_STRUCTURE_TYPE_SUBMIT_INFO,
640                                                            DE_NULL,
641                                                            1u,
642                                                            &imageReadySemaphore,
643                                                            &waitDstStage,
644                                                            1u,
645                                                            &commandBuffer,
646                                                            1u,
647                                                            &renderingCompleteSemaphore};
648                 const VkPresentInfoKHR presentInfo      = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
649                                                            DE_NULL,
650                                                            1u,
651                                                            &renderingCompleteSemaphore,
652                                                            1u,
653                                                            &*swapchain,
654                                                            &imageNdx,
655                                                            (VkResult *)DE_NULL};
656 
657                 if (checkHdr)
658                 {
659                     const VkHdrMetadataEXT hdrData = {VK_STRUCTURE_TYPE_HDR_METADATA_EXT,
660                                                       DE_NULL,
661                                                       makeXYColorEXT(0.680f, 0.320f),
662                                                       makeXYColorEXT(0.265f, 0.690f),
663                                                       makeXYColorEXT(0.150f, 0.060f),
664                                                       makeXYColorEXT(0.3127f, 0.3290f),
665                                                       1000.0,
666                                                       0.0,
667                                                       1000.0,
668                                                       70.0};
669                     vector<VkSwapchainKHR> swapchainArray;
670 
671                     swapchainArray.push_back(*swapchain);
672                     vkd.setHdrMetadataEXT(device, (uint32_t)swapchainArray.size(), swapchainArray.data(), &hdrData);
673                 }
674 
675                 renderer.recordFrame(commandBuffer, imageNdx, frameNdx);
676                 VK_CHECK(vkd.queueSubmit(devHelper.queue, 1u, &submitInfo, imageReadyFence));
677                 VK_CHECK_WSI(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
678             }
679         }
680 
681         VK_CHECK(vkd.deviceWaitIdle(device));
682     }
683     catch (...)
684     {
685         // Make sure device is idle before destroying resources
686         vkd.deviceWaitIdle(device);
687         throw;
688     }
689 
690     return tcu::TestStatus::pass("Rendering test succeeded");
691 }
692 
surfaceFormatRenderTests(Context & context,Type wsiType)693 tcu::TestStatus surfaceFormatRenderTests(Context &context, Type wsiType)
694 {
695     const tcu::UVec2 desiredSize(256, 256);
696     const InstanceHelper instHelper(context, wsiType);
697     const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
698     const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
699                                                      native.getWindow(), context.getTestContext().getCommandLine()));
700     const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
701 
702     if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(),
703                       "VK_EXT_swapchain_colorspace"))
704         TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
705 
706     const vector<VkSurfaceFormatKHR> formats =
707         getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
708     for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
709     {
710         surfaceFormatRenderTest(context, wsiType, instHelper, devHelper, *surface, *curFmt);
711         context.getTestContext().touchWatchdog();
712     }
713     return tcu::TestStatus::pass("Rendering tests succeeded");
714 }
715 
surfaceFormatRenderWithHdrTests(Context & context,Type wsiType)716 tcu::TestStatus surfaceFormatRenderWithHdrTests(Context &context, Type wsiType)
717 {
718     const tcu::UVec2 desiredSize(256, 256);
719     const InstanceHelper instHelper(context, wsiType);
720     const NativeObjects native(context, instHelper.supportedExtensions, wsiType, 1u, tcu::just(desiredSize));
721     const Unique<VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, wsiType, native.getDisplay(),
722                                                      native.getWindow(), context.getTestContext().getCommandLine()));
723     const DeviceHelper devHelper(context, instHelper.vki, instHelper.instance, *surface);
724 
725     if (!de::contains(context.getInstanceExtensions().begin(), context.getInstanceExtensions().end(),
726                       "VK_EXT_swapchain_colorspace"))
727         TCU_THROW(NotSupportedError, "Extension VK_EXT_swapchain_colorspace not supported");
728 
729     const vector<VkSurfaceFormatKHR> formats =
730         getPhysicalDeviceSurfaceFormats(instHelper.vki, devHelper.physicalDevice, *surface);
731     for (vector<VkSurfaceFormatKHR>::const_iterator curFmt = formats.begin(); curFmt != formats.end(); ++curFmt)
732     {
733         surfaceFormatRenderTest(context, wsiType, instHelper, devHelper, *surface, *curFmt, true);
734         context.getTestContext().touchWatchdog();
735     }
736     return tcu::TestStatus::pass("Rendering tests succeeded");
737 }
738 
739 // We need different versions of this function in order to invoke
740 // different overloaded versions of addFunctionCaseWithPrograms.
getBasicRenderPrograms2(SourceCollections & dst,TestParams)741 void getBasicRenderPrograms2(SourceCollections &dst, TestParams)
742 {
743     WsiTriangleRenderer::getPrograms(dst);
744 }
745 
getBasicRenderPrograms(SourceCollections & dst,Type)746 void getBasicRenderPrograms(SourceCollections &dst, Type)
747 {
748     WsiTriangleRenderer::getPrograms(dst);
749 }
750 } // namespace
751 
createColorSpaceTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)752 void createColorSpaceTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
753 {
754     // Verify Colorspace Extensions
755     addFunctionCase(testGroup, "extensions", basicExtensionTest, wsiType);
756     // Basic Rendering Tests
757     addFunctionCaseWithPrograms(testGroup, "basic", getBasicRenderPrograms, surfaceFormatRenderTests, wsiType);
758     // Basic Rendering Tests with HDR
759     addFunctionCaseWithPrograms(testGroup, "hdr", getBasicRenderPrograms, surfaceFormatRenderWithHdrTests, wsiType);
760 }
761 
createColorspaceCompareTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)762 void createColorspaceCompareTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
763 {
764     const VkFormat formatList[] = {
765         VK_FORMAT_B8G8R8A8_UNORM,      VK_FORMAT_R8G8B8A8_UNORM,           VK_FORMAT_R8G8B8A8_SRGB,
766         VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_R16G16B16A16_SFLOAT};
767 
768     // Create test for every format.
769     for (const VkFormat &format : formatList)
770     {
771         const char *const enumName = getFormatName(format);
772         const string caseName      = de::toLower(string(enumName).substr(10));
773         const TestParams params    = {wsiType, format};
774         addFunctionCaseWithPrograms(testGroup, caseName, getBasicRenderPrograms2, colorspaceCompareTest, params);
775     }
776 }
777 
778 } // namespace wsi
779 } // namespace vkt
780