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