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