blob: 861c26c4e664e6f6c1638501800311a2edd12c96 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief VkSurface Tests
*//*--------------------------------------------------------------------*/
#include "vktWsiSurfaceTests.hpp"
#include "vktTestCaseUtil.hpp"
#include "vktTestGroupUtil.hpp"
#include "vktCustomInstancesDevices.hpp"
#include "vkDefs.hpp"
#include "vkPlatform.hpp"
#include "vkStrUtil.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkDeviceUtil.hpp"
#include "vkPrograms.hpp"
#include "vkTypeUtil.hpp"
#include "vkWsiPlatform.hpp"
#include "vkWsiUtil.hpp"
#include "vkAllocationCallbackUtil.hpp"
#include "vkQueryUtil.hpp"
#include "tcuTestLog.hpp"
#include "tcuFormatUtil.hpp"
#include "tcuPlatform.hpp"
#include "tcuResultCollector.hpp"
#include "tcuCommandLine.hpp"
#include "deUniquePtr.hpp"
#include "deStringUtil.hpp"
#include "deMemory.h"
namespace vk
{
inline bool operator!= (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
{
return (a.format != b.format) || (a.colorSpace != b.colorSpace);
}
inline bool operator== (const VkSurfaceFormatKHR& a, const VkSurfaceFormatKHR& b)
{
return !(a != b);
}
inline bool operator!= (const VkExtent2D& a, const VkExtent2D& b)
{
return (a.width != b.width) || (a.height != b.height);
}
inline bool operator!= (const VkSurfaceCapabilitiesKHR& a, const VkSurfaceCapabilitiesKHR& b)
{
return (a.minImageCount != b.minImageCount) ||
(a.maxImageCount != b.maxImageCount) ||
(a.currentExtent != b.currentExtent) ||
(a.minImageExtent != b.minImageExtent) ||
(a.maxImageExtent != b.maxImageExtent) ||
(a.maxImageArrayLayers != b.maxImageArrayLayers) ||
(a.supportedTransforms != b.supportedTransforms) ||
(a.currentTransform != b.currentTransform) ||
(a.supportedCompositeAlpha != b.supportedCompositeAlpha) ||
(a.supportedUsageFlags != b.supportedUsageFlags);
}
} // vk
namespace vkt
{
namespace wsi
{
namespace
{
using namespace vk;
using namespace vk::wsi;
using tcu::TestLog;
using tcu::Maybe;
using tcu::UVec2;
using de::MovePtr;
using de::UniquePtr;
using std::string;
using std::vector;
enum
{
SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC = 0xffffffff
};
enum
{
GUARD_SIZE = 0x20, //!< Number of bytes to check
GUARD_VALUE = 0xcd, //!< Data pattern
};
template<typename T>
class CheckIncompleteResult
{
public:
virtual ~CheckIncompleteResult (void) {}
virtual void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, T* data) = 0;
void operator() (tcu::ResultCollector& results,
const InstanceInterface& vki,
const VkPhysicalDevice physDevice,
const VkSurfaceKHR surface,
const std::size_t expectedCompleteSize)
{
if (expectedCompleteSize == 0)
return;
vector<T> outputData (expectedCompleteSize);
const deUint32 usedSize = static_cast<deUint32>(expectedCompleteSize / 3);
ValidateQueryBits::fillBits(outputData.begin(), outputData.end()); // unused entries should have this pattern intact
m_count = usedSize;
m_result = VK_SUCCESS;
getResult(vki, physDevice, surface, &outputData[0]); // update m_count and m_result
if (m_count != usedSize || m_result != VK_INCOMPLETE || !ValidateQueryBits::checkBits(outputData.begin() + m_count, outputData.end()))
results.fail("Query didn't return VK_INCOMPLETE");
}
protected:
deUint32 m_count;
VkResult m_result;
};
struct CheckPhysicalDeviceSurfaceFormatsIncompleteResult : public CheckIncompleteResult<VkSurfaceFormatKHR>
{
void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkSurfaceFormatKHR* data)
{
m_result = vki.getPhysicalDeviceSurfaceFormatsKHR(physDevice, surface, &m_count, data);
}
};
struct CheckPhysicalDeviceSurfacePresentModesIncompleteResult : public CheckIncompleteResult<VkPresentModeKHR>
{
void getResult (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const VkSurfaceKHR surface, VkPresentModeKHR* data)
{
m_result = vki.getPhysicalDeviceSurfacePresentModesKHR(physDevice, surface, &m_count, data);
}
};
typedef vector<VkExtensionProperties> Extensions;
CustomInstance createInstanceWithWsi (Context& context,
Type wsiType,
const vector<string> extraExtensions,
const VkAllocationCallbacks* pAllocator = DE_NULL)
{
const deUint32 version = context.getUsedApiVersion();
vector<string> extensions = extraExtensions;
extensions.push_back("VK_KHR_surface");
extensions.push_back(getExtensionName(wsiType));
vector<string> instanceExtensions;
for (const auto& ext : extensions)
{
if (!context.isInstanceFunctionalitySupported(ext))
TCU_THROW(NotSupportedError, (ext + " is not supported").c_str());
if (!isCoreInstanceExtension(version, ext))
instanceExtensions.push_back(ext);
}
return vkt::createCustomInstanceWithExtensions(context, instanceExtensions, pAllocator);
}
struct InstanceHelper
{
const vector<VkExtensionProperties> supportedExtensions;
CustomInstance instance;
const InstanceDriver& vki;
InstanceHelper (Context& context, Type wsiType, const VkAllocationCallbacks* pAllocator = DE_NULL)
: supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
DE_NULL))
, instance (createInstanceWithWsi(context,
wsiType,
vector<string>(),
pAllocator))
, vki (instance.getDriver())
{}
InstanceHelper (Context& context, Type wsiType, const vector<string>& extensions, const VkAllocationCallbacks* pAllocator = DE_NULL)
: supportedExtensions (enumerateInstanceExtensionProperties(context.getPlatformInterface(),
DE_NULL))
, instance (createInstanceWithWsi(context,
wsiType,
extensions,
pAllocator))
, vki (instance.getDriver())
{}
};
MovePtr<Display> createDisplay (const vk::Platform& platform,
const Extensions& supportedExtensions,
Type wsiType)
{
try
{
return MovePtr<Display>(platform.createWsiDisplay(wsiType));
}
catch (const tcu::NotSupportedError& e)
{
if (isExtensionSupported(supportedExtensions, RequiredExtension(getExtensionName(wsiType))) &&
platform.hasDisplay(wsiType))
{
// If VK_KHR_{platform}_surface was supported, vk::Platform implementation
// must support creating native display & window for that WSI type.
throw tcu::TestError(e.getMessage());
}
else
throw;
}
}
MovePtr<Window> createWindow (const Display& display, const Maybe<UVec2>& initialSize)
{
try
{
return MovePtr<Window>(display.createWindow(initialSize));
}
catch (const tcu::NotSupportedError& e)
{
// See createDisplay - assuming that wsi::Display was supported platform port
// should also support creating a window.
throw tcu::TestError(e.getMessage());
}
}
struct NativeObjects
{
const UniquePtr<Display> display;
const UniquePtr<Window> window;
NativeObjects (Context& context,
const Extensions& supportedExtensions,
Type wsiType,
const Maybe<UVec2>& initialWindowSize = tcu::nothing<UVec2>())
: display (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(), supportedExtensions, wsiType))
, window (createWindow(*display, initialWindowSize))
{}
};
tcu::TestStatus createSurfaceTest (Context& context, Type wsiType)
{
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
return tcu::TestStatus::pass("Creating surface succeeded");
}
tcu::TestStatus querySurfaceCounterTest (Context& context, Type wsiType)
{
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vk::InstanceInterface& vki = context.getInstanceInterface();
const vk::VkPhysicalDevice physicalDevice = context.getPhysicalDevice();
if (!isInstanceExtensionSupported(context.getUsedApiVersion(), context.getInstanceExtensions(), "VK_EXT_display_surface_counter"))
TCU_THROW(NotSupportedError, "VK_EXT_display_surface_counter not supported");
const vk::VkSurfaceCapabilities2EXT capsExt = getPhysicalDeviceSurfaceCapabilities2EXT (vki, physicalDevice, surface.get());
const vk::VkSurfaceCapabilitiesKHR capsKhr = getPhysicalDeviceSurfaceCapabilities (vki, physicalDevice, surface.get());
if (!sameSurfaceCapabilities(capsKhr, capsExt))
{
return tcu::TestStatus::fail("KHR and EXT surface capabilities do not match");
}
if (capsExt.supportedSurfaceCounters != 0)
{
return tcu::TestStatus::fail("supportedSurfaceCounters nonzero (" + de::toString(capsExt.supportedSurfaceCounters) + ") for non-display surface");
}
return tcu::TestStatus::pass("Pass");
}
tcu::TestStatus createSurfaceCustomAllocatorTest (Context& context, Type wsiType)
{
AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
tcu::TestLog& log = context.getTestContext().getLog();
{
const InstanceHelper instHelper (context, wsiType, allocationRecorder.getCallbacks());
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
instHelper.instance,
wsiType,
*native.display,
*native.window,
allocationRecorder.getCallbacks()));
if (!validateAndLog(log,
allocationRecorder,
(1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT) |
(1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
return tcu::TestStatus::fail("Detected invalid system allocation callback");
}
if (!validateAndLog(log, allocationRecorder, 0u))
return tcu::TestStatus::fail("Detected invalid system allocation callback");
if (allocationRecorder.getRecordsBegin() == allocationRecorder.getRecordsEnd())
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
else
return tcu::TestStatus::pass("Creating surface succeeded using custom allocator");
}
tcu::TestStatus createSurfaceSimulateOOMTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
for (deUint32 numPassingAllocs = 0; numPassingAllocs <= 1024u; ++numPassingAllocs)
{
AllocationCallbackRecorder allocationRecorder (getSystemAllocator());
DeterministicFailAllocator failingAllocator (allocationRecorder.getCallbacks(),
DeterministicFailAllocator::MODE_DO_NOT_COUNT,
0);
bool gotOOM = false;
log << TestLog::Message << "Testing with " << numPassingAllocs << " first allocations succeeding" << TestLog::EndMessage;
try
{
const InstanceHelper instHelper (context, wsiType, failingAllocator.getCallbacks());
// OOM is not simulated for VkInstance as we don't want to spend time
// testing OOM paths inside instance creation.
failingAllocator.reset(DeterministicFailAllocator::MODE_COUNT_AND_FAIL, numPassingAllocs);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki,
instHelper.instance,
wsiType,
*native.display,
*native.window,
failingAllocator.getCallbacks()));
if (!validateAndLog(log,
allocationRecorder,
(1u<<VK_SYSTEM_ALLOCATION_SCOPE_OBJECT) |
(1u<<VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE)))
return tcu::TestStatus::fail("Detected invalid system allocation callback");
}
catch (const OutOfMemoryError& e)
{
log << TestLog::Message << "Got " << e.getError() << TestLog::EndMessage;
gotOOM = true;
}
if (!validateAndLog(log, allocationRecorder, 0u))
return tcu::TestStatus::fail("Detected invalid system allocation callback");
if (!gotOOM)
{
log << TestLog::Message << "Creating surface succeeded!" << TestLog::EndMessage;
if (numPassingAllocs == 0)
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Allocation callbacks were not used");
else
return tcu::TestStatus::pass("OOM simulation completed");
}
}
return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Creating surface did not succeed, callback limit exceeded");
}
deUint32 getNumQueueFamilies (const InstanceInterface& vki, VkPhysicalDevice physicalDevice)
{
deUint32 numFamilies = 0;
vki.getPhysicalDeviceQueueFamilyProperties(physicalDevice, &numFamilies, DE_NULL);
return numFamilies;
}
tcu::TestStatus querySurfaceSupportTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
// On Android surface must be supported by all devices and queue families
const bool expectSupportedOnAll = wsiType == TYPE_ANDROID;
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
const VkPhysicalDevice physicalDevice = physicalDevices[deviceNdx];
const deUint32 numQueueFamilies = getNumQueueFamilies(instHelper.vki, physicalDevice);
for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
{
const VkBool32 isSupported = getPhysicalDeviceSurfaceSupport(instHelper.vki, physicalDevice, queueFamilyNdx, *surface);
log << TestLog::Message << "Device " << deviceNdx << ", queue family " << queueFamilyNdx << ": "
<< (isSupported == VK_FALSE ? "NOT " : "") << "supported"
<< TestLog::EndMessage;
if (expectSupportedOnAll && !isSupported)
results.fail("Surface must be supported by all devices and queue families");
}
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus queryPresentationSupportTest(Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
const VkPhysicalDevice physicalDevice = physicalDevices[deviceNdx];
const deUint32 numQueueFamilies = getNumQueueFamilies(instHelper.vki, physicalDevice);
for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
{
VkBool32 isPresentationSupported = getPhysicalDevicePresentationSupport(instHelper.vki, physicalDevice, queueFamilyNdx, wsiType, *native.display);
VkBool32 isSurfaceSupported = getPhysicalDeviceSurfaceSupport(instHelper.vki, physicalDevice, queueFamilyNdx, *surface);
log << TestLog::Message << "Device " << deviceNdx << ", queue family " << queueFamilyNdx << ": presentation "
<< (isPresentationSupported == VK_FALSE ? "NOT " : "") << "supported. Surface "
<< (isSurfaceSupported == VK_FALSE ? "NOT " : "") << "supported."
<< TestLog::EndMessage;
if (isPresentationSupported != isSurfaceSupported)
results.fail("Presentation support is different from surface support");
}
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
bool isSupportedByAnyQueue (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface)
{
const deUint32 numQueueFamilies = getNumQueueFamilies(vki, physicalDevice);
for (deUint32 queueFamilyNdx = 0; queueFamilyNdx < numQueueFamilies; ++queueFamilyNdx)
{
if (getPhysicalDeviceSurfaceSupport(vki, physicalDevice, queueFamilyNdx, surface) != VK_FALSE)
return true;
}
return false;
}
void validateSurfaceCapabilities (tcu::ResultCollector& results, const VkSurfaceCapabilitiesKHR& capabilities)
{
results.check(capabilities.minImageCount > 0,
"minImageCount must be larger than 0");
results.check(capabilities.minImageExtent.width > 0 &&
capabilities.minImageExtent.height > 0,
"minImageExtent dimensions must be larger than 0");
results.check(capabilities.maxImageExtent.width > 0 &&
capabilities.maxImageExtent.height > 0,
"maxImageExtent dimensions must be larger than 0");
results.check(capabilities.minImageExtent.width <= capabilities.maxImageExtent.width &&
capabilities.minImageExtent.height <= capabilities.maxImageExtent.height,
"maxImageExtent must be larger or equal to minImageExtent");
if (capabilities.currentExtent.width != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC ||
capabilities.currentExtent.height != SURFACE_EXTENT_DETERMINED_BY_SWAPCHAIN_MAGIC)
{
results.check(capabilities.currentExtent.width > 0 &&
capabilities.currentExtent.height > 0,
"currentExtent dimensions must be larger than 0");
results.check(de::inRange(capabilities.currentExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width) &&
de::inRange(capabilities.currentExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height),
"currentExtent is not in supported extent limits");
}
results.check(capabilities.maxImageArrayLayers > 0,
"maxImageArrayLayers must be larger than 0");
results.check((capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0,
"VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT must be set in supportedUsageFlags");
results.check(capabilities.supportedTransforms != 0,
"At least one transform must be supported");
results.check(dePop32(capabilities.currentTransform) != 0,
"Invalid currentTransform");
results.check((capabilities.supportedTransforms & capabilities.currentTransform) != 0,
"currentTransform is not supported by surface");
results.check(capabilities.supportedCompositeAlpha != 0,
"At least one alpha mode must be supported");
}
tcu::TestStatus querySurfaceCapabilitiesTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
physicalDevices[deviceNdx],
*surface);
log << TestLog::Message << "Device " << deviceNdx << ": " << capabilities << TestLog::EndMessage;
validateSurfaceCapabilities(results, capabilities);
}
// else skip query as surface is not supported by the device
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus querySurfaceCapabilities2Test (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
const VkSurfaceCapabilitiesKHR refCapabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki,
physicalDevices[deviceNdx],
*surface);
VkSurfaceCapabilities2KHR extCapabilities;
deMemset(&extCapabilities, 0xcd, sizeof(VkSurfaceCapabilities2KHR));
extCapabilities.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
extCapabilities.pNext = DE_NULL;
{
const VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
DE_NULL,
*surface
};
VkPhysicalDeviceSurfaceInfo2KHR infoCopy;
deMemcpy(&infoCopy, &surfaceInfo, sizeof(VkPhysicalDeviceSurfaceInfo2KHR));
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevices[deviceNdx], &surfaceInfo, &extCapabilities));
results.check(deMemoryEqual(&surfaceInfo, &infoCopy, sizeof(VkPhysicalDeviceSurfaceInfo2KHR)) == DE_TRUE, "Driver wrote into input struct");
}
results.check(extCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR &&
extCapabilities.pNext == DE_NULL,
"sType/pNext modified");
if (refCapabilities != extCapabilities.surfaceCapabilities)
{
log << TestLog::Message
<< "Device " << deviceNdx
<< ": expected " << refCapabilities
<< ", got " << extCapabilities.surfaceCapabilities
<< TestLog::EndMessage;
results.fail("Mismatch between VK_KHR_surface and VK_KHR_surface2 query results");
}
}
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus querySurfaceProtectedCapabilitiesTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
vector<string> requiredExtensions;
requiredExtensions.push_back("VK_KHR_get_surface_capabilities2");
requiredExtensions.push_back("VK_KHR_surface_protected_capabilities");
const InstanceHelper instHelper (context, wsiType, requiredExtensions);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
VkSurfaceCapabilities2KHR extCapabilities;
VkSurfaceProtectedCapabilitiesKHR extProtectedCapabilities;
deMemset(&extProtectedCapabilities, 0xcd, sizeof(VkSurfaceProtectedCapabilitiesKHR));
extProtectedCapabilities.sType = VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
extProtectedCapabilities.pNext = DE_NULL;
deMemset(&extCapabilities, 0xcd, sizeof(VkSurfaceCapabilities2KHR));
extCapabilities.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
extCapabilities.pNext = &extProtectedCapabilities;
{
VkPhysicalDeviceSurfaceInfo2KHR infoCopy;
const VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
DE_NULL,
*surface
};
deMemcpy(&infoCopy, &surfaceInfo, sizeof(VkPhysicalDeviceSurfaceInfo2KHR));
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceCapabilities2KHR(physicalDevices[deviceNdx], &surfaceInfo, &extCapabilities));
results.check(deMemoryEqual(&surfaceInfo, &infoCopy, sizeof(VkPhysicalDeviceSurfaceInfo2KHR)) == DE_TRUE, "Driver wrote into input struct");
}
results.check(extCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR &&
extCapabilities.pNext == &extProtectedCapabilities,
"sType/pNext modified");
results.check(extProtectedCapabilities.sType == VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR &&
extProtectedCapabilities.pNext == DE_NULL,
"sType/pNext modified");
results.check(extProtectedCapabilities.supportsProtected == 0 ||
extProtectedCapabilities.supportsProtected == 1,
"supportsProtected ");
}
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
void validateSurfaceFormats (tcu::ResultCollector& results, Type wsiType, const vector<VkSurfaceFormatKHR>& formats)
{
const VkSurfaceFormatKHR* requiredFormats = DE_NULL;
size_t numRequiredFormats = 0;
if (wsiType == TYPE_ANDROID)
{
static const VkSurfaceFormatKHR s_androidFormats[] =
{
{ VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
{ VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR },
{ VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR }
};
requiredFormats = &s_androidFormats[0];
numRequiredFormats = DE_LENGTH_OF_ARRAY(s_androidFormats);
}
for (size_t ndx = 0; ndx < numRequiredFormats; ++ndx)
{
const VkSurfaceFormatKHR& requiredFormat = requiredFormats[ndx];
if (!de::contains(formats.begin(), formats.end(), requiredFormat))
results.fail(de::toString(requiredFormat) + " not supported");
}
// Check that there are no duplicates
for (size_t ndx = 1; ndx < formats.size(); ++ndx)
{
if (de::contains(formats.begin(), formats.begin() + ndx, formats[ndx]))
results.fail("Found duplicate entry " + de::toString(formats[ndx]));
}
}
tcu::TestStatus querySurfaceFormatsTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
deUint32 numFormats = 0;
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevices[deviceNdx], *surface, &numFormats, DE_NULL));
std::vector<VkSurfaceFormatKHR> formats (numFormats + 1);
if (numFormats > 0)
{
const deUint32 numFormatsOrig = numFormats;
// check if below call properly overwrites formats count
numFormats++;
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormatsKHR(physicalDevices[deviceNdx], *surface, &numFormats, &formats[0]));
if (numFormats != numFormatsOrig)
results.fail("Format count changed between calls");
}
formats.pop_back();
log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(formats.begin(), formats.end()) << TestLog::EndMessage;
validateSurfaceFormats(results, wsiType, formats);
CheckPhysicalDeviceSurfaceFormatsIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, formats.size());
}
// else skip query as surface is not supported by the device
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus querySurfaceFormats2Test (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_get_surface_capabilities2")));
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
const vector<VkSurfaceFormatKHR> refFormats = getPhysicalDeviceSurfaceFormats(instHelper.vki,
physicalDevices[deviceNdx],
*surface);
const VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo =
{
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
DE_NULL,
*surface
};
deUint32 numFormats = 0;
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, DE_NULL));
if ((size_t)numFormats != refFormats.size())
results.fail("vkGetPhysicalDeviceSurfaceFormats2KHR() returned different number of formats");
if (numFormats > 0)
{
vector<VkSurfaceFormat2KHR> formats (numFormats + 1);
for (size_t ndx = 0; ndx < formats.size(); ++ndx)
{
formats[ndx].sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
formats[ndx].pNext = DE_NULL;
}
const deUint32 numFormatsOrig = numFormats;
// check if below call properly overwrites formats count
numFormats++;
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numFormats, &formats[0]));
if ((size_t)numFormats != numFormatsOrig)
results.fail("Format count changed between calls");
formats.pop_back();
{
vector<VkSurfaceFormatKHR> extFormats (formats.size());
for (size_t ndx = 0; ndx < formats.size(); ++ndx)
{
results.check(formats[ndx].sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR &&
formats[ndx].pNext == DE_NULL,
"sType/pNext modified");
extFormats[ndx] = formats[ndx].surfaceFormat;
}
for (size_t ndx = 0; ndx < refFormats.size(); ++ndx)
{
if (!de::contains(extFormats.begin(), extFormats.end(), refFormats[ndx]))
results.fail(de::toString(refFormats[ndx]) + " missing from extended query");
}
}
// Check VK_INCOMPLETE
{
vector<VkSurfaceFormat2KHR> formatsClone (formats);
deUint32 numToSupply = numFormats/2;
VkResult queryResult;
ValidateQueryBits::fillBits(formatsClone.begin() + numToSupply, formatsClone.end());
queryResult = instHelper.vki.getPhysicalDeviceSurfaceFormats2KHR(physicalDevices[deviceNdx], &surfaceInfo, &numToSupply, &formatsClone[0]);
results.check(queryResult == VK_INCOMPLETE, "Expected VK_INCOMPLETE");
results.check(ValidateQueryBits::checkBits(formatsClone.begin() + numToSupply, formatsClone.end()),
"Driver wrote past last element");
for (size_t ndx = 0; ndx < (size_t)numToSupply; ++ndx)
{
results.check(formatsClone[ndx].sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR &&
formatsClone[ndx].pNext == DE_NULL &&
formatsClone[ndx].surfaceFormat == formats[ndx].surfaceFormat,
"Returned element " + de::toString(ndx) + " is different");
}
}
}
}
// else skip query as surface is not supported by the device
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
void validateSurfacePresentModes (tcu::ResultCollector& results, Type wsiType, const vector<VkPresentModeKHR>& modes)
{
results.check(de::contains(modes.begin(), modes.end(), VK_PRESENT_MODE_FIFO_KHR),
"VK_PRESENT_MODE_FIFO_KHR is not supported");
if (wsiType == TYPE_ANDROID)
results.check(de::contains(modes.begin(), modes.end(), VK_PRESENT_MODE_MAILBOX_KHR),
"VK_PRESENT_MODE_MAILBOX_KHR is not supported");
}
tcu::TestStatus querySurfacePresentModesTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType);
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
deUint32 numModes = 0;
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevices[deviceNdx], *surface, &numModes, DE_NULL));
vector<VkPresentModeKHR> modes (numModes + 1);
if (numModes > 0)
{
const deUint32 numModesOrig = numModes;
// check if below call properly overwrites mode count
numModes++;
VK_CHECK(instHelper.vki.getPhysicalDeviceSurfacePresentModesKHR(physicalDevices[deviceNdx], *surface, &numModes, &modes[0]));
if ((size_t)numModes != numModesOrig)
TCU_FAIL("Mode count changed between calls");
}
modes.pop_back();
log << TestLog::Message << "Device " << deviceNdx << ": " << tcu::formatArray(modes.begin(), modes.end()) << TestLog::EndMessage;
validateSurfacePresentModes(results, wsiType, modes);
CheckPhysicalDeviceSurfacePresentModesIncompleteResult()(results, instHelper.vki, physicalDevices[deviceNdx], *surface, modes.size());
}
// else skip query as surface is not supported by the device
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus queryDevGroupSurfacePresentCapabilitiesTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
const float queuePriority = 1.0f;
const tcu::CommandLine& cmdLine = context.getTestContext().getCommandLine();
const deUint32 devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
const deUint32 deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
const VkDeviceGroupPresentModeFlagsKHR requiredFlag = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
const VkDeviceGroupPresentModeFlagsKHR maxValidFlag = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR |
VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR;
deUint8 buffer [sizeof(VkDeviceGroupPresentCapabilitiesKHR) + GUARD_SIZE];
deUint32 queueFamilyIndex = 0;
VkDeviceGroupPresentCapabilitiesKHR* presentCapabilities;
VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
const Extensions& supportedExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
std::vector<const char*> deviceExtensions;
if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
deviceExtensions.push_back("VK_KHR_device_group");
deviceExtensions.push_back("VK_KHR_swapchain");
for (int ndx = 0; ndx < int(deviceExtensions.size()); ++ndx)
{
if (!isExtensionSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
}
const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps = enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx]);
for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
{
if (queueProps[queueNdx].queueFlags & VK_QUEUE_GRAPHICS_BIT)
queueFamilyIndex = (deUint32)queueNdx;
}
const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, //type
DE_NULL, //pNext
(VkDeviceQueueCreateFlags)0u, //flags
queueFamilyIndex, //queueFamilyIndex;
1u, //queueCount;
&queuePriority, //pQueuePriorities;
};
const VkDeviceGroupDeviceCreateInfo deviceGroupInfo =
{
VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, //stype
DE_NULL, //pNext
deviceGroupProps[devGroupIdx].physicalDeviceCount, //physicalDeviceCount
deviceGroupProps[devGroupIdx].physicalDevices //physicalDevices
};
const VkDeviceCreateInfo deviceCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType;
&deviceGroupInfo, //pNext;
(VkDeviceCreateFlags)0u, //flags
1, //queueRecordCount;
&deviceQueueCreateInfo, //pRequestedQueues;
0, //layerCount;
DE_NULL, //ppEnabledLayerNames;
deUint32(deviceExtensions.size()), //enabledExtensionCount;
(deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0]), //ppEnabledExtensionNames;
DE_NULL, //pEnabledFeatures;
};
Move<VkDevice> deviceGroup = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx], &deviceCreateInfo);
const DeviceDriver vk (context.getPlatformInterface(), instHelper.instance, *deviceGroup);
presentCapabilities = reinterpret_cast<VkDeviceGroupPresentCapabilitiesKHR*>(buffer);
deMemset(buffer, GUARD_VALUE, sizeof(buffer));
presentCapabilities->sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR;
presentCapabilities->pNext = DE_NULL;
VK_CHECK(vk.getDeviceGroupPresentCapabilitiesKHR(deviceGroup.get(), presentCapabilities));
// Guard check
for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
{
if (buffer[ndx + sizeof(VkDeviceGroupPresentCapabilitiesKHR)] != GUARD_VALUE)
{
log << TestLog::Message << "deviceGroupPresentCapabilities - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
return tcu::TestStatus::fail("deviceGroupPresentCapabilities buffer overflow");
}
}
// Check each physical device can present on itself
for (size_t physDevIdx = 0; physDevIdx < VK_MAX_DEVICE_GROUP_SIZE_KHR; physDevIdx++)
{
if (presentCapabilities->presentMask[physDevIdx])
if (!((1 << physDevIdx) & (presentCapabilities->presentMask[physDevIdx])))
return tcu::TestStatus::fail("deviceGroupPresentCapabilities, device can not present on itself, invalid present mask");
}
// Check if flags are valid
if ((!(presentCapabilities->modes & requiredFlag)) ||
presentCapabilities->modes > maxValidFlag)
return tcu::TestStatus::fail("deviceGroupPresentCapabilities flag not valid");
return tcu::TestStatus::pass("Querying deviceGroup present capabilities succeeded");
}
tcu::TestStatus queryDevGroupSurfacePresentModesTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType, vector<string>(1, string("VK_KHR_device_group_creation")));
const NativeObjects native (context, instHelper.supportedExtensions, wsiType);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *native.display, *native.window));
const float queuePriority = 1.0f;
const tcu::CommandLine& cmdLine = context.getTestContext().getCommandLine();
const deUint32 devGroupIdx = cmdLine.getVKDeviceGroupId() - 1;
const deUint32 deviceIdx = context.getTestContext().getCommandLine().getVKDeviceId() - 1u;
const VkDeviceGroupPresentModeFlagsKHR requiredFlag = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR;
const VkDeviceGroupPresentModeFlagsKHR maxValidFlag = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR |
VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR|VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR;
VkResult result = VK_SUCCESS;
deUint8 buffer [sizeof(VkDeviceGroupPresentModeFlagsKHR) + GUARD_SIZE];
deUint32 rectCount = 0;
deUint32 incompleteRectCount = 0;
deUint32 queueFamilyIndex = 0;
VkRect2D* presentRectangles;
VkDeviceGroupPresentModeFlagsKHR* presentModeFlags;
vector<deUint8> rectanglesBuffer;
VkPhysicalDevice physicalDevice = chooseDevice(instHelper.vki, instHelper.instance, cmdLine);
const Extensions& supportedExtensions = enumerateDeviceExtensionProperties(instHelper.vki, physicalDevice, DE_NULL);
std::vector<const char*> deviceExtensions;
if (!isCoreDeviceExtension(context.getUsedApiVersion(), "VK_KHR_device_group"))
deviceExtensions.push_back("VK_KHR_device_group");
deviceExtensions.push_back("VK_KHR_swapchain");
for (int ndx = 0; ndx < int(deviceExtensions.size()); ++ndx)
{
if (!isExtensionSupported(supportedExtensions, RequiredExtension(deviceExtensions[ndx])))
TCU_THROW(NotSupportedError, (string(deviceExtensions[ndx]) + " is not supported").c_str());
}
const vector<VkPhysicalDeviceGroupProperties> deviceGroupProps = enumeratePhysicalDeviceGroups(instHelper.vki, instHelper.instance);
const std::vector<VkQueueFamilyProperties> queueProps = getPhysicalDeviceQueueFamilyProperties(instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx]);
for (size_t queueNdx = 0; queueNdx < queueProps.size(); queueNdx++)
{
if (queueProps[queueNdx].queueFlags & VK_QUEUE_GRAPHICS_BIT)
queueFamilyIndex = (deUint32)queueNdx;
}
const VkDeviceQueueCreateInfo deviceQueueCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, //type
DE_NULL, //pNext
(VkDeviceQueueCreateFlags)0u, //flags
queueFamilyIndex, //queueFamilyIndex;
1u, //queueCount;
&queuePriority, //pQueuePriorities;
};
const VkDeviceGroupDeviceCreateInfo deviceGroupInfo =
{
VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR, //stype
DE_NULL, //pNext
deviceGroupProps[devGroupIdx].physicalDeviceCount, //physicalDeviceCount
deviceGroupProps[devGroupIdx].physicalDevices //physicalDevices
};
const VkDeviceCreateInfo deviceCreateInfo =
{
VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType;
&deviceGroupInfo, //pNext;
(VkDeviceCreateFlags)0u, //flags
1, //queueRecordCount;
&deviceQueueCreateInfo, //pRequestedQueues;
0, //layerCount;
DE_NULL, //ppEnabledLayerNames;
deUint32(deviceExtensions.size()), //enabledExtensionCount;
(deviceExtensions.empty() ? DE_NULL : &deviceExtensions[0]), //ppEnabledExtensionNames;
DE_NULL, //pEnabledFeatures;
};
Move<VkDevice> deviceGroup = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(), instHelper.instance, instHelper.vki, deviceGroupProps[devGroupIdx].physicalDevices[deviceIdx], &deviceCreateInfo);
const DeviceDriver vk (context.getPlatformInterface(), instHelper.instance, *deviceGroup);
presentModeFlags = reinterpret_cast<VkDeviceGroupPresentModeFlagsKHR*>(buffer);
deMemset(buffer, GUARD_VALUE, sizeof(buffer));
VK_CHECK(vk.getDeviceGroupSurfacePresentModesKHR(deviceGroup.get(), *surface, presentModeFlags));
// Guard check
for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
{
if (buffer[ndx + sizeof(VkDeviceGroupPresentModeFlagsKHR)] != GUARD_VALUE)
{
log << TestLog::Message << "queryDevGroupSurfacePresentModesTest - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
return tcu::TestStatus::fail("queryDevGroupSurfacePresentModesTest buffer overflow");
}
}
// Check if flags are valid
if ((!(*presentModeFlags & requiredFlag)) ||
*presentModeFlags > maxValidFlag)
return tcu::TestStatus::fail("queryDevGroupSurfacePresentModesTest flag not valid");
// getPhysicalDevicePresentRectanglesKHR is supported only when VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR is set
if ((*presentModeFlags & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR))
{
for (size_t physDevIdx = 0; physDevIdx < deviceGroupProps[devGroupIdx].physicalDeviceCount; physDevIdx++)
{
VK_CHECK(instHelper.vki.getPhysicalDevicePresentRectanglesKHR(deviceGroupProps[devGroupIdx].physicalDevices[physDevIdx], *surface, &rectCount, DE_NULL));
rectanglesBuffer.resize(sizeof(VkRect2D) * rectCount + GUARD_SIZE);
presentRectangles = reinterpret_cast<VkRect2D*>(rectanglesBuffer.data());
deMemset(rectanglesBuffer.data(), GUARD_VALUE, rectanglesBuffer.size());
VK_CHECK(instHelper.vki.getPhysicalDevicePresentRectanglesKHR(deviceGroupProps[devGroupIdx].physicalDevices[physDevIdx], *surface, &rectCount, presentRectangles));
// Guard check
for (deInt32 ndx = 0; ndx < GUARD_SIZE; ndx++)
{
if (rectanglesBuffer[ndx + sizeof(VkRect2D) * rectCount] != GUARD_VALUE)
{
log << TestLog::Message << "getPhysicalDevicePresentRectanglesKHR - Guard offset " << ndx << " not valid" << TestLog::EndMessage;
return tcu::TestStatus::fail("getPhysicalDevicePresentRectanglesKHR buffer overflow");
}
}
// Check rectangles do not overlap
for (size_t rectIdx1 = 0; rectIdx1 < rectCount; rectIdx1++)
{
for (size_t rectIdx2 = 0; rectIdx2 < rectCount; rectIdx2++)
{
if (rectIdx1 != rectIdx2)
{
deUint32 rectATop = presentRectangles[rectIdx1].offset.y;
deUint32 rectALeft = presentRectangles[rectIdx1].offset.x;
deUint32 rectABottom = presentRectangles[rectIdx1].offset.y + presentRectangles[rectIdx1].extent.height;
deUint32 rectARight = presentRectangles[rectIdx1].offset.x + presentRectangles[rectIdx1].extent.width;
deUint32 rectBTop = presentRectangles[rectIdx2].offset.y;
deUint32 rectBLeft = presentRectangles[rectIdx2].offset.x;
deUint32 rectBBottom = presentRectangles[rectIdx2].offset.y + presentRectangles[rectIdx2].extent.height;
deUint32 rectBRight = presentRectangles[rectIdx2].offset.x + presentRectangles[rectIdx2].extent.width;
if (rectALeft < rectBRight && rectARight > rectBLeft &&
rectATop < rectBBottom && rectABottom > rectBTop)
return tcu::TestStatus::fail("getPhysicalDevicePresentRectanglesKHR rectangles overlap");
}
}
}
// Check incomplete
incompleteRectCount = rectCount / 2;
result = instHelper.vki.getPhysicalDevicePresentRectanglesKHR(deviceGroupProps[devGroupIdx].physicalDevices[physDevIdx], *surface, &incompleteRectCount, presentRectangles);
results.check(result == VK_INCOMPLETE, "Expected VK_INCOMPLETE");
}
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus createSurfaceInitialSizeTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType);
const UniquePtr<Display> nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
instHelper.supportedExtensions,
wsiType));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
const UVec2 sizes[] =
{
UVec2(64, 64),
UVec2(124, 119),
UVec2(256, 512)
};
DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE);
for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
{
const UVec2& testSize = sizes[sizeNdx];
const UniquePtr<Window> nativeWindow (createWindow(*nativeDisplay, tcu::just(testSize)));
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
// \note Assumes that surface size is NOT set by swapchain if initial window size is honored by platform
results.check(capabilities.currentExtent.width == testSize.x() &&
capabilities.currentExtent.height == testSize.y(),
"currentExtent " + de::toString(capabilities.currentExtent) + " doesn't match requested size " + de::toString(testSize));
}
}
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus resizeSurfaceTest (Context& context, Type wsiType)
{
tcu::TestLog& log = context.getTestContext().getLog();
tcu::ResultCollector results (log);
const InstanceHelper instHelper (context, wsiType);
const UniquePtr<Display> nativeDisplay (createDisplay(context.getTestContext().getPlatform().getVulkanPlatform(),
instHelper.supportedExtensions,
wsiType));
UniquePtr<Window> nativeWindow (createWindow(*nativeDisplay, tcu::nothing<UVec2>()));
const vector<VkPhysicalDevice> physicalDevices = enumeratePhysicalDevices(instHelper.vki, instHelper.instance);
const Unique<VkSurfaceKHR> surface (createSurface(instHelper.vki, instHelper.instance, wsiType, *nativeDisplay, *nativeWindow));
const UVec2 sizes[] =
{
UVec2(64, 64),
UVec2(124, 119),
UVec2(256, 512)
};
DE_ASSERT(getPlatformProperties(wsiType).features & PlatformProperties::FEATURE_RESIZE_WINDOW);
for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(sizes); ++sizeNdx)
{
const UVec2 testSize = sizes[sizeNdx];
try
{
nativeWindow->resize(testSize);
}
catch (const tcu::Exception& e)
{
// Make sure all exception types result in a test failure
results.fail(e.getMessage());
}
for (size_t deviceNdx = 0; deviceNdx < physicalDevices.size(); ++deviceNdx)
{
if (isSupportedByAnyQueue(instHelper.vki, physicalDevices[deviceNdx], *surface))
{
const VkSurfaceCapabilitiesKHR capabilities = getPhysicalDeviceSurfaceCapabilities(instHelper.vki, physicalDevices[deviceNdx], *surface);
// \note Assumes that surface size is NOT set by swapchain if initial window size is honored by platform
results.check(capabilities.currentExtent.width == testSize.x() &&
capabilities.currentExtent.height == testSize.y(),
"currentExtent " + de::toString(capabilities.currentExtent) + " doesn't match requested size " + de::toString(testSize));
}
}
}
return tcu::TestStatus(results.getResult(), results.getMessage());
}
tcu::TestStatus destroyNullHandleSurfaceTest (Context& context, Type wsiType)
{
const InstanceHelper instHelper (context, wsiType);
const VkSurfaceKHR nullHandle = DE_NULL;
// Default allocator
instHelper.vki.destroySurfaceKHR(instHelper.instance, nullHandle, DE_NULL);
// Custom allocator
{
AllocationCallbackRecorder recordingAllocator (getSystemAllocator(), 1u);
instHelper.vki.destroySurfaceKHR(instHelper.instance, nullHandle, recordingAllocator.getCallbacks());
if (recordingAllocator.getNumRecords() != 0u)
return tcu::TestStatus::fail("Implementation allocated/freed the memory");
}
return tcu::TestStatus::pass("Destroying a VK_NULL_HANDLE surface has no effect");
}
} // anonymous
void createSurfaceTests (tcu::TestCaseGroup* testGroup, vk::wsi::Type wsiType)
{
const PlatformProperties& platformProperties = getPlatformProperties(wsiType);
addFunctionCase(testGroup, "create", "Create surface", createSurfaceTest, wsiType);
addFunctionCase(testGroup, "create_custom_allocator", "Create surface with custom allocator", createSurfaceCustomAllocatorTest, wsiType);
addFunctionCase(testGroup, "create_simulate_oom", "Create surface with simulating OOM", createSurfaceSimulateOOMTest, wsiType);
addFunctionCase(testGroup, "query_support", "Query surface support", querySurfaceSupportTest, wsiType);
addFunctionCase(testGroup, "query_presentation_support", "Query native presentation support", queryPresentationSupportTest, wsiType);
addFunctionCase(testGroup, "query_capabilities", "Query surface capabilities", querySurfaceCapabilitiesTest, wsiType);
addFunctionCase(testGroup, "query_capabilities2", "Query extended surface capabilities", querySurfaceCapabilities2Test, wsiType);
addFunctionCase(testGroup, "query_protected_capabilities", "Query protected surface capabilities", querySurfaceProtectedCapabilitiesTest, wsiType);
addFunctionCase(testGroup, "query_surface_counters", "Query and check available surface counters", querySurfaceCounterTest, wsiType);
addFunctionCase(testGroup, "query_formats", "Query surface formats", querySurfaceFormatsTest, wsiType);
addFunctionCase(testGroup, "query_formats2", "Query extended surface formats", querySurfaceFormats2Test, wsiType);
addFunctionCase(testGroup, "query_present_modes", "Query surface present modes", querySurfacePresentModesTest, wsiType);
addFunctionCase(testGroup, "query_devgroup_present_capabilities", "Query surface present modes capabilities in device groups",queryDevGroupSurfacePresentCapabilitiesTest,wsiType);
addFunctionCase(testGroup, "query_devgroup_present_modes", "Query surface present modes for device groups", queryDevGroupSurfacePresentModesTest, wsiType);
addFunctionCase(testGroup, "destroy_null_handle", "Destroy VK_NULL_HANDLE surface", destroyNullHandleSurfaceTest, wsiType);
if ((platformProperties.features & PlatformProperties::FEATURE_INITIAL_WINDOW_SIZE) != 0)
addFunctionCase(testGroup, "initial_size", "Create surface with initial window size set", createSurfaceInitialSizeTest, wsiType);
if ((platformProperties.features & PlatformProperties::FEATURE_RESIZE_WINDOW) != 0)
addFunctionCase(testGroup, "resize", "Resize window and surface", resizeSurfaceTest, wsiType);
}
} // wsi
} // vkt