GOOGLE_display_timing: Trigger the fence off vkQueueSubmit
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / wsi / vktWsiDisplayTimingTests.cpp
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 "vktWsiDisplayTimingTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28 #include "vkRefUtil.hpp"
29 #include "vkWsiPlatform.hpp"
30 #include "vkWsiUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkDeviceUtil.hpp"
33 #include "vkPlatform.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkPrograms.hpp"
36
37 #include "vkWsiUtil.hpp"
38
39 #include "tcuPlatform.hpp"
40 #include "tcuResultCollector.hpp"
41 #include "tcuTestLog.hpp"
42 #include "deClock.h"
43
44 #include <vector>
45 #include <string>
46
47 using std::vector;
48 using std::string;
49
50 using tcu::Maybe;
51 using tcu::UVec2;
52 using tcu::TestLog;
53
54 namespace vkt
55 {
56 namespace wsi
57 {
58 namespace
59 {
60 static const deUint64 MILLISECOND = 1000ull * 1000ull;
61 static const deUint64 SECOND = 1000ull * MILLISECOND;
62
63 typedef vector<vk::VkExtensionProperties> Extensions;
64
65 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
66 {
67         for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
68                  requiredExtName != requiredExtensions.end();
69                  ++requiredExtName)
70         {
71                 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(*requiredExtName)))
72                         TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
73         }
74 }
75
76 vk::Move<vk::VkInstance> createInstanceWithWsi (const vk::PlatformInterface&            vkp,
77                                                                                                 const Extensions&                                       supportedExtensions,
78                                                                                                 vk::wsi::Type                                           wsiType)
79 {
80         vector<string>  extensions;
81
82         extensions.push_back("VK_KHR_surface");
83         extensions.push_back(getExtensionName(wsiType));
84
85         checkAllSupported(supportedExtensions, extensions);
86
87         return vk::createDefaultInstance(vkp, vector<string>(), extensions);
88 }
89
90 vk::VkPhysicalDeviceFeatures getDeviceNullFeatures (void)
91 {
92         vk::VkPhysicalDeviceFeatures features;
93         deMemset(&features, 0, sizeof(features));
94         return features;
95 }
96
97 deUint32 getNumQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
98 {
99         deUint32        numFamilies             = 0;
100
101         vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
102
103         return numFamilies;
104 }
105
106 vector<deUint32> getSupportedQueueFamilyIndices (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
107 {
108         const deUint32          numTotalFamilyIndices   = getNumQueueFamilyIndices(vki, physicalDevice);
109         vector<deUint32>        supportedFamilyIndices;
110
111         for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numTotalFamilyIndices; ++queueFamilyNdx)
112         {
113                 if (vk::wsi::getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) == VK_TRUE)
114                         supportedFamilyIndices.push_back(queueFamilyNdx);
115         }
116
117         return supportedFamilyIndices;
118 }
119
120 deUint32 chooseQueueFamilyIndex (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface)
121 {
122         const vector<deUint32>  supportedFamilyIndices  = getSupportedQueueFamilyIndices(vki, physicalDevice, surface);
123
124         if (supportedFamilyIndices.empty())
125                 TCU_THROW(NotSupportedError, "Device doesn't support presentation");
126
127         return supportedFamilyIndices[0];
128 }
129
130 vk::Move<vk::VkDevice> createDeviceWithWsi (const vk::InstanceInterface&                vki,
131                                                                                         vk::VkPhysicalDevice                            physicalDevice,
132                                                                                         const Extensions&                                       supportedExtensions,
133                                                                                         const deUint32                                          queueFamilyIndex,
134                                                                                         bool                                                            requiresDisplayTiming,
135                                                                                         const vk::VkAllocationCallbacks*        pAllocator = DE_NULL)
136 {
137         const float                                                     queuePriorities[]       = { 1.0f };
138         const vk::VkDeviceQueueCreateInfo       queueInfos[]            =
139         {
140                 {
141                         vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
142                         DE_NULL,
143                         (vk::VkDeviceQueueCreateFlags)0,
144                         queueFamilyIndex,
145                         DE_LENGTH_OF_ARRAY(queuePriorities),
146                         &queuePriorities[0]
147                 }
148         };
149         const vk::VkPhysicalDeviceFeatures      features                = getDeviceNullFeatures();
150         const char* const                                       extensions[]    =
151         {
152                 "VK_KHR_swapchain",
153                 "VK_GOOGLE_display_timing"
154         };
155
156         const vk::VkDeviceCreateInfo            deviceParams    =
157         {
158                 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
159                 DE_NULL,
160                 (vk::VkDeviceCreateFlags)0,
161                 DE_LENGTH_OF_ARRAY(queueInfos),
162                 &queueInfos[0],
163                 0u,
164                 DE_NULL,
165                 requiresDisplayTiming ? 2u : 1u,
166                 DE_ARRAY_BEGIN(extensions),
167                 &features
168         };
169
170         for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(extensions); ++ndx)
171         {
172                 if (!isExtensionSupported(supportedExtensions, vk::RequiredExtension(extensions[ndx])))
173                         TCU_THROW(NotSupportedError, (string(extensions[ndx]) + " is not supported").c_str());
174         }
175
176         return createDevice(vki, physicalDevice, &deviceParams, pAllocator);
177 }
178
179 de::MovePtr<vk::wsi::Display> createDisplay (const vk::Platform&        platform,
180                                                                                          const Extensions&              supportedExtensions,
181                                                                                          vk::wsi::Type                  wsiType)
182 {
183         try
184         {
185                 return de::MovePtr<vk::wsi::Display>(platform.createWsiDisplay(wsiType));
186         }
187         catch (const tcu::NotSupportedError& e)
188         {
189                 if (isExtensionSupported(supportedExtensions, vk::RequiredExtension(getExtensionName(wsiType))))
190                 {
191                         // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
192                         // must support creating native display & window for that WSI type.
193                         throw tcu::TestError(e.getMessage());
194                 }
195                 else
196                         throw;
197         }
198 }
199
200 de::MovePtr<vk::wsi::Window> createWindow (const vk::wsi::Display& display, const Maybe<UVec2>& initialSize)
201 {
202         try
203         {
204                 return de::MovePtr<vk::wsi::Window>(display.createWindow(initialSize));
205         }
206         catch (const tcu::NotSupportedError& e)
207         {
208                 // See createDisplay - assuming that wsi::Display was supported platform port
209                 // should also support creating a window.
210                 throw tcu::TestError(e.getMessage());
211         }
212 }
213
214 void initSemaphores (const vk::DeviceInterface&         vkd,
215                                          vk::VkDevice                                   device,
216                                          std::vector<vk::VkSemaphore>&  semaphores)
217 {
218         for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
219                 semaphores[ndx] = createSemaphore(vkd, device).disown();
220 }
221
222 void deinitSemaphores (const vk::DeviceInterface&       vkd,
223                                          vk::VkDevice                                   device,
224                                          std::vector<vk::VkSemaphore>&  semaphores)
225 {
226         for (size_t ndx = 0; ndx < semaphores.size(); ndx++)
227         {
228                 if (semaphores[ndx] != (vk::VkSemaphore)0)
229                         vkd.destroySemaphore(device, semaphores[ndx], DE_NULL);
230
231                 semaphores[ndx] = (vk::VkSemaphore)0;
232         }
233
234         semaphores.clear();
235 }
236
237 void initFences (const vk::DeviceInterface&     vkd,
238                                  vk::VkDevice                           device,
239                                  std::vector<vk::VkFence>&      fences)
240 {
241         for (size_t ndx = 0; ndx < fences.size(); ndx++)
242                 fences[ndx] = createFence(vkd, device).disown();
243 }
244
245 void deinitFences (const vk::DeviceInterface&   vkd,
246                                    vk::VkDevice                                 device,
247                                    std::vector<vk::VkFence>&    fences)
248 {
249         for (size_t ndx = 0; ndx < fences.size(); ndx++)
250         {
251                 if (fences[ndx] != (vk::VkFence)0)
252                         vkd.destroyFence(device, fences[ndx], DE_NULL);
253
254                 fences[ndx] = (vk::VkFence)0;
255         }
256
257         fences.clear();
258 }
259
260 void cmdRenderFrame (const vk::DeviceInterface& vkd,
261                                          vk::VkCommandBuffer            commandBuffer,
262                                          vk::VkPipelineLayout           pipelineLayout,
263                                          vk::VkPipeline                         pipeline,
264                                          size_t                                         frameNdx,
265                                          deUint32                                       quadCount)
266 {
267         const deUint32  frameNdxValue   = (deUint32)frameNdx;
268
269         vkd.cmdPushConstants(commandBuffer, pipelineLayout, vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u, &frameNdxValue);
270         vkd.cmdBindPipeline(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
271         vkd.cmdDraw(commandBuffer, quadCount * 6u, 1u, 0u, 0u);
272 }
273
274 vk::Move<vk::VkCommandBuffer> createCommandBuffer (const vk::DeviceInterface&   vkd,
275                                                                                                    vk::VkDevice                                 device,
276                                                                                                    vk::VkCommandPool                    commandPool,
277                                                                                                    vk::VkPipelineLayout                 pipelineLayout,
278                                                                                                    vk::VkRenderPass                             renderPass,
279                                                                                                    vk::VkFramebuffer                    framebuffer,
280                                                                                                    vk::VkPipeline                               pipeline,
281                                                                                                    size_t                                               frameNdx,
282                                                                                                    deUint32                                             quadCount,
283                                                                                                    deUint32                                             imageWidth,
284                                                                                                    deUint32                                             imageHeight)
285 {
286         const vk::VkCommandBufferAllocateInfo allocateInfo =
287         {
288                 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
289                 DE_NULL,
290
291                 commandPool,
292                 vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY,
293                 1
294         };
295         const vk::VkCommandBufferBeginInfo      beginInfo               =
296         {
297                 vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
298                 DE_NULL,
299                 0u,
300                 DE_NULL
301         };
302
303         vk::Move<vk::VkCommandBuffer>   commandBuffer   (vk::allocateCommandBuffer(vkd, device, &allocateInfo));
304         VK_CHECK(vkd.beginCommandBuffer(*commandBuffer, &beginInfo));
305
306         {
307                 const vk::VkClearValue                  clearValue                      = vk::makeClearValueColorF32(0.25f, 0.50f, 0.75f, 1.00f);
308                 const vk::VkRenderPassBeginInfo renderPassBeginInfo     =
309                 {
310                         vk::VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
311                         DE_NULL,
312
313                         renderPass,
314                         framebuffer,
315
316                         {
317                                 { (deInt32)0, (deInt32)0 },
318                                 { imageWidth, imageHeight }
319                         },
320                         1u,
321                         &clearValue
322                 };
323                 vkd.cmdBeginRenderPass(*commandBuffer, &renderPassBeginInfo, vk::VK_SUBPASS_CONTENTS_INLINE);
324         }
325
326         cmdRenderFrame(vkd, *commandBuffer, pipelineLayout, pipeline, frameNdx, quadCount);
327
328         vkd.cmdEndRenderPass(*commandBuffer);
329
330         VK_CHECK(vkd.endCommandBuffer(*commandBuffer));
331         return commandBuffer;
332 }
333
334 void deinitCommandBuffers (const vk::DeviceInterface&                   vkd,
335                                                    vk::VkDevice                                                 device,
336                                                    vk::VkCommandPool                                    commandPool,
337                                                    std::vector<vk::VkCommandBuffer>&    commandBuffers)
338 {
339         for (size_t ndx = 0; ndx < commandBuffers.size(); ndx++)
340         {
341                 if (commandBuffers[ndx] != (vk::VkCommandBuffer)0)
342                         vkd.freeCommandBuffers(device, commandPool, 1u,  &commandBuffers[ndx]);
343
344                 commandBuffers[ndx] = (vk::VkCommandBuffer)0;
345         }
346
347         commandBuffers.clear();
348 }
349
350 vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface&       vkd,
351                                                                                            vk::VkDevice                                 device,
352                                                                                            deUint32                                             queueFamilyIndex)
353 {
354         const vk::VkCommandPoolCreateInfo createInfo =
355         {
356                 vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
357                 DE_NULL,
358                 0u,
359                 queueFamilyIndex
360         };
361
362         return vk::createCommandPool(vkd, device, &createInfo);
363 }
364
365 vk::Move<vk::VkFramebuffer>     createFramebuffer (const vk::DeviceInterface&   vkd,
366                                                                                            vk::VkDevice                                 device,
367                                                                                            vk::VkRenderPass                             renderPass,
368                                                                                            vk::VkImageView                              imageView,
369                                                                                            deUint32                                             width,
370                                                                                            deUint32                                             height)
371 {
372         const vk::VkFramebufferCreateInfo createInfo =
373         {
374                 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
375                 DE_NULL,
376
377                 0u,
378                 renderPass,
379                 1u,
380                 &imageView,
381                 width,
382                 height,
383                 1u
384         };
385
386         return vk::createFramebuffer(vkd, device, &createInfo);
387 }
388
389 void initFramebuffers (const vk::DeviceInterface&               vkd,
390                                            vk::VkDevice                                         device,
391                                            vk::VkRenderPass                                     renderPass,
392                                            std::vector<vk::VkImageView>         imageViews,
393                                            deUint32                                                     width,
394                                            deUint32                                                     height,
395                                            std::vector<vk::VkFramebuffer>&      framebuffers)
396 {
397         DE_ASSERT(framebuffers.size() == imageViews.size());
398
399         for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
400                 framebuffers[ndx] = createFramebuffer(vkd, device, renderPass, imageViews[ndx], width, height).disown();
401 }
402
403 void deinitFramebuffers (const vk::DeviceInterface&                     vkd,
404                                                  vk::VkDevice                                           device,
405                                                  std::vector<vk::VkFramebuffer>&        framebuffers)
406 {
407         for (size_t ndx = 0; ndx < framebuffers.size(); ndx++)
408         {
409                 if (framebuffers[ndx] != (vk::VkFramebuffer)0)
410                         vkd.destroyFramebuffer(device, framebuffers[ndx], DE_NULL);
411
412                 framebuffers[ndx] = (vk::VkFramebuffer)0;
413         }
414
415         framebuffers.clear();
416 }
417
418 vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface&   vkd,
419                                                                                    vk::VkDevice                                 device,
420                                                                                    vk::VkImage                                  image,
421                                                                                    vk::VkFormat                                 format)
422 {
423         const vk::VkImageViewCreateInfo createInfo =
424         {
425                 vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
426                 DE_NULL,
427
428                 0u,
429                 image,
430                 vk::VK_IMAGE_VIEW_TYPE_2D,
431                 format,
432                 vk::makeComponentMappingRGBA(),
433                 {
434                         vk::VK_IMAGE_ASPECT_COLOR_BIT,
435                         0u,
436                         1u,
437                         0u,
438                         1u
439                 }
440         };
441
442         return vk::createImageView(vkd, device, &createInfo, DE_NULL);
443 }
444
445 void initImageViews (const vk::DeviceInterface&                 vkd,
446                                          vk::VkDevice                                           device,
447                                          const std::vector<vk::VkImage>&        images,
448                                          vk::VkFormat                                           format,
449                                          std::vector<vk::VkImageView>&          imageViews)
450 {
451         DE_ASSERT(images.size() == imageViews.size());
452
453         for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
454                 imageViews[ndx] = createImageView(vkd, device, images[ndx], format).disown();
455 }
456
457 void deinitImageViews (const vk::DeviceInterface&               vkd,
458                                            vk::VkDevice                                         device,
459                                            std::vector<vk::VkImageView>&        imageViews)
460 {
461         for (size_t ndx = 0; ndx < imageViews.size(); ndx++)
462         {
463                 if (imageViews[ndx] != (vk::VkImageView)0)
464                         vkd.destroyImageView(device, imageViews[ndx], DE_NULL);
465
466                 imageViews[ndx] = (vk::VkImageView)0;
467         }
468
469         imageViews.clear();
470 }
471
472 vk::Move<vk::VkRenderPass> createRenderPass (const vk::DeviceInterface& vkd,
473                                                                                          vk::VkDevice                           device,
474                                                                                          vk::VkFormat                           format)
475 {
476         const vk::VkAttachmentDescription       attachments[]                   =
477         {
478                 {
479                         0u,
480                         format,
481                         vk::VK_SAMPLE_COUNT_1_BIT,
482
483                         vk::VK_ATTACHMENT_LOAD_OP_LOAD,
484                         vk::VK_ATTACHMENT_STORE_OP_STORE,
485
486                         vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,
487                         vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,
488
489                         vk::VK_IMAGE_LAYOUT_UNDEFINED,
490                         vk::VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
491                 }
492         };
493         const vk::VkAttachmentReference         colorAttachmentRefs[]   =
494         {
495                 {
496                         0u,
497                         vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
498                 }
499         };
500         const vk::VkSubpassDescription          subpasses[]                             =
501         {
502                 {
503                         0u,
504                         vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
505                         0u,
506                         DE_NULL,
507
508                         DE_LENGTH_OF_ARRAY(colorAttachmentRefs),
509                         colorAttachmentRefs,
510                         DE_NULL,
511
512                         DE_NULL,
513                         0u,
514                         DE_NULL
515                 }
516         };
517
518         const vk::VkRenderPassCreateInfo        createInfo                              =
519         {
520                 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
521                 DE_NULL,
522                 0u,
523
524                 DE_LENGTH_OF_ARRAY(attachments),
525                 attachments,
526
527                 DE_LENGTH_OF_ARRAY(subpasses),
528                 subpasses,
529
530                 0u,
531                 DE_NULL
532         };
533
534         return vk::createRenderPass(vkd, device, &createInfo);
535 }
536
537 vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface&     vkd,
538                                                                                  vk::VkDevice                           device,
539                                                                                  vk::VkRenderPass                       renderPass,
540                                                                                  vk::VkPipelineLayout           layout,
541                                                                                  vk::VkShaderModule                     vertexShaderModule,
542                                                                                  vk::VkShaderModule                     fragmentShaderModule,
543                                                                                  deUint32                                       width,
544                                                                                  deUint32                                       height)
545 {
546         const vk::VkSpecializationInfo                          shaderSpecialization    =
547         {
548                 0u,
549                 DE_NULL,
550                 0,
551                 DE_NULL
552         };
553         const vk::VkPipelineShaderStageCreateInfo               stages[]                        =
554         {
555                 {
556                         vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
557                         DE_NULL,
558                         0u,
559                         vk::VK_SHADER_STAGE_VERTEX_BIT,
560                         vertexShaderModule,
561                         "main",
562                         &shaderSpecialization
563                 },
564                 {
565                         vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
566                         DE_NULL,
567                         0u,
568                         vk::VK_SHADER_STAGE_FRAGMENT_BIT,
569                         fragmentShaderModule,
570                         "main",
571                         &shaderSpecialization
572                 }
573         };
574         const vk::VkPipelineVertexInputStateCreateInfo  vertexInputState        =
575         {
576                 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
577                 DE_NULL,
578                 0u,
579                 0u,
580                 DE_NULL,
581                 0u,
582                 DE_NULL
583         };
584         const vk::VkPipelineInputAssemblyStateCreateInfo        inputAssemblyState      =
585         {
586                 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
587                 DE_NULL,
588                 0u,
589                 vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
590                 VK_FALSE
591         };
592         const vk::VkViewport viewports[] =
593         {
594                 {
595                         0.0f, 0.0f,
596                         (float)width, (float)height,
597                         0.0f, 1.0f
598                 }
599         };
600         const vk::VkRect2D scissors[] =
601         {
602                 {
603                         { 0u, 0u },
604                         { width, height }
605                 }
606         };
607         const vk::VkPipelineViewportStateCreateInfo                     viewportState           =
608         {
609                 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
610                 DE_NULL,
611                 0u,
612
613                 DE_LENGTH_OF_ARRAY(viewports),
614                 viewports,
615                 DE_LENGTH_OF_ARRAY(scissors),
616                 scissors
617         };
618         const vk::VkPipelineRasterizationStateCreateInfo        rasterizationState      =
619         {
620                 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
621                 DE_NULL,
622                 0u,
623                 VK_TRUE,
624                 VK_FALSE,
625                 vk::VK_POLYGON_MODE_FILL,
626                 vk::VK_CULL_MODE_NONE,
627                 vk::VK_FRONT_FACE_CLOCKWISE,
628                 VK_FALSE,
629                 0.0f,
630                 0.0f,
631                 0.0f,
632                 1.0f
633         };
634         const vk::VkSampleMask                                                          sampleMask                      = ~0u;
635         const vk::VkPipelineMultisampleStateCreateInfo          multisampleState        =
636         {
637                 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
638                 DE_NULL,
639                 0u,
640                 vk::VK_SAMPLE_COUNT_1_BIT,
641                 VK_FALSE,
642                 0.0f,
643                 &sampleMask,
644                 VK_FALSE,
645                 VK_FALSE
646         };
647         const vk::VkPipelineDepthStencilStateCreateInfo depthStencilState               =
648         {
649                 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
650                 DE_NULL,
651                 0u,
652                 DE_FALSE,
653                 DE_FALSE,
654                 vk::VK_COMPARE_OP_ALWAYS,
655                 DE_FALSE,
656                 DE_FALSE,
657                 {
658                         vk::VK_STENCIL_OP_KEEP,
659                         vk::VK_STENCIL_OP_KEEP,
660                         vk::VK_STENCIL_OP_KEEP,
661                         vk::VK_COMPARE_OP_ALWAYS,
662                         0u,
663                         0u,
664                         0u,
665                 },
666                 {
667                         vk::VK_STENCIL_OP_KEEP,
668                         vk::VK_STENCIL_OP_KEEP,
669                         vk::VK_STENCIL_OP_KEEP,
670                         vk::VK_COMPARE_OP_ALWAYS,
671                         0u,
672                         0u,
673                         0u,
674                 },
675                 0.0f,
676                 1.0f
677         };
678         const vk::VkPipelineColorBlendAttachmentState   attachmentBlendState                    =
679         {
680                 VK_FALSE,
681                 vk::VK_BLEND_FACTOR_ONE,
682                 vk::VK_BLEND_FACTOR_ZERO,
683                 vk::VK_BLEND_OP_ADD,
684                 vk::VK_BLEND_FACTOR_ONE,
685                 vk::VK_BLEND_FACTOR_ZERO,
686                 vk::VK_BLEND_OP_ADD,
687                 (vk::VK_COLOR_COMPONENT_R_BIT|
688                  vk::VK_COLOR_COMPONENT_G_BIT|
689                  vk::VK_COLOR_COMPONENT_B_BIT|
690                  vk::VK_COLOR_COMPONENT_A_BIT),
691         };
692         const vk::VkPipelineColorBlendStateCreateInfo   blendState                              =
693         {
694                 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
695                 DE_NULL,
696                 0u,
697                 DE_FALSE,
698                 vk::VK_LOGIC_OP_COPY,
699                 1u,
700                 &attachmentBlendState,
701                 { 0.0f, 0.0f, 0.0f, 0.0f }
702         };
703         const vk::VkPipelineDynamicStateCreateInfo                      dynamicState            =
704         {
705                 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
706                 DE_NULL,
707                 0u,
708
709                 0u,
710                 DE_NULL
711         };
712         const vk::VkGraphicsPipelineCreateInfo                          createInfo                      =
713         {
714                 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
715                 DE_NULL,
716                 0u,
717
718                 DE_LENGTH_OF_ARRAY(stages),
719                 stages,
720                 &vertexInputState,
721                 &inputAssemblyState,
722                 DE_NULL,
723                 &viewportState,
724                 &rasterizationState,
725                 &multisampleState,
726                 &depthStencilState,
727                 &blendState,
728                 &dynamicState,
729                 layout,
730                 renderPass,
731                 0u,
732                 DE_NULL,
733                 0u
734         };
735
736         return vk::createGraphicsPipeline(vkd, device, DE_NULL,  &createInfo);
737 }
738
739 vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vkd,
740                                                                                                          vk::VkDevice                           device)
741 {
742         const vk::VkPushConstantRange                   pushConstants[] =
743         {
744                 {
745                         vk::VK_SHADER_STAGE_FRAGMENT_BIT,
746                         0u,
747                         4u
748                 }
749         };
750         const vk::VkPipelineLayoutCreateInfo    createInfo      =
751         {
752                 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
753                 DE_NULL,
754                 0u,
755
756                 0u,
757                 DE_NULL,
758
759                 DE_LENGTH_OF_ARRAY(pushConstants),
760                 pushConstants
761         };
762
763         return vk::createPipelineLayout(vkd, device, &createInfo);
764 }
765
766 struct TestConfig
767 {
768         vk::wsi::Type                   wsiType;
769         bool                                    useDisplayTiming;
770         vk::VkPresentModeKHR    presentMode;
771 };
772
773 class DisplayTimingTestInstance : public TestInstance
774 {
775 public:
776                                                                                                 DisplayTimingTestInstance       (Context& context, const TestConfig& testConfig);
777                                                                                                 ~DisplayTimingTestInstance      (void);
778
779         tcu::TestStatus                                                         iterate                                         (void);
780
781 private:
782         const bool                                                              m_useDisplayTiming;
783         const deUint32                                                  m_quadCount;
784         const vk::PlatformInterface&                    m_vkp;
785         const Extensions                                                m_instanceExtensions;
786         const vk::Unique<vk::VkInstance>                m_instance;
787         const vk::InstanceDriver                                m_vki;
788         const vk::VkPhysicalDevice                              m_physicalDevice;
789         const de::UniquePtr<vk::wsi::Display>   m_nativeDisplay;
790         const de::UniquePtr<vk::wsi::Window>    m_nativeWindow;
791         const vk::Unique<vk::VkSurfaceKHR>              m_surface;
792
793         const deUint32                                                  m_queueFamilyIndex;
794         const Extensions                                                m_deviceExtensions;
795         const vk::Unique<vk::VkDevice>                  m_device;
796         const vk::DeviceDriver                                  m_vkd;
797         const vk::VkQueue                                               m_queue;
798
799         const vk::Unique<vk::VkCommandPool>             m_commandPool;
800         const vk::Unique<vk::VkShaderModule>    m_vertexShaderModule;
801         const vk::Unique<vk::VkShaderModule>    m_fragmentShaderModule;
802         const vk::Unique<vk::VkPipelineLayout>  m_pipelineLayout;
803
804         const vk::VkSurfaceCapabilitiesKHR              m_surfaceProperties;
805         const vector<vk::VkSurfaceFormatKHR>    m_surfaceFormats;
806         const vector<vk::VkPresentModeKHR>              m_presentModes;
807
808         tcu::ResultCollector                                    m_resultCollector;
809
810         vk::Move<vk::VkSwapchainKHR>                    m_swapchain;
811         std::vector<vk::VkImage>                                m_swapchainImages;
812
813         vk::Move<vk::VkRenderPass>                              m_renderPass;
814         vk::Move<vk::VkPipeline>                                m_pipeline;
815
816         std::vector<vk::VkImageView>                    m_swapchainImageViews;
817         std::vector<vk::VkFramebuffer>                  m_framebuffers;
818         std::vector<vk::VkCommandBuffer>                m_commandBuffers;
819         std::vector<vk::VkSemaphore>                    m_acquireSemaphores;
820         std::vector<vk::VkSemaphore>                    m_renderSemaphores;
821         std::vector<vk::VkFence>                                m_fences;
822
823         vk::VkSemaphore                                                 m_freeAcquireSemaphore;
824         vk::VkSemaphore                                                 m_freeRenderSemaphore;
825
826         vk::VkSwapchainCreateInfoKHR                    m_swapchainConfig;
827
828         const size_t                                                    m_frameCount;
829         size_t                                                                  m_frameNdx;
830
831         const size_t                                                    m_maxOutOfDateCount;
832         size_t                                                                  m_outOfDateCount;
833
834         std::map<deUint32, deUint64>                    m_queuePresentTimes;
835
836     vk::VkRefreshCycleDurationGOOGLE            m_rcDuration;
837         deUint64                                                                m_refreshDurationMultiplier;
838         deUint64                                                                m_targetIPD;
839         deUint64                                                                m_prevDesiredPresentTime;
840         deUint32                                                                m_nextPresentID;
841         deUint32                                                                m_ignoreThruPresentID;
842         bool                                                                    m_ExpectImage80Late;
843
844         void                                                                    initSwapchainResources          (void);
845         void                                                                    deinitSwapchainResources        (void);
846         void                                                                    render                                          (void);
847 };
848
849 vk::VkSwapchainCreateInfoKHR createSwapchainConfig (vk::VkSurfaceKHR                                            surface,
850                                                                                                         deUint32                                                                queueFamilyIndex,
851                                                                                                         const vk::VkSurfaceCapabilitiesKHR&             properties,
852                                                                                                         const vector<vk::VkSurfaceFormatKHR>&   formats,
853                                                                                                         const vector<vk::VkPresentModeKHR>&             presentModes,
854                                                                                                         vk::VkPresentModeKHR                                    presentMode)
855 {
856         const deUint32                          imageLayers             = 1u;
857         const vk::VkImageUsageFlags     imageUsage              = properties.supportedUsageFlags;
858         const vk::VkBool32                      clipped                 = VK_FALSE;
859
860         const deUint32                          imageWidth              = (properties.currentExtent.width != 0xFFFFFFFFu)
861                                                                                                         ? properties.currentExtent.width
862                                                                                                         : de::min(1024u, properties.minImageExtent.width + ((properties.maxImageExtent.width - properties.minImageExtent.width) / 2));
863         const deUint32                          imageHeight             = (properties.currentExtent.height != 0xFFFFFFFFu)
864                                                                                                         ? properties.currentExtent.height
865                                                                                                         : de::min(1024u, properties.minImageExtent.height + ((properties.maxImageExtent.height - properties.minImageExtent.height) / 2));
866         const vk::VkExtent2D            imageSize               = { imageWidth, imageHeight };
867
868         {
869                 size_t presentModeNdx;
870
871                 for (presentModeNdx = 0; presentModeNdx < presentModes.size(); presentModeNdx++)
872                 {
873                         if (presentModes[presentModeNdx] == presentMode)
874                                 break;
875                 }
876
877                 if (presentModeNdx == presentModes.size())
878                         TCU_THROW(NotSupportedError, "Present mode not supported");
879         }
880
881         // Pick the first supported transform, alpha, and format:
882         vk::VkSurfaceTransformFlagsKHR transform;
883         for (transform = 1u; transform <= properties.supportedTransforms; transform = transform << 1u)
884         {
885                 if ((properties.supportedTransforms & transform) != 0)
886                         break;
887     }
888
889         vk::VkCompositeAlphaFlagsKHR alpha;
890         for (alpha = 1u; alpha <= properties.supportedCompositeAlpha; alpha = alpha << 1u)
891         {
892                 if ((alpha & properties.supportedCompositeAlpha) != 0)
893                         break;
894         }
895
896         {
897                 const vk::VkSurfaceTransformFlagBitsKHR preTransform    = (vk::VkSurfaceTransformFlagBitsKHR)transform;
898                 const vk::VkCompositeAlphaFlagBitsKHR   compositeAlpha  = (vk::VkCompositeAlphaFlagBitsKHR)alpha;
899                 const vk::VkFormat                                              imageFormat             = formats[0].format;
900                 const vk::VkColorSpaceKHR                               imageColorSpace = formats[0].colorSpace;
901                 const vk::VkSwapchainCreateInfoKHR              createInfo              =
902                 {
903                         vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
904                         DE_NULL,
905                         0u,
906                         surface,
907                         properties.minImageCount,
908                         imageFormat,
909                         imageColorSpace,
910                         imageSize,
911                         imageLayers,
912                         imageUsage,
913                         vk::VK_SHARING_MODE_EXCLUSIVE,
914                         1u,
915                         &queueFamilyIndex,
916                         preTransform,
917                         compositeAlpha,
918                         presentMode,
919                         clipped,
920                         (vk::VkSwapchainKHR)0
921                 };
922
923                 return createInfo;
924         }
925 }
926
927 DisplayTimingTestInstance::DisplayTimingTestInstance (Context& context, const TestConfig& testConfig)
928         : TestInstance                          (context)
929         , m_useDisplayTiming            (testConfig.useDisplayTiming)
930         , m_quadCount                           (16u)
931         , m_vkp                                         (context.getPlatformInterface())
932         , m_instanceExtensions          (vk::enumerateInstanceExtensionProperties(m_vkp, DE_NULL))
933         , m_instance                            (createInstanceWithWsi(m_vkp, m_instanceExtensions, testConfig.wsiType))
934         , m_vki                                         (m_vkp, *m_instance)
935         , m_physicalDevice                      (vk::chooseDevice(m_vki, *m_instance, context.getTestContext().getCommandLine()))
936         , m_nativeDisplay                       (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), m_instanceExtensions, testConfig.wsiType))
937         , m_nativeWindow                        (createWindow(*m_nativeDisplay, tcu::nothing<UVec2>()))
938         , m_surface                                     (vk::wsi::createSurface(m_vki, *m_instance, testConfig.wsiType, *m_nativeDisplay, *m_nativeWindow))
939
940         , m_queueFamilyIndex            (chooseQueueFamilyIndex(m_vki, m_physicalDevice, *m_surface))
941         , m_deviceExtensions            (vk::enumerateDeviceExtensionProperties(m_vki, m_physicalDevice, DE_NULL))
942         , m_device                                      (createDeviceWithWsi(m_vki, m_physicalDevice, m_deviceExtensions, m_queueFamilyIndex, testConfig.useDisplayTiming))
943         , m_vkd                                         (m_vki, *m_device)
944         , m_queue                                       (getDeviceQueue(m_vkd, *m_device, m_queueFamilyIndex, 0u))
945
946         , m_commandPool                         (createCommandPool(m_vkd, *m_device, m_queueFamilyIndex))
947         , m_vertexShaderModule          (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-vert"), 0u))
948         , m_fragmentShaderModule        (vk::createShaderModule(m_vkd, *m_device, context.getBinaryCollection().get("quad-frag"), 0u))
949         , m_pipelineLayout                      (createPipelineLayout(m_vkd, *m_device))
950
951         , m_surfaceProperties           (vk::wsi::getPhysicalDeviceSurfaceCapabilities(m_vki, m_physicalDevice, *m_surface))
952         , m_surfaceFormats                      (vk::wsi::getPhysicalDeviceSurfaceFormats(m_vki, m_physicalDevice, *m_surface))
953         , m_presentModes                        (vk::wsi::getPhysicalDeviceSurfacePresentModes(m_vki, m_physicalDevice, *m_surface))
954
955         , m_freeAcquireSemaphore        ((vk::VkSemaphore)0)
956         , m_freeRenderSemaphore         ((vk::VkSemaphore)0)
957
958         , m_swapchainConfig                     (createSwapchainConfig(*m_surface, m_queueFamilyIndex, m_surfaceProperties, m_surfaceFormats, m_presentModes, testConfig.presentMode))
959
960         , m_frameCount                          (60u * 5u)
961         , m_frameNdx                            (0u)
962
963         , m_maxOutOfDateCount           (20u)
964         , m_outOfDateCount                      (0u)
965         , m_ExpectImage80Late           (false)
966 {
967         {
968                 const tcu::ScopedLogSection surfaceInfo (m_context.getTestContext().getLog(), "SurfaceCapabilities", "SurfaceCapabilities");
969                 m_context.getTestContext().getLog() << TestLog::Message << m_surfaceProperties << TestLog::EndMessage;
970         }
971 }
972
973 DisplayTimingTestInstance::~DisplayTimingTestInstance (void)
974 {
975         deinitSwapchainResources();
976 }
977
978 void DisplayTimingTestInstance::initSwapchainResources (void)
979 {
980         const size_t            fenceCount      = 6;
981         const deUint32          imageWidth      = m_swapchainConfig.imageExtent.width;
982         const deUint32          imageHeight     = m_swapchainConfig.imageExtent.height;
983         const vk::VkFormat      imageFormat     = m_swapchainConfig.imageFormat;
984
985         m_swapchain                             = vk::createSwapchainKHR(m_vkd, *m_device, &m_swapchainConfig);
986         m_swapchainImages               = vk::wsi::getSwapchainImages(m_vkd, *m_device, *m_swapchain);
987
988         m_renderPass                    = createRenderPass(m_vkd, *m_device, imageFormat);
989         m_pipeline                              = createPipeline(m_vkd, *m_device, *m_renderPass, *m_pipelineLayout, *m_vertexShaderModule, *m_fragmentShaderModule, imageWidth, imageHeight);
990
991         m_swapchainImageViews   = std::vector<vk::VkImageView>(m_swapchainImages.size(), (vk::VkImageView)0);
992         m_framebuffers                  = std::vector<vk::VkFramebuffer>(m_swapchainImages.size(), (vk::VkFramebuffer)0);
993         m_acquireSemaphores             = std::vector<vk::VkSemaphore>(m_swapchainImages.size(), (vk::VkSemaphore)0);
994         m_renderSemaphores              = std::vector<vk::VkSemaphore>(m_swapchainImages.size(), (vk::VkSemaphore)0);
995
996         m_fences                                = std::vector<vk::VkFence>(fenceCount, (vk::VkFence)0);
997         m_commandBuffers                = std::vector<vk::VkCommandBuffer>(m_fences.size(), (vk::VkCommandBuffer)0);
998
999         m_freeAcquireSemaphore  = (vk::VkSemaphore)0;
1000         m_freeRenderSemaphore   = (vk::VkSemaphore)0;
1001
1002         m_freeAcquireSemaphore  = createSemaphore(m_vkd, *m_device).disown();
1003         m_freeRenderSemaphore   = createSemaphore(m_vkd, *m_device).disown();
1004
1005         initImageViews(m_vkd, *m_device, m_swapchainImages, imageFormat, m_swapchainImageViews);
1006         initFramebuffers(m_vkd, *m_device, *m_renderPass, m_swapchainImageViews, imageWidth, imageHeight, m_framebuffers);
1007         initSemaphores(m_vkd, *m_device, m_acquireSemaphores);
1008         initSemaphores(m_vkd, *m_device, m_renderSemaphores);
1009
1010         initFences(m_vkd, *m_device, m_fences);
1011
1012         if (m_useDisplayTiming)
1013         {
1014                 // This portion should do interesting bits
1015                 m_queuePresentTimes                     = std::map<deUint32, deUint64>();
1016
1017                 m_vkd.getRefreshCycleDurationGOOGLE(*m_device, *m_swapchain, &m_rcDuration);
1018
1019                 m_refreshDurationMultiplier     = 1u;
1020                 m_targetIPD                                     = m_rcDuration.refreshDuration;
1021                 m_prevDesiredPresentTime        = 0u;
1022                 m_nextPresentID                         = 0u;
1023                 m_ignoreThruPresentID           = 0u;
1024         }
1025 }
1026
1027 void DisplayTimingTestInstance::deinitSwapchainResources (void)
1028 {
1029         VK_CHECK(m_vkd.queueWaitIdle(m_queue));
1030
1031         if (m_freeAcquireSemaphore != (vk::VkSemaphore)0)
1032         {
1033                 m_vkd.destroySemaphore(*m_device, m_freeAcquireSemaphore, DE_NULL);
1034                 m_freeAcquireSemaphore = (vk::VkSemaphore)0;
1035         }
1036
1037         if (m_freeRenderSemaphore != (vk::VkSemaphore)0)
1038         {
1039                 m_vkd.destroySemaphore(*m_device, m_freeRenderSemaphore, DE_NULL);
1040                 m_freeRenderSemaphore = (vk::VkSemaphore)0;
1041         }
1042
1043         deinitSemaphores(m_vkd, *m_device, m_acquireSemaphores);
1044         deinitSemaphores(m_vkd, *m_device, m_renderSemaphores);
1045         deinitFences(m_vkd, *m_device, m_fences);
1046         deinitCommandBuffers(m_vkd, *m_device, *m_commandPool, m_commandBuffers);
1047         deinitFramebuffers(m_vkd, *m_device, m_framebuffers);
1048         deinitImageViews(m_vkd, *m_device, m_swapchainImageViews);
1049
1050         m_swapchainImages.clear();
1051
1052         m_swapchain             = vk::Move<vk::VkSwapchainKHR>();
1053         m_renderPass    = vk::Move<vk::VkRenderPass>();
1054         m_pipeline              = vk::Move<vk::VkPipeline>();
1055
1056 }
1057
1058 vector<vk::VkPastPresentationTimingGOOGLE> getPastPresentationTiming (const vk::DeviceInterface&        vkd,
1059                                                                                                                                           vk::VkDevice                                  device,
1060                                                                                                                                           vk::VkSwapchainKHR                    swapchain)
1061 {
1062         vector<vk::VkPastPresentationTimingGOOGLE>      pastPresentationTimings;
1063         deUint32                                                                        numPastPresentationTimings = 0;
1064
1065         vkd.getPastPresentationTimingGOOGLE(device, swapchain, &numPastPresentationTimings, DE_NULL);
1066
1067         pastPresentationTimings.resize(numPastPresentationTimings);
1068
1069         if (numPastPresentationTimings > 0)
1070                 vkd.getPastPresentationTimingGOOGLE(device, swapchain, &numPastPresentationTimings, &pastPresentationTimings[0]);
1071
1072         return pastPresentationTimings;
1073 }
1074
1075 void DisplayTimingTestInstance::render (void)
1076 {
1077         const deUint64          foreverNs               = ~0x0ull;
1078         const vk::VkFence       fence                   = m_fences[m_frameNdx % m_fences.size()];
1079         const deUint32          width                   = m_swapchainConfig.imageExtent.width;
1080         const deUint32          height                  = m_swapchainConfig.imageExtent.height;
1081         tcu::TestLog&           log                             = m_context.getTestContext().getLog();
1082
1083         // Throttle execution
1084         if (m_frameNdx >= m_fences.size())
1085         {
1086                 VK_CHECK(m_vkd.waitForFences(*m_device, 1u, &fence, VK_TRUE, foreverNs));
1087                 VK_CHECK(m_vkd.resetFences(*m_device, 1u, &fence));
1088
1089                 m_vkd.freeCommandBuffers(*m_device, *m_commandPool, 1u, &m_commandBuffers[m_frameNdx % m_commandBuffers.size()]);
1090                 m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = (vk::VkCommandBuffer)0;
1091         }
1092
1093         vk::VkSemaphore         currentAcquireSemaphore = m_freeAcquireSemaphore;
1094         vk::VkSemaphore         currentRenderSemaphore  = m_freeRenderSemaphore;
1095         deUint32                        imageIndex;
1096
1097         // Acquire next image
1098         VK_CHECK(m_vkd.acquireNextImageKHR(*m_device, *m_swapchain, foreverNs, currentAcquireSemaphore, (vk::VkFence)0, &imageIndex));
1099
1100         // Create command buffer
1101         m_commandBuffers[m_frameNdx % m_commandBuffers.size()] = createCommandBuffer(m_vkd, *m_device, *m_commandPool, *m_pipelineLayout, *m_renderPass, m_framebuffers[imageIndex], *m_pipeline, m_frameNdx, m_quadCount, width, height).disown();
1102
1103         // Obtain timing data from previous frames
1104         if (m_useDisplayTiming)
1105         {
1106                 const vector<vk::VkPastPresentationTimingGOOGLE>        pastPresentationTimings (getPastPresentationTiming(m_vkd, *m_device, *m_swapchain));
1107                 bool                                                                                            isEarly                                 = false;
1108                 bool                                                                                            isLate                                  = false;
1109
1110                 for (size_t pastPresentationInfoNdx = 0 ; pastPresentationInfoNdx < pastPresentationTimings.size(); pastPresentationInfoNdx++)
1111                 {
1112                         if (m_queuePresentTimes[pastPresentationTimings[pastPresentationInfoNdx].presentID] > pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime)
1113                         {
1114                                 m_resultCollector.fail("Image with PresentID " + de::toString(pastPresentationTimings[pastPresentationInfoNdx].presentID) + "was displayed before vkQueuePresentKHR was called.");
1115                         }
1116                         if (!m_ignoreThruPresentID)
1117                         {
1118                                 // This is the first time that we've received an
1119                                 // actualPresentTime for this swapchain.  In order to not
1120                                 // perceive these early frames as "late", we need to sync-up
1121                                 // our future desiredPresentTime's with the
1122                                 // actualPresentTime(s) that we're receiving now.
1123                                 const deInt64   multiple        = m_nextPresentID - pastPresentationTimings.back().presentID;
1124
1125                                 m_prevDesiredPresentTime        = pastPresentationTimings.back().actualPresentTime + (multiple * m_targetIPD);
1126                                 m_ignoreThruPresentID           = pastPresentationTimings[pastPresentationInfoNdx].presentID + 1;
1127                         }
1128                         else if (pastPresentationTimings[pastPresentationInfoNdx].presentID > m_ignoreThruPresentID)
1129                         {
1130                                 if (pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime > (pastPresentationTimings[pastPresentationInfoNdx].desiredPresentTime + m_rcDuration.refreshDuration + MILLISECOND))
1131                                 {
1132                                         const deUint64 actual   = pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime;
1133                                         const deUint64 desired  = pastPresentationTimings[pastPresentationInfoNdx].desiredPresentTime;
1134                                         const deUint64 rdur             = m_rcDuration.refreshDuration;
1135                                         const deUint64 diff1    = actual - (desired + rdur);
1136                                         const deUint64 diff2    = actual - desired;
1137
1138                                         log << TestLog::Message << "Image PresentID " << pastPresentationTimings[pastPresentationInfoNdx].presentID << " was " << diff1 << " nsec late." << TestLog::EndMessage;
1139                                         if (m_ExpectImage80Late && (pastPresentationTimings[pastPresentationInfoNdx].presentID == 80))
1140                                         {
1141                                                 if (diff1 > (SECOND / 2))
1142                                                         log << TestLog::Message << "\tNote: Image PresentID 80 was expected to be late by approximately 1 second." << TestLog::EndMessage;
1143                                                 else
1144                                                         m_resultCollector.fail("Image PresentID 80 was not late by approximately 1 second, as expected.");
1145                                         }
1146                                         log << TestLog::Message << "\t\t   actualPresentTime = " << actual << " nsec" << TestLog::EndMessage;
1147                                         log << TestLog::Message << "\t\t - desiredPresentTime= " << desired << " nsec" << TestLog::EndMessage;
1148                                         log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
1149                                         log << TestLog::Message << "\t\t   diff              =       " << diff2 << " nsec" << TestLog::EndMessage;
1150                                         log << TestLog::Message << "\t\t - refreshDuration   =       "    << rdur << " nsec" << TestLog::EndMessage;
1151                                         log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
1152                                         log << TestLog::Message << "\t\t   diff              =        " << diff1 << " nsec" << TestLog::EndMessage;
1153
1154                                         isLate = true;
1155                                 }
1156                                 else if ((pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime > pastPresentationTimings[pastPresentationInfoNdx].earliestPresentTime) &&
1157                                                  (pastPresentationTimings[pastPresentationInfoNdx].presentMargin > (2 * MILLISECOND)))
1158                                 {
1159                                         const deUint64 actual   = pastPresentationTimings[pastPresentationInfoNdx].actualPresentTime;
1160                                         const deUint64 earliest = pastPresentationTimings[pastPresentationInfoNdx].earliestPresentTime;
1161                                         const deUint64 diff             = actual - earliest;
1162
1163                                         log << TestLog::Message << "Image PresentID " << pastPresentationTimings[pastPresentationInfoNdx].presentID << " can be presented " << diff << " nsec earlier." << TestLog::EndMessage;
1164                                         log << TestLog::Message << "\t\t   actualPresentTime = " << actual << " nsec" << TestLog::EndMessage;
1165                                         log << TestLog::Message << "\t\t -earliestPresentTime= " << earliest << " nsec" << TestLog::EndMessage;
1166                                         log << TestLog::Message << "\t\t =========================================" << TestLog::EndMessage;
1167                                         log << TestLog::Message << "\t\t   diff              =        " << diff << " nsec" << TestLog::EndMessage;
1168
1169                                         isEarly = true;
1170                                 }
1171                         }
1172                 }
1173                 // Preference is given to late presents over early presents:
1174                 if (isLate)
1175                 {
1176                         // Demonstrate how to slow down the frame rate if a frame is late,
1177                         // but don't go too slow (for test time reasons):
1178                         if (++m_refreshDurationMultiplier > 2)
1179                                 m_refreshDurationMultiplier = 2;
1180                         else
1181                                 log << TestLog::Message << "Increasing multiplier." << TestLog::EndMessage;
1182                 }
1183                 else if (isEarly)
1184                 {
1185                         // Demonstrate how to speed up the frame rate if a frame is early,
1186                         // but don't let the multiplier hit zero:
1187                         if (--m_refreshDurationMultiplier == 0)
1188                                 m_refreshDurationMultiplier = 1;
1189                         else
1190                                 log << TestLog::Message << "Decreasing multiplier." << TestLog::EndMessage;
1191                 }
1192                 m_targetIPD = m_rcDuration.refreshDuration * m_refreshDurationMultiplier;
1193         }
1194
1195         // Submit command buffer
1196         {
1197                 const vk::VkPipelineStageFlags  dstStageMask    = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1198                 const vk::VkSubmitInfo                  submitInfo              =
1199                 {
1200                         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
1201                         DE_NULL,
1202                         1u,
1203                         &currentAcquireSemaphore,
1204                         &dstStageMask,
1205                         1u,
1206                         &m_commandBuffers[m_frameNdx % m_commandBuffers.size()],
1207                         1u,
1208                         &currentRenderSemaphore
1209                 };
1210
1211                 VK_CHECK(m_vkd.queueSubmit(m_queue, 1u, &submitInfo, fence));
1212         }
1213
1214         // Present frame
1215         if (m_useDisplayTiming)
1216         {
1217                 // This portion should do interesting bits
1218
1219                 // Initially, mirror reference to move things along
1220                 vk::VkResult result;
1221                 vk::VkPresentTimeGOOGLE presentTime =
1222                 {
1223                         ++m_nextPresentID,
1224                         m_prevDesiredPresentTime
1225                 };
1226                 // Record the current time, to record as the time of the vkQueuePresentKHR() call:
1227                 const deUint64 curtimeNano = deGetMicroseconds() * 1000;
1228                 m_queuePresentTimes[m_nextPresentID] = curtimeNano;
1229
1230                 deUint64 desiredPresentTime = 0u;
1231                 if (m_prevDesiredPresentTime == 0)
1232                 {
1233                         // This must be the first present for this swapchain.  Find out the
1234                         // current time, as the basis for desiredPresentTime:
1235                         if (curtimeNano != 0)
1236                         {
1237                                 presentTime.desiredPresentTime = curtimeNano;
1238                                 presentTime.desiredPresentTime += (m_targetIPD / 2);
1239                         }
1240                         else
1241                         {
1242                                 // Since we didn't find out the current time, don't give a
1243                                 // desiredPresentTime:
1244                                 presentTime.desiredPresentTime = 0;
1245                         }
1246                 }
1247                 else
1248                 {
1249                         desiredPresentTime = m_prevDesiredPresentTime + m_targetIPD;
1250                         if ((presentTime.presentID == 80) && (m_swapchainConfig.presentMode != vk::VK_PRESENT_MODE_MAILBOX_KHR))
1251                         {
1252                                 // Test if desiredPresentTime is 1 second earlier (i.e. before the previous image could have been presented)
1253                                 presentTime.desiredPresentTime -= SECOND;
1254                                 m_ExpectImage80Late = true;
1255                         }
1256                 }
1257                 m_prevDesiredPresentTime = desiredPresentTime;
1258
1259                 const vk::VkPresentTimesInfoGOOGLE presentTimesInfo =
1260                 {
1261                         vk::VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,
1262                         DE_NULL,
1263                         1u,
1264                         &presentTime
1265                 };
1266                 const vk::VkPresentInfoKHR presentInfo =
1267                 {
1268                         vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1269                         &presentTimesInfo,
1270                         1u,
1271                         &currentRenderSemaphore,
1272                         1u,
1273                         &*m_swapchain,
1274                         &imageIndex,
1275                         &result
1276                 };
1277
1278                 VK_CHECK(m_vkd.queuePresentKHR(m_queue, &presentInfo));
1279                 VK_CHECK(result);
1280         }
1281         else
1282         {
1283                 vk::VkResult result;
1284                 const vk::VkPresentInfoKHR presentInfo =
1285                 {
1286                         vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1287                         DE_NULL,
1288                         1u,
1289                         &currentRenderSemaphore,
1290                         1u,
1291                         &*m_swapchain,
1292                         &imageIndex,
1293                         &result
1294                 };
1295
1296                 VK_CHECK(m_vkd.queuePresentKHR(m_queue, &presentInfo));
1297                 VK_CHECK(result);
1298         }
1299
1300         {
1301                 m_freeAcquireSemaphore = m_acquireSemaphores[imageIndex];
1302                 m_acquireSemaphores[imageIndex] = currentAcquireSemaphore;
1303
1304                 m_freeRenderSemaphore = m_renderSemaphores[imageIndex];
1305                 m_renderSemaphores[imageIndex] = currentRenderSemaphore;
1306         }
1307 }
1308
1309 tcu::TestStatus DisplayTimingTestInstance::iterate (void)
1310 {
1311         // Initialize swapchain specific resources
1312         // Render test
1313         try
1314         {
1315                 if (m_frameNdx == 0)
1316                 {
1317                         if (m_outOfDateCount == 0)
1318                                 m_context.getTestContext().getLog() << tcu::TestLog::Message << "Swapchain: " << m_swapchainConfig << tcu::TestLog::EndMessage;
1319
1320                         initSwapchainResources();
1321                 }
1322
1323                 render();
1324         }
1325         catch (const vk::Error& error)
1326         {
1327                 if (error.getError() == vk::VK_ERROR_OUT_OF_DATE_KHR)
1328                 {
1329                         if (m_outOfDateCount < m_maxOutOfDateCount)
1330                         {
1331                                 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date. Recreating resources." << TestLog::EndMessage;
1332                                 deinitSwapchainResources();
1333                                 m_frameNdx = 0;
1334                                 m_outOfDateCount++;
1335
1336                                 return tcu::TestStatus::incomplete();
1337                         }
1338                         else
1339                         {
1340                                 m_context.getTestContext().getLog() << TestLog::Message << "Frame " << m_frameNdx << ": Swapchain out of date." << TestLog::EndMessage;
1341                                 m_resultCollector.fail("Received too many VK_ERROR_OUT_OF_DATE_KHR errors. Received " + de::toString(m_outOfDateCount) + ", max " + de::toString(m_maxOutOfDateCount));
1342                         }
1343                 }
1344                 else
1345                 {
1346                         m_resultCollector.fail(error.what());
1347                 }
1348
1349                 deinitSwapchainResources();
1350
1351                 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1352         }
1353
1354         m_frameNdx++;
1355
1356         if (m_frameNdx >= m_frameCount)
1357         {
1358                 deinitSwapchainResources();
1359
1360                 return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage());
1361         }
1362         else
1363                 return tcu::TestStatus::incomplete();
1364 }
1365
1366 struct Programs
1367 {
1368         static void init (vk::SourceCollections& dst, TestConfig)
1369         {
1370                 dst.glslSources.add("quad-vert") << glu::VertexSource(
1371                         "#version 450\n"
1372                         "out gl_PerVertex {\n"
1373                         "\tvec4 gl_Position;\n"
1374                         "};\n"
1375                         "highp float;\n"
1376                         "void main (void) {\n"
1377                         "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n"
1378                         "\t                   ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n"
1379                         "}\n");
1380                 dst.glslSources.add("quad-frag") << glu::FragmentSource(
1381                         "#version 310 es\n"
1382                         "layout(location = 0) out highp vec4 o_color;\n"
1383                         "layout(push_constant) uniform PushConstant {\n"
1384                         "\thighp uint frameNdx;\n"
1385                         "} pushConstants;\n"
1386                         "void main (void)\n"
1387                         "{\n"
1388                         "\thighp uint frameNdx = pushConstants.frameNdx;\n"
1389                         "\thighp uint x = frameNdx + uint(gl_FragCoord.x);\n"
1390                         "\thighp uint y = frameNdx + uint(gl_FragCoord.y);\n"
1391                         "\thighp uint r = 128u * bitfieldExtract(x, 0, 1)\n"
1392                         "\t             +  64u * bitfieldExtract(y, 1, 1)\n"
1393                         "\t             +  32u * bitfieldExtract(x, 3, 1);\n"
1394                         "\thighp uint g = 128u * bitfieldExtract(y, 0, 1)\n"
1395                         "\t             +  64u * bitfieldExtract(x, 2, 1)\n"
1396                         "\t             +  32u * bitfieldExtract(y, 3, 1);\n"
1397                         "\thighp uint b = 128u * bitfieldExtract(x, 1, 1)\n"
1398                         "\t             +  64u * bitfieldExtract(y, 2, 1)\n"
1399                         "\t             +  32u * bitfieldExtract(x, 4, 1);\n"
1400                         "\to_color = vec4(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0, 1.0);\n"
1401                         "}\n");
1402         }
1403 };
1404
1405 } // anonymous
1406
1407 void createDisplayTimingTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
1408 {
1409         const struct
1410         {
1411                 vk::VkPresentModeKHR    mode;
1412                 const char*                             name;
1413         } presentModes[] =
1414         {
1415                 { vk::VK_PRESENT_MODE_FIFO_KHR,                 "fifo"                  },
1416                 { vk::VK_PRESENT_MODE_FIFO_RELAXED_KHR, "fifo_relaxed"  },
1417                 { vk::VK_PRESENT_MODE_IMMEDIATE_KHR,    "immediate"             },
1418                 { vk::VK_PRESENT_MODE_MAILBOX_KHR,              "mailbox"               },
1419         };
1420
1421         for (size_t presentModeNdx = 0; presentModeNdx < DE_LENGTH_OF_ARRAY(presentModes); presentModeNdx++)
1422         {
1423                 de::MovePtr<tcu::TestCaseGroup> presentModeGroup        (new tcu::TestCaseGroup(testGroup->getTestContext(), presentModes[presentModeNdx].name, presentModes[presentModeNdx].name));
1424
1425                 for (size_t ref = 0; ref < 2; ref++)
1426                 {
1427                         const bool                                              isReference     = (ref == 0);
1428                         const char* const                               name            = isReference ? "reference" : "display_timing";
1429                         TestConfig                                              config;
1430
1431                         config.wsiType                                  = wsiType;
1432                         config.useDisplayTiming                 = !isReference;
1433                         config.presentMode                              = presentModes[presentModeNdx].mode;
1434
1435                         presentModeGroup->addChild(new vkt::InstanceFactory1<DisplayTimingTestInstance, TestConfig, Programs>(testGroup->getTestContext(), tcu::NODETYPE_SELF_VALIDATE, name, name, Programs(), config));
1436                 }
1437
1438                 testGroup->addChild(presentModeGroup.release());
1439         }
1440 }
1441
1442 } // wsi
1443 } // vkt