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