Frontends: Use common GL context wrapper
This commit is contained in:
parent
4f4c4f4146
commit
2156236f52
|
@ -155,15 +155,6 @@ std::tuple<s32, s32> GPU_HW_OpenGL::ConvertToFramebufferCoordinates(s32 x, s32 y
|
|||
|
||||
void GPU_HW_OpenGL::SetCapabilities(HostDisplay* host_display)
|
||||
{
|
||||
Log_InfoPrintf("Context Type: %s", IsGLES() ? "OpenGL ES" : "OpenGL");
|
||||
|
||||
const char* gl_vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const char* gl_renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
const char* gl_version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
Log_InfoPrintf("GL_VENDOR: %s", gl_vendor);
|
||||
Log_InfoPrintf("GL_RENDERER: %s", gl_renderer);
|
||||
Log_InfoPrintf("GL_VERSION: %s", gl_version);
|
||||
|
||||
GLint max_texture_size = VRAM_WIDTH;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
|
||||
Log_InfoPrintf("Max texture size: %dx%d", max_texture_size, max_texture_size);
|
||||
|
|
|
@ -58,6 +58,7 @@ add_executable(duckstation-qt
|
|||
settingsdialog.ui
|
||||
)
|
||||
|
||||
target_include_directories(duckstation-qt PRIVATE "${Qt5Gui_PRIVATE_INCLUDE_DIRS}")
|
||||
target_link_libraries(duckstation-qt PRIVATE frontend-common core common imgui glad minizip scmversion Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network)
|
||||
|
||||
if(WIN32)
|
||||
|
@ -89,9 +90,4 @@ if(WIN32)
|
|||
add_custom_command(TARGET duckstation-qt POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qt.conf.win" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qt.conf"
|
||||
)
|
||||
else()
|
||||
if(OpenGL_GLX_FOUND)
|
||||
target_compile_definitions(duckstation-qt PRIVATE "HAS_GLX")
|
||||
target_link_libraries(duckstation-qt PRIVATE OpenGL::GLX)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -102,14 +102,14 @@ void MainWindow::createDisplay(QThread* worker_thread, bool use_debug_device, bo
|
|||
return;
|
||||
}
|
||||
|
||||
if (!m_host_display->createSurface() || !m_host_display->makeDeviceContextCurrent())
|
||||
if (!m_host_display->createSurface())
|
||||
{
|
||||
reportError(tr("Failed to create host display surface."));
|
||||
m_host_display->destroyDeviceContext();
|
||||
return;
|
||||
}
|
||||
|
||||
m_host_display->moveContextToThread(worker_thread);
|
||||
m_host_display->deactivateDeviceContext();
|
||||
}
|
||||
|
||||
void MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool render_to_main)
|
||||
|
@ -117,10 +117,7 @@ void MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool ren
|
|||
const bool is_fullscreen = m_display_widget->isFullScreen();
|
||||
const bool is_rendering_to_main = (!is_fullscreen && m_display_widget->parent());
|
||||
if (fullscreen == is_fullscreen && is_rendering_to_main == render_to_main)
|
||||
{
|
||||
m_host_display->moveContextToThread(worker_thread);
|
||||
return;
|
||||
}
|
||||
|
||||
m_host_display->destroySurface();
|
||||
|
||||
|
@ -160,8 +157,6 @@ void MainWindow::updateDisplay(QThread* worker_thread, bool fullscreen, bool ren
|
|||
|
||||
QSignalBlocker blocker(m_ui.actionFullscreen);
|
||||
m_ui.actionFullscreen->setChecked(fullscreen);
|
||||
|
||||
m_host_display->moveContextToThread(worker_thread);
|
||||
}
|
||||
|
||||
void MainWindow::destroyDisplay()
|
||||
|
|
|
@ -10,87 +10,12 @@
|
|||
#include <QtGui/QWindow>
|
||||
#include <array>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#if !defined(WIN32) && !defined(APPLE)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
#include <tuple>
|
||||
Log_SetChannel(OpenGLHostDisplay);
|
||||
|
||||
static thread_local QOpenGLContext* s_thread_gl_context;
|
||||
|
||||
static void* GetProcAddressCallback(const char* name)
|
||||
{
|
||||
QOpenGLContext* ctx = s_thread_gl_context;
|
||||
if (!ctx)
|
||||
return nullptr;
|
||||
|
||||
return (void*)ctx->getProcAddress(name);
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
#include "common/windows_headers.h"
|
||||
#elif defined(HAS_GLX)
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
|
||||
/// Changes the swap interval on a window. Since Qt doesn't expose this functionality, we need to change it manually
|
||||
/// ourselves it by calling system-specific functions. Assumes the context is current.
|
||||
static void SetSwapInterval(QOpenGLContext* context, int interval)
|
||||
{
|
||||
static QOpenGLContext* last_context = nullptr;
|
||||
|
||||
#ifdef WIN32
|
||||
static void(WINAPI * wgl_swap_interval_ext)(int) = nullptr;
|
||||
|
||||
if (last_context != context)
|
||||
{
|
||||
wgl_swap_interval_ext = nullptr;
|
||||
last_context = context;
|
||||
|
||||
HMODULE gl_module = GetModuleHandleA("opengl32.dll");
|
||||
if (!gl_module)
|
||||
return;
|
||||
|
||||
const auto wgl_get_proc_address =
|
||||
reinterpret_cast<PROC(WINAPI*)(LPCSTR)>(GetProcAddress(gl_module, "wglGetProcAddress"));
|
||||
if (!wgl_get_proc_address)
|
||||
return;
|
||||
|
||||
wgl_swap_interval_ext =
|
||||
reinterpret_cast<decltype(wgl_swap_interval_ext)>(wgl_get_proc_address("wglSwapIntervalEXT"));
|
||||
}
|
||||
|
||||
if (wgl_swap_interval_ext)
|
||||
wgl_swap_interval_ext(interval);
|
||||
#elif __linux__
|
||||
const QString platform_name(QGuiApplication::platformName());
|
||||
if (platform_name == QStringLiteral("xcb"))
|
||||
{
|
||||
static void (*glx_swap_interval_ext)(Display*, GLXDrawable, int) = nullptr;
|
||||
|
||||
if (last_context != context)
|
||||
{
|
||||
glx_swap_interval_ext = nullptr;
|
||||
last_context = context;
|
||||
|
||||
glx_swap_interval_ext = reinterpret_cast<decltype(glx_swap_interval_ext)>(
|
||||
glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXSwapIntervalEXT")));
|
||||
if (!glx_swap_interval_ext)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!glx_swap_interval_ext)
|
||||
return;
|
||||
|
||||
Display* dpy = glXGetCurrentDisplay();
|
||||
GLXDrawable drawable = glXGetCurrentDrawable();
|
||||
if (dpy && drawable != GLX_NONE)
|
||||
glx_swap_interval_ext(dpy, drawable, interval);
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "Unknown platform: " << platform_name;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
class OpenGLDisplayWidgetTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
|
@ -148,7 +73,7 @@ QtDisplayWidget* OpenGLHostDisplay::createWidget(QWidget* parent)
|
|||
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_gl_context->isOpenGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
|
||||
return m_gl_context->IsGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
|
@ -161,6 +86,12 @@ void* OpenGLHostDisplay::GetRenderContext() const
|
|||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
QtHostDisplay::WindowResized(new_window_width, new_window_height);
|
||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> OpenGLHostDisplay::CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic)
|
||||
{
|
||||
|
@ -213,13 +144,13 @@ void OpenGLHostDisplay::SetVSync(bool enabled)
|
|||
GLint current_fbo = 0;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
SetSwapInterval(m_gl_context.get(), enabled ? 1 : 0);
|
||||
m_gl_context->SetSwapInterval(enabled ? 1 : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
const char* OpenGLHostDisplay::GetGLSLVersionString() const
|
||||
{
|
||||
if (m_gl_context->isOpenGLES())
|
||||
if (m_gl_context->IsGLES())
|
||||
{
|
||||
if (GLAD_GL_ES_VERSION_3_0)
|
||||
return "#version 300 es";
|
||||
|
@ -239,7 +170,7 @@ std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
|
|||
{
|
||||
std::string header = GetGLSLVersionString();
|
||||
header += "\n\n";
|
||||
if (m_gl_context->isOpenGLES())
|
||||
if (m_gl_context->IsGLES())
|
||||
{
|
||||
header += "precision highp float;\n";
|
||||
header += "precision highp int;\n\n";
|
||||
|
@ -273,80 +204,60 @@ bool OpenGLHostDisplay::hasDeviceContext() const
|
|||
return static_cast<bool>(m_gl_context);
|
||||
}
|
||||
|
||||
WindowInfo OpenGLHostDisplay::getWindowInfo() const
|
||||
{
|
||||
WindowInfo wi;
|
||||
|
||||
// Windows and Apple are easy here since there's no display connection.
|
||||
#if defined(WIN32)
|
||||
wi.type = WindowInfo::Type::Win32;
|
||||
wi.window_handle = reinterpret_cast<void*>(m_widget->winId());
|
||||
#elif defined(__APPLE__)
|
||||
wi.type = WindowInfo::Type::MacOS;
|
||||
wi.window_handle = reinterpret_cast<void*>(m_widget->winId());
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
const QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("xcb"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::X11;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle());
|
||||
wi.window_handle = reinterpret_cast<void*>(m_widget->winId());
|
||||
}
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
{
|
||||
wi.type = WindowInfo::Type::Wayland;
|
||||
wi.display_connection = pni->nativeResourceForWindow("display", m_widget->windowHandle());
|
||||
wi.window_handle = pni->nativeResourceForWindow("surface", m_widget->windowHandle());
|
||||
}
|
||||
else
|
||||
{
|
||||
qCritical() << "Unknown PNI platform " << platform_name;
|
||||
return wi;
|
||||
}
|
||||
#endif
|
||||
|
||||
wi.surface_width = m_widget->width();
|
||||
wi.surface_height = m_widget->height();
|
||||
wi.surface_format = WindowInfo::SurfaceFormat::RGB8;
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::createDeviceContext(bool debug_device)
|
||||
{
|
||||
m_gl_context = std::make_unique<QOpenGLContext>();
|
||||
|
||||
// Prefer a desktop OpenGL context where possible. If we can't get this, try OpenGL ES.
|
||||
static constexpr std::array<std::tuple<int, int>, 11> desktop_versions_to_try = {
|
||||
{{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}, {3, 1}, {3, 0}}};
|
||||
static constexpr std::array<std::tuple<int, int>, 4> es_versions_to_try = {{{3, 2}, {3, 1}, {3, 0}}};
|
||||
|
||||
QSurfaceFormat surface_format; // = requestedFormat();
|
||||
surface_format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
|
||||
surface_format.setSwapInterval(0);
|
||||
surface_format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
surface_format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
if (debug_device)
|
||||
surface_format.setOption(QSurfaceFormat::DebugContext);
|
||||
|
||||
for (const auto [major, minor] : desktop_versions_to_try)
|
||||
{
|
||||
surface_format.setVersion(major, minor);
|
||||
m_gl_context->setFormat(surface_format);
|
||||
if (m_gl_context->create())
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_gl_context->isValid())
|
||||
{
|
||||
// try forcing ES
|
||||
surface_format.setRenderableType(QSurfaceFormat::OpenGLES);
|
||||
surface_format.setProfile(QSurfaceFormat::NoProfile);
|
||||
if (debug_device)
|
||||
surface_format.setOption(QSurfaceFormat::DebugContext, false);
|
||||
|
||||
for (const auto [major, minor] : es_versions_to_try)
|
||||
{
|
||||
surface_format.setVersion(major, minor);
|
||||
m_gl_context->setFormat(surface_format);
|
||||
if (m_gl_context->create())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_gl_context->isValid())
|
||||
m_gl_context = GL::Context::Create(getWindowInfo());
|
||||
if (!m_gl_context)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create any GL context");
|
||||
m_gl_context.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
surface_format = m_gl_context->format();
|
||||
Log_InfoPrintf("Got a %s %d.%d context", (m_gl_context->isOpenGLES() ? "OpenGL ES" : "desktop OpenGL"),
|
||||
surface_format.majorVersion(), surface_format.minorVersion());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::initializeDeviceContext(bool debug_device)
|
||||
{
|
||||
if (!m_gl_context->makeCurrent(m_widget->windowHandle()))
|
||||
return false;
|
||||
|
||||
s_thread_gl_context = m_gl_context.get();
|
||||
|
||||
// Load GLAD.
|
||||
const auto load_result =
|
||||
m_gl_context->isOpenGLES() ? gladLoadGLES2Loader(GetProcAddressCallback) : gladLoadGLLoader(GetProcAddressCallback);
|
||||
if (!load_result)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to load GL functions");
|
||||
s_thread_gl_context = nullptr;
|
||||
m_gl_context->doneCurrent();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debug_device && GLAD_GL_KHR_debug)
|
||||
{
|
||||
glad_glDebugMessageCallbackKHR(GLDebugCallback, nullptr);
|
||||
|
@ -356,17 +267,16 @@ bool OpenGLHostDisplay::initializeDeviceContext(bool debug_device)
|
|||
|
||||
if (!QtHostDisplay::initializeDeviceContext(debug_device))
|
||||
{
|
||||
s_thread_gl_context = nullptr;
|
||||
m_gl_context->doneCurrent();
|
||||
m_gl_context->DoneCurrent();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenGLHostDisplay::makeDeviceContextCurrent()
|
||||
bool OpenGLHostDisplay::activateDeviceContext()
|
||||
{
|
||||
if (!m_gl_context->makeCurrent(m_widget->windowHandle()))
|
||||
if (!m_gl_context->MakeCurrent())
|
||||
{
|
||||
Log_ErrorPrintf("Failed to make GL context current");
|
||||
return false;
|
||||
|
@ -375,20 +285,15 @@ bool OpenGLHostDisplay::makeDeviceContextCurrent()
|
|||
return true;
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::moveContextToThread(QThread* new_thread)
|
||||
void OpenGLHostDisplay::deactivateDeviceContext()
|
||||
{
|
||||
m_gl_context->doneCurrent();
|
||||
m_gl_context->moveToThread(new_thread);
|
||||
m_gl_context->DoneCurrent();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::destroyDeviceContext()
|
||||
{
|
||||
Assert(m_gl_context && s_thread_gl_context == m_gl_context.get());
|
||||
|
||||
QtHostDisplay::destroyDeviceContext();
|
||||
|
||||
s_thread_gl_context = nullptr;
|
||||
m_gl_context->doneCurrent();
|
||||
m_gl_context->DoneCurrent();
|
||||
m_gl_context.reset();
|
||||
}
|
||||
|
||||
|
@ -397,6 +302,10 @@ bool OpenGLHostDisplay::createSurface()
|
|||
m_window_width = m_widget->scaledWindowWidth();
|
||||
m_window_height = m_widget->scaledWindowHeight();
|
||||
emit m_widget->windowResizedEvent(m_window_width, m_window_height);
|
||||
|
||||
if (m_gl_context)
|
||||
m_gl_context->ChangeSurface(getWindowInfo());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -455,7 +364,7 @@ void main()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!m_gl_context->isOpenGLES())
|
||||
if (!m_gl_context->IsGLES())
|
||||
m_display_program.BindFragData(0, "o_col0");
|
||||
|
||||
if (!m_display_program.Link())
|
||||
|
@ -508,9 +417,7 @@ void OpenGLHostDisplay::Render()
|
|||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
QWindow* window_handle = m_widget->windowHandle();
|
||||
m_gl_context->makeCurrent(window_handle);
|
||||
m_gl_context->swapBuffers(window_handle);
|
||||
m_gl_context->SwapBuffers();
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
#define __glext_h_
|
||||
#endif
|
||||
|
||||
#include "common/gl/context.h"
|
||||
#include "common/gl/program.h"
|
||||
#include "common/gl/texture.h"
|
||||
#include "common/window_info.h"
|
||||
#include "core/host_display.h"
|
||||
#include "qtdisplaywidget.h"
|
||||
#include "qthostdisplay.h"
|
||||
#include <QtGui/QOpenGLContext>
|
||||
#include <memory>
|
||||
|
||||
class QtHostInterface;
|
||||
|
@ -29,8 +30,8 @@ public:
|
|||
bool hasDeviceContext() const override;
|
||||
bool createDeviceContext(bool debug_device) override;
|
||||
bool initializeDeviceContext(bool debug_device) override;
|
||||
bool makeDeviceContextCurrent() override;
|
||||
void moveContextToThread(QThread* new_thread) override;
|
||||
bool activateDeviceContext() override;
|
||||
void deactivateDeviceContext() override;
|
||||
void destroyDeviceContext() override;
|
||||
bool createSurface() override;
|
||||
void destroySurface();
|
||||
|
@ -38,6 +39,7 @@ public:
|
|||
RenderAPI GetRenderAPI() const override;
|
||||
void* GetRenderDevice() const override;
|
||||
void* GetRenderContext() const override;
|
||||
void WindowResized(s32 new_window_width, s32 new_window_height) override;
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* initial_data,
|
||||
u32 initial_data_stride, bool dynamic) override;
|
||||
|
@ -54,6 +56,8 @@ private:
|
|||
const char* GetGLSLVersionString() const;
|
||||
std::string GetGLSLVersionHeader() const;
|
||||
|
||||
WindowInfo getWindowInfo() const;
|
||||
|
||||
bool createImGuiContext() override;
|
||||
void destroyImGuiContext() override;
|
||||
bool createDeviceResources() override;
|
||||
|
@ -61,7 +65,7 @@ private:
|
|||
|
||||
void renderDisplay();
|
||||
|
||||
std::unique_ptr<QOpenGLContext> m_gl_context = nullptr;
|
||||
std::unique_ptr<GL::Context> m_gl_context = nullptr;
|
||||
|
||||
GL::Program m_display_program;
|
||||
GLuint m_display_vao = 0;
|
||||
|
|
|
@ -50,12 +50,12 @@ bool QtHostDisplay::initializeDeviceContext(bool debug_device)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool QtHostDisplay::makeDeviceContextCurrent()
|
||||
bool QtHostDisplay::activateDeviceContext()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void QtHostDisplay::moveContextToThread(QThread* new_thread) {}
|
||||
void QtHostDisplay::deactivateDeviceContext() {}
|
||||
|
||||
void QtHostDisplay::destroyDeviceContext()
|
||||
{
|
||||
|
|
|
@ -23,8 +23,8 @@ public:
|
|||
virtual bool hasDeviceContext() const;
|
||||
virtual bool createDeviceContext(bool debug_device);
|
||||
virtual bool initializeDeviceContext(bool debug_device);
|
||||
virtual bool makeDeviceContextCurrent();
|
||||
virtual void moveContextToThread(QThread* new_thread);
|
||||
virtual bool activateDeviceContext();
|
||||
virtual void deactivateDeviceContext();
|
||||
virtual void destroyDeviceContext();
|
||||
virtual bool createSurface();
|
||||
virtual void destroySurface();
|
||||
|
|
|
@ -317,7 +317,7 @@ bool QtHostInterface::AcquireHostDisplay()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!getHostDisplay()->makeDeviceContextCurrent() ||
|
||||
if (!getHostDisplay()->activateDeviceContext() ||
|
||||
!getHostDisplay()->initializeDeviceContext(m_settings.gpu_use_debug_device))
|
||||
{
|
||||
getHostDisplay()->destroyDeviceContext();
|
||||
|
@ -366,9 +366,9 @@ void QtHostInterface::disconnectDisplaySignals()
|
|||
void QtHostInterface::updateDisplayState()
|
||||
{
|
||||
// this expects the context to get moved back to us afterwards
|
||||
getHostDisplay()->moveContextToThread(m_original_thread);
|
||||
getHostDisplay()->deactivateDeviceContext();
|
||||
emit updateDisplayRequested(m_worker_thread, m_is_fullscreen, m_is_rendering_to_main);
|
||||
if (!getHostDisplay()->makeDeviceContextCurrent())
|
||||
if (!getHostDisplay()->activateDeviceContext())
|
||||
Panic("Failed to make device context current after updating");
|
||||
|
||||
getHostDisplay()->updateImGuiDisplaySize();
|
||||
|
|
|
@ -2,12 +2,24 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/log.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include <SDL_syswm.h>
|
||||
#include <array>
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <tuple>
|
||||
Log_SetChannel(OpenGLHostDisplay);
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <objc/message.h>
|
||||
struct NSView;
|
||||
|
||||
static NSView* GetContentViewFromWindow(NSWindow* window)
|
||||
{
|
||||
// window.contentView
|
||||
return reinterpret_cast<NSView* (*)(id, SEL)>(objc_msgSend)(reinterpret_cast<id>(window), sel_getUid("contentView"));
|
||||
}
|
||||
#endif
|
||||
|
||||
class OpenGLDisplayWidgetTexture : public HostDisplayTexture
|
||||
{
|
||||
public:
|
||||
|
@ -67,8 +79,7 @@ OpenGLHostDisplay::~OpenGLHostDisplay()
|
|||
m_display_program.Destroy();
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplSDL2_Shutdown();
|
||||
SDL_GL_MakeCurrent(nullptr, nullptr);
|
||||
SDL_GL_DeleteContext(m_gl_context);
|
||||
m_gl_context.reset();
|
||||
}
|
||||
|
||||
if (m_window)
|
||||
|
@ -77,7 +88,7 @@ OpenGLHostDisplay::~OpenGLHostDisplay()
|
|||
|
||||
HostDisplay::RenderAPI OpenGLHostDisplay::GetRenderAPI() const
|
||||
{
|
||||
return m_is_gles ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
|
||||
return m_gl_context->IsGLES() ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
|
||||
}
|
||||
|
||||
void* OpenGLHostDisplay::GetRenderDevice() const
|
||||
|
@ -87,13 +98,15 @@ void* OpenGLHostDisplay::GetRenderDevice() const
|
|||
|
||||
void* OpenGLHostDisplay::GetRenderContext() const
|
||||
{
|
||||
return m_gl_context;
|
||||
return m_gl_context.get();
|
||||
}
|
||||
|
||||
void OpenGLHostDisplay::WindowResized(s32 new_window_width, s32 new_window_height)
|
||||
{
|
||||
HostDisplay::WindowResized(new_window_width, new_window_height);
|
||||
SDL_GL_GetDrawableSize(m_window, &m_window_width, &m_window_height);
|
||||
m_gl_context->ResizeSurface(static_cast<u32>(new_window_width), static_cast<u32>(new_window_height));
|
||||
m_window_width = static_cast<s32>(m_gl_context->GetSurfaceWidth());
|
||||
m_window_height = static_cast<s32>(m_gl_context->GetSurfaceHeight());
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
}
|
||||
|
@ -150,13 +163,13 @@ void OpenGLHostDisplay::SetVSync(bool enabled)
|
|||
GLint current_fbo = 0;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, ¤t_fbo);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
SDL_GL_SetSwapInterval(enabled ? 1 : 0);
|
||||
m_gl_context->SetSwapInterval(enabled ? 1 : 0);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current_fbo);
|
||||
}
|
||||
|
||||
const char* OpenGLHostDisplay::GetGLSLVersionString() const
|
||||
{
|
||||
if (m_is_gles)
|
||||
if (m_gl_context->IsGLES())
|
||||
{
|
||||
if (GLAD_GL_ES_VERSION_3_0)
|
||||
return "#version 300 es";
|
||||
|
@ -176,7 +189,7 @@ std::string OpenGLHostDisplay::GetGLSLVersionHeader() const
|
|||
{
|
||||
std::string header = GetGLSLVersionString();
|
||||
header += "\n\n";
|
||||
if (m_is_gles)
|
||||
if (m_gl_context->IsGLES())
|
||||
{
|
||||
header += "precision highp float;\n";
|
||||
header += "precision highp int;\n\n";
|
||||
|
@ -207,64 +220,55 @@ static void APIENTRY GLDebugCallback(GLenum source, GLenum type, GLuint id, GLen
|
|||
|
||||
bool OpenGLHostDisplay::CreateGLContext(bool debug_device)
|
||||
{
|
||||
// Prefer a desktop OpenGL context where possible. If we can't get this, try OpenGL ES.
|
||||
static constexpr std::array<std::tuple<int, int>, 11> desktop_versions_to_try = {
|
||||
{{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}, {3, 1}, {3, 0}}};
|
||||
static constexpr std::array<std::tuple<int, int>, 4> es_versions_to_try = {{{3, 2}, {3, 1}, {3, 0}}};
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
if (debug_device)
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
||||
|
||||
for (const auto [major, minor] : desktop_versions_to_try)
|
||||
SDL_SysWMinfo syswm = {};
|
||||
SDL_VERSION(&syswm.version);
|
||||
if (!SDL_GetWindowWMInfo(m_window, &syswm))
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
|
||||
|
||||
Log_InfoPrintf("Trying a Desktop OpenGL %d.%d context", major, minor);
|
||||
m_gl_context = SDL_GL_CreateContext(m_window);
|
||||
if (m_gl_context)
|
||||
{
|
||||
Log_InfoPrintf("Got a desktop OpenGL %d.%d context", major, minor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_gl_context)
|
||||
{
|
||||
// try es
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
|
||||
|
||||
for (const auto [major, minor] : es_versions_to_try)
|
||||
{
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, minor);
|
||||
|
||||
Log_InfoPrintf("Trying a OpenGL ES %d.%d context", major, minor);
|
||||
m_gl_context = SDL_GL_CreateContext(m_window);
|
||||
if (m_gl_context)
|
||||
{
|
||||
Log_InfoPrintf("Got a OpenGL ES %d.%d context", major, minor);
|
||||
m_is_gles = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_gl_context || SDL_GL_MakeCurrent(m_window, m_gl_context) != 0)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create any GL context");
|
||||
Log_ErrorPrintf("SDL_GetWindowWMInfo failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load GLAD.
|
||||
const auto load_result =
|
||||
m_is_gles ? gladLoadGLES2Loader(SDL_GL_GetProcAddress) : gladLoadGLLoader(SDL_GL_GetProcAddress);
|
||||
if (!load_result)
|
||||
int window_width, window_height;
|
||||
SDL_GetWindowSize(m_window, &window_width, &window_height);
|
||||
|
||||
WindowInfo wi;
|
||||
wi.surface_width = static_cast<u32>(window_width);
|
||||
wi.surface_height = static_cast<u32>(window_height);
|
||||
wi.surface_format = WindowInfo::SurfaceFormat::RGB8;
|
||||
|
||||
switch (syswm.subsystem)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to load GL functions");
|
||||
#ifdef SDL_VIDEO_DRIVER_WINDOWS
|
||||
case SDL_SYSWM_WINDOWS:
|
||||
wi.type = WindowInfo::Type::Win32;
|
||||
wi.window_handle = syswm.info.win.window;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_COCOA
|
||||
case SDL_SYSWM_COCOA:
|
||||
wi.type = WindowInfo::Type::MacOS;
|
||||
wi.window_handle = GetContentViewFromWindow(syswm.info.cocoa.window);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11
|
||||
case SDL_SYSWM_X11:
|
||||
wi.type = WindowInfo::Type::X11;
|
||||
wi.window_handle = reinterpret_cast<void*>(static_cast<uintptr_t>(syswm.info.x11.window));
|
||||
wi.display_connection = syswm.info.x11.display;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Log_ErrorPrintf("Unhandled syswm subsystem %u", static_cast<u32>(syswm.subsystem));
|
||||
return false;
|
||||
}
|
||||
|
||||
m_gl_context = GL::Context::Create(wi);
|
||||
if (!m_gl_context)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to create a GL context of any kind.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -276,10 +280,11 @@ bool OpenGLHostDisplay::CreateGLContext(bool debug_device)
|
|||
}
|
||||
|
||||
// this can change due to retina scaling on macos?
|
||||
SDL_GL_GetDrawableSize(m_window, &m_window_width, &m_window_height);
|
||||
m_window_width = static_cast<s32>(m_gl_context->GetSurfaceWidth());
|
||||
m_window_height = static_cast<s32>(m_gl_context->GetSurfaceHeight());
|
||||
|
||||
// start with vsync on
|
||||
SDL_GL_SetSwapInterval(1);
|
||||
m_gl_context->SetSwapInterval(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -288,7 +293,7 @@ bool OpenGLHostDisplay::CreateImGuiContext()
|
|||
ImGui::GetIO().DisplaySize.x = static_cast<float>(m_window_width);
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(m_window_height);
|
||||
|
||||
if (!ImGui_ImplSDL2_InitForOpenGL(m_window, m_gl_context) || !ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||
if (!ImGui_ImplSDL2_InitForOpenGL(m_window, nullptr) || !ImGui_ImplOpenGL3_Init(GetGLSLVersionString()))
|
||||
return false;
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
|
@ -329,7 +334,7 @@ void main()
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!m_is_gles)
|
||||
if (!m_gl_context->IsGLES())
|
||||
m_display_program.BindFragData(0, "o_col0");
|
||||
|
||||
if (!m_display_program.Link())
|
||||
|
@ -377,7 +382,7 @@ void OpenGLHostDisplay::Render()
|
|||
ImGui::Render();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
SDL_GL_SwapWindow(m_window);
|
||||
m_gl_context->SwapBuffers();
|
||||
|
||||
ImGui::NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame(m_window);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
#include "common/gl/context.h"
|
||||
#include "common/gl/program.h"
|
||||
#include "common/gl/texture.h"
|
||||
#include "core/host_display.h"
|
||||
|
@ -41,12 +42,10 @@ private:
|
|||
void RenderDisplay();
|
||||
|
||||
SDL_Window* m_window = nullptr;
|
||||
SDL_GLContext m_gl_context = nullptr;
|
||||
std::unique_ptr<GL::Context> m_gl_context;
|
||||
|
||||
GL::Program m_display_program;
|
||||
GLuint m_display_vao = 0;
|
||||
GLuint m_display_nearest_sampler = 0;
|
||||
GLuint m_display_linear_sampler = 0;
|
||||
|
||||
bool m_is_gles = false;
|
||||
};
|
||||
|
|
|
@ -81,8 +81,7 @@ bool SDLHostInterface::CreateSDLWindow()
|
|||
static constexpr u32 DEFAULT_WINDOW_HEIGHT = 700;
|
||||
|
||||
// Create window.
|
||||
const u32 window_flags =
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | (UseOpenGLRenderer() ? SDL_WINDOW_OPENGL : 0);
|
||||
const u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
|
||||
u32 window_width = DEFAULT_WINDOW_WIDTH;
|
||||
u32 window_height = DEFAULT_WINDOW_HEIGHT;
|
||||
|
@ -116,6 +115,8 @@ bool SDLHostInterface::CreateSDLWindow()
|
|||
if (m_fullscreen)
|
||||
SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
||||
|
||||
// Process events so that we have everything sorted out before creating a child window for the GL context (X11).
|
||||
SDL_PumpEvents();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -818,7 +819,7 @@ void SDLHostInterface::DrawDebugMenu()
|
|||
for (u32 i = LOGLEVEL_NONE; i < LOGLEVEL_COUNT; i++)
|
||||
{
|
||||
if (ImGui::MenuItem(Settings::GetLogLevelDisplayName(static_cast<LOGLEVEL>(i)), nullptr,
|
||||
m_settings.log_level == static_cast<LOGLEVEL>(i)))
|
||||
m_settings.log_level == static_cast<LOGLEVEL>(i)))
|
||||
{
|
||||
m_settings_copy.log_level = static_cast<LOGLEVEL>(i);
|
||||
settings_changed = true;
|
||||
|
|
Loading…
Reference in New Issue