blob: 06a2c3417e2c678b4e76c041b6d7342ee676711c [file] [log] [blame]
// Copyright 2019 The Dawn Authors
//
// 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.
#include "dawn_native/vulkan/BackendVk.h"
#include "common/SystemUtils.h"
#include "dawn_native/Instance.h"
#include "dawn_native/VulkanBackend.h"
#include "dawn_native/vulkan/AdapterVk.h"
#include "dawn_native/vulkan/VulkanError.h"
#include <iostream>
#if defined(DAWN_PLATFORM_LINUX)
# if defined(DAWN_PLATFORM_ANDROID)
const char kVulkanLibName[] = "libvulkan.so";
# else
const char kVulkanLibName[] = "libvulkan.so.1";
# endif
#elif defined(DAWN_PLATFORM_WINDOWS)
const char kVulkanLibName[] = "vulkan-1.dll";
#elif defined(DAWN_PLATFORM_FUCHSIA)
const char kVulkanLibName[] = "libvulkan.so";
#else
# error "Unimplemented Vulkan backend platform"
#endif
namespace dawn_native { namespace vulkan {
Backend::Backend(InstanceBase* instance) : BackendConnection(instance, BackendType::Vulkan) {
}
Backend::~Backend() {
if (mDebugReportCallback != VK_NULL_HANDLE) {
mFunctions.DestroyDebugReportCallbackEXT(mInstance, mDebugReportCallback, nullptr);
mDebugReportCallback = VK_NULL_HANDLE;
}
// VkPhysicalDevices are destroyed when the VkInstance is destroyed
if (mInstance != VK_NULL_HANDLE) {
mFunctions.DestroyInstance(mInstance, nullptr);
mInstance = VK_NULL_HANDLE;
}
}
const VulkanFunctions& Backend::GetFunctions() const {
return mFunctions;
}
VkInstance Backend::GetVkInstance() const {
return mInstance;
}
const VulkanGlobalInfo& Backend::GetGlobalInfo() const {
return mGlobalInfo;
}
MaybeError Backend::Initialize() {
#if defined(DAWN_ENABLE_VULKAN_VALIDATION_LAYERS)
if (GetInstance()->IsBackendValidationEnabled()) {
std::string vkDataDir = GetExecutableDirectory() + DAWN_VK_DATA_DIR;
if (!SetEnvironmentVar("VK_LAYER_PATH", vkDataDir.c_str())) {
return DAWN_DEVICE_LOST_ERROR("Couldn't set VK_LAYER_PATH");
}
}
#endif
#if defined(DAWN_SWIFTSHADER_VK_ICD_JSON)
std::string fullSwiftshaderICDPath =
GetExecutableDirectory() + DAWN_SWIFTSHADER_VK_ICD_JSON;
if (!SetEnvironmentVar("VK_ICD_FILENAMES", fullSwiftshaderICDPath.c_str())) {
return DAWN_DEVICE_LOST_ERROR("Couldn't set VK_ICD_FILENAMES");
}
#endif
if (!mVulkanLib.Open(kVulkanLibName)) {
return DAWN_DEVICE_LOST_ERROR(std::string("Couldn't open ") + kVulkanLibName);
}
DAWN_TRY(mFunctions.LoadGlobalProcs(mVulkanLib));
DAWN_TRY_ASSIGN(mGlobalInfo, GatherGlobalInfo(*this));
VulkanGlobalKnobs usedGlobalKnobs = {};
DAWN_TRY_ASSIGN(usedGlobalKnobs, CreateInstance());
*static_cast<VulkanGlobalKnobs*>(&mGlobalInfo) = usedGlobalKnobs;
DAWN_TRY(mFunctions.LoadInstanceProcs(mInstance, mGlobalInfo));
if (usedGlobalKnobs.debugReport) {
DAWN_TRY(RegisterDebugReport());
}
DAWN_TRY_ASSIGN(mPhysicalDevices, GetPhysicalDevices(*this));
return {};
}
std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
std::vector<std::unique_ptr<AdapterBase>> adapters;
for (VkPhysicalDevice physicalDevice : mPhysicalDevices) {
std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(this, physicalDevice);
if (GetInstance()->ConsumedError(adapter->Initialize())) {
continue;
}
adapters.push_back(std::move(adapter));
}
return adapters;
}
ResultOrError<VulkanGlobalKnobs> Backend::CreateInstance() {
VulkanGlobalKnobs usedKnobs = {};
std::vector<const char*> layersToRequest;
std::vector<const char*> extensionsToRequest;
// vktrace works by instering a layer, but we hide it behind a macro due to the vktrace
// layer crashes when used without vktrace server started. See this vktrace issue:
// https://github.com/LunarG/VulkanTools/issues/254
// Also it is good to put it in first position so that it doesn't see Vulkan calls inserted
// by other layers.
#if defined(DAWN_USE_VKTRACE)
if (mGlobalInfo.vktrace) {
layersToRequest.push_back(kLayerNameLunargVKTrace);
usedKnobs.vktrace = true;
}
#endif
// RenderDoc installs a layer at the system level for its capture but we don't want to use
// it unless we are debugging in RenderDoc so we hide it behind a macro.
#if defined(DAWN_USE_RENDERDOC)
if (mGlobalInfo.renderDocCapture) {
layersToRequest.push_back(kLayerNameRenderDocCapture);
usedKnobs.renderDocCapture = true;
}
#endif
if (GetInstance()->IsBackendValidationEnabled()) {
if (mGlobalInfo.standardValidation) {
layersToRequest.push_back(kLayerNameLunargStandardValidation);
usedKnobs.standardValidation = true;
}
if (mGlobalInfo.debugReport) {
extensionsToRequest.push_back(kExtensionNameExtDebugReport);
usedKnobs.debugReport = true;
}
}
if (mGlobalInfo.fuchsiaImagePipeSwapchain) {
layersToRequest.push_back(kLayerNameFuchsiaImagePipeSwapchain);
usedKnobs.fuchsiaImagePipeSwapchain = true;
}
// Always request all extensions used to create VkSurfaceKHR objects so that they are
// always available for embedders looking to create VkSurfaceKHR on our VkInstance.
if (mGlobalInfo.macosSurface) {
extensionsToRequest.push_back(kExtensionNameMvkMacosSurface);
usedKnobs.macosSurface = true;
}
if (mGlobalInfo.externalMemoryCapabilities) {
extensionsToRequest.push_back(kExtensionNameKhrExternalMemoryCapabilities);
usedKnobs.externalMemoryCapabilities = true;
}
if (mGlobalInfo.externalSemaphoreCapabilities) {
extensionsToRequest.push_back(kExtensionNameKhrExternalSemaphoreCapabilities);
usedKnobs.externalSemaphoreCapabilities = true;
}
if (mGlobalInfo.getPhysicalDeviceProperties2) {
extensionsToRequest.push_back(kExtensionNameKhrGetPhysicalDeviceProperties2);
usedKnobs.getPhysicalDeviceProperties2 = true;
}
if (mGlobalInfo.surface) {
extensionsToRequest.push_back(kExtensionNameKhrSurface);
usedKnobs.surface = true;
}
if (mGlobalInfo.waylandSurface) {
extensionsToRequest.push_back(kExtensionNameKhrWaylandSurface);
usedKnobs.waylandSurface = true;
}
if (mGlobalInfo.win32Surface) {
extensionsToRequest.push_back(kExtensionNameKhrWin32Surface);
usedKnobs.win32Surface = true;
}
if (mGlobalInfo.xcbSurface) {
extensionsToRequest.push_back(kExtensionNameKhrXcbSurface);
usedKnobs.xcbSurface = true;
}
if (mGlobalInfo.xlibSurface) {
extensionsToRequest.push_back(kExtensionNameKhrXlibSurface);
usedKnobs.xlibSurface = true;
}
if (mGlobalInfo.fuchsiaImagePipeSurface) {
extensionsToRequest.push_back(kExtensionNameFuchsiaImagePipeSurface);
usedKnobs.fuchsiaImagePipeSurface = true;
}
VkApplicationInfo appInfo;
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pNext = nullptr;
appInfo.pApplicationName = nullptr;
appInfo.applicationVersion = 0;
appInfo.pEngineName = nullptr;
appInfo.engineVersion = 0;
appInfo.apiVersion = mGlobalInfo.apiVersion;
VkInstanceCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pNext = nullptr;
createInfo.flags = 0;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledLayerCount = static_cast<uint32_t>(layersToRequest.size());
createInfo.ppEnabledLayerNames = layersToRequest.data();
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensionsToRequest.size());
createInfo.ppEnabledExtensionNames = extensionsToRequest.data();
DAWN_TRY(CheckVkSuccess(mFunctions.CreateInstance(&createInfo, nullptr, &mInstance),
"vkCreateInstance"));
return usedKnobs;
}
MaybeError Backend::RegisterDebugReport() {
VkDebugReportCallbackCreateInfoEXT createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
createInfo.pNext = nullptr;
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
createInfo.pfnCallback = Backend::OnDebugReportCallback;
createInfo.pUserData = this;
return CheckVkSuccess(mFunctions.CreateDebugReportCallbackEXT(
mInstance, &createInfo, nullptr, &mDebugReportCallback),
"vkCreateDebugReportcallback");
}
VKAPI_ATTR VkBool32 VKAPI_CALL
Backend::OnDebugReportCallback(VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT /*objectType*/,
uint64_t /*object*/,
size_t /*location*/,
int32_t /*messageCode*/,
const char* /*pLayerPrefix*/,
const char* pMessage,
void* /*pUserdata*/) {
std::cout << pMessage << std::endl;
ASSERT((flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) == 0);
return VK_FALSE;
}
BackendConnection* Connect(InstanceBase* instance) {
Backend* backend = new Backend(instance);
if (instance->ConsumedError(backend->Initialize())) {
delete backend;
return nullptr;
}
return backend;
}
}} // namespace dawn_native::vulkan