blob: be3c33039626e0d2134a5c8244d2be1403117333 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2019 The Khronos Group Inc.
* Copyright (c) 2019 Valve Corporation.
*
* 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 Auxiliar functions to help create custom devices and instances.
*//*--------------------------------------------------------------------*/
#include "vkRefUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkDeviceUtil.hpp"
#include "tcuCommandLine.hpp"
#include "vktCustomInstancesDevices.hpp"
#include <algorithm>
using std::vector;
using std::string;
using vk::Move;
using vk::VkInstance;
using vk::InstanceDriver;
using vk::DebugReportRecorder;
namespace vkt
{
namespace
{
vector<const char*> getValidationLayers (const vector<vk::VkLayerProperties>& supportedLayers)
{
static const char* s_magicLayer = "VK_LAYER_KHRONOS_validation";
static const char* s_defaultLayers[] =
{
"VK_LAYER_LUNARG_standard_validation", // Deprecated by at least Vulkan SDK 1.1.121.
"VK_LAYER_GOOGLE_threading", // Deprecated by at least Vulkan SDK 1.1.121.
"VK_LAYER_LUNARG_parameter_validation", // Deprecated by at least Vulkan SDK 1.1.121.
"VK_LAYER_LUNARG_device_limits",
"VK_LAYER_LUNARG_object_tracker", // Deprecated by at least Vulkan SDK 1.1.121.
"VK_LAYER_LUNARG_image",
"VK_LAYER_LUNARG_core_validation", // Deprecated by at least Vulkan SDK 1.1.121.
"VK_LAYER_LUNARG_swapchain",
"VK_LAYER_GOOGLE_unique_objects" // Deprecated by at least Vulkan SDK 1.1.121.
};
vector<const char*> enabledLayers;
if (vk::isLayerSupported(supportedLayers, vk::RequiredLayer(s_magicLayer)))
enabledLayers.push_back(s_magicLayer);
else
{
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_defaultLayers); ++ndx)
{
if (isLayerSupported(supportedLayers, vk::RequiredLayer(s_defaultLayers[ndx])))
enabledLayers.push_back(s_defaultLayers[ndx]);
}
}
return enabledLayers;
}
} // anonymous
vector<const char*> getValidationLayers (const vk::PlatformInterface& vkp)
{
return getValidationLayers(enumerateInstanceLayerProperties(vkp));
}
vector<const char*> getValidationLayers (const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice)
{
return getValidationLayers(enumerateDeviceLayerProperties(vki, physicalDevice));
}
CustomInstance::CustomInstance (Context& context, Move<VkInstance> instance, bool enableDebugReportRecorder, bool printValidationErrors)
: m_context (&context)
, m_instance (instance)
, m_driver (new InstanceDriver(context.getPlatformInterface(), *m_instance))
, m_recorder (enableDebugReportRecorder ? (new DebugReportRecorder(*m_driver, *m_instance, printValidationErrors)) : nullptr)
{
}
CustomInstance::CustomInstance ()
: m_context (nullptr)
, m_instance ()
, m_driver (nullptr)
, m_recorder (nullptr)
{
}
CustomInstance::CustomInstance (CustomInstance&& other)
: CustomInstance()
{
this->swap(other);
}
CustomInstance::~CustomInstance ()
{
collectMessages();
}
CustomInstance& CustomInstance::operator= (CustomInstance&& other)
{
CustomInstance destroyer;
destroyer.swap(other);
this->swap(destroyer);
return *this;
}
void CustomInstance::swap (CustomInstance& other)
{
std::swap(m_context, other.m_context);
Move<VkInstance> aux = m_instance; m_instance = other.m_instance; other.m_instance = aux;
m_driver.swap(other.m_driver);
m_recorder.swap(other.m_recorder);
}
CustomInstance::operator VkInstance () const
{
return *m_instance;
}
const vk::InstanceDriver& CustomInstance::getDriver() const
{
return *m_driver;
}
void CustomInstance::collectMessages ()
{
if (m_recorder)
collectAndReportDebugMessages(*m_recorder, *m_context);
}
UncheckedInstance::UncheckedInstance ()
: m_context (nullptr)
, m_allocator (nullptr)
, m_instance (DE_NULL)
, m_driver (nullptr)
, m_recorder (nullptr)
{
}
UncheckedInstance::UncheckedInstance (Context& context, vk::VkInstance instance, const vk::VkAllocationCallbacks* pAllocator, bool enableDebugReportRecorder, bool printValidationErrors)
: m_context (&context)
, m_allocator (pAllocator)
, m_instance (instance)
, m_driver ((m_instance != DE_NULL) ? new InstanceDriver(context.getPlatformInterface(), m_instance) : nullptr)
, m_recorder ((enableDebugReportRecorder && m_instance != DE_NULL) ? (new DebugReportRecorder(*m_driver, m_instance, printValidationErrors)) : nullptr)
{
}
UncheckedInstance::~UncheckedInstance ()
{
if (m_recorder)
collectAndReportDebugMessages(*m_recorder, *m_context);
if (m_instance != DE_NULL)
{
m_recorder.reset(nullptr);
m_driver->destroyInstance(m_instance, m_allocator);
}
}
void UncheckedInstance::swap (UncheckedInstance& other)
{
std::swap(m_context, other.m_context);
std::swap(m_allocator, other.m_allocator);
vk::VkInstance aux = m_instance; m_instance = other.m_instance; other.m_instance = aux;
m_driver.swap(other.m_driver);
m_recorder.swap(other.m_recorder);
}
UncheckedInstance::UncheckedInstance (UncheckedInstance&& other)
: UncheckedInstance()
{
this->swap(other);
}
UncheckedInstance& UncheckedInstance::operator= (UncheckedInstance&& other)
{
UncheckedInstance destroyer;
destroyer.swap(other);
this->swap(destroyer);
return *this;
}
UncheckedInstance::operator vk::VkInstance () const
{
return m_instance;
}
UncheckedInstance::operator bool () const
{
return (m_instance != DE_NULL);
}
CustomInstance createCustomInstanceWithExtensions (Context& context, const std::vector<std::string>& extensions, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
{
vector<const char*> enabledLayers;
vector<string> enabledLayersStr;
const auto& cmdLine = context.getTestContext().getCommandLine();
const bool validationEnabled = (cmdLine.isValidationEnabled() && allowLayers);
const bool printValidationErrors = cmdLine.printValidationErrors();
if (validationEnabled)
{
enabledLayers = getValidationLayers(context.getPlatformInterface());
enabledLayersStr = vector<string>(begin(enabledLayers), end(enabledLayers));
}
// Filter extension list and throw NotSupported if a required extension is not supported.
const deUint32 apiVersion = context.getUsedApiVersion();
const vk::PlatformInterface& vkp = context.getPlatformInterface();
const std::vector<vk::VkExtensionProperties> availableExtensions = vk::enumerateInstanceExtensionProperties(vkp, DE_NULL);
vector<string> extensionPtrs;
vector<string> availableExtensionNames;
for (const auto& ext : availableExtensions)
availableExtensionNames.push_back(ext.extensionName);
for (const auto& ext : extensions)
{
if (!vk::isInstanceExtensionSupported(apiVersion, availableExtensionNames, ext))
TCU_THROW(NotSupportedError, ext + " is not supported");
if (!vk::isCoreInstanceExtension(apiVersion, ext))
extensionPtrs.push_back(ext);
}
Move<VkInstance> instance = vk::createDefaultInstance(vkp, apiVersion, enabledLayersStr, extensionPtrs, pAllocator);
return CustomInstance(context, instance, validationEnabled, printValidationErrors);
}
CustomInstance createCustomInstanceWithExtension (Context& context, const std::string& extension, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
{
return createCustomInstanceWithExtensions(context, std::vector<std::string>(1, extension), pAllocator, allowLayers);
}
CustomInstance createCustomInstanceFromContext (Context& context, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
{
return createCustomInstanceWithExtensions(context, std::vector<std::string>(), pAllocator, allowLayers);
}
const char kDebugReportExt[] = "VK_EXT_debug_report";
vector<const char*> addDebugReportExt(const vk::PlatformInterface& vkp, const vk::VkInstanceCreateInfo& createInfo)
{
if (!isDebugReportSupported(vkp))
TCU_THROW(NotSupportedError, "VK_EXT_debug_report is not supported");
vector<const char*> actualExtensions;
if (createInfo.enabledExtensionCount != 0u)
{
for (deUint32 i = 0u; i < createInfo.enabledExtensionCount; ++i)
actualExtensions.push_back(createInfo.ppEnabledExtensionNames[i]);
}
if (std::find_if(begin(actualExtensions), end(actualExtensions), [](const char* name) { return (strcmp(name, kDebugReportExt) == 0); })
== end(actualExtensions))
{
actualExtensions.push_back(kDebugReportExt);
}
return actualExtensions;
}
CustomInstance createCustomInstanceFromInfo (Context& context, const vk::VkInstanceCreateInfo* instanceCreateInfo, const vk::VkAllocationCallbacks* pAllocator, bool allowLayers)
{
vector<const char*> enabledLayers;
vector<const char*> enabledExtensions;
vk::VkInstanceCreateInfo createInfo = *instanceCreateInfo;
const auto& cmdLine = context.getTestContext().getCommandLine();
const bool validationEnabled = cmdLine.isValidationEnabled();
const bool printValidationErrors = cmdLine.printValidationErrors();
const vk::PlatformInterface& vkp = context.getPlatformInterface();
if (validationEnabled && allowLayers)
{
// Activate some layers if requested.
if (createInfo.enabledLayerCount == 0u)
{
enabledLayers = getValidationLayers(vkp);
createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
}
// Make sure the debug report extension is enabled when validation is enabled.
enabledExtensions = addDebugReportExt(vkp, createInfo);
createInfo.enabledExtensionCount = static_cast<deUint32>(enabledExtensions.size());
createInfo.ppEnabledExtensionNames = enabledExtensions.data();
}
return CustomInstance(context, vk::createInstance(vkp, &createInfo, pAllocator), validationEnabled, printValidationErrors);
}
vk::VkResult createUncheckedInstance (Context& context, const vk::VkInstanceCreateInfo* instanceCreateInfo, const vk::VkAllocationCallbacks* pAllocator, UncheckedInstance* instance, bool allowLayers)
{
vector<const char*> enabledLayers;
vector<const char*> enabledExtensions;
vk::VkInstanceCreateInfo createInfo = *instanceCreateInfo;
const auto& cmdLine = context.getTestContext().getCommandLine();
const bool validationEnabled = cmdLine.isValidationEnabled();
const bool printValidationErrors = cmdLine.printValidationErrors();
const vk::PlatformInterface& vkp = context.getPlatformInterface();
const bool addLayers = (validationEnabled && allowLayers);
if (addLayers)
{
// Activate some layers if requested.
if (createInfo.enabledLayerCount == 0u)
{
enabledLayers = getValidationLayers(vkp);
createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
}
// Make sure the debug report extension is enabled when validation is enabled.
enabledExtensions = addDebugReportExt(vkp, createInfo);
createInfo.enabledExtensionCount = static_cast<deUint32>(enabledExtensions.size());
createInfo.ppEnabledExtensionNames = enabledExtensions.data();
}
vk::VkInstance raw_instance = DE_NULL;
vk::VkResult result = vkp.createInstance(&createInfo, pAllocator, &raw_instance);
*instance = UncheckedInstance(context, raw_instance, pAllocator, addLayers, printValidationErrors);
return result;
}
vk::Move<vk::VkDevice> createCustomDevice (bool validationEnabled, const vk::PlatformInterface& vkp, vk::VkInstance instance, const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, const vk::VkDeviceCreateInfo* pCreateInfo, const vk::VkAllocationCallbacks* pAllocator)
{
vector<const char*> enabledLayers;
vk::VkDeviceCreateInfo createInfo = *pCreateInfo;
if (createInfo.enabledLayerCount == 0u && validationEnabled)
{
enabledLayers = getValidationLayers(vki, physicalDevice);
createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
}
return createDevice(vkp, instance, vki, physicalDevice, &createInfo, pAllocator);
}
vk::VkResult createUncheckedDevice (bool validationEnabled, const vk::InstanceInterface& vki, vk::VkPhysicalDevice physicalDevice, const vk::VkDeviceCreateInfo* pCreateInfo, const vk::VkAllocationCallbacks* pAllocator, vk::VkDevice* pDevice)
{
vector<const char*> enabledLayers;
vk::VkDeviceCreateInfo createInfo = *pCreateInfo;
if (createInfo.enabledLayerCount == 0u && validationEnabled)
{
enabledLayers = getValidationLayers(vki, physicalDevice);
createInfo.enabledLayerCount = static_cast<deUint32>(enabledLayers.size());
createInfo.ppEnabledLayerNames = (enabledLayers.empty() ? DE_NULL : enabledLayers.data());
}
return vki.createDevice(physicalDevice, &createInfo, pAllocator, pDevice);
}
}