mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-09 17:14:47 -06:00
Vulkan: implement Android surface & recreation
This commit is contained in:
parent
03e1aab320
commit
4f64e1186f
@ -22,6 +22,10 @@ elseif(UNIX)
|
||||
else()
|
||||
add_compile_definitions(_XOPEN_SOURCE)
|
||||
endif()
|
||||
elseif(ANDROID)
|
||||
if(ENABLE_VULKAN)
|
||||
add_compile_definitions(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
endif()
|
||||
else()
|
||||
if (ENABLE_VULKAN)
|
||||
add_compile_definitions(
|
||||
|
||||
@ -15,7 +15,11 @@ SwapchainInfoVk::SwapchainInfoVk(bool mainWindow, Vector2i size) : mainWindow(ma
|
||||
m_logicalDevice = renderer->GetLogicalDevice();
|
||||
m_physicalDevice = renderer->GetPhysicalDevice();
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
m_surface = renderer->CreateFramebufferSurface(m_instance, windowHandleInfo, &m_currentWindow);
|
||||
#else
|
||||
m_surface = renderer->CreateFramebufferSurface(m_instance, windowHandleInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +30,31 @@ SwapchainInfoVk::~SwapchainInfoVk()
|
||||
vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
|
||||
}
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
void SwapchainInfoVk::RecreateSurface()
|
||||
{
|
||||
if (!mainWindow)
|
||||
return;
|
||||
|
||||
auto& windowHandleInfo = WindowSystem::GetWindowInfo().canvas_main;
|
||||
|
||||
windowHandleInfo.surface.wait(m_currentWindow);
|
||||
|
||||
auto newSurface = VulkanRenderer::CreateFramebufferSurface(m_instance, windowHandleInfo, &m_currentWindow);
|
||||
vkDestroySurfaceKHR(m_instance, m_surface, nullptr);
|
||||
m_surface = newSurface;
|
||||
|
||||
surfaceWasLost = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void SwapchainInfoVk::Create()
|
||||
{
|
||||
#if BOOST_PLAT_ANDROID
|
||||
if (surfaceWasLost)
|
||||
RecreateSurface();
|
||||
#endif
|
||||
|
||||
const auto details = QuerySwapchainSupport(m_surface, m_physicalDevice);
|
||||
m_surfaceFormat = ChooseSurfaceFormat(details.formats);
|
||||
m_actualExtent = ChooseSwapExtent(details.capabilities);
|
||||
@ -231,6 +258,15 @@ bool SwapchainInfoVk::AcquireImage()
|
||||
VkResult result = vkAcquireNextImageKHR(m_logicalDevice, m_swapchain, 1'000'000'000, acquireSemaphore, m_imageAvailableFence, &swapchainImageIndex);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
m_shouldRecreate = true;
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
if (result == VK_ERROR_SURFACE_LOST_KHR)
|
||||
{
|
||||
surfaceWasLost = true;
|
||||
m_shouldRecreate = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (result == VK_TIMEOUT)
|
||||
{
|
||||
swapchainImageIndex = -1;
|
||||
@ -240,10 +276,17 @@ bool SwapchainInfoVk::AcquireImage()
|
||||
if (result < 0)
|
||||
{
|
||||
swapchainImageIndex = -1;
|
||||
if (result != VK_ERROR_OUT_OF_DATE_KHR)
|
||||
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result));
|
||||
return false;
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
return false;
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
if (result == VK_ERROR_SURFACE_LOST_KHR)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
throw std::runtime_error(fmt::format("Failed to acquire next image: {}", result));
|
||||
}
|
||||
|
||||
m_currentSemaphore = acquireSemaphore;
|
||||
m_awaitableFence = m_imageAvailableFence;
|
||||
m_acquireIndex = (m_acquireIndex + 1) % m_swapchainImages.size();
|
||||
@ -319,7 +362,7 @@ VkSurfaceFormatKHR SwapchainInfoVk::ChooseSurfaceFormat(const std::vector<VkSurf
|
||||
|
||||
for (const auto& format : formats)
|
||||
{
|
||||
if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
if ((format.format == VK_FORMAT_B8G8R8A8_UNORM || format.format == VK_FORMAT_R8G8B8A8_UNORM) && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return format;
|
||||
}
|
||||
|
||||
@ -391,8 +434,11 @@ VkSwapchainCreateInfoKHR SwapchainInfoVk::CreateSwapchainCreateInfo(VkSurfaceKHR
|
||||
}
|
||||
else
|
||||
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
|
||||
#else
|
||||
createInfo.preTransform = swapchainSupport.capabilities.currentTransform;
|
||||
#endif
|
||||
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
createInfo.presentMode = ChoosePresentMode(swapchainSupport.presentModes);
|
||||
createInfo.clipped = VK_TRUE;
|
||||
|
||||
@ -3,6 +3,10 @@
|
||||
#include "util/math/vector2.h"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
#include <android/native_window.h>
|
||||
#endif
|
||||
|
||||
struct SwapchainInfoVk
|
||||
{
|
||||
enum class VSync
|
||||
@ -58,10 +62,13 @@ struct SwapchainInfoVk
|
||||
|
||||
bool mainWindow{};
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
bool surfaceWasLost = false;
|
||||
#endif
|
||||
|
||||
bool m_shouldRecreate = false;
|
||||
VSync m_vsyncState = VSync::Immediate;
|
||||
bool hasDefinedSwapchainImage{}; // indicates if the swapchain image is in a defined state
|
||||
|
||||
VkInstance m_instance{};
|
||||
VkPhysicalDevice m_physicalDevice{};
|
||||
VkDevice m_logicalDevice{};
|
||||
@ -91,5 +98,10 @@ private:
|
||||
VkFence m_awaitableFence = VK_NULL_HANDLE;
|
||||
VkSemaphore m_currentSemaphore = VK_NULL_HANDLE;
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
void RecreateSurface();
|
||||
ANativeWindow* m_currentWindow = nullptr;
|
||||
#endif
|
||||
|
||||
std::array<uint32, 2> m_swapchainQueueFamilyIndices;
|
||||
};
|
||||
|
||||
@ -130,12 +130,16 @@ VKFUNC_DEVICE(vkDestroyPipeline);
|
||||
VKFUNC_DEVICE(vkCmdBindPipeline);
|
||||
|
||||
// swapchain
|
||||
#if BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
#if BOOST_PLAT_ANDROID
|
||||
VKFUNC_INSTANCE(vkCreateAndroidSurfaceKHR);
|
||||
#elif BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
VKFUNC_INSTANCE(vkCreateXlibSurfaceKHR);
|
||||
VKFUNC_INSTANCE(vkCreateXcbSurfaceKHR);
|
||||
|
||||
#ifdef HAS_WAYLAND
|
||||
VKFUNC_INSTANCE(vkCreateWaylandSurfaceKHR);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
|
||||
@ -113,6 +113,8 @@ std::vector<VulkanRenderer::DeviceInfo> VulkanRenderer::GetDevices()
|
||||
requiredExtensions.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#if BOOST_OS_WINDOWS
|
||||
requiredExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#elif BOOST_PLAT_ANDROID
|
||||
requiredExtensions.emplace_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
||||
#elif BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
auto backend = WindowSystem::GetWindowInfo().window_main.backend;
|
||||
if(backend == WindowSystem::WindowHandleInfo::Backend::X11)
|
||||
@ -1481,6 +1483,8 @@ std::vector<const char*> VulkanRenderer::CheckInstanceExtensionSupport(FeatureCo
|
||||
requiredInstanceExtensions.emplace_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
||||
#if BOOST_OS_WINDOWS
|
||||
requiredInstanceExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
||||
#elif BOOST_PLAT_ANDROID
|
||||
requiredInstanceExtensions.emplace_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
||||
#elif BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
auto backend = WindowSystem::GetWindowInfo().window_main.backend;
|
||||
if(backend == WindowSystem::WindowHandleInfo::Backend::X11)
|
||||
@ -1568,7 +1572,25 @@ VkSurfaceKHR VulkanRenderer::CreateWinSurface(VkInstance instance, HWND hwindow)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
#if BOOST_PLAT_ANDROID
|
||||
VkSurfaceKHR VulkanRenderer::CreateAndroidSurface(VkInstance instance, ANativeWindow* window)
|
||||
{
|
||||
VkAndroidSurfaceCreateInfoKHR sci{};
|
||||
sci.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
|
||||
sci.flags = 0;
|
||||
sci.window = window;
|
||||
|
||||
VkSurfaceKHR result;
|
||||
VkResult err;
|
||||
if ((err = vkCreateAndroidSurfaceKHR(instance, &sci, nullptr, &result)) != VK_SUCCESS)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Cannot create an Android Vulkan surface: {}", (sint32)err);
|
||||
throw std::runtime_error(fmt::format("Cannot create an Android Vulkan surface: {}", err));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#elif BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
VkSurfaceKHR VulkanRenderer::CreateXlibSurface(VkInstance instance, Display* dpy, Window window)
|
||||
{
|
||||
VkXlibSurfaceCreateInfoKHR sci{};
|
||||
@ -1625,9 +1647,23 @@ VkSurfaceKHR VulkanRenderer::CreateWaylandSurface(VkInstance instance, wl_displa
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif // HAS_WAYLAND
|
||||
#endif // BOOST_OS_LINUX
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struct WindowSystem::WindowHandleInfo& windowInfo, ANativeWindow** nativeWindow)
|
||||
{
|
||||
auto window = static_cast<ANativeWindow*>(windowInfo.surface.load());
|
||||
VkSurfaceKHR surface = CreateAndroidSurface(instance, window);
|
||||
|
||||
if (nativeWindow != nullptr)
|
||||
{
|
||||
*nativeWindow = window;
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
#else
|
||||
VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, WindowSystem::WindowHandleInfo& windowInfo)
|
||||
{
|
||||
#if BOOST_OS_WINDOWS
|
||||
@ -1644,6 +1680,7 @@ VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, Windo
|
||||
return CreateCocoaSurface(instance, windowInfo.surface.load());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void VulkanRenderer::CreateCommandPool()
|
||||
{
|
||||
@ -3029,6 +3066,11 @@ bool VulkanRenderer::UpdateSwapchainProperties(bool mainWindow)
|
||||
if (width != extent.width || height != extent.height)
|
||||
stateChanged = true;
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
if (chainInfo.surfaceWasLost)
|
||||
stateChanged = true;
|
||||
#endif
|
||||
|
||||
if(stateChanged)
|
||||
{
|
||||
try
|
||||
@ -3104,19 +3146,34 @@ void VulkanRenderer::SwapBuffer(bool mainWindow)
|
||||
}
|
||||
|
||||
VkResult result = vkQueuePresentKHR(m_presentQueue, &presentInfo);
|
||||
if (result < 0 && result != VK_ERROR_OUT_OF_DATE_KHR)
|
||||
if (result < 0 && result != VK_ERROR_OUT_OF_DATE_KHR
|
||||
#if BOOST_PLAT_ANDROID
|
||||
&& result != VK_ERROR_SURFACE_LOST_KHR
|
||||
#endif
|
||||
)
|
||||
{
|
||||
throw std::runtime_error(fmt::format("Failed to present image: {}", result));
|
||||
}
|
||||
if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
chainInfo.m_shouldRecreate = true;
|
||||
|
||||
if(result >= 0)
|
||||
if (result >= 0)
|
||||
{
|
||||
chainInfo.m_queueDepth++;
|
||||
chainInfo.m_presentId++;
|
||||
}
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
if (result == VK_ERROR_SURFACE_LOST_KHR)
|
||||
chainInfo.surfaceWasLost = true;
|
||||
#endif
|
||||
|
||||
#if !BOOST_PLAT_ANDROID
|
||||
if (result == VK_SUBOPTIMAL_KHR)
|
||||
chainInfo.m_shouldRecreate = true;
|
||||
#endif
|
||||
|
||||
chainInfo.hasDefinedSwapchainImage = false;
|
||||
|
||||
chainInfo.swapchainImageIndex = -1;
|
||||
|
||||
@ -216,16 +216,21 @@ public:
|
||||
#if BOOST_OS_WINDOWS
|
||||
static VkSurfaceKHR CreateWinSurface(VkInstance instance, HWND hwindow);
|
||||
#endif
|
||||
#if BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
#if BOOST_PLAT_ANDROID
|
||||
static VkSurfaceKHR CreateAndroidSurface(VkInstance instance, ANativeWindow* window);
|
||||
#elif BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
static VkSurfaceKHR CreateXlibSurface(VkInstance instance, Display* dpy, Window window);
|
||||
static VkSurfaceKHR CreateXcbSurface(VkInstance instance, xcb_connection_t* connection, xcb_window_t window);
|
||||
#ifdef HAS_WAYLAND
|
||||
#ifdef HAS_WAYLAND
|
||||
static VkSurfaceKHR CreateWaylandSurface(VkInstance instance, wl_display* display, wl_surface* surface);
|
||||
#endif
|
||||
#endif // HAS_WAYLAND
|
||||
#endif
|
||||
|
||||
#if BOOST_PLAT_ANDROID
|
||||
static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowSystem::WindowHandleInfo& windowInfo, ANativeWindow** nativeWindow = nullptr);
|
||||
#else
|
||||
static VkSurfaceKHR CreateFramebufferSurface(VkInstance instance, struct WindowSystem::WindowHandleInfo& windowInfo);
|
||||
|
||||
#endif
|
||||
void AppendOverlayDebugInfo() override;
|
||||
|
||||
void ImguiInit();
|
||||
|
||||
@ -12,6 +12,7 @@ namespace WindowSystem
|
||||
Wayland,
|
||||
Cocoa,
|
||||
Windows,
|
||||
Android,
|
||||
} backend;
|
||||
std::atomic<void*> display = nullptr;
|
||||
std::atomic<void*> surface = nullptr;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user