blob: 7384a176043f15c1570c649b06975737285ddb13 [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 "vkDebugReportUtil.hpp"
#include "tcuCommandLine.hpp"
#include "vktCustomInstancesDevices.hpp"
#include <algorithm>
#include <memory>
#include <set>
using std::vector;
using std::string;
using vk::Move;
using vk::VkInstance;
#ifndef CTS_USES_VULKANSC
using vk::InstanceDriver;
using vk::DebugReportRecorder;
using vk::VkDebugReportCallbackCreateInfoEXT;
using vk::VkDebugReportCallbackEXT;
#else
using vk::InstanceDriverSC;
#endif // CTS_USES_VULKANSC
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));
}
#ifndef CTS_USES_VULKANSC
CustomInstance::CustomInstance(Context& context, Move<VkInstance> instance, std::unique_ptr<vk::DebugReportRecorder>& recorder)
#else
CustomInstance::CustomInstance(Context& context, Move<VkInstance> instance)
#endif // CTS_USES_VULKANSC
: m_context (&context)
#ifndef CTS_USES_VULKANSC
, m_recorder (recorder.release())
#endif // CTS_USES_VULKANSC
, m_instance (instance)
#ifndef CTS_USES_VULKANSC
, m_driver (new InstanceDriver(context.getPlatformInterface(), *m_instance))
, m_callback (m_recorder ? m_recorder->createCallback(*m_driver, *m_instance) : Move<VkDebugReportCallbackEXT>())
#else
, m_driver (new InstanceDriverSC(context.getPlatformInterface(), *m_instance, context.getTestContext().getCommandLine(), context.getResourceInterface()))
#endif // CTS_USES_VULKANSC
{
}
CustomInstance::CustomInstance ()
: m_context (nullptr)
#ifndef CTS_USES_VULKANSC
, m_recorder (nullptr)
#endif // CTS_USES_VULKANSC
, m_instance ()
, m_driver (nullptr)
#ifndef CTS_USES_VULKANSC
, m_callback ()
#endif // CTS_USES_VULKANSC
{
}
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);
#ifndef CTS_USES_VULKANSC
m_recorder.swap(other.m_recorder);
#endif // CTS_USES_VULKANSC
Move<VkInstance> aux = m_instance; m_instance = other.m_instance; other.m_instance = aux;
m_driver.swap(other.m_driver);
#ifndef CTS_USES_VULKANSC
Move<VkDebugReportCallbackEXT> aux2 = m_callback; m_callback = other.m_callback; other.m_callback = aux2;
#endif // CTS_USES_VULKANSC
}
CustomInstance::operator VkInstance () const
{
return *m_instance;
}
const vk::InstanceDriver& CustomInstance::getDriver() const
{
return *m_driver;
}
void CustomInstance::collectMessages ()
{
#ifndef CTS_USES_VULKANSC
if (m_recorder)
collectAndReportDebugMessages(*m_recorder, *m_context);
#endif // CTS_USES_VULKANSC
}
UncheckedInstance::UncheckedInstance ()
: m_context (nullptr)
#ifndef CTS_USES_VULKANSC
, m_recorder (nullptr)
#endif // CTS_USES_VULKANSC
, m_allocator (nullptr)
, m_instance (DE_NULL)
, m_driver (nullptr)
#ifndef CTS_USES_VULKANSC
, m_callback ()
#endif // CTS_USES_VULKANSC
{
}
#ifndef CTS_USES_VULKANSC
UncheckedInstance::UncheckedInstance (Context& context, vk::VkInstance instance, const vk::VkAllocationCallbacks* pAllocator, std::unique_ptr<DebugReportRecorder>& recorder)
#else
UncheckedInstance::UncheckedInstance(Context& context, vk::VkInstance instance, const vk::VkAllocationCallbacks* pAllocator)
#endif // CTS_USES_VULKANSC
: m_context (&context)
#ifndef CTS_USES_VULKANSC
, m_recorder (recorder.release())
#endif // CTS_USES_VULKANSC
, m_allocator (pAllocator)
, m_instance (instance)
#ifndef CTS_USES_VULKANSC
, m_driver((m_instance != DE_NULL) ? new InstanceDriver(context.getPlatformInterface(), m_instance) : nullptr)
, m_callback (m_recorder ? m_recorder->createCallback(*m_driver, m_instance) : Move<VkDebugReportCallbackEXT>())
#else
, m_driver((m_instance != DE_NULL) ? new InstanceDriverSC(context.getPlatformInterface(), m_instance, context.getTestContext().getCommandLine(), context.getResourceInterface()) : nullptr)
#endif // CTS_USES_VULKANSC
{
}
UncheckedInstance::~UncheckedInstance ()
{
#ifndef CTS_USES_VULKANSC
if (m_recorder)
collectAndReportDebugMessages(*m_recorder, *m_context);
#endif // CTS_USES_VULKANSC
if (m_instance != DE_NULL)
{
#ifndef CTS_USES_VULKANSC
m_recorder.reset(nullptr);
#endif // CTS_USES_VULKANSC
m_driver->destroyInstance(m_instance, m_allocator);
}
}
void UncheckedInstance::swap (UncheckedInstance& other)
{
std::swap(m_context, other.m_context);
#ifndef CTS_USES_VULKANSC
m_recorder.swap(other.m_recorder);
#endif // CTS_USES_VULKANSC
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);
#ifndef CTS_USES_VULKANSC
Move<VkDebugReportCallbackEXT> aux2 = m_callback; m_callback = other.m_callback; other.m_callback = aux2;
#endif // CTS_USES_VULKANSC
}
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 validationRequested = (cmdLine.isValidationEnabled() && allowLayers);
#ifndef CTS_USES_VULKANSC
const bool printValidationErrors = cmdLine.printValidationErrors();
#endif // CTS_USES_VULKANSC
if (validationRequested)
{
enabledLayers = getValidationLayers(context.getPlatformInterface());
enabledLayersStr = vector<string>(begin(enabledLayers), end(enabledLayers));
}
const bool validationEnabled = !enabledLayers.empty();
// 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 vector<vk::VkExtensionProperties> availableExtensions = vk::enumerateInstanceExtensionProperties(vkp, DE_NULL);
std::set<string> usedExtensions;
// Get list of available extension names.
vector<string> availableExtensionNames;
for (const auto& ext : availableExtensions)
availableExtensionNames.push_back(ext.extensionName);
// Filter duplicates and remove core extensions.
for (const auto& ext : extensions)
{
if (!vk::isCoreInstanceExtension(apiVersion, ext))
usedExtensions.insert(ext);
}
// Add debug extension if validation is enabled.
if (validationEnabled)
usedExtensions.insert("VK_EXT_debug_report");
// Check extension support.
for (const auto& ext : usedExtensions)
{
if (!vk::isInstanceExtensionSupported(apiVersion, availableExtensionNames, ext))
TCU_THROW(NotSupportedError, ext + " is not supported");
}
#ifndef CTS_USES_VULKANSC
std::unique_ptr<DebugReportRecorder> debugReportRecorder;
if (validationEnabled)
debugReportRecorder.reset(new DebugReportRecorder(printValidationErrors));
#endif // CTS_USES_VULKANSC
// Create custom instance.
const vector<string> usedExtensionsVec(begin(usedExtensions), end(usedExtensions));
#ifndef CTS_USES_VULKANSC
Move<VkInstance> instance = vk::createDefaultInstance(vkp, apiVersion, enabledLayersStr, usedExtensionsVec, debugReportRecorder.get(), pAllocator);
return CustomInstance(context, instance, debugReportRecorder);
#else
Move<VkInstance> instance = vk::createDefaultInstance(vkp, apiVersion, enabledLayersStr, usedExtensionsVec, pAllocator);
return CustomInstance(context, instance);
#endif // CTS_USES_VULKANSC
}
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();
#ifndef CTS_USES_VULKANSC
const bool printValidationErrors = cmdLine.printValidationErrors();
#endif // CTS_USES_VULKANSC
const vk::PlatformInterface& vkp = context.getPlatformInterface();
#ifndef CTS_USES_VULKANSC
std::unique_ptr<DebugReportRecorder> recorder;
VkDebugReportCallbackCreateInfoEXT callbackInfo;
#endif // CTS_USES_VULKANSC
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();
#ifndef CTS_USES_VULKANSC
recorder.reset(new DebugReportRecorder(printValidationErrors));
callbackInfo = recorder->makeCreateInfo();
callbackInfo.pNext = createInfo.pNext;
createInfo.pNext = &callbackInfo;
#endif // CTS_USES_VULKANSC
}
#ifndef CTS_USES_VULKANSC
return CustomInstance(context, vk::createInstance(vkp, &createInfo, pAllocator), recorder);
#else
return CustomInstance(context, vk::createInstance(vkp, &createInfo, pAllocator));
#endif // CTS_USES_VULKANSC
}
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();
#ifndef CTS_USES_VULKANSC
const bool printValidationErrors = cmdLine.printValidationErrors();
#endif // CTS_USES_VULKANSC
const vk::PlatformInterface& vkp = context.getPlatformInterface();
const bool addLayers = (validationEnabled && allowLayers);
#ifndef CTS_USES_VULKANSC
std::unique_ptr<DebugReportRecorder> recorder;
VkDebugReportCallbackCreateInfoEXT callbackInfo;
#endif // CTS_USES_VULKANSC
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();
#ifndef CTS_USES_VULKANSC
// Prepare debug report recorder also for instance creation.
recorder.reset(new DebugReportRecorder(printValidationErrors));
callbackInfo = recorder->makeCreateInfo();
callbackInfo.pNext = createInfo.pNext;
createInfo.pNext = &callbackInfo;
#endif // CTS_USES_VULKANSC
}
vk::VkInstance raw_instance = DE_NULL;
vk::VkResult result = vkp.createInstance(&createInfo, pAllocator, &raw_instance);
#ifndef CTS_USES_VULKANSC
*instance = UncheckedInstance(context, raw_instance, pAllocator, recorder);
#else
*instance = UncheckedInstance(context, raw_instance, pAllocator);
#endif // CTS_USES_VULKANSC
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);
}
CustomInstanceWrapper::CustomInstanceWrapper (Context& context)
: instance(vkt::createCustomInstanceFromContext(context))
{
}
}