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