xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/wsi/vktWsiDisplayTimingTests.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 VK_GOOGLE_display_timing
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vkRefUtil.hpp"
25 #include "vkWsiPlatform.hpp"
26 #include "vkWsiUtil.hpp"
27 #include "vkQueryUtil.hpp"
28 #include "vkDeviceUtil.hpp"
29 #include "vkPlatform.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkWsiUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkObjUtil.hpp"
36 
37 #include "vktWsiDisplayTimingTests.hpp"
38 #include "vktTestCaseUtil.hpp"
39 #include "vktTestGroupUtil.hpp"
40 #include "vktCustomInstancesDevices.hpp"
41 
42 #include "tcuPlatform.hpp"
43 #include "tcuResultCollector.hpp"
44 #include "tcuTestLog.hpp"
45 #include "tcuCommandLine.hpp"
46 
47 #include "deClock.h"
48 
49 #include <vector>
50 #include <string>
51 
52 using std::string;
53 using std::vector;
54 
55 using tcu::Maybe;
56 using tcu::TestLog;
57 using tcu::UVec2;
58 
59 namespace vkt
60 {
61 namespace wsi
62 {
63 namespace
64 {
65 static const uint64_t MILLISECOND = 1000ull * 1000ull;
66 static const uint64_t SECOND      = 1000ull * MILLISECOND;
67 
68 typedef vector<vk::VkExtensionProperties> Extensions;
69 
checkAllSupported(const Extensions & supportedExtensions,const vector<string> & requiredExtensions)70 void checkAllSupported(const Extensions &supportedExtensions, const vector<string> &requiredExtensions)
71 {
72     for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
73          requiredExtName != requiredExtensions.end(); ++requiredExtName)
74     {
75         if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
76             TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
77     }
78 }
79 
createInstanceWithWsi(Context & context,const Extensions & supportedExtensions,vk::wsi::Type wsiType)80 CustomInstance createInstanceWithWsi(Context &context, const Extensions &supportedExtensions, vk::wsi::Type wsiType)
81 {
82     vector<string> extensions;
83 
84     extensions.push_back("VK_KHR_surface");
85     extensions.push_back(getExtensionName(wsiType));
86     if (isDisplaySurface(wsiType))
87         extensions.push_back("VK_KHR_display");
88 
89     checkAllSupported(supportedExtensions, extensions);
90 
91     return vkt::createCustomInstanceWithExtensions(context, extensions);
92 }
93 
getDeviceNullFeatures(void)94 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures(void)
95 {
96     vk::VkPhysicalDeviceFeatures features;
97     deMemset(&features, 0, sizeof(features));
98     return features;
99 }
100 
createDeviceWithWsi(const vk::PlatformInterface & vkp,const vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const Extensions & supportedExtensions,const uint32_t queueFamilyIndex,bool requiresDisplayTiming,bool validationEnabled,const vk::VkAllocationCallbacks * pAllocator=DE_NULL)101 vk::Move<vk::VkDevice> createDeviceWithWsi(const vk::PlatformInterface &vkp, const vk::VkInstance instance,
102                                            const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
103                                            const Extensions &supportedExtensions, const uint32_t queueFamilyIndex,
104                                            bool requiresDisplayTiming, bool validationEnabled,
105                                            const vk::VkAllocationCallbacks *pAllocator = DE_NULL)
106 {
107     const float queuePriorities[]                  = {1.0f};
108     const vk::VkDeviceQueueCreateInfo queueInfos[] = {{vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, DE_NULL,
109                                                        (vk::VkDeviceQueueCreateFlags)0, queueFamilyIndex,
110                                                        DE_LENGTH_OF_ARRAY(queuePriorities), &queuePriorities[0]}};
111     const vk::VkPhysicalDeviceFeatures features    = getDeviceNullFeatures();
112     const char *const extensions[]                 = {"VK_KHR_swapchain", "VK_GOOGLE_display_timing"};
113 
114     const vk::VkDeviceCreateInfo deviceParams = {vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
115                                                  DE_NULL,
116                                                  (vk::VkDeviceCreateFlags)0,
117                                                  DE_LENGTH_OF_ARRAY(queueInfos),
118                                                  &queueInfos[0],
119                                                  0u,
120                                                  DE_NULL,
121                                                  requiresDisplayTiming ? 2u : 1u,
122                                                  DE_ARRAY_BEGIN(extensions),
123                                                  &features};
124 
125     for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
126     {
127         if (!isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
128             TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
129     }
130 
131     return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
132 }
133 
createDisplay(const vk::Platform & platform,const Extensions & supportedExtensions,vk::wsi::Type wsiType)134 de::MovePtr<vk::wsi::Display> createDisplay(const vk::Platform &platform, const Extensions &supportedExtensions,
135                                             vk::wsi::Type wsiType)
136 {
137     try
138     {
139         return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
140     }
141     catch (const tcu::NotSupportedError &e)
142     {
143         if (isExtensionStructSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))) &&
144             platform.hasDisplay(wsiType))
145         {
146             // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
147             // must support creating native display & window for that WSI type.
148             throw tcu::TestError(e.getMessage());
149         }
150         else
151             throw;
152     }
153 }
154 
createWindow(const vk::wsi::Display & display,const Maybe<UVec2> & initialSize)155 de::MovePtr<vk::wsi::Window> createWindow(const vk::wsi::Display &display, const Maybe<UVec2> &initialSize)
156 {
157     try
158     {
159         return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
160     }
161     catch (const tcu::NotSupportedError &e)
162     {
163         // See createDisplay - assuming that wsi::Display was supported platform port
164         // should also support creating a window.
165         throw tcu::TestError(e.getMessage());
166     }
167 }
168 
initSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)169 void initSemaphores(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkSemaphore> &semaphores)
170 {
171     for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
172         semaphores[ndx] = createSemaphore(vkd, device).disown();
173 }
174 
deinitSemaphores(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkSemaphore> & semaphores)175 void deinitSemaphores(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkSemaphore> &semaphores)
176 {
177     for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
178     {
179         if (semaphores[ndx] != (vk::VkSemaphore)0)
180             vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
181 
182         semaphores[ndx] = (vk::VkSemaphore)0;
183     }
184 
185     semaphores.clear();
186 }
187 
initFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)188 void initFences(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkFence> &fences)
189 {
190     for (size_t ndx = 0; ndx < fences.size(); ndx++)
191         fences[ndx] = createFence(vkd, device).disown();
192 }
193 
deinitFences(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFence> & fences)194 void deinitFences(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkFence> &fences)
195 {
196     for (size_t ndx = 0; ndx < fences.size(); ndx++)
197     {
198         if (fences[ndx] != (vk::VkFence)0)
199             vkd.destroyFence(device, fences[ndx], DE_NULL);
200 
201         fences[ndx] = (vk::VkFence)0;
202     }
203 
204     fences.clear();
205 }
206 
cmdRenderFrame(const vk::DeviceInterface & vkd,vk::VkCommandBuffer commandBuffer,vk::VkPipelineLayout pipelineLayout,vk::VkPipeline pipeline,size_t frameNdx,uint32_t quadCount)207 void cmdRenderFrame(const vk::DeviceInterface &vkd, vk::VkCommandBuffer commandBuffer,
208                     vk::VkPipelineLayout pipelineLayout, vk::VkPipeline pipeline, size_t frameNdx, uint32_t quadCount)
209 {
210     const uint32_t frameNdxValue = (uint32_t)frameNdx;
211 
212     vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
213     vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
214     vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
215 }
216 
createCommandBuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,vk::VkPipelineLayout pipelineLayout,vk::VkRenderPass renderPass,vk::VkFramebuffer framebuffer,vk::VkPipeline pipeline,vk::VkImage image,bool isFirst,size_t frameNdx,uint32_t quadCount,uint32_t imageWidth,uint32_t imageHeight)217 vk::Move<vk::VkCommandBuffer> createCommandBuffer(const vk::DeviceInterface &vkd, vk::VkDevice device,
218                                                   vk::VkCommandPool commandPool, vk::VkPipelineLayout pipelineLayout,
219                                                   vk::VkRenderPass renderPass, vk::VkFramebuffer framebuffer,
220                                                   vk::VkPipeline pipeline, vk::VkImage image, bool isFirst,
221                                                   size_t frameNdx, uint32_t quadCount, uint32_t imageWidth,
222                                                   uint32_t imageHeight)
223 {
224     const vk::VkCommandBufferAllocateInfo allocateInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, DE_NULL,
225 
226                                                           commandPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1};
227 
228     vk::Move<vk::VkCommandBuffer> commandBuffer(vk::allocateCommandBuffer(vkd, device, &allocateInfo));
229     beginCommandBuffer(vkd, *commandBuffer, 0u);
230 
231     {
232         const vk::VkImageSubresourceRange subRange = {vk::VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
233         const vk::VkImageMemoryBarrier barrier     = {
234             vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
235             DE_NULL,
236             vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
237             vk::VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
238             isFirst ? vk::VK_IMAGE_LAYOUT_UNDEFINED : vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
239             vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
240             VK_QUEUE_FAMILY_IGNORED,
241             VK_QUEUE_FAMILY_IGNORED,
242             image,
243             subRange};
244         vkd.cmdPipelineBarrier(*commandBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
245                                vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, DE_NULL, 0, DE_NULL, 1,
246                                &barrier);
247     }
248 
249     beginRenderPass(vkd, *commandBuffer, renderPass, framebuffer, vk::makeRect2D(imageWidth, imageHeight),
250                     tcu::Vec4(0.25f, 0.5f, 0.75f, 1.0f));
251 
252     cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
253 
254     endRenderPass(vkd, *commandBuffer);
255 
256     endCommandBuffer(vkd, *commandBuffer);
257     return commandBuffer;
258 }
259 
deinitCommandBuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool commandPool,std::vector<vk::VkCommandBuffer> & commandBuffers)260 void deinitCommandBuffers(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkCommandPool commandPool,
261                           std::vector<vk::VkCommandBuffer> &commandBuffers)
262 {
263     for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
264     {
265         if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
266             vkd.freeCommandBuffers(device, commandPool, 1u, &commandBuffers[ndx]);
267 
268         commandBuffers[ndx] = (vk::VkCommandBuffer)0;
269     }
270 
271     commandBuffers.clear();
272 }
273 
createCommandPool(const vk::DeviceInterface & vkd,vk::VkDevice device,uint32_t queueFamilyIndex)274 vk::Move<vk::VkCommandPool> createCommandPool(const vk::DeviceInterface &vkd, vk::VkDevice device,
275                                               uint32_t queueFamilyIndex)
276 {
277     const vk::VkCommandPoolCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, DE_NULL, 0u,
278                                                     queueFamilyIndex};
279 
280     return vk::createCommandPool(vkd, device, &createInfo);
281 }
282 
createFramebuffer(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,vk::VkImageView imageView,uint32_t width,uint32_t height)283 vk::Move<vk::VkFramebuffer> createFramebuffer(const vk::DeviceInterface &vkd, vk::VkDevice device,
284                                               vk::VkRenderPass renderPass, vk::VkImageView imageView, uint32_t width,
285                                               uint32_t height)
286 {
287     const vk::VkFramebufferCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
288                                                     DE_NULL,
289 
290                                                     0u,
291                                                     renderPass,
292                                                     1u,
293                                                     &imageView,
294                                                     width,
295                                                     height,
296                                                     1u};
297 
298     return vk::createFramebuffer(vkd, device, &createInfo);
299 }
300 
initFramebuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkRenderPass renderPass,std::vector<vk::VkImageView> imageViews,uint32_t width,uint32_t height,std::vector<vk::VkFramebuffer> & framebuffers)301 void initFramebuffers(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkRenderPass renderPass,
302                       std::vector<vk::VkImageView> imageViews, uint32_t width, uint32_t height,
303                       std::vector<vk::VkFramebuffer> &framebuffers)
304 {
305     DE_ASSERT(framebuffers.size() == imageViews.size());
306 
307     for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
308         framebuffers[ndx] = createFramebuffer(vkd, device, renderPass, imageViews[ndx], width, height).disown();
309 }
310 
deinitFramebuffers(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkFramebuffer> & framebuffers)311 void deinitFramebuffers(const vk::DeviceInterface &vkd, vk::VkDevice device,
312                         std::vector<vk::VkFramebuffer> &framebuffers)
313 {
314     for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
315     {
316         if (framebuffers[ndx] != (vk::VkFramebuffer)0)
317             vkd.destroyFramebuffer(device, framebuffers[ndx], DE_NULL);
318 
319         framebuffers[ndx] = (vk::VkFramebuffer)0;
320     }
321 
322     framebuffers.clear();
323 }
324 
createImageView(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkImage image,vk::VkFormat format)325 vk::Move<vk::VkImageView> createImageView(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkImage image,
326                                           vk::VkFormat format)
327 {
328     const vk::VkImageViewCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
329                                                   DE_NULL,
330 
331                                                   0u,
332                                                   image,
333                                                   vk::VK_IMAGE_VIEW_TYPE_2D,
334                                                   format,
335                                                   vk::makeComponentMappingRGBA(),
336                                                   {vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}};
337 
338     return vk::createImageView(vkd, device, &createInfo, DE_NULL);
339 }
340 
initImageViews(const vk::DeviceInterface & vkd,vk::VkDevice device,const std::vector<vk::VkImage> & images,vk::VkFormat format,std::vector<vk::VkImageView> & imageViews)341 void initImageViews(const vk::DeviceInterface &vkd, vk::VkDevice device, const std::vector<vk::VkImage> &images,
342                     vk::VkFormat format, std::vector<vk::VkImageView> &imageViews)
343 {
344     DE_ASSERT(images.size() == imageViews.size());
345 
346     for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
347         imageViews[ndx] = createImageView(vkd, device, images[ndx], format).disown();
348 }
349 
deinitImageViews(const vk::DeviceInterface & vkd,vk::VkDevice device,std::vector<vk::VkImageView> & imageViews)350 void deinitImageViews(const vk::DeviceInterface &vkd, vk::VkDevice device, std::vector<vk::VkImageView> &imageViews)
351 {
352     for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
353     {
354         if (imageViews[ndx] != (vk::VkImageView)0)
355             vkd.destroyImageView(device, imageViews[ndx], DE_NULL);
356 
357         imageViews[ndx] = (vk::VkImageView)0;
358     }
359 
360     imageViews.clear();
361 }
362 
createRenderPass(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkFormat format)363 vk::Move<vk::VkRenderPass> createRenderPass(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkFormat format)
364 {
365     return vk::makeRenderPass(vkd, device, format, vk::VK_FORMAT_UNDEFINED, vk::VK_ATTACHMENT_LOAD_OP_LOAD,
366                               vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
367 }
368 
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)369 vk::Move<vk::VkPipeline> createPipeline(const vk::DeviceInterface &vkd, vk::VkDevice device,
370                                         vk::VkRenderPass renderPass, vk::VkPipelineLayout layout,
371                                         vk::VkShaderModule vertexShaderModule, vk::VkShaderModule fragmentShaderModule,
372                                         uint32_t width, uint32_t height)
373 {
374     const vk::VkPipelineVertexInputStateCreateInfo vertexInputState = {
375         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, DE_NULL, 0u, 0u, DE_NULL, 0u, DE_NULL};
376     const std::vector<vk::VkViewport> viewports(1, vk::makeViewport(tcu::UVec2(width, height)));
377     const std::vector<vk::VkRect2D> scissors(1, vk::makeRect2D(tcu::UVec2(width, height)));
378 
379     return vk::makeGraphicsPipeline(
380         vkd,                  // const DeviceInterface&                        vk
381         device,               // const VkDevice                                device
382         layout,               // const VkPipelineLayout                        pipelineLayout
383         vertexShaderModule,   // const VkShaderModule                          vertexShaderModule
384         DE_NULL,              // const VkShaderModule                          tessellationControlShaderModule
385         DE_NULL,              // const VkShaderModule                          tessellationEvalShaderModule
386         DE_NULL,              // const VkShaderModule                          geometryShaderModule
387         fragmentShaderModule, // const VkShaderModule                          fragmentShaderModule
388         renderPass,           // const VkRenderPass                            renderPass
389         viewports,            // const std::vector<VkViewport>&                viewports
390         scissors,             // const std::vector<VkRect2D>&                  scissors
391         vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology                     topology
392         0u,                                      // const uint32_t                                subpass
393         0u,                                      // const uint32_t                                patchControlPoints
394         &vertexInputState); // const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
395 }
396 
createPipelineLayout(const vk::DeviceInterface & vkd,vk::VkDevice device)397 vk::Move<vk::VkPipelineLayout> createPipelineLayout(const vk::DeviceInterface &vkd, vk::VkDevice device)
398 {
399     const vk::VkPushConstantRange pushConstants[]   = {{vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u}};
400     const vk::VkPipelineLayoutCreateInfo createInfo = {vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
401                                                        DE_NULL,
402                                                        0u,
403 
404                                                        0u,
405                                                        DE_NULL,
406 
407                                                        DE_LENGTH_OF_ARRAY(pushConstants),
408                                                        pushConstants};
409 
410     return vk::createPipelineLayout(vkd, device, &createInfo);
411 }
412 
413 struct TestConfig
414 {
415     vk::wsi::Type wsiType;
416     bool useDisplayTiming;
417     vk::VkPresentModeKHR presentMode;
418 };
419 
420 class DisplayTimingTestInstance : public TestInstance
421 {
422 public:
423     DisplayTimingTestInstance(Context &context, const TestConfig &testConfig);
424     ~DisplayTimingTestInstance(void);
425 
426     tcu::TestStatus iterate(void);
427 
428 private:
429     const bool m_useDisplayTiming;
430     const uint32_t m_quadCount;
431     const vk::PlatformInterface &m_vkp;
432     const Extensions m_instanceExtensions;
433     const CustomInstance m_instance;
434     const vk::InstanceDriver &m_vki;
435     const vk::VkPhysicalDevice m_physicalDevice;
436     const de::UniquePtr<vk::wsi::Display> m_nativeDisplay;
437     const de::UniquePtr<vk::wsi::Window> m_nativeWindow;
438     const vk::Unique<vk::VkSurfaceKHR> m_surface;
439 
440     const uint32_t m_queueFamilyIndex;
441     const Extensions m_deviceExtensions;
442     const vk::Unique<vk::VkDevice> m_device;
443     const vk::DeviceDriver m_vkd;
444     const vk::VkQueue m_queue;
445 
446     const vk::Unique<vk::VkCommandPool> m_commandPool;
447     const vk::Unique<vk::VkShaderModule> m_vertexShaderModule;
448     const vk::Unique<vk::VkShaderModule> m_fragmentShaderModule;
449     const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
450 
451     const vk::VkSurfaceCapabilitiesKHR m_surfaceProperties;
452     const vector<vk::VkSurfaceFormatKHR> m_surfaceFormats;
453     const vector<vk::VkPresentModeKHR> m_presentModes;
454 
455     tcu::ResultCollector m_resultCollector;
456 
457     vk::Move<vk::VkSwapchainKHR> m_swapchain;
458     std::vector<vk::VkImage> m_swapchainImages;
459     std::vector<bool> m_isFirst;
460 
461     vk::Move<vk::VkRenderPass> m_renderPass;
462     vk::Move<vk::VkPipeline> m_pipeline;
463 
464     std::vector<vk::VkImageView> m_swapchainImageViews;
465     std::vector<vk::VkFramebuffer> m_framebuffers;
466     std::vector<vk::VkCommandBuffer> m_commandBuffers;
467     std::vector<vk::VkSemaphore> m_acquireSemaphores;
468     std::vector<vk::VkSemaphore> m_renderSemaphores;
469     std::vector<vk::VkFence> m_fences;
470 
471     vk::VkSemaphore m_freeAcquireSemaphore;
472     vk::VkSemaphore m_freeRenderSemaphore;
473 
474     vk::VkSwapchainCreateInfoKHR m_swapchainConfig;
475 
476     const size_t m_frameCount;
477     size_t m_frameNdx;
478 
479     const size_t m_maxOutOfDateCount;
480     size_t m_outOfDateCount;
481 
482     std::map<uint32_t, uint64_t> m_queuePresentTimes;
483 
484     vk::VkRefreshCycleDurationGOOGLE m_rcDuration;
485     uint64_t m_refreshDurationMultiplier;
486     uint64_t m_targetIPD;
487     uint64_t m_prevDesiredPresentTime;
488     uint32_t m_nextPresentID;
489     uint32_t m_ignoreThruPresentID;
490     bool m_ExpectImage80Late;
491 
492     void initSwapchainResources(void);
493     void deinitSwapchainResources(void);
494     void render(void);
495 };
496 
createSwapchainConfig(vk::VkSurfaceKHR surface,uint32_t queueFamilyIndex,const vk::VkSurfaceCapabilitiesKHR & properties,const vector<vk::VkSurfaceFormatKHR> & formats,const vector<vk::VkPresentModeKHR> & presentModes,vk::VkPresentModeKHR presentMode)497 vk::VkSwapchainCreateInfoKHR createSwapchainConfig(vk::VkSurfaceKHR surface, uint32_t queueFamilyIndex,
498                                                    const vk::VkSurfaceCapabilitiesKHR &properties,
499                                                    const vector<vk::VkSurfaceFormatKHR> &formats,
500                                                    const vector<vk::VkPresentModeKHR> &presentModes,
501                                                    vk::VkPresentModeKHR presentMode)
502 {
503     const uint32_t imageLayers             = 1u;
504     const vk::VkImageUsageFlags imageUsage = properties.supportedUsageFlags;
505     const vk::VkBool32 clipped             = VK_FALSE;
506 
507     const uint32_t imageWidth =
508         (properties.currentExtent.width != 0xFFFFFFFFu) ?
509             properties.currentExtent.width :
510             de::min(1024u, properties.minImageExtent.width +
511                                ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2));
512     const uint32_t imageHeight =
513         (properties.currentExtent.height != 0xFFFFFFFFu) ?
514             properties.currentExtent.height :
515             de::min(1024u, properties.minImageExtent.height +
516                                ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2));
517     const vk::VkExtent2D imageSize = {imageWidth, imageHeight};
518 
519     {
520         size_t presentModeNdx;
521 
522         for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
523         {
524             if (presentModes[presentModeNdx] == presentMode)
525                 break;
526         }
527 
528         if (presentModeNdx == presentModes.size())
529             TCU_THROW(NotSupportedError, "Present mode not supported");
530     }
531 
532     // Pick the first supported transform, alpha, and format:
533     vk::VkSurfaceTransformFlagsKHR transform;
534     for (transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
535     {
536         if ((properties.supportedTransforms & transform) != 0)
537             break;
538     }
539 
540     vk::VkCompositeAlphaFlagsKHR alpha;
541     for (alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
542     {
543         if ((alpha & properties.supportedCompositeAlpha) != 0)
544             break;
545     }
546 
547     {
548         const vk::VkSurfaceTransformFlagBitsKHR preTransform = (vk::VkSurfaceTransformFlagBitsKHR)transform;
549         const vk::VkCompositeAlphaFlagBitsKHR compositeAlpha = (vk::VkCompositeAlphaFlagBitsKHR)alpha;
550         const vk::VkFormat imageFormat                       = formats[0].format;
551         const vk::VkColorSpaceKHR imageColorSpace            = formats[0].colorSpace;
552         const vk::VkSwapchainCreateInfoKHR createInfo        = {vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
553                                                                 DE_NULL,
554                                                                 0u,
555                                                                 surface,
556                                                                 properties.minImageCount,
557                                                                 imageFormat,
558                                                                 imageColorSpace,
559                                                                 imageSize,
560                                                                 imageLayers,
561                                                                 imageUsage,
562                                                                 vk::VK_SHARING_MODE_EXCLUSIVE,
563                                                                 1u,
564                                                                 &queueFamilyIndex,
565                                                                 preTransform,
566                                                                 compositeAlpha,
567                                                                 presentMode,
568                                                                 clipped,
569                                                                 (vk::VkSwapchainKHR)0};
570 
571         return createInfo;
572     }
573 }
574 
DisplayTimingTestInstance(Context & context,const TestConfig & testConfig)575 DisplayTimingTestInstance::DisplayTimingTestInstance(Context &context, const TestConfig &testConfig)
576     : TestInstance(context)
577     , m_useDisplayTiming(testConfig.useDisplayTiming)
578     , m_quadCount(16u)
579     , m_vkp(context.getPlatformInterface())
580     , m_instanceExtensions(vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
581     , m_instance(createInstanceWithWsi(context, m_instanceExtensions, testConfig.wsiType))
582     , m_vki(m_instance.getDriver())
583     , m_physicalDevice(vk::chooseDevice(m_vki, m_instance, context.getTestContext().getCommandLine()))
584     , m_nativeDisplay(createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions,
585                                     testConfig.wsiType))
586     , m_nativeWindow(createWindow(*m_nativeDisplay, tcu::Nothing))
587     , m_surface(vk::wsi::createSurface(m_vki, m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow,
588                                        context.getTestContext().getCommandLine()))
589 
590     , m_queueFamilyIndex(vk::wsi::chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
591     , m_deviceExtensions(vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
592     , m_device(createDeviceWithWsi(m_vkp, m_instance, m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex,
593                                    testConfig.useDisplayTiming,
594                                    context.getTestContext().getCommandLine().isValidationEnabled()))
595     , m_vkd(m_vkp, m_instance, *m_device, context.getUsedApiVersion(), context.getTestContext().getCommandLine())
596     , m_queue(getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
597 
598     , m_commandPool(createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
599     , m_vertexShaderModule(vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
600     , m_fragmentShaderModule(
601           vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
602     , m_pipelineLayout(createPipelineLayout(m_vkd, *m_device))
603 
604     , m_surfaceProperties(vk::wsi::getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface))
605     , m_surfaceFormats(vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
606     , m_presentModes(vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
607 
608     , m_freeAcquireSemaphore((vk::VkSemaphore)0)
609     , m_freeRenderSemaphore((vk::VkSemaphore)0)
610 
611     , m_swapchainConfig(createSwapchainConfig(*m_surface, m_queueFamilyIndex, m_surfaceProperties, m_surfaceFormats,
612                                               m_presentModes, testConfig.presentMode))
613 
614     , m_frameCount(60u * 5u)
615     , m_frameNdx(0u)
616 
617     , m_maxOutOfDateCount(20u)
618     , m_outOfDateCount(0u)
619     , m_ExpectImage80Late(false)
620 {
621     {
622         const tcu::ScopedLogSection surfaceInfo(m_context.getTestContext().getLog(), "SurfaceCapabilities",
623                                                 "SurfaceCapabilities");
624         m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
625     }
626 }
627 
~DisplayTimingTestInstance(void)628 DisplayTimingTestInstance::~DisplayTimingTestInstance(void)
629 {
630     deinitSwapchainResources();
631 }
632 
initSwapchainResources(void)633 void DisplayTimingTestInstance::initSwapchainResources(void)
634 {
635     const size_t fenceCount        = 6;
636     const uint32_t imageWidth      = m_swapchainConfig.imageExtent.width;
637     const uint32_t imageHeight     = m_swapchainConfig.imageExtent.height;
638     const vk::VkFormat imageFormat = m_swapchainConfig.imageFormat;
639 
640     m_swapchain       = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfig);
641     m_swapchainImages = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain);
642     m_isFirst.resize(m_swapchainImages.size(), true);
643 
644     m_renderPass = createRenderPass(m_vkd, *m_device, imageFormat);
645     m_pipeline   = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule,
646                                   *m_fragmentShaderModule, imageWidth, imageHeight);
647 
648     m_swapchainImageViews = std::vector<vk::VkImageView>(m_swapchainImages.size(), (vk::VkImageView)0);
649     m_framebuffers        = std::vector<vk::VkFramebuffer>(m_swapchainImages.size(), (vk::VkFramebuffer)0);
650     m_acquireSemaphores   = std::vector<vk::VkSemaphore>(m_swapchainImages.size(), (vk::VkSemaphore)0);
651     m_renderSemaphores    = std::vector<vk::VkSemaphore>(m_swapchainImages.size(), (vk::VkSemaphore)0);
652 
653     m_fences         = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
654     m_commandBuffers = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
655 
656     m_freeAcquireSemaphore = (vk::VkSemaphore)0;
657     m_freeRenderSemaphore  = (vk::VkSemaphore)0;
658 
659     m_freeAcquireSemaphore = createSemaphore(m_vkd, *m_device).disown();
660     m_freeRenderSemaphore  = createSemaphore(m_vkd, *m_device).disown();
661 
662     initImageViews(m_vkd, *m_device, m_swapchainImages, imageFormat, m_swapchainImageViews);
663     initFramebuffers(m_vkd, *m_device, *m_renderPass, m_swapchainImageViews, imageWidth, imageHeight, m_framebuffers);
664     initSemaphores(m_vkd, *m_device, m_acquireSemaphores);
665     initSemaphores(m_vkd, *m_device, m_renderSemaphores);
666 
667     initFences(m_vkd, *m_device, m_fences);
668 
669     if (m_useDisplayTiming)
670     {
671         // This portion should do interesting bits
672         m_queuePresentTimes = std::map<uint32_t, uint64_t>();
673 
674         m_vkd.getRefreshCycleDurationGOOGLE(*m_device, *m_swapchain, &m_rcDuration);
675 
676         m_refreshDurationMultiplier = 1u;
677         m_targetIPD                 = m_rcDuration.refreshDuration;
678         m_prevDesiredPresentTime    = 0u;
679         m_nextPresentID             = 0u;
680         m_ignoreThruPresentID       = 0u;
681     }
682 }
683 
deinitSwapchainResources(void)684 void DisplayTimingTestInstance::deinitSwapchainResources(void)
685 {
686     VK_CHECK(m_vkd.queueWaitIdle(m_queue));
687 
688     if (m_freeAcquireSemaphore != (vk::VkSemaphore)0)
689     {
690         m_vkd.destroySemaphore(*m_device, m_freeAcquireSemaphore, DE_NULL);
691         m_freeAcquireSemaphore = (vk::VkSemaphore)0;
692     }
693 
694     if (m_freeRenderSemaphore != (vk::VkSemaphore)0)
695     {
696         m_vkd.destroySemaphore(*m_device, m_freeRenderSemaphore, DE_NULL);
697         m_freeRenderSemaphore = (vk::VkSemaphore)0;
698     }
699 
700     deinitSemaphores(m_vkd, *m_device, m_acquireSemaphores);
701     deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
702     deinitFences(m_vkd, *m_device, m_fences);
703     deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
704     deinitFramebuffers(m_vkd, *m_device, m_framebuffers);
705     deinitImageViews(m_vkd, *m_device, m_swapchainImageViews);
706 
707     m_swapchainImages.clear();
708     m_isFirst.clear();
709 
710     m_swapchain  = vk::Move<vk::VkSwapchainKHR>();
711     m_renderPass = vk::Move<vk::VkRenderPass>();
712     m_pipeline   = vk::Move<vk::VkPipeline>();
713 }
714 
getPastPresentationTiming(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkSwapchainKHR swapchain)715 vector<vk::VkPastPresentationTimingGOOGLE> getPastPresentationTiming(const vk::DeviceInterface &vkd,
716                                                                      vk::VkDevice device, vk::VkSwapchainKHR swapchain)
717 {
718     vector<vk::VkPastPresentationTimingGOOGLE> pastPresentationTimings;
719     uint32_t numPastPresentationTimings = 0;
720 
721     vkd.getPastPresentationTimingGOOGLE(device, swapchain, &numPastPresentationTimings, DE_NULL);
722 
723     pastPresentationTimings.resize(numPastPresentationTimings);
724 
725     if (numPastPresentationTimings > 0)
726         vkd.getPastPresentationTimingGOOGLE(device, swapchain, &numPastPresentationTimings,
727                                             &pastPresentationTimings[0]);
728 
729     return pastPresentationTimings;
730 }
731 
render(void)732 void DisplayTimingTestInstance::render(void)
733 {
734     const uint64_t foreverNs = ~0x0ull;
735     const vk::VkFence fence  = m_fences[m_frameNdx % m_fences.size()];
736     const uint32_t width     = m_swapchainConfig.imageExtent.width;
737     const uint32_t height    = m_swapchainConfig.imageExtent.height;
738     tcu::TestLog &log        = m_context.getTestContext().getLog();
739 
740     // Throttle execution
741     if (m_frameNdx >= m_fences.size())
742     {
743         VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
744         VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
745 
746         m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u,
747                                  &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
748         m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
749     }
750 
751     vk::VkSemaphore currentAcquireSemaphore = m_freeAcquireSemaphore;
752     vk::VkSemaphore currentRenderSemaphore  = m_freeRenderSemaphore;
753     uint32_t imageIndex;
754 
755     // Acquire next image
756     VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, currentAcquireSemaphore, (vk::VkFence)0,
757                                        &imageIndex));
758 
759     // Create command buffer
760     m_commandBuffers[m_frameNdx % m_commandBuffers.size()] =
761         createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_pipelineLayout, *m_renderPass,
762                             m_framebuffers[imageIndex], *m_pipeline, m_swapchainImages[imageIndex],
763                             m_isFirst[imageIndex], m_frameNdx, m_quadCount, width, height)
764             .disown();
765     m_isFirst[imageIndex] = false;
766 
767     // Obtain timing data from previous frames
768     if (m_useDisplayTiming)
769     {
770         const vector<vk::VkPastPresentationTimingGOOGLE> pastPresentationTimings(
771             getPastPresentationTiming(m_vkd, *m_device, *m_swapchain));
772         bool isEarly = false;
773         bool isLate  = false;
774 
775         for (size_t pastPresentationInfoNdx = 0; pastPresentationInfoNdx < pastPresentationTimings.size();
776              pastPresentationInfoNdx++)
777         {
778             if (m_queuePresentTimes[pastPresentationTimings[pastPresentationInfoNdx].presentID] >
779                 pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime)
780             {
781                 m_resultCollector.fail("Image with PresentID " +
782                                        de::toString(pastPresentationTimings[pastPresentationInfoNdx].presentID) +
783                                        "was displayed before vkQueuePresentKHR was called.");
784             }
785             if (!m_ignoreThruPresentID)
786             {
787                 // This is the first time that we've received an
788                 // actualPresentTime for this swapchain.  In order to not
789                 // perceive these early frames as "late", we need to sync-up
790                 // our future desiredPresentTime's with the
791                 // actualPresentTime(s) that we're receiving now.
792                 const int64_t multiple = m_nextPresentID - pastPresentationTimings.back().presentID;
793 
794                 m_prevDesiredPresentTime = pastPresentationTimings.back().actualPresentTime + (multiple * m_targetIPD);
795                 m_ignoreThruPresentID    = pastPresentationTimings[pastPresentationInfoNdx].presentID + 1;
796             }
797             else if (pastPresentationTimings[pastPresentationInfoNdx].presentID > m_ignoreThruPresentID)
798             {
799                 if (pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime >
800                     (pastPresentationTimings[pastPresentationInfoNdx].desiredPresentTime +
801                      m_rcDuration.refreshDuration + MILLISECOND))
802                 {
803                     const uint64_t actual  = pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime;
804                     const uint64_t desired = pastPresentationTimings[pastPresentationInfoNdx].desiredPresentTime;
805                     const uint64_t rdur    = m_rcDuration.refreshDuration;
806                     const uint64_t diff1   = actual - (desired + rdur);
807                     const uint64_t diff2   = actual - desired;
808 
809                     log << TestLog::Message << "Image PresentID "
810                         << pastPresentationTimings[pastPresentationInfoNdx].presentID << " was " << diff1
811                         << " nsec late." << TestLog::EndMessage;
812                     if (m_ExpectImage80Late && (pastPresentationTimings[pastPresentationInfoNdx].presentID == 80))
813                     {
814                         if (diff1 > (SECOND / 2))
815                             log << TestLog::Message
816                                 << "\tNote: Image PresentID 80 was expected to be late by approximately 1 second."
817                                 << TestLog::EndMessage;
818                         else
819                             m_resultCollector.fail(
820                                 "Image PresentID 80 was not late by approximately 1 second, as expected.");
821                     }
822                     log << TestLog::Message << "\t\t   actualPresentTime = " << actual << " nsec"
823                         << TestLog::EndMessage;
824                     log << TestLog::Message << "\t\t - desiredPresentTime= " << desired << " nsec"
825                         << TestLog::EndMessage;
826                     log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
827                     log << TestLog::Message << "\t\t   diff              =       " << diff2 << " nsec"
828                         << TestLog::EndMessage;
829                     log << TestLog::Message << "\t\t - refreshDuration   =       " << rdur << " nsec"
830                         << TestLog::EndMessage;
831                     log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
832                     log << TestLog::Message << "\t\t   diff              =        " << diff1 << " nsec"
833                         << TestLog::EndMessage;
834 
835                     isLate = true;
836                 }
837                 else if ((pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime >
838                           pastPresentationTimings[pastPresentationInfoNdx].earliestPresentTime) &&
839                          (pastPresentationTimings[pastPresentationInfoNdx].presentMargin > (2 * MILLISECOND)))
840                 {
841                     const uint64_t actual   = pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime;
842                     const uint64_t earliest = pastPresentationTimings[pastPresentationInfoNdx].earliestPresentTime;
843                     const uint64_t diff     = actual - earliest;
844 
845                     log << TestLog::Message << "Image PresentID "
846                         << pastPresentationTimings[pastPresentationInfoNdx].presentID << " can be presented " << diff
847                         << " nsec earlier." << TestLog::EndMessage;
848                     log << TestLog::Message << "\t\t   actualPresentTime = " << actual << " nsec"
849                         << TestLog::EndMessage;
850                     log << TestLog::Message << "\t\t -earliestPresentTime= " << earliest << " nsec"
851                         << TestLog::EndMessage;
852                     log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
853                     log << TestLog::Message << "\t\t   diff              =        " << diff << " nsec"
854                         << TestLog::EndMessage;
855 
856                     isEarly = true;
857                 }
858             }
859         }
860         // Preference is given to late presents over early presents:
861         if (isLate)
862         {
863             // Demonstrate how to slow down the frame rate if a frame is late,
864             // but don't go too slow (for test time reasons):
865             if (++m_refreshDurationMultiplier > 2)
866                 m_refreshDurationMultiplier = 2;
867             else
868                 log << TestLog::Message << "Increasing multiplier." << TestLog::EndMessage;
869         }
870         else if (isEarly)
871         {
872             // Demonstrate how to speed up the frame rate if a frame is early,
873             // but don't let the multiplier hit zero:
874             if (--m_refreshDurationMultiplier == 0)
875                 m_refreshDurationMultiplier = 1;
876             else
877                 log << TestLog::Message << "Decreasing multiplier." << TestLog::EndMessage;
878         }
879         m_targetIPD = m_rcDuration.refreshDuration * m_refreshDurationMultiplier;
880     }
881 
882     // Submit command buffer
883     {
884         const vk::VkPipelineStageFlags dstStageMask = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
885         const vk::VkSubmitInfo submitInfo           = {vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
886                                                        DE_NULL,
887                                                        1u,
888                                                        &currentAcquireSemaphore,
889                                                        &dstStageMask,
890                                                        1u,
891                                                        &m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
892                                                        1u,
893                                                        &currentRenderSemaphore};
894 
895         VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
896     }
897 
898     // Present frame
899     if (m_useDisplayTiming)
900     {
901         // This portion should do interesting bits
902 
903         // Initially, mirror reference to move things along
904         vk::VkResult result;
905         vk::VkPresentTimeGOOGLE presentTime = {++m_nextPresentID, m_prevDesiredPresentTime};
906         // Record the current time, to record as the time of the vkQueuePresentKHR() call:
907         const uint64_t curtimeNano           = deGetMicroseconds() * 1000;
908         m_queuePresentTimes[m_nextPresentID] = curtimeNano;
909 
910         uint64_t desiredPresentTime = 0u;
911         if (m_prevDesiredPresentTime == 0)
912         {
913             // This must be the first present for this swapchain.  Find out the
914             // current time, as the basis for desiredPresentTime:
915             if (curtimeNano != 0)
916             {
917                 presentTime.desiredPresentTime = curtimeNano;
918                 presentTime.desiredPresentTime += (m_targetIPD / 2);
919             }
920             else
921             {
922                 // Since we didn't find out the current time, don't give a
923                 // desiredPresentTime:
924                 presentTime.desiredPresentTime = 0;
925             }
926         }
927         else
928         {
929             desiredPresentTime = m_prevDesiredPresentTime + m_targetIPD;
930             if ((presentTime.presentID == 80) && (m_swapchainConfig.presentMode != vk::VK_PRESENT_MODE_MAILBOX_KHR))
931             {
932                 // Test if desiredPresentTime is 1 second earlier (i.e. before the previous image could have been presented)
933                 presentTime.desiredPresentTime -= SECOND;
934                 m_ExpectImage80Late = true;
935             }
936         }
937         m_prevDesiredPresentTime = desiredPresentTime;
938 
939         const vk::VkPresentTimesInfoGOOGLE presentTimesInfo = {vk::VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE, DE_NULL,
940                                                                1u, &presentTime};
941         const vk::VkPresentInfoKHR presentInfo              = {vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
942                                                                &presentTimesInfo,
943                                                                1u,
944                                                                &currentRenderSemaphore,
945                                                                1u,
946                                                                &*m_swapchain,
947                                                                &imageIndex,
948                                                                &result};
949 
950         VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
951         VK_CHECK_WSI(result);
952     }
953     else
954     {
955         vk::VkResult result;
956         const vk::VkPresentInfoKHR presentInfo = {vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
957                                                   DE_NULL,
958                                                   1u,
959                                                   &currentRenderSemaphore,
960                                                   1u,
961                                                   &*m_swapchain,
962                                                   &imageIndex,
963                                                   &result};
964 
965         VK_CHECK_WSI(m_vkd.queuePresentKHR(m_queue, &presentInfo));
966         VK_CHECK_WSI(result);
967     }
968 
969     {
970         m_freeAcquireSemaphore          = m_acquireSemaphores[imageIndex];
971         m_acquireSemaphores[imageIndex] = currentAcquireSemaphore;
972 
973         m_freeRenderSemaphore          = m_renderSemaphores[imageIndex];
974         m_renderSemaphores[imageIndex] = currentRenderSemaphore;
975     }
976 }
977 
iterate(void)978 tcu::TestStatus DisplayTimingTestInstance::iterate(void)
979 {
980     // Initialize swapchain specific resources
981     // Render test
982     try
983     {
984         if (m_frameNdx == 0)
985         {
986             if (m_outOfDateCount == 0)
987                 m_context.getTestContext().getLog()
988                     << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfig << tcu::TestLog::EndMessage;
989 
990             initSwapchainResources();
991         }
992 
993         render();
994     }
995     catch (const vk::Error &error)
996     {
997         if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
998         {
999             if (m_outOfDateCount < m_maxOutOfDateCount)
1000             {
1001                 m_context.getTestContext().getLog()
1002                     << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources."
1003                     << TestLog::EndMessage;
1004                 deinitSwapchainResources();
1005                 m_frameNdx = 0;
1006                 m_outOfDateCount++;
1007 
1008                 return tcu::TestStatus::incomplete();
1009             }
1010             else
1011             {
1012                 m_context.getTestContext().getLog()
1013                     << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
1014                 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " +
1015                                        de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
1016             }
1017         }
1018         else
1019         {
1020             m_resultCollector.fail(error.what());
1021         }
1022 
1023         deinitSwapchainResources();
1024 
1025         return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1026     }
1027 
1028     m_frameNdx++;
1029 
1030     if (m_frameNdx >= m_frameCount)
1031     {
1032         deinitSwapchainResources();
1033 
1034         return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1035     }
1036     else
1037         return tcu::TestStatus::incomplete();
1038 }
1039 
1040 struct Programs
1041 {
initvkt::wsi::__anon9a1226100111::Programs1042     static void init(vk::SourceCollections &dst, TestConfig)
1043     {
1044         dst.glslSources.add("quad-vert") << glu::VertexSource(
1045             "#version 450\n"
1046             "out gl_PerVertex {\n"
1047             "\tvec4 gl_Position;\n"
1048             "};\n"
1049             "highp float;\n"
1050             "void main (void) {\n"
1051             "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
1052             "\t                   ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
1053             "}\n");
1054         dst.glslSources.add("quad-frag") << glu::FragmentSource(
1055             "#version 310 es\n"
1056             "layout(location = 0) out highp vec4 o_color;\n"
1057             "layout(push_constant) uniform PushConstant {\n"
1058             "\thighp uint frameNdx;\n"
1059             "} pushConstants;\n"
1060             "void main (void)\n"
1061             "{\n"
1062             "\thighp uint frameNdx = pushConstants.frameNdx;\n"
1063             "\thighp uint x = frameNdx + uint(gl_FragCoord.x);\n"
1064             "\thighp uint y = frameNdx + uint(gl_FragCoord.y);\n"
1065             "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
1066             "\t             +  64u * bitfieldExtract(y, 1, 1)\n"
1067             "\t             +  32u * bitfieldExtract(x, 3, 1);\n"
1068             "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
1069             "\t             +  64u * bitfieldExtract(x, 2, 1)\n"
1070             "\t             +  32u * bitfieldExtract(y, 3, 1);\n"
1071             "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
1072             "\t             +  64u * bitfieldExtract(y, 2, 1)\n"
1073             "\t             +  32u * bitfieldExtract(x, 4, 1);\n"
1074             "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
1075             "}\n");
1076     }
1077 };
1078 
1079 } // namespace
1080 
createDisplayTimingTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1081 void createDisplayTimingTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
1082 {
1083     const struct
1084     {
1085         vk::VkPresentModeKHR mode;
1086         const char *name;
1087     } presentModes[] = {
1088         {vk::VK_PRESENT_MODE_FIFO_KHR, "fifo"},
1089         {vk::VK_PRESENT_MODE_FIFO_RELAXED_KHR, "fifo_relaxed"},
1090         {vk::VK_PRESENT_MODE_IMMEDIATE_KHR, "immediate"},
1091         {vk::VK_PRESENT_MODE_MAILBOX_KHR, "mailbox"},
1092     };
1093 
1094     for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1095     {
1096         de::MovePtr<tcu::TestCaseGroup> presentModeGroup(
1097             new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name));
1098 
1099         for (size_t ref = 0; ref < 2; ref++)
1100         {
1101             const bool isReference = (ref == 0);
1102             const char *const name = isReference ? "reference" : "display_timing";
1103             TestConfig config;
1104 
1105             config.wsiType          = wsiType;
1106             config.useDisplayTiming = !isReference;
1107             config.presentMode      = presentModes[presentModeNdx].mode;
1108 
1109             presentModeGroup->addChild(new vkt::InstanceFactory1<DisplayTimingTestInstance, TestConfig, Programs>(
1110                 testGroup->getTestContext(), name, Programs(), config));
1111         }
1112 
1113         testGroup->addChild(presentModeGroup.release());
1114     }
1115 }
1116 
1117 } // namespace wsi
1118 } // namespace vkt
1119