mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2026-07-12 23:01:23 -05:00
Merge a6b4f8720a into d8d37fdbc4
This commit is contained in:
commit
298c77df4a
68
CMake/FindWayland.cmake
Normal file
68
CMake/FindWayland.cmake
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# Try to find Wayland on a Unix system
|
||||
#
|
||||
# This will define:
|
||||
#
|
||||
# Wayland_FOUND - True if Wayland is found
|
||||
#
|
||||
# The following imported targets:
|
||||
# Wayland::Client - Imported Client
|
||||
# Wayland::Server - Imported Server
|
||||
# Wayland::Egl - Imported Egl
|
||||
# Wayland::Cursor - Imported Cursor
|
||||
#
|
||||
# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
IF (NOT WIN32)
|
||||
IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES)
|
||||
# In the cache already
|
||||
SET(WAYLAND_FIND_QUIETLY TRUE)
|
||||
ENDIF ()
|
||||
|
||||
FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h)
|
||||
FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h)
|
||||
FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h)
|
||||
FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h)
|
||||
|
||||
FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client)
|
||||
FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server)
|
||||
FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl)
|
||||
FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
# FIND_PACKAGE_HANDLE_STANDARD_ARGS is just meant to find the main package and set package found. Not set variables or find individual libs
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Wayland REQUIRED_VARS
|
||||
WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR
|
||||
WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR
|
||||
WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR
|
||||
WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if (WAYLAND_CLIENT_INCLUDE_DIR AND WAYLAND_CLIENT_LIBRARIES AND NOT TARGET Wayland::Client)
|
||||
add_library(Wayland::Client UNKNOWN IMPORTED)
|
||||
set_target_properties(Wayland::Client PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CLIENT_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CLIENT_LIBRARIES}")
|
||||
endif()
|
||||
if (WAYLAND_SERVER_INCLUDE_DIR AND WAYLAND_SERVER_LIBRARIES AND NOT TARGET Wayland::Server)
|
||||
add_library(Wayland::Server UNKNOWN IMPORTED)
|
||||
set_target_properties(Wayland::Server PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_SERVER_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_SERVER_LIBRARIES}")
|
||||
endif()
|
||||
if (WAYLAND_EGL_INCLUDE_DIR AND WAYLAND_EGL_LIBRARIES AND NOT TARGET Wayland::Egl)
|
||||
add_library(Wayland::Egl UNKNOWN IMPORTED)
|
||||
set_target_properties(Wayland::Egl PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_EGL_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_EGL_LIBRARIES}")
|
||||
endif()
|
||||
if (WAYLAND_CURSOR_INCLUDE_DIR AND WAYLAND_CURSOR_LIBRARIES AND NOT TARGET Wayland::Cursor)
|
||||
add_library(Wayland::Cursor UNKNOWN IMPORTED)
|
||||
set_target_properties(Wayland::Cursor PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WAYLAND_CURSOR_INCLUDE_DIR}" IMPORTED_LOCATION "${WAYLAND_CURSOR_LIBRARIES}")
|
||||
endif()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES
|
||||
WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES
|
||||
WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES
|
||||
WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES
|
||||
)
|
||||
|
||||
ENDIF ()
|
||||
|
|
@ -67,6 +67,7 @@ set(DOLPHIN_DEFAULT_UPDATE_TRACK "" CACHE STRING "Name of the default update tra
|
|||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
option(ENABLE_X11 "Enables X11 Support" ON)
|
||||
option(ENABLE_WAYLAND "Enables Wayland support" ON)
|
||||
endif()
|
||||
if(NOT WIN32 AND NOT APPLE AND NOT HAIKU)
|
||||
option(ENABLE_EGL "Enables EGL OpenGL Interface" ON)
|
||||
|
|
@ -508,6 +509,16 @@ if(ENABLE_X11)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_WAYLAND)
|
||||
find_package(Wayland)
|
||||
if(Wayland_FOUND)
|
||||
add_definitions(-DHAVE_WAYLAND=1)
|
||||
message(STATUS "Wayland support enabled")
|
||||
else()
|
||||
message(WARNING "Wayland support enabled but not found. This build will not support Wayland.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENABLE_EGL)
|
||||
find_package(EGL)
|
||||
if(EGL_FOUND)
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ Common::Flag s_is_booting;
|
|||
bool s_game_metadata_is_valid = false;
|
||||
} // Anonymous namespace
|
||||
|
||||
static float GetRenderSurfaceScale(JNIEnv* env);
|
||||
|
||||
void UpdatePointer()
|
||||
{
|
||||
// Update touch pointer
|
||||
|
|
@ -448,7 +450,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang
|
|||
__android_log_print(ANDROID_LOG_ERROR, DOLPHIN_TAG, "Error: Surface is null.");
|
||||
|
||||
if (g_presenter)
|
||||
g_presenter->ChangeSurface(s_surf);
|
||||
{
|
||||
const u32 width = s_surf ? static_cast<u32>(ANativeWindow_getWidth(s_surf)) : 0;
|
||||
const u32 height = s_surf ? static_cast<u32>(ANativeWindow_getHeight(s_surf)) : 0;
|
||||
g_presenter->ChangeSurface(s_surf, width, height, GetRenderSurfaceScale(env));
|
||||
}
|
||||
|
||||
s_surface_cv.notify_all();
|
||||
}
|
||||
|
|
@ -471,7 +477,11 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestr
|
|||
std::lock_guard surface_guard(s_surface_lock);
|
||||
|
||||
if (g_presenter)
|
||||
g_presenter->ChangeSurface(nullptr);
|
||||
{
|
||||
g_presenter->ChangeSurface(nullptr, g_presenter->GetBackbufferWidth(),
|
||||
g_presenter->GetBackbufferHeight(),
|
||||
g_presenter->GetBackbufferScale());
|
||||
}
|
||||
|
||||
if (s_surf)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -306,6 +306,13 @@ if(ENABLE_EGL AND EGL_FOUND)
|
|||
target_link_libraries(common PUBLIC ${EGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(ENABLE_WAYLAND AND WAYLAND_FOUND AND ENABLE_EGL AND EGL_FOUND)
|
||||
target_sources(common PRIVATE
|
||||
GL/GLInterface/EGLWayland.cpp
|
||||
GL/GLInterface/EGLWayland.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(common PRIVATE
|
||||
CompatPatches.cpp
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
#if HAVE_X11
|
||||
#include "Common/GL/GLInterface/EGLX11.h"
|
||||
#endif
|
||||
#if HAVE_EGL && HAVE_WAYLAND
|
||||
#include "Common/GL/GLInterface/EGLWayland.h"
|
||||
#endif
|
||||
#if defined(ANDROID)
|
||||
#include "Common/GL/GLInterface/EGLAndroid.h"
|
||||
#endif
|
||||
|
|
@ -54,12 +57,15 @@ bool GLContext::ClearCurrent()
|
|||
return false;
|
||||
}
|
||||
|
||||
void GLContext::Update()
|
||||
void GLContext::Update(u32 width, u32 height)
|
||||
{
|
||||
m_backbuffer_width = width;
|
||||
m_backbuffer_height = height;
|
||||
}
|
||||
|
||||
void GLContext::UpdateSurface(void* window_handle)
|
||||
void GLContext::UpdateSurface(void* window_handle, u32 width, u32 height)
|
||||
{
|
||||
Update(width, height);
|
||||
}
|
||||
|
||||
void GLContext::Swap()
|
||||
|
|
@ -100,6 +106,12 @@ std::unique_ptr<GLContext> GLContext::Create(const WindowSystemInfo& wsi, bool s
|
|||
if (wsi.type == WindowSystemType::X11)
|
||||
context = std::make_unique<GLContextEGLX11>();
|
||||
#endif
|
||||
#endif
|
||||
#if HAVE_EGL && HAVE_WAYLAND
|
||||
if (wsi.type == WindowSystemType::Wayland)
|
||||
context = std::make_unique<GLContextEGLWayland>();
|
||||
#endif
|
||||
#if HAVE_EGL
|
||||
if (wsi.type == WindowSystemType::Headless || wsi.type == WindowSystemType::FBDev)
|
||||
context = std::make_unique<GLContextEGL>();
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@ public:
|
|||
virtual bool MakeCurrent();
|
||||
virtual bool ClearCurrent();
|
||||
|
||||
virtual void Update();
|
||||
virtual void UpdateSurface(void* window_handle);
|
||||
virtual void Update(u32 width, u32 height);
|
||||
virtual void UpdateSurface(void* window_handle, u32 width, u32 height);
|
||||
|
||||
virtual void Swap();
|
||||
virtual void SwapInterval(int interval);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public:
|
|||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
|
||||
void Update() override;
|
||||
void Update(u32 width, u32 height) override;
|
||||
|
||||
void Swap() override;
|
||||
void SwapInterval(int interval) override;
|
||||
|
|
|
|||
|
|
@ -5,27 +5,7 @@
|
|||
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
// UpdateCachedDimensions and AttachContextToView contain calls to UI APIs, so they must only be
|
||||
// called from the main thread or they risk crashing!
|
||||
|
||||
static bool UpdateCachedDimensions(NSView* view, u32* width, u32* height)
|
||||
{
|
||||
NSWindow* window = [view window];
|
||||
NSSize size = [view frame].size;
|
||||
|
||||
const CGFloat scale = [window backingScaleFactor];
|
||||
u32 new_width = static_cast<u32>(size.width * scale);
|
||||
u32 new_height = static_cast<u32>(size.height * scale);
|
||||
|
||||
if (*width == new_width && *height == new_height)
|
||||
return false;
|
||||
|
||||
*width = new_width;
|
||||
*height = new_height;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool AttachContextToView(NSOpenGLContext* context, NSView* view, u32* width, u32* height)
|
||||
static bool AttachContextToView(NSOpenGLContext* context, NSView* view)
|
||||
{
|
||||
// Enable high-resolution display support.
|
||||
[view setWantsBestResolutionOpenGLSurface:YES];
|
||||
|
|
@ -37,8 +17,6 @@ static bool AttachContextToView(NSOpenGLContext* context, NSView* view, u32* wid
|
|||
return false;
|
||||
}
|
||||
|
||||
(void)UpdateCachedDimensions(view, width, height);
|
||||
|
||||
[context setView:view];
|
||||
|
||||
return true;
|
||||
|
|
@ -98,16 +76,18 @@ bool GLContextAGL::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor
|
|||
|
||||
m_view = static_cast<NSView*>(wsi.render_surface);
|
||||
m_opengl_mode = Mode::OpenGL;
|
||||
m_backbuffer_width = wsi.render_surface_width;
|
||||
m_backbuffer_height = wsi.render_surface_height;
|
||||
|
||||
__block bool success;
|
||||
if ([NSThread isMainThread])
|
||||
{
|
||||
success = AttachContextToView(m_context, m_view, &m_backbuffer_width, &m_backbuffer_height);
|
||||
success = AttachContextToView(m_context, m_view);
|
||||
}
|
||||
else
|
||||
{
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
success = AttachContextToView(m_context, m_view, &m_backbuffer_width, &m_backbuffer_height);
|
||||
success = AttachContextToView(m_context, m_view);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -150,16 +130,11 @@ bool GLContextAGL::ClearCurrent()
|
|||
return true;
|
||||
}
|
||||
|
||||
void GLContextAGL::Update()
|
||||
void GLContextAGL::Update(u32 width, u32 height)
|
||||
{
|
||||
if (!m_view)
|
||||
return;
|
||||
|
||||
GLContext::Update(width, height);
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
if (UpdateCachedDimensions(m_view, &m_backbuffer_width, &m_backbuffer_height))
|
||||
{
|
||||
[m_context update];
|
||||
}
|
||||
[m_context update];
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ void GLContextBGL::Swap()
|
|||
m_gl->SwapBuffers();
|
||||
}
|
||||
|
||||
void GLContextBGL::Update()
|
||||
void GLContextBGL::Update(u32, u32)
|
||||
{
|
||||
m_gl->LockLooper();
|
||||
BRect size = m_gl->Frame();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public:
|
|||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
|
||||
void Update() override;
|
||||
void Update(u32, u32) override;
|
||||
|
||||
void Swap() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@ bool GLContextEGL::Initialize(const WindowSystemInfo& wsi, bool stereo, bool cor
|
|||
bool supports_core_profile = false;
|
||||
|
||||
m_wsi = wsi;
|
||||
m_backbuffer_width = wsi.render_surface_width;
|
||||
m_backbuffer_height = wsi.render_surface_height;
|
||||
m_egl_display = OpenEGLDisplay();
|
||||
if (!m_egl_display)
|
||||
{
|
||||
|
|
@ -346,8 +348,9 @@ bool GLContextEGL::MakeCurrent()
|
|||
return eglMakeCurrent(m_egl_display, m_egl_surface, m_egl_surface, m_egl_context);
|
||||
}
|
||||
|
||||
void GLContextEGL::UpdateSurface(void* window_handle)
|
||||
void GLContextEGL::UpdateSurface(void* window_handle, u32 width, u32 height)
|
||||
{
|
||||
GLContext::UpdateSurface(window_handle, width, height);
|
||||
m_wsi.render_surface = window_handle;
|
||||
ClearCurrent();
|
||||
DestroyWindowSurface();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public:
|
|||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
|
||||
void UpdateSurface(void* window_handle) override;
|
||||
void UpdateSurface(void* window_handle, u32 width, u32 height) override;
|
||||
|
||||
void Swap() override;
|
||||
void SwapInterval(int interval) override;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,5 @@ EGLNativeWindowType GLContextEGLAndroid::GetEGLNativeWindow(EGLConfig config)
|
|||
EGLint format;
|
||||
eglGetConfigAttrib(m_egl_display, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
ANativeWindow_setBuffersGeometry(static_cast<ANativeWindow*>(m_wsi.render_surface), 0, 0, format);
|
||||
m_backbuffer_width = ANativeWindow_getWidth(static_cast<ANativeWindow*>(m_wsi.render_surface));
|
||||
m_backbuffer_height = ANativeWindow_getHeight(static_cast<ANativeWindow*>(m_wsi.render_surface));
|
||||
return static_cast<EGLNativeWindowType>(m_wsi.render_surface);
|
||||
}
|
||||
|
|
|
|||
47
Source/Core/Common/GL/GLInterface/EGLWayland.cpp
Normal file
47
Source/Core/Common/GL/GLInterface/EGLWayland.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Common/GL/GLInterface/EGLWayland.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
GLContextEGLWayland::~GLContextEGLWayland()
|
||||
{
|
||||
if (m_window)
|
||||
m_wl_egl_window_destroy(m_window);
|
||||
}
|
||||
|
||||
void GLContextEGLWayland::Update(u32 width, u32 height)
|
||||
{
|
||||
GLContext::Update(width, height);
|
||||
if (m_window)
|
||||
m_wl_egl_window_resize(m_window, width, height, 0, 0);
|
||||
}
|
||||
|
||||
EGLDisplay GLContextEGLWayland::OpenEGLDisplay()
|
||||
{
|
||||
return eglGetDisplay(static_cast<EGLNativeDisplayType>(m_wsi.display_connection));
|
||||
}
|
||||
|
||||
EGLNativeWindowType GLContextEGLWayland::GetEGLNativeWindow(EGLConfig config)
|
||||
{
|
||||
if (!m_wayland_lib.IsOpen())
|
||||
{
|
||||
std::string name = Common::DynamicLibrary::GetVersionedFilename("wayland-egl", 1);
|
||||
m_wayland_lib.Open(name.c_str());
|
||||
if (!m_wayland_lib.IsOpen())
|
||||
{
|
||||
PanicAlertFmt("Failed to load {}", name);
|
||||
return reinterpret_cast<EGLNativeWindowType>(m_window);
|
||||
}
|
||||
#define LOAD(x) m_wayland_lib.GetSymbol(#x, &m_##x)
|
||||
LOAD(wl_egl_window_create);
|
||||
LOAD(wl_egl_window_destroy);
|
||||
LOAD(wl_egl_window_resize);
|
||||
#undef LOAD
|
||||
}
|
||||
if (m_window)
|
||||
m_wl_egl_window_destroy(m_window);
|
||||
m_window = m_wl_egl_window_create(static_cast<wl_surface*>(m_wsi.render_surface),
|
||||
m_wsi.render_surface_width, m_wsi.render_surface_height);
|
||||
return reinterpret_cast<EGLNativeWindowType>(m_window);
|
||||
}
|
||||
28
Source/Core/Common/GL/GLInterface/EGLWayland.h
Normal file
28
Source/Core/Common/GL/GLInterface/EGLWayland.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wayland-egl.h>
|
||||
#include "Common/DynamicLibrary.h"
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
|
||||
struct wl_egl_window;
|
||||
struct wl_surface;
|
||||
|
||||
class GLContextEGLWayland final : public GLContextEGL
|
||||
{
|
||||
public:
|
||||
~GLContextEGLWayland() override;
|
||||
|
||||
void Update(u32 width, u32 height) override;
|
||||
|
||||
protected:
|
||||
EGLDisplay OpenEGLDisplay() override;
|
||||
EGLNativeWindowType GetEGLNativeWindow(EGLConfig config) override;
|
||||
Common::DynamicLibrary m_wayland_lib;
|
||||
wl_egl_window* (*m_wl_egl_window_create)(wl_surface* surface, int width, int height);
|
||||
void (*m_wl_egl_window_destroy)(wl_egl_window* window);
|
||||
void (*m_wl_egl_window_resize)(wl_egl_window* window, int width, int height, int dx, int dy);
|
||||
wl_egl_window* m_window = nullptr;
|
||||
};
|
||||
|
|
@ -11,7 +11,7 @@ GLContextEGLX11::~GLContextEGLX11()
|
|||
m_render_window.reset();
|
||||
}
|
||||
|
||||
void GLContextEGLX11::Update()
|
||||
void GLContextEGLX11::Update(u32, u32)
|
||||
{
|
||||
m_render_window->UpdateDimensions();
|
||||
m_backbuffer_width = m_render_window->GetWidth();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class GLContextEGLX11 final : public GLContextEGL
|
|||
public:
|
||||
~GLContextEGLX11() override;
|
||||
|
||||
void Update() override;
|
||||
void Update(u32, u32) override;
|
||||
|
||||
protected:
|
||||
EGLDisplay OpenEGLDisplay() override;
|
||||
|
|
|
|||
|
|
@ -478,14 +478,3 @@ bool GLContextWGL::ClearCurrent()
|
|||
{
|
||||
return wglMakeCurrent(m_dc, nullptr) == TRUE;
|
||||
}
|
||||
|
||||
// Update window width, size and etc. Called from Render.cpp
|
||||
void GLContextWGL::Update()
|
||||
{
|
||||
RECT rcWindow;
|
||||
GetClientRect(m_window_handle, &rcWindow);
|
||||
|
||||
// Get the new window width and height
|
||||
m_backbuffer_width = rcWindow.right - rcWindow.left;
|
||||
m_backbuffer_height = rcWindow.bottom - rcWindow.top;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ public:
|
|||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
|
||||
void Update() override;
|
||||
|
||||
void Swap() override;
|
||||
void SwapInterval(int interval) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ struct WindowSystemInfo
|
|||
// during video backend startup the surface pointer may change (MoltenVK).
|
||||
void* render_surface = nullptr;
|
||||
|
||||
// Width of the render surface
|
||||
int render_surface_width = 0;
|
||||
// Height of the render surface
|
||||
int render_surface_height = 0;
|
||||
|
||||
// Scale of the render surface. For hidpi systems, this will be >1.
|
||||
float render_surface_scale = 1.0f;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@ WindowSystemInfo PlatformFBDev::GetWindowSystemInfo() const
|
|||
wsi.display_connection = nullptr; // EGL_DEFAULT_DISPLAY
|
||||
wsi.render_window = nullptr;
|
||||
wsi.render_surface = nullptr;
|
||||
wsi.render_surface_width = 0;
|
||||
wsi.render_surface_height = 0;
|
||||
wsi.render_surface_scale = 1.f;
|
||||
return wsi;
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -21,6 +21,39 @@
|
|||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
@class AppDelegate;
|
||||
|
||||
class PlatformMacOS : public Platform
|
||||
{
|
||||
public:
|
||||
~PlatformMacOS() override;
|
||||
|
||||
bool Init() override;
|
||||
void SetTitle(const std::string& title) override;
|
||||
void MainLoop() override;
|
||||
|
||||
WindowSystemInfo GetWindowSystemInfo() const override;
|
||||
|
||||
NSWindow* Window() const { return m_window; }
|
||||
|
||||
private:
|
||||
void ProcessEvents();
|
||||
void UpdateWindowPosition();
|
||||
void HandleSaveStates(NSUInteger key, NSUInteger flags);
|
||||
void SetupMenu();
|
||||
|
||||
NSRect m_window_rect;
|
||||
NSWindow* m_window;
|
||||
NSMenu* menuBar;
|
||||
AppDelegate* m_app_delegate;
|
||||
|
||||
int m_window_x = Config::Get(Config::MAIN_RENDER_WINDOW_XPOS);
|
||||
int m_window_y = Config::Get(Config::MAIN_RENDER_WINDOW_YPOS);
|
||||
unsigned int m_window_width = Config::Get(Config::MAIN_RENDER_WINDOW_WIDTH);
|
||||
unsigned int m_window_height = Config::Get(Config::MAIN_RENDER_WINDOW_HEIGHT);
|
||||
bool m_window_fullscreen = Config::Get(Config::MAIN_FULLSCREEN);
|
||||
};
|
||||
|
||||
@interface Application : NSApplication
|
||||
@property Platform* platform;
|
||||
- (void)shutdown;
|
||||
|
|
@ -80,12 +113,13 @@
|
|||
}
|
||||
@end
|
||||
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate>
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
|
||||
|
||||
@property(readonly) Platform* platform;
|
||||
@property(readonly) PlatformMacOS* platform;
|
||||
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender;
|
||||
- (id)initWithPlatform:(Platform*)platform;
|
||||
- (void)windowDidResize:(NSNotification*)notification;
|
||||
@end
|
||||
|
||||
@implementation AppDelegate
|
||||
|
|
@ -94,7 +128,7 @@
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithPlatform:(Platform*)platform
|
||||
- (id)initWithPlatform:(PlatformMacOS*)platform
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
|
|
@ -103,54 +137,25 @@
|
|||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface WindowDelegate : NSObject <NSWindowDelegate>
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)notification;
|
||||
@end
|
||||
|
||||
@implementation WindowDelegate
|
||||
|
||||
- (void)windowDidResize:(NSNotification*)notification
|
||||
{
|
||||
WindowSystemInfo info = _platform->GetWindowSystemInfo();
|
||||
if (g_presenter)
|
||||
g_presenter->ResizeSurface();
|
||||
g_presenter->ResizeSurface(info.render_surface_width, info.render_surface_height,
|
||||
info.render_surface_scale);
|
||||
}
|
||||
|
||||
- (void)windowDidChangeScreen:(NSNotification*)notification
|
||||
{
|
||||
if (NSWindow* window = _platform->Window())
|
||||
if (CALayer* layer = [[window contentView] layer])
|
||||
[layer setContentsScale:[window backingScaleFactor]];
|
||||
[self windowDidResize:notification];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
namespace
|
||||
{
|
||||
class PlatformMacOS : public Platform
|
||||
{
|
||||
public:
|
||||
~PlatformMacOS() override;
|
||||
|
||||
bool Init() override;
|
||||
void SetTitle(const std::string& title) override;
|
||||
void MainLoop() override;
|
||||
|
||||
WindowSystemInfo GetWindowSystemInfo() const override;
|
||||
|
||||
private:
|
||||
void ProcessEvents();
|
||||
void UpdateWindowPosition();
|
||||
void HandleSaveStates(NSUInteger key, NSUInteger flags);
|
||||
void SetupMenu();
|
||||
|
||||
NSRect m_window_rect;
|
||||
NSWindow* m_window;
|
||||
NSMenu* menuBar;
|
||||
AppDelegate* m_app_delegate;
|
||||
WindowDelegate* m_window_delegate;
|
||||
|
||||
int m_window_x = Config::Get(Config::MAIN_RENDER_WINDOW_XPOS);
|
||||
int m_window_y = Config::Get(Config::MAIN_RENDER_WINDOW_YPOS);
|
||||
unsigned int m_window_width = Config::Get(Config::MAIN_RENDER_WINDOW_WIDTH);
|
||||
unsigned int m_window_height = Config::Get(Config::MAIN_RENDER_WINDOW_HEIGHT);
|
||||
bool m_window_fullscreen = Config::Get(Config::MAIN_FULLSCREEN);
|
||||
};
|
||||
|
||||
PlatformMacOS::~PlatformMacOS()
|
||||
{
|
||||
[m_window close];
|
||||
|
|
@ -176,8 +181,7 @@ bool PlatformMacOS::Init()
|
|||
styleMask:styleMask
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
m_window_delegate = [[WindowDelegate alloc] init];
|
||||
[m_window setDelegate:m_window_delegate];
|
||||
[m_window setDelegate:m_app_delegate];
|
||||
|
||||
NSNotificationCenter* c = [NSNotificationCenter defaultCenter];
|
||||
[c addObserver:NSApp
|
||||
|
|
@ -237,10 +241,15 @@ WindowSystemInfo PlatformMacOS::GetWindowSystemInfo() const
|
|||
{
|
||||
@autoreleasepool
|
||||
{
|
||||
NSRect frame = [m_window contentRectForFrameRect:[m_window frame]];
|
||||
CGFloat scale = [m_window backingScaleFactor];
|
||||
WindowSystemInfo wsi;
|
||||
wsi.type = WindowSystemType::MacOS;
|
||||
wsi.render_window = (void*)CFBridgingRetain([m_window contentView]);
|
||||
wsi.render_window = (__bridge void*)[m_window contentView];
|
||||
wsi.render_surface = wsi.render_window;
|
||||
wsi.render_surface_width = frame.size.width * scale;
|
||||
wsi.render_surface_height = frame.size.height * scale;
|
||||
wsi.render_surface_scale = scale;
|
||||
return wsi;
|
||||
}
|
||||
}
|
||||
|
|
@ -421,8 +430,6 @@ void PlatformMacOS::SetupMenu()
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<Platform> Platform::CreateMacOSPlatform()
|
||||
{
|
||||
return std::make_unique<PlatformMacOS>();
|
||||
|
|
|
|||
|
|
@ -137,6 +137,9 @@ WindowSystemInfo PlatformWin32::GetWindowSystemInfo() const
|
|||
wsi.type = WindowSystemType::Windows;
|
||||
wsi.render_window = reinterpret_cast<void*>(m_hwnd);
|
||||
wsi.render_surface = reinterpret_cast<void*>(m_hwnd);
|
||||
wsi.render_surface_width = m_window_width;
|
||||
wsi.render_surface_height = m_window_height;
|
||||
wsi.render_surface_scale = 1.f;
|
||||
return wsi;
|
||||
}
|
||||
|
||||
|
|
@ -192,8 +195,9 @@ LRESULT PlatformWin32::WndProc(const HWND hwnd, const UINT msg, const WPARAM wPa
|
|||
|
||||
case WM_SIZE:
|
||||
{
|
||||
UpdateWindowPosition();
|
||||
if (g_presenter)
|
||||
g_presenter->ResizeSurface();
|
||||
g_presenter->ResizeSurface(m_window_width, m_window_height, 1.f);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,10 @@ WindowSystemInfo PlatformX11::GetWindowSystemInfo() const
|
|||
wsi.display_connection = static_cast<void*>(m_display);
|
||||
wsi.render_window = reinterpret_cast<void*>(m_window);
|
||||
wsi.render_surface = reinterpret_cast<void*>(m_window);
|
||||
// TODO: Actually get these (currently both the X11 Vulkan and OGL backends ignore this)
|
||||
wsi.render_surface_width = 0;
|
||||
wsi.render_surface_height = 0;
|
||||
wsi.render_surface_scale = 1.f;
|
||||
return wsi;
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +271,7 @@ void PlatformX11::ProcessEvents()
|
|||
case ConfigureNotify:
|
||||
{
|
||||
if (g_presenter)
|
||||
g_presenter->ResizeSurface();
|
||||
g_presenter->ResizeSurface(0, 0, 1.f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,21 +56,6 @@ Host* Host::GetInstance()
|
|||
return s_instance;
|
||||
}
|
||||
|
||||
void Host::SetRenderHandle(void* handle)
|
||||
{
|
||||
m_render_to_main = Config::Get(Config::MAIN_RENDER_TO_MAIN);
|
||||
|
||||
if (m_render_handle == handle)
|
||||
return;
|
||||
|
||||
m_render_handle = handle;
|
||||
if (g_presenter)
|
||||
{
|
||||
g_presenter->ChangeSurface(handle);
|
||||
g_controller_interface.ChangeWindow(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void Host::SetMainWindowHandle(void* handle)
|
||||
{
|
||||
m_main_window_handle = handle;
|
||||
|
|
@ -185,10 +170,20 @@ void Host::SetTASInputFocus(const bool focus)
|
|||
m_tas_input_focus = focus;
|
||||
}
|
||||
|
||||
void Host::ResizeSurface(int new_width, int new_height)
|
||||
void Host::SetRenderWindowInfo(void* new_handle, int new_width, int new_height, float new_scale)
|
||||
{
|
||||
if (new_handle)
|
||||
{
|
||||
m_render_to_main = Config::Get(Config::MAIN_RENDER_TO_MAIN);
|
||||
if (m_render_handle == new_handle)
|
||||
new_handle = nullptr;
|
||||
else
|
||||
m_render_handle = new_handle;
|
||||
}
|
||||
if (g_presenter)
|
||||
g_presenter->ResizeSurface();
|
||||
g_presenter->ChangeSurface(new_handle, new_width, new_height, new_scale);
|
||||
if (g_presenter && new_handle)
|
||||
g_controller_interface.ChangeWindow(new_handle);
|
||||
}
|
||||
|
||||
std::vector<std::string> Host_GetPreferredLocales()
|
||||
|
|
|
|||
|
|
@ -28,10 +28,11 @@ public:
|
|||
bool GetTASInputFocus() const;
|
||||
|
||||
void SetMainWindowHandle(void* handle);
|
||||
void SetRenderHandle(void* handle);
|
||||
void SetRenderFocus(bool focus);
|
||||
void SetRenderFullFocus(bool focus);
|
||||
void SetRenderFullscreen(bool fullscreen);
|
||||
// null new_handle => resize
|
||||
void SetRenderWindowInfo(void* new_handle, int new_width, int new_height, float new_scale);
|
||||
void SetTASInputFocus(bool focus);
|
||||
void ResizeSurface(int new_width, int new_height);
|
||||
|
||||
|
|
|
|||
|
|
@ -149,14 +149,14 @@ int main(int argc, char* argv[])
|
|||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 3, 0))
|
||||
setenv("QT_XCB_NO_XI2", "1", true);
|
||||
#endif
|
||||
// Dolphin currently doesn't work on Wayland (Only the UI does, games do not launch.) This makes
|
||||
// XCB the default and forces it on if the platform is specified to be wayland, to prevent this
|
||||
// from happening.
|
||||
// For more information: https://bugs.dolphin-emu.org/issues/11807
|
||||
#if !HAVE_WAYLAND
|
||||
// If Dolphin was built without Wayland support, force XCB when the platform is explicitly set to
|
||||
// Wayland so users get a working backend.
|
||||
const char* current_qt_platform = getenv("QT_QPA_PLATFORM");
|
||||
const bool replace_qt_platform = current_qt_platform != nullptr &&
|
||||
Common::CaseInsensitiveContains(current_qt_platform, "wayland");
|
||||
setenv("QT_QPA_PLATFORM", "xcb", replace_qt_platform);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
QCoreApplication::setOrganizationName(QStringLiteral("Dolphin Emulator"));
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ static WindowSystemType GetWindowSystemType()
|
|||
return WindowSystemType::MacOS;
|
||||
else if (platform_name == QStringLiteral("xcb"))
|
||||
return WindowSystemType::X11;
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
else if (platform_name.startsWith(QStringLiteral("wayland")))
|
||||
return WindowSystemType::Wayland;
|
||||
else if (platform_name == QStringLiteral("haiku"))
|
||||
return WindowSystemType::Haiku;
|
||||
|
|
@ -197,7 +197,10 @@ static WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
|||
wsi.render_window = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
|
||||
wsi.render_surface = wsi.render_window;
|
||||
#endif
|
||||
wsi.render_surface_scale = window ? static_cast<float>(window->devicePixelRatio()) : 1.0f;
|
||||
float dpr = window ? static_cast<float>(window->devicePixelRatio()) : 1.f;
|
||||
wsi.render_surface_width = window ? static_cast<u32>(window->width() * dpr) : 0;
|
||||
wsi.render_surface_height = window ? static_cast<u32>(window->height() * dpr) : 0;
|
||||
wsi.render_surface_scale = dpr;
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,7 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
|||
// (which results in them not getting called)
|
||||
connect(this, &RenderWidget::StateChanged, Host::GetInstance(), &Host::SetRenderFullscreen,
|
||||
Qt::DirectConnection);
|
||||
connect(this, &RenderWidget::HandleChanged, this, &RenderWidget::OnHandleChanged,
|
||||
Qt::DirectConnection);
|
||||
connect(this, &RenderWidget::SizeChanged, Host::GetInstance(), &Host::ResizeSurface,
|
||||
connect(this, &RenderWidget::WindowChanged, Host::GetInstance(), &Host::SetRenderWindowInfo,
|
||||
Qt::DirectConnection);
|
||||
connect(this, &RenderWidget::FocusChanged, Host::GetInstance(), &Host::SetRenderFocus,
|
||||
Qt::DirectConnection);
|
||||
|
|
@ -130,20 +128,6 @@ void RenderWidget::dropEvent(QDropEvent* event)
|
|||
State::LoadAs(Core::System::GetInstance(), path.toStdString());
|
||||
}
|
||||
|
||||
void RenderWidget::OnHandleChanged(void* handle)
|
||||
{
|
||||
if (handle)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Remove rounded corners from the render window on Windows 11
|
||||
const DWM_WINDOW_CORNER_PREFERENCE corner_preference = DWMWCP_DONOTROUND;
|
||||
DwmSetWindowAttribute(static_cast<HWND>(handle), DWMWA_WINDOW_CORNER_PREFERENCE,
|
||||
&corner_preference, sizeof(corner_preference));
|
||||
#endif
|
||||
}
|
||||
Host::GetInstance()->SetRenderHandle(handle);
|
||||
}
|
||||
|
||||
void RenderWidget::OnHideCursorChanged()
|
||||
{
|
||||
UpdateCursor();
|
||||
|
|
@ -212,7 +196,7 @@ void RenderWidget::showFullScreen()
|
|||
|
||||
const auto dpr = screen->devicePixelRatio();
|
||||
|
||||
emit SizeChanged(width() * dpr, height() * dpr);
|
||||
emit WindowChanged(nullptr, width() * dpr, height() * dpr, dpr);
|
||||
}
|
||||
|
||||
// Lock the cursor within the window/widget internal borders, including the aspect ratio if wanted
|
||||
|
|
@ -402,9 +386,6 @@ bool RenderWidget::event(QEvent* event)
|
|||
m_mouse_timer->start(MOUSE_HIDE_DELAY);
|
||||
}
|
||||
break;
|
||||
case QEvent::WinIdChange:
|
||||
emit HandleChanged(reinterpret_cast<void*>(winId()));
|
||||
break;
|
||||
case QEvent::Show:
|
||||
// Don't do if "stay on top" changed (or was true)
|
||||
if (Settings::Instance().GetLockCursor() &&
|
||||
|
|
@ -469,27 +450,37 @@ bool RenderWidget::event(QEvent* event)
|
|||
|
||||
// According to https://bugreports.qt.io/browse/QTBUG-95925 the recommended practice for
|
||||
// handling DPI change is responding to paint events
|
||||
case QEvent::WinIdChange:
|
||||
case QEvent::Paint:
|
||||
case QEvent::Resize:
|
||||
{
|
||||
SetCursorLocked(m_cursor_locked);
|
||||
void* handle = nullptr;
|
||||
if (event->type() == QEvent::WinIdChange)
|
||||
{
|
||||
handle = reinterpret_cast<void*>(winId());
|
||||
#ifdef _WIN32
|
||||
// Remove rounded corners from the render window on Windows 11
|
||||
const DWM_WINDOW_CORNER_PREFERENCE corner_preference = DWMWCP_DONOTROUND;
|
||||
DwmSetWindowAttribute(reinterpret_cast<HWND>(handle), DWMWA_WINDOW_CORNER_PREFERENCE,
|
||||
&corner_preference, sizeof(corner_preference));
|
||||
#endif
|
||||
}
|
||||
|
||||
const QResizeEvent* se = static_cast<QResizeEvent*>(event);
|
||||
QSize new_size = se->size();
|
||||
SetCursorLocked(m_cursor_locked);
|
||||
|
||||
QScreen* screen = window()->windowHandle()->screen();
|
||||
|
||||
const float dpr = screen->devicePixelRatio();
|
||||
const int width = new_size.width() * dpr;
|
||||
const int height = new_size.height() * dpr;
|
||||
const int width = this->width() * dpr;
|
||||
const int height = this->height() * dpr;
|
||||
|
||||
if (m_last_window_width != width || m_last_window_height != height ||
|
||||
if (handle || m_last_window_width != width || m_last_window_height != height ||
|
||||
m_last_window_scale != dpr)
|
||||
{
|
||||
m_last_window_width = width;
|
||||
m_last_window_height = height;
|
||||
m_last_window_scale = dpr;
|
||||
emit SizeChanged(width, height);
|
||||
emit WindowChanged(handle, width, height, dpr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,14 +27,13 @@ public:
|
|||
signals:
|
||||
void EscapePressed();
|
||||
void Closed();
|
||||
void HandleChanged(void* handle);
|
||||
void StateChanged(bool fullscreen);
|
||||
void SizeChanged(int new_width, int new_height);
|
||||
// null new_handle => resize only
|
||||
void WindowChanged(void* new_handle, int new_width, int new_height, float new_scale);
|
||||
void FocusChanged(bool focus);
|
||||
|
||||
private:
|
||||
void HandleCursorTimer();
|
||||
void OnHandleChanged(void* handle);
|
||||
void OnHideCursorChanged();
|
||||
void OnNeverHideCursorChanged();
|
||||
void OnLockCursorChanged();
|
||||
|
|
|
|||
|
|
@ -184,22 +184,25 @@ void Gfx::OnConfigChanged(u32 bits)
|
|||
|
||||
void Gfx::CheckForSwapChainChanges()
|
||||
{
|
||||
const bool surface_changed = g_presenter->SurfaceChangedTestAndClear();
|
||||
const auto change_info = g_presenter->SurfaceChangedTestAndClear();
|
||||
const bool surface_resized =
|
||||
g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange();
|
||||
if (!surface_changed && !surface_resized)
|
||||
(change_info && !change_info->new_handle) || m_swap_chain->CheckForFullscreenChange();
|
||||
if (!change_info && !surface_resized)
|
||||
return;
|
||||
|
||||
if (surface_changed)
|
||||
if (change_info && change_info->new_handle)
|
||||
{
|
||||
m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle());
|
||||
m_swap_chain->ChangeSurface(change_info->new_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_swap_chain->ResizeSwapChain();
|
||||
}
|
||||
|
||||
g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
|
||||
if (change_info)
|
||||
m_backbuffer_scale = change_info->new_scale;
|
||||
|
||||
g_presenter->SetBackbuffer(GetSurfaceInfo());
|
||||
}
|
||||
|
||||
void Gfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
|
||||
|
|
|
|||
|
|
@ -374,24 +374,27 @@ bool Gfx::BindBackbuffer(const ClearColor& clear_color)
|
|||
|
||||
void Gfx::CheckForSwapChainChanges()
|
||||
{
|
||||
const bool surface_changed = g_presenter->SurfaceChangedTestAndClear();
|
||||
const auto change_info = g_presenter->SurfaceChangedTestAndClear();
|
||||
const bool surface_resized =
|
||||
g_presenter->SurfaceResizedTestAndClear() || m_swap_chain->CheckForFullscreenChange();
|
||||
if (!surface_changed && !surface_resized)
|
||||
(change_info && !change_info->new_handle) || m_swap_chain->CheckForFullscreenChange();
|
||||
if (!change_info && !surface_resized)
|
||||
return;
|
||||
|
||||
// The swap chain could be in use from a previous frame.
|
||||
WaitForGPUIdle();
|
||||
if (surface_changed)
|
||||
if (change_info && change_info->new_handle)
|
||||
{
|
||||
m_swap_chain->ChangeSurface(g_presenter->GetNewSurfaceHandle());
|
||||
m_swap_chain->ChangeSurface(change_info->new_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_swap_chain->ResizeSwapChain();
|
||||
}
|
||||
|
||||
g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
|
||||
if (change_info)
|
||||
m_backbuffer_scale = change_info->new_scale;
|
||||
|
||||
g_presenter->SetBackbuffer(GetSurfaceInfo());
|
||||
}
|
||||
|
||||
void Gfx::PresentBackbuffer()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include "VideoBackends/Metal/MRCHelpers.h"
|
||||
|
||||
struct WindowSystemInfo;
|
||||
|
||||
namespace Metal
|
||||
{
|
||||
class Framebuffer;
|
||||
|
|
@ -18,7 +20,7 @@ class Texture;
|
|||
class Gfx final : public ::AbstractGfx
|
||||
{
|
||||
public:
|
||||
Gfx(MRCOwned<CAMetalLayer*> layer);
|
||||
Gfx(MRCOwned<CAMetalLayer*> layer, const WindowSystemInfo& wsi);
|
||||
~Gfx() override;
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
|
@ -84,7 +86,6 @@ private:
|
|||
std::array<u32, 4> m_shader_counter = {};
|
||||
|
||||
void CheckForSurfaceChange();
|
||||
void CheckForSurfaceResize();
|
||||
void SetupSurface();
|
||||
void SetupSurface(u32 width, u32 height, float scale);
|
||||
};
|
||||
} // namespace Metal
|
||||
|
|
|
|||
|
|
@ -18,12 +18,13 @@
|
|||
|
||||
#include <fstream>
|
||||
|
||||
Metal::Gfx::Gfx(MRCOwned<CAMetalLayer*> layer) : m_layer(std::move(layer))
|
||||
Metal::Gfx::Gfx(MRCOwned<CAMetalLayer*> layer, const WindowSystemInfo& wsi)
|
||||
: m_layer(std::move(layer))
|
||||
{
|
||||
UpdateActiveConfig();
|
||||
[m_layer setDisplaySyncEnabled:g_ActiveConfig.bVSyncActive];
|
||||
|
||||
SetupSurface();
|
||||
SetupSurface(wsi.render_surface_width, wsi.render_surface_height, wsi.render_surface_scale);
|
||||
g_state_tracker->FlushEncoders();
|
||||
}
|
||||
|
||||
|
|
@ -453,7 +454,6 @@ bool Metal::Gfx::BindBackbuffer(const ClearColor& clear_color)
|
|||
@autoreleasepool
|
||||
{
|
||||
CheckForSurfaceChange();
|
||||
CheckForSurfaceResize();
|
||||
m_drawable = MRCRetain([m_layer nextDrawable]);
|
||||
m_backbuffer->UpdateBackbufferTexture([m_drawable texture]);
|
||||
SetAndClearFramebuffer(m_backbuffer.get(), clear_color);
|
||||
|
|
@ -488,33 +488,28 @@ void Metal::Gfx::PresentBackbuffer()
|
|||
|
||||
void Metal::Gfx::CheckForSurfaceChange()
|
||||
{
|
||||
if (!g_presenter->SurfaceChangedTestAndClear())
|
||||
return;
|
||||
m_layer = MRCRetain(static_cast<CAMetalLayer*>(g_presenter->GetNewSurfaceHandle()));
|
||||
SetupSurface();
|
||||
if (auto change_info = g_presenter->SurfaceChangedTestAndClear())
|
||||
{
|
||||
if (void* handle = change_info->new_handle)
|
||||
m_layer = MRCRetain(static_cast<CAMetalLayer*>(handle));
|
||||
SetupSurface(change_info->new_width, change_info->new_height, change_info->new_scale);
|
||||
}
|
||||
}
|
||||
|
||||
void Metal::Gfx::CheckForSurfaceResize()
|
||||
void Metal::Gfx::SetupSurface(u32 width, u32 height, float scale)
|
||||
{
|
||||
if (!g_presenter->SurfaceResizedTestAndClear())
|
||||
return;
|
||||
SetupSurface();
|
||||
}
|
||||
AbstractTextureFormat format = Util::ToAbstract([m_layer pixelFormat]);
|
||||
[m_layer setContentsScale:scale];
|
||||
[m_layer setDrawableSize:{static_cast<double>(width), static_cast<double>(height)}];
|
||||
|
||||
void Metal::Gfx::SetupSurface()
|
||||
{
|
||||
auto info = GetSurfaceInfo();
|
||||
|
||||
[m_layer setDrawableSize:{static_cast<double>(info.width), static_cast<double>(info.height)}];
|
||||
|
||||
TextureConfig cfg(info.width, info.height, 1, 1, 1, info.format, AbstractTextureFlag_RenderTarget,
|
||||
TextureConfig cfg(width, height, 1, 1, 1, format, AbstractTextureFlag_RenderTarget,
|
||||
AbstractTextureType::Texture_2DArray);
|
||||
m_bb_texture = std::make_unique<Texture>(nullptr, cfg);
|
||||
m_backbuffer = std::make_unique<Framebuffer>(
|
||||
m_bb_texture.get(), nullptr, std::vector<AbstractTexture*>{}, info.width, info.height, 1, 1);
|
||||
m_bb_texture.get(), nullptr, std::vector<AbstractTexture*>{}, width, height, 1, 1);
|
||||
|
||||
if (g_presenter)
|
||||
g_presenter->SetBackbuffer(info);
|
||||
g_presenter->SetBackbuffer({width, height, scale, format});
|
||||
}
|
||||
|
||||
SurfaceInfo Metal::Gfx::GetSurfaceInfo() const
|
||||
|
|
@ -522,9 +517,9 @@ SurfaceInfo Metal::Gfx::GetSurfaceInfo() const
|
|||
if (!m_layer) // Headless
|
||||
return {};
|
||||
|
||||
CGSize size = [m_layer bounds].size;
|
||||
CGSize size = [m_layer drawableSize];
|
||||
const float scale = [m_layer contentsScale];
|
||||
|
||||
return {static_cast<u32>(size.width * scale), static_cast<u32>(size.height * scale), scale,
|
||||
return {static_cast<u32>(size.width), static_cast<u32>(size.height), scale,
|
||||
Util::ToAbstract([m_layer pixelFormat])};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,9 +125,9 @@ bool Metal::VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
|||
ObjectCache::Initialize(std::move(adapter));
|
||||
g_state_tracker = std::make_unique<StateTracker>();
|
||||
|
||||
return InitializeShared(
|
||||
std::make_unique<Metal::Gfx>(std::move(layer)), std::make_unique<Metal::VertexManager>(),
|
||||
std::make_unique<Metal::PerfQuery>(), std::make_unique<Metal::BoundingBox>());
|
||||
return InitializeShared(std::make_unique<Gfx>(std::move(layer), wsi),
|
||||
std::make_unique<VertexManager>(), std::make_unique<PerfQuery>(),
|
||||
std::make_unique<BoundingBox>());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -410,7 +410,6 @@ void OGLGfx::ClearRegion(const MathUtil::Rectangle<int>& target_rc, bool colorEn
|
|||
bool OGLGfx::BindBackbuffer(const ClearColor& clear_color)
|
||||
{
|
||||
CheckForSurfaceChange();
|
||||
CheckForSurfaceResize();
|
||||
SetAndClearFramebuffer(m_system_framebuffer.get(), clear_color);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -459,29 +458,21 @@ void OGLGfx::WaitForGPUIdle()
|
|||
|
||||
void OGLGfx::CheckForSurfaceChange()
|
||||
{
|
||||
if (!g_presenter->SurfaceChangedTestAndClear())
|
||||
return;
|
||||
if (auto change_info = g_presenter->SurfaceChangedTestAndClear())
|
||||
{
|
||||
if (void* handle = change_info->new_handle)
|
||||
m_main_gl_context->UpdateSurface(handle, change_info->new_width, change_info->new_height);
|
||||
else
|
||||
m_main_gl_context->Update(change_info->new_width, change_info->new_height);
|
||||
|
||||
m_main_gl_context->UpdateSurface(g_presenter->GetNewSurfaceHandle());
|
||||
u32 width = m_main_gl_context->GetBackBufferWidth();
|
||||
u32 height = m_main_gl_context->GetBackBufferHeight();
|
||||
m_backbuffer_scale = change_info->new_scale;
|
||||
|
||||
u32 width = m_main_gl_context->GetBackBufferWidth();
|
||||
u32 height = m_main_gl_context->GetBackBufferHeight();
|
||||
|
||||
// With a surface change, the window likely has new dimensions.
|
||||
g_presenter->SetBackbuffer(width, height);
|
||||
m_system_framebuffer->UpdateDimensions(width, height);
|
||||
}
|
||||
|
||||
void OGLGfx::CheckForSurfaceResize()
|
||||
{
|
||||
if (!g_presenter->SurfaceResizedTestAndClear())
|
||||
return;
|
||||
|
||||
m_main_gl_context->Update();
|
||||
u32 width = m_main_gl_context->GetBackBufferWidth();
|
||||
u32 height = m_main_gl_context->GetBackBufferHeight();
|
||||
g_presenter->SetBackbuffer(width, height);
|
||||
m_system_framebuffer->UpdateDimensions(width, height);
|
||||
// With a surface change, the window likely has new dimensions.
|
||||
g_presenter->SetBackbuffer(GetSurfaceInfo());
|
||||
m_system_framebuffer->UpdateDimensions(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void OGLGfx::BeginUtilityDrawing()
|
||||
|
|
|
|||
|
|
@ -96,7 +96,6 @@ public:
|
|||
|
||||
private:
|
||||
void CheckForSurfaceChange();
|
||||
void CheckForSurfaceResize();
|
||||
|
||||
void ApplyRasterizationState(const RasterizationState state);
|
||||
void ApplyDepthState(const DepthState state);
|
||||
|
|
|
|||
|
|
@ -58,12 +58,12 @@ SWGfx::CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* dep
|
|||
bool SWGfx::BindBackbuffer(const ClearColor& clear_color)
|
||||
{
|
||||
// Look for framebuffer resizes
|
||||
if (!g_presenter->SurfaceResizedTestAndClear())
|
||||
return true;
|
||||
|
||||
GLContext* context = m_window->GetContext();
|
||||
context->Update();
|
||||
g_presenter->SetBackbuffer(context->GetBackBufferWidth(), context->GetBackBufferHeight());
|
||||
if (auto change_info = g_presenter->SurfaceChangedTestAndClear())
|
||||
{
|
||||
GLContext* context = m_window->GetContext();
|
||||
context->Update(change_info->new_width, change_info->new_height);
|
||||
g_presenter->SetBackbuffer(GetSurfaceInfo());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ void SWOGLWindow::ShowImage(const AbstractTexture* image,
|
|||
const MathUtil::Rectangle<int>& xfb_region)
|
||||
{
|
||||
const SW::SWTexture* sw_image = static_cast<const SW::SWTexture*>(image);
|
||||
m_gl_context->Update(); // just updates the render window position and the backbuffer size
|
||||
|
||||
GLsizei glWidth = (GLsizei)m_gl_context->GetBackBufferWidth();
|
||||
GLsizei glHeight = (GLsizei)m_gl_context->GetBackBufferHeight();
|
||||
|
|
|
|||
|
|
@ -225,7 +225,6 @@ bool VKGfx::BindBackbuffer(const ClearColor& clear_color)
|
|||
|
||||
// Handle host window resizes.
|
||||
CheckForSurfaceChange();
|
||||
CheckForSurfaceResize();
|
||||
|
||||
// Check for exclusive fullscreen request.
|
||||
if (m_swap_chain->GetCurrentFullscreenState() != m_swap_chain->GetNextFullscreenState() &&
|
||||
|
|
@ -263,18 +262,18 @@ bool VKGfx::BindBackbuffer(const ClearColor& clear_color)
|
|||
{
|
||||
// The present keeps returning exclusive mode lost unless we re-create the swap chain.
|
||||
INFO_LOG_FMT(VIDEO, "Lost exclusive fullscreen.");
|
||||
m_swap_chain->RecreateSwapChain();
|
||||
m_swap_chain->RecreateSwapChain(0, 0);
|
||||
}
|
||||
else if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
|
||||
{
|
||||
INFO_LOG_FMT(VIDEO, "Resizing swap chain due to suboptimal/out-of-date");
|
||||
m_swap_chain->ResizeSwapChain();
|
||||
m_swap_chain->ResizeSwapChain(0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Unknown present error {:#010X} {}, please report.",
|
||||
std::to_underlying(res), VkResultToString(res));
|
||||
m_swap_chain->RecreateSwapChain();
|
||||
m_swap_chain->RecreateSwapChain(0, 0);
|
||||
}
|
||||
|
||||
res = m_swap_chain->AcquireNextImage();
|
||||
|
|
@ -358,7 +357,8 @@ void VKGfx::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completio
|
|||
|
||||
void VKGfx::CheckForSurfaceChange()
|
||||
{
|
||||
if (!g_presenter->SurfaceChangedTestAndClear() || !m_swap_chain)
|
||||
std::optional<VideoCommon::Presenter::SurfaceChangedInfo> change_info;
|
||||
if (!(change_info = g_presenter->SurfaceChangedTestAndClear()) || !m_swap_chain)
|
||||
return;
|
||||
|
||||
// Submit the current draws up until rendering the XFB.
|
||||
|
|
@ -367,38 +367,25 @@ void VKGfx::CheckForSurfaceChange()
|
|||
// Clear the present failed flag, since we don't want to resize after recreating.
|
||||
g_command_buffer_mgr->CheckLastPresentFail();
|
||||
|
||||
// Recreate the surface. If this fails we're in trouble.
|
||||
if (!m_swap_chain->RecreateSurface(g_presenter->GetNewSurfaceHandle()))
|
||||
PanicAlertFmt("Failed to recreate Vulkan surface. Cannot continue.");
|
||||
if (change_info->new_handle)
|
||||
{
|
||||
// Recreate the surface. If this fails we're in trouble.
|
||||
if (!m_swap_chain->RecreateSurface(change_info->new_handle, //
|
||||
change_info->new_width, change_info->new_height))
|
||||
{
|
||||
PanicAlertFmt("Failed to recreate Vulkan surface. Cannot continue.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_swap_chain->RecreateSwapChain(change_info->new_width, change_info->new_height);
|
||||
}
|
||||
m_backbuffer_scale = change_info->new_scale;
|
||||
|
||||
// Handle case where the dimensions are now different.
|
||||
OnSwapChainResized();
|
||||
}
|
||||
|
||||
void VKGfx::CheckForSurfaceResize()
|
||||
{
|
||||
if (!g_presenter->SurfaceResizedTestAndClear())
|
||||
return;
|
||||
|
||||
// If we don't have a surface, how can we resize the swap chain?
|
||||
// CheckForSurfaceChange should handle this case.
|
||||
if (!m_swap_chain)
|
||||
{
|
||||
WARN_LOG_FMT(VIDEO, "Surface resize event received without active surface, ignoring");
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the GPU to catch up since we're going to destroy the swap chain.
|
||||
ExecuteCommandBuffer(false, true);
|
||||
|
||||
// Clear the present failed flag, since we don't want to resize after recreating.
|
||||
g_command_buffer_mgr->CheckLastPresentFail();
|
||||
|
||||
// Resize the swap chain.
|
||||
m_swap_chain->RecreateSwapChain();
|
||||
OnSwapChainResized();
|
||||
}
|
||||
|
||||
void VKGfx::OnConfigChanged(u32 bits)
|
||||
{
|
||||
AbstractGfx::OnConfigChanged(bits);
|
||||
|
|
@ -417,7 +404,7 @@ void VKGfx::OnConfigChanged(u32 bits)
|
|||
if (m_swap_chain && ((bits & CONFIG_CHANGE_BIT_STEREO_MODE) || (bits & CONFIG_CHANGE_BIT_HDR)))
|
||||
{
|
||||
ExecuteCommandBuffer(false, true);
|
||||
m_swap_chain->RecreateSwapChain();
|
||||
m_swap_chain->RecreateSwapChain(0, 0);
|
||||
}
|
||||
|
||||
// Wipe sampler cache if force texture filtering or anisotropy changes.
|
||||
|
|
@ -430,7 +417,7 @@ void VKGfx::OnConfigChanged(u32 bits)
|
|||
|
||||
void VKGfx::OnSwapChainResized()
|
||||
{
|
||||
g_presenter->SetBackbuffer(m_swap_chain->GetWidth(), m_swap_chain->GetHeight());
|
||||
g_presenter->SetBackbuffer(GetSurfaceInfo());
|
||||
}
|
||||
|
||||
void VKGfx::BindFramebuffer(VKFramebuffer* fb)
|
||||
|
|
|
|||
|
|
@ -89,7 +89,6 @@ public:
|
|||
|
||||
private:
|
||||
void CheckForSurfaceChange();
|
||||
void CheckForSurfaceResize();
|
||||
|
||||
void ResetSamplerStates();
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,29 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, const WindowSys
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
if (wsi.type == WindowSystemType::Wayland)
|
||||
{
|
||||
VkWaylandSurfaceCreateInfoKHR surface_create_info = {
|
||||
VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkWaylandSurfaceCreateFlagsKHR flags
|
||||
static_cast<wl_display*>(wsi.display_connection), // struct wl_display* display
|
||||
static_cast<wl_surface*>(wsi.render_surface) // struct wl_surface* surface
|
||||
};
|
||||
|
||||
VkSurfaceKHR surface;
|
||||
VkResult res = vkCreateWaylandSurfaceKHR(instance, &surface_create_info, nullptr, &surface);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateWaylandSurfaceKHR failed: ");
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
if (wsi.type == WindowSystemType::Android)
|
||||
{
|
||||
|
|
@ -132,8 +155,11 @@ std::unique_ptr<SwapChain> SwapChain::Create(const WindowSystemInfo& wsi, VkSurf
|
|||
bool vsync)
|
||||
{
|
||||
std::unique_ptr<SwapChain> swap_chain = std::make_unique<SwapChain>(wsi, surface, vsync);
|
||||
if (!swap_chain->CreateSwapChain() || !swap_chain->SetupSwapChainImages())
|
||||
if (!swap_chain->CreateSwapChain(wsi.render_surface_width, wsi.render_surface_height) ||
|
||||
!swap_chain->SetupSwapChainImages())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return swap_chain;
|
||||
}
|
||||
|
|
@ -271,7 +297,7 @@ bool SwapChain::SelectPresentMode()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SwapChain::CreateSwapChain()
|
||||
bool SwapChain::CreateSwapChain(u32 width, u32 height)
|
||||
{
|
||||
// Look up surface properties to determine image count and dimensions
|
||||
VkSurfaceCapabilitiesKHR surface_capabilities;
|
||||
|
|
@ -299,8 +325,8 @@ bool SwapChain::CreateSwapChain()
|
|||
VkExtent2D size = surface_capabilities.currentExtent;
|
||||
if (size.width == UINT32_MAX)
|
||||
{
|
||||
size.width = std::max(g_presenter->GetBackbufferWidth(), 1);
|
||||
size.height = std::max(g_presenter->GetBackbufferHeight(), 1);
|
||||
size.width = width == 0 ? m_width : width;
|
||||
size.height = height == 0 ? m_height : height;
|
||||
}
|
||||
size.width = std::clamp(size.width, surface_capabilities.minImageExtent.width,
|
||||
surface_capabilities.maxImageExtent.width);
|
||||
|
|
@ -500,10 +526,10 @@ VkResult SwapChain::AcquireNextImage()
|
|||
return res;
|
||||
}
|
||||
|
||||
bool SwapChain::ResizeSwapChain()
|
||||
bool SwapChain::ResizeSwapChain(u32 width, u32 height)
|
||||
{
|
||||
DestroySwapChainImages();
|
||||
if (!CreateSwapChain() || !SetupSwapChainImages())
|
||||
if (!CreateSwapChain(width, height) || !SetupSwapChainImages())
|
||||
{
|
||||
PanicAlertFmt("Failed to re-configure swap chain images, this is fatal (for now)");
|
||||
return false;
|
||||
|
|
@ -512,11 +538,11 @@ bool SwapChain::ResizeSwapChain()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SwapChain::RecreateSwapChain()
|
||||
bool SwapChain::RecreateSwapChain(u32 width, u32 height)
|
||||
{
|
||||
DestroySwapChainImages();
|
||||
DestroySwapChain();
|
||||
if (!CreateSwapChain() || !SetupSwapChainImages())
|
||||
if (!CreateSwapChain(width, height) || !SetupSwapChainImages())
|
||||
{
|
||||
PanicAlertFmt("Failed to re-configure swap chain images, this is fatal (for now)");
|
||||
return false;
|
||||
|
|
@ -532,7 +558,7 @@ bool SwapChain::SetVSync(bool enabled)
|
|||
|
||||
// Recreate the swap chain with the new present mode.
|
||||
m_vsync_enabled = enabled;
|
||||
return RecreateSwapChain();
|
||||
return RecreateSwapChain(m_width, m_height);
|
||||
}
|
||||
|
||||
bool SwapChain::SetFullscreenState(bool state)
|
||||
|
|
@ -568,7 +594,7 @@ bool SwapChain::SetFullscreenState(bool state)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool SwapChain::RecreateSurface(void* native_handle)
|
||||
bool SwapChain::RecreateSurface(void* native_handle, u32 width, u32 height)
|
||||
{
|
||||
// Destroy the old swap chain, images, and surface.
|
||||
DestroySwapChainImages();
|
||||
|
|
@ -604,7 +630,7 @@ bool SwapChain::RecreateSurface(void* native_handle)
|
|||
m_next_fullscreen_state = false;
|
||||
|
||||
// Finally re-create the swap chain
|
||||
if (!CreateSwapChain() || !SetupSwapChainImages())
|
||||
if (!CreateSwapChain(width, height) || !SetupSwapChainImages())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ public:
|
|||
}
|
||||
VkResult AcquireNextImage();
|
||||
|
||||
bool RecreateSurface(void* native_handle);
|
||||
bool ResizeSwapChain();
|
||||
bool RecreateSwapChain();
|
||||
bool RecreateSurface(void* native_handle, u32 width, u32 height);
|
||||
bool ResizeSwapChain(u32 width, u32 height);
|
||||
bool RecreateSwapChain(u32 width, u32 height);
|
||||
|
||||
// Change vsync enabled state. This may fail as it causes a swapchain recreation.
|
||||
bool SetVSync(bool enabled);
|
||||
|
|
@ -76,7 +76,7 @@ private:
|
|||
bool SelectSurfaceFormat();
|
||||
bool SelectPresentMode();
|
||||
|
||||
bool CreateSwapChain();
|
||||
bool CreateSwapChain(u32 width, u32 height);
|
||||
void DestroySwapChain();
|
||||
|
||||
bool SetupSwapChainImages();
|
||||
|
|
|
|||
|
|
@ -362,6 +362,13 @@ bool VulkanContext::SelectInstanceExtensions(std::vector<const char*>* extension
|
|||
return false;
|
||||
}
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
if (wstype == WindowSystemType::Wayland &&
|
||||
!AddExtension(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
if (wstype == WindowSystemType::Android &&
|
||||
!AddExtension(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, true))
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ VULKAN_INSTANCE_ENTRY_POINT(vkCreateXlibSurfaceKHR, false)
|
|||
VULKAN_INSTANCE_ENTRY_POINT(vkGetPhysicalDeviceXlibPresentationSupportKHR, false)
|
||||
#endif
|
||||
|
||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkCreateWaylandSurfaceKHR, false)
|
||||
#endif
|
||||
|
||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||
VULKAN_INSTANCE_ENTRY_POINT(vkCreateAndroidSurfaceKHR, false)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@
|
|||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_WAYLAND)
|
||||
#define VK_USE_PLATFORM_WAYLAND_KHR
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID)
|
||||
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -583,24 +583,33 @@ void Presenter::ReleaseXFBContentLock()
|
|||
m_xfb_entry->ReleaseContentLock();
|
||||
}
|
||||
|
||||
void Presenter::ChangeSurface(void* new_surface_handle)
|
||||
void Presenter::ChangeSurface(void* new_surface_handle, u32 width, u32 height, float scale)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_swap_mutex);
|
||||
m_new_surface_handle = new_surface_handle;
|
||||
m_surface_changed.Set();
|
||||
// If you ChangeSurface then ResizeSurface, don't forget about the surface change
|
||||
// (null new_surface_handle => ResizeSurface)
|
||||
if (new_surface_handle)
|
||||
m_new_surface_handle = new_surface_handle;
|
||||
m_new_surface_width = width;
|
||||
m_new_surface_height = height;
|
||||
m_new_surface_scale = scale;
|
||||
// Actual data is accessed under the mutex, so this can be relaxed
|
||||
m_surface_changed.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Presenter::ResizeSurface()
|
||||
Presenter::SurfaceChangedInfo Presenter::SurfaceChangedGetAndClear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_swap_mutex);
|
||||
m_surface_resized.Set();
|
||||
}
|
||||
|
||||
void* Presenter::GetNewSurfaceHandle()
|
||||
{
|
||||
void* handle = m_new_surface_handle;
|
||||
SurfaceChangedInfo info = {};
|
||||
// clang-format off
|
||||
info.new_handle = m_new_surface_handle;
|
||||
info.new_width = m_new_surface_width;
|
||||
info.new_height = m_new_surface_height;
|
||||
info.new_scale = m_new_surface_scale;
|
||||
// clang-format on
|
||||
m_new_surface_handle = nullptr;
|
||||
return handle;
|
||||
m_surface_changed.store(false, std::memory_order_relaxed);
|
||||
return info;
|
||||
}
|
||||
|
||||
u32 Presenter::AutoIntegralScale() const
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include <array>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <tuple>
|
||||
|
||||
class AbstractTexture;
|
||||
|
|
@ -91,11 +93,24 @@ public:
|
|||
VideoCommon::PostProcessing* GetPostProcessor() const { return m_post_processor.get(); }
|
||||
// Final surface changing
|
||||
// This is called when the surface is resized (WX) or the window changes (Android).
|
||||
void ChangeSurface(void* new_surface_handle);
|
||||
void ResizeSurface();
|
||||
bool SurfaceResizedTestAndClear() { return m_surface_resized.TestAndClear(); }
|
||||
bool SurfaceChangedTestAndClear() { return m_surface_changed.TestAndClear(); }
|
||||
void* GetNewSurfaceHandle();
|
||||
void ChangeSurface(void* new_surface_handle, u32 width, u32 height, float scale);
|
||||
void ResizeSurface(u32 width, u32 height, float scale)
|
||||
{
|
||||
ChangeSurface(nullptr, width, height, scale);
|
||||
}
|
||||
struct SurfaceChangedInfo
|
||||
{
|
||||
void* new_handle; ///< New surface handle if changed, else null
|
||||
int new_width; ///< New surface width
|
||||
int new_height; ///< New surface height
|
||||
float new_scale; ///< New surface scale
|
||||
};
|
||||
std::optional<SurfaceChangedInfo> SurfaceChangedTestAndClear()
|
||||
{
|
||||
if (!m_surface_changed.load(std::memory_order_relaxed))
|
||||
return std::nullopt;
|
||||
return SurfaceChangedGetAndClear();
|
||||
}
|
||||
|
||||
void SetKeyMap(const DolphinKeyMap& key_map);
|
||||
|
||||
|
|
@ -141,8 +156,12 @@ private:
|
|||
AbstractTextureFormat m_backbuffer_format = AbstractTextureFormat::Undefined;
|
||||
|
||||
void* m_new_surface_handle = nullptr;
|
||||
Common::Flag m_surface_changed;
|
||||
Common::Flag m_surface_resized;
|
||||
int m_new_surface_width = 0;
|
||||
int m_new_surface_height = 0;
|
||||
float m_new_surface_scale = 1.f;
|
||||
// note: Atomic for anti-tearing / anti-compiler-optimization only, write only under m_swap_mutex
|
||||
std::atomic_bool m_surface_changed;
|
||||
SurfaceChangedInfo SurfaceChangedGetAndClear();
|
||||
|
||||
// The presentation rectangle.
|
||||
// Width and height correspond to the final output resolution.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user