renderer_vulkan: Isolate surface creation to vk_platform.cpp
* Also cleanup the init code somewhat
This commit is contained in:
@ -14,7 +14,7 @@ namespace Frontend {
|
|||||||
|
|
||||||
/// Information for the Graphics Backends signifying what type of screen pointer is in
|
/// Information for the Graphics Backends signifying what type of screen pointer is in
|
||||||
/// WindowInformation
|
/// WindowInformation
|
||||||
enum class WindowSystemType {
|
enum class WindowSystemType : u8 {
|
||||||
Headless,
|
Headless,
|
||||||
Windows,
|
Windows,
|
||||||
X11,
|
X11,
|
||||||
|
@ -93,6 +93,7 @@ add_library(video_core STATIC
|
|||||||
renderer_vulkan/vk_instance.h
|
renderer_vulkan/vk_instance.h
|
||||||
renderer_vulkan/vk_pipeline_cache.cpp
|
renderer_vulkan/vk_pipeline_cache.cpp
|
||||||
renderer_vulkan/vk_pipeline_cache.h
|
renderer_vulkan/vk_pipeline_cache.h
|
||||||
|
renderer_vulkan/vk_platform.cpp
|
||||||
renderer_vulkan/vk_platform.h
|
renderer_vulkan/vk_platform.h
|
||||||
renderer_vulkan/vk_renderpass_cache.cpp
|
renderer_vulkan/vk_renderpass_cache.cpp
|
||||||
renderer_vulkan/vk_renderpass_cache.h
|
renderer_vulkan/vk_renderpass_cache.h
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
#define VULKAN_HPP_NO_CONSTRUCTORS
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <array>
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "core/frontend/emu_window.h"
|
||||||
#include "video_core/renderer_vulkan/vk_platform.h"
|
#include "video_core/renderer_vulkan/vk_platform.h"
|
||||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||||
|
|
||||||
@ -45,9 +45,7 @@ Instance::Instance(Frontend::EmuWindow& window) {
|
|||||||
.ppEnabledExtensionNames = extensions.data()
|
.ppEnabledExtensionNames = extensions.data()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create VkInstance
|
|
||||||
instance = vk::createInstance(instance_info);
|
instance = vk::createInstance(instance_info);
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
|
||||||
surface = CreateSurface(instance, window);
|
surface = CreateSurface(instance, window);
|
||||||
|
|
||||||
// TODO: GPU select dialog
|
// TODO: GPU select dialog
|
||||||
@ -55,8 +53,7 @@ Instance::Instance(Frontend::EmuWindow& window) {
|
|||||||
physical_device = physical_devices[0];
|
physical_device = physical_devices[0];
|
||||||
device_properties = physical_device.getProperties();
|
device_properties = physical_device.getProperties();
|
||||||
|
|
||||||
// Create logical device
|
CreateDevice();
|
||||||
CreateDevice(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance::~Instance() {
|
Instance::~Instance() {
|
||||||
@ -114,45 +111,16 @@ vk::Format Instance::GetFormatAlternative(vk::Format format) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instance::CreateDevice(bool validation_enabled) {
|
bool Instance::CreateDevice() {
|
||||||
// Determine required extensions and features
|
|
||||||
auto feature_chain = physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
|
auto feature_chain = physical_device.getFeatures2<vk::PhysicalDeviceFeatures2,
|
||||||
vk::PhysicalDeviceDynamicRenderingFeaturesKHR,
|
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
|
||||||
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT,
|
|
||||||
vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT>();
|
|
||||||
|
|
||||||
// Not having geometry shaders or wide lines will cause issues with rendering.
|
// Not having geometry shaders will cause issues with accelerated rendering.
|
||||||
const vk::PhysicalDeviceFeatures available = feature_chain.get().features;
|
const vk::PhysicalDeviceFeatures available = feature_chain.get().features;
|
||||||
if (!available.geometryShader && !available.wideLines) {
|
if (!available.geometryShader) {
|
||||||
LOG_WARNING(Render_Vulkan, "Geometry shaders not availabe! Accelerated rendering not possible!");
|
LOG_WARNING(Render_Vulkan, "Geometry shaders not availabe! Accelerated rendering not possible!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable some common features other emulators like Dolphin use
|
|
||||||
const vk::PhysicalDeviceFeatures2 features = {
|
|
||||||
.features = {
|
|
||||||
.robustBufferAccess = available.robustBufferAccess,
|
|
||||||
.geometryShader = available.geometryShader,
|
|
||||||
.sampleRateShading = available.sampleRateShading,
|
|
||||||
.dualSrcBlend = available.dualSrcBlend,
|
|
||||||
.logicOp = available.logicOp,
|
|
||||||
.depthClamp = available.depthClamp,
|
|
||||||
.largePoints = available.largePoints,
|
|
||||||
.samplerAnisotropy = available.samplerAnisotropy,
|
|
||||||
.occlusionQueryPrecise = available.occlusionQueryPrecise,
|
|
||||||
.fragmentStoresAndAtomics = available.fragmentStoresAndAtomics,
|
|
||||||
.shaderStorageImageMultisample = available.shaderStorageImageMultisample,
|
|
||||||
.shaderClipDistance = available.shaderClipDistance
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Enable newer Vulkan features
|
|
||||||
auto enabled_features = vk::StructureChain{
|
|
||||||
features,
|
|
||||||
//feature_chain.get<vk::PhysicalDeviceDynamicRenderingFeaturesKHR>(),
|
|
||||||
//feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
|
|
||||||
//feature_chain.get<vk::PhysicalDeviceExtendedDynamicState2FeaturesEXT>()
|
|
||||||
};
|
|
||||||
|
|
||||||
auto extension_list = physical_device.enumerateDeviceExtensionProperties();
|
auto extension_list = physical_device.enumerateDeviceExtensionProperties();
|
||||||
if (extension_list.empty()) {
|
if (extension_list.empty()) {
|
||||||
LOG_CRITICAL(Render_Vulkan, "No extensions supported by device.");
|
LOG_CRITICAL(Render_Vulkan, "No extensions supported by device.");
|
||||||
@ -163,7 +131,7 @@ bool Instance::CreateDevice(bool validation_enabled) {
|
|||||||
std::array<const char*, 6> enabled_extensions;
|
std::array<const char*, 6> enabled_extensions;
|
||||||
u32 enabled_extension_count = 0;
|
u32 enabled_extension_count = 0;
|
||||||
|
|
||||||
auto AddExtension = [&](std::string_view name, bool required) -> bool {
|
auto AddExtension = [&](std::string_view name) -> bool {
|
||||||
auto result = std::find_if(extension_list.begin(), extension_list.end(), [&](const auto& prop) {
|
auto result = std::find_if(extension_list.begin(), extension_list.end(), [&](const auto& prop) {
|
||||||
return name.compare(prop.extensionName.data());
|
return name.compare(prop.extensionName.data());
|
||||||
});
|
});
|
||||||
@ -174,20 +142,13 @@ bool Instance::CreateDevice(bool validation_enabled) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (required) {
|
LOG_WARNING(Render_Vulkan, "Extension {} unavailable.", name);
|
||||||
LOG_ERROR(Render_Vulkan, "Unable to find required extension {}.", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add required extensions
|
extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, true);
|
push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME);
|
||||||
|
AddExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||||
// Check for optional features
|
|
||||||
//dynamic_rendering = AddExtension(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, false);
|
|
||||||
//extended_dynamic_state = AddExtension(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
|
|
||||||
//push_descriptors = AddExtension(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, false);
|
|
||||||
|
|
||||||
// Search queue families for graphics and present queues
|
// Search queue families for graphics and present queues
|
||||||
auto family_properties = physical_device.getQueueFamilyProperties();
|
auto family_properties = physical_device.getQueueFamilyProperties();
|
||||||
@ -236,39 +197,50 @@ bool Instance::CreateDevice(bool validation_enabled) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::DeviceCreateInfo device_info = {
|
const u32 queue_count = graphics_queue_family_index != present_queue_family_index ? 2u : 1u;
|
||||||
.pNext = &features, // TODO: Change this
|
const vk::StructureChain device_chain = {
|
||||||
.queueCreateInfoCount = 1,
|
vk::DeviceCreateInfo{
|
||||||
.pQueueCreateInfos = queue_infos.data(),
|
.queueCreateInfoCount = queue_count,
|
||||||
.enabledExtensionCount = enabled_extension_count,
|
.pQueueCreateInfos = queue_infos.data(),
|
||||||
.ppEnabledExtensionNames = enabled_extensions.data(),
|
.enabledExtensionCount = enabled_extension_count,
|
||||||
|
.ppEnabledExtensionNames = enabled_extensions.data(),
|
||||||
|
},
|
||||||
|
vk::PhysicalDeviceFeatures2{
|
||||||
|
.features = {
|
||||||
|
.robustBufferAccess = available.robustBufferAccess,
|
||||||
|
.geometryShader = available.geometryShader,
|
||||||
|
.dualSrcBlend = available.dualSrcBlend,
|
||||||
|
.logicOp = available.logicOp,
|
||||||
|
.depthClamp = available.depthClamp,
|
||||||
|
.largePoints = available.largePoints,
|
||||||
|
.samplerAnisotropy = available.samplerAnisotropy,
|
||||||
|
.fragmentStoresAndAtomics = available.fragmentStoresAndAtomics,
|
||||||
|
.shaderStorageImageMultisample = available.shaderStorageImageMultisample,
|
||||||
|
.shaderClipDistance = available.shaderClipDistance
|
||||||
|
}
|
||||||
|
},
|
||||||
|
feature_chain.get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (graphics_queue_family_index != present_queue_family_index) {
|
|
||||||
device_info.queueCreateInfoCount = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create logical device
|
// Create logical device
|
||||||
device = physical_device.createDevice(device_info);
|
device = physical_device.createDevice(device_chain.get());
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);
|
||||||
|
|
||||||
// Grab the graphics and present queues.
|
// Grab the graphics and present queues.
|
||||||
graphics_queue = device.getQueue(graphics_queue_family_index, 0);
|
graphics_queue = device.getQueue(graphics_queue_family_index, 0);
|
||||||
present_queue = device.getQueue(present_queue_family_index, 0);
|
present_queue = device.getQueue(present_queue_family_index, 0);
|
||||||
|
|
||||||
// Create the VMA allocator
|
|
||||||
CreateAllocator();
|
CreateAllocator();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::CreateAllocator() {
|
void Instance::CreateAllocator() {
|
||||||
VmaVulkanFunctions functions = {
|
const VmaVulkanFunctions functions = {
|
||||||
.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr,
|
.vkGetInstanceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetInstanceProcAddr,
|
||||||
.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr
|
.vkGetDeviceProcAddr = VULKAN_HPP_DEFAULT_DISPATCHER.vkGetDeviceProcAddr
|
||||||
};
|
};
|
||||||
|
|
||||||
VmaAllocatorCreateInfo allocator_info = {
|
const VmaAllocatorCreateInfo allocator_info = {
|
||||||
.physicalDevice = physical_device,
|
.physicalDevice = physical_device,
|
||||||
.device = device,
|
.device = device,
|
||||||
.pVulkanFunctions = &functions,
|
.pVulkanFunctions = &functions,
|
||||||
@ -276,7 +248,7 @@ void Instance::CreateAllocator() {
|
|||||||
.vulkanApiVersion = VK_API_VERSION_1_1
|
.vulkanApiVersion = VK_API_VERSION_1_1
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto result = vmaCreateAllocator(&allocator_info, &allocator); result != VK_SUCCESS) {
|
if (VkResult result = vmaCreateAllocator(&allocator_info, &allocator); result != VK_SUCCESS) {
|
||||||
LOG_CRITICAL(Render_Vulkan, "Failed to initialize VMA with error {}", result);
|
LOG_CRITICAL(Render_Vulkan, "Failed to initialize VMA with error {}", result);
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -68,10 +68,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Feature support
|
/// Feature support
|
||||||
bool IsDynamicRenderingSupported() const {
|
|
||||||
return dynamic_rendering;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsExtendedDynamicStateSupported() const {
|
bool IsExtendedDynamicStateSupported() const {
|
||||||
// TODO: Enable this when the pipeline builder is confirmed functional
|
// TODO: Enable this when the pipeline builder is confirmed functional
|
||||||
return false;
|
return false;
|
||||||
@ -102,27 +98,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreateDevice(bool validation_enabled);
|
/// Creates the logical device opportunistically enabling extensions
|
||||||
|
bool CreateDevice();
|
||||||
|
|
||||||
|
/// Creates the VMA allocator handle
|
||||||
void CreateAllocator();
|
void CreateAllocator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Queue family indexes
|
|
||||||
u32 present_queue_family_index = 0;
|
|
||||||
u32 graphics_queue_family_index = 0;
|
|
||||||
vk::Queue present_queue, graphics_queue;
|
|
||||||
|
|
||||||
// Core vulkan objects
|
|
||||||
vk::Device device;
|
vk::Device device;
|
||||||
vk::PhysicalDevice physical_device;
|
vk::PhysicalDevice physical_device;
|
||||||
vk::Instance instance;
|
vk::Instance instance;
|
||||||
vk::SurfaceKHR surface;
|
vk::SurfaceKHR surface;
|
||||||
vk::PhysicalDeviceProperties device_properties;
|
vk::PhysicalDeviceProperties device_properties;
|
||||||
VmaAllocator allocator;
|
VmaAllocator allocator;
|
||||||
|
vk::Queue present_queue;
|
||||||
// Features per vulkan version
|
vk::Queue graphics_queue;
|
||||||
bool dynamic_rendering = false;
|
u32 present_queue_family_index = 0;
|
||||||
|
u32 graphics_queue_family_index = 0;
|
||||||
bool extended_dynamic_state = false;
|
bool extended_dynamic_state = false;
|
||||||
bool push_descriptors = false;
|
bool push_descriptors = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCore::Vulkan
|
} // namespace Vulkan
|
||||||
|
134
src/video_core/renderer_vulkan/vk_platform.cpp
Normal file
134
src/video_core/renderer_vulkan/vk_platform.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
// Copyright 2022 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
// Include the vulkan platform specific header
|
||||||
|
#if defined(ANDROID) || defined (__ANDROID__)
|
||||||
|
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define VK_USE_PLATFORM_WIN32_KHR
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define VK_USE_PLATFORM_MACOS_MVK
|
||||||
|
#define VK_USE_PLATFORM_METAL_EXT
|
||||||
|
#else
|
||||||
|
#ifdef WAYLAND_DISPLAY
|
||||||
|
#define VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
|
#else // wayland
|
||||||
|
#define VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/frontend/emu_window.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_platform.h"
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window) {
|
||||||
|
const auto& window_info = emu_window.GetWindowInfo();
|
||||||
|
vk::SurfaceKHR surface{};
|
||||||
|
|
||||||
|
// Perform instance function loading here, to also load window system functions
|
||||||
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);
|
||||||
|
|
||||||
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
|
if (window_info.type == Frontend::WindowSystemType::Windows) {
|
||||||
|
const vk::Win32SurfaceCreateInfoKHR win32_ci = {
|
||||||
|
.hinstance = nullptr,
|
||||||
|
.hwnd = static_cast<HWND>(window_info.render_surface)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (instance.createWin32SurfaceKHR(&win32_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
||||||
|
LOG_CRITICAL(Render_Vulkan, "Failed to initialize Win32 surface");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||||
|
if (window_info.type == Frontend::WindowSystemType::X11) {
|
||||||
|
const vk::XlibSurfaceCreateInfoKHR xlib_ci = {
|
||||||
|
.dpy = static_cast<Display*>(window_info.display_connection),
|
||||||
|
.window = reinterpret_cast<Window>(window_info.render_surface)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (instance.createXlibSurfaceKHR(&xlib_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||||
|
if (window_info.type == Frontend::WindowSystemType::Wayland) {
|
||||||
|
const vk::WaylandSurfaceCreateInfoKHR wayland_ci{{},
|
||||||
|
static_cast<wl_display*>(window_info.display_connection),
|
||||||
|
static_cast<wl_surface*>(window_info.render_surface)};
|
||||||
|
if (instance.createWaylandSurfaceKHR(&wayland_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!surface) {
|
||||||
|
LOG_CRITICAL(Render_Vulkan, "Presentation not supported on this platform");
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window_type, bool enable_debug_utils) {
|
||||||
|
const auto properties = vk::enumerateInstanceExtensionProperties();
|
||||||
|
if (properties.empty()) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
|
||||||
|
return std::vector<const char*>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the windowing system specific extension
|
||||||
|
std::vector<const char*> extensions;
|
||||||
|
extensions.reserve(6);
|
||||||
|
|
||||||
|
switch (window_type) {
|
||||||
|
case Frontend::WindowSystemType::Headless:
|
||||||
|
break;
|
||||||
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
|
case Frontend::WindowSystemType::Windows:
|
||||||
|
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||||
|
break;
|
||||||
|
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||||
|
case Frontend::WindowSystemType::X11:
|
||||||
|
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
||||||
|
break;
|
||||||
|
#elif defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||||
|
case 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 != Frontend::WindowSystemType::Headless) {
|
||||||
|
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable_debug_utils) {
|
||||||
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const char* extension : extensions) {
|
||||||
|
const auto iter = std::ranges::find_if(properties, [extension](const auto& prop) {
|
||||||
|
return std::strcmp(extension, prop.extensionName) == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (iter == properties.end()) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
|
||||||
|
return std::vector<const char*>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
@ -4,131 +4,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Include the vulkan platform specific header
|
|
||||||
#if defined(ANDROID) || defined (__ANDROID__)
|
|
||||||
#define VK_USE_PLATFORM_ANDROID_KHR 1
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#define VK_USE_PLATFORM_WIN32_KHR 1
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#define VK_USE_PLATFORM_MACOS_MVK 1
|
|
||||||
#define VK_USE_PLATFORM_METAL_EXT 1
|
|
||||||
#else
|
|
||||||
#ifdef WAYLAND_DISPLAY
|
|
||||||
#define VK_USE_PLATFORM_WAYLAND_KHR 1
|
|
||||||
#else // wayland
|
|
||||||
#define VK_USE_PLATFORM_XLIB_KHR 1
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define VULKAN_HPP_NO_CONSTRUCTORS
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/assert.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
|
||||||
#include "core/frontend/emu_window.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_common.h"
|
#include "video_core/renderer_vulkan/vk_common.h"
|
||||||
|
|
||||||
|
namespace Frontend {
|
||||||
|
class EmuWindow;
|
||||||
|
enum class WindowSystemType : u8;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
inline vk::SurfaceKHR CreateSurface(const vk::Instance& instance, const Frontend::EmuWindow& emu_window) {
|
std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window_type, bool enable_debug_utils);
|
||||||
const auto& window_info = emu_window.GetWindowInfo();
|
|
||||||
vk::SurfaceKHR surface;
|
|
||||||
|
|
||||||
#if VK_USE_PLATFORM_WIN32_KHR
|
vk::SurfaceKHR CreateSurface(vk::Instance instance, const Frontend::EmuWindow& emu_window);
|
||||||
if (window_info.type == Frontend::WindowSystemType::Windows) {
|
|
||||||
const vk::Win32SurfaceCreateInfoKHR win32_ci = {
|
|
||||||
.hinstance = nullptr,
|
|
||||||
.hwnd = static_cast<HWND>(window_info.render_surface)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (instance.createWin32SurfaceKHR(&win32_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
|
||||||
LOG_CRITICAL(Render_Vulkan, "Failed to initialize Win32 surface");
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#elif VK_USE_PLATFORM_XLIB_KHR
|
|
||||||
if (window_info.type == Frontend::WindowSystemType::X11) {
|
|
||||||
const vk::XlibSurfaceCreateInfoKHR xlib_ci = {
|
|
||||||
.dpy = static_cast<Display*>(window_info.display_connection),
|
|
||||||
.window = reinterpret_cast<Window>(window_info.render_surface)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (instance.createXlibSurfaceKHR(&xlib_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to initialize Xlib surface");
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif VK_USE_PLATFORM_WAYLAND_KHR
|
|
||||||
if (window_info.type == Frontend::WindowSystemType::Wayland) {
|
|
||||||
const vk::WaylandSurfaceCreateInfoKHR wayland_ci{{},
|
|
||||||
static_cast<wl_display*>(window_info.display_connection),
|
|
||||||
static_cast<wl_surface*>(window_info.render_surface)};
|
|
||||||
if (instance.createWaylandSurfaceKHR(&wayland_ci, nullptr, &surface) != vk::Result::eSuccess) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to initialize Wayland surface");
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!surface) {
|
|
||||||
LOG_CRITICAL(Render_Vulkan, "Presentation not supported on this platform");
|
|
||||||
}
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto GetInstanceExtensions(Frontend::WindowSystemType window_type, bool enable_debug_utils) {
|
|
||||||
const auto properties = vk::enumerateInstanceExtensionProperties();
|
|
||||||
if (properties.empty()) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Failed to query extension properties");
|
|
||||||
return std::vector<const char*>{};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the windowing system specific extension
|
|
||||||
std::vector<const char*> extensions;
|
|
||||||
extensions.reserve(6);
|
|
||||||
|
|
||||||
switch (window_type) {
|
|
||||||
case Frontend::WindowSystemType::Headless:
|
|
||||||
break;
|
|
||||||
#if VK_USE_PLATFORM_WIN32_KHR
|
|
||||||
case Frontend::WindowSystemType::Windows:
|
|
||||||
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
||||||
break;
|
|
||||||
#elif VK_USE_PLATFORM_XLIB_KHR
|
|
||||||
case Frontend::WindowSystemType::X11:
|
|
||||||
extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
|
|
||||||
break;
|
|
||||||
#elif VK_USE_PLATFORM_WAYLAND_KHR
|
|
||||||
case 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 != Frontend::WindowSystemType::Headless) {
|
|
||||||
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enable_debug_utils) {
|
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const char* extension : extensions) {
|
|
||||||
const auto iter = std::ranges::find_if(properties, [extension](const auto& prop) {
|
|
||||||
return std::strcmp(extension, prop.extensionName) == 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (iter == properties.end()) {
|
|
||||||
LOG_ERROR(Render_Vulkan, "Required instance extension {} is not available", extension);
|
|
||||||
return std::vector<const char*>{};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
Reference in New Issue
Block a user