xref: /aosp_15_r20/external/deqp/external/vulkancts/modules/vulkan/wsi/vktWsiPresentIdWaitTests.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Valve Corporation.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tests for the present id and present wait extensions.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktWsiPresentIdWaitTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktCustomInstancesDevices.hpp"
28 #include "vktNativeObjectsUtil.hpp"
29 
30 #include "vkQueryUtil.hpp"
31 #include "vkDeviceUtil.hpp"
32 #include "vkWsiUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkRefUtil.hpp"
36 
37 #include "tcuTestContext.hpp"
38 #include "tcuPlatform.hpp"
39 #include "tcuCommandLine.hpp"
40 #include "tcuTestLog.hpp"
41 
42 #include "deDefs.hpp"
43 
44 #include <vector>
45 #include <string>
46 #include <set>
47 #include <sstream>
48 #include <chrono>
49 #include <algorithm>
50 #include <utility>
51 #include <limits>
52 
53 using std::set;
54 using std::string;
55 using std::vector;
56 
57 namespace vkt
58 {
59 namespace wsi
60 {
61 
62 namespace
63 {
64 
65 // Handy time constants in nanoseconds.
66 constexpr uint64_t k10sec = 10000000000ull;
67 constexpr uint64_t k1sec  = 1000000000ull;
68 
69 // 100 milliseconds, way above 1/50 seconds for systems with 50Hz ticks.
70 // This should also take into account possible measure deviations due to the machine being loaded.
71 constexpr uint64_t kMargin = 100000000ull;
72 
73 using TimeoutRange = std::pair<int64_t, int64_t>;
74 
75 // Calculate acceptable timeout range based on indicated timeout and taking into account kMargin.
calcTimeoutRange(uint64_t timeout)76 TimeoutRange calcTimeoutRange(uint64_t timeout)
77 {
78     constexpr auto kUnsignedMax = std::numeric_limits<uint64_t>::max();
79     constexpr auto kSignedMax   = static_cast<uint64_t>(std::numeric_limits<int64_t>::max());
80 
81     // Watch for over- and under-flows.
82     uint64_t timeoutMin = ((timeout < kMargin) ? 0ull : (timeout - kMargin));
83     uint64_t timeoutMax = ((kUnsignedMax - timeout < kMargin) ? kUnsignedMax : timeout + kMargin);
84 
85     // Make sure casting is safe.
86     timeoutMin = de::min(kSignedMax, timeoutMin);
87     timeoutMax = de::min(kSignedMax, timeoutMax);
88 
89     return TimeoutRange(static_cast<int64_t>(timeoutMin), static_cast<int64_t>(timeoutMax));
90 }
91 
92 class PresentIdWaitInstance : public TestInstance
93 {
94 public:
PresentIdWaitInstance(Context & context,vk::wsi::Type wsiType)95     PresentIdWaitInstance(Context &context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType)
96     {
97     }
~PresentIdWaitInstance(void)98     virtual ~PresentIdWaitInstance(void)
99     {
100     }
101 
102     virtual tcu::TestStatus iterate(void);
103 
104     virtual tcu::TestStatus run(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkQueue queue,
105                                 vk::VkCommandPool commandPool, vk::VkSwapchainKHR swapchain, size_t swapchainSize,
106                                 const vk::wsi::WsiTriangleRenderer &renderer) = 0;
107 
108     // Subclasses will need to implement a static method like this one indicating which extensions they need.
requiredDeviceExts(void)109     static vector<const char *> requiredDeviceExts(void)
110     {
111         return vector<const char *>();
112     }
113 
114     // Subclasses will also need to implement this nonstatic method returning the same information as above.
115     virtual vector<const char *> getRequiredDeviceExts(void) = 0;
116 
117 protected:
118     vk::wsi::Type m_wsiType;
119 };
120 
getRequiredInstanceExtensions(vk::wsi::Type wsiType)121 vector<const char *> getRequiredInstanceExtensions(vk::wsi::Type wsiType)
122 {
123     vector<const char *> extensions;
124     extensions.push_back("VK_KHR_surface");
125     extensions.push_back(getExtensionName(wsiType));
126     if (isDisplaySurface(wsiType))
127         extensions.push_back("VK_KHR_display");
128     return extensions;
129 }
130 
createInstanceWithWsi(Context & context,vk::wsi::Type wsiType,const vk::VkAllocationCallbacks * pAllocator=nullptr)131 CustomInstance createInstanceWithWsi(Context &context, vk::wsi::Type wsiType,
132                                      const vk::VkAllocationCallbacks *pAllocator = nullptr)
133 {
134     const auto version            = context.getUsedApiVersion();
135     const auto requiredExtensions = getRequiredInstanceExtensions(wsiType);
136 
137     vector<string> requestedExtensions;
138     for (const auto &extensionName : requiredExtensions)
139     {
140         if (!vk::isCoreInstanceExtension(version, extensionName))
141             requestedExtensions.push_back(extensionName);
142     }
143 
144     return vkt::createCustomInstanceWithExtensions(context, requestedExtensions, pAllocator);
145 }
146 
147 struct InstanceHelper
148 {
149     const vector<vk::VkExtensionProperties> supportedExtensions;
150     CustomInstance instance;
151     const vk::InstanceDriver &vki;
152 
InstanceHelpervkt::wsi::__anon85122c350111::InstanceHelper153     InstanceHelper(Context &context, vk::wsi::Type wsiType, const vk::VkAllocationCallbacks *pAllocator = nullptr)
154         : supportedExtensions(enumerateInstanceExtensionProperties(context.getPlatformInterface(), nullptr))
155         , instance(createInstanceWithWsi(context, wsiType, pAllocator))
156         , vki(instance.getDriver())
157     {
158     }
159 };
160 
getMandatoryDeviceExtensions()161 vector<const char *> getMandatoryDeviceExtensions()
162 {
163     vector<const char *> mandatoryExtensions;
164     mandatoryExtensions.push_back("VK_KHR_swapchain");
165     return mandatoryExtensions;
166 }
167 
createDeviceWithWsi(const vk::PlatformInterface & vkp,vk::VkInstance instance,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,const vector<const char * > & extraExtensions,const uint32_t queueFamilyIndex,bool validationEnabled,const vk::VkAllocationCallbacks * pAllocator=nullptr)168 vk::Move<vk::VkDevice> createDeviceWithWsi(const vk::PlatformInterface &vkp, vk::VkInstance instance,
169                                            const vk::InstanceInterface &vki, vk::VkPhysicalDevice physicalDevice,
170                                            const vector<const char *> &extraExtensions, const uint32_t queueFamilyIndex,
171                                            bool validationEnabled,
172                                            const vk::VkAllocationCallbacks *pAllocator = nullptr)
173 {
174     const float queuePriorities[]                  = {1.0f};
175     const vk::VkDeviceQueueCreateInfo queueInfos[] = {{vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, nullptr,
176                                                        (vk::VkDeviceQueueCreateFlags)0, queueFamilyIndex,
177                                                        DE_LENGTH_OF_ARRAY(queuePriorities), &queuePriorities[0]}};
178     vk::VkPhysicalDeviceFeatures features;
179     std::vector<const char *> extensions = extraExtensions;
180     const auto mandatoryExtensions       = getMandatoryDeviceExtensions();
181 
182     for (const auto &ext : mandatoryExtensions)
183         extensions.push_back(ext);
184 
185     deMemset(&features, 0, sizeof(features));
186 
187     vk::VkPhysicalDeviceFeatures2 physicalDeviceFeatures2{vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, DE_NULL,
188                                                           features};
189 
190     vk::VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures = {
191         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR, DE_NULL, true};
192     vk::VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures = {
193         vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR, DE_NULL, true};
194 
195     void *pNext = DE_NULL;
196     for (size_t i = 0; i < extraExtensions.size(); ++i)
197     {
198         if (strcmp(extraExtensions[i], "VK_KHR_present_id") == 0)
199         {
200             presentIdFeatures.pNext = pNext;
201             pNext                   = &presentIdFeatures;
202         }
203         else if (strcmp(extraExtensions[i], "VK_KHR_present_wait") == 0)
204         {
205             presentWaitFeatures.pNext = pNext;
206             pNext                     = &presentWaitFeatures;
207         }
208     }
209     physicalDeviceFeatures2.pNext = pNext;
210 
211     const vk::VkDeviceCreateInfo deviceParams = {vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
212                                                  pNext ? &physicalDeviceFeatures2 : DE_NULL,
213                                                  (vk::VkDeviceCreateFlags)0,
214                                                  DE_LENGTH_OF_ARRAY(queueInfos),
215                                                  &queueInfos[0],
216                                                  0u,                                       // enabledLayerCount
217                                                  nullptr,                                  // ppEnabledLayerNames
218                                                  static_cast<uint32_t>(extensions.size()), // enabledExtensionCount
219                                                  extensions.data(),                        // ppEnabledExtensionNames
220                                                  pNext ? DE_NULL : &features};
221 
222     return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
223 }
224 
225 struct DeviceHelper
226 {
227     const vk::VkPhysicalDevice physicalDevice;
228     const uint32_t queueFamilyIndex;
229     const vk::Unique<vk::VkDevice> device;
230     const vk::DeviceDriver vkd;
231     const vk::VkQueue queue;
232 
DeviceHelpervkt::wsi::__anon85122c350111::DeviceHelper233     DeviceHelper(Context &context, const vk::InstanceInterface &vki, vk::VkInstance instance,
234                  const vector<vk::VkSurfaceKHR> &surfaces, const vector<const char *> &extraExtensions,
235                  const vk::VkAllocationCallbacks *pAllocator = nullptr)
236         : physicalDevice(chooseDevice(vki, instance, context.getTestContext().getCommandLine()))
237         , queueFamilyIndex(vk::wsi::chooseQueueFamilyIndex(vki, physicalDevice, surfaces))
238         , device(createDeviceWithWsi(context.getPlatformInterface(), instance, vki, physicalDevice, extraExtensions,
239                                      queueFamilyIndex, context.getTestContext().getCommandLine().isValidationEnabled(),
240                                      pAllocator))
241         , vkd(context.getPlatformInterface(), instance, *device, context.getUsedApiVersion(),
242               context.getTestContext().getCommandLine())
243         , queue(getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
244     {
245     }
246 };
247 
getBasicSwapchainParameters(vk::wsi::Type wsiType,const vk::InstanceInterface & vki,vk::VkPhysicalDevice physicalDevice,vk::VkSurfaceKHR surface,const tcu::UVec2 & desiredSize,uint32_t desiredImageCount)248 vk::VkSwapchainCreateInfoKHR getBasicSwapchainParameters(vk::wsi::Type wsiType, const vk::InstanceInterface &vki,
249                                                          vk::VkPhysicalDevice physicalDevice, vk::VkSurfaceKHR surface,
250                                                          const tcu::UVec2 &desiredSize, uint32_t desiredImageCount)
251 {
252     const vk::VkSurfaceCapabilitiesKHR capabilities =
253         vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki, physicalDevice, surface);
254     const vector<vk::VkSurfaceFormatKHR> formats =
255         vk::wsi::getPhysicalDeviceSurfaceFormats(vki, physicalDevice, surface);
256     const vk::wsi::PlatformProperties &platformProperties = vk::wsi::getPlatformProperties(wsiType);
257     const vk::VkSurfaceTransformFlagBitsKHR transform =
258         (capabilities.supportedTransforms & vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) ?
259             vk::VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR :
260             capabilities.currentTransform;
261     const vk::VkSwapchainCreateInfoKHR parameters = {
262         vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
263         nullptr,
264         (vk::VkSwapchainCreateFlagsKHR)0,
265         surface,
266         de::clamp(desiredImageCount, capabilities.minImageCount,
267                   capabilities.maxImageCount > 0 ? capabilities.maxImageCount :
268                                                    capabilities.minImageCount + desiredImageCount),
269         formats[0].format,
270         formats[0].colorSpace,
271         (platformProperties.swapchainExtent == vk::wsi::PlatformProperties::SWAPCHAIN_EXTENT_MUST_MATCH_WINDOW_SIZE ?
272              capabilities.currentExtent :
273              vk::makeExtent2D(desiredSize.x(), desiredSize.y())),
274         1u, // imageArrayLayers
275         vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
276         vk::VK_SHARING_MODE_EXCLUSIVE,
277         0u,
278         nullptr,
279         transform,
280         vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
281         vk::VK_PRESENT_MODE_FIFO_KHR,
282         VK_FALSE,             // clipped
283         (vk::VkSwapchainKHR)0 // oldSwapchain
284     };
285 
286     return parameters;
287 }
288 
289 using CommandBufferSp = de::SharedPtr<vk::Unique<vk::VkCommandBuffer>>;
290 using FenceSp         = de::SharedPtr<vk::Unique<vk::VkFence>>;
291 using SemaphoreSp     = de::SharedPtr<vk::Unique<vk::VkSemaphore>>;
292 
createFences(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numFences)293 vector<FenceSp> createFences(const vk::DeviceInterface &vkd, const vk::VkDevice device, size_t numFences)
294 {
295     vector<FenceSp> fences(numFences);
296 
297     for (size_t ndx = 0; ndx < numFences; ++ndx)
298         fences[ndx] = FenceSp(new vk::Unique<vk::VkFence>(createFence(vkd, device, vk::VK_FENCE_CREATE_SIGNALED_BIT)));
299 
300     return fences;
301 }
302 
createSemaphores(const vk::DeviceInterface & vkd,const vk::VkDevice device,size_t numSemaphores)303 vector<SemaphoreSp> createSemaphores(const vk::DeviceInterface &vkd, const vk::VkDevice device, size_t numSemaphores)
304 {
305     vector<SemaphoreSp> semaphores(numSemaphores);
306 
307     for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
308         semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
309 
310     return semaphores;
311 }
312 
allocateCommandBuffers(const vk::DeviceInterface & vkd,const vk::VkDevice device,const vk::VkCommandPool commandPool,const vk::VkCommandBufferLevel level,const size_t numCommandBuffers)313 vector<CommandBufferSp> allocateCommandBuffers(const vk::DeviceInterface &vkd, const vk::VkDevice device,
314                                                const vk::VkCommandPool commandPool,
315                                                const vk::VkCommandBufferLevel level, const size_t numCommandBuffers)
316 {
317     vector<CommandBufferSp> buffers(numCommandBuffers);
318 
319     for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
320         buffers[ndx] = CommandBufferSp(
321             new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
322 
323     return buffers;
324 }
325 
326 class FrameStreamObjects
327 {
328 public:
329     struct FrameObjects
330     {
331         const vk::VkFence &renderCompleteFence;
332         const vk::VkSemaphore &renderCompleteSemaphore;
333         const vk::VkSemaphore &imageAvailableSemaphore;
334         const vk::VkCommandBuffer &commandBuffer;
335     };
336 
FrameStreamObjects(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkCommandPool cmdPool,size_t maxQueuedFrames)337     FrameStreamObjects(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkCommandPool cmdPool,
338                        size_t maxQueuedFrames)
339         : renderingCompleteFences(createFences(vkd, device, maxQueuedFrames))
340         , renderingCompleteSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
341         , imageAvailableSemaphores(createSemaphores(vkd, device, maxQueuedFrames))
342         , commandBuffers(
343               allocateCommandBuffers(vkd, device, cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, maxQueuedFrames))
344         , m_maxQueuedFrames(maxQueuedFrames)
345         , m_nextFrame(0u)
346     {
347     }
348 
frameNumber(void) const349     size_t frameNumber(void) const
350     {
351         DE_ASSERT(m_nextFrame > 0u);
352         return m_nextFrame - 1u;
353     }
354 
newFrame()355     FrameObjects newFrame()
356     {
357         const size_t mod = m_nextFrame % m_maxQueuedFrames;
358         FrameObjects ret = {
359             **renderingCompleteFences[mod],
360             **renderingCompleteSemaphores[mod],
361             **imageAvailableSemaphores[mod],
362             **commandBuffers[mod],
363         };
364         ++m_nextFrame;
365         return ret;
366     }
367 
368 private:
369     const vector<FenceSp> renderingCompleteFences;
370     const vector<SemaphoreSp> renderingCompleteSemaphores;
371     const vector<SemaphoreSp> imageAvailableSemaphores;
372     const vector<CommandBufferSp> commandBuffers;
373 
374     const size_t m_maxQueuedFrames;
375     size_t m_nextFrame;
376 };
377 
iterate(void)378 tcu::TestStatus PresentIdWaitInstance::iterate(void)
379 {
380     const tcu::UVec2 desiredSize(256, 256);
381     const InstanceHelper instHelper(m_context, m_wsiType);
382     const NativeObjects native(m_context, instHelper.supportedExtensions, m_wsiType, 1u, tcu::just(desiredSize));
383     const vk::Unique<vk::VkSurfaceKHR> surface(createSurface(instHelper.vki, instHelper.instance, m_wsiType,
384                                                              native.getDisplay(), native.getWindow(),
385                                                              m_context.getTestContext().getCommandLine()));
386     const DeviceHelper devHelper(m_context, instHelper.vki, instHelper.instance,
387                                  vector<vk::VkSurfaceKHR>(1u, surface.get()), getRequiredDeviceExts());
388     const vk::DeviceInterface &vkd = devHelper.vkd;
389     const vk::VkDevice device      = *devHelper.device;
390     vk::SimpleAllocator allocator(vkd, device,
391                                   getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
392     const vk::VkSwapchainCreateInfoKHR swapchainInfo =
393         getBasicSwapchainParameters(m_wsiType, instHelper.vki, devHelper.physicalDevice, *surface, desiredSize, 2);
394     const vk::Unique<vk::VkSwapchainKHR> swapchain(vk::createSwapchainKHR(vkd, device, &swapchainInfo));
395     const vector<vk::VkImage> swapchainImages = vk::wsi::getSwapchainImages(vkd, device, *swapchain);
396     const vk::Unique<vk::VkCommandPool> commandPool(createCommandPool(
397         vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
398     const vk::wsi::WsiTriangleRenderer renderer(
399         vkd, device, allocator, m_context.getBinaryCollection(), false, swapchainImages, swapchainImages,
400         swapchainInfo.imageFormat, tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
401 
402     try
403     {
404         return run(vkd, device, devHelper.queue, commandPool.get(), swapchain.get(), swapchainImages.size(), renderer);
405     }
406     catch (...)
407     {
408         // Make sure device is idle before destroying resources
409         vkd.deviceWaitIdle(device);
410         throw;
411     }
412 
413     return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
414 }
415 
416 struct PresentParameters
417 {
418     tcu::Maybe<uint64_t> presentId;
419     tcu::Maybe<vk::VkResult> expectedResult;
420 };
421 
422 struct WaitParameters
423 {
424     uint64_t presentId;
425     uint64_t timeout; // Nanoseconds.
426     bool timeoutExpected;
427 };
428 
429 // This structure represents a set of present operations to be run followed by a set of wait operations to be run after them.
430 // When running the present operations, the present id can be provided, together with an optional expected result to be checked.
431 // When runing the wait operations, the present id must be provided together with a timeout and an indication of whether the operation is expected to time out or not.
432 struct PresentAndWaitOps
433 {
434     vector<PresentParameters> presentOps;
435     vector<WaitParameters> waitOps;
436 };
437 
438 // Parent class for VK_KHR_present_id and VK_KHR_present_wait simple tests.
439 class PresentIdWaitSimpleInstance : public PresentIdWaitInstance
440 {
441 public:
PresentIdWaitSimpleInstance(Context & context,vk::wsi::Type wsiType,const vector<PresentAndWaitOps> & sequence)442     PresentIdWaitSimpleInstance(Context &context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps> &sequence)
443         : PresentIdWaitInstance(context, wsiType)
444         , m_sequence(sequence)
445     {
446     }
447 
~PresentIdWaitSimpleInstance()448     virtual ~PresentIdWaitSimpleInstance()
449     {
450     }
451 
452     virtual tcu::TestStatus run(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkQueue queue,
453                                 vk::VkCommandPool commandPool, vk::VkSwapchainKHR swapchain, size_t swapchainSize,
454                                 const vk::wsi::WsiTriangleRenderer &renderer);
455 
456 protected:
457     const vector<PresentAndWaitOps> m_sequence;
458 };
459 
460 // Waits for the appropriate fences, acquires swapchain image, records frame and submits it to the given queue, signaling the appropriate frame semaphores.
461 // Returns the image index from the swapchain.
recordAndSubmitFrame(FrameStreamObjects::FrameObjects & frameObjects,const vk::wsi::WsiTriangleRenderer & triangleRenderer,const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkSwapchainKHR swapchain,size_t swapchainSize,vk::VkQueue queue,size_t frameNumber,tcu::TestLog & testLog)462 uint32_t recordAndSubmitFrame(FrameStreamObjects::FrameObjects &frameObjects,
463                               const vk::wsi::WsiTriangleRenderer &triangleRenderer, const vk::DeviceInterface &vkd,
464                               vk::VkDevice device, vk::VkSwapchainKHR swapchain, size_t swapchainSize,
465                               vk::VkQueue queue, size_t frameNumber, tcu::TestLog &testLog)
466 {
467     // Wait and reset the render complete fence to avoid having too many submitted frames.
468     VK_CHECK(vkd.waitForFences(device, 1u, &frameObjects.renderCompleteFence, VK_TRUE,
469                                std::numeric_limits<uint64_t>::max()));
470     VK_CHECK(vkd.resetFences(device, 1, &frameObjects.renderCompleteFence));
471 
472     // Acquire swapchain image.
473     uint32_t imageNdx = std::numeric_limits<uint32_t>::max();
474     const vk::VkResult acquireResult =
475         vkd.acquireNextImageKHR(device, swapchain, std::numeric_limits<uint64_t>::max(),
476                                 frameObjects.imageAvailableSemaphore, (vk::VkFence)0, &imageNdx);
477 
478     if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
479         testLog << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNumber
480                 << tcu::TestLog::EndMessage;
481     else
482         VK_CHECK(acquireResult);
483     TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainSize);
484 
485     // Submit frame to the queue.
486     const vk::VkPipelineStageFlags waitDstStage = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
487     const vk::VkSubmitInfo submitInfo           = {
488         vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
489         nullptr,
490         1u,
491         &frameObjects.imageAvailableSemaphore,
492         &waitDstStage,
493         1u,
494         &frameObjects.commandBuffer,
495         1u,
496         &frameObjects.renderCompleteSemaphore,
497     };
498 
499     triangleRenderer.recordFrame(frameObjects.commandBuffer, imageNdx, static_cast<uint32_t>(frameNumber));
500     VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
501 
502     return imageNdx;
503 }
504 
run(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::VkQueue queue,vk::VkCommandPool commandPool,vk::VkSwapchainKHR swapchain,size_t swapchainSize,const vk::wsi::WsiTriangleRenderer & renderer)505 tcu::TestStatus PresentIdWaitSimpleInstance::run(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::VkQueue queue,
506                                                  vk::VkCommandPool commandPool, vk::VkSwapchainKHR swapchain,
507                                                  size_t swapchainSize, const vk::wsi::WsiTriangleRenderer &renderer)
508 {
509     const size_t maxQueuedFrames = swapchainSize * 2;
510     FrameStreamObjects frameStreamObjects(vkd, device, commandPool, maxQueuedFrames);
511 
512     for (const auto &step : m_sequence)
513     {
514         for (const auto &presentOp : step.presentOps)
515         {
516             // Get objects for the next frame.
517             FrameStreamObjects::FrameObjects frameObjects = frameStreamObjects.newFrame();
518 
519             // Record and submit new frame.
520             uint32_t imageNdx =
521                 recordAndSubmitFrame(frameObjects, renderer, vkd, device, swapchain, swapchainSize, queue,
522                                      frameStreamObjects.frameNumber(), m_context.getTestContext().getLog());
523 
524             // Present rendered frame.
525             const vk::VkPresentIdKHR presentId = {
526                 vk::VK_STRUCTURE_TYPE_PRESENT_ID_KHR,                         // VkStructureType sType;
527                 nullptr,                                                      // const void* pNext;
528                 (presentOp.presentId ? 1u : 0u),                              // uint32_t swapchainCount;
529                 (presentOp.presentId ? &presentOp.presentId.get() : nullptr), // const uint64_t* pPresentIds;
530             };
531 
532             const vk::VkPresentInfoKHR presentInfo = {
533                 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
534                 (presentOp.presentId ? &presentId : nullptr),
535                 1u,
536                 &frameObjects.renderCompleteSemaphore,
537                 1u,
538                 &swapchain,
539                 &imageNdx,
540                 nullptr,
541             };
542 
543             vk::VkResult result = vkd.queuePresentKHR(queue, &presentInfo);
544 
545             if (presentOp.expectedResult)
546             {
547                 const vk::VkResult expected = presentOp.expectedResult.get();
548                 if ((expected == vk::VK_SUCCESS && result != vk::VK_SUCCESS && result != vk::VK_SUBOPTIMAL_KHR) ||
549                     (expected != vk::VK_SUCCESS && result != expected))
550                 {
551                     std::ostringstream msg;
552                     msg << "Got " << result << " while expecting " << expected << " after presenting with ";
553                     if (presentOp.presentId)
554                         msg << "id " << presentOp.presentId.get();
555                     else
556                         msg << "no id";
557                     TCU_FAIL(msg.str());
558                 }
559             }
560         }
561 
562         // Wait operations.
563         for (const auto &waitOp : step.waitOps)
564         {
565             auto before             = std::chrono::high_resolution_clock::now();
566             vk::VkResult waitResult = vkd.waitForPresentKHR(device, swapchain, waitOp.presentId, waitOp.timeout);
567             auto after              = std::chrono::high_resolution_clock::now();
568             auto diff               = std::chrono::nanoseconds(after - before).count();
569 
570             if (waitOp.timeoutExpected)
571             {
572                 if (waitResult != vk::VK_TIMEOUT)
573                 {
574                     std::ostringstream msg;
575                     msg << "Got " << waitResult << " while expecting a timeout in vkWaitForPresentKHR call";
576                     TCU_FAIL(msg.str());
577                 }
578 
579                 const auto timeoutRange = calcTimeoutRange(waitOp.timeout);
580 
581                 if (diff < timeoutRange.first || diff > timeoutRange.second)
582                 {
583                     std::ostringstream msg;
584                     msg << "vkWaitForPresentKHR waited for " << diff << " nanoseconds with a timeout of "
585                         << waitOp.timeout << " nanoseconds";
586                     TCU_FAIL(msg.str());
587                 }
588             }
589             else if (waitResult != vk::VK_SUCCESS)
590             {
591                 std::ostringstream msg;
592                 msg << "Got " << waitResult << " while expecting success in vkWaitForPresentKHR call";
593                 TCU_FAIL(msg.str());
594             }
595         }
596     }
597 
598     // Wait until device is idle.
599     VK_CHECK(vkd.deviceWaitIdle(device));
600 
601     return tcu::TestStatus::pass("Pass");
602 }
603 
604 // Parent class for VK_KHR_present_id simple tests.
605 class PresentIdInstance : public PresentIdWaitSimpleInstance
606 {
607 public:
PresentIdInstance(Context & context,vk::wsi::Type wsiType,const vector<PresentAndWaitOps> & sequence)608     PresentIdInstance(Context &context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps> &sequence)
609         : PresentIdWaitSimpleInstance(context, wsiType, sequence)
610     {
611     }
612 
~PresentIdInstance()613     virtual ~PresentIdInstance()
614     {
615     }
616 
requiredDeviceExts(void)617     static vector<const char *> requiredDeviceExts(void)
618     {
619         vector<const char *> extensions;
620         extensions.push_back("VK_KHR_present_id");
621         return extensions;
622     }
623 
getRequiredDeviceExts(void)624     virtual vector<const char *> getRequiredDeviceExts(void)
625     {
626         return requiredDeviceExts();
627     }
628 };
629 
630 // Parent class for VK_KHR_present_wait simple tests.
631 class PresentWaitInstance : public PresentIdWaitSimpleInstance
632 {
633 public:
PresentWaitInstance(Context & context,vk::wsi::Type wsiType,const vector<PresentAndWaitOps> & sequence)634     PresentWaitInstance(Context &context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps> &sequence)
635         : PresentIdWaitSimpleInstance(context, wsiType, sequence)
636     {
637     }
638 
~PresentWaitInstance()639     virtual ~PresentWaitInstance()
640     {
641     }
642 
requiredDeviceExts(void)643     static vector<const char *> requiredDeviceExts(void)
644     {
645         vector<const char *> extensions;
646         extensions.push_back("VK_KHR_present_id");
647         extensions.push_back("VK_KHR_present_wait");
648         return extensions;
649     }
650 
getRequiredDeviceExts(void)651     virtual vector<const char *> getRequiredDeviceExts(void)
652     {
653         return requiredDeviceExts();
654     }
655 };
656 
657 class PresentIdZeroInstance : public PresentIdInstance
658 {
659 public:
660     static const vector<PresentAndWaitOps> sequence;
661 
PresentIdZeroInstance(Context & context,vk::wsi::Type wsiType)662     PresentIdZeroInstance(Context &context, vk::wsi::Type wsiType) : PresentIdInstance(context, wsiType, sequence)
663     {
664     }
665 };
666 
667 const vector<PresentAndWaitOps> PresentIdZeroInstance::sequence = {
668     {
669         // PresentAndWaitOps
670         {
671             // presentOps vector
672             {tcu::just<uint64_t>(0), tcu::just(vk::VK_SUCCESS)},
673         },
674         {
675             // waitOps vector
676         },
677     },
678 };
679 
680 class PresentIdIncreasingInstance : public PresentIdInstance
681 {
682 public:
683     static const vector<PresentAndWaitOps> sequence;
684 
PresentIdIncreasingInstance(Context & context,vk::wsi::Type wsiType)685     PresentIdIncreasingInstance(Context &context, vk::wsi::Type wsiType) : PresentIdInstance(context, wsiType, sequence)
686     {
687     }
688 };
689 
690 const vector<PresentAndWaitOps> PresentIdIncreasingInstance::sequence = {
691     {
692         // PresentAndWaitOps
693         {
694             // presentOps vector
695             {tcu::just<uint64_t>(1), tcu::just(vk::VK_SUCCESS)},
696             {tcu::just(std::numeric_limits<uint64_t>::max()), tcu::just(vk::VK_SUCCESS)},
697         },
698         {
699             // waitOps vector
700         },
701     },
702 };
703 
704 class PresentIdInterleavedInstance : public PresentIdInstance
705 {
706 public:
707     static const vector<PresentAndWaitOps> sequence;
708 
PresentIdInterleavedInstance(Context & context,vk::wsi::Type wsiType)709     PresentIdInterleavedInstance(Context &context, vk::wsi::Type wsiType)
710         : PresentIdInstance(context, wsiType, sequence)
711     {
712     }
713 };
714 
715 const vector<PresentAndWaitOps> PresentIdInterleavedInstance::sequence = {
716     {
717         // PresentAndWaitOps
718         {
719             // presentOps vector
720             {tcu::just<uint64_t>(0), tcu::just(vk::VK_SUCCESS)},
721             {tcu::just<uint64_t>(1), tcu::just(vk::VK_SUCCESS)},
722             {tcu::Nothing, tcu::just(vk::VK_SUCCESS)},
723             {tcu::just(std::numeric_limits<uint64_t>::max()), tcu::just(vk::VK_SUCCESS)},
724         },
725         {
726             // waitOps vector
727         },
728     },
729 };
730 
731 class PresentWaitSingleFrameInstance : public PresentWaitInstance
732 {
733 public:
734     static const vector<PresentAndWaitOps> sequence;
735 
PresentWaitSingleFrameInstance(Context & context,vk::wsi::Type wsiType)736     PresentWaitSingleFrameInstance(Context &context, vk::wsi::Type wsiType)
737         : PresentWaitInstance(context, wsiType, sequence)
738     {
739     }
740 };
741 
742 const vector<PresentAndWaitOps> PresentWaitSingleFrameInstance::sequence = {
743     {
744         // PresentAndWaitOps
745         {
746             // presentOps vector
747             {tcu::just<uint64_t>(1), tcu::just(vk::VK_SUCCESS)},
748         },
749         {
750             // waitOps vector
751             {1ull, k10sec, false},
752         },
753     },
754 };
755 
756 class PresentWaitPastFrameInstance : public PresentWaitInstance
757 {
758 public:
759     static const vector<PresentAndWaitOps> sequence;
760 
PresentWaitPastFrameInstance(Context & context,vk::wsi::Type wsiType)761     PresentWaitPastFrameInstance(Context &context, vk::wsi::Type wsiType)
762         : PresentWaitInstance(context, wsiType, sequence)
763     {
764     }
765 };
766 
767 const vector<PresentAndWaitOps> PresentWaitPastFrameInstance::sequence = {
768     // Start with present id 1.
769     {
770         // PresentAndWaitOps
771         {
772             // presentOps vector
773             {tcu::just<uint64_t>(1), tcu::just(vk::VK_SUCCESS)},
774         },
775         {
776             // waitOps vector
777             {1ull, k10sec, false},
778             {1ull, 0ull, false},
779         },
780     },
781     // Then the maximum value. Both waiting for id 1 and the max id should work.
782     {
783         // PresentAndWaitOps
784         {
785             // presentOps vector
786             {tcu::just(std::numeric_limits<uint64_t>::max()), tcu::just(vk::VK_SUCCESS)},
787         },
788         {
789             // waitOps vector
790             {1ull, 0ull, false},
791             {1ull, k10sec, false},
792             {std::numeric_limits<uint64_t>::max(), k10sec, false},
793             {std::numeric_limits<uint64_t>::max(), 0ull, false},
794         },
795     },
796     // Submit some frames without id after having used the maximum value. This should also work.
797     {
798         // PresentAndWaitOps
799         {
800             // presentOps vector
801             {tcu::Nothing, tcu::just(vk::VK_SUCCESS)},
802             {tcu::just<uint64_t>(0), tcu::just(vk::VK_SUCCESS)},
803         },
804         {
805             // waitOps vector
806         },
807     },
808 };
809 
810 class PresentWaitNoFramesInstance : public PresentWaitInstance
811 {
812 public:
813     static const vector<PresentAndWaitOps> sequence;
814 
PresentWaitNoFramesInstance(Context & context,vk::wsi::Type wsiType)815     PresentWaitNoFramesInstance(Context &context, vk::wsi::Type wsiType)
816         : PresentWaitInstance(context, wsiType, sequence)
817     {
818     }
819 };
820 
821 const vector<PresentAndWaitOps> PresentWaitNoFramesInstance::sequence = {
822     {
823         // PresentAndWaitOps
824         {
825             // presentOps vector
826         },
827         {
828             // waitOps vector
829             {1ull, 0ull, true},
830             {1ull, k1sec, true},
831         },
832     },
833 };
834 
835 class PresentWaitNoFrameIdInstance : public PresentWaitInstance
836 {
837 public:
838     static const vector<PresentAndWaitOps> sequence;
839 
PresentWaitNoFrameIdInstance(Context & context,vk::wsi::Type wsiType)840     PresentWaitNoFrameIdInstance(Context &context, vk::wsi::Type wsiType)
841         : PresentWaitInstance(context, wsiType, sequence)
842     {
843     }
844 };
845 
846 const vector<PresentAndWaitOps> PresentWaitNoFrameIdInstance::sequence = {
847     {
848         // PresentAndWaitOps
849         {
850             // presentOps vector
851             {tcu::just<uint64_t>(0), tcu::just(vk::VK_SUCCESS)},
852         },
853         {
854             // waitOps vector
855             {1ull, 0ull, true},
856             {1ull, k1sec, true},
857         },
858     },
859     {
860         // PresentAndWaitOps
861         {
862             // presentOps vector
863             {tcu::Nothing, tcu::just(vk::VK_SUCCESS)},
864         },
865         {
866             // waitOps vector
867             {1ull, 0ull, true},
868             {1ull, k1sec, true},
869         },
870     },
871 };
872 
873 class PresentWaitFutureFrameInstance : public PresentWaitInstance
874 {
875 public:
876     static const vector<PresentAndWaitOps> sequence;
877 
PresentWaitFutureFrameInstance(Context & context,vk::wsi::Type wsiType)878     PresentWaitFutureFrameInstance(Context &context, vk::wsi::Type wsiType)
879         : PresentWaitInstance(context, wsiType, sequence)
880     {
881     }
882 };
883 
884 const vector<PresentAndWaitOps> PresentWaitFutureFrameInstance::sequence = {
885     {
886         // PresentAndWaitOps
887         {
888             // presentOps vector
889             {tcu::just<uint64_t>(1), tcu::just(vk::VK_SUCCESS)},
890         },
891         {
892             // waitOps vector
893             {std::numeric_limits<uint64_t>::max(), k1sec, true},
894             {std::numeric_limits<uint64_t>::max(), 0ull, true},
895             {2ull, 0ull, true},
896             {2ull, k1sec, true},
897         },
898     },
899 };
900 
901 // Instance with two windows and surfaces to check present ids are not mixed up.
902 class PresentWaitDualInstance : public TestInstance
903 {
904 public:
PresentWaitDualInstance(Context & context,vk::wsi::Type wsiType)905     PresentWaitDualInstance(Context &context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType)
906     {
907     }
~PresentWaitDualInstance(void)908     virtual ~PresentWaitDualInstance(void)
909     {
910     }
911 
912     virtual tcu::TestStatus iterate(void);
913 
requiredDeviceExts(void)914     static vector<const char *> requiredDeviceExts(void)
915     {
916         vector<const char *> extensions;
917         extensions.push_back("VK_KHR_present_id");
918         extensions.push_back("VK_KHR_present_wait");
919         return extensions;
920     }
921 
getRequiredDeviceExts(void)922     virtual vector<const char *> getRequiredDeviceExts(void)
923     {
924         return requiredDeviceExts();
925     }
926 
927 protected:
928     vk::wsi::Type m_wsiType;
929 };
930 
931 struct IdAndWait
932 {
933     uint64_t presentId;
934     bool wait;
935 };
936 
937 struct DualIdAndWait
938 {
939     IdAndWait idWait1;
940     IdAndWait idWait2;
941 };
942 
iterate(void)943 tcu::TestStatus PresentWaitDualInstance::iterate(void)
944 {
945     const vk::wsi::PlatformProperties &platformProperties = getPlatformProperties(m_wsiType);
946     if (2 > platformProperties.maxWindowsPerDisplay)
947         TCU_THROW(NotSupportedError, "Creating 2 windows not supported");
948 
949     const tcu::UVec2 desiredSize(256, 256);
950     const InstanceHelper instHelper(m_context, m_wsiType);
951     const NativeObjects native(m_context, instHelper.supportedExtensions, m_wsiType, 2u, tcu::just(desiredSize));
952     const vk::Unique<vk::VkSurfaceKHR> surface1(createSurface(instHelper.vki, instHelper.instance, m_wsiType,
953                                                               native.getDisplay(), native.getWindow(0),
954                                                               m_context.getTestContext().getCommandLine()));
955     const vk::Unique<vk::VkSurfaceKHR> surface2(createSurface(instHelper.vki, instHelper.instance, m_wsiType,
956                                                               native.getDisplay(), native.getWindow(1),
957                                                               m_context.getTestContext().getCommandLine()));
958     const DeviceHelper devHelper(m_context, instHelper.vki, instHelper.instance,
959                                  vector<vk::VkSurfaceKHR>{surface1.get(), surface2.get()}, getRequiredDeviceExts());
960     const vk::DeviceInterface &vkd = devHelper.vkd;
961     const vk::VkDevice device      = *devHelper.device;
962     vk::SimpleAllocator allocator(vkd, device,
963                                   getPhysicalDeviceMemoryProperties(instHelper.vki, devHelper.physicalDevice));
964     const vk::VkSwapchainCreateInfoKHR swapchainInfo1 = getBasicSwapchainParameters(
965         m_wsiType, instHelper.vki, devHelper.physicalDevice, surface1.get(), desiredSize, 2);
966     const vk::VkSwapchainCreateInfoKHR swapchainInfo2 = getBasicSwapchainParameters(
967         m_wsiType, instHelper.vki, devHelper.physicalDevice, surface2.get(), desiredSize, 2);
968     const vk::Unique<vk::VkSwapchainKHR> swapchain1(vk::createSwapchainKHR(vkd, device, &swapchainInfo1));
969     const vk::Unique<vk::VkSwapchainKHR> swapchain2(vk::createSwapchainKHR(vkd, device, &swapchainInfo2));
970     const vector<vk::VkImage> swapchainImages1 = vk::wsi::getSwapchainImages(vkd, device, swapchain1.get());
971     const vector<vk::VkImage> swapchainImages2 = vk::wsi::getSwapchainImages(vkd, device, swapchain2.get());
972     const vk::Unique<vk::VkCommandPool> commandPool(createCommandPool(
973         vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, devHelper.queueFamilyIndex));
974     const vk::wsi::WsiTriangleRenderer renderer1(
975         vkd, device, allocator, m_context.getBinaryCollection(), false, swapchainImages1, swapchainImages1,
976         swapchainInfo1.imageFormat, tcu::UVec2(swapchainInfo1.imageExtent.width, swapchainInfo1.imageExtent.height));
977     const vk::wsi::WsiTriangleRenderer renderer2(
978         vkd, device, allocator, m_context.getBinaryCollection(), false, swapchainImages2, swapchainImages2,
979         swapchainInfo2.imageFormat, tcu::UVec2(swapchainInfo2.imageExtent.width, swapchainInfo2.imageExtent.height));
980     tcu::TestLog &testLog = m_context.getTestContext().getLog();
981 
982     try
983     {
984         const size_t maxQueuedFrames = swapchainImages1.size() * 2;
985         FrameStreamObjects frameStreamObjects1(vkd, device, commandPool.get(), maxQueuedFrames);
986         FrameStreamObjects frameStreamObjects2(vkd, device, commandPool.get(), maxQueuedFrames);
987 
988         // Increasing ids for both swapchains, waiting on some to make sure we do not time out unexpectedly.
989         const vector<DualIdAndWait> sequence = {
990             {
991                 {1ull, false},
992                 {2ull, true},
993             },
994             {
995                 {4ull, true},
996                 {3ull, false},
997             },
998             {
999                 {5ull, true},
1000                 {6ull, true},
1001             },
1002         };
1003 
1004         for (const auto &step : sequence)
1005         {
1006             // Get objects for the next frames.
1007             FrameStreamObjects::FrameObjects frameObjects1 = frameStreamObjects1.newFrame();
1008             FrameStreamObjects::FrameObjects frameObjects2 = frameStreamObjects2.newFrame();
1009 
1010             // Record and submit frame.
1011             uint32_t imageNdx1 =
1012                 recordAndSubmitFrame(frameObjects1, renderer1, vkd, device, swapchain1.get(), swapchainImages1.size(),
1013                                      devHelper.queue, frameStreamObjects1.frameNumber(), testLog);
1014             uint32_t imageNdx2 =
1015                 recordAndSubmitFrame(frameObjects2, renderer2, vkd, device, swapchain2.get(), swapchainImages2.size(),
1016                                      devHelper.queue, frameStreamObjects2.frameNumber(), testLog);
1017 
1018             // Present both images at the same time with their corresponding ids.
1019             const uint64_t presentIdsArr[]     = {step.idWait1.presentId, step.idWait2.presentId};
1020             const vk::VkPresentIdKHR presentId = {
1021                 vk::VK_STRUCTURE_TYPE_PRESENT_ID_KHR,                     // VkStructureType sType;
1022                 nullptr,                                                  // const void* pNext;
1023                 static_cast<uint32_t>(DE_LENGTH_OF_ARRAY(presentIdsArr)), // uint32_t swapchainCount;
1024                 presentIdsArr,                                            // const uint64_t* pPresentIds;
1025             };
1026 
1027             const vk::VkSemaphore semaphoreArr[]    = {frameObjects1.renderCompleteSemaphore,
1028                                                        frameObjects2.renderCompleteSemaphore};
1029             const vk::VkSwapchainKHR swapchainArr[] = {swapchain1.get(), swapchain2.get()};
1030             const uint32_t imgIndexArr[]            = {imageNdx1, imageNdx2};
1031             const vk::VkPresentInfoKHR presentInfo  = {
1032                 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
1033                 &presentId,
1034                 static_cast<uint32_t>(DE_LENGTH_OF_ARRAY(semaphoreArr)),
1035                 semaphoreArr,
1036                 static_cast<uint32_t>(DE_LENGTH_OF_ARRAY(swapchainArr)),
1037                 swapchainArr,
1038                 imgIndexArr,
1039                 nullptr,
1040             };
1041 
1042             VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
1043 
1044             const IdAndWait *idWaitArr[] = {&step.idWait1, &step.idWait2};
1045             for (int i = 0; i < DE_LENGTH_OF_ARRAY(idWaitArr); ++i)
1046             {
1047                 if (idWaitArr[i]->wait)
1048                     VK_CHECK(vkd.waitForPresentKHR(device, swapchainArr[i], idWaitArr[i]->presentId, k10sec));
1049             }
1050         }
1051 
1052         // Wait until device is idle.
1053         VK_CHECK(vkd.deviceWaitIdle(device));
1054 
1055         return tcu::TestStatus::pass("Pass");
1056     }
1057     catch (...)
1058     {
1059         // Make sure device is idle before destroying resources
1060         vkd.deviceWaitIdle(device);
1061         throw;
1062     }
1063 
1064     return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
1065 }
1066 
1067 // Templated class for every instance type.
1068 template <class T> // T is the test instance class.
1069 class PresentIdWaitCase : public TestCase
1070 {
1071 public:
1072     PresentIdWaitCase(vk::wsi::Type wsiType, tcu::TestContext &ctx, const std::string &name);
~PresentIdWaitCase(void)1073     virtual ~PresentIdWaitCase(void)
1074     {
1075     }
1076     virtual void initPrograms(vk::SourceCollections &programCollection) const;
1077     virtual TestInstance *createInstance(Context &context) const;
1078     virtual void checkSupport(Context &context) const;
1079 
1080 protected:
1081     vk::wsi::Type m_wsiType;
1082 };
1083 
1084 template <class T>
PresentIdWaitCase(vk::wsi::Type wsiType,tcu::TestContext & ctx,const std::string & name)1085 PresentIdWaitCase<T>::PresentIdWaitCase(vk::wsi::Type wsiType, tcu::TestContext &ctx, const std::string &name)
1086     : TestCase(ctx, name)
1087     , m_wsiType(wsiType)
1088 {
1089 }
1090 
1091 template <class T>
initPrograms(vk::SourceCollections & programCollection) const1092 void PresentIdWaitCase<T>::initPrograms(vk::SourceCollections &programCollection) const
1093 {
1094     vk::wsi::WsiTriangleRenderer::getPrograms(programCollection);
1095 }
1096 
1097 template <class T>
createInstance(Context & context) const1098 TestInstance *PresentIdWaitCase<T>::createInstance(Context &context) const
1099 {
1100     return new T(context, m_wsiType);
1101 }
1102 
1103 template <class T>
checkSupport(Context & context) const1104 void PresentIdWaitCase<T>::checkSupport(Context &context) const
1105 {
1106     // Check instance extension support.
1107     const auto instanceExtensions = getRequiredInstanceExtensions(m_wsiType);
1108     for (const auto &ext : instanceExtensions)
1109     {
1110         if (!context.isInstanceFunctionalitySupported(ext))
1111             TCU_THROW(NotSupportedError, ext + string(" is not supported"));
1112     }
1113 
1114     // Check device extension support.
1115     const auto &vki                = context.getInstanceInterface();
1116     const auto physDev             = context.getPhysicalDevice();
1117     const auto supportedDeviceExts = vk::enumerateDeviceExtensionProperties(vki, physDev, nullptr);
1118     const auto mandatoryDeviceExts = getMandatoryDeviceExtensions();
1119 
1120     auto checkedDeviceExts = T::requiredDeviceExts();
1121     for (const auto &ext : mandatoryDeviceExts)
1122         checkedDeviceExts.push_back(ext);
1123 
1124     for (const auto &ext : checkedDeviceExts)
1125     {
1126         if (!context.isDeviceFunctionalitySupported(ext))
1127             TCU_THROW(NotSupportedError, ext + string(" is not supported"));
1128     }
1129 }
1130 
createPresentIdTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1131 void createPresentIdTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
1132 {
1133     // Use present id zero
1134     testGroup->addChild(new PresentIdWaitCase<PresentIdZeroInstance>(wsiType, testGroup->getTestContext(), "zero"));
1135     // Use increasing present ids
1136     testGroup->addChild(
1137         new PresentIdWaitCase<PresentIdIncreasingInstance>(wsiType, testGroup->getTestContext(), "increasing"));
1138     // Use increasing present ids interleaved with no ids
1139     testGroup->addChild(
1140         new PresentIdWaitCase<PresentIdInterleavedInstance>(wsiType, testGroup->getTestContext(), "interleaved"));
1141 }
1142 
createPresentWaitTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1143 void createPresentWaitTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
1144 {
1145     // Present single frame with no expected timeout
1146     testGroup->addChild(new PresentIdWaitCase<PresentWaitSingleFrameInstance>(wsiType, testGroup->getTestContext(),
1147                                                                               "single_no_timeout"));
1148     // Wait for past frame with no expected timeout
1149     testGroup->addChild(
1150         new PresentIdWaitCase<PresentWaitPastFrameInstance>(wsiType, testGroup->getTestContext(), "past_no_timeout"));
1151     // Expect timeout before submitting any frame
1152     testGroup->addChild(
1153         new PresentIdWaitCase<PresentWaitNoFramesInstance>(wsiType, testGroup->getTestContext(), "no_frames"));
1154     // Expect timeout after submitting frames with no id
1155     testGroup->addChild(
1156         new PresentIdWaitCase<PresentWaitNoFrameIdInstance>(wsiType, testGroup->getTestContext(), "no_frame_id"));
1157     // Expect timeout when waiting for a future frame
1158     testGroup->addChild(
1159         new PresentIdWaitCase<PresentWaitFutureFrameInstance>(wsiType, testGroup->getTestContext(), "future_frame"));
1160     // Smoke test using two windows, surfaces and swapchains
1161     testGroup->addChild(
1162         new PresentIdWaitCase<PresentWaitDualInstance>(wsiType, testGroup->getTestContext(), "two_swapchains"));
1163 }
1164 
1165 } // namespace
1166 
createPresentIdWaitTests(tcu::TestCaseGroup * testGroup,vk::wsi::Type wsiType)1167 void createPresentIdWaitTests(tcu::TestCaseGroup *testGroup, vk::wsi::Type wsiType)
1168 {
1169     // VK_KHR_present_id tests
1170     de::MovePtr<tcu::TestCaseGroup> idGroup(new tcu::TestCaseGroup(testGroup->getTestContext(), "id"));
1171     // VK_KHR_present_wait tests
1172     de::MovePtr<tcu::TestCaseGroup> waitGroup(new tcu::TestCaseGroup(testGroup->getTestContext(), "wait"));
1173 
1174     createPresentIdTests(idGroup.get(), wsiType);
1175     createPresentWaitTests(waitGroup.get(), wsiType);
1176 
1177     testGroup->addChild(idGroup.release());
1178     testGroup->addChild(waitGroup.release());
1179 }
1180 
1181 } // namespace wsi
1182 } // namespace vkt
1183