Browse Source
Merge pull request #5230 from ReinUsesLisp/vulkan-common
Merge pull request #5230 from ReinUsesLisp/vulkan-common
vulkan_common: Move reusable Vulkan abstractions to a separate directorynce_cpp
committed by
GitHub
60 changed files with 574 additions and 486 deletions
-
12src/video_core/CMakeLists.txt
-
2src/video_core/renderer_vulkan/blit_image.cpp
-
2src/video_core/renderer_vulkan/blit_image.h
-
2src/video_core/renderer_vulkan/maxwell_to_vk.cpp
-
2src/video_core/renderer_vulkan/maxwell_to_vk.h
-
306src/video_core/renderer_vulkan/renderer_vulkan.cpp
-
11src/video_core/renderer_vulkan/renderer_vulkan.h
-
2src/video_core/renderer_vulkan/vk_blit_screen.cpp
-
2src/video_core/renderer_vulkan/vk_blit_screen.h
-
2src/video_core/renderer_vulkan/vk_buffer_cache.cpp
-
2src/video_core/renderer_vulkan/vk_buffer_cache.h
-
2src/video_core/renderer_vulkan/vk_command_pool.cpp
-
2src/video_core/renderer_vulkan/vk_command_pool.h
-
2src/video_core/renderer_vulkan/vk_compute_pass.cpp
-
2src/video_core/renderer_vulkan/vk_compute_pass.h
-
2src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
-
2src/video_core/renderer_vulkan/vk_compute_pipeline.h
-
2src/video_core/renderer_vulkan/vk_descriptor_pool.cpp
-
2src/video_core/renderer_vulkan/vk_descriptor_pool.h
-
146src/video_core/renderer_vulkan/vk_device.cpp
-
18src/video_core/renderer_vulkan/vk_device.h
-
2src/video_core/renderer_vulkan/vk_fence_manager.cpp
-
2src/video_core/renderer_vulkan/vk_fence_manager.h
-
2src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
-
2src/video_core/renderer_vulkan/vk_graphics_pipeline.h
-
2src/video_core/renderer_vulkan/vk_master_semaphore.cpp
-
2src/video_core/renderer_vulkan/vk_master_semaphore.h
-
2src/video_core/renderer_vulkan/vk_memory_manager.cpp
-
2src/video_core/renderer_vulkan/vk_memory_manager.h
-
2src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
-
2src/video_core/renderer_vulkan/vk_pipeline_cache.h
-
2src/video_core/renderer_vulkan/vk_query_cache.cpp
-
2src/video_core/renderer_vulkan/vk_query_cache.h
-
2src/video_core/renderer_vulkan/vk_rasterizer.cpp
-
2src/video_core/renderer_vulkan/vk_rasterizer.h
-
2src/video_core/renderer_vulkan/vk_scheduler.cpp
-
2src/video_core/renderer_vulkan/vk_scheduler.h
-
11src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
-
2src/video_core/renderer_vulkan/vk_shader_util.cpp
-
2src/video_core/renderer_vulkan/vk_shader_util.h
-
2src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp
-
2src/video_core/renderer_vulkan/vk_staging_buffer_pool.h
-
2src/video_core/renderer_vulkan/vk_stream_buffer.cpp
-
2src/video_core/renderer_vulkan/vk_stream_buffer.h
-
2src/video_core/renderer_vulkan/vk_swapchain.cpp
-
2src/video_core/renderer_vulkan/vk_swapchain.h
-
2src/video_core/renderer_vulkan/vk_texture_cache.cpp
-
2src/video_core/renderer_vulkan/vk_texture_cache.h
-
2src/video_core/renderer_vulkan/vk_update_descriptor.cpp
-
2src/video_core/renderer_vulkan/vk_update_descriptor.h
-
45src/video_core/vulkan_common/vulkan_debug_callback.cpp
-
11src/video_core/vulkan_common/vulkan_debug_callback.h
-
151src/video_core/vulkan_common/vulkan_instance.cpp
-
32src/video_core/vulkan_common/vulkan_instance.h
-
36src/video_core/vulkan_common/vulkan_library.cpp
-
13src/video_core/vulkan_common/vulkan_library.h
-
81src/video_core/vulkan_common/vulkan_surface.cpp
-
18src/video_core/vulkan_common/vulkan_surface.h
-
58src/video_core/vulkan_common/vulkan_wrapper.cpp
-
23src/video_core/vulkan_common/vulkan_wrapper.h
@ -0,0 +1,45 @@ |
|||
// Copyright 2020 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <string_view>
|
|||
#include "common/logging/log.h"
|
|||
#include "video_core/vulkan_common/vulkan_debug_callback.h"
|
|||
|
|||
namespace Vulkan { |
|||
namespace { |
|||
VkBool32 Callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, |
|||
VkDebugUtilsMessageTypeFlagsEXT type, |
|||
const VkDebugUtilsMessengerCallbackDataEXT* data, |
|||
[[maybe_unused]] void* user_data) { |
|||
const std::string_view message{data->pMessage}; |
|||
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) { |
|||
LOG_CRITICAL(Render_Vulkan, "{}", message); |
|||
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { |
|||
LOG_WARNING(Render_Vulkan, "{}", message); |
|||
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) { |
|||
LOG_INFO(Render_Vulkan, "{}", message); |
|||
} else if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) { |
|||
LOG_DEBUG(Render_Vulkan, "{}", message); |
|||
} |
|||
return VK_FALSE; |
|||
} |
|||
} // Anonymous namespace
|
|||
|
|||
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance) { |
|||
return instance.CreateDebugUtilsMessenger(VkDebugUtilsMessengerCreateInfoEXT{ |
|||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, |
|||
.pNext = nullptr, |
|||
.flags = 0, |
|||
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | |
|||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | |
|||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | |
|||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, |
|||
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | |
|||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | |
|||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, |
|||
.pfnUserCallback = Callback, |
|||
}); |
|||
} |
|||
|
|||
} // namespace Vulkan
|
|||
@ -0,0 +1,11 @@ |
|||
// Copyright 2020 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#include "video_core/vulkan_common/vulkan_wrapper.h" |
|||
|
|||
namespace Vulkan { |
|||
|
|||
vk::DebugUtilsMessenger CreateDebugCallback(const vk::Instance& instance); |
|||
|
|||
} // namespace Vulkan |
|||
@ -0,0 +1,151 @@ |
|||
// Copyright 2020 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <algorithm>
|
|||
#include <optional>
|
|||
#include <span>
|
|||
#include <utility>
|
|||
#include <vector>
|
|||
|
|||
#include "common/common_types.h"
|
|||
#include "common/dynamic_library.h"
|
|||
#include "common/logging/log.h"
|
|||
#include "core/frontend/emu_window.h"
|
|||
#include "video_core/vulkan_common/vulkan_instance.h"
|
|||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
|||
|
|||
// Include these late to avoid polluting previous headers
|
|||
#ifdef _WIN32
|
|||
#include <windows.h>
|
|||
// ensure include order
|
|||
#include <vulkan/vulkan_win32.h>
|
|||
#endif
|
|||
|
|||
#if !defined(_WIN32) && !defined(__APPLE__)
|
|||
#include <X11/Xlib.h>
|
|||
#include <vulkan/vulkan_wayland.h>
|
|||
#include <vulkan/vulkan_xlib.h>
|
|||
#endif
|
|||
|
|||
namespace Vulkan { |
|||
namespace { |
|||
[[nodiscard]] std::vector<const char*> RequiredExtensions( |
|||
Core::Frontend::WindowSystemType window_type, bool enable_debug_utils) { |
|||
std::vector<const char*> extensions; |
|||
extensions.reserve(6); |
|||
switch (window_type) { |
|||
case Core::Frontend::WindowSystemType::Headless: |
|||
break; |
|||
#ifdef _WIN32
|
|||
case Core::Frontend::WindowSystemType::Windows: |
|||
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); |
|||
break; |
|||
#endif
|
|||
#if !defined(_WIN32) && !defined(__APPLE__)
|
|||
case Core::Frontend::WindowSystemType::X11: |
|||
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); |
|||
break; |
|||
case Core::Frontend::WindowSystemType::Wayland: |
|||
extensions.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); |
|||
break; |
|||
#endif
|
|||
default: |
|||
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); |
|||
break; |
|||
} |
|||
if (window_type != Core::Frontend::WindowSystemType::Headless) { |
|||
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); |
|||
} |
|||
if (enable_debug_utils) { |
|||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
|||
} |
|||
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
|||
return extensions; |
|||
} |
|||
|
|||
[[nodiscard]] bool AreExtensionsSupported(const vk::InstanceDispatch& dld, |
|||
std::span<const char* const> extensions) { |
|||
const std::optional properties = vk::EnumerateInstanceExtensionProperties(dld); |
|||
if (!properties) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to query extension properties"); |
|||
return false; |
|||
} |
|||
for (const char* extension : extensions) { |
|||
const auto it = std::ranges::find_if(*properties, [extension](const auto& prop) { |
|||
return std::strcmp(extension, prop.extensionName) == 0; |
|||
}); |
|||
if (it == properties->end()) { |
|||
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension); |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
[[nodiscard]] std::vector<const char*> Layers(bool enable_layers) { |
|||
std::vector<const char*> layers; |
|||
if (enable_layers) { |
|||
layers.push_back("VK_LAYER_KHRONOS_validation"); |
|||
} |
|||
return layers; |
|||
} |
|||
|
|||
void RemoveUnavailableLayers(const vk::InstanceDispatch& dld, std::vector<const char*>& layers) { |
|||
const std::optional layer_properties = vk::EnumerateInstanceLayerProperties(dld); |
|||
if (!layer_properties) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to query layer properties, disabling layers"); |
|||
layers.clear(); |
|||
} |
|||
std::erase_if(layers, [&layer_properties](const char* layer) { |
|||
const auto comp = [layer](const VkLayerProperties& layer_property) { |
|||
return std::strcmp(layer, layer_property.layerName) == 0; |
|||
}; |
|||
const auto it = std::ranges::find_if(*layer_properties, comp); |
|||
if (it == layer_properties->end()) { |
|||
LOG_ERROR(Render_Vulkan, "Layer {} not available, removing it", layer); |
|||
return true; |
|||
} |
|||
return false; |
|||
}); |
|||
} |
|||
} // Anonymous namespace
|
|||
|
|||
vk::Instance CreateInstance(const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, |
|||
u32 required_version, Core::Frontend::WindowSystemType window_type, |
|||
bool enable_debug_utils, bool enable_layers) { |
|||
if (!library.IsOpen()) { |
|||
LOG_ERROR(Render_Vulkan, "Vulkan library not available"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
if (!library.GetSymbol("vkGetInstanceProcAddr", &dld.vkGetInstanceProcAddr)) { |
|||
LOG_ERROR(Render_Vulkan, "vkGetInstanceProcAddr not present in Vulkan"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
if (!vk::Load(dld)) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan function pointers"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
const std::vector<const char*> extensions = RequiredExtensions(window_type, enable_debug_utils); |
|||
if (!AreExtensionsSupported(dld, extensions)) { |
|||
throw vk::Exception(VK_ERROR_EXTENSION_NOT_PRESENT); |
|||
} |
|||
std::vector<const char*> layers = Layers(enable_layers); |
|||
RemoveUnavailableLayers(dld, layers); |
|||
|
|||
const u32 available_version = vk::AvailableVersion(dld); |
|||
if (available_version < required_version) { |
|||
LOG_ERROR(Render_Vulkan, "Vulkan {}.{} is not supported, {}.{} is required", |
|||
VK_VERSION_MAJOR(available_version), VK_VERSION_MINOR(available_version), |
|||
VK_VERSION_MAJOR(required_version), VK_VERSION_MINOR(required_version)); |
|||
throw vk::Exception(VK_ERROR_INCOMPATIBLE_DRIVER); |
|||
} |
|||
vk::Instance instance = vk::Instance::Create(required_version, layers, extensions, dld); |
|||
if (!vk::Load(*instance, dld)) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to load Vulkan instance function pointers"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
return instance; |
|||
} |
|||
|
|||
} // namespace Vulkan
|
|||
@ -0,0 +1,32 @@ |
|||
// Copyright 2020 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_types.h" |
|||
#include "common/dynamic_library.h" |
|||
#include "core/frontend/emu_window.h" |
|||
#include "video_core/vulkan_common/vulkan_wrapper.h" |
|||
|
|||
namespace Vulkan { |
|||
|
|||
/** |
|||
* Create a Vulkan instance |
|||
* |
|||
* @param library Dynamic library to load the Vulkan instance from |
|||
* @param dld Dispatch table to load function pointers into |
|||
* @param required_version Required Vulkan version (for example, VK_API_VERSION_1_1) |
|||
* @param window_type Window system type's enabled extension |
|||
* @param enable_debug_utils Whether to enable VK_EXT_debug_utils_extension_name or not |
|||
* @param enable_layers Whether to enable Vulkan validation layers or not |
|||
* |
|||
* @return A new Vulkan instance |
|||
* @throw vk::Exception on failure |
|||
*/ |
|||
[[nodiscard]] vk::Instance CreateInstance( |
|||
const Common::DynamicLibrary& library, vk::InstanceDispatch& dld, u32 required_version, |
|||
Core::Frontend::WindowSystemType window_type = Core::Frontend::WindowSystemType::Headless, |
|||
bool enable_debug_utils = false, bool enable_layers = false); |
|||
|
|||
} // namespace Vulkan |
|||
@ -0,0 +1,36 @@ |
|||
// Copyright 2020 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <cstdlib>
|
|||
#include <string>
|
|||
|
|||
#include "common/dynamic_library.h"
|
|||
#include "common/file_util.h"
|
|||
#include "video_core/vulkan_common/vulkan_library.h"
|
|||
|
|||
namespace Vulkan { |
|||
|
|||
Common::DynamicLibrary OpenLibrary() { |
|||
Common::DynamicLibrary library; |
|||
#ifdef __APPLE__
|
|||
// Check if a path to a specific Vulkan library has been specified.
|
|||
char* const libvulkan_env = std::getenv("LIBVULKAN_PATH"); |
|||
if (!libvulkan_env || !library.Open(libvulkan_env)) { |
|||
// Use the libvulkan.dylib from the application bundle.
|
|||
const std::string filename = |
|||
Common::FS::GetBundleDirectory() + "/Contents/Frameworks/libvulkan.dylib"; |
|||
library.Open(filename.c_str()); |
|||
} |
|||
#else
|
|||
std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); |
|||
if (!library.Open(filename.c_str())) { |
|||
// Android devices may not have libvulkan.so.1, only libvulkan.so.
|
|||
filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); |
|||
void(library.Open(filename.c_str())); |
|||
} |
|||
#endif
|
|||
return library; |
|||
} |
|||
|
|||
} // namespace Vulkan
|
|||
@ -0,0 +1,13 @@ |
|||
// Copyright 2020 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/dynamic_library.h" |
|||
|
|||
namespace Vulkan { |
|||
|
|||
Common::DynamicLibrary OpenLibrary(); |
|||
|
|||
} // namespace Vulkan |
|||
@ -0,0 +1,81 @@ |
|||
// Copyright 2020 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include "common/logging/log.h"
|
|||
#include "core/frontend/emu_window.h"
|
|||
#include "video_core/vulkan_common/vulkan_surface.h"
|
|||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
|||
|
|||
// Include these late to avoid polluting previous headers
|
|||
#ifdef _WIN32
|
|||
#include <windows.h>
|
|||
// ensure include order
|
|||
#include <vulkan/vulkan_win32.h>
|
|||
#endif
|
|||
|
|||
#if !defined(_WIN32) && !defined(__APPLE__)
|
|||
#include <X11/Xlib.h>
|
|||
#include <vulkan/vulkan_wayland.h>
|
|||
#include <vulkan/vulkan_xlib.h>
|
|||
#endif
|
|||
|
|||
namespace Vulkan { |
|||
|
|||
vk::SurfaceKHR CreateSurface(const vk::Instance& instance, |
|||
const Core::Frontend::EmuWindow& emu_window) { |
|||
[[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch(); |
|||
[[maybe_unused]] const auto& window_info = emu_window.GetWindowInfo(); |
|||
VkSurfaceKHR unsafe_surface = nullptr; |
|||
|
|||
#ifdef _WIN32
|
|||
if (window_info.type == Core::Frontend::WindowSystemType::Windows) { |
|||
const HWND hWnd = static_cast<HWND>(window_info.render_surface); |
|||
const VkWin32SurfaceCreateInfoKHR win32_ci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, |
|||
nullptr, 0, nullptr, hWnd}; |
|||
const auto vkCreateWin32SurfaceKHR = reinterpret_cast<PFN_vkCreateWin32SurfaceKHR>( |
|||
dld.vkGetInstanceProcAddr(*instance, "vkCreateWin32SurfaceKHR")); |
|||
if (!vkCreateWin32SurfaceKHR || |
|||
vkCreateWin32SurfaceKHR(*instance, &win32_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to initialize Win32 surface"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
} |
|||
#endif
|
|||
#if !defined(_WIN32) && !defined(__APPLE__)
|
|||
if (window_info.type == Core::Frontend::WindowSystemType::X11) { |
|||
const VkXlibSurfaceCreateInfoKHR xlib_ci{ |
|||
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, |
|||
static_cast<Display*>(window_info.display_connection), |
|||
reinterpret_cast<Window>(window_info.render_surface)}; |
|||
const auto vkCreateXlibSurfaceKHR = reinterpret_cast<PFN_vkCreateXlibSurfaceKHR>( |
|||
dld.vkGetInstanceProcAddr(*instance, "vkCreateXlibSurfaceKHR")); |
|||
if (!vkCreateXlibSurfaceKHR || |
|||
vkCreateXlibSurfaceKHR(*instance, &xlib_ci, nullptr, &unsafe_surface) != VK_SUCCESS) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
} |
|||
if (window_info.type == Core::Frontend::WindowSystemType::Wayland) { |
|||
const VkWaylandSurfaceCreateInfoKHR wayland_ci{ |
|||
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0, |
|||
static_cast<wl_display*>(window_info.display_connection), |
|||
static_cast<wl_surface*>(window_info.render_surface)}; |
|||
const auto vkCreateWaylandSurfaceKHR = reinterpret_cast<PFN_vkCreateWaylandSurfaceKHR>( |
|||
dld.vkGetInstanceProcAddr(*instance, "vkCreateWaylandSurfaceKHR")); |
|||
if (!vkCreateWaylandSurfaceKHR || |
|||
vkCreateWaylandSurfaceKHR(*instance, &wayland_ci, nullptr, &unsafe_surface) != |
|||
VK_SUCCESS) { |
|||
LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
} |
|||
#endif
|
|||
if (!unsafe_surface) { |
|||
LOG_ERROR(Render_Vulkan, "Presentation not supported on this platform"); |
|||
throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); |
|||
} |
|||
return vk::SurfaceKHR(unsafe_surface, *instance, dld); |
|||
} |
|||
|
|||
} // namespace Vulkan
|
|||
@ -0,0 +1,18 @@ |
|||
// Copyright 2020 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include "video_core/vulkan_common/vulkan_wrapper.h" |
|||
|
|||
namespace Core::Frontend { |
|||
class EmuWindow; |
|||
} |
|||
|
|||
namespace Vulkan { |
|||
|
|||
[[nodiscard]] vk::SurfaceKHR CreateSurface(const vk::Instance& instance, |
|||
const Core::Frontend::EmuWindow& emu_window); |
|||
|
|||
} // namespace Vulkan |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue