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