xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/wsi/vktWsiSharedPresentableImageTests.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 Tests for shared presentable image extension
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktWsiSharedPresentableImageTests.hpp"
25 #include "vktCustomInstancesDevices.hpp"
26 
27 #include "vktTestCaseUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vkRefUtil.hpp"
30 #include "vkWsiPlatform.hpp"
31 #include "vkWsiUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkDeviceUtil.hpp"
34 #include "vkPlatform.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkCmdUtil.hpp"
38 #include "vkObjUtil.hpp"
39 
40 #include "vkWsiUtil.hpp"
41 
42 #include "tcuPlatform.hpp"
43 #include "tcuResultCollector.hpp"
44 #include "tcuTestLog.hpp"
45 #include "tcuCommandLine.hpp"
46 
47 #include <vector>
48 #include <string>
49 
50 using std::string;
51 using std::vector;
52 
53 using tcu::Maybe;
54 using tcu::TestLog;
55 using tcu::UVec2;
56 
57 namespace vkt
58 {
59 namespace wsi
60 {
61 namespace
62 {
63 enum Scaling
64 {
65     SCALING_NONE,
66     SCALING_UP,
67     SCALING_DOWN
68 };
69 
70 typedef vector<vk::VkExtensionProperties> Extensions;
71 
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)72 void checkAllSupported(const Extensions &supportedExtensions, const vector<string> &requiredExtensions)
73 {
74     for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
75          requiredExtName != requiredExtensions.end(); ++requiredExtName)
76     {
77         if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
78             TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
79     }
80 }
81 
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,vk::wsi::Type wsiType)82 CustomInstance createInstanceWithWsi(Context &context, const Extensions &supportedExtensions, vk::wsi::Type wsiType)
83 {
84     const uint32_t version = context.getUsedApiVersion();
85     vector<string> extensions;
86 
87     if (!vk::isCoreInstanceExtension(version, "VK_KHR_get_physical_device_properties2"))
88         extensions.push_back("VK_KHR_get_physical_device_properties2");
89 
90     extensions.push_back("VK_KHR_surface");
91     extensions.push_back("VK_KHR_get_surface_capabilities2");
92     // Required for device extension to expose new physical device bits (in this
93     // case, presentation mode enums)
94     extensions.push_back(getExtensionName(wsiType));
95     if (isDisplaySurface(wsiType))
96         extensions.push_back("VK_KHR_display");
97 
98     checkAllSupported(supportedExtensions, extensions);
99 
100     return vkt::createCustomInstanceWithExtensions(context, extensions);
101 }
102 
getDeviceNullFeatures(void)103 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures(void)
104 {
105     vk::VkPhysicalDeviceFeatures features;
106     deMemset(&features, 0, sizeof(features));
107     return features;
108 }
109 
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const uint32_t queueFamilyIndex,bool requiresSharedPresentableImage,bool validationEnabled,const vk::VkAllocationCallbacks * pAllocator=DE_NULL)110 vk::Move<vk::VkDevice> createDeviceWithWsi(const vk::PlatformInterface &vkp, vk::VkInstance instance,
111                                            const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
112                                            const Extensions &supportedExtensions, const uint32_t queueFamilyIndex,
113                                            bool requiresSharedPresentableImage, bool validationEnabled,
114                                            const vk::VkAllocationCallbacks *pAllocator = DE_NULL)
115 {
116     const float queuePriorities[]                  = {1.0f};
117     const vk::VkDeviceQueueCreateInfo queueInfos[] = {{vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, DE_NULL,
118                                                        (vk::VkDeviceQueueCreateFlags)0, queueFamilyIndex,
119                                                        DE_LENGTH_OF_ARRAY(queuePriorities), &queuePriorities[0]}};
120     const vk::VkPhysicalDeviceFeatures features    = getDeviceNullFeatures();
121     const char *const extensions[]                 = {"VK_KHR_swapchain", "VK_KHR_shared_presentable_image"};
122 
123     const vk::VkDeviceCreateInfo deviceParams = {vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
124                                                  DE_NULL,
125                                                  (vk::VkDeviceCreateFlags)0,
126                                                  DE_LENGTH_OF_ARRAY(queueInfos),
127                                                  &queueInfos[0],
128                                                  0u,
129                                                  DE_NULL,
130                                                  requiresSharedPresentableImage ? 2u : 1u,
131                                                  DE_ARRAY_BEGIN(extensions),
132                                                  &features};
133 
134     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
135     {
136         if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
137             TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
138     }
139 
140     return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
141 }
142 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)143 de::MovePtr<vk::wsi::Display> createDisplay(const vk::Platform &platform, const Extensions &supportedExtensions,
144                                             vk::wsi::Type wsiType)
145 {
146     try
147     {
148         return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
149     }
150     catch (const tcu::NotSupportedError &e)
151     {
152         if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
153             platform.hasDisplay(wsiType))
154         {
155             // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
156             // must support creating native display & window for that WSI type.
157             throw tcu::TestError(e.getMessage());
158         }
159         else
160             throw;
161     }
162 }
163 
createWindow(const vk::wsi::Display & display,const Maybe<UVec2> & initialSize)164 de::MovePtr<vk::wsi::Window> createWindow(const vk::wsi::Display &display, const Maybe<UVec2> &initialSize)
165 {
166     try
167     {
168         return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
169     }
170     catch (const tcu::NotSupportedError &e)
171     {
172         // See createDisplay - assuming that wsi::Display was supported platform port
173         // should also support creating a window.
174         throw tcu::TestError(e.getMessage());
175     }
176 }
177 
wsiTypeSupportsScaling(vk::wsi::Type wsiType)178 bool wsiTypeSupportsScaling(vk::wsi::Type wsiType)
179 {
180     return vk::wsi::getPlatformProperties(wsiType).swapchainExtent ==
181            vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_SCALED_TO_WINDOW_SIZE;
182 }
183 
initSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)184 void initSemaphores(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkSemaphore> &semaphores)
185 {
186     for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
187         semaphores[ndx] = createSemaphore(vkd, device).disown();
188 }
189 
deinitSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)190 void deinitSemaphores(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkSemaphore> &semaphores)
191 {
192     for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
193     {
194         if (semaphores[ndx] != (vk::VkSemaphore)0)
195             vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
196 
197         semaphores[ndx] = (vk::VkSemaphore)0;
198     }
199 
200     semaphores.clear();
201 }
202 
initFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)203 void initFences(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkFence> &fences)
204 {
205     for (size_t ndx = 0; ndx < fences.size(); ndx++)
206         fences[ndx] = createFence(vkd, device).disown();
207 }
208 
deinitFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)209 void deinitFences(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkFence> &fences)
210 {
211     for (size_t ndx = 0; ndx < fences.size(); ndx++)
212     {
213         if (fences[ndx] != (vk::VkFence)0)
214             vkd.destroyFence(device, fences[ndx], DE_NULL);
215 
216         fences[ndx] = (vk::VkFence)0;
217     }
218 
219     fences.clear();
220 }
221 
cmdRenderFrame(const vk::DeviceInterface & vkd,vk::VkCommandBuffer commandBuffer,vk::VkPipelineLayout pipelineLayout,vk::VkPipeline pipeline,size_t frameNdx,uint32_t quadCount)222 void cmdRenderFrame(const vk::DeviceInterface &vkd, vk::VkCommandBuffer commandBuffer,
223                     vk::VkPipelineLayout pipelineLayout, vk::VkPipeline pipeline, size_t frameNdx, uint32_t quadCount)
224 {
225     const uint32_t frameNdxValue = (uint32_t)frameNdx;
226 
227     vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
228     vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
229     vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
230 }
231 
createCommandBuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,vk::VkPipelineLayout pipelineLayout,vk::VkRenderPass renderPass,vk::VkFramebuffer framebuffer,vk::VkPipeline pipeline,size_t frameNdx,uint32_t quadCount,uint32_t imageWidth,uint32_t imageHeight)232 vk::Move<vk::VkCommandBuffer> createCommandBuffer(const vk::DeviceInterface &vkd, vk::VkDevice device,
233                                                   vk::VkCommandPool commandPool, vk::VkPipelineLayout pipelineLayout,
234                                                   vk::VkRenderPass renderPass, vk::VkFramebuffer framebuffer,
235                                                   vk::VkPipeline pipeline, size_t frameNdx, uint32_t quadCount,
236                                                   uint32_t imageWidth, uint32_t imageHeight)
237 {
238     const vk::VkCommandBufferAllocateInfo allocateInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, DE_NULL,
239 
240                                                           commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
241 
242     vk::Move<vk::VkCommandBuffer> commandBuffer(vk::allocateCommandBuffer(vkd, device, &allocateInfo));
243     beginCommandBuffer(vkd, *commandBuffer, 0u);
244 
245     beginRenderPass(vkd, *commandBuffer, renderPass, framebuffer, vk::makeRect2D(0, 0, imageWidth, imageHeight),
246                     tcu::Vec4(0.25f, 0.5f, 0.75f, 1.0f));
247 
248     cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
249 
250     endRenderPass(vkd, *commandBuffer);
251 
252     endCommandBuffer(vkd, *commandBuffer);
253     return commandBuffer;
254 }
255 
deinitCommandBuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,std::vector<vk::VkCommandBuffer> & commandBuffers)256 void deinitCommandBuffers(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkCommandPool commandPool,
257                           std::vector<vk::VkCommandBuffer> &commandBuffers)
258 {
259     for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
260     {
261         if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
262             vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]);
263 
264         commandBuffers[ndx] = (vk::VkCommandBuffer)0;
265     }
266 
267     commandBuffers.clear();
268 }
269 
createCommandPool(const vk::DeviceInterface & vkd,vk::VkDevice device,uint32_t queueFamilyIndex)270 vk::Move<vk::VkCommandPool> createCommandPool(const vk::DeviceInterface &vkd, vk::VkDevice device,
271                                               uint32_t queueFamilyIndex)
272 {
273     const vk::VkCommandPoolCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, DE_NULL, 0u,
274                                                     queueFamilyIndex};
275 
276     return vk::createCommandPool(vkd, device, &createInfo);
277 }
278 
createFramebuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,vk::VkImageView imageView,uint32_t width,uint32_t height)279 vk::Move<vk::VkFramebuffer> createFramebuffer(const vk::DeviceInterface &vkd, vk::VkDevice device,
280                                               vk::VkRenderPass renderPass, vk::VkImageView imageView, uint32_t width,
281                                               uint32_t height)
282 {
283     const vk::VkFramebufferCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
284                                                     DE_NULL,
285 
286                                                     0u,
287                                                     renderPass,
288                                                     1u,
289                                                     &imageView,
290                                                     width,
291                                                     height,
292                                                     1u};
293 
294     return vk::createFramebuffer(vkd, device, &createInfo);
295 }
296 
createImageView(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkImage image,vk::VkFormat format)297 vk::Move<vk::VkImageView> createImageView(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkImage image,
298                                           vk::VkFormat format)
299 {
300     const vk::VkImageViewCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
301                                                   DE_NULL,
302 
303                                                   0u,
304                                                   image,
305                                                   vk::VK_IMAGE_VIEW_TYPE_2D,
306                                                   format,
307                                                   vk::makeComponentMappingRGBA(),
308                                                   {vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
309 
310     return vk::createImageView(vkd, device, &createInfo, DE_NULL);
311 }
312 
createRenderPass(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkFormat format)313 vk::Move<vk::VkRenderPass> createRenderPass(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkFormat format)
314 {
315     const vk::VkAttachmentDescription attachments[] = {
316         {0u, format, vk::VK_SAMPLE_COUNT_1_BIT,
317 
318          vk::VK_ATTACHMENT_LOAD_OP_LOAD, vk::VK_ATTACHMENT_STORE_OP_STORE,
319 
320          vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
321 
322          // This differs from the usual layout handling in that the
323          // swapchain image remains in IMAGE_LAYOUT_SHARED_PRESENT_KHR all
324          // the time. We should not ever transition it away (or discard the
325          // contents with a transition from UNDEFINED) as the PE is accessing
326          // the image concurrently with our rendering.
327          vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR}};
328     const vk::VkAttachmentReference colorAttachmentRefs[] = {{0u, vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR}};
329     const vk::VkSubpassDescription subpasses[]            = {{0u, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, DE_NULL,
330 
331                                                               DE_LENGTH_OF_ARRAY(colorAttachmentRefs), colorAttachmentRefs,
332                                                               DE_NULL,
333 
334                                                               DE_NULL, 0u, DE_NULL}};
335 
336     const vk::VkRenderPassCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
337                                                    DE_NULL,
338                                                    0u,
339 
340                                                    DE_LENGTH_OF_ARRAY(attachments),
341                                                    attachments,
342 
343                                                    DE_LENGTH_OF_ARRAY(subpasses),
344                                                    subpasses,
345 
346                                                    0u,
347                                                    DE_NULL};
348 
349     return vk::createRenderPass(vkd, device, &createInfo);
350 }
351 
createPipeline(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,vk::VkPipelineLayout layout,vk::VkShaderModule vertexShaderModule,vk::VkShaderModule fragmentShaderModule,uint32_t width,uint32_t height)352 vk::Move<vk::VkPipeline> createPipeline(const vk::DeviceInterface &vkd, vk::VkDevice device,
353                                         vk::VkRenderPass renderPass, vk::VkPipelineLayout layout,
354                                         vk::VkShaderModule vertexShaderModule, vk::VkShaderModule fragmentShaderModule,
355                                         uint32_t width, uint32_t height)
356 {
357     const vk::VkPipelineVertexInputStateCreateInfo vertexInputState = {
358         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, DE_NULL, 0u, 0u, DE_NULL, 0u, DE_NULL};
359     const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(tcu::UVec2(width, height)));
360     const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(tcu::UVec2(width, height)));
361 
362     return vk::makeGraphicsPipeline(
363         vkd,                  // const DeviceInterface&                        vk
364         device,               // const VkDevice                                device
365         layout,               // const VkPipelineLayout                        pipelineLayout
366         vertexShaderModule,   // const VkShaderModule                          vertexShaderModule
367         DE_NULL,              // const VkShaderModule                          tessellationControlShaderModule
368         DE_NULL,              // const VkShaderModule                          tessellationEvalShaderModule
369         DE_NULL,              // const VkShaderModule                          geometryShaderModule
370         fragmentShaderModule, // const VkShaderModule                          fragmentShaderModule
371         renderPass,           // const VkRenderPass                            renderPass
372         viewports,            // const std::vector<VkViewport>&                viewports
373         scissors,             // const std::vector<VkRect2D>&                  scissors
374         vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology                     topology
375         0u,                                      // const uint32_t                                subpass
376         0u,                                      // const uint32_t                                patchControlPoints
377         &vertexInputState); // const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
378 }
379 
createPipelineLayout(const vk::DeviceInterface & vkd,vk::VkDevice device)380 vk::Move<vk::VkPipelineLayout> createPipelineLayout(const vk::DeviceInterface &vkd, vk::VkDevice device)
381 {
382     const vk::VkPushConstantRange pushConstants[]   = {{vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u}};
383     const vk::VkPipelineLayoutCreateInfo createInfo = {
384         vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
385         DE_NULL,
386         0u,
387 
388         0u,
389         DE_NULL,
390 
391         DE_LENGTH_OF_ARRAY(pushConstants),
392         pushConstants,
393     };
394 
395     return vk::createPipelineLayout(vkd, device, &createInfo);
396 }
397 
398 struct TestConfig
399 {
400     vk::wsi::Type wsiType;
401     Scaling scaling;
402     bool useSharedPresentableImage;
403     vk::VkPresentModeKHR presentMode;
404     vk::VkSurfaceTransformFlagsKHR transform;
405     vk::VkCompositeAlphaFlagsKHR alpha;
406 };
407 
408 class SharedPresentableImageTestInstance : public TestInstance
409 {
410 public:
411     SharedPresentableImageTestInstance(Context &context, const TestConfig &testConfig);
412     ~SharedPresentableImageTestInstance(void);
413 
414     tcu::TestStatus iterate(void);
415 
416 private:
417     const TestConfig m_testConfig;
418     const uint32_t m_quadCount;
419     const vk::PlatformInterface &m_vkp;
420     const Extensions m_instanceExtensions;
421     const CustomInstance m_instance;
422     const vk::InstanceDriver &m_vki;
423     const vk::VkPhysicalDevice m_physicalDevice;
424     const de::UniquePtr<vk::wsi::Display> m_nativeDisplay;
425     const de::UniquePtr<vk::wsi::Window> m_nativeWindow;
426     const vk::Unique<vk::VkSurfaceKHR> m_surface;
427 
428     const uint32_t m_queueFamilyIndex;
429     const Extensions m_deviceExtensions;
430     const vk::Unique<vk::VkDevice> m_device;
431     const vk::DeviceDriver m_vkd;
432     const vk::VkQueue m_queue;
433 
434     const vk::Unique<vk::VkCommandPool> m_commandPool;
435     const vk::Unique<vk::VkShaderModule> m_vertexShaderModule;
436     const vk::Unique<vk::VkShaderModule> m_fragmentShaderModule;
437     const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
438 
439     vk::VkImageUsageFlags m_supportedUsageFlags;
440     const vk::VkSurfaceCapabilitiesKHR m_surfaceProperties;
441     const vector<vk::VkSurfaceFormatKHR> m_surfaceFormats;
442     const vector<vk::VkPresentModeKHR> m_presentModes;
443 
444     tcu::ResultCollector m_resultCollector;
445 
446     vk::Move<vk::VkSwapchainKHR> m_swapchain;
447     vk::VkImage m_swapchainImage; // NOTE: not owning. lifetime managed by swapchain
448     vk::Move<vk::VkImageView> m_swapchainImageView;
449     vk::Move<vk::VkFramebuffer> m_framebuffer;
450 
451     vk::Move<vk::VkRenderPass> m_renderPass;
452     vk::Move<vk::VkPipeline> m_pipeline;
453 
454     std::vector<vk::VkCommandBuffer> m_commandBuffers;
455     std::vector<vk::VkSemaphore> m_renderSemaphores;
456     std::vector<vk::VkFence> m_fences;
457 
458     std::vector<vk::VkSwapchainCreateInfoKHR> m_swapchainConfigs;
459     size_t m_swapchainConfigNdx;
460 
461     const size_t m_frameCount;
462     size_t m_frameNdx;
463 
464     const size_t m_maxOutOfDateCount;
465     size_t m_outOfDateCount;
466 
467     void initSwapchainResources(void);
468     void deinitSwapchainResources(void);
469     void render(void);
470 };
471 
generateSwapchainConfigs(const vk::InstanceDriver & vki,const vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,uint32_t queueFamilyIndex,Scaling scaling,const vk::VkSurfaceCapabilitiesKHR & properties,const vector<vk::VkSurfaceFormatKHR> & formats,const vector<vk::VkPresentModeKHR> & presentModes,vk::VkPresentModeKHR presentMode,vk::VkImageUsageFlags supportedImageUsage,const vk::VkSurfaceTransformFlagsKHR transform,const vk::VkCompositeAlphaFlagsKHR alpha)472 std::vector<vk::VkSwapchainCreateInfoKHR> generateSwapchainConfigs(
473     const vk::InstanceDriver &vki, const vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface,
474     uint32_t queueFamilyIndex, Scaling scaling, const vk::VkSurfaceCapabilitiesKHR &properties,
475     const vector<vk::VkSurfaceFormatKHR> &formats, const vector<vk::VkPresentModeKHR> &presentModes,
476     vk::VkPresentModeKHR presentMode, vk::VkImageUsageFlags supportedImageUsage,
477     const vk::VkSurfaceTransformFlagsKHR transform, const vk::VkCompositeAlphaFlagsKHR alpha)
478 {
479     const uint32_t imageLayers             = 1u;
480     const vk::VkImageUsageFlags imageUsage = properties.supportedUsageFlags & supportedImageUsage;
481     const vk::VkBool32 clipped             = VK_FALSE;
482     vector<vk::VkSwapchainCreateInfoKHR> createInfos;
483 
484     const uint32_t currentWidth =
485         properties.currentExtent.width != 0xFFFFFFFFu ?
486             properties.currentExtent.width :
487             de::min(1024u, properties.minImageExtent.width +
488                                ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2));
489     const uint32_t currentHeight =
490         properties.currentExtent.height != 0xFFFFFFFFu ?
491             properties.currentExtent.height :
492             de::min(1024u, properties.minImageExtent.height +
493                                ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2));
494 
495     const uint32_t imageWidth =
496         scaling == SCALING_NONE ?
497             currentWidth :
498             (scaling == SCALING_UP ?
499                  de::max(31u, properties.minImageExtent.width) :
500                  de::min(deSmallestGreaterOrEquallPowerOfTwoU32(currentWidth + 1), properties.maxImageExtent.width));
501     const uint32_t imageHeight =
502         scaling == SCALING_NONE ?
503             currentHeight :
504             (scaling == SCALING_UP ?
505                  de::max(31u, properties.minImageExtent.height) :
506                  de::min(deSmallestGreaterOrEquallPowerOfTwoU32(currentHeight + 1), properties.maxImageExtent.height));
507     const vk::VkExtent2D imageSize = {imageWidth, imageHeight};
508 
509     {
510         size_t presentModeNdx;
511 
512         for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
513         {
514             if (presentModes[presentModeNdx] == presentMode)
515                 break;
516         }
517 
518         if (presentModeNdx == presentModes.size())
519             TCU_THROW(NotSupportedError, "Present mode not supported");
520 
521         if ((properties.supportedTransforms & transform) == 0)
522             TCU_THROW(NotSupportedError, "Transform not supported");
523 
524         if ((properties.supportedCompositeAlpha & alpha) == 0)
525             TCU_THROW(NotSupportedError, "Composite alpha not supported");
526     }
527 
528     for (size_t formatNdx = 0; formatNdx < formats.size(); formatNdx++)
529     {
530         const vk::VkSurfaceTransformFlagBitsKHR preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
531         const vk::VkCompositeAlphaFlagBitsKHR compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alpha;
532         const vk::VkFormat imageFormat                       = formats[formatNdx].format;
533         const vk::VkColorSpaceKHR imageColorSpace            = formats[formatNdx].colorSpace;
534         const vk::VkSwapchainCreateInfoKHR createInfo        = {vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
535                                                                 DE_NULL,
536                                                                 0u,
537                                                                 surface,
538                                                                 1, // Always 1 image for a shared presentable image swapchain.
539                                                                 imageFormat,
540                                                                 imageColorSpace,
541                                                                 imageSize,
542                                                                 imageLayers,
543                                                                 imageUsage,
544                                                                 vk::VK_SHARING_MODE_EXCLUSIVE,
545                                                                 1u,
546                                                                 &queueFamilyIndex,
547                                                                 preTransform,
548                                                                 compositeAlpha,
549                                                                 presentMode,
550                                                                 clipped,
551                                                                 (vk::VkSwapchainKHR)0};
552 
553         {
554             vk::VkImageFormatProperties imageFormatProperties;
555 
556             deMemset(&imageFormatProperties, 0, sizeof(imageFormatProperties));
557 
558             vk::VkResult result = vki.getPhysicalDeviceImageFormatProperties(
559                 physicalDevice, imageFormat, vk::VK_IMAGE_TYPE_2D, vk::VK_IMAGE_TILING_OPTIMAL, imageUsage, 0,
560                 &imageFormatProperties);
561 
562             if (result == vk::VK_ERROR_FORMAT_NOT_SUPPORTED)
563                 continue;
564         }
565 
566         createInfos.push_back(createInfo);
567     }
568 
569     return createInfos;
570 }
571 
getPhysicalDeviceSurfaceCapabilities(const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,vk::VkImageUsageFlags * usage)572 vk::VkSurfaceCapabilitiesKHR getPhysicalDeviceSurfaceCapabilities(const vk::InstanceInterface &vki,
573                                                                   vk::VkPhysicalDevice physicalDevice,
574                                                                   vk::VkSurfaceKHR surface,
575                                                                   vk::VkImageUsageFlags *usage)
576 {
577     const vk::VkPhysicalDeviceSurfaceInfo2KHR info = {vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR, DE_NULL,
578 
579                                                       surface};
580     vk::VkSharedPresentSurfaceCapabilitiesKHR sharedCapabilities;
581     vk::VkSurfaceCapabilities2KHR capabilities;
582 
583     sharedCapabilities.sType = vk::VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
584     sharedCapabilities.pNext = DE_NULL;
585 
586     capabilities.sType = vk::VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
587     capabilities.pNext = &sharedCapabilities;
588 
589     VK_CHECK(vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevice, &info, &capabilities));
590 
591     TCU_CHECK(sharedCapabilities.sharedPresentSupportedUsageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
592     *usage = sharedCapabilities.sharedPresentSupportedUsageFlags;
593 
594     return capabilities.surfaceCapabilities;
595 }
596 
SharedPresentableImageTestInstance(Context & context,const TestConfig & testConfig)597 SharedPresentableImageTestInstance::SharedPresentableImageTestInstance(Context &context, const TestConfig &testConfig)
598     : TestInstance(context)
599     , m_testConfig(testConfig)
600     , m_quadCount(16u)
601     , m_vkp(context.getPlatformInterface())
602     , m_instanceExtensions(vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
603     , m_instance(createInstanceWithWsi(context, m_instanceExtensions, testConfig.wsiType))
604     , m_vki(m_instance.getDriver())
605     , m_physicalDevice(vk::chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
606     , m_nativeDisplay(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions,
607                                     testConfig.wsiType))
608     , m_nativeWindow(createWindow(*m_nativeDisplay, tcu::Nothing))
609     , m_surface(vk::wsi::createSurface(m_vki, m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow,
610                                        context.getTestContext().getCommandLine()))
611 
612     , m_queueFamilyIndex(vk::wsi::chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
613     , m_deviceExtensions(vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
614     , m_device(createDeviceWithWsi(m_vkp, m_instance, m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex,
615                                    testConfig.useSharedPresentableImage,
616                                    context.getTestContext().getCommandLine().isValidationEnabled()))
617     , m_vkd(m_vkp, m_instance, *m_device, context.getUsedApiVersion(), context.getTestContext().getCommandLine())
618     , m_queue(getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
619 
620     , m_commandPool(createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
621     , m_vertexShaderModule(vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
622     , m_fragmentShaderModule(
623           vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
624     , m_pipelineLayout(createPipelineLayout(m_vkd, *m_device))
625 
626     , m_supportedUsageFlags(0u)
627     , m_surfaceProperties(
628           getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface, &m_supportedUsageFlags))
629     , m_surfaceFormats(vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
630     , m_presentModes(vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
631 
632     , m_swapchainConfigs(generateSwapchainConfigs(m_vki, m_physicalDevice, *m_surface, m_queueFamilyIndex,
633                                                   testConfig.scaling, m_surfaceProperties, m_surfaceFormats,
634                                                   m_presentModes, testConfig.presentMode, m_supportedUsageFlags,
635                                                   testConfig.transform, testConfig.alpha))
636     , m_swapchainConfigNdx(0u)
637 
638     , m_frameCount(60u * 5u)
639     , m_frameNdx(0u)
640 
641     , m_maxOutOfDateCount(20u)
642     , m_outOfDateCount(0u)
643 {
644     {
645         const tcu::ScopedLogSection surfaceInfo(m_context.getTestContext().getLog(), "SurfaceCapabilities",
646                                                 "SurfaceCapabilities");
647         m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
648         m_context.getTestContext().getLog()
649             << TestLog::Message << "SharedPresentSupportedUsageFlags: " << m_supportedUsageFlags << TestLog::EndMessage;
650     }
651 }
652 
~SharedPresentableImageTestInstance(void)653 SharedPresentableImageTestInstance::~SharedPresentableImageTestInstance(void)
654 {
655     deinitSwapchainResources();
656 }
657 
initSwapchainResources(void)658 void SharedPresentableImageTestInstance::initSwapchainResources(void)
659 {
660     const size_t fenceCount        = 6;
661     const uint32_t imageWidth      = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
662     const uint32_t imageHeight     = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
663     const vk::VkFormat imageFormat = m_swapchainConfigs[m_swapchainConfigNdx].imageFormat;
664 
665     m_swapchain      = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfigs[m_swapchainConfigNdx]);
666     m_swapchainImage = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain).front();
667 
668     m_renderPass = createRenderPass(m_vkd, *m_device, imageFormat);
669     m_pipeline   = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule,
670                                   *m_fragmentShaderModule, imageWidth, imageHeight);
671 
672     m_swapchainImageView = createImageView(m_vkd, *m_device, m_swapchainImage, imageFormat);
673     m_framebuffer = createFramebuffer(m_vkd, *m_device, *m_renderPass, *m_swapchainImageView, imageWidth, imageHeight);
674 
675     m_renderSemaphores = std::vector<vk::VkSemaphore>(fenceCount, (vk::VkSemaphore)0);
676     m_fences           = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
677     m_commandBuffers   = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
678 
679     initSemaphores(m_vkd, *m_device, m_renderSemaphores);
680 
681     initFences(m_vkd, *m_device, m_fences);
682 
683     // Unlike a traditional swapchain, where we'd acquire a new image from the
684     // PE every frame, a shared image swapchain has a single image that is
685     // acquired upfront. We acquire it here, transition it to the proper layout,
686     // and present it.
687 
688     // Acquire the one image
689     const uint64_t foreverNs = 0xFFFFFFFFFFFFFFFFul;
690     vk::Move<vk::VkSemaphore> semaphore(createSemaphore(m_vkd, *m_device));
691     uint32_t imageIndex = 42; // initialize to junk value
692 
693     VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, *semaphore, 0u, &imageIndex));
694     TCU_CHECK(imageIndex == 0);
695 
696     // Transition to IMAGE_LAYOUT_SHARED_PRESENT_KHR
697     const vk::VkCommandBufferAllocateInfo allocateInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, DE_NULL,
698                                                           *m_commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
699 
700     const vk::Unique<vk::VkCommandBuffer> commandBuffer(vk::allocateCommandBuffer(m_vkd, *m_device, &allocateInfo));
701     beginCommandBuffer(m_vkd, *commandBuffer, 0u);
702 
703     const vk::VkImageMemoryBarrier barrier = {
704         vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
705         DE_NULL,
706         0,
707         0,
708         vk::VK_IMAGE_LAYOUT_UNDEFINED,
709         vk::VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
710         VK_QUEUE_FAMILY_IGNORED,
711         VK_QUEUE_FAMILY_IGNORED,
712         m_swapchainImage,
713         {vk::VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1},
714     };
715 
716     m_vkd.cmdPipelineBarrier(*commandBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
717                              vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0u, 0, DE_NULL, 0, DE_NULL, 1, &barrier);
718 
719     endCommandBuffer(m_vkd, *commandBuffer);
720 
721     const vk::VkPipelineStageFlags waitDstStages[] = {vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
722     const vk::VkSubmitInfo submitInfo              = {
723         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO, DE_NULL, 1, &*semaphore, waitDstStages, 1, &*commandBuffer, 0, DE_NULL,
724     };
725 
726     VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, (vk::VkFence)0));
727     VK_CHECK(m_vkd.queueWaitIdle(m_queue));
728 }
729 
deinitSwapchainResources(void)730 void SharedPresentableImageTestInstance::deinitSwapchainResources(void)
731 {
732     VK_CHECK(m_vkd.queueWaitIdle(m_queue));
733 
734     deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
735     deinitFences(m_vkd, *m_device, m_fences);
736     deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
737 
738     m_framebuffer        = vk::Move<vk::VkFramebuffer>();
739     m_swapchainImageView = vk::Move<vk::VkImageView>();
740     m_swapchainImage     = (vk::VkImage)0;
741 
742     m_swapchain  = vk::Move<vk::VkSwapchainKHR>();
743     m_renderPass = vk::Move<vk::VkRenderPass>();
744     m_pipeline   = vk::Move<vk::VkPipeline>();
745 }
746 
render(void)747 void SharedPresentableImageTestInstance::render(void)
748 {
749     const uint64_t foreverNs = 0xFFFFFFFFFFFFFFFFul;
750     const vk::VkFence fence  = m_fences[m_frameNdx % m_fences.size()];
751     const uint32_t width     = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.width;
752     const uint32_t height    = m_swapchainConfigs[m_swapchainConfigNdx].imageExtent.height;
753 
754     // Throttle execution
755     if (m_frameNdx >= m_fences.size())
756     {
757         VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
758         VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
759 
760         m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u,
761                                  &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
762         m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
763     }
764 
765     uint32_t imageIndex                          = 0; // There is only one image.
766     const vk::VkSemaphore currentRenderSemaphore = m_renderSemaphores[m_frameNdx % m_renderSemaphores.size()];
767 
768     const bool willPresent =
769         m_swapchainConfigs[m_swapchainConfigNdx].presentMode == vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
770         !m_frameNdx;
771 
772     // Create command buffer
773     m_commandBuffers[m_frameNdx % m_commandBuffers.size()] =
774         createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_pipelineLayout, *m_renderPass, *m_framebuffer,
775                             *m_pipeline, m_frameNdx, m_quadCount, width, height)
776             .disown();
777 
778     // Submit command buffer
779     {
780         const vk::VkSubmitInfo submitInfo = {
781             vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
782             DE_NULL,
783             0u,
784             DE_NULL,
785             DE_NULL,
786             1u,
787             &m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
788             willPresent ? 1u : 0u, // Only signal the semaphore if we're going to call QueuePresent.
789             &currentRenderSemaphore};
790 
791         // With a traditional swapchain, we'd fence on completion of
792         // AcquireNextImage. We never call that for a shared image swapchain, so
793         // fence on completion of the rendering work instead. A real shared
794         // image application would want a more substantial pacing mechanism.
795         VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
796     }
797 
798     // DEMAND_REFRESH requires us to call QueuePresent whenever we want to be
799     // assured the PE has picked up a new frame. The PE /may/ also pick up
800     // changes whenever it likes.
801     //
802     // For CONTINUOUS_REFRESH, we need to just call QueuePresent once on the
803     // first frame to kick things off.
804     if (willPresent)
805     {
806 
807         // Present frame
808         vk::VkResult result;
809         const vk::VkPresentInfoKHR presentInfo = {vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
810                                                   DE_NULL,
811                                                   1u,
812                                                   &currentRenderSemaphore,
813                                                   1u,
814                                                   &*m_swapchain,
815                                                   &imageIndex,
816                                                   &result};
817 
818         VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
819         VK_CHECK_WSI(result);
820     }
821 
822     // With either present mode, we can call GetSwapchainStatus at any time
823     // to detect possible OUT_OF_DATE conditions. Let's do that every frame.
824 
825     const vk::VkResult swapchainStatus = m_vkd.getSwapchainStatusKHR(*m_device, *m_swapchain);
826     VK_CHECK(swapchainStatus);
827 }
828 
iterate(void)829 tcu::TestStatus SharedPresentableImageTestInstance::iterate(void)
830 {
831     // Initialize swapchain specific resources
832     // Render test
833     try
834     {
835         if (m_frameNdx == 0)
836         {
837             if (m_outOfDateCount == 0)
838                 m_context.getTestContext().getLog()
839                     << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfigs[m_swapchainConfigNdx]
840                     << tcu::TestLog::EndMessage;
841 
842             initSwapchainResources();
843         }
844 
845         render();
846     }
847     catch (const vk::Error &error)
848     {
849         if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
850         {
851             m_swapchainConfigs = generateSwapchainConfigs(
852                 m_vki, m_physicalDevice, *m_surface, m_queueFamilyIndex, m_testConfig.scaling, m_surfaceProperties,
853                 m_surfaceFormats, m_presentModes, m_testConfig.presentMode, m_supportedUsageFlags,
854                 m_testConfig.transform, m_testConfig.alpha);
855 
856             if (m_outOfDateCount < m_maxOutOfDateCount)
857             {
858                 m_context.getTestContext().getLog()
859                     << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources."
860                     << TestLog::EndMessage;
861                 deinitSwapchainResources();
862                 m_frameNdx = 0;
863                 m_outOfDateCount++;
864 
865                 return tcu::TestStatus::incomplete();
866             }
867             else
868             {
869                 m_context.getTestContext().getLog()
870                     << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
871                 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " +
872                                        de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
873             }
874         }
875         else
876         {
877             m_resultCollector.fail(error.what());
878         }
879 
880         deinitSwapchainResources();
881 
882         m_swapchainConfigNdx++;
883         m_frameNdx       = 0;
884         m_outOfDateCount = 0;
885 
886         if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
887             return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
888         else
889             return tcu::TestStatus::incomplete();
890     }
891 
892     m_frameNdx++;
893 
894     if (m_frameNdx >= m_frameCount)
895     {
896         m_frameNdx       = 0;
897         m_outOfDateCount = 0;
898         m_swapchainConfigNdx++;
899 
900         deinitSwapchainResources();
901 
902         if (m_swapchainConfigNdx >= m_swapchainConfigs.size())
903             return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
904         else
905             return tcu::TestStatus::incomplete();
906     }
907     else
908         return tcu::TestStatus::incomplete();
909 }
910 
911 struct Programs
912 {
initvkt::wsi::__anon5b90bc810111::Programs913     static void init(vk::SourceCollections &dst, TestConfig)
914     {
915         dst.glslSources.add("quad-vert") << glu::VertexSource(
916             "#version 450\n"
917             "out gl_PerVertex {\n"
918             "\tvec4 gl_Position;\n"
919             "};\n"
920             "layout(location = 0) out highp uint quadIndex;\n"
921             "highp float;\n"
922             "void main (void) {\n"
923             "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
924             "\t                   ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
925             "\tquadIndex = gl_VertexIndex / 6;\n"
926             "}\n");
927         dst.glslSources.add("quad-frag") << glu::FragmentSource(
928             "#version 310 es\n"
929             "layout(location = 0) flat in highp uint quadIndex;\n"
930             "layout(location = 0) out highp vec4 o_color;\n"
931             "layout(push_constant) uniform PushConstant {\n"
932             "\thighp uint frameNdx;\n"
933             "} pushConstants;\n"
934             "void main (void)\n"
935             "{\n"
936             "\thighp uint frameNdx = pushConstants.frameNdx;\n"
937             "\thighp uint cellX = bitfieldExtract(uint(gl_FragCoord.x), 7, 10);\n"
938             "\thighp uint cellY = bitfieldExtract(uint(gl_FragCoord.y), 7, 10);\n"
939             "\thighp uint x = quadIndex ^ (frameNdx + (uint(gl_FragCoord.x) >> cellX));\n"
940             "\thighp uint y = quadIndex ^ (frameNdx + (uint(gl_FragCoord.y) >> cellY));\n"
941             "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
942             "\t             +  64u * bitfieldExtract(y, 1, 1)\n"
943             "\t             +  32u * bitfieldExtract(x, 3, 1);\n"
944             "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
945             "\t             +  64u * bitfieldExtract(x, 2, 1)\n"
946             "\t             +  32u * bitfieldExtract(y, 3, 1);\n"
947             "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
948             "\t             +  64u * bitfieldExtract(y, 2, 1)\n"
949             "\t             +  32u * bitfieldExtract(x, 4, 1);\n"
950             "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
951             "}\n");
952     }
953 };
954 
955 } // namespace
956 
createSharedPresentableImageTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)957 void createSharedPresentableImageTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
958 {
959     const struct
960     {
961         Scaling scaling;
962         const char *name;
963     } scaling[] = {{SCALING_NONE, "scale_none"}, {SCALING_UP, "scale_up"}, {SCALING_DOWN, "scale_down"}};
964     const struct
965     {
966         vk::VkPresentModeKHR mode;
967         const char *name;
968     } presentModes[] = {
969         {vk::VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR, "demand"},
970         {vk::VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR, "continuous"},
971     };
972     const struct
973     {
974         vk::VkSurfaceTransformFlagsKHR transform;
975         const char *name;
976     } transforms[] = {{vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR, "identity"},
977                       {vk::VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR, "rotate_90"},
978                       {vk::VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR, "rotate_180"},
979                       {vk::VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR, "rotate_270"},
980                       {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR, "horizontal_mirror"},
981                       {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR, "horizontal_mirror_rotate_90"},
982                       {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR, "horizontal_mirror_rotate_180"},
983                       {vk::VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR, "horizontal_mirror_rotate_270"},
984                       {vk::VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR, "inherit"}};
985     const struct
986     {
987         vk::VkCompositeAlphaFlagsKHR alpha;
988         const char *name;
989     } alphas[] = {{vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, "opaque"},
990                   {vk::VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR, "pre_multiplied"},
991                   {vk::VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR, "post_multiplied"},
992                   {vk::VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, "inherit"}};
993 
994     for (size_t scalingNdx = 0; scalingNdx < DE_LENGTH_OF_ARRAY(scaling); scalingNdx++)
995     {
996         if (scaling[scalingNdx].scaling == SCALING_NONE || wsiTypeSupportsScaling(wsiType))
997         {
998             de::MovePtr<tcu::TestCaseGroup> scaleGroup(
999                 new tcu::TestCaseGroup(testGroup->getTestContext(), scaling[scalingNdx].name));
1000 
1001             for (size_t transformNdx = 0; transformNdx < DE_LENGTH_OF_ARRAY(transforms); transformNdx++)
1002             {
1003                 de::MovePtr<tcu::TestCaseGroup> transformGroup(
1004                     new tcu::TestCaseGroup(testGroup->getTestContext(), transforms[transformNdx].name));
1005 
1006                 for (size_t alphaNdx = 0; alphaNdx < DE_LENGTH_OF_ARRAY(alphas); alphaNdx++)
1007                 {
1008                     de::MovePtr<tcu::TestCaseGroup> alphaGroup(
1009                         new tcu::TestCaseGroup(testGroup->getTestContext(), alphas[alphaNdx].name));
1010 
1011                     for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1012                     {
1013                         const char *const name = presentModes[presentModeNdx].name;
1014                         TestConfig config;
1015 
1016                         config.wsiType                   = wsiType;
1017                         config.useSharedPresentableImage = true;
1018                         config.scaling                   = scaling[scalingNdx].scaling;
1019                         config.transform                 = transforms[transformNdx].transform;
1020                         config.alpha                     = alphas[alphaNdx].alpha;
1021                         config.presentMode               = presentModes[presentModeNdx].mode;
1022 
1023                         alphaGroup->addChild(
1024                             new vkt::InstanceFactory1<SharedPresentableImageTestInstance, TestConfig, Programs>(
1025                                 testGroup->getTestContext(), name, Programs(), config));
1026                     }
1027 
1028                     transformGroup->addChild(alphaGroup.release());
1029                 }
1030 
1031                 scaleGroup->addChild(transformGroup.release());
1032             }
1033 
1034             testGroup->addChild(scaleGroup.release());
1035         }
1036     }
1037 }
1038 
1039 } // namespace wsi
1040 } // namespace vkt
1041