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