mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-30 01:25:51 +00:00
HostDisplay: Support refresh rate queries on all platforms except Mac
This commit is contained in:
parent
e94c68e874
commit
924756860e
2
.github/workflows/rolling-release.yml
vendored
2
.github/workflows/rolling-release.yml
vendored
|
@ -166,7 +166,7 @@ jobs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -y install cmake ninja-build ccache libsdl2-dev libgtk-3-dev qtbase5-dev qtbase5-dev-tools qtbase5-private-dev qt5-default qttools5-dev libegl1-mesa-dev libevdev-dev libgbm-dev libdrm-dev libwayland-dev libwayland-egl-backend-dev extra-cmake-modules libcurl4-gnutls-dev
|
sudo apt-get -y install cmake ninja-build ccache libsdl2-dev libgtk-3-dev qtbase5-dev qtbase5-dev-tools qtbase5-private-dev qt5-default qttools5-dev libegl1-mesa-dev libevdev-dev libgbm-dev libdrm-dev libwayland-dev libwayland-egl-backend-dev extra-cmake-modules libcurl4-gnutls-dev libxrandr-dev
|
||||||
|
|
||||||
- name: Compile build
|
- name: Compile build
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
|
@ -113,6 +113,9 @@ if(USE_EGL)
|
||||||
endif()
|
endif()
|
||||||
if(USE_X11)
|
if(USE_X11)
|
||||||
find_package(X11 REQUIRED)
|
find_package(X11 REQUIRED)
|
||||||
|
if (NOT X11_Xrandr_FOUND)
|
||||||
|
message(FATAL_ERROR "XRandR extension is required")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(USE_WAYLAND)
|
if(USE_WAYLAND)
|
||||||
find_package(ECM REQUIRED NO_MODULE)
|
find_package(ECM REQUIRED NO_MODULE)
|
||||||
|
|
|
@ -184,7 +184,7 @@ Requirements:
|
||||||
### Linux
|
### Linux
|
||||||
Requirements (Debian/Ubuntu package names):
|
Requirements (Debian/Ubuntu package names):
|
||||||
- CMake (`cmake`)
|
- CMake (`cmake`)
|
||||||
- SDL2 (`libsdl2-dev`)
|
- SDL2 (`libsdl2-dev`, `libxrandr-dev`)
|
||||||
- pkgconfig (`pkg-config`)
|
- pkgconfig (`pkg-config`)
|
||||||
- Qt 5 (`qtbase5-dev`, `qtbase5-private-dev`, `qtbase5-dev-tools`, `qttools5-dev`)
|
- Qt 5 (`qtbase5-dev`, `qtbase5-private-dev`, `qtbase5-dev-tools`, `qttools5-dev`)
|
||||||
- libevdev (`libevdev-dev`)
|
- libevdev (`libevdev-dev`)
|
||||||
|
|
|
@ -177,7 +177,7 @@ jbyteArray VectorToByteArray(JNIEnv* env, const std::vector<u8>& data)
|
||||||
}
|
}
|
||||||
|
|
||||||
jobjectArray CreateObjectArray(JNIEnv* env, jclass object_class, const jobject* objects, size_t num_objects,
|
jobjectArray CreateObjectArray(JNIEnv* env, jclass object_class, const jobject* objects, size_t num_objects,
|
||||||
bool release_refs/* = false*/)
|
bool release_refs /* = false*/)
|
||||||
{
|
{
|
||||||
if (!objects || num_objects == 0)
|
if (!objects || num_objects == 0)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -294,18 +294,23 @@ void AndroidHostInterface::RegisterHotkeys()
|
||||||
CommonHostInterface::RegisterHotkeys();
|
CommonHostInterface::RegisterHotkeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidHostInterface::GetMainDisplayRefreshRate(float* refresh_rate)
|
float AndroidHostInterface::GetRefreshRate() const
|
||||||
{
|
{
|
||||||
if (!m_emulation_activity_object)
|
if (!m_emulation_activity_object)
|
||||||
return false;
|
return 0.0f;
|
||||||
|
|
||||||
float value = AndroidHelpers::GetJNIEnv()->CallFloatMethod(m_emulation_activity_object,
|
const float value = AndroidHelpers::GetJNIEnv()->CallFloatMethod(m_emulation_activity_object,
|
||||||
s_EmulationActivity_method_getRefreshRate);
|
s_EmulationActivity_method_getRefreshRate);
|
||||||
if (value <= 0.0f)
|
return (value > 0.0f) ? value : 0.0f;
|
||||||
return false;
|
}
|
||||||
|
|
||||||
*refresh_rate = value;
|
float AndroidHostInterface::GetSurfaceScale(int width, int height) const
|
||||||
return true;
|
{
|
||||||
|
if (width <= 0 || height <= 0)
|
||||||
|
return 1.0f;
|
||||||
|
|
||||||
|
// TODO: Really need a better way of determining this.
|
||||||
|
return (width > height) ? (static_cast<float>(width) / 1280.0f) : (static_cast<float>(height) / 1280.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::SetUserDirectory()
|
void AndroidHostInterface::SetUserDirectory()
|
||||||
|
@ -591,9 +596,8 @@ bool AndroidHostInterface::AcquireHostDisplay()
|
||||||
wi.window_handle = m_surface;
|
wi.window_handle = m_surface;
|
||||||
wi.surface_width = ANativeWindow_getWidth(m_surface);
|
wi.surface_width = ANativeWindow_getWidth(m_surface);
|
||||||
wi.surface_height = ANativeWindow_getHeight(m_surface);
|
wi.surface_height = ANativeWindow_getHeight(m_surface);
|
||||||
|
wi.surface_refresh_rate = GetRefreshRate();
|
||||||
// TODO: Really need a better way of determining this.
|
wi.surface_scale = GetSurfaceScale(wi.surface_width, wi.surface_height);
|
||||||
wi.surface_scale = 2.0f;
|
|
||||||
|
|
||||||
switch (g_settings.gpu_renderer)
|
switch (g_settings.gpu_renderer)
|
||||||
{
|
{
|
||||||
|
@ -709,7 +713,7 @@ void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, in
|
||||||
if (m_display && (width != m_display->GetWindowWidth() || height != m_display->GetWindowHeight()))
|
if (m_display && (width != m_display->GetWindowWidth() || height != m_display->GetWindowHeight()))
|
||||||
{
|
{
|
||||||
m_display->ResizeRenderWindow(width, height);
|
m_display->ResizeRenderWindow(width, height);
|
||||||
OnHostDisplayResized(width, height, m_display->GetWindowScale());
|
OnHostDisplayResized();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -724,11 +728,12 @@ void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, in
|
||||||
wi.window_handle = surface;
|
wi.window_handle = surface;
|
||||||
wi.surface_width = width;
|
wi.surface_width = width;
|
||||||
wi.surface_height = height;
|
wi.surface_height = height;
|
||||||
wi.surface_scale = m_display->GetWindowScale();
|
wi.surface_refresh_rate = GetRefreshRate();
|
||||||
|
wi.surface_scale = GetSurfaceScale(width, height);
|
||||||
|
|
||||||
m_display->ChangeRenderWindow(wi);
|
m_display->ChangeRenderWindow(wi);
|
||||||
if (surface)
|
if (surface)
|
||||||
OnHostDisplayResized(width, height, m_display->GetWindowScale());
|
OnHostDisplayResized();
|
||||||
|
|
||||||
if (surface && System::GetState() == System::State::Paused)
|
if (surface && System::GetState() == System::State::Paused)
|
||||||
PauseSystem(false);
|
PauseSystem(false);
|
||||||
|
@ -1666,7 +1671,6 @@ DEFINE_JNI_ARGS_METHOD(jstring, AndroidHostInterface_importBIOSImage, jobject ob
|
||||||
return env->NewStringUTF(hash.ToString().c_str());
|
return env->NewStringUTF(hash.ToString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_hasMediaSubImages, jobject obj)
|
DEFINE_JNI_ARGS_METHOD(jboolean, AndroidHostInterface_hasMediaSubImages, jobject obj)
|
||||||
{
|
{
|
||||||
if (!System::IsValid())
|
if (!System::IsValid())
|
||||||
|
|
|
@ -39,7 +39,6 @@ public:
|
||||||
void ReportMessage(const char* message) override;
|
void ReportMessage(const char* message) override;
|
||||||
|
|
||||||
std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) override;
|
std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) override;
|
||||||
bool GetMainDisplayRefreshRate(float* refresh_rate) override;
|
|
||||||
|
|
||||||
bool IsEmulationThreadRunning() const { return m_emulation_thread_running.load(); }
|
bool IsEmulationThreadRunning() const { return m_emulation_thread_running.load(); }
|
||||||
bool IsEmulationThreadPaused() const;
|
bool IsEmulationThreadPaused() const;
|
||||||
|
@ -90,6 +89,8 @@ private:
|
||||||
void UpdateInputMap(SettingsInterface& si) override;
|
void UpdateInputMap(SettingsInterface& si) override;
|
||||||
void SetVibration(bool enabled);
|
void SetVibration(bool enabled);
|
||||||
void UpdateVibration();
|
void UpdateVibration();
|
||||||
|
float GetRefreshRate() const;
|
||||||
|
float GetSurfaceScale(int width, int height) const;
|
||||||
|
|
||||||
jobject m_java_object = {};
|
jobject m_java_object = {};
|
||||||
jobject m_emulation_activity_object = {};
|
jobject m_emulation_activity_object = {};
|
||||||
|
|
|
@ -108,6 +108,8 @@ add_library(common
|
||||||
vulkan/util.h
|
vulkan/util.h
|
||||||
wav_writer.cpp
|
wav_writer.cpp
|
||||||
wav_writer.h
|
wav_writer.h
|
||||||
|
window_info.cpp
|
||||||
|
window_info.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(common PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
target_include_directories(common PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||||
|
@ -147,8 +149,8 @@ if(USE_X11)
|
||||||
gl/x11_window.h
|
gl/x11_window.h
|
||||||
)
|
)
|
||||||
target_compile_definitions(common PRIVATE "-DUSE_X11=1")
|
target_compile_definitions(common PRIVATE "-DUSE_X11=1")
|
||||||
target_include_directories(common PRIVATE "${X11_INCLUDE_DIR}")
|
target_include_directories(common PRIVATE "${X11_INCLUDE_DIR}" "${X11_Xrandr_INCLUDE_PATH}")
|
||||||
target_link_libraries(common PRIVATE "${X11_LIBRARIES}")
|
target_link_libraries(common PRIVATE "${X11_LIBRARIES}" "${X11_Xrandr_LIB}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(USE_DRMKMS)
|
if(USE_DRMKMS)
|
||||||
|
|
|
@ -189,6 +189,7 @@
|
||||||
<ClCompile Include="vulkan\util.cpp" />
|
<ClCompile Include="vulkan\util.cpp" />
|
||||||
<ClCompile Include="wav_writer.cpp" />
|
<ClCompile Include="wav_writer.cpp" />
|
||||||
<ClCompile Include="win32_progress_callback.cpp" />
|
<ClCompile Include="win32_progress_callback.cpp" />
|
||||||
|
<ClCompile Include="window_info.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="bitfield.natvis" />
|
<Natvis Include="bitfield.natvis" />
|
||||||
|
|
|
@ -217,6 +217,7 @@
|
||||||
<ClCompile Include="cd_image_pbp.cpp" />
|
<ClCompile Include="cd_image_pbp.cpp" />
|
||||||
<ClCompile Include="error.cpp" />
|
<ClCompile Include="error.cpp" />
|
||||||
<ClCompile Include="cd_image_m3u.cpp" />
|
<ClCompile Include="cd_image_m3u.cpp" />
|
||||||
|
<ClCompile Include="window_info.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="bitfield.natvis" />
|
<Natvis Include="bitfield.natvis" />
|
||||||
|
|
|
@ -17,6 +17,11 @@ public:
|
||||||
int GetCardFD() const { return m_card_fd; }
|
int GetCardFD() const { return m_card_fd; }
|
||||||
u32 GetWidth() const { return m_mode->hdisplay; }
|
u32 GetWidth() const { return m_mode->hdisplay; }
|
||||||
u32 GetHeight() const { return m_mode->vdisplay; }
|
u32 GetHeight() const { return m_mode->vdisplay; }
|
||||||
|
float GetRefreshRate() const
|
||||||
|
{
|
||||||
|
return (static_cast<float>(m_mode->clock) * 1000.0f) /
|
||||||
|
(static_cast<float>(m_mode->htotal) * static_cast<float>(m_mode->vtotal));
|
||||||
|
}
|
||||||
|
|
||||||
u32 GetModeCount() const { return m_connector->count_modes; }
|
u32 GetModeCount() const { return m_connector->count_modes; }
|
||||||
u32 GetModeWidth(u32 i) const { return m_connector->modes[i].hdisplay; }
|
u32 GetModeWidth(u32 i) const { return m_connector->modes[i].hdisplay; }
|
||||||
|
|
|
@ -43,7 +43,7 @@ std::unique_ptr<Context> ContextEGLGBM::Create(const WindowInfo& wi, const Versi
|
||||||
size_t num_versions_to_try)
|
size_t num_versions_to_try)
|
||||||
{
|
{
|
||||||
std::unique_ptr<ContextEGLGBM> context = std::make_unique<ContextEGLGBM>(wi);
|
std::unique_ptr<ContextEGLGBM> context = std::make_unique<ContextEGLGBM>(wi);
|
||||||
if (!context->CreateDisplay(wi) || !context->CreateGBMDevice() ||
|
if (!context->CreateDisplay() || !context->CreateGBMDevice() ||
|
||||||
!context->Initialize(versions_to_try, num_versions_to_try))
|
!context->Initialize(versions_to_try, num_versions_to_try))
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -81,9 +81,15 @@ bool ContextEGLGBM::CreateGBMDevice()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContextEGLGBM::CreateDisplay(const WindowInfo& wi)
|
bool ContextEGLGBM::CreateDisplay()
|
||||||
{
|
{
|
||||||
return m_drm_display.Initialize(wi.surface_width, wi.surface_height, wi.surface_refresh_rate);
|
if (!m_drm_display.Initialize(m_wi.surface_width, m_wi.surface_height, m_wi.surface_refresh_rate))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_wi.surface_width = m_drm_display.GetWidth();
|
||||||
|
m_wi.surface_height = m_drm_display.GetHeight();
|
||||||
|
m_wi.surface_refresh_rate = m_drm_display.GetRefreshRate();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ContextEGLGBM::SetDisplay()
|
bool ContextEGLGBM::SetDisplay()
|
||||||
|
|
|
@ -44,7 +44,7 @@ private:
|
||||||
u32 fb_id;
|
u32 fb_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CreateDisplay(const WindowInfo& wi);
|
bool CreateDisplay();
|
||||||
|
|
||||||
bool CreateGBMDevice();
|
bool CreateGBMDevice();
|
||||||
Buffer* LockFrontBuffer();
|
Buffer* LockFrontBuffer();
|
||||||
|
|
|
@ -353,7 +353,7 @@ bool Context::Create(std::string_view gpu_name, const WindowInfo* wi, std::uniqu
|
||||||
wi_copy = *wi;
|
wi_copy = *wi;
|
||||||
|
|
||||||
if (enable_surface &&
|
if (enable_surface &&
|
||||||
(surface = SwapChain::CreateVulkanSurface(instance, gpus[gpu_index], wi_copy)) == VK_NULL_HANDLE)
|
(surface = SwapChain::CreateVulkanSurface(instance, gpus[gpu_index], &wi_copy)) == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
vkDestroyInstance(instance, nullptr);
|
vkDestroyInstance(instance, nullptr);
|
||||||
Vulkan::UnloadVulkanLibrary();
|
Vulkan::UnloadVulkanLibrary();
|
||||||
|
|
|
@ -20,9 +20,9 @@ Log_SetChannel(Vulkan::SwapChain);
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include <objc/message.h>
|
#include <objc/message.h>
|
||||||
|
|
||||||
static bool CreateMetalLayer(WindowInfo& wi)
|
static bool CreateMetalLayer(WindowInfo* wi)
|
||||||
{
|
{
|
||||||
id view = reinterpret_cast<id>(wi.window_handle);
|
id view = reinterpret_cast<id>(wi->window_handle);
|
||||||
|
|
||||||
Class clsCAMetalLayer = objc_getClass("CAMetalLayer");
|
Class clsCAMetalLayer = objc_getClass("CAMetalLayer");
|
||||||
if (!clsCAMetalLayer)
|
if (!clsCAMetalLayer)
|
||||||
|
@ -55,28 +55,28 @@ static bool CreateMetalLayer(WindowInfo& wi)
|
||||||
reinterpret_cast<void (*)(id, SEL, double)>(objc_msgSend)(layer, sel_getUid("setContentsScale:"), factor);
|
reinterpret_cast<void (*)(id, SEL, double)>(objc_msgSend)(layer, sel_getUid("setContentsScale:"), factor);
|
||||||
|
|
||||||
// Store the layer pointer, that way MoltenVK doesn't call [NSView layer] outside the main thread.
|
// Store the layer pointer, that way MoltenVK doesn't call [NSView layer] outside the main thread.
|
||||||
wi.surface_handle = layer;
|
wi->surface_handle = layer;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DestroyMetalLayer(WindowInfo& wi)
|
static void DestroyMetalLayer(WindowInfo* wi)
|
||||||
{
|
{
|
||||||
id view = reinterpret_cast<id>(wi.window_handle);
|
id view = reinterpret_cast<id>(wi->window_handle);
|
||||||
id layer = reinterpret_cast<id>(wi.surface_handle);
|
id layer = reinterpret_cast<id>(wi->surface_handle);
|
||||||
if (layer == nil)
|
if (layer == nil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
reinterpret_cast<void (*)(id, SEL, id)>(objc_msgSend)(view, sel_getUid("setLayer:"), nil);
|
reinterpret_cast<void (*)(id, SEL, id)>(objc_msgSend)(view, sel_getUid("setLayer:"), nil);
|
||||||
reinterpret_cast<void (*)(id, SEL, BOOL)>(objc_msgSend)(view, sel_getUid("setWantsLayer:"), NO);
|
reinterpret_cast<void (*)(id, SEL, BOOL)>(objc_msgSend)(view, sel_getUid("setWantsLayer:"), NO);
|
||||||
reinterpret_cast<void (*)(id, SEL)>(objc_msgSend)(layer, sel_getUid("release"));
|
reinterpret_cast<void (*)(id, SEL)>(objc_msgSend)(layer, sel_getUid("release"));
|
||||||
wi.surface_handle = nullptr;
|
wi->surface_handle = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
SwapChain::SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync)
|
SwapChain::SwapChain(const WindowInfo& wi, VkSurfaceKHR surface, bool vsync)
|
||||||
: m_wi(wi), m_vsync_enabled(vsync), m_surface(surface)
|
: m_window_info(wi), m_surface(surface), m_vsync_enabled(vsync)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,9 +88,9 @@ SwapChain::~SwapChain()
|
||||||
DestroySurface();
|
DestroySurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice physical_device, const WindowInfo& wi)
|
static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi)
|
||||||
{
|
{
|
||||||
Log_InfoPrintf("Trying to create a VK_KHR_display surface of %ux%u", wi.surface_width, wi.surface_height);
|
Log_InfoPrintf("Trying to create a VK_KHR_display surface of %ux%u", wi->surface_width, wi->surface_height);
|
||||||
|
|
||||||
u32 num_displays;
|
u32 num_displays;
|
||||||
VkResult res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, nullptr);
|
VkResult res = vkGetPhysicalDeviceDisplayPropertiesKHR(physical_device, &num_displays, nullptr);
|
||||||
|
@ -137,9 +137,9 @@ static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice p
|
||||||
refresh_rate);
|
refresh_rate);
|
||||||
|
|
||||||
if (!matched_mode &&
|
if (!matched_mode &&
|
||||||
((wi.surface_width == 0 && wi.surface_height == 0) ||
|
((wi->surface_width == 0 && wi->surface_height == 0) ||
|
||||||
(mode.parameters.visibleRegion.width == wi.surface_width && mode.parameters.visibleRegion.height &&
|
(mode.parameters.visibleRegion.width == wi->surface_width && mode.parameters.visibleRegion.height &&
|
||||||
(wi.surface_refresh_rate == 0.0f || std::abs(refresh_rate - wi.surface_refresh_rate) < 0.1f))))
|
(wi->surface_refresh_rate == 0.0f || std::abs(refresh_rate - wi->surface_refresh_rate) < 0.1f))))
|
||||||
{
|
{
|
||||||
matched_mode = &mode;
|
matched_mode = &mode;
|
||||||
}
|
}
|
||||||
|
@ -219,6 +219,7 @@ static VkSurfaceKHR CreateDisplaySurface(VkInstance instance, VkPhysicalDevice p
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wi->surface_refresh_rate = static_cast<float>(matched_mode->parameters.refreshRate) / 1000.0f;
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,17 +287,17 @@ static std::vector<SwapChain::FullscreenModeInfo> GetDisplayModes(VkInstance ins
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo& wi)
|
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi)
|
||||||
{
|
{
|
||||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||||
if (wi.type == WindowInfo::Type::Win32)
|
if (wi->type == WindowInfo::Type::Win32)
|
||||||
{
|
{
|
||||||
VkWin32SurfaceCreateInfoKHR surface_create_info = {
|
VkWin32SurfaceCreateInfoKHR surface_create_info = {
|
||||||
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkWin32SurfaceCreateFlagsKHR flags
|
0, // VkWin32SurfaceCreateFlagsKHR flags
|
||||||
nullptr, // HINSTANCE hinstance
|
nullptr, // HINSTANCE hinstance
|
||||||
reinterpret_cast<HWND>(wi.window_handle) // HWND hwnd
|
reinterpret_cast<HWND>(wi->window_handle) // HWND hwnd
|
||||||
};
|
};
|
||||||
|
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
@ -312,14 +313,14 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
#if defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||||
if (wi.type == WindowInfo::Type::X11)
|
if (wi->type == WindowInfo::Type::X11)
|
||||||
{
|
{
|
||||||
VkXlibSurfaceCreateInfoKHR surface_create_info = {
|
VkXlibSurfaceCreateInfoKHR surface_create_info = {
|
||||||
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkXlibSurfaceCreateFlagsKHR flags
|
0, // VkXlibSurfaceCreateFlagsKHR flags
|
||||||
static_cast<Display*>(wi.display_connection), // Display* dpy
|
static_cast<Display*>(wi->display_connection), // Display* dpy
|
||||||
reinterpret_cast<Window>(wi.window_handle) // Window window
|
reinterpret_cast<Window>(wi->window_handle) // Window window
|
||||||
};
|
};
|
||||||
|
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
@ -335,11 +336,11 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
|
||||||
if (wi.type == WindowInfo::Type::Wayland)
|
if (wi->type == WindowInfo::Type::Wayland)
|
||||||
{
|
{
|
||||||
VkWaylandSurfaceCreateInfoKHR surface_create_info = {VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
VkWaylandSurfaceCreateInfoKHR surface_create_info = {VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, nullptr, 0,
|
||||||
static_cast<struct wl_display*>(wi.display_connection),
|
static_cast<struct wl_display*>(wi->display_connection),
|
||||||
static_cast<struct wl_surface*>(wi.window_handle)};
|
static_cast<struct wl_surface*>(wi->window_handle)};
|
||||||
|
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkResult res = vkCreateWaylandSurfaceKHR(instance, &surface_create_info, nullptr, &surface);
|
VkResult res = vkCreateWaylandSurfaceKHR(instance, &surface_create_info, nullptr, &surface);
|
||||||
|
@ -354,13 +355,13 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
if (wi.type == WindowInfo::Type::Android)
|
if (wi->type == WindowInfo::Type::Android)
|
||||||
{
|
{
|
||||||
VkAndroidSurfaceCreateInfoKHR surface_create_info = {
|
VkAndroidSurfaceCreateInfoKHR surface_create_info = {
|
||||||
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
0, // VkAndroidSurfaceCreateFlagsKHR flags
|
0, // VkAndroidSurfaceCreateFlagsKHR flags
|
||||||
reinterpret_cast<ANativeWindow*>(wi.window_handle) // ANativeWindow* window
|
reinterpret_cast<ANativeWindow*>(wi->window_handle) // ANativeWindow* window
|
||||||
};
|
};
|
||||||
|
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
|
@ -376,13 +377,13 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
||||||
if (wi.type == WindowInfo::Type::MacOS)
|
if (wi->type == WindowInfo::Type::MacOS)
|
||||||
{
|
{
|
||||||
if (!wi.surface_handle && !CreateMetalLayer(wi))
|
if (!wi->surface_handle && !CreateMetalLayer(wi))
|
||||||
return VK_NULL_HANDLE;
|
return VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkMetalSurfaceCreateInfoEXT surface_create_info = {VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, nullptr, 0,
|
VkMetalSurfaceCreateInfoEXT surface_create_info = {VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, nullptr, 0,
|
||||||
static_cast<const CAMetalLayer*>(wi.surface_handle)};
|
static_cast<const CAMetalLayer*>(wi->surface_handle)};
|
||||||
|
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkResult res = vkCreateMetalSurfaceEXT(instance, &surface_create_info, nullptr, &surface);
|
VkResult res = vkCreateMetalSurfaceEXT(instance, &surface_create_info, nullptr, &surface);
|
||||||
|
@ -395,10 +396,10 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
#elif defined(VK_USE_PLATFORM_MACOS_MVK)
|
||||||
if (wi.type == WindowInfo::Type::MacOS)
|
if (wi->type == WindowInfo::Type::MacOS)
|
||||||
{
|
{
|
||||||
VkMacOSSurfaceCreateInfoMVK surface_create_info = {VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, nullptr, 0,
|
VkMacOSSurfaceCreateInfoMVK surface_create_info = {VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK, nullptr, 0,
|
||||||
wi.window_handle};
|
wi->window_handle};
|
||||||
|
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
VkResult res = vkCreateMacOSSurfaceMVK(instance, &surface_create_info, nullptr, &surface);
|
VkResult res = vkCreateMacOSSurfaceMVK(instance, &surface_create_info, nullptr, &surface);
|
||||||
|
@ -412,18 +413,18 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, VkPhysicalDevic
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (wi.type == WindowInfo::Type::Display)
|
if (wi->type == WindowInfo::Type::Display)
|
||||||
return CreateDisplaySurface(instance, physical_device, wi);
|
return CreateDisplaySurface(instance, physical_device, wi);
|
||||||
|
|
||||||
return VK_NULL_HANDLE;
|
return VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo& wi, VkSurfaceKHR surface)
|
void SwapChain::DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface)
|
||||||
{
|
{
|
||||||
vkDestroySurfaceKHR(g_vulkan_context->GetVulkanInstance(), surface, nullptr);
|
vkDestroySurfaceKHR(g_vulkan_context->GetVulkanInstance(), surface, nullptr);
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
if (wi.type == WindowInfo::Type::MacOS && wi.surface_handle)
|
if (wi->type == WindowInfo::Type::MacOS && wi->surface_handle)
|
||||||
DestroyMetalLayer(wi);
|
DestroyMetalLayer(wi);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -567,8 +568,8 @@ bool SwapChain::CreateSwapChain()
|
||||||
if (size.width == UINT32_MAX)
|
if (size.width == UINT32_MAX)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size.width = m_wi.surface_width;
|
size.width = m_window_info.surface_width;
|
||||||
size.height = m_wi.surface_height;
|
size.height = m_window_info.surface_height;
|
||||||
}
|
}
|
||||||
size.width =
|
size.width =
|
||||||
std::clamp(size.width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width);
|
std::clamp(size.width, surface_capabilities.minImageExtent.width, surface_capabilities.maxImageExtent.width);
|
||||||
|
@ -637,8 +638,8 @@ bool SwapChain::CreateSwapChain()
|
||||||
if (old_swap_chain != VK_NULL_HANDLE)
|
if (old_swap_chain != VK_NULL_HANDLE)
|
||||||
vkDestroySwapchainKHR(g_vulkan_context->GetDevice(), old_swap_chain, nullptr);
|
vkDestroySwapchainKHR(g_vulkan_context->GetDevice(), old_swap_chain, nullptr);
|
||||||
|
|
||||||
m_width = size.width;
|
m_window_info.surface_width = size.width;
|
||||||
m_height = size.height;
|
m_window_info.surface_height = size.height;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,8 +676,8 @@ bool SwapChain::SetupSwapChainImages()
|
||||||
image.image = images[i];
|
image.image = images[i];
|
||||||
|
|
||||||
// Create texture object, which creates a view of the backbuffer
|
// Create texture object, which creates a view of the backbuffer
|
||||||
if (!image.texture.Adopt(image.image, VK_IMAGE_VIEW_TYPE_2D, m_width, m_height, 1, 1, m_surface_format.format,
|
if (!image.texture.Adopt(image.image, VK_IMAGE_VIEW_TYPE_2D, m_window_info.surface_width,
|
||||||
VK_SAMPLE_COUNT_1_BIT))
|
m_window_info.surface_height, 1, 1, m_surface_format.format, VK_SAMPLE_COUNT_1_BIT))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -723,8 +724,8 @@ bool SwapChain::ResizeSwapChain(u32 new_width /* = 0 */, u32 new_height /* = 0 *
|
||||||
|
|
||||||
if (new_width != 0 && new_height != 0)
|
if (new_width != 0 && new_height != 0)
|
||||||
{
|
{
|
||||||
m_wi.surface_width = new_width;
|
m_window_info.surface_width = new_width;
|
||||||
m_wi.surface_height = new_height;
|
m_window_info.surface_height = new_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateSemaphores())
|
if (!CreateSwapChain() || !SetupSwapChainImages() || !CreateSemaphores())
|
||||||
|
@ -769,8 +770,9 @@ bool SwapChain::RecreateSurface(const WindowInfo& new_wi)
|
||||||
DestroySurface();
|
DestroySurface();
|
||||||
|
|
||||||
// Re-create the surface with the new native handle
|
// Re-create the surface with the new native handle
|
||||||
m_wi = new_wi;
|
m_window_info = new_wi;
|
||||||
m_surface = CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), m_wi);
|
m_surface =
|
||||||
|
CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), g_vulkan_context->GetPhysicalDevice(), &m_window_info);
|
||||||
if (m_surface == VK_NULL_HANDLE)
|
if (m_surface == VK_NULL_HANDLE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -799,7 +801,7 @@ bool SwapChain::RecreateSurface(const WindowInfo& new_wi)
|
||||||
|
|
||||||
void SwapChain::DestroySurface()
|
void SwapChain::DestroySurface()
|
||||||
{
|
{
|
||||||
DestroyVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_wi, m_surface);
|
DestroyVulkanSurface(g_vulkan_context->GetVulkanInstance(), &m_window_info, m_surface);
|
||||||
m_surface = VK_NULL_HANDLE;
|
m_surface = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ public:
|
||||||
~SwapChain();
|
~SwapChain();
|
||||||
|
|
||||||
// Creates a vulkan-renderable surface for the specified window handle.
|
// Creates a vulkan-renderable surface for the specified window handle.
|
||||||
static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo& wi);
|
static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, VkPhysicalDevice physical_device, WindowInfo* wi);
|
||||||
|
|
||||||
// Destroys a previously-created surface.
|
// Destroys a previously-created surface.
|
||||||
static void DestroyVulkanSurface(VkInstance instance, WindowInfo& wi, VkSurfaceKHR surface);
|
static void DestroyVulkanSurface(VkInstance instance, WindowInfo* wi, VkSurfaceKHR surface);
|
||||||
|
|
||||||
// Enumerates fullscreen modes for window info.
|
// Enumerates fullscreen modes for window info.
|
||||||
struct FullscreenModeInfo
|
struct FullscreenModeInfo
|
||||||
|
@ -44,8 +44,9 @@ public:
|
||||||
ALWAYS_INLINE VkFormat GetTextureFormat() const { return m_surface_format.format; }
|
ALWAYS_INLINE VkFormat GetTextureFormat() const { return m_surface_format.format; }
|
||||||
ALWAYS_INLINE bool IsVSyncEnabled() const { return m_vsync_enabled; }
|
ALWAYS_INLINE bool IsVSyncEnabled() const { return m_vsync_enabled; }
|
||||||
ALWAYS_INLINE VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
|
ALWAYS_INLINE VkSwapchainKHR GetSwapChain() const { return m_swap_chain; }
|
||||||
ALWAYS_INLINE u32 GetWidth() const { return m_width; }
|
ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; }
|
||||||
ALWAYS_INLINE u32 GetHeight() const { return m_height; }
|
ALWAYS_INLINE u32 GetWidth() const { return m_window_info.surface_width; }
|
||||||
|
ALWAYS_INLINE u32 GetHeight() const { return m_window_info.surface_height; }
|
||||||
ALWAYS_INLINE u32 GetCurrentImageIndex() const { return m_current_image; }
|
ALWAYS_INLINE u32 GetCurrentImageIndex() const { return m_current_image; }
|
||||||
ALWAYS_INLINE u32 GetImageCount() const { return static_cast<u32>(m_images.size()); }
|
ALWAYS_INLINE u32 GetImageCount() const { return static_cast<u32>(m_images.size()); }
|
||||||
ALWAYS_INLINE VkImage GetCurrentImage() const { return m_images[m_current_image].image; }
|
ALWAYS_INLINE VkImage GetCurrentImage() const { return m_images[m_current_image].image; }
|
||||||
|
@ -87,10 +88,7 @@ private:
|
||||||
VkFramebuffer framebuffer;
|
VkFramebuffer framebuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 m_width = 0;
|
WindowInfo m_window_info;
|
||||||
u32 m_height = 0;
|
|
||||||
WindowInfo m_wi;
|
|
||||||
bool m_vsync_enabled = false;
|
|
||||||
|
|
||||||
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||||
VkSurfaceFormatKHR m_surface_format = {};
|
VkSurfaceFormatKHR m_surface_format = {};
|
||||||
|
@ -105,6 +103,7 @@ private:
|
||||||
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
|
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
|
||||||
std::vector<SwapChainImage> m_images;
|
std::vector<SwapChainImage> m_images;
|
||||||
u32 m_current_image = 0;
|
u32 m_current_image = 0;
|
||||||
|
bool m_vsync_enabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
191
src/common/window_info.cpp
Normal file
191
src/common/window_info.cpp
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
#include "window_info.h"
|
||||||
|
#include "common/log.h"
|
||||||
|
Log_SetChannel(WindowInfo);
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
#include "common/windows_headers.h"
|
||||||
|
#include <dwmapi.h>
|
||||||
|
|
||||||
|
static bool GetRefreshRateFromDWM(HWND hwnd, float* refresh_rate)
|
||||||
|
{
|
||||||
|
static HMODULE dwm_module = nullptr;
|
||||||
|
static HRESULT(STDAPICALLTYPE * is_composition_enabled)(BOOL * pfEnabled) = nullptr;
|
||||||
|
static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr;
|
||||||
|
static bool load_tried = false;
|
||||||
|
if (!load_tried)
|
||||||
|
{
|
||||||
|
load_tried = true;
|
||||||
|
dwm_module = LoadLibrary("dwmapi.dll");
|
||||||
|
if (dwm_module)
|
||||||
|
{
|
||||||
|
std::atexit([]() {
|
||||||
|
FreeLibrary(dwm_module);
|
||||||
|
dwm_module = nullptr;
|
||||||
|
});
|
||||||
|
is_composition_enabled =
|
||||||
|
reinterpret_cast<decltype(is_composition_enabled)>(GetProcAddress(dwm_module, "DwmIsCompositionEnabled"));
|
||||||
|
get_timing_info =
|
||||||
|
reinterpret_cast<decltype(get_timing_info)>(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL composition_enabled;
|
||||||
|
if (!is_composition_enabled || FAILED(is_composition_enabled(&composition_enabled) || !get_timing_info))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DWM_TIMING_INFO ti = {};
|
||||||
|
ti.cbSize = sizeof(ti);
|
||||||
|
HRESULT hr = get_timing_info(nullptr, &ti);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*refresh_rate = static_cast<float>(ti.rateRefresh.uiNumerator) / static_cast<float>(ti.rateRefresh.uiDenominator);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool GetRefreshRateFromMonitor(HWND hwnd, float* refresh_rate)
|
||||||
|
{
|
||||||
|
HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
|
||||||
|
if (!mon)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MONITORINFOEXW mi = {};
|
||||||
|
mi.cbSize = sizeof(mi);
|
||||||
|
if (GetMonitorInfoW(mon, &mi))
|
||||||
|
{
|
||||||
|
DEVMODEW dm = {};
|
||||||
|
dm.dmSize = sizeof(dm);
|
||||||
|
|
||||||
|
// 0/1 are reserved for "defaults".
|
||||||
|
if (EnumDisplaySettingsW(mi.szDevice, ENUM_CURRENT_SETTINGS, &dm) && dm.dmDisplayFrequency > 1)
|
||||||
|
{
|
||||||
|
*refresh_rate = static_cast<float>(dm.dmDisplayFrequency);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate)
|
||||||
|
{
|
||||||
|
if (wi.type != Type::Win32 || !wi.window_handle)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Try DWM first, then fall back to integer values.
|
||||||
|
const HWND hwnd = static_cast<HWND>(wi.window_handle);
|
||||||
|
return GetRefreshRateFromDWM(hwnd, refresh_rate) || GetRefreshRateFromMonitor(hwnd, refresh_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__linux__)
|
||||||
|
|
||||||
|
#ifdef USE_X11
|
||||||
|
|
||||||
|
#include "common/scope_guard.h"
|
||||||
|
#include "gl/x11_window.h"
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
|
||||||
|
static bool GetRefreshRateFromXRandR(const WindowInfo& wi, float* refresh_rate)
|
||||||
|
{
|
||||||
|
Display* display = static_cast<Display*>(wi.display_connection);
|
||||||
|
Window window = static_cast<Window>(reinterpret_cast<uintptr_t>(wi.window_handle));
|
||||||
|
if (!display || !window)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
GL::X11InhibitErrors inhibiter;
|
||||||
|
|
||||||
|
XRRScreenResources* res = XRRGetScreenResources(display, window);
|
||||||
|
if (!res)
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("XRRGetScreenResources() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ScopeGuard res_guard([res]() { XRRFreeScreenResources(res); });
|
||||||
|
|
||||||
|
int num_monitors;
|
||||||
|
XRRMonitorInfo* mi = XRRGetMonitors(display, window, True, &num_monitors);
|
||||||
|
if (num_monitors < 0)
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("XRRGetMonitors() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (num_monitors > 1)
|
||||||
|
{
|
||||||
|
Log_WarningPrintf("XRRGetMonitors() returned %d monitors, using first", num_monitors);
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ScopeGuard mi_guard([mi]() { XRRFreeMonitors(mi); });
|
||||||
|
if (mi->noutput <= 0)
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("Monitor has no outputs");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (mi->noutput > 1)
|
||||||
|
{
|
||||||
|
Log_WarningPrintf("Monitor has %d outputs, using first", mi->noutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
XRROutputInfo* oi = XRRGetOutputInfo(display, res, mi->outputs[0]);
|
||||||
|
if (!oi)
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("XRRGetOutputInfo() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ScopeGuard oi_guard([oi]() { XRRFreeOutputInfo(oi); });
|
||||||
|
|
||||||
|
XRRCrtcInfo* ci = XRRGetCrtcInfo(display, res, oi->crtc);
|
||||||
|
if (!ci)
|
||||||
|
{
|
||||||
|
Log_ErrorPrint("XRRGetCrtcInfo() failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common::ScopeGuard ci_guard([ci]() { XRRFreeCrtcInfo(ci); });
|
||||||
|
|
||||||
|
XRRModeInfo* mode = nullptr;
|
||||||
|
for (int i = 0; i < res->nmode; i++)
|
||||||
|
{
|
||||||
|
if (res->modes[i].id == ci->mode)
|
||||||
|
{
|
||||||
|
mode = &res->modes[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mode)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to look up mode %d (of %d)", static_cast<int>(ci->mode), res->nmode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode->dotClock == 0 || mode->hTotal == 0 || mode->vTotal == 0)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Modeline is invalid: %ld/%d/%d", mode->dotClock, mode->hTotal, mode->vTotal);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*refresh_rate =
|
||||||
|
static_cast<double>(mode->dotClock) / (static_cast<double>(mode->hTotal) * static_cast<double>(mode->vTotal));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_X11
|
||||||
|
|
||||||
|
bool WindowInfo::QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate)
|
||||||
|
{
|
||||||
|
#if defined(USE_X11)
|
||||||
|
if (wi.type == WindowInfo::Type::X11)
|
||||||
|
return GetRefreshRateFromXRandR(wi, refresh_rate);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -38,4 +38,6 @@ struct WindowInfo
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
void* surface_handle = nullptr;
|
void* surface_handle = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static bool QueryRefreshRateForWindow(const WindowInfo& wi, float* refresh_rate);
|
||||||
};
|
};
|
||||||
|
|
|
@ -88,7 +88,13 @@ bool HostDisplay::SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32
|
||||||
|
|
||||||
bool HostDisplay::GetHostRefreshRate(float* refresh_rate)
|
bool HostDisplay::GetHostRefreshRate(float* refresh_rate)
|
||||||
{
|
{
|
||||||
return g_host_interface->GetMainDisplayRefreshRate(refresh_rate);
|
if (m_window_info.surface_refresh_rate > 0.0f)
|
||||||
|
{
|
||||||
|
*refresh_rate = m_window_info.surface_refresh_rate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WindowInfo::QueryRefreshRateForWindow(m_window_info, refresh_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/)
|
void HostDisplay::SetSoftwareCursor(std::unique_ptr<HostDisplayTexture> texture, float scale /*= 1.0f*/)
|
||||||
|
|
|
@ -25,11 +25,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
Log_SetChannel(HostInterface);
|
Log_SetChannel(HostInterface);
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "common/windows_headers.h"
|
|
||||||
#include <dwmapi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
HostInterface* g_host_interface;
|
HostInterface* g_host_interface;
|
||||||
|
|
||||||
HostInterface::HostInterface()
|
HostInterface::HostInterface()
|
||||||
|
@ -1065,43 +1060,6 @@ std::string HostInterface::TranslateStdString(const char* context, const char* s
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HostInterface::GetMainDisplayRefreshRate(float* refresh_rate)
|
|
||||||
{
|
|
||||||
#ifdef _WIN32
|
|
||||||
static HMODULE dwm_module = nullptr;
|
|
||||||
static HRESULT(STDAPICALLTYPE * get_timing_info)(HWND hwnd, DWM_TIMING_INFO * pTimingInfo) = nullptr;
|
|
||||||
static bool load_tried = false;
|
|
||||||
if (!load_tried)
|
|
||||||
{
|
|
||||||
load_tried = true;
|
|
||||||
dwm_module = LoadLibrary("dwmapi.dll");
|
|
||||||
if (dwm_module)
|
|
||||||
{
|
|
||||||
std::atexit([]() {
|
|
||||||
FreeLibrary(dwm_module);
|
|
||||||
dwm_module = nullptr;
|
|
||||||
});
|
|
||||||
get_timing_info =
|
|
||||||
reinterpret_cast<decltype(get_timing_info)>(GetProcAddress(dwm_module, "DwmGetCompositionTimingInfo"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DWM_TIMING_INFO ti = {};
|
|
||||||
ti.cbSize = sizeof(ti);
|
|
||||||
HRESULT hr = get_timing_info(nullptr, &ti);
|
|
||||||
if (SUCCEEDED(hr))
|
|
||||||
{
|
|
||||||
if (ti.rateRefresh.uiNumerator == 0 || ti.rateRefresh.uiDenominator == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
*refresh_rate = static_cast<float>(ti.rateRefresh.uiNumerator) / static_cast<float>(ti.rateRefresh.uiDenominator);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void HostInterface::ToggleSoftwareRendering()
|
void HostInterface::ToggleSoftwareRendering()
|
||||||
{
|
{
|
||||||
if (System::IsShutdown() || g_settings.gpu_renderer == GPURenderer::Software)
|
if (System::IsShutdown() || g_settings.gpu_renderer == GPURenderer::Software)
|
||||||
|
|
|
@ -126,10 +126,6 @@ public:
|
||||||
virtual std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr,
|
virtual std::string TranslateStdString(const char* context, const char* str, const char* disambiguation = nullptr,
|
||||||
int n = -1) const;
|
int n = -1) const;
|
||||||
|
|
||||||
/// Returns the refresh rate for the "main" display. Use when it's not possible to query the graphics API for the
|
|
||||||
/// refresh rate of the monitor the window is running in.
|
|
||||||
virtual bool GetMainDisplayRefreshRate(float* refresh_rate);
|
|
||||||
|
|
||||||
/// Returns the path to the directory to search for BIOS images.
|
/// Returns the path to the directory to search for BIOS images.
|
||||||
virtual std::string GetBIOSDirectory();
|
virtual std::string GetBIOSDirectory();
|
||||||
|
|
||||||
|
|
|
@ -95,12 +95,6 @@ bool SDLHostInterface::SetFullscreen(bool enabled)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
SDL_SetWindowFullscreen(m_window, enabled ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
SDL_SetWindowFullscreen(m_window, enabled ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
||||||
|
|
||||||
int window_width, window_height;
|
|
||||||
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
|
||||||
m_display->ResizeRenderWindow(window_width, window_height);
|
|
||||||
OnHostDisplayResized(window_width, window_height, GetDPIScaleFactor(m_window));
|
|
||||||
|
|
||||||
m_fullscreen = enabled;
|
m_fullscreen = enabled;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -119,11 +113,6 @@ bool SDLHostInterface::RequestRenderWindowSize(s32 new_window_width, s32 new_win
|
||||||
1);
|
1);
|
||||||
|
|
||||||
SDL_SetWindowSize(m_window, scaled_width, scaled_height);
|
SDL_SetWindowSize(m_window, scaled_width, scaled_height);
|
||||||
|
|
||||||
s32 window_width, window_height;
|
|
||||||
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
|
||||||
m_display->ResizeRenderWindow(window_width, window_height);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,14 +276,12 @@ void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
|
||||||
{
|
{
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
{
|
{
|
||||||
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
|
if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
|
||||||
{
|
{
|
||||||
m_display->ResizeRenderWindow(event->window.data1, event->window.data2);
|
s32 window_width, window_height;
|
||||||
OnHostDisplayResized(event->window.data1, event->window.data2, GetDPIScaleFactor(m_window));
|
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
||||||
}
|
m_display->ResizeRenderWindow(window_width, window_height);
|
||||||
else if (event->window.event == SDL_WINDOWEVENT_MOVED)
|
OnHostDisplayResized();
|
||||||
{
|
|
||||||
// TODO: Do we want to update DPI scale here?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -470,7 +470,7 @@ void QtHostInterface::onDisplayWindowResized(int width, int height)
|
||||||
|
|
||||||
Log_DevPrintf("Display window resized to %dx%d", width, height);
|
Log_DevPrintf("Display window resized to %dx%d", width, height);
|
||||||
m_display->ResizeRenderWindow(width, height);
|
m_display->ResizeRenderWindow(width, height);
|
||||||
OnHostDisplayResized(width, height, m_display->GetWindowScale());
|
OnHostDisplayResized();
|
||||||
|
|
||||||
// re-render the display, since otherwise it will be out of date and stretched if paused
|
// re-render the display, since otherwise it will be out of date and stretched if paused
|
||||||
if (!System::IsShutdown())
|
if (!System::IsShutdown())
|
||||||
|
@ -615,7 +615,7 @@ void QtHostInterface::updateDisplayState()
|
||||||
connectDisplaySignals(display_widget);
|
connectDisplaySignals(display_widget);
|
||||||
m_is_exclusive_fullscreen = m_display->IsFullscreen();
|
m_is_exclusive_fullscreen = m_display->IsFullscreen();
|
||||||
|
|
||||||
OnHostDisplayResized(m_display->GetWindowWidth(), m_display->GetWindowHeight(), m_display->GetWindowScale());
|
OnHostDisplayResized();
|
||||||
|
|
||||||
if (!System::IsShutdown())
|
if (!System::IsShutdown())
|
||||||
{
|
{
|
||||||
|
|
|
@ -520,6 +520,8 @@ bool CommonHostInterface::CreateHostDisplayResources()
|
||||||
|
|
||||||
const float framebuffer_scale = m_display->GetWindowScale();
|
const float framebuffer_scale = m_display->GetWindowScale();
|
||||||
ImGui::GetIO().DisplayFramebufferScale = ImVec2(framebuffer_scale, framebuffer_scale);
|
ImGui::GetIO().DisplayFramebufferScale = ImVec2(framebuffer_scale, framebuffer_scale);
|
||||||
|
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_display->GetWindowWidth());
|
||||||
|
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_display->GetWindowHeight());
|
||||||
ImGui::GetStyle() = ImGuiStyle();
|
ImGui::GetStyle() = ImGuiStyle();
|
||||||
ImGui::StyleColorsDarker();
|
ImGui::StyleColorsDarker();
|
||||||
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
|
||||||
|
@ -566,8 +568,15 @@ void CommonHostInterface::ReleaseHostDisplayResources()
|
||||||
m_logo_texture.reset();
|
m_logo_texture.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommonHostInterface::OnHostDisplayResized(u32 new_width, u32 new_height, float new_scale)
|
void CommonHostInterface::OnHostDisplayResized()
|
||||||
{
|
{
|
||||||
|
const u32 new_width = m_display ? std::max<u32>(m_display->GetWindowWidth(), 1) : 0;
|
||||||
|
const u32 new_height = m_display ? std::max<u32>(m_display->GetWindowHeight(), 1) : 0;
|
||||||
|
const float new_scale = m_display ? m_display->GetWindowScale() : 1.0f;
|
||||||
|
|
||||||
|
ImGui::GetIO().DisplaySize.x = static_cast<float>(new_width);
|
||||||
|
ImGui::GetIO().DisplaySize.y = static_cast<float>(new_height);
|
||||||
|
|
||||||
if (new_scale != ImGui::GetIO().DisplayFramebufferScale.x)
|
if (new_scale != ImGui::GetIO().DisplayFramebufferScale.x)
|
||||||
{
|
{
|
||||||
ImGui::GetIO().DisplayFramebufferScale = ImVec2(new_scale, new_scale);
|
ImGui::GetIO().DisplayFramebufferScale = ImVec2(new_scale, new_scale);
|
||||||
|
@ -1792,7 +1801,7 @@ void CommonHostInterface::RegisterGeneralHotkeys()
|
||||||
if (pressed)
|
if (pressed)
|
||||||
SetTurboEnabled(!m_turbo_enabled);
|
SetTurboEnabled(!m_turbo_enabled);
|
||||||
});
|
});
|
||||||
#ifndef ANDROID
|
#ifndef __ANDROID__
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("ToggleFullscreen"),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "General")), StaticString("ToggleFullscreen"),
|
||||||
StaticString(TRANSLATABLE("Hotkeys", "Toggle Fullscreen")), [this](bool pressed) {
|
StaticString(TRANSLATABLE("Hotkeys", "Toggle Fullscreen")), [this](bool pressed) {
|
||||||
if (pressed)
|
if (pressed)
|
||||||
|
|
|
@ -414,7 +414,7 @@ protected:
|
||||||
|
|
||||||
bool CreateHostDisplayResources();
|
bool CreateHostDisplayResources();
|
||||||
void ReleaseHostDisplayResources();
|
void ReleaseHostDisplayResources();
|
||||||
void OnHostDisplayResized(u32 new_width, u32 new_height, float new_scale);
|
void OnHostDisplayResized();
|
||||||
|
|
||||||
virtual void DrawImGuiWindows();
|
virtual void DrawImGuiWindows();
|
||||||
|
|
||||||
|
|
|
@ -473,10 +473,17 @@ bool D3D11HostDisplay::CreateSwapChainRTV()
|
||||||
m_window_info.surface_width = backbuffer_desc.Width;
|
m_window_info.surface_width = backbuffer_desc.Width;
|
||||||
m_window_info.surface_height = backbuffer_desc.Height;
|
m_window_info.surface_height = backbuffer_desc.Height;
|
||||||
|
|
||||||
if (ImGui::GetCurrentContext())
|
BOOL fullscreen = FALSE;
|
||||||
|
DXGI_SWAP_CHAIN_DESC desc;
|
||||||
|
if (SUCCEEDED(m_swap_chain->GetFullscreenState(&fullscreen, nullptr)) && fullscreen &&
|
||||||
|
SUCCEEDED(m_swap_chain->GetDesc(&desc)))
|
||||||
{
|
{
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(backbuffer_desc.Width);
|
m_window_info.surface_refresh_rate = static_cast<float>(desc.BufferDesc.RefreshRate.Numerator) /
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(backbuffer_desc.Height);
|
static_cast<float>(desc.BufferDesc.RefreshRate.Denominator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_window_info.surface_refresh_rate = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -664,8 +671,6 @@ void D3D11HostDisplay::DestroyResources()
|
||||||
|
|
||||||
bool D3D11HostDisplay::CreateImGuiContext()
|
bool D3D11HostDisplay::CreateImGuiContext()
|
||||||
{
|
{
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
|
||||||
return ImGui_ImplDX11_Init(m_device.Get(), m_context.Get());
|
return ImGui_ImplDX11_Init(m_device.Get(), m_context.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -384,9 +384,7 @@ bool OpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_vie
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_window_info = wi;
|
m_window_info = m_gl_context->GetWindowInfo();
|
||||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
|
||||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,16 +465,7 @@ bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_window_info = new_wi;
|
m_window_info = m_gl_context->GetWindowInfo();
|
||||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
|
||||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
|
||||||
|
|
||||||
if (ImGui::GetCurrentContext())
|
|
||||||
{
|
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,14 +475,7 @@ void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||||
m_window_info.surface_width = m_gl_context->GetSurfaceWidth();
|
m_window_info = m_gl_context->GetWindowInfo();
|
||||||
m_window_info.surface_height = m_gl_context->GetSurfaceHeight();
|
|
||||||
|
|
||||||
if (ImGui::GetCurrentContext())
|
|
||||||
{
|
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLHostDisplay::SupportsFullscreen() const
|
bool OpenGLHostDisplay::SupportsFullscreen() const
|
||||||
|
@ -539,8 +521,6 @@ void OpenGLHostDisplay::DestroyRenderSurface()
|
||||||
|
|
||||||
bool OpenGLHostDisplay::CreateImGuiContext()
|
bool OpenGLHostDisplay::CreateImGuiContext()
|
||||||
{
|
{
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
|
||||||
return ImGui_ImplOpenGL3_Init(GetGLSLVersionString());
|
return ImGui_ImplOpenGL3_Init(GetGLSLVersionString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,12 +76,13 @@ bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||||
{
|
{
|
||||||
g_vulkan_context->ExecuteCommandBuffer(true);
|
g_vulkan_context->ExecuteCommandBuffer(true);
|
||||||
m_swap_chain.reset();
|
m_swap_chain.reset();
|
||||||
|
m_window_info = new_wi;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowInfo wi_copy(new_wi);
|
WindowInfo wi_copy(new_wi);
|
||||||
VkSurfaceKHR surface = Vulkan::SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(),
|
VkSurfaceKHR surface = Vulkan::SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(),
|
||||||
g_vulkan_context->GetPhysicalDevice(), wi_copy);
|
g_vulkan_context->GetPhysicalDevice(), &wi_copy);
|
||||||
if (surface == VK_NULL_HANDLE)
|
if (surface == VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to create new surface for swap chain");
|
Log_ErrorPrintf("Failed to create new surface for swap chain");
|
||||||
|
@ -95,16 +96,7 @@ bool VulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_window_info = wi_copy;
|
m_window_info = m_swap_chain->GetWindowInfo();
|
||||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
|
||||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
|
||||||
|
|
||||||
if (ImGui::GetCurrentContext())
|
|
||||||
{
|
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,14 +107,7 @@ void VulkanHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_
|
||||||
if (!m_swap_chain->ResizeSwapChain(new_window_width, new_window_height))
|
if (!m_swap_chain->ResizeSwapChain(new_window_width, new_window_height))
|
||||||
Panic("Failed to resize swap chain");
|
Panic("Failed to resize swap chain");
|
||||||
|
|
||||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
m_window_info = m_swap_chain->GetWindowInfo();
|
||||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
|
||||||
|
|
||||||
if (ImGui::GetCurrentContext())
|
|
||||||
{
|
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanHostDisplay::SupportsFullscreen() const
|
bool VulkanHostDisplay::SupportsFullscreen() const
|
||||||
|
@ -320,19 +305,15 @@ void VulkanHostDisplay::SetVSync(bool enabled)
|
||||||
bool VulkanHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
|
bool VulkanHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
|
||||||
bool threaded_presentation)
|
bool threaded_presentation)
|
||||||
{
|
{
|
||||||
if (!Vulkan::Context::Create(adapter_name, &wi, &m_swap_chain, threaded_presentation, debug_device, false))
|
WindowInfo local_wi(wi);
|
||||||
|
if (!Vulkan::Context::Create(adapter_name, &local_wi, &m_swap_chain, threaded_presentation, debug_device, false))
|
||||||
{
|
{
|
||||||
Log_ErrorPrintf("Failed to create Vulkan context");
|
Log_ErrorPrintf("Failed to create Vulkan context");
|
||||||
|
m_window_info = {};
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_window_info = wi;
|
m_window_info = m_swap_chain ? m_swap_chain->GetWindowInfo() : local_wi;
|
||||||
if (m_swap_chain)
|
|
||||||
{
|
|
||||||
m_window_info.surface_width = m_swap_chain->GetWidth();
|
|
||||||
m_window_info.surface_height = m_swap_chain->GetHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,9 +507,6 @@ void VulkanHostDisplay::DestroyResources()
|
||||||
|
|
||||||
bool VulkanHostDisplay::CreateImGuiContext()
|
bool VulkanHostDisplay::CreateImGuiContext()
|
||||||
{
|
{
|
||||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_info.surface_width);
|
|
||||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_info.surface_height);
|
|
||||||
|
|
||||||
ImGui_ImplVulkan_InitInfo vii = {};
|
ImGui_ImplVulkan_InitInfo vii = {};
|
||||||
vii.Instance = g_vulkan_context->GetVulkanInstance();
|
vii.Instance = g_vulkan_context->GetVulkanInstance();
|
||||||
vii.PhysicalDevice = g_vulkan_context->GetPhysicalDevice();
|
vii.PhysicalDevice = g_vulkan_context->GetPhysicalDevice();
|
||||||
|
|
Loading…
Reference in a new issue