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