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