Update Vulkan CTS to version 1.0.2.3
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / wsi / vktWsiSurfaceTests.cpp
1 /*-------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 Google Inc.
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  *//*!
20  * \file
21  * \brief VkSurface Tests
22  *//*--------------------------------------------------------------------*/
23
24 #include "vktWsiSurfaceTests.hpp"
25
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTestGroupUtil.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkPlatform.hpp"
31 #include "vkStrUtil.hpp"
32 #include "vkRef.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"
42
43 #include "tcuTestLog.hpp"
44 #include "tcuFormatUtil.hpp"
45 #include "tcuPlatform.hpp"
46 #include "tcuResultCollector.hpp"
47
48 #include "deUniquePtr.hpp"
49 #include "deStringUtil.hpp"
50 #include "deMemory.h"
51
52 namespace vk
53 {
54
55 inline bool operator!= (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
56 {
57         return (a.format != b.format) || (a.colorSpace != b.colorSpace);
58 }
59
60 inline bool operator== (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
61 {
62         return !(a != b);
63 }
64
65 inline bool operator!= (const VkExtent2D& a, const VkExtent2D& b)
66 {
67         return (a.width != b.width) || (a.height != b.height);
68 }
69
70 inline bool operator!= (const VkSurfaceCapabilitiesKHR& a, const VkSurfaceCapabilitiesKHR& b)
71 {
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);
82 }
83
84 } // vk
85
86 namespace vkt
87 {
88 namespace wsi
89 {
90
91 namespace
92 {
93
94 using namespace vk;
95 using namespace vk::wsi;
96
97 using tcu::TestLog;
98 using tcu::Maybe;
99 using tcu::UVec2;
100
101 using de::MovePtr;
102 using de::UniquePtr;
103
104 using std::string;
105 using std::vector;
106
107 enum
108 {
109         SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC    = 0xffffffff
110 };
111
112 template<typename T>
113 class CheckIncompleteResult
114 {
115 public:
116         virtual                 ~CheckIncompleteResult  (void) {}
117         virtual void    getResult                               (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, T* data) = 0;
118
119         void operator() (tcu::ResultCollector&          results,
120                                          const InstanceInterface&       vki,
121                                          const VkPhysicalDevice         physDevice,
122                                          const VkSurfaceKHR                     surface,
123                                          const std::size_t                      expectedCompleteSize)
124         {
125                 if (expectedCompleteSize == 0)
126                         return;
127
128                 vector<T>               outputData      (expectedCompleteSize);
129                 const deUint32  usedSize        = static_cast<deUint32>(expectedCompleteSize / 3);
130
131                 ValidateQueryBits::fillBits(outputData.begin(), outputData.end());      // unused entries should have this pattern intact
132                 m_count         = usedSize;
133                 m_result        = VK_SUCCESS;
134
135                 getResult(vki, physDevice, surface, &outputData[0]);                            // update m_count and m_result
136
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");
139         }
140
141 protected:
142         deUint32        m_count;
143         VkResult        m_result;
144 };
145
146 struct CheckPhysicalDeviceSurfaceFormatsIncompleteResult : public CheckIncompleteResult<VkSurfaceFormatKHR>
147 {
148         void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkSurfaceFormatKHR* data)
149         {
150                 m_result = vki.getPhysicalDeviceSurfaceFormatsKHR(physDevice, surface, &m_count, data);
151         }
152 };
153
154 struct CheckPhysicalDeviceSurfacePresentModesIncompleteResult : public CheckIncompleteResult<VkPresentModeKHR>
155 {
156         void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkPresentModeKHR* data)
157         {
158                 m_result = vki.getPhysicalDeviceSurfacePresentModesKHR(physDevice, surface, &m_count, data);
159         }
160 };
161
162 typedef vector<VkExtensionProperties> Extensions;
163
164 void checkAllSupported (const Extensions& supportedExtensions, const vector<string>& requiredExtensions)
165 {
166         for (vector<string>::const_iterator requiredExtName = requiredExtensions.begin();
167                  requiredExtName != requiredExtensions.end();
168                  ++requiredExtName)
169         {
170                 if (!isExtensionSupported(supportedExtensions, RequiredExtension(*requiredExtName)))
171                         TCU_THROW(NotSupportedError, (*requiredExtName + " is not supported").c_str());
172         }
173 }
174
175 Move<VkInstance> createInstanceWithWsi (const PlatformInterface&                vkp,
176                                                                                 const Extensions&                               supportedExtensions,
177                                                                                 Type                                                    wsiType,
178                                                                                 const vector<string>                    extraExtensions,
179                                                                                 const VkAllocationCallbacks*    pAllocator      = DE_NULL)
180 {
181         vector<string>  extensions      = extraExtensions;
182
183         extensions.push_back("VK_KHR_surface");
184         extensions.push_back(getExtensionName(wsiType));
185
186         checkAllSupported(supportedExtensions, extensions);
187
188         return createDefaultInstance(vkp, vector<string>(), extensions, pAllocator);
189 }
190
191 struct InstanceHelper
192 {
193         const vector<VkExtensionProperties>     supportedExtensions;
194         Unique<VkInstance>                                      instance;
195         const InstanceDriver                            vki;
196
197         InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
198                 : supportedExtensions   (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
199                                                                                                                                           DE_NULL))
200                 , instance                              (createInstanceWithWsi(context.getPlatformInterface(),
201                                                                                                            supportedExtensions,
202                                                                                                            wsiType,
203                                                                                                            vector<string>(),
204                                                                                                            pAllocator))
205                 , vki                                   (context.getPlatformInterface(), *instance)
206         {}
207
208         InstanceHelper (Context& context, Type wsiType, const vector<string>& extensions, const VkAllocationCallbacks* pAllocator = DE_NULL)
209                 : supportedExtensions   (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
210                                                                                                                                           DE_NULL))
211                 , instance                              (createInstanceWithWsi(context.getPlatformInterface(),
212                                                                                                            supportedExtensions,
213                                                                                                            wsiType,
214                                                                                                            extensions,
215                                                                                                            pAllocator))
216                 , vki                                   (context.getPlatformInterface(), *instance)
217         {}
218 };
219
220 MovePtr<Display> createDisplay (const vk::Platform&     platform,
221                                                                 const Extensions&       supportedExtensions,
222                                                                 Type                            wsiType)
223 {
224         try
225         {
226                 return MovePtr<Display>(platform.createWsiDisplay(wsiType));
227         }
228         catch (const tcu::NotSupportedError& e)
229         {
230                 if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))))
231                 {
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());
235                 }
236                 else
237                         throw;
238         }
239 }
240
241 MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
242 {
243         try
244         {
245                 return MovePtr<Window>(display.createWindow(initialSize));
246         }
247         catch (const tcu::NotSupportedError& e)
248         {
249                 // See createDisplay - assuming that wsi::Display was supported platform port
250                 // should also support creating a window.
251                 throw tcu::TestError(e.getMessage());
252         }
253 }
254
255 struct NativeObjects
256 {
257         const UniquePtr<Display>        display;
258         const UniquePtr<Window>         window;
259
260         NativeObjects (Context&                         context,
261                                    const Extensions&    supportedExtensions,
262                                    Type                                 wsiType,
263                                    const Maybe<UVec2>&  initialWindowSize = tcu::nothing<UVec2>())
264                 : display       (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
265                 , window        (createWindow(*display, initialWindowSize))
266         {}
267 };
268
269 tcu::TestStatus createSurfaceTest (Context& context, Type wsiType)
270 {
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));
274
275         return tcu::TestStatus::pass("Creating surface succeeded");
276 }
277
278 tcu::TestStatus createSurfaceCustomAllocatorTest (Context& context, Type wsiType)
279 {
280         AllocationCallbackRecorder      allocationRecorder      (getSystemAllocator());
281         tcu::TestLog&                           log                                     = context.getTestContext().getLog();
282
283         {
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,
288                                                                                                                            wsiType,
289                                                                                                                            *native.display,
290                                                                                                                            *native.window,
291                                                                                                                            allocationRecorder.getCallbacks()));
292
293                 if (!validateAndLog(log,
294                                                         allocationRecorder,
295                                                         (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)         |
296                                                         (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
297                         return tcu::TestStatus::fail("Detected invalid system allocation callback");
298         }
299
300         if (!validateAndLog(log, allocationRecorder, 0u))
301                 return tcu::TestStatus::fail("Detected invalid system allocation callback");
302
303         if (allocationRecorder.getRecordsBegin() == allocationRecorder.getRecordsEnd())
304                 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
305         else
306                 return tcu::TestStatus::pass("Creating surface succeeded using custom allocator");
307 }
308
309 tcu::TestStatus createSurfaceSimulateOOMTest (Context& context, Type wsiType)
310 {
311         tcu::TestLog&   log     = context.getTestContext().getLog();
312
313         for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 1024u; ++numPassingAllocs)
314         {
315                 AllocationCallbackRecorder      allocationRecorder      (getSystemAllocator());
316                 DeterministicFailAllocator      failingAllocator        (allocationRecorder.getCallbacks(),
317                                                                                                                  DeterministicFailAllocator::MODE_DO_NOT_COUNT,
318                                                                                                                  0);
319                 bool                                            gotOOM                          = false;
320
321                 log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
322
323                 try
324                 {
325                         const InstanceHelper            instHelper      (context, wsiType, failingAllocator.getCallbacks());
326
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);
330
331                         const NativeObjects                     native          (context, instHelper.supportedExtensions, wsiType);
332                         const Unique<VkSurfaceKHR>      surface         (createSurface(instHelper.vki,
333                                                                                                                                    *instHelper.instance,
334                                                                                                                                    wsiType,
335                                                                                                                                    *native.display,
336                                                                                                                                    *native.window,
337                                                                                                                                    failingAllocator.getCallbacks()));
338
339                         if (!validateAndLog(log,
340                                                                 allocationRecorder,
341                                                                 (1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT)         |
342                                                                 (1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
343                                 return tcu::TestStatus::fail("Detected invalid system allocation callback");
344                 }
345                 catch (const OutOfMemoryError& e)
346                 {
347                         log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
348                         gotOOM = true;
349                 }
350
351                 if (!validateAndLog(log, allocationRecorder, 0u))
352                         return tcu::TestStatus::fail("Detected invalid system allocation callback");
353
354                 if (!gotOOM)
355                 {
356                         log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
357
358                         if (numPassingAllocs == 0)
359                                 return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
360                         else
361                                 return tcu::TestStatus::pass("OOM simulation completed");
362                 }
363         }
364
365         return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating surface did not succeed, callback limit exceeded");
366 }
367
368 deUint32 getNumQueueFamilies (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
369 {
370         deUint32        numFamilies             = 0;
371
372         vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
373
374         return numFamilies;
375 }
376
377 tcu::TestStatus querySurfaceSupportTest (Context& context, Type wsiType)
378 {
379         tcu::TestLog&                                   log                                             = context.getTestContext().getLog();
380         tcu::ResultCollector                    results                                 (log);
381
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);
386
387         // On Android surface must be supported by all devices and queue families
388         const bool                                              expectSupportedOnAll    = wsiType == TYPE_ANDROID;
389
390         for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
391         {
392                 const VkPhysicalDevice          physicalDevice          = physicalDevices[deviceNdx];
393                 const deUint32                          numQueueFamilies        = getNumQueueFamilies(instHelper.vki, physicalDevice);
394
395                 for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
396                 {
397                         const VkBool32  isSupported             = getPhysicalDeviceSurfaceSupport(instHelper.vki, physicalDevice, queueFamilyNdx, *surface);
398
399                         log << TestLog::Message << "Device " << deviceNdx << ", queue family " << queueFamilyNdx << ": "
400                                                                         << (isSupported == VK_FALSE ? "NOT " : "") << "supported"
401                                 << TestLog::EndMessage;
402
403                         if (expectSupportedOnAll && !isSupported)
404                                 results.fail("Surface must be supported by all devices and queue families");
405                 }
406         }
407
408         return tcu::TestStatus(results.getResult(), results.getMessage());
409 }
410
411 bool isSupportedByAnyQueue (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
412 {
413         const deUint32  numQueueFamilies        = getNumQueueFamilies(vki, physicalDevice);
414
415         for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
416         {
417                 if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
418                         return true;
419         }
420
421         return false;
422 }
423
424 void validateSurfaceCapabilities (tcu::ResultCollector& results, const VkSurfaceCapabilitiesKHR& capabilities)
425 {
426         results.check(capabilities.minImageCount > 0,
427                                   "minImageCount must be larger than 0");
428
429         results.check(capabilities.minImageExtent.width > 0 &&
430                                   capabilities.minImageExtent.height > 0,
431                                   "minImageExtent dimensions must be larger than 0");
432
433         results.check(capabilities.maxImageExtent.width > 0 &&
434                                   capabilities.maxImageExtent.height > 0,
435                                   "maxImageExtent dimensions must be larger than 0");
436
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");
440
441         if (capabilities.currentExtent.width != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC ||
442                 capabilities.currentExtent.height != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC)
443         {
444                 results.check(capabilities.currentExtent.width > 0 &&
445                                           capabilities.currentExtent.height > 0,
446                                           "currentExtent dimensions must be larger than 0");
447
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");
451         }
452
453         results.check(capabilities.maxImageArrayLayers > 0,
454                                   "maxImageArrayLayers must be larger than 0");
455
456         results.check((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
457                                   "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT must be set in supportedUsageFlags");
458
459         results.check(capabilities.supportedTransforms != 0,
460                                   "At least one transform must be supported");
461
462         results.check(dePop32(capabilities.currentTransform) != 0,
463                                   "Invalid currentTransform");
464
465         results.check((capabilities.supportedTransforms & capabilities.currentTransform) != 0,
466                                   "currentTransform is not supported by surface");
467
468         results.check(capabilities.supportedCompositeAlpha != 0,
469                                   "At least one alpha mode must be supported");
470 }
471
472 tcu::TestStatus querySurfaceCapabilitiesTest (Context& context, Type wsiType)
473 {
474         tcu::TestLog&                                   log                                             = context.getTestContext().getLog();
475         tcu::ResultCollector                    results                                 (log);
476
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);
481
482         for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
483         {
484                 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
485                 {
486                         const VkSurfaceCapabilitiesKHR  capabilities    = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
487                                                                                                                                                                                                    physicalDevices[deviceNdx],
488                                                                                                                                                                                                    *surface);
489
490                         log << TestLog::Message << "Device " << deviceNdx << ": " << capabilities << TestLog::EndMessage;
491
492                         validateSurfaceCapabilities(results, capabilities);
493                 }
494                 // else skip query as surface is not supported by the device
495         }
496
497         return tcu::TestStatus(results.getResult(), results.getMessage());
498 }
499
500 tcu::TestStatus querySurfaceCapabilities2Test (Context& context, Type wsiType)
501 {
502         tcu::TestLog&                                   log                                             = context.getTestContext().getLog();
503         tcu::ResultCollector                    results                                 (log);
504
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);
509
510         for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
511         {
512                 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
513                 {
514                         const VkSurfaceCapabilitiesKHR  refCapabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
515                                                                                                                                                                                                    physicalDevices[deviceNdx],
516                                                                                                                                                                                                    *surface);
517                         VkSurfaceCapabilities2KHR               extCapabilities;
518
519                         deMemset(&extCapabilities, 0xcd, sizeof(VkSurfaceCapabilities2KHR));
520                         extCapabilities.sType   = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
521                         extCapabilities.pNext   = DE_NULL;
522
523                         {
524                                 const VkPhysicalDeviceSurfaceInfo2KHR   surfaceInfo     =
525                                 {
526                                         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
527                                         DE_NULL,
528                                         *surface
529                                 };
530                                 VkPhysicalDeviceSurfaceInfo2KHR                 infoCopy;
531
532                                 deMemcpy(&infoCopy, &surfaceInfo, sizeof(VkPhysicalDeviceSurfaceInfo2KHR));
533
534                                 VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevices[deviceNdx], &surfaceInfo, &extCapabilities));
535
536                                 results.check(deMemoryEqual(&surfaceInfo, &infoCopy, sizeof(VkPhysicalDeviceSurfaceInfo2KHR)) == DE_TRUE, "Driver wrote into input struct");
537                         }
538
539                         results.check(extCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR &&
540                                                   extCapabilities.pNext == DE_NULL,
541                                                   "sType/pNext modified");
542
543                         if (refCapabilities != extCapabilities.surfaceCapabilities)
544                         {
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");
551                         }
552                 }
553         }
554
555         return tcu::TestStatus(results.getResult(), results.getMessage());
556 }
557
558 void validateSurfaceFormats (tcu::ResultCollector& results, Type wsiType, const vector<VkSurfaceFormatKHR>& formats)
559 {
560         const VkSurfaceFormatKHR*       requiredFormats         = DE_NULL;
561         size_t                                          numRequiredFormats      = 0;
562
563         if (wsiType == TYPE_ANDROID)
564         {
565                 static const VkSurfaceFormatKHR s_androidFormats[] =
566                 {
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       }
570                 };
571
572                 requiredFormats         = &s_androidFormats[0];
573                 numRequiredFormats      = DE_LENGTH_OF_ARRAY(s_androidFormats);
574         }
575
576         for (size_t ndx = 0; ndx < numRequiredFormats; ++ndx)
577         {
578                 const VkSurfaceFormatKHR&       requiredFormat  = requiredFormats[ndx];
579
580                 if (!de::contains(formats.begin(), formats.end(), requiredFormat))
581                         results.fail(de::toString(requiredFormat) + " not supported");
582         }
583
584         // Check that there are no duplicates
585         for (size_t ndx = 1; ndx < formats.size(); ++ndx)
586         {
587                 if (de::contains(formats.begin(), formats.begin() + ndx, formats[ndx]))
588                         results.fail("Found duplicate entry " + de::toString(formats[ndx]));
589         }
590 }
591
592 tcu::TestStatus querySurfaceFormatsTest (Context& context, Type wsiType)
593 {
594         tcu::TestLog&                                   log                             = context.getTestContext().getLog();
595         tcu::ResultCollector                    results                 (log);
596
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);
601
602         for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
603         {
604                 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
605                 {
606                         const vector<VkSurfaceFormatKHR>        formats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
607                                                                                                                                                                                   physicalDevices[deviceNdx],
608                                                                                                                                                                                   *surface);
609
610                         log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(formats.begin(), formats.end()) << TestLog::EndMessage;
611
612                         validateSurfaceFormats(results, wsiType, formats);
613                         CheckPhysicalDeviceSurfaceFormatsIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, formats.size());
614                 }
615                 // else skip query as surface is not supported by the device
616         }
617
618         return tcu::TestStatus(results.getResult(), results.getMessage());
619 }
620
621 tcu::TestStatus querySurfaceFormats2Test (Context& context, Type wsiType)
622 {
623         tcu::TestLog&                                   log                             = context.getTestContext().getLog();
624         tcu::ResultCollector                    results                 (log);
625
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);
630
631         for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
632         {
633                 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
634                 {
635                         const vector<VkSurfaceFormatKHR>                refFormats      = getPhysicalDeviceSurfaceFormats(instHelper.vki,
636                                                                                                                                                                                                   physicalDevices[deviceNdx],
637                                                                                                                                                                                                   *surface);
638                         const VkPhysicalDeviceSurfaceInfo2KHR   surfaceInfo     =
639                         {
640                                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
641                                 DE_NULL,
642                                 *surface
643                         };
644                         deUint32                                                                numFormats      = 0;
645
646                         VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, DE_NULL));
647
648                         if ((size_t)numFormats != refFormats.size())
649                                 results.fail("vkGetPhysicalDeviceSurfaceFormats2KHR() returned different number of formats");
650
651                         if (numFormats > 0)
652                         {
653                                 vector<VkSurfaceFormat2KHR>     formats (numFormats);
654
655                                 for (size_t ndx = 0; ndx < formats.size(); ++ndx)
656                                 {
657                                         formats[ndx].sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
658                                         formats[ndx].pNext = DE_NULL;
659                                 }
660
661                                 VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, &formats[0]));
662
663                                 if ((size_t)numFormats != formats.size())
664                                         results.fail("Format count changed between calls");
665
666                                 {
667                                         vector<VkSurfaceFormatKHR>      extFormats      (formats.size());
668
669                                         for (size_t ndx = 0; ndx < formats.size(); ++ndx)
670                                         {
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;
675                                         }
676
677                                         for (size_t ndx = 0; ndx < refFormats.size(); ++ndx)
678                                         {
679                                                 if (!de::contains(extFormats.begin(), extFormats.end(), refFormats[ndx]))
680                                                         results.fail(de::toString(refFormats[ndx]) + " missing from extended query");
681                                         }
682                                 }
683
684                                 // Check VK_INCOMPLETE
685                                 {
686                                         vector<VkSurfaceFormat2KHR>     formatsClone    (formats);
687                                         deUint32                                        numToSupply             = numFormats/2;
688                                         VkResult                                        queryResult;
689
690                                         ValidateQueryBits::fillBits(formatsClone.begin() + numToSupply, formatsClone.end());
691
692                                         queryResult = instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numToSupply, &formatsClone[0]);
693
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");
697
698                                         for (size_t ndx = 0; ndx < (size_t)numToSupply; ++ndx)
699                                         {
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");
704                                         }
705                                 }
706                         }
707                 }
708                 // else skip query as surface is not supported by the device
709         }
710
711         return tcu::TestStatus(results.getResult(), results.getMessage());
712 }
713
714 void validateSurfacePresentModes (tcu::ResultCollector& results, Type wsiType, const vector<VkPresentModeKHR>& modes)
715 {
716         results.check(de::contains(modes.begin(), modes.end(), VK_PRESENT_MODE_FIFO_KHR),
717                                   "VK_PRESENT_MODE_FIFO_KHR is not supported");
718
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");
722 }
723
724 tcu::TestStatus querySurfacePresentModesTest (Context& context, Type wsiType)
725 {
726         tcu::TestLog&                                   log                             = context.getTestContext().getLog();
727         tcu::ResultCollector                    results                 (log);
728
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);
733
734         for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
735         {
736                 if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
737                 {
738                         const vector<VkPresentModeKHR>  modes   = getPhysicalDeviceSurfacePresentModes(instHelper.vki, physicalDevices[deviceNdx], *surface);
739
740                         log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(modes.begin(), modes.end()) << TestLog::EndMessage;
741
742                         validateSurfacePresentModes(results, wsiType, modes);
743                         CheckPhysicalDeviceSurfacePresentModesIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, modes.size());
744                 }
745                 // else skip query as surface is not supported by the device
746         }
747
748         return tcu::TestStatus(results.getResult(), results.getMessage());
749 }
750
751 tcu::TestStatus createSurfaceInitialSizeTest (Context& context, Type wsiType)
752 {
753         tcu::TestLog&                                   log                             = context.getTestContext().getLog();
754         tcu::ResultCollector                    results                 (log);
755
756         const InstanceHelper                    instHelper              (context, wsiType);
757
758         const UniquePtr<Display>                nativeDisplay   (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
759                                                                                                                                    instHelper.supportedExtensions,
760                                                                                                                                    wsiType));
761
762         const vector<VkPhysicalDevice>  physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
763         const UVec2                                             sizes[]                 =
764         {
765                 UVec2(64, 64),
766                 UVec2(124, 119),
767                 UVec2(256, 512)
768         };
769
770         DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE);
771
772         for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
773         {
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));
777
778                 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
779                 {
780                         if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
781                         {
782                                 const VkSurfaceCapabilitiesKHR  capabilities    = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
783
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));
788                         }
789                 }
790         }
791
792         return tcu::TestStatus(results.getResult(), results.getMessage());
793 }
794
795 tcu::TestStatus resizeSurfaceTest (Context& context, Type wsiType)
796 {
797         tcu::TestLog&                                   log                             = context.getTestContext().getLog();
798         tcu::ResultCollector                    results                 (log);
799
800         const InstanceHelper                    instHelper              (context, wsiType);
801
802         const UniquePtr<Display>                nativeDisplay   (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
803                                                                                                                                    instHelper.supportedExtensions,
804                                                                                                                                    wsiType));
805         UniquePtr<Window>                               nativeWindow    (createWindow(*nativeDisplay, tcu::nothing<UVec2>()));
806
807         const vector<VkPhysicalDevice>  physicalDevices = enumeratePhysicalDevices(instHelper.vki, *instHelper.instance);
808         const Unique<VkSurfaceKHR>              surface                 (createSurface(instHelper.vki, *instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
809
810         const UVec2                                             sizes[]                 =
811         {
812                 UVec2(64, 64),
813                 UVec2(124, 119),
814                 UVec2(256, 512)
815         };
816
817         DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_RESIZE_WINDOW);
818
819         for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
820         {
821                 const UVec2             testSize        = sizes[sizeNdx];
822
823                 try
824                 {
825                         nativeWindow->resize(testSize);
826                 }
827                 catch (const tcu::Exception& e)
828                 {
829                         // Make sure all exception types result in a test failure
830                         results.fail(e.getMessage());
831                 }
832
833                 for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
834                 {
835                         if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
836                         {
837                                 const VkSurfaceCapabilitiesKHR  capabilities    = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
838
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));
843                         }
844                 }
845         }
846
847         return tcu::TestStatus(results.getResult(), results.getMessage());
848 }
849
850 tcu::TestStatus destroyNullHandleSurfaceTest (Context& context, Type wsiType)
851 {
852         const InstanceHelper    instHelper      (context, wsiType);
853         const VkSurfaceKHR              nullHandle      = DE_NULL;
854
855         // Default allocator
856         instHelper.vki.destroySurfaceKHR(*instHelper.instance, nullHandle, DE_NULL);
857
858         // Custom allocator
859         {
860                 AllocationCallbackRecorder      recordingAllocator      (getSystemAllocator(), 1u);
861
862                 instHelper.vki.destroySurfaceKHR(*instHelper.instance, nullHandle, recordingAllocator.getCallbacks());
863
864                 if (recordingAllocator.getNumRecords() != 0u)
865                         return tcu::TestStatus::fail("Implementation allocated/freed the memory");
866         }
867
868         return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
869 }
870
871 } // anonymous
872
873 void createSurfaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
874 {
875         const PlatformProperties&       platformProperties      = getPlatformProperties(wsiType);
876
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);
887
888         if ((platformProperties.features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE) != 0)
889                 addFunctionCase(testGroup, "initial_size",      "Create surface with initial window size set",  createSurfaceInitialSizeTest,   wsiType);
890
891         if ((platformProperties.features & PlatformProperties::FEATURE_RESIZE_WINDOW) != 0)
892                 addFunctionCase(testGroup, "resize",            "Resize window and surface",                                    resizeSurfaceTest,                              wsiType);
893 }
894
895 } // wsi
896 } // vkt