1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2019 The Khronos Group Inc.
6 * Copyright (c) 2019 Valve Corporation.
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * \brief Tests for the present id and present wait extensions.
23 *//*--------------------------------------------------------------------*/
25 #include "vktWsiPresentIdWaitTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktCustomInstancesDevices.hpp"
28 #include "vktNativeObjectsUtil.hpp"
30 #include "vkQueryUtil.hpp"
31 #include "vkDeviceUtil.hpp"
32 #include "vkWsiUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkRefUtil.hpp"
37 #include "tcuTestContext.hpp"
38 #include "tcuPlatform.hpp"
39 #include "tcuCommandLine.hpp"
40 #include "tcuTestLog.hpp"
65 // Handy time constants in nanoseconds.
66 constexpr deUint64 k10sec = 10000000000ull;
67 constexpr deUint64 k1sec = 1000000000ull;
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;
73 using TimeoutRange = std::pair<deInt64, deInt64>;
75 // Calculate acceptable timeout range based on indicated timeout and taking into account kMargin.
76 TimeoutRange calcTimeoutRange (deUint64 timeout)
78 constexpr auto kUnsignedMax = std::numeric_limits<deUint64>::max();
79 constexpr auto kSignedMax = static_cast<deUint64>(std::numeric_limits<deInt64>::max());
81 // Watch for over- and under-flows.
82 deUint64 timeoutMin = ((timeout < kMargin) ? 0ull : (timeout - kMargin));
83 deUint64 timeoutMax = ((kUnsignedMax - timeout < kMargin) ? kUnsignedMax : timeout + kMargin);
85 // Make sure casting is safe.
86 timeoutMin = de::min(kSignedMax, timeoutMin);
87 timeoutMax = de::min(kSignedMax, timeoutMax);
89 return TimeoutRange(static_cast<deInt64>(timeoutMin), static_cast<deInt64>(timeoutMax));
92 class PresentIdWaitInstance : public TestInstance
95 PresentIdWaitInstance (Context& context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType) {}
96 virtual ~PresentIdWaitInstance (void) {}
98 virtual tcu::TestStatus iterate (void);
100 virtual tcu::TestStatus run (const vk::DeviceInterface& vkd,
103 vk::VkCommandPool commandPool,
104 vk::VkSwapchainKHR swapchain,
105 size_t swapchainSize,
106 const vk::wsi::WsiTriangleRenderer& renderer) = 0;
108 // Subclasses will need to implement a static method like this one indicating which extensions they need.
109 static vector<const char*> requiredDeviceExts (void) { return vector<const char*>(); }
111 // Subclasses will also need to implement this nonstatic method returning the same information as above.
112 virtual vector<const char*> getRequiredDeviceExts (void) = 0;
115 vk::wsi::Type m_wsiType;
118 vector<const char*> getRequiredInstanceExtensions (vk::wsi::Type wsiType)
120 vector<const char*> extensions;
121 extensions.push_back("VK_KHR_surface");
122 extensions.push_back(getExtensionName(wsiType));
126 CustomInstance createInstanceWithWsi (Context& context,
127 vk::wsi::Type wsiType,
128 const vk::VkAllocationCallbacks* pAllocator = nullptr)
130 const auto version = context.getUsedApiVersion();
131 const auto requiredExtensions = getRequiredInstanceExtensions(wsiType);
133 vector<string> requestedExtensions;
134 for (const auto& extensionName : requiredExtensions)
136 if (!vk::isCoreInstanceExtension(version, extensionName))
137 requestedExtensions.push_back(extensionName);
140 return vkt::createCustomInstanceWithExtensions(context, requestedExtensions, pAllocator);
143 struct InstanceHelper
145 const vector<vk::VkExtensionProperties> supportedExtensions;
146 CustomInstance instance;
147 const vk::InstanceDriver& vki;
149 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())
156 vector<const char*> getMandatoryDeviceExtensions ()
158 vector<const char*> mandatoryExtensions;
159 mandatoryExtensions.push_back("VK_KHR_swapchain");
160 return mandatoryExtensions;
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)
172 const float queuePriorities[] = { 1.0f };
173 const vk::VkDeviceQueueCreateInfo queueInfos[] =
176 vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
178 (vk::VkDeviceQueueCreateFlags)0,
180 DE_LENGTH_OF_ARRAY(queuePriorities),
184 vk::VkPhysicalDeviceFeatures features;
185 std::vector<const char*> extensions = extraExtensions;
186 const auto mandatoryExtensions = getMandatoryDeviceExtensions();
188 for (const auto& ext : mandatoryExtensions)
189 extensions.push_back(ext);
191 deMemset(&features, 0, sizeof(features));
192 const vk::VkDeviceCreateInfo deviceParams =
194 vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
196 (vk::VkDeviceCreateFlags)0,
197 DE_LENGTH_OF_ARRAY(queueInfos),
199 0u, // enabledLayerCount
200 nullptr, // ppEnabledLayerNames
201 static_cast<deUint32>(extensions.size()), // enabledExtensionCount
202 extensions.data(), // ppEnabledExtensionNames
206 return createCustomDevice(validationEnabled, vkp, instance, vki, physicalDevice, &deviceParams, pAllocator);
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;
217 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(),
231 context.getTestContext().getCommandLine().isValidationEnabled(),
233 , vkd (context.getPlatformInterface(), instance, *device)
234 , queue (getDeviceQueue(vkd, *device, queueFamilyIndex, 0))
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)
246 const vk::VkSurfaceCapabilitiesKHR capabilities = vk::wsi::getPhysicalDeviceSurfaceCapabilities(vki,
249 const vector<vk::VkSurfaceFormatKHR> formats = vk::wsi::getPhysicalDeviceSurfaceFormats(vki,
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 =
256 vk::VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
258 (vk::VkSwapchainCreateFlagsKHR)0,
260 de::clamp(desiredImageCount, capabilities.minImageCount, capabilities.maxImageCount > 0 ? capabilities.maxImageCount : capabilities.minImageCount + desiredImageCount),
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,
271 vk::VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
272 vk::VK_PRESENT_MODE_FIFO_KHR,
274 (vk::VkSwapchainKHR)0 // oldSwapchain
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>>;
284 vector<FenceSp> createFences (const vk::DeviceInterface& vkd,
285 const vk::VkDevice device,
288 vector<FenceSp> fences(numFences);
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)));
296 vector<SemaphoreSp> createSemaphores (const vk::DeviceInterface& vkd,
297 const vk::VkDevice device,
298 size_t numSemaphores)
300 vector<SemaphoreSp> semaphores(numSemaphores);
302 for (size_t ndx = 0; ndx < numSemaphores; ++ndx)
303 semaphores[ndx] = SemaphoreSp(new vk::Unique<vk::VkSemaphore>(createSemaphore(vkd, device)));
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)
314 vector<CommandBufferSp> buffers (numCommandBuffers);
316 for (size_t ndx = 0; ndx < numCommandBuffers; ++ndx)
317 buffers[ndx] = CommandBufferSp(new vk::Unique<vk::VkCommandBuffer>(allocateCommandBuffer(vkd, device, commandPool, level)));
322 class FrameStreamObjects
327 const vk::VkFence& renderCompleteFence;
328 const vk::VkSemaphore& renderCompleteSemaphore;
329 const vk::VkSemaphore& imageAvailableSemaphore;
330 const vk::VkCommandBuffer& commandBuffer;
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)
342 size_t frameNumber (void) const { DE_ASSERT(m_nextFrame > 0u); return m_nextFrame - 1u; }
344 FrameObjects newFrame ()
346 const size_t mod = m_nextFrame % m_maxQueuedFrames;
349 **renderingCompleteFences[mod],
350 **renderingCompleteSemaphores[mod],
351 **imageAvailableSemaphores[mod],
352 **commandBuffers[mod],
359 const vector<FenceSp> renderingCompleteFences;
360 const vector<SemaphoreSp> renderingCompleteSemaphores;
361 const vector<SemaphoreSp> imageAvailableSemaphores;
362 const vector<CommandBufferSp> commandBuffers;
364 const size_t m_maxQueuedFrames;
368 tcu::TestStatus PresentIdWaitInstance::iterate (void)
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,
385 m_context.getBinaryCollection(),
389 swapchainInfo.imageFormat,
390 tcu::UVec2(swapchainInfo.imageExtent.width, swapchainInfo.imageExtent.height));
394 return run(vkd, device, devHelper.queue, commandPool.get(), swapchain.get(), swapchainImages.size(), renderer);
398 // Make sure device is idle before destroying resources
399 vkd.deviceWaitIdle(device);
403 return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
406 struct PresentParameters
408 tcu::Maybe<deUint64> presentId;
409 tcu::Maybe<vk::VkResult> expectedResult;
412 struct WaitParameters
415 deUint64 timeout; // Nanoseconds.
416 bool timeoutExpected;
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
424 vector<PresentParameters> presentOps;
425 vector<WaitParameters> waitOps;
428 // Parent class for VK_KHR_present_id and VK_KHR_present_wait simple tests.
429 class PresentIdWaitSimpleInstance : public PresentIdWaitInstance
432 PresentIdWaitSimpleInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
433 : PresentIdWaitInstance(context, wsiType), m_sequence(sequence)
436 virtual ~PresentIdWaitSimpleInstance() {}
438 virtual tcu::TestStatus run (const vk::DeviceInterface& vkd,
441 vk::VkCommandPool commandPool,
442 vk::VkSwapchainKHR swapchain,
443 size_t swapchainSize,
444 const vk::wsi::WsiTriangleRenderer& renderer);
446 const vector<PresentAndWaitOps> m_sequence;
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.
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)
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));
457 // Acquire swapchain image.
458 deUint32 imageNdx = std::numeric_limits<deUint32>::max();
459 const vk::VkResult acquireResult = vkd.acquireNextImageKHR(device,
461 std::numeric_limits<deUint64>::max(),
462 frameObjects.imageAvailableSemaphore,
466 if (acquireResult == vk::VK_SUBOPTIMAL_KHR)
467 testLog << tcu::TestLog::Message << "Got " << acquireResult << " at frame " << frameNumber << tcu::TestLog::EndMessage;
469 VK_CHECK(acquireResult);
470 TCU_CHECK(static_cast<size_t>(imageNdx) < swapchainSize);
472 // Submit frame to the queue.
473 const vk::VkPipelineStageFlags waitDstStage = vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
474 const vk::VkSubmitInfo submitInfo =
476 vk::VK_STRUCTURE_TYPE_SUBMIT_INFO,
479 &frameObjects.imageAvailableSemaphore,
482 &frameObjects.commandBuffer,
484 &frameObjects.renderCompleteSemaphore,
487 triangleRenderer.recordFrame(frameObjects.commandBuffer, imageNdx, static_cast<deUint32>(frameNumber));
488 VK_CHECK(vkd.queueSubmit(queue, 1u, &submitInfo, frameObjects.renderCompleteFence));
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)
495 const size_t maxQueuedFrames = swapchainSize*2;
496 FrameStreamObjects frameStreamObjects (vkd, device, commandPool, maxQueuedFrames);
498 for (const auto& step : m_sequence)
500 for (const auto& presentOp : step.presentOps)
502 // Get objects for the next frame.
503 FrameStreamObjects::FrameObjects frameObjects = frameStreamObjects.newFrame();
505 // Record and submit new frame.
506 deUint32 imageNdx = recordAndSubmitFrame(frameObjects, renderer, vkd, device, swapchain, swapchainSize, queue, frameStreamObjects.frameNumber(), m_context.getTestContext().getLog());
508 // Present rendered frame.
509 const vk::VkPresentIdKHR presentId =
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;
517 const vk::VkPresentInfoKHR presentInfo =
519 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
520 (presentOp.presentId ? &presentId : nullptr),
522 &frameObjects.renderCompleteSemaphore,
529 vk::VkResult result = vkd.queuePresentKHR(queue, &presentInfo);
531 if (presentOp.expectedResult)
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))
537 std::ostringstream msg;
538 msg << "Got " << result << " while expecting " << expected << " after presenting with ";
539 if (presentOp.presentId)
540 msg << "id " << presentOp.presentId.get();
549 for (const auto& waitOp : step.waitOps)
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();
556 if (waitOp.timeoutExpected)
558 if (waitResult != vk::VK_TIMEOUT)
560 std::ostringstream msg;
561 msg << "Got " << waitResult << " while expecting a timeout in vkWaitForPresentKHR call";
565 const auto timeoutRange = calcTimeoutRange(waitOp.timeout);
567 if (diff < timeoutRange.first || diff > timeoutRange.second)
569 std::ostringstream msg;
570 msg << "vkWaitForPresentKHR waited for " << diff << " nanoseconds with a timeout of " << waitOp.timeout << " nanoseconds";
574 else if (waitResult != vk::VK_SUCCESS)
576 std::ostringstream msg;
577 msg << "Got " << waitResult << " while expecting success in vkWaitForPresentKHR call";
583 // Wait until device is idle.
584 VK_CHECK(vkd.deviceWaitIdle(device));
586 return tcu::TestStatus::pass("Pass");
589 // Parent class for VK_KHR_present_id simple tests.
590 class PresentIdInstance : public PresentIdWaitSimpleInstance
593 PresentIdInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
594 : PresentIdWaitSimpleInstance(context, wsiType, sequence)
597 virtual ~PresentIdInstance() {}
599 static vector<const char*> requiredDeviceExts (void)
601 vector<const char*> extensions;
602 extensions.push_back("VK_KHR_present_id");
606 virtual vector<const char*> getRequiredDeviceExts (void)
608 return requiredDeviceExts();
612 // Parent class for VK_KHR_present_wait simple tests.
613 class PresentWaitInstance : public PresentIdWaitSimpleInstance
616 PresentWaitInstance(Context& context, vk::wsi::Type wsiType, const vector<PresentAndWaitOps>& sequence)
617 : PresentIdWaitSimpleInstance(context, wsiType, sequence)
620 virtual ~PresentWaitInstance() {}
622 static vector<const char*> requiredDeviceExts (void)
624 vector<const char*> extensions;
625 extensions.push_back("VK_KHR_present_id");
626 extensions.push_back("VK_KHR_present_wait");
630 virtual vector<const char*> getRequiredDeviceExts (void)
632 return requiredDeviceExts();
636 class PresentIdZeroInstance : public PresentIdInstance
639 static const vector<PresentAndWaitOps> sequence;
641 PresentIdZeroInstance (Context& context, vk::wsi::Type wsiType)
642 : PresentIdInstance(context, wsiType, sequence)
646 const vector<PresentAndWaitOps> PresentIdZeroInstance::sequence =
648 { // PresentAndWaitOps
649 { // presentOps vector
650 { tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
657 class PresentIdIncreasingInstance : public PresentIdInstance
660 static const vector<PresentAndWaitOps> sequence;
662 PresentIdIncreasingInstance (Context& context, vk::wsi::Type wsiType)
663 : PresentIdInstance(context, wsiType, sequence)
667 const vector<PresentAndWaitOps> PresentIdIncreasingInstance::sequence =
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) },
679 class PresentIdInterleavedInstance : public PresentIdInstance
682 static const vector<PresentAndWaitOps> sequence;
684 PresentIdInterleavedInstance (Context& context, vk::wsi::Type wsiType)
685 : PresentIdInstance(context, wsiType, sequence)
689 const vector<PresentAndWaitOps> PresentIdInterleavedInstance::sequence =
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<deUint64>(), tcu::just(vk::VK_SUCCESS) },
696 { tcu::just(std::numeric_limits<deUint64>::max()), tcu::just(vk::VK_SUCCESS) },
703 class PresentWaitSingleFrameInstance : public PresentWaitInstance
706 static const vector<PresentAndWaitOps> sequence;
708 PresentWaitSingleFrameInstance (Context& context, vk::wsi::Type wsiType)
709 : PresentWaitInstance(context, wsiType, sequence)
713 const vector<PresentAndWaitOps> PresentWaitSingleFrameInstance::sequence =
715 { // PresentAndWaitOps
716 { // presentOps vector
717 { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
720 { 1ull, k10sec, false },
725 class PresentWaitPastFrameInstance : public PresentWaitInstance
728 static const vector<PresentAndWaitOps> sequence;
730 PresentWaitPastFrameInstance (Context& context, vk::wsi::Type wsiType)
731 : PresentWaitInstance(context, wsiType, sequence)
735 const vector<PresentAndWaitOps> PresentWaitPastFrameInstance::sequence =
737 // Start with present id 1.
738 { // PresentAndWaitOps
739 { // presentOps vector
740 { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
743 { 1ull, k10sec, false },
744 { 1ull, 0ull, false },
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) },
753 { 1ull, 0ull, false },
754 { 1ull, k10sec, false },
755 { std::numeric_limits<deUint64>::max(), k10sec, false },
756 { std::numeric_limits<deUint64>::max(), 0ull, false },
759 // Submit some frames without id after having used the maximum value. This should also work.
760 { // PresentAndWaitOps
761 { // presentOps vector
762 { tcu::nothing<deUint64>(), tcu::just(vk::VK_SUCCESS) },
763 { tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
770 class PresentWaitNoFramesInstance : public PresentWaitInstance
773 static const vector<PresentAndWaitOps> sequence;
775 PresentWaitNoFramesInstance (Context& context, vk::wsi::Type wsiType)
776 : PresentWaitInstance(context, wsiType, sequence)
780 const vector<PresentAndWaitOps> PresentWaitNoFramesInstance::sequence =
782 { // PresentAndWaitOps
783 { // presentOps vector
786 { 1ull, 0ull, true },
787 { 1ull, k1sec, true },
792 class PresentWaitNoFrameIdInstance : public PresentWaitInstance
795 static const vector<PresentAndWaitOps> sequence;
797 PresentWaitNoFrameIdInstance (Context& context, vk::wsi::Type wsiType)
798 : PresentWaitInstance(context, wsiType, sequence)
802 const vector<PresentAndWaitOps> PresentWaitNoFrameIdInstance::sequence =
804 { // PresentAndWaitOps
805 { // presentOps vector
806 { tcu::just<deUint64>(0), tcu::just(vk::VK_SUCCESS) },
809 { 1ull, 0ull, true },
810 { 1ull, k1sec, true },
813 { // PresentAndWaitOps
814 { // presentOps vector
815 { tcu::nothing<deUint64>(), tcu::just(vk::VK_SUCCESS) },
818 { 1ull, 0ull, true },
819 { 1ull, k1sec, true },
824 class PresentWaitFutureFrameInstance : public PresentWaitInstance
827 static const vector<PresentAndWaitOps> sequence;
829 PresentWaitFutureFrameInstance (Context& context, vk::wsi::Type wsiType)
830 : PresentWaitInstance(context, wsiType, sequence)
834 const vector<PresentAndWaitOps> PresentWaitFutureFrameInstance::sequence =
836 { // PresentAndWaitOps
837 { // presentOps vector
838 { tcu::just<deUint64>(1), tcu::just(vk::VK_SUCCESS) },
841 { std::numeric_limits<deUint64>::max(), k1sec, true },
842 { std::numeric_limits<deUint64>::max(), 0ull, true },
843 { 2ull, 0ull, true },
844 { 2ull, k1sec, true },
849 // Instance with two windows and surfaces to check present ids are not mixed up.
850 class PresentWaitDualInstance : public TestInstance
853 PresentWaitDualInstance (Context& context, vk::wsi::Type wsiType) : TestInstance(context), m_wsiType(wsiType) {}
854 virtual ~PresentWaitDualInstance (void) {}
856 virtual tcu::TestStatus iterate (void);
858 static vector<const char*> requiredDeviceExts (void)
860 vector<const char*> extensions;
861 extensions.push_back("VK_KHR_present_id");
862 extensions.push_back("VK_KHR_present_wait");
866 virtual vector<const char*> getRequiredDeviceExts (void)
868 return requiredDeviceExts();
872 vk::wsi::Type m_wsiType;
887 tcu::TestStatus PresentWaitDualInstance::iterate (void)
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,
908 m_context.getBinaryCollection(),
912 swapchainInfo1.imageFormat,
913 tcu::UVec2(swapchainInfo1.imageExtent.width, swapchainInfo1.imageExtent.height));
914 const vk::wsi::WsiTriangleRenderer renderer2 (vkd,
917 m_context.getBinaryCollection(),
921 swapchainInfo2.imageFormat,
922 tcu::UVec2(swapchainInfo2.imageExtent.width, swapchainInfo2.imageExtent.height));
923 tcu::TestLog& testLog = m_context.getTestContext().getLog();
927 const size_t maxQueuedFrames = swapchainImages1.size()*2;
928 FrameStreamObjects frameStreamObjects1 (vkd, device, commandPool.get(), maxQueuedFrames);
929 FrameStreamObjects frameStreamObjects2 (vkd, device, commandPool.get(), maxQueuedFrames);
931 // Increasing ids for both swapchains, waiting on some to make sure we do not time out unexpectedly.
932 const vector<DualIdAndWait> sequence =
948 for (const auto& step : sequence)
950 // Get objects for the next frames.
951 FrameStreamObjects::FrameObjects frameObjects1 = frameStreamObjects1.newFrame();
952 FrameStreamObjects::FrameObjects frameObjects2 = frameStreamObjects2.newFrame();
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);
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 =
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;
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 =
973 vk::VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
975 static_cast<deUint32>(DE_LENGTH_OF_ARRAY(semaphoreArr)),
977 static_cast<deUint32>(DE_LENGTH_OF_ARRAY(swapchainArr)),
983 VK_CHECK(vkd.queuePresentKHR(devHelper.queue, &presentInfo));
985 const IdAndWait* idWaitArr[] = { &step.idWait1, &step.idWait2 };
986 for (int i = 0; i < DE_LENGTH_OF_ARRAY(idWaitArr); ++i)
988 if (idWaitArr[i]->wait)
989 VK_CHECK(vkd.waitForPresentKHR(device, swapchainArr[i], idWaitArr[i]->presentId, k10sec));
993 // Wait until device is idle.
994 VK_CHECK(vkd.deviceWaitIdle(device));
996 return tcu::TestStatus::pass("Pass");
1000 // Make sure device is idle before destroying resources
1001 vkd.deviceWaitIdle(device);
1005 return tcu::TestStatus(QP_TEST_RESULT_INTERNAL_ERROR, "Reached unreachable code");
1008 // Templated class for every instance type.
1009 template <class T> // T is the test instance class.
1010 class PresentIdWaitCase : public TestCase
1013 PresentIdWaitCase (vk::wsi::Type wsiType, tcu::TestContext& ctx, const std::string& name, const std::string& description);
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;
1020 vk::wsi::Type m_wsiType;
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)
1030 void PresentIdWaitCase<T>::initPrograms (vk::SourceCollections& programCollection) const
1032 vk::wsi::WsiTriangleRenderer::getPrograms(programCollection);
1036 TestInstance* PresentIdWaitCase<T>::createInstance (Context& context) const
1038 return new T(context, m_wsiType);
1042 void PresentIdWaitCase<T>::checkSupport (Context& context) const
1044 // Check instance extension support.
1045 const auto instanceExtensions = getRequiredInstanceExtensions(m_wsiType);
1046 for (const auto& ext : instanceExtensions)
1048 if (!context.isInstanceFunctionalitySupported(ext))
1049 TCU_THROW(NotSupportedError, ext + string(" is not supported"));
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();
1058 auto checkedDeviceExts = T::requiredDeviceExts();
1059 for (const auto& ext : mandatoryDeviceExts)
1060 checkedDeviceExts.push_back(ext);
1062 for (const auto& ext : checkedDeviceExts)
1064 if (!vk::isExtensionSupported(supportedDeviceExts, vk::RequiredExtension(ext)))
1065 TCU_THROW(NotSupportedError, ext + string(" is not supported"));
1069 void createPresentIdTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
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"));
1076 void createPresentWaitTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
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"));
1088 void createPresentIdWaitTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
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"));
1093 createPresentIdTests (idGroup.get(), wsiType);
1094 createPresentWaitTests (waitGroup.get(), wsiType);
1096 testGroup->addChild(idGroup.release());
1097 testGroup->addChild(waitGroup.release());