1 /*-------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
5 * Copyright (c) 2016 Google Inc.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 * \brief VkSurface Tests
22 *//*--------------------------------------------------------------------*/
24 #include "vktWsiSurfaceTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
30 #include "vkPlatform.hpp"
31 #include "vkStrUtil.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkDeviceUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkWsiPlatform.hpp"
40 #include "vkWsiUtil.hpp"
41 #include "vkAllocationCallbackUtil.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuFormatUtil.hpp"
45 #include "tcuPlatform.hpp"
46 #include "tcuResultCollector.hpp"
48 #include "deUniquePtr.hpp"
49 #include "deStringUtil.hpp"
55 inline bool operator!= (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
57 return (a.format != b.format) || (a.colorSpace != b.colorSpace);
60 inline bool operator== (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
65 inline bool operator!= (const VkExtent2D& a, const VkExtent2D& b)
67 return (a.width != b.width) || (a.height != b.height);
70 inline bool operator!= (const VkSurfaceCapabilitiesKHR& a, const VkSurfaceCapabilitiesKHR& b)
72 return (a.minImageCount != b.minImageCount) ||
73 (a.maxImageCount != b.maxImageCount) ||
74 (a.currentExtent != b.currentExtent) ||
75 (a.minImageExtent != b.minImageExtent) ||
76 (a.maxImageExtent != b.maxImageExtent) ||
77 (a.maxImageArrayLayers != b.maxImageArrayLayers) ||
78 (a.supportedTransforms != b.supportedTransforms) ||
79 (a.currentTransform != b.currentTransform) ||
80 (a.supportedCompositeAlpha != b.supportedCompositeAlpha) ||
81 (a.supportedUsageFlags != b.supportedUsageFlags);
95 using namespace vk::wsi;
109 SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC = 0xffffffff
113 class CheckIncompleteResult
116 virtual ~CheckIncompleteResult (void) {}
117 virtual void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, T* data) = 0;
119 void operator() (tcu::ResultCollector& results,
120 const InstanceInterface& vki,
121 const VkPhysicalDevice physDevice,
122 const VkSurfaceKHR surface,
123 const std::size_t expectedCompleteSize)
125 if (expectedCompleteSize == 0)
128 vector<T> outputData (expectedCompleteSize);
129 const deUint32 usedSize = static_cast<deUint32>(expectedCompleteSize / 3);
131 ValidateQueryBits::fillBits(outputData.begin(), outputData.end()); // unused entries should have this pattern intact
133 m_result = VK_SUCCESS;
135 getResult(vki, physDevice, surface, &outputData[0]); // update m_count and m_result
137 if (m_count != usedSize || m_result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(outputData.begin() + m_count, outputData.end()))
138 results.fail("Query didn't return VK_INCOMPLETE");
146 struct CheckPhysicalDeviceSurfaceFormatsIncompleteResult : public CheckIncompleteResult<VkSurfaceFormatKHR>
148 void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkSurfaceFormatKHR* data)
150 m_result = vki.getPhysicalDeviceSurfaceFormatsKHR(physDevice, surface, &m_count, data);
154 struct CheckPhysicalDeviceSurfacePresentModesIncompleteResult : public CheckIncompleteResult<VkPresentModeKHR>
156 void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkPresentModeKHR* data)
158 m_result = vki.getPhysicalDeviceSurfacePresentModesKHR(physDevice, surface, &m_count, data);
162 typedef vector<VkExtensionProperties> Extensions;
164 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
166 for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
167 requiredExtName != requiredExtensions.end();
170 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
171 TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
175 Move<VkInstance> createInstanceWithWsi (const PlatformInterface& vkp,
176 const Extensions& supportedExtensions,
178 const vector<string> extraExtensions,
179 const VkAllocationCallbacks* pAllocator = DE_NULL)
181 vector<string> extensions = extraExtensions;
183 extensions.push_back("VK_KHR_surface");
184 extensions.push_back(getExtensionName(wsiType));
186 checkAllSupported(supportedExtensions, extensions);
188 return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
191 struct InstanceHelper
193 const vector<VkExtensionProperties> supportedExtensions;
194 Unique<VkInstance> instance;
195 const InstanceDriver vki;
197 InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
198 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
200 , instance (createInstanceWithWsi(context.getPlatformInterface(),
205 , vki (context.getPlatformInterface(), *instance)
208 InstanceHelper (Context& context, Type wsiType, const vector<string>& extensions, const VkAllocationCallbacks* pAllocator = DE_NULL)
209 : supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
211 , instance (createInstanceWithWsi(context.getPlatformInterface(),
216 , vki (context.getPlatformInterface(), *instance)
220 MovePtr<Display> createDisplay (const vk::Platform& platform,
221 const Extensions& supportedExtensions,
226 return MovePtr<Display>(platform.createWsiDisplay(wsiType));
228 catch (const tcu::NotSupportedError& e)
230 if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))))
232 // If VK_KHR_{platform}_surface was supported, vk::Platform implementation
233 // must support creating native display & window for that WSI type.
234 throw tcu::TestError(e.getMessage());
241 MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
245 return MovePtr<Window>(display.createWindow(initialSize));
247 catch (const tcu::NotSupportedError& e)
249 // See createDisplay - assuming that wsi::Display was supported platform port
250 // should also support creating a window.
251 throw tcu::TestError(e.getMessage());
257 const UniquePtr<Display> display;
258 const UniquePtr<Window> window;
260 NativeObjects (Context& context,
261 const Extensions& supportedExtensions,
263 const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
264 : display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
265 , window (createWindow(*display, initialWindowSize))
269 tcu::TestStatus createSurfaceTest (Context& context, Type wsiType)
271 const InstanceHelper instHelper (context, wsiType);
272 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
273 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
275 return tcu::TestStatus::pass("Creating surface succeeded");
278 tcu::TestStatus createSurfaceCustomAllocatorTest (Context& context, Type wsiType)
280 AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
281 tcu::TestLog& log = context.getTestContext().getLog();
284 const InstanceHelper instHelper (context, wsiType, allocationRecorder.getCallbacks());
285 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
286 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
287 *instHelper.instance,
291 allocationRecorder.getCallbacks()));
293 if (!validateAndLog(log,
295 (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT) |
296 (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
297 return tcu::TestStatus::fail("Detected invalid system allocation callback");
300 if (!validateAndLog(log, allocationRecorder, 0u))
301 return tcu::TestStatus::fail("Detected invalid system allocation callback");
303 if (allocationRecorder.getRecordsBegin() == allocationRecorder.getRecordsEnd())
304 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
306 return tcu::TestStatus::pass("Creating surface succeeded using custom allocator");
309 tcu::TestStatus createSurfaceSimulateOOMTest (Context& context, Type wsiType)
311 tcu::TestLog& log = context.getTestContext().getLog();
313 for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 1024u; ++numPassingAllocs)
315 AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
316 DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(),
317 DeterministicFailAllocator::MODE_DO_NOT_COUNT,
321 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
325 const InstanceHelper instHelper (context, wsiType, failingAllocator.getCallbacks());
327 // OOM is not simulated for VkInstance as we don't want to spend time
328 // testing OOM paths inside instance creation.
329 failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
331 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
332 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
333 *instHelper.instance,
337 failingAllocator.getCallbacks()));
339 if (!validateAndLog(log,
341 (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT) |
342 (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
343 return tcu::TestStatus::fail("Detected invalid system allocation callback");
345 catch (const OutOfMemoryError& e)
347 log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
351 if (!validateAndLog(log, allocationRecorder, 0u))
352 return tcu::TestStatus::fail("Detected invalid system allocation callback");
356 log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
358 if (numPassingAllocs == 0)
359 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
361 return tcu::TestStatus::pass("OOM simulation completed");
365 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating surface did not succeed, callback limit exceeded");
368 deUint32 getNumQueueFamilies (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
370 deUint32 numFamilies = 0;
372 vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
377 tcu::TestStatus querySurfaceSupportTest (Context& context, Type wsiType)
379 tcu::TestLog& log = context.getTestContext().getLog();
380 tcu::ResultCollector results (log);
382 const InstanceHelper instHelper (context, wsiType);
383 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
384 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
385 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
387 // On Android surface must be supported by all devices and queue families
388 const bool expectSupportedOnAll = wsiType == TYPE_ANDROID;
390 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
392 const VkPhysicalDevice physicalDevice = physicalDevices[deviceNdx];
393 const deUint32 numQueueFamilies = getNumQueueFamilies(instHelper.vki, physicalDevice);
395 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
397 const VkBool32 isSupported = getPhysicalDeviceSurfaceSupport(instHelper.vki, physicalDevice, queueFamilyNdx, *surface);
399 log << TestLog::Message << "Device " << deviceNdx << ", queue family " << queueFamilyNdx << ": "
400 << (isSupported == VK_FALSE ? "NOT " : "") << "supported"
401 << TestLog::EndMessage;
403 if (expectSupportedOnAll && !isSupported)
404 results.fail("Surface must be supported by all devices and queue families");
408 return tcu::TestStatus(results.getResult(), results.getMessage());
411 bool isSupportedByAnyQueue (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
413 const deUint32 numQueueFamilies = getNumQueueFamilies(vki, physicalDevice);
415 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
417 if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
424 void validateSurfaceCapabilities (tcu::ResultCollector& results, const VkSurfaceCapabilitiesKHR& capabilities)
426 results.check(capabilities.minImageCount > 0,
427 "minImageCount must be larger than 0");
429 results.check(capabilities.minImageExtent.width > 0 &&
430 capabilities.minImageExtent.height > 0,
431 "minImageExtent dimensions must be larger than 0");
433 results.check(capabilities.maxImageExtent.width > 0 &&
434 capabilities.maxImageExtent.height > 0,
435 "maxImageExtent dimensions must be larger than 0");
437 results.check(capabilities.minImageExtent.width <= capabilities.maxImageExtent.width &&
438 capabilities.minImageExtent.height <= capabilities.maxImageExtent.height,
439 "maxImageExtent must be larger or equal to minImageExtent");
441 if (capabilities.currentExtent.width != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC ||
442 capabilities.currentExtent.height != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC)
444 results.check(capabilities.currentExtent.width > 0 &&
445 capabilities.currentExtent.height > 0,
446 "currentExtent dimensions must be larger than 0");
448 results.check(de::inRange(capabilities.currentExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width) &&
449 de::inRange(capabilities.currentExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height),
450 "currentExtent is not in supported extent limits");
453 results.check(capabilities.maxImageArrayLayers > 0,
454 "maxImageArrayLayers must be larger than 0");
456 results.check((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
457 "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT must be set in supportedUsageFlags");
459 results.check(capabilities.supportedTransforms != 0,
460 "At least one transform must be supported");
462 results.check(dePop32(capabilities.currentTransform) != 0,
463 "Invalid currentTransform");
465 results.check((capabilities.supportedTransforms & capabilities.currentTransform) != 0,
466 "currentTransform is not supported by surface");
468 results.check(capabilities.supportedCompositeAlpha != 0,
469 "At least one alpha mode must be supported");
472 tcu::TestStatus querySurfaceCapabilitiesTest (Context& context, Type wsiType)
474 tcu::TestLog& log = context.getTestContext().getLog();
475 tcu::ResultCollector results (log);
477 const InstanceHelper instHelper (context, wsiType);
478 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
479 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
480 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
482 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
484 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
486 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
487 physicalDevices[deviceNdx],
490 log << TestLog::Message << "Device " << deviceNdx << ": " << capabilities << TestLog::EndMessage;
492 validateSurfaceCapabilities(results, capabilities);
494 // else skip query as surface is not supported by the device
497 return tcu::TestStatus(results.getResult(), results.getMessage());
500 tcu::TestStatus querySurfaceCapabilities2Test (Context& context, Type wsiType)
502 tcu::TestLog& log = context.getTestContext().getLog();
503 tcu::ResultCollector results (log);
505 const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
506 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
507 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
508 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
510 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
512 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
514 const VkSurfaceCapabilitiesKHR refCapabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
515 physicalDevices[deviceNdx],
517 VkSurfaceCapabilities2KHR extCapabilities;
519 deMemset(&extCapabilities, 0xcd, sizeof(VkSurfaceCapabilities2KHR));
520 extCapabilities.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
521 extCapabilities.pNext = DE_NULL;
524 const VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo =
526 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
530 VkPhysicalDeviceSurfaceInfo2KHR infoCopy;
532 deMemcpy(&infoCopy, &surfaceInfo, sizeof(VkPhysicalDeviceSurfaceInfo2KHR));
534 VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevices[deviceNdx], &surfaceInfo, &extCapabilities));
536 results.check(deMemoryEqual(&surfaceInfo, &infoCopy, sizeof(VkPhysicalDeviceSurfaceInfo2KHR)) == DE_TRUE, "Driver wrote into input struct");
539 results.check(extCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR &&
540 extCapabilities.pNext == DE_NULL,
541 "sType/pNext modified");
543 if (refCapabilities != extCapabilities.surfaceCapabilities)
545 log << TestLog::Message
546 << "Device " << deviceNdx
547 << ": expected " << refCapabilities
548 << ", got " << extCapabilities.surfaceCapabilities
549 << TestLog::EndMessage;
550 results.fail("Mismatch between VK_KHR_surface and VK_KHR_surface2 query results");
555 return tcu::TestStatus(results.getResult(), results.getMessage());
558 void validateSurfaceFormats (tcu::ResultCollector& results, Type wsiType, const vector<VkSurfaceFormatKHR>& formats)
560 const VkSurfaceFormatKHR* requiredFormats = DE_NULL;
561 size_t numRequiredFormats = 0;
563 if (wsiType == TYPE_ANDROID)
565 static const VkSurfaceFormatKHR s_androidFormats[] =
567 { VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
568 { VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
569 { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }
572 requiredFormats = &s_androidFormats[0];
573 numRequiredFormats = DE_LENGTH_OF_ARRAY(s_androidFormats);
576 for (size_t ndx = 0; ndx < numRequiredFormats; ++ndx)
578 const VkSurfaceFormatKHR& requiredFormat = requiredFormats[ndx];
580 if (!de::contains(formats.begin(), formats.end(), requiredFormat))
581 results.fail(de::toString(requiredFormat) + " not supported");
584 // Check that there are no duplicates
585 for (size_t ndx = 1; ndx < formats.size(); ++ndx)
587 if (de::contains(formats.begin(), formats.begin() + ndx, formats[ndx]))
588 results.fail("Found duplicate entry " + de::toString(formats[ndx]));
592 tcu::TestStatus querySurfaceFormatsTest (Context& context, Type wsiType)
594 tcu::TestLog& log = context.getTestContext().getLog();
595 tcu::ResultCollector results (log);
597 const InstanceHelper instHelper (context, wsiType);
598 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
599 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
600 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
602 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
604 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
606 const vector<VkSurfaceFormatKHR> formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
607 physicalDevices[deviceNdx],
610 log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(formats.begin(), formats.end()) << TestLog::EndMessage;
612 validateSurfaceFormats(results, wsiType, formats);
613 CheckPhysicalDeviceSurfaceFormatsIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, formats.size());
615 // else skip query as surface is not supported by the device
618 return tcu::TestStatus(results.getResult(), results.getMessage());
621 tcu::TestStatus querySurfaceFormats2Test (Context& context, Type wsiType)
623 tcu::TestLog& log = context.getTestContext().getLog();
624 tcu::ResultCollector results (log);
626 const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
627 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
628 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
629 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
631 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
633 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
635 const vector<VkSurfaceFormatKHR> refFormats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
636 physicalDevices[deviceNdx],
638 const VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo =
640 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
644 deUint32 numFormats = 0;
646 VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, DE_NULL));
648 if ((size_t)numFormats != refFormats.size())
649 results.fail("vkGetPhysicalDeviceSurfaceFormats2KHR() returned different number of formats");
653 vector<VkSurfaceFormat2KHR> formats (numFormats);
655 for (size_t ndx = 0; ndx < formats.size(); ++ndx)
657 formats[ndx].sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
658 formats[ndx].pNext = DE_NULL;
661 VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, &formats[0]));
663 if ((size_t)numFormats != formats.size())
664 results.fail("Format count changed between calls");
667 vector<VkSurfaceFormatKHR> extFormats (formats.size());
669 for (size_t ndx = 0; ndx < formats.size(); ++ndx)
671 results.check(formats[ndx].sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR &&
672 formats[ndx].pNext == DE_NULL,
673 "sType/pNext modified");
674 extFormats[ndx] = formats[ndx].surfaceFormat;
677 for (size_t ndx = 0; ndx < refFormats.size(); ++ndx)
679 if (!de::contains(extFormats.begin(), extFormats.end(), refFormats[ndx]))
680 results.fail(de::toString(refFormats[ndx]) + " missing from extended query");
684 // Check VK_INCOMPLETE
686 vector<VkSurfaceFormat2KHR> formatsClone (formats);
687 deUint32 numToSupply = numFormats/2;
688 VkResult queryResult;
690 ValidateQueryBits::fillBits(formatsClone.begin() + numToSupply, formatsClone.end());
692 queryResult = instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numToSupply, &formatsClone[0]);
694 results.check(queryResult == VK_INCOMPLETE, "Expected VK_INCOMPLETE");
695 results.check(ValidateQueryBits::checkBits(formatsClone.begin() + numToSupply, formatsClone.end()),
696 "Driver wrote past last element");
698 for (size_t ndx = 0; ndx < (size_t)numToSupply; ++ndx)
700 results.check(formatsClone[ndx].sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR &&
701 formatsClone[ndx].pNext == DE_NULL &&
702 formatsClone[ndx].surfaceFormat == formats[ndx].surfaceFormat,
703 "Returned element " + de::toString(ndx) + " is different");
708 // else skip query as surface is not supported by the device
711 return tcu::TestStatus(results.getResult(), results.getMessage());
714 void validateSurfacePresentModes (tcu::ResultCollector& results, Type wsiType, const vector<VkPresentModeKHR>& modes)
716 results.check(de::contains(modes.begin(), modes.end(), VK_PRESENT_MODE_FIFO_KHR),
717 "VK_PRESENT_MODE_FIFO_KHR is not supported");
719 if (wsiType == TYPE_ANDROID)
720 results.check(de::contains(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR),
721 "VK_PRESENT_MODE_MAILBOX_KHR is not supported");
724 tcu::TestStatus querySurfacePresentModesTest (Context& context, Type wsiType)
726 tcu::TestLog& log = context.getTestContext().getLog();
727 tcu::ResultCollector results (log);
729 const InstanceHelper instHelper (context, wsiType);
730 const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
731 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *native.display, *native.window));
732 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
734 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
736 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
738 const vector<VkPresentModeKHR> modes = getPhysicalDeviceSurfacePresentModes(instHelper.vki, physicalDevices[deviceNdx], *surface);
740 log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(modes.begin(), modes.end()) << TestLog::EndMessage;
742 validateSurfacePresentModes(results, wsiType, modes);
743 CheckPhysicalDeviceSurfacePresentModesIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, modes.size());
745 // else skip query as surface is not supported by the device
748 return tcu::TestStatus(results.getResult(), results.getMessage());
751 tcu::TestStatus createSurfaceInitialSizeTest (Context& context, Type wsiType)
753 tcu::TestLog& log = context.getTestContext().getLog();
754 tcu::ResultCollector results (log);
756 const InstanceHelper instHelper (context, wsiType);
758 const UniquePtr<Display> nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
759 instHelper.supportedExtensions,
762 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
763 const UVec2 sizes[] =
770 DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE);
772 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
774 const UVec2& testSize = sizes[sizeNdx];
775 const UniquePtr<Window> nativeWindow (createWindow(*nativeDisplay, tcu::just(testSize)));
776 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
778 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
780 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
782 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
784 // \note Assumes that surface size is NOT set by swapchain if initial window size is honored by platform
785 results.check(capabilities.currentExtent.width == testSize.x() &&
786 capabilities.currentExtent.height == testSize.y(),
787 "currentExtent " + de::toString(capabilities.currentExtent) + " doesn't match requested size " + de::toString(testSize));
792 return tcu::TestStatus(results.getResult(), results.getMessage());
795 tcu::TestStatus resizeSurfaceTest (Context& context, Type wsiType)
797 tcu::TestLog& log = context.getTestContext().getLog();
798 tcu::ResultCollector results (log);
800 const InstanceHelper instHelper (context, wsiType);
802 const UniquePtr<Display> nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
803 instHelper.supportedExtensions,
805 UniquePtr<Window> nativeWindow (createWindow(*nativeDisplay, tcu::nothing<UVec2>()));
807 const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
808 const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, *instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
810 const UVec2 sizes[] =
817 DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_RESIZE_WINDOW);
819 for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
821 const UVec2 testSize = sizes[sizeNdx];
825 nativeWindow->resize(testSize);
827 catch (const tcu::Exception& e)
829 // Make sure all exception types result in a test failure
830 results.fail(e.getMessage());
833 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
835 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
837 const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
839 // \note Assumes that surface size is NOT set by swapchain if initial window size is honored by platform
840 results.check(capabilities.currentExtent.width == testSize.x() &&
841 capabilities.currentExtent.height == testSize.y(),
842 "currentExtent " + de::toString(capabilities.currentExtent) + " doesn't match requested size " + de::toString(testSize));
847 return tcu::TestStatus(results.getResult(), results.getMessage());
850 tcu::TestStatus destroyNullHandleSurfaceTest (Context& context, Type wsiType)
852 const InstanceHelper instHelper (context, wsiType);
853 const VkSurfaceKHR nullHandle = DE_NULL;
856 instHelper.vki.destroySurfaceKHR(*instHelper.instance, nullHandle, DE_NULL);
860 AllocationCallbackRecorder recordingAllocator (getSystemAllocator(), 1u);
862 instHelper.vki.destroySurfaceKHR(*instHelper.instance, nullHandle, recordingAllocator.getCallbacks());
864 if (recordingAllocator.getNumRecords() != 0u)
865 return tcu::TestStatus::fail("Implementation allocated/freed the memory");
868 return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
873 void createSurfaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
875 const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
877 addFunctionCase(testGroup, "create", "Create surface", createSurfaceTest, wsiType);
878 addFunctionCase(testGroup, "create_custom_allocator", "Create surface with custom allocator", createSurfaceCustomAllocatorTest, wsiType);
879 addFunctionCase(testGroup, "create_simulate_oom", "Create surface with simulating OOM", createSurfaceSimulateOOMTest, wsiType);
880 addFunctionCase(testGroup, "query_support", "Query surface support", querySurfaceSupportTest, wsiType);
881 addFunctionCase(testGroup, "query_capabilities", "Query surface capabilities", querySurfaceCapabilitiesTest, wsiType);
882 addFunctionCase(testGroup, "query_capabilities2", "Query extended surface capabilities", querySurfaceCapabilities2Test, wsiType);
883 addFunctionCase(testGroup, "query_formats", "Query surface formats", querySurfaceFormatsTest, wsiType);
884 addFunctionCase(testGroup, "query_formats2", "Query extended surface formats", querySurfaceFormats2Test, wsiType);
885 addFunctionCase(testGroup, "query_present_modes", "Query surface present modes", querySurfacePresentModesTest, wsiType);
886 addFunctionCase(testGroup, "destroy_null_handle", "Destroy VK_NULL_HANDLE surface", destroyNullHandleSurfaceTest, wsiType);
888 if ((platformProperties.features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE) != 0)
889 addFunctionCase(testGroup, "initial_size", "Create surface with initial window size set", createSurfaceInitialSizeTest, wsiType);
891 if ((platformProperties.features & PlatformProperties::FEATURE_RESIZE_WINDOW) != 0)
892 addFunctionCase(testGroup, "resize", "Resize window and surface", resizeSurfaceTest, wsiType);