Merge pull request #7450 from stenzek/glcontext
GLInterface refactoring/cleanup and runtime platform selection
This commit is contained in:
commit
c4d1e4adff
|
@ -0,0 +1,54 @@
|
|||
# from https://raw.githubusercontent.com/WebKit/webkit/master/Source/cmake/FindEGL.cmake
|
||||
# - Try to Find EGL
|
||||
# Once done, this will define
|
||||
#
|
||||
# EGL_FOUND - system has EGL installed.
|
||||
# EGL_INCLUDE_DIRS - directories which contain the EGL headers.
|
||||
# EGL_LIBRARIES - libraries required to link against EGL.
|
||||
# EGL_DEFINITIONS - Compiler switches required for using EGL.
|
||||
#
|
||||
# Copyright (C) 2012 Intel Corporation. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
pkg_check_modules(PC_EGL egl)
|
||||
|
||||
if (PC_EGL_FOUND)
|
||||
set(EGL_DEFINITIONS ${PC_EGL_CFLAGS_OTHER})
|
||||
endif ()
|
||||
|
||||
find_path(EGL_INCLUDE_DIRS NAMES EGL/egl.h
|
||||
HINTS ${PC_EGL_INCLUDEDIR} ${PC_EGL_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(EGL_NAMES ${EGL_NAMES} egl EGL)
|
||||
find_library(EGL_LIBRARIES NAMES ${EGL_NAMES}
|
||||
HINTS ${PC_EGL_LIBDIR} ${PC_EGL_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(EGL DEFAULT_MSG EGL_INCLUDE_DIRS EGL_LIBRARIES)
|
||||
|
||||
mark_as_advanced(EGL_INCLUDE_DIRS EGL_LIBRARIES)
|
|
@ -16,8 +16,13 @@ project(dolphin-emu)
|
|||
# unique name here.
|
||||
set(DISTRIBUTOR "None" CACHE STRING "Name of the distributor.")
|
||||
|
||||
option(USE_EGL "Enables EGL OpenGL Interface" OFF)
|
||||
option(TRY_X11 "Enables X11 Support" ON)
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
option(ENABLE_X11 "Enables X11 Support" ON)
|
||||
endif()
|
||||
if(NOT WIN32 AND NOT APPLE)
|
||||
option(ENABLE_EGL "Enables EGL OpenGL Interface" ON)
|
||||
endif()
|
||||
|
||||
option(USE_SHARED_ENET "Use shared libenet if found rather than Dolphin's soon-to-compatibly-diverge version" OFF)
|
||||
option(USE_UPNP "Enables UPnP port mapping support" ON)
|
||||
option(ENABLE_QT "Enable Qt (Default)" ON)
|
||||
|
@ -87,13 +92,8 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
|||
|
||||
# Set up paths
|
||||
set(bindir ${CMAKE_INSTALL_PREFIX}/bin CACHE PATH "bindir")
|
||||
if(HAIKU)
|
||||
set(datadir ${CMAKE_INSTALL_PREFIX}/data/dolphin-emu CACHE PATH "datadir")
|
||||
set(mandir ${CMAKE_INSTALL_PREFIX}/documentation/man CACHE PATH "mandir")
|
||||
else()
|
||||
set(datadir ${CMAKE_INSTALL_PREFIX}/share/dolphin-emu CACHE PATH "datadir")
|
||||
set(mandir ${CMAKE_INSTALL_PREFIX}/share/man CACHE PATH "mandir")
|
||||
endif()
|
||||
set(datadir ${CMAKE_INSTALL_PREFIX}/share/dolphin-emu CACHE PATH "datadir")
|
||||
set(mandir ${CMAKE_INSTALL_PREFIX}/share/man CACHE PATH "mandir")
|
||||
add_definitions(-DDATA_DIR="${datadir}/")
|
||||
|
||||
if(CMAKE_SYSROOT)
|
||||
|
@ -370,9 +370,7 @@ if(ANDROID)
|
|||
# but not as a shared library. We want an executable.
|
||||
set(ANDROID 0)
|
||||
endif()
|
||||
set(USE_X11 0)
|
||||
set(USE_UPNP 0)
|
||||
set(USE_EGL 1)
|
||||
set(ENABLE_QT 0)
|
||||
set(USE_DISCORD_PRESENCE 0)
|
||||
|
||||
|
@ -381,20 +379,10 @@ if(ANDROID)
|
|||
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
elseif(HAIKU)
|
||||
set(USE_X11 0)
|
||||
set(USE_UPNP 0)
|
||||
set(USE_EGL 0)
|
||||
endif()
|
||||
|
||||
if(ENABLE_HEADLESS)
|
||||
if(APPLE)
|
||||
message(STATUS "Enabling Headless! Disabling GUI.")
|
||||
else()
|
||||
message(STATUS "Enabling Headless! Disabling GUI, force enabling EGL!")
|
||||
set(USE_EGL 1)
|
||||
endif()
|
||||
set(USE_X11 0)
|
||||
message(STATUS "Enabling Headless! Disabling GUI.")
|
||||
set(ENABLE_QT 0)
|
||||
set(USE_DISCORD_PRESENCE 0)
|
||||
add_definitions(-DUSE_HEADLESS)
|
||||
|
@ -425,38 +413,31 @@ if (OPENGL_GL)
|
|||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
set(USE_X11 0)
|
||||
|
||||
if(UNIX AND NOT APPLE AND NOT ANDROID AND NOT HAIKU AND NOT ENABLE_HEADLESS)
|
||||
if(ENABLE_X11)
|
||||
find_package(X11)
|
||||
if(TRY_X11 AND X11_FOUND)
|
||||
set(USE_X11 1)
|
||||
if(X11_FOUND)
|
||||
add_definitions(-DHAVE_X11=1)
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
check_lib(XRANDR xrandr Xrandr)
|
||||
if(XRANDR_FOUND)
|
||||
add_definitions(-DHAVE_XRANDR=1)
|
||||
else()
|
||||
add_definitions(-DHAVE_XRANDR=0)
|
||||
endif()
|
||||
pkg_check_modules(X11_INPUT REQUIRED xi>=1.5.0)
|
||||
message(STATUS "X11 support enabled")
|
||||
else()
|
||||
set(USE_X11 0)
|
||||
SET(X11_FOUND "")
|
||||
message(STATUS "X11 support disabled")
|
||||
add_definitions(-DHAVE_X11=0)
|
||||
endif()
|
||||
|
||||
if (NOT USE_X11)
|
||||
message(FATAL_ERROR "\n"
|
||||
"No suitable display platform found\n"
|
||||
"Requires x11 to run")
|
||||
message(WARNING "X11 support enabled but not found. This build will not support X11.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_X11)
|
||||
check_lib(XRANDR xrandr Xrandr)
|
||||
if(XRANDR_FOUND)
|
||||
add_definitions(-DHAVE_XRANDR=1)
|
||||
if(ENABLE_EGL)
|
||||
find_package(EGL)
|
||||
if(EGL_FOUND)
|
||||
add_definitions(-DHAVE_EGL=1)
|
||||
message(STATUS "EGL OpenGL interface enabled")
|
||||
else()
|
||||
add_definitions(-DHAVE_XRANDR=0)
|
||||
message(WARNING "EGL support enabled but not found. This build will not support EGL.")
|
||||
endif()
|
||||
|
||||
pkg_check_modules(X11_INPUT REQUIRED xi>=1.5.0)
|
||||
endif()
|
||||
|
||||
if(ENCODE_FRAMEDUMPS)
|
||||
|
@ -482,11 +463,6 @@ if(OPROFILING)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_EGL)
|
||||
message(STATUS "EGL OpenGL interface enabled")
|
||||
add_definitions(-DUSE_EGL=1)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EVDEV)
|
||||
find_package(Libudev REQUIRED)
|
||||
find_package(Libevdev REQUIRED)
|
||||
|
|
|
@ -22,10 +22,10 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/Logging/LogManager.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/Version.h"
|
||||
#include "Common/WindowSystemInfo.h"
|
||||
|
||||
#include "Core/Analytics.h"
|
||||
#include "Core/Boot/Boot.h"
|
||||
|
@ -90,11 +90,6 @@ void Host_Message(HostMessageID id)
|
|||
}
|
||||
}
|
||||
|
||||
void* Host_GetRenderHandle()
|
||||
{
|
||||
return s_surf;
|
||||
}
|
||||
|
||||
void Host_UpdateTitle(const std::string& title)
|
||||
{
|
||||
__android_log_write(ANDROID_LOG_INFO, DOLPHIN_TAG, title.c_str());
|
||||
|
@ -566,7 +561,8 @@ static void Run(const std::string& path, bool first_open,
|
|||
s_have_wm_user_stop = false;
|
||||
std::unique_ptr<BootParameters> boot = BootParameters::GenerateFromFile(path, savestate_path);
|
||||
boot->delete_savestate = delete_savestate;
|
||||
if (BootManager::BootCore(std::move(boot)))
|
||||
WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf);
|
||||
if (BootManager::BootCore(std::move(boot), wsi))
|
||||
{
|
||||
static constexpr int TIMEOUT = 10000;
|
||||
static constexpr int WAIT_STEP = 25;
|
||||
|
|
|
@ -110,17 +110,18 @@ endif()
|
|||
target_sources(common PRIVATE
|
||||
GL/GLUtil.cpp
|
||||
GL/GLExtensions/GLExtensions.cpp
|
||||
GL/GLInterface/GLInterface.cpp
|
||||
GL/GLContext.cpp
|
||||
)
|
||||
|
||||
if(USE_EGL)
|
||||
if(ENABLE_EGL AND EGL_FOUND)
|
||||
target_sources(common PRIVATE GL/GLInterface/EGL.cpp)
|
||||
if(ANDROID)
|
||||
target_sources(common PRIVATE GL/GLInterface/EGLAndroid.cpp)
|
||||
elseif(USE_X11)
|
||||
elseif(ENABLE_X11 AND X11_FOUND)
|
||||
target_sources(common PRIVATE GL/GLInterface/EGLX11.cpp)
|
||||
endif()
|
||||
target_link_libraries(common PUBLIC EGL)
|
||||
target_include_directories(common PRIVATE ${EGL_INCLUDE_DIRS})
|
||||
target_link_libraries(common PUBLIC ${EGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
|
@ -130,18 +131,14 @@ if(WIN32)
|
|||
)
|
||||
elseif(APPLE)
|
||||
target_sources(common PRIVATE GL/GLInterface/AGL.mm)
|
||||
elseif(HAIKU)
|
||||
target_sources(common PRIVATE GL/GLInterface/BGL.cpp)
|
||||
target_link_libraries(common PUBLIC be GL)
|
||||
elseif(USE_X11)
|
||||
if (NOT USE_EGL)
|
||||
target_sources(common PRIVATE GL/GLInterface/GLX.cpp)
|
||||
# GLX has a hard dependency on libGL.
|
||||
# Make sure to link to it if using GLX.
|
||||
target_link_libraries(common PUBLIC ${OPENGL_LIBRARIES})
|
||||
endif()
|
||||
target_sources(common PRIVATE GL/GLInterface/X11_Util.cpp)
|
||||
target_link_libraries(common PUBLIC ${XRANDR_LIBRARIES})
|
||||
elseif(ENABLE_X11 AND X11_FOUND)
|
||||
target_sources(common PRIVATE
|
||||
GL/GLX11Window.cpp
|
||||
GL/GLInterface/GLX.cpp)
|
||||
|
||||
# GLX has a hard dependency on libGL.
|
||||
# Make sure to link to it if using GLX.
|
||||
target_link_libraries(common PUBLIC ${OPENGL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
@ -163,9 +160,6 @@ if(UNIX)
|
|||
if(SYSTEMD_FOUND)
|
||||
target_link_libraries(traversal_server PRIVATE ${SYSTEMD_LIBRARIES})
|
||||
endif()
|
||||
if(HAIKU)
|
||||
target_link_libraries(traversal_server PRIVATE network)
|
||||
endif()
|
||||
elseif(WIN32)
|
||||
target_link_libraries(common PRIVATE "-INCLUDE:enableCompatPatches")
|
||||
endif()
|
||||
|
|
|
@ -121,7 +121,7 @@
|
|||
<ClInclude Include="GL\GLExtensions\NV_depth_buffer_float.h" />
|
||||
<ClInclude Include="GL\GLExtensions\NV_occlusion_query_samples.h" />
|
||||
<ClInclude Include="GL\GLExtensions\NV_primitive_restart.h" />
|
||||
<ClInclude Include="GL\GLInterfaceBase.h" />
|
||||
<ClInclude Include="GL\GLContext.h" />
|
||||
<ClInclude Include="GL\GLInterface\WGL.h" />
|
||||
<ClInclude Include="GL\GLUtil.h" />
|
||||
<ClInclude Include="FloatUtils.h" />
|
||||
|
@ -189,7 +189,7 @@
|
|||
<ClCompile Include="FloatUtils.cpp" />
|
||||
<ClCompile Include="GekkoDisassembler.cpp" />
|
||||
<ClCompile Include="GL\GLExtensions\GLExtensions.cpp" />
|
||||
<ClCompile Include="GL\GLInterface\GLInterface.cpp" />
|
||||
<ClCompile Include="GL\GLContext.cpp" />
|
||||
<ClCompile Include="GL\GLInterface\WGL.cpp" />
|
||||
<ClCompile Include="GL\GLUtil.cpp" />
|
||||
<ClCompile Include="Hash.cpp" />
|
||||
|
@ -255,4 +255,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -243,9 +243,6 @@
|
|||
<ClInclude Include="GL\GLInterface\WGL.h">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GL\GLInterfaceBase.h">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Assert.h" />
|
||||
<ClInclude Include="Analytics.h" />
|
||||
<ClInclude Include="Semaphore.h" />
|
||||
|
@ -275,6 +272,9 @@
|
|||
<ClInclude Include="Debug\MemoryPatches.h">
|
||||
<Filter>Debug</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GL\GLContext.h">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CDUtils.cpp" />
|
||||
|
@ -339,9 +339,6 @@
|
|||
<ClCompile Include="GL\GLInterface\WGL.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GL\GLInterface\GLInterface.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Analytics.cpp" />
|
||||
<ClCompile Include="MD5.cpp" />
|
||||
<ClCompile Include="File.cpp" />
|
||||
|
@ -355,6 +352,9 @@
|
|||
<ClCompile Include="Debug\MemoryPatches.cpp">
|
||||
<Filter>Debug</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GL\GLContext.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
|
@ -362,4 +362,4 @@
|
|||
<ItemGroup>
|
||||
<Natvis Include="BitField.natvis" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "Common/GL/GLInterface/AGL.h"
|
||||
#endif
|
||||
#if defined(WIN32)
|
||||
#include "Common/GL/GLInterface/WGL.h"
|
||||
#endif
|
||||
#if HAVE_X11
|
||||
#include "Common/GL/GLInterface/GLX.h"
|
||||
#endif
|
||||
#if HAVE_EGL
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
#if HAVE_X11
|
||||
#include "Common/GL/GLInterface/EGLX11.h"
|
||||
#endif
|
||||
#if defined(ANDROID)
|
||||
#include "Common/GL/GLInterface/EGLAndroid.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const std::array<std::pair<int, int>, 9> GLContext::s_desktop_opengl_versions = {
|
||||
{{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}}};
|
||||
|
||||
GLContext::~GLContext() = default;
|
||||
|
||||
bool GLContext::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLContext::IsHeadless() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<GLContext> GLContext::CreateSharedContext()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool GLContext::MakeCurrent()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLContext::ClearCurrent()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLContext::Update()
|
||||
{
|
||||
}
|
||||
|
||||
void GLContext::UpdateSurface(void* window_handle)
|
||||
{
|
||||
}
|
||||
|
||||
void GLContext::Swap()
|
||||
{
|
||||
}
|
||||
|
||||
void GLContext::SwapInterval(int interval)
|
||||
{
|
||||
}
|
||||
|
||||
void* GLContext::GetFuncAddress(const std::string& name)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<GLContext> GLContext::Create(const WindowSystemInfo& wsi, bool stereo, bool core,
|
||||
bool prefer_egl, bool prefer_gles)
|
||||
{
|
||||
std::unique_ptr<GLContext> context;
|
||||
#if defined(__APPLE__)
|
||||
if (wsi.type == WindowSystemType::MacOS || wsi.type == WindowSystemType::Headless)
|
||||
context = std::make_unique<GLContextAGL>();
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
if (wsi.type == WindowSystemType::Windows)
|
||||
context = std::make_unique<GLContextWGL>();
|
||||
#endif
|
||||
#if defined(ANDROID)
|
||||
if (wsi.type == WindowSystemType::Android)
|
||||
context = std::make_unique<GLContextEGLAndroid>();
|
||||
#endif
|
||||
#if HAVE_X11
|
||||
if (wsi.type == WindowSystemType::X11)
|
||||
{
|
||||
// GLES 3 is not supported via GLX.
|
||||
const bool use_egl = prefer_egl || prefer_gles;
|
||||
#if defined(HAVE_EGL)
|
||||
if (use_egl)
|
||||
context = std::make_unique<GLContextEGLX11>();
|
||||
else
|
||||
context = std::make_unique<GLContextGLX>();
|
||||
#else
|
||||
context = std::make_unique<GLContextGLX>();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if HAVE_EGL
|
||||
if (wsi.type == WindowSystemType::Headless)
|
||||
context = std::make_unique<GLContextEGL>();
|
||||
#endif
|
||||
|
||||
if (!context)
|
||||
return nullptr;
|
||||
|
||||
// Option to prefer GLES on desktop platforms, useful for testing.
|
||||
if (prefer_gles)
|
||||
context->m_opengl_mode = Mode::OpenGLES;
|
||||
|
||||
if (!context->Initialize(wsi.display_connection, wsi.render_surface, stereo, core))
|
||||
return nullptr;
|
||||
|
||||
return context;
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/WindowSystemInfo.h"
|
||||
|
||||
class GLContext
|
||||
{
|
||||
public:
|
||||
enum class Mode
|
||||
{
|
||||
Detect,
|
||||
OpenGL,
|
||||
OpenGLES
|
||||
};
|
||||
|
||||
virtual ~GLContext();
|
||||
|
||||
Mode GetMode() { return m_opengl_mode; }
|
||||
bool IsGLES() const { return m_opengl_mode == Mode::OpenGLES; }
|
||||
|
||||
u32 GetBackBufferWidth() { return m_backbuffer_width; }
|
||||
u32 GetBackBufferHeight() { return m_backbuffer_height; }
|
||||
|
||||
virtual bool IsHeadless() const;
|
||||
|
||||
virtual std::unique_ptr<GLContext> CreateSharedContext();
|
||||
|
||||
virtual bool MakeCurrent();
|
||||
virtual bool ClearCurrent();
|
||||
|
||||
virtual void Update();
|
||||
virtual void UpdateSurface(void* window_handle);
|
||||
|
||||
virtual void Swap();
|
||||
virtual void SwapInterval(int interval);
|
||||
|
||||
virtual void* GetFuncAddress(const std::string& name);
|
||||
|
||||
// Creates an instance of GLContext specific to the platform we are running on.
|
||||
// If successful, the context is made current on the calling thread.
|
||||
static std::unique_ptr<GLContext> Create(const WindowSystemInfo& wsi, bool stereo = false,
|
||||
bool core = true, bool prefer_egl = false,
|
||||
bool prefer_gles = false);
|
||||
|
||||
protected:
|
||||
virtual bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core);
|
||||
|
||||
Mode m_opengl_mode = Mode::Detect;
|
||||
|
||||
// Window dimensions.
|
||||
u32 m_backbuffer_width = 0;
|
||||
u32 m_backbuffer_height = 0;
|
||||
bool m_is_shared = false;
|
||||
|
||||
// A list of desktop OpenGL versions to attempt to create a context for.
|
||||
// (4.6-3.2, geometry shaders is a minimum requirement since we're using core profile).
|
||||
static const std::array<std::pair<int, int>, 9> s_desktop_opengl_versions;
|
||||
};
|
|
@ -5,8 +5,8 @@
|
|||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/GL/GLExtensions/GLExtensions.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
|
@ -2148,12 +2148,11 @@ const GLFunc gl_function_array[] = {
|
|||
namespace GLExtensions
|
||||
{
|
||||
// Private members and functions
|
||||
static bool _isES;
|
||||
static u32 _GLVersion;
|
||||
static std::unordered_map<std::string, bool> m_extension_list;
|
||||
static u32 s_gl_version;
|
||||
static std::unordered_map<std::string, bool> s_extension_list;
|
||||
|
||||
// Private initialization functions
|
||||
bool InitFunctionPointers();
|
||||
bool InitFunctionPointers(GLContext* context);
|
||||
|
||||
// Initializes the extension list the old way
|
||||
static void InitExtensionList21()
|
||||
|
@ -2163,28 +2162,28 @@ static void InitExtensionList21()
|
|||
std::istringstream buffer(tmp);
|
||||
|
||||
while (buffer >> tmp)
|
||||
m_extension_list[tmp] = true;
|
||||
s_extension_list[tmp] = true;
|
||||
}
|
||||
|
||||
static void InitExtensionList()
|
||||
static void InitExtensionList(GLContext* context)
|
||||
{
|
||||
m_extension_list.clear();
|
||||
if (_isES)
|
||||
s_extension_list.clear();
|
||||
if (context->IsGLES())
|
||||
{
|
||||
switch (_GLVersion)
|
||||
switch (s_gl_version)
|
||||
{
|
||||
default:
|
||||
case 320:
|
||||
m_extension_list["VERSION_GLES_3_2"] = true;
|
||||
s_extension_list["VERSION_GLES_3_2"] = true;
|
||||
case 310:
|
||||
m_extension_list["VERSION_GLES_3_1"] = true;
|
||||
s_extension_list["VERSION_GLES_3_1"] = true;
|
||||
case 300:
|
||||
m_extension_list["VERSION_GLES_3"] = true;
|
||||
s_extension_list["VERSION_GLES_3"] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// We always have ES 2.0
|
||||
m_extension_list["VERSION_GLES_2"] = true;
|
||||
s_extension_list["VERSION_GLES_2"] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2194,7 +2193,7 @@ static void InitExtensionList()
|
|||
// When an extension got merged in to core, the naming may have changed
|
||||
|
||||
// This has intentional fall through
|
||||
switch (_GLVersion)
|
||||
switch (s_gl_version)
|
||||
{
|
||||
default:
|
||||
case 450:
|
||||
|
@ -2213,7 +2212,7 @@ static void InitExtensionList()
|
|||
"VERSION_4_5",
|
||||
};
|
||||
for (auto it : gl450exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 440:
|
||||
{
|
||||
|
@ -2229,7 +2228,7 @@ static void InitExtensionList()
|
|||
"VERSION_4_4",
|
||||
};
|
||||
for (auto it : gl440exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 430:
|
||||
{
|
||||
|
@ -2257,7 +2256,7 @@ static void InitExtensionList()
|
|||
"VERSION_4_3",
|
||||
};
|
||||
for (auto it : gl430exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 420:
|
||||
{
|
||||
|
@ -2277,7 +2276,7 @@ static void InitExtensionList()
|
|||
"VERSION_4_2",
|
||||
};
|
||||
for (auto it : gl420exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 410:
|
||||
{
|
||||
|
@ -2291,7 +2290,7 @@ static void InitExtensionList()
|
|||
"VERSION_4_1",
|
||||
};
|
||||
for (auto it : gl410exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 400:
|
||||
{
|
||||
|
@ -2311,7 +2310,7 @@ static void InitExtensionList()
|
|||
"VERSION_4_0",
|
||||
};
|
||||
for (auto it : gl400exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 330:
|
||||
{
|
||||
|
@ -2329,7 +2328,7 @@ static void InitExtensionList()
|
|||
"VERSION_3_3",
|
||||
};
|
||||
for (auto it : gl330exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 320:
|
||||
{
|
||||
|
@ -2346,7 +2345,7 @@ static void InitExtensionList()
|
|||
"VERSION_3_2",
|
||||
};
|
||||
for (auto it : gl320exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 310:
|
||||
{
|
||||
|
@ -2361,7 +2360,7 @@ static void InitExtensionList()
|
|||
"VERSION_3_1",
|
||||
};
|
||||
for (auto it : gl310exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 300:
|
||||
{
|
||||
|
@ -2392,7 +2391,7 @@ static void InitExtensionList()
|
|||
"VERSION_3_0",
|
||||
};
|
||||
for (auto it : gl300exts)
|
||||
m_extension_list[it] = true;
|
||||
s_extension_list[it] = true;
|
||||
}
|
||||
case 210:
|
||||
case 200:
|
||||
|
@ -2406,10 +2405,10 @@ static void InitExtensionList()
|
|||
break;
|
||||
}
|
||||
// So we can easily determine if we are running dekstop GL
|
||||
m_extension_list["VERSION_GL"] = true;
|
||||
s_extension_list["VERSION_GL"] = true;
|
||||
}
|
||||
|
||||
if (_GLVersion < 300)
|
||||
if (s_gl_version < 300)
|
||||
{
|
||||
InitExtensionList21();
|
||||
return;
|
||||
|
@ -2417,7 +2416,7 @@ static void InitExtensionList()
|
|||
GLint NumExtension = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &NumExtension);
|
||||
for (GLint i = 0; i < NumExtension; ++i)
|
||||
m_extension_list[std::string((const char*)glGetStringi(GL_EXTENSIONS, i))] = true;
|
||||
s_extension_list[std::string((const char*)glGetStringi(GL_EXTENSIONS, i))] = true;
|
||||
}
|
||||
static void InitVersion()
|
||||
{
|
||||
|
@ -2425,14 +2424,14 @@ static void InitVersion()
|
|||
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||
if (glGetError() == GL_NO_ERROR)
|
||||
_GLVersion = major * 100 + minor * 10;
|
||||
s_gl_version = major * 100 + minor * 10;
|
||||
else
|
||||
_GLVersion = 210;
|
||||
s_gl_version = 210;
|
||||
}
|
||||
|
||||
static void* GetFuncAddress(const std::string& name, void** func)
|
||||
static void* GetFuncAddress(GLContext* context, const std::string& name, void** func)
|
||||
{
|
||||
*func = GLInterface->GetFuncAddress(name);
|
||||
*func = context->GetFuncAddress(name);
|
||||
if (*func == nullptr)
|
||||
{
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
|
@ -2448,37 +2447,36 @@ static void* GetFuncAddress(const std::string& name, void** func)
|
|||
// Public members
|
||||
u32 Version()
|
||||
{
|
||||
return _GLVersion;
|
||||
return s_gl_version;
|
||||
}
|
||||
bool Supports(const std::string& name)
|
||||
{
|
||||
return m_extension_list[name];
|
||||
return s_extension_list[name];
|
||||
}
|
||||
|
||||
bool Init()
|
||||
bool Init(GLContext* context)
|
||||
{
|
||||
_isES = GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL;
|
||||
|
||||
// Grab a few functions for initial checking
|
||||
// We need them to grab the extension list
|
||||
// Also to check if there is an error grabbing the version
|
||||
if (GetFuncAddress("glGetIntegerv", (void**)&glGetIntegerv) == nullptr)
|
||||
if (GetFuncAddress(context, "glGetIntegerv", (void**)&glGetIntegerv) == nullptr)
|
||||
return false;
|
||||
if (GetFuncAddress("glGetString", (void**)&glGetString) == nullptr)
|
||||
if (GetFuncAddress(context, "glGetString", (void**)&glGetString) == nullptr)
|
||||
return false;
|
||||
if (GetFuncAddress("glGetError", (void**)&glGetError) == nullptr)
|
||||
if (GetFuncAddress(context, "glGetError", (void**)&glGetError) == nullptr)
|
||||
return false;
|
||||
|
||||
InitVersion();
|
||||
|
||||
// We need to use glGetStringi to get the extension list
|
||||
// if we are using GLES3 or a GL version greater than 2.1
|
||||
if (_GLVersion > 210 && GetFuncAddress("glGetStringi", (void**)&glGetStringi) == nullptr)
|
||||
if (s_gl_version > 210 &&
|
||||
GetFuncAddress(context, "glGetStringi", (void**)&glGetStringi) == nullptr)
|
||||
return false;
|
||||
|
||||
InitExtensionList();
|
||||
InitExtensionList(context);
|
||||
|
||||
return InitFunctionPointers();
|
||||
return InitFunctionPointers(context);
|
||||
}
|
||||
|
||||
// Private initialization functions
|
||||
|
@ -2491,20 +2489,20 @@ static bool HasFeatures(const std::string& extensions)
|
|||
while (buffer >> tmp)
|
||||
{
|
||||
if (tmp[0] == '!')
|
||||
result &= !m_extension_list[tmp.erase(0, 1)];
|
||||
result &= !s_extension_list[tmp.erase(0, 1)];
|
||||
else if (tmp[0] == '|')
|
||||
result |= m_extension_list[tmp.erase(0, 1)];
|
||||
result |= s_extension_list[tmp.erase(0, 1)];
|
||||
else
|
||||
result &= m_extension_list[tmp];
|
||||
result &= s_extension_list[tmp];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
bool InitFunctionPointers()
|
||||
bool InitFunctionPointers(GLContext* context)
|
||||
{
|
||||
bool result = true;
|
||||
for (const auto& it : gl_function_array)
|
||||
if (HasFeatures(it.requirements))
|
||||
result &= !!GetFuncAddress(it.function_name, it.function_ptr);
|
||||
result &= !!GetFuncAddress(context, it.function_name, it.function_ptr);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace GLExtensions
|
||||
|
|
|
@ -54,10 +54,12 @@
|
|||
#include "Common/GL/GLExtensions/gl_4_4.h"
|
||||
#include "Common/GL/GLExtensions/gl_4_5.h"
|
||||
|
||||
class GLContext;
|
||||
|
||||
namespace GLExtensions
|
||||
{
|
||||
// Initializes the interface
|
||||
bool Init();
|
||||
bool Init(GLContext* context);
|
||||
|
||||
// Function for checking if the hardware supports an extension
|
||||
// example: if (GLExtensions::Supports("GL_ARB_multi_map"))
|
||||
|
@ -65,4 +67,4 @@ bool Supports(const std::string& name);
|
|||
|
||||
// Returns OpenGL version in format 430
|
||||
u32 Version();
|
||||
}
|
||||
} // namespace GLExtensions
|
||||
|
|
|
@ -12,22 +12,28 @@ struct NSOpenGLPixelFormat;
|
|||
struct NSView;
|
||||
#endif
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
class cInterfaceAGL : public cInterfaceBase
|
||||
class GLContextAGL final : public GLContext
|
||||
{
|
||||
public:
|
||||
void Swap() override;
|
||||
bool Create(void* window_handle, bool stereo, bool core) override;
|
||||
bool Create(cInterfaceBase* main_context) override;
|
||||
~GLContextAGL() override;
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
std::unique_ptr<GLContext> CreateSharedContext() override;
|
||||
|
||||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
void Shutdown() override;
|
||||
void Update() override;
|
||||
void SwapInterval(int interval) override;
|
||||
std::unique_ptr<cInterfaceBase> CreateSharedContext() override;
|
||||
|
||||
private:
|
||||
void Update() override;
|
||||
|
||||
void Swap() override;
|
||||
void SwapInterval(int interval) override;
|
||||
|
||||
protected:
|
||||
bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;
|
||||
|
||||
NSView* m_view = nullptr;
|
||||
NSOpenGLContext* m_context = nullptr;
|
||||
NSOpenGLPixelFormat* m_pixel_format = nullptr;
|
||||
|
|
|
@ -10,16 +10,15 @@ static bool UpdateCachedDimensions(NSView* view, u32* width, u32* height)
|
|||
NSWindow* window = [view window];
|
||||
NSSize size = [view frame].size;
|
||||
|
||||
float scale = [window backingScaleFactor];
|
||||
size.width *= scale;
|
||||
size.height *= scale;
|
||||
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 == size.width && *height == size.height)
|
||||
if (*width == new_width && *height == new_height)
|
||||
return false;
|
||||
|
||||
*width = size.width;
|
||||
*height = size.height;
|
||||
|
||||
*width = new_width;
|
||||
*height = new_height;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -44,14 +43,33 @@ static bool AttachContextToView(NSOpenGLContext* context, NSView* view, u32* wid
|
|||
return true;
|
||||
}
|
||||
|
||||
void cInterfaceAGL::Swap()
|
||||
GLContextAGL::~GLContextAGL()
|
||||
{
|
||||
if ([NSOpenGLContext currentContext] == m_context)
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
|
||||
if (m_context)
|
||||
{
|
||||
[m_context clearDrawable];
|
||||
[m_context release];
|
||||
}
|
||||
if (m_pixel_format)
|
||||
[m_pixel_format release];
|
||||
}
|
||||
|
||||
bool GLContextAGL::IsHeadless() const
|
||||
{
|
||||
return !m_view;
|
||||
}
|
||||
|
||||
void GLContextAGL::Swap()
|
||||
{
|
||||
[m_context flushBuffer];
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceAGL::Create(void* window_handle, bool stereo, bool core)
|
||||
bool GLContextAGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
|
||||
{
|
||||
NSOpenGLPixelFormatAttribute attr[] = {
|
||||
NSOpenGLPFADoubleBuffer,
|
||||
|
@ -78,65 +96,54 @@ bool cInterfaceAGL::Create(void* window_handle, bool stereo, bool core)
|
|||
return true;
|
||||
|
||||
m_view = static_cast<NSView*>(window_handle);
|
||||
return AttachContextToView(m_context, m_view, &s_backbuffer_width, &s_backbuffer_height);
|
||||
}
|
||||
|
||||
bool cInterfaceAGL::Create(cInterfaceBase* main_context)
|
||||
{
|
||||
cInterfaceAGL* agl_context = static_cast<cInterfaceAGL*>(main_context);
|
||||
NSOpenGLPixelFormat* pixel_format = agl_context->m_pixel_format;
|
||||
NSOpenGLContext* share_context = agl_context->m_context;
|
||||
|
||||
m_context = [[NSOpenGLContext alloc] initWithFormat:pixel_format shareContext:share_context];
|
||||
if (m_context == nil)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "failed to create shared context");
|
||||
m_opengl_mode = Mode::OpenGL;
|
||||
if (!AttachContextToView(m_context, m_view, &m_backbuffer_width, &m_backbuffer_height))
|
||||
return false;
|
||||
}
|
||||
|
||||
[m_context makeCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<cInterfaceBase> cInterfaceAGL::CreateSharedContext()
|
||||
std::unique_ptr<GLContext> GLContextAGL::CreateSharedContext()
|
||||
{
|
||||
std::unique_ptr<cInterfaceBase> context = std::make_unique<cInterfaceAGL>();
|
||||
if (!context->Create(this))
|
||||
NSOpenGLContext* new_agl_context =
|
||||
[[NSOpenGLContext alloc] initWithFormat:m_pixel_format shareContext:m_context];
|
||||
if (new_agl_context == nil)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "failed to create shared context");
|
||||
return nullptr;
|
||||
return context;
|
||||
}
|
||||
|
||||
std::unique_ptr<GLContextAGL> new_context = std::make_unique<GLContextAGL>();
|
||||
new_context->m_context = new_agl_context;
|
||||
new_context->m_pixel_format = m_pixel_format;
|
||||
[new_context->m_pixel_format retain];
|
||||
new_context->m_is_shared = true;
|
||||
return new_context;
|
||||
}
|
||||
|
||||
bool cInterfaceAGL::MakeCurrent()
|
||||
bool GLContextAGL::MakeCurrent()
|
||||
{
|
||||
[m_context makeCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceAGL::ClearCurrent()
|
||||
bool GLContextAGL::ClearCurrent()
|
||||
{
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
return true;
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceAGL::Shutdown()
|
||||
{
|
||||
[m_context clearDrawable];
|
||||
[m_context release];
|
||||
m_context = nil;
|
||||
[m_pixel_format release];
|
||||
m_pixel_format = nil;
|
||||
}
|
||||
|
||||
void cInterfaceAGL::Update()
|
||||
void GLContextAGL::Update()
|
||||
{
|
||||
if (!m_view)
|
||||
return;
|
||||
|
||||
if (UpdateCachedDimensions(m_view, &s_backbuffer_width, &s_backbuffer_height))
|
||||
if (UpdateCachedDimensions(m_view, &m_backbuffer_width, &m_backbuffer_height))
|
||||
[m_context update];
|
||||
}
|
||||
|
||||
void cInterfaceAGL::SwapInterval(int interval)
|
||||
void GLContextAGL::SwapInterval(int interval)
|
||||
{
|
||||
[m_context setValues:static_cast<GLint*>(&interval) forParameter:NSOpenGLCPSwapInterval];
|
||||
}
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/GL/GLInterface/BGL.h"
|
||||
|
||||
#include <GLView.h>
|
||||
#include <Size.h>
|
||||
#include <Window.h>
|
||||
|
||||
void cInterfaceBGL::Swap()
|
||||
{
|
||||
m_gl->SwapBuffers();
|
||||
}
|
||||
|
||||
bool cInterfaceBGL::Create(void* window_handle, bool stereo, bool core)
|
||||
{
|
||||
m_window = static_cast<BWindow*>(window_handle);
|
||||
|
||||
m_gl = new BGLView(m_window->Bounds(), "cInterfaceBGL", B_FOLLOW_ALL_SIDES, 0,
|
||||
BGL_RGB | BGL_DOUBLE | BGL_ALPHA);
|
||||
m_window->AddChild(m_gl);
|
||||
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
|
||||
|
||||
// Control m_window size and picture scaling
|
||||
BRect size = m_gl->Frame();
|
||||
s_backbuffer_width = size.IntegerWidth();
|
||||
s_backbuffer_height = size.IntegerHeight();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceBGL::MakeCurrent()
|
||||
{
|
||||
m_gl->LockGL();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceBGL::ClearCurrent()
|
||||
{
|
||||
m_gl->UnlockGL();
|
||||
return true;
|
||||
}
|
||||
|
||||
void cInterfaceBGL::Shutdown()
|
||||
{
|
||||
// We don't need to delete m_gl, it's owned by the BWindow.
|
||||
m_gl = nullptr;
|
||||
}
|
||||
|
||||
void cInterfaceBGL::Update()
|
||||
{
|
||||
BRect size = m_gl->Frame();
|
||||
|
||||
if (s_backbuffer_width == size.IntegerWidth() && s_backbuffer_height == size.IntegerHeight())
|
||||
return;
|
||||
|
||||
s_backbuffer_width = size.IntegerWidth();
|
||||
s_backbuffer_height = size.IntegerHeight();
|
||||
}
|
||||
|
||||
void cInterfaceBGL::SwapInterval(int interval)
|
||||
{
|
||||
}
|
||||
|
||||
void* cInterfaceBGL::GetFuncAddress(const std::string& name)
|
||||
{
|
||||
return m_gl->GetGLProcAddress(name.c_str());
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
|
||||
class BWindow;
|
||||
class BGLView;
|
||||
|
||||
class cInterfaceBGL final : public cInterfaceBase
|
||||
{
|
||||
public:
|
||||
void Swap() override;
|
||||
void* GetFuncAddress(const std::string& name) override;
|
||||
bool Create(void* window_handle, bool stereo, bool core) override;
|
||||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
void Shutdown() override;
|
||||
void Update() override;
|
||||
void SwapInterval(int interval) override;
|
||||
|
||||
private:
|
||||
BWindow* m_window;
|
||||
BGLView* m_gl;
|
||||
};
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
|
||||
#ifndef EGL_KHR_create_context
|
||||
#define EGL_KHR_create_context 1
|
||||
|
@ -28,35 +27,37 @@
|
|||
#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
|
||||
#endif /* EGL_KHR_create_context */
|
||||
|
||||
// Show the current FPS
|
||||
void cInterfaceEGL::Swap()
|
||||
GLContextEGL::~GLContextEGL()
|
||||
{
|
||||
if (egl_surf != EGL_NO_SURFACE)
|
||||
eglSwapBuffers(egl_dpy, egl_surf);
|
||||
}
|
||||
void cInterfaceEGL::SwapInterval(int Interval)
|
||||
{
|
||||
eglSwapInterval(egl_dpy, Interval);
|
||||
DestroyWindowSurface();
|
||||
DestroyContext();
|
||||
}
|
||||
|
||||
void* cInterfaceEGL::GetFuncAddress(const std::string& name)
|
||||
bool GLContextEGL::IsHeadless() const
|
||||
{
|
||||
return m_host_window == nullptr;
|
||||
}
|
||||
|
||||
void GLContextEGL::Swap()
|
||||
{
|
||||
if (m_egl_surface != EGL_NO_SURFACE)
|
||||
eglSwapBuffers(m_egl_display, m_egl_surface);
|
||||
}
|
||||
void GLContextEGL::SwapInterval(int interval)
|
||||
{
|
||||
eglSwapInterval(m_egl_display, interval);
|
||||
}
|
||||
|
||||
void* GLContextEGL::GetFuncAddress(const std::string& name)
|
||||
{
|
||||
return (void*)eglGetProcAddress(name.c_str());
|
||||
}
|
||||
|
||||
void cInterfaceEGL::DetectMode()
|
||||
void GLContextEGL::DetectMode(bool has_handle)
|
||||
{
|
||||
if (s_opengl_mode != GLInterfaceMode::MODE_DETECT)
|
||||
return;
|
||||
bool preferGLES = Config::Get(Config::GFX_PREFER_GLES);
|
||||
|
||||
EGLint num_configs;
|
||||
bool supportsGL = false, supportsGLES2 = false, supportsGLES3 = false;
|
||||
std::array<int, 3> renderable_types{{
|
||||
EGL_OPENGL_BIT,
|
||||
(1 << 6), /* EGL_OPENGL_ES3_BIT_KHR */
|
||||
EGL_OPENGL_ES2_BIT,
|
||||
}};
|
||||
bool supportsGL = false, supportsGLES3 = false;
|
||||
std::array<int, 3> renderable_types{{EGL_OPENGL_BIT, EGL_OPENGL_ES3_BIT_KHR}};
|
||||
|
||||
for (auto renderable_type : renderable_types)
|
||||
{
|
||||
|
@ -71,11 +72,11 @@ void cInterfaceEGL::DetectMode()
|
|||
EGL_RENDERABLE_TYPE,
|
||||
renderable_type,
|
||||
EGL_SURFACE_TYPE,
|
||||
m_has_handle ? EGL_WINDOW_BIT : 0,
|
||||
has_handle ? EGL_WINDOW_BIT : 0,
|
||||
EGL_NONE};
|
||||
|
||||
// Get how many configs there are
|
||||
if (!eglChooseConfig(egl_dpy, attribs, nullptr, 0, &num_configs))
|
||||
if (!eglChooseConfig(m_egl_display, attribs, nullptr, 0, &num_configs))
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config");
|
||||
continue;
|
||||
|
@ -84,7 +85,7 @@ void cInterfaceEGL::DetectMode()
|
|||
EGLConfig* config = new EGLConfig[num_configs];
|
||||
|
||||
// Get all the configurations
|
||||
if (!eglChooseConfig(egl_dpy, attribs, config, num_configs, &num_configs))
|
||||
if (!eglChooseConfig(m_egl_display, attribs, config, num_configs, &num_configs))
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config");
|
||||
delete[] config;
|
||||
|
@ -95,80 +96,68 @@ void cInterfaceEGL::DetectMode()
|
|||
{
|
||||
EGLint attribVal;
|
||||
bool ret;
|
||||
ret = eglGetConfigAttrib(egl_dpy, config[i], EGL_RENDERABLE_TYPE, &attribVal);
|
||||
ret = eglGetConfigAttrib(m_egl_display, config[i], EGL_RENDERABLE_TYPE, &attribVal);
|
||||
if (ret)
|
||||
{
|
||||
if (attribVal & EGL_OPENGL_BIT)
|
||||
supportsGL = true;
|
||||
if (attribVal & (1 << 6)) /* EGL_OPENGL_ES3_BIT_KHR */
|
||||
if (attribVal & EGL_OPENGL_ES3_BIT_KHR)
|
||||
supportsGLES3 = true;
|
||||
if (attribVal & EGL_OPENGL_ES2_BIT)
|
||||
supportsGLES2 = true;
|
||||
}
|
||||
}
|
||||
delete[] config;
|
||||
}
|
||||
|
||||
if (preferGLES)
|
||||
{
|
||||
if (supportsGLES3)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3;
|
||||
else if (supportsGLES2)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2;
|
||||
else if (supportsGL)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (supportsGL)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
|
||||
else if (supportsGLES3)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES3;
|
||||
else if (supportsGLES2)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGLES2;
|
||||
}
|
||||
|
||||
if (s_opengl_mode == GLInterfaceMode::MODE_OPENGL)
|
||||
if (supportsGL)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Using OpenGL");
|
||||
m_opengl_mode = Mode::OpenGL;
|
||||
}
|
||||
else if (s_opengl_mode == GLInterfaceMode::MODE_OPENGLES3)
|
||||
else if (supportsGLES3)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Using OpenGL|ES 3");
|
||||
INFO_LOG(VIDEO, "Using OpenGL|ES");
|
||||
m_opengl_mode = Mode::OpenGLES;
|
||||
}
|
||||
else if (s_opengl_mode == GLInterfaceMode::MODE_OPENGLES2)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Using OpenGL|ES 2");
|
||||
}
|
||||
else if (s_opengl_mode == GLInterfaceMode::MODE_DETECT)
|
||||
else
|
||||
{
|
||||
// Errored before we found a mode
|
||||
ERROR_LOG(VIDEO, "Error: Failed to detect OpenGL flavour, falling back to OpenGL");
|
||||
// This will fail to create a context, as it'll try to use the same attribs we just failed to
|
||||
// find a matching config with
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
|
||||
m_opengl_mode = Mode::OpenGL;
|
||||
}
|
||||
}
|
||||
|
||||
EGLDisplay GLContextEGL::OpenEGLDisplay()
|
||||
{
|
||||
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
EGLNativeWindowType GLContextEGL::GetEGLNativeWindow(EGLConfig config)
|
||||
{
|
||||
return reinterpret_cast<EGLNativeWindowType>(EGL_DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core)
|
||||
bool GLContextEGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
|
||||
{
|
||||
const bool has_handle = !!window_handle;
|
||||
|
||||
EGLint egl_major, egl_minor;
|
||||
bool supports_core_profile = false;
|
||||
|
||||
egl_dpy = OpenDisplay();
|
||||
m_host_window = (EGLNativeWindowType)window_handle;
|
||||
m_has_handle = !!window_handle;
|
||||
m_core = core;
|
||||
m_host_display = display_handle;
|
||||
m_host_window = window_handle;
|
||||
m_egl_display = OpenEGLDisplay();
|
||||
|
||||
if (!egl_dpy)
|
||||
if (!m_egl_display)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: eglGetDisplay() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eglInitialize(egl_dpy, &egl_major, &egl_minor))
|
||||
if (!eglInitialize(m_egl_display, &egl_major, &egl_minor))
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: eglInitialize() failed");
|
||||
return false;
|
||||
|
@ -177,12 +166,13 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core)
|
|||
/* Detection code */
|
||||
EGLint num_configs;
|
||||
|
||||
DetectMode();
|
||||
if (m_opengl_mode == Mode::Detect)
|
||||
DetectMode(has_handle);
|
||||
|
||||
// attributes for a visual in RGBA format with at least
|
||||
// 8 bits per color
|
||||
int attribs[] = {EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_ES2_BIT,
|
||||
0,
|
||||
EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
|
@ -190,43 +180,38 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core)
|
|||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_SURFACE_TYPE,
|
||||
m_has_handle ? EGL_WINDOW_BIT : 0,
|
||||
has_handle ? EGL_WINDOW_BIT : 0,
|
||||
EGL_NONE};
|
||||
|
||||
std::vector<EGLint> ctx_attribs;
|
||||
switch (s_opengl_mode)
|
||||
switch (m_opengl_mode)
|
||||
{
|
||||
case GLInterfaceMode::MODE_OPENGL:
|
||||
case Mode::OpenGL:
|
||||
attribs[1] = EGL_OPENGL_BIT;
|
||||
ctx_attribs = {EGL_NONE};
|
||||
break;
|
||||
case GLInterfaceMode::MODE_OPENGLES2:
|
||||
attribs[1] = EGL_OPENGL_ES2_BIT;
|
||||
ctx_attribs = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
|
||||
break;
|
||||
case GLInterfaceMode::MODE_OPENGLES3:
|
||||
attribs[1] = (1 << 6); /* EGL_OPENGL_ES3_BIT_KHR */
|
||||
case Mode::OpenGLES:
|
||||
attribs[1] = EGL_OPENGL_ES3_BIT_KHR;
|
||||
ctx_attribs = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(VIDEO, "Unknown opengl mode set");
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!eglChooseConfig(egl_dpy, attribs, &m_config, 1, &num_configs))
|
||||
if (!eglChooseConfig(m_egl_display, attribs, &m_config, 1, &num_configs))
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: couldn't get an EGL visual config");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_opengl_mode == GLInterfaceMode::MODE_OPENGL)
|
||||
if (m_opengl_mode == Mode::OpenGL)
|
||||
eglBindAPI(EGL_OPENGL_API);
|
||||
else
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
std::string tmp;
|
||||
std::istringstream buffer(eglQueryString(egl_dpy, EGL_EXTENSIONS));
|
||||
std::istringstream buffer(eglQueryString(m_egl_display, EGL_EXTENSIONS));
|
||||
while (buffer >> tmp)
|
||||
{
|
||||
if (tmp == "EGL_KHR_surfaceless_context")
|
||||
|
@ -235,19 +220,9 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core)
|
|||
supports_core_profile = true;
|
||||
}
|
||||
|
||||
if (supports_core_profile && core && s_opengl_mode == GLInterfaceMode::MODE_OPENGL)
|
||||
if (supports_core_profile && core && m_opengl_mode == Mode::OpenGL)
|
||||
{
|
||||
std::array<std::pair<int, int>, 7> versions_to_try = {{
|
||||
{4, 5},
|
||||
{4, 4},
|
||||
{4, 3},
|
||||
{4, 2},
|
||||
{4, 1},
|
||||
{4, 0},
|
||||
{3, 3},
|
||||
}};
|
||||
|
||||
for (const auto& version : versions_to_try)
|
||||
for (const auto& version : s_desktop_opengl_versions)
|
||||
{
|
||||
std::vector<EGLint> core_attribs = {EGL_CONTEXT_MAJOR_VERSION_KHR,
|
||||
version.first,
|
||||
|
@ -259,8 +234,8 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core)
|
|||
EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
|
||||
EGL_NONE};
|
||||
|
||||
egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &core_attribs[0]);
|
||||
if (egl_ctx)
|
||||
m_egl_context = eglCreateContext(m_egl_display, m_config, EGL_NO_CONTEXT, &core_attribs[0]);
|
||||
if (m_egl_context)
|
||||
{
|
||||
m_attribs = std::move(core_attribs);
|
||||
break;
|
||||
|
@ -268,14 +243,13 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core)
|
|||
}
|
||||
}
|
||||
|
||||
if (!egl_ctx)
|
||||
if (!m_egl_context)
|
||||
{
|
||||
m_core = false;
|
||||
egl_ctx = eglCreateContext(egl_dpy, m_config, EGL_NO_CONTEXT, &ctx_attribs[0]);
|
||||
m_egl_context = eglCreateContext(m_egl_display, m_config, EGL_NO_CONTEXT, &ctx_attribs[0]);
|
||||
m_attribs = std::move(ctx_attribs);
|
||||
}
|
||||
|
||||
if (!egl_ctx)
|
||||
if (!m_egl_context)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: eglCreateContext failed");
|
||||
return false;
|
||||
|
@ -286,56 +260,45 @@ bool cInterfaceEGL::Create(void* window_handle, bool stereo, bool core)
|
|||
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x", eglGetError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return MakeCurrent();
|
||||
}
|
||||
|
||||
std::unique_ptr<cInterfaceBase> cInterfaceEGL::CreateSharedContext()
|
||||
std::unique_ptr<GLContext> GLContextEGL::CreateSharedContext()
|
||||
{
|
||||
std::unique_ptr<cInterfaceBase> context = std::make_unique<cInterfaceEGL>();
|
||||
if (!context->Create(this))
|
||||
return nullptr;
|
||||
return context;
|
||||
}
|
||||
|
||||
bool cInterfaceEGL::Create(cInterfaceBase* main_context)
|
||||
{
|
||||
cInterfaceEGL* egl_context = static_cast<cInterfaceEGL*>(main_context);
|
||||
|
||||
egl_dpy = egl_context->egl_dpy;
|
||||
m_core = egl_context->m_core;
|
||||
m_config = egl_context->m_config;
|
||||
m_supports_surfaceless = egl_context->m_supports_surfaceless;
|
||||
m_is_shared = true;
|
||||
m_has_handle = false;
|
||||
|
||||
if (egl_context->GetMode() == GLInterfaceMode::MODE_OPENGL)
|
||||
eglBindAPI(EGL_OPENGL_API);
|
||||
else
|
||||
eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
egl_ctx =
|
||||
eglCreateContext(egl_dpy, m_config, egl_context->egl_ctx, egl_context->m_attribs.data());
|
||||
if (!egl_ctx)
|
||||
eglBindAPI(m_opengl_mode == Mode::OpenGL ? EGL_OPENGL_API : EGL_OPENGL_ES_API);
|
||||
EGLContext new_egl_context =
|
||||
eglCreateContext(m_egl_display, m_config, m_egl_context, m_attribs.data());
|
||||
if (!new_egl_context)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: eglCreateContext failed 0x%04x", eglGetError());
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!CreateWindowSurface())
|
||||
std::unique_ptr<GLContextEGL> new_context = std::make_unique<GLContextEGL>();
|
||||
new_context->m_opengl_mode = m_opengl_mode;
|
||||
new_context->m_egl_context = new_egl_context;
|
||||
new_context->m_host_display = m_host_display;
|
||||
new_context->m_egl_display = m_egl_display;
|
||||
new_context->m_config = m_config;
|
||||
new_context->m_supports_surfaceless = m_supports_surfaceless;
|
||||
new_context->m_is_shared = true;
|
||||
if (!new_context->CreateWindowSurface())
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed 0x%04x", eglGetError());
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
return true;
|
||||
|
||||
return new_context;
|
||||
}
|
||||
|
||||
bool cInterfaceEGL::CreateWindowSurface()
|
||||
bool GLContextEGL::CreateWindowSurface()
|
||||
{
|
||||
if (m_has_handle)
|
||||
if (m_host_window)
|
||||
{
|
||||
EGLNativeWindowType native_window = InitializePlatform(m_host_window, m_config);
|
||||
egl_surf = eglCreateWindowSurface(egl_dpy, m_config, native_window, nullptr);
|
||||
if (!egl_surf)
|
||||
EGLNativeWindowType native_window = GetEGLNativeWindow(m_config);
|
||||
m_egl_surface = eglCreateWindowSurface(m_egl_display, m_config, native_window, nullptr);
|
||||
if (!m_egl_surface)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: eglCreateWindowSurface failed");
|
||||
return false;
|
||||
|
@ -346,8 +309,8 @@ bool cInterfaceEGL::CreateWindowSurface()
|
|||
EGLint attrib_list[] = {
|
||||
EGL_NONE,
|
||||
};
|
||||
egl_surf = eglCreatePbufferSurface(egl_dpy, m_config, attrib_list);
|
||||
if (!egl_surf)
|
||||
m_egl_surface = eglCreatePbufferSurface(m_egl_display, m_config, attrib_list);
|
||||
if (!m_egl_surface)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Error: eglCreatePbufferSurface failed");
|
||||
return false;
|
||||
|
@ -355,56 +318,54 @@ bool cInterfaceEGL::CreateWindowSurface()
|
|||
}
|
||||
else
|
||||
{
|
||||
egl_surf = EGL_NO_SURFACE;
|
||||
m_egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cInterfaceEGL::DestroyWindowSurface()
|
||||
void GLContextEGL::DestroyWindowSurface()
|
||||
{
|
||||
if (egl_surf != EGL_NO_SURFACE && !eglDestroySurface(egl_dpy, egl_surf))
|
||||
if (m_egl_surface == EGL_NO_SURFACE)
|
||||
return;
|
||||
|
||||
if (eglGetCurrentSurface(EGL_DRAW) == m_egl_surface)
|
||||
eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (!eglDestroySurface(m_egl_display, m_egl_surface))
|
||||
NOTICE_LOG(VIDEO, "Could not destroy window surface.");
|
||||
egl_surf = EGL_NO_SURFACE;
|
||||
m_egl_surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
bool cInterfaceEGL::MakeCurrent()
|
||||
bool GLContextEGL::MakeCurrent()
|
||||
{
|
||||
return eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx);
|
||||
return eglMakeCurrent(m_egl_display, m_egl_surface, m_egl_surface, m_egl_context);
|
||||
}
|
||||
|
||||
void cInterfaceEGL::UpdateHandle(void* window_handle)
|
||||
{
|
||||
m_host_window = (EGLNativeWindowType)window_handle;
|
||||
m_has_handle = !!window_handle;
|
||||
}
|
||||
|
||||
void cInterfaceEGL::UpdateSurface()
|
||||
void GLContextEGL::UpdateSurface(void* window_handle)
|
||||
{
|
||||
m_host_window = window_handle;
|
||||
ClearCurrent();
|
||||
DestroyWindowSurface();
|
||||
CreateWindowSurface();
|
||||
MakeCurrent();
|
||||
}
|
||||
|
||||
bool cInterfaceEGL::ClearCurrent()
|
||||
bool GLContextEGL::ClearCurrent()
|
||||
{
|
||||
return eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
return eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceEGL::Shutdown()
|
||||
void GLContextEGL::DestroyContext()
|
||||
{
|
||||
ShutdownPlatform();
|
||||
if (egl_ctx)
|
||||
{
|
||||
if (!eglMakeCurrent(egl_dpy, egl_surf, egl_surf, egl_ctx))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
eglMakeCurrent(egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (!eglDestroyContext(egl_dpy, egl_ctx))
|
||||
NOTICE_LOG(VIDEO, "Could not destroy drawing context.");
|
||||
DestroyWindowSurface();
|
||||
if (!m_is_shared && !eglTerminate(egl_dpy))
|
||||
NOTICE_LOG(VIDEO, "Could not destroy display connection.");
|
||||
egl_ctx = nullptr;
|
||||
}
|
||||
if (!m_egl_context)
|
||||
return;
|
||||
|
||||
if (eglGetCurrentContext() == m_egl_context)
|
||||
eglMakeCurrent(m_egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
if (!eglDestroyContext(m_egl_display, m_egl_context))
|
||||
NOTICE_LOG(VIDEO, "Could not destroy drawing context.");
|
||||
if (!m_is_shared && !eglTerminate(m_egl_display))
|
||||
NOTICE_LOG(VIDEO, "Could not destroy display connection.");
|
||||
m_egl_context = EGL_NO_CONTEXT;
|
||||
m_egl_display = EGL_NO_DISPLAY;
|
||||
}
|
||||
|
|
|
@ -9,44 +9,46 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
class cInterfaceEGL : public cInterfaceBase
|
||||
class GLContextEGL : public GLContext
|
||||
{
|
||||
private:
|
||||
EGLConfig m_config;
|
||||
bool m_has_handle;
|
||||
EGLNativeWindowType m_host_window;
|
||||
bool m_supports_surfaceless = false;
|
||||
std::vector<int> m_attribs;
|
||||
public:
|
||||
virtual ~GLContextEGL() override;
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
std::unique_ptr<GLContext> CreateSharedContext() override;
|
||||
|
||||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
|
||||
void UpdateSurface(void* window_handle) override;
|
||||
|
||||
void Swap() override;
|
||||
void SwapInterval(int interval) override;
|
||||
|
||||
void* GetFuncAddress(const std::string& name) override;
|
||||
|
||||
protected:
|
||||
virtual EGLDisplay OpenEGLDisplay();
|
||||
virtual EGLNativeWindowType GetEGLNativeWindow(EGLConfig config);
|
||||
|
||||
bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;
|
||||
|
||||
bool CreateWindowSurface();
|
||||
void DestroyWindowSurface();
|
||||
void DetectMode(bool has_handle);
|
||||
void DestroyContext();
|
||||
|
||||
protected:
|
||||
void DetectMode();
|
||||
EGLSurface egl_surf;
|
||||
EGLContext egl_ctx;
|
||||
EGLDisplay egl_dpy;
|
||||
void* m_host_display = nullptr;
|
||||
void* m_host_window = nullptr;
|
||||
|
||||
virtual EGLDisplay OpenDisplay() { return eglGetDisplay(EGL_DEFAULT_DISPLAY); }
|
||||
virtual EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config)
|
||||
{
|
||||
return (EGLNativeWindowType)EGL_DEFAULT_DISPLAY;
|
||||
}
|
||||
virtual void ShutdownPlatform() {}
|
||||
EGLConfig m_config;
|
||||
bool m_supports_surfaceless = false;
|
||||
std::vector<int> m_attribs;
|
||||
|
||||
public:
|
||||
void Swap() override;
|
||||
void SwapInterval(int interval) override;
|
||||
void SetMode(GLInterfaceMode mode) override { s_opengl_mode = mode; }
|
||||
void* GetFuncAddress(const std::string& name) override;
|
||||
bool Create(void* window_handle, bool stereo, bool core) override;
|
||||
bool Create(cInterfaceBase* main_context) override;
|
||||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
void Shutdown() override;
|
||||
void UpdateHandle(void* window_handle) override;
|
||||
void UpdateSurface() override;
|
||||
std::unique_ptr<cInterfaceBase> CreateSharedContext() override;
|
||||
EGLSurface m_egl_surface = EGL_NO_SURFACE;
|
||||
EGLContext m_egl_context = EGL_NO_CONTEXT;
|
||||
EGLDisplay m_egl_display = EGL_NO_DISPLAY;
|
||||
};
|
||||
|
|
|
@ -3,26 +3,19 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/GL/GLInterface/EGLAndroid.h"
|
||||
#include <android/native_window.h>
|
||||
|
||||
EGLDisplay cInterfaceEGLAndroid::OpenDisplay()
|
||||
EGLDisplay GLContextEGLAndroid::OpenEGLDisplay()
|
||||
{
|
||||
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
EGLNativeWindowType cInterfaceEGLAndroid::InitializePlatform(EGLNativeWindowType host_window,
|
||||
EGLConfig config)
|
||||
EGLNativeWindowType GLContextEGLAndroid::GetEGLNativeWindow(EGLConfig config)
|
||||
{
|
||||
EGLint format;
|
||||
eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
ANativeWindow_setBuffersGeometry(host_window, 0, 0, format);
|
||||
|
||||
const int width = ANativeWindow_getWidth(host_window);
|
||||
const int height = ANativeWindow_getHeight(host_window);
|
||||
GLInterface->SetBackBufferDimensions(width, height);
|
||||
|
||||
return host_window;
|
||||
}
|
||||
|
||||
void cInterfaceEGLAndroid::ShutdownPlatform()
|
||||
{
|
||||
eglGetConfigAttrib(m_egl_display, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
ANativeWindow_setBuffersGeometry(static_cast<ANativeWindow*>(m_host_window), 0, 0, format);
|
||||
m_backbuffer_width = ANativeWindow_getWidth(static_cast<ANativeWindow*>(m_host_window));
|
||||
m_backbuffer_height = ANativeWindow_getHeight(static_cast<ANativeWindow*>(m_host_window));
|
||||
return static_cast<EGLNativeWindowType>(m_host_window);
|
||||
}
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <android/native_window.h>
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
|
||||
class cInterfaceEGLAndroid : public cInterfaceEGL
|
||||
class GLContextEGLAndroid final : public GLContextEGL
|
||||
{
|
||||
protected:
|
||||
EGLDisplay OpenDisplay() override;
|
||||
EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window,
|
||||
EGLConfig config) override;
|
||||
void ShutdownPlatform() override;
|
||||
EGLDisplay OpenEGLDisplay() override;
|
||||
EGLNativeWindowType GetEGLNativeWindow(EGLConfig config) override;
|
||||
};
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/GL/GLInterface/EGLHaiku.h"
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
EGLDisplay cInterfaceEGLHaiku::OpenDisplay()
|
||||
{
|
||||
return eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
}
|
||||
|
||||
EGLNativeWindowType cInterfaceEGLHaiku::InitializePlatform(EGLNativeWindowType host_window,
|
||||
EGLConfig config)
|
||||
{
|
||||
EGLint format;
|
||||
eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
|
||||
BWindow* window = reinterpret_cast<BWindow*>(host_window);
|
||||
const int width = window->Size().width;
|
||||
const int height = window->Size().height;
|
||||
GLInterface->SetBackBufferDimensions(width, height);
|
||||
|
||||
return host_window;
|
||||
}
|
||||
|
||||
void cInterfaceEGLHaiku::ShutdownPlatform()
|
||||
{
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
|
||||
class cInterfaceEGLHaiku final : public cInterfaceEGL
|
||||
{
|
||||
protected:
|
||||
EGLDisplay OpenDisplay() override;
|
||||
EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window,
|
||||
EGLConfig config) override;
|
||||
void ShutdownPlatform() override;
|
||||
};
|
|
@ -3,43 +3,48 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/GL/GLInterface/EGLX11.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
EGLDisplay cInterfaceEGLX11::OpenDisplay()
|
||||
GLContextEGLX11::~GLContextEGLX11()
|
||||
{
|
||||
dpy = XOpenDisplay(nullptr);
|
||||
XWindow.Initialize(dpy);
|
||||
return eglGetDisplay(dpy);
|
||||
// The context must be destroyed before the window.
|
||||
DestroyWindowSurface();
|
||||
DestroyContext();
|
||||
m_render_window.reset();
|
||||
}
|
||||
|
||||
EGLNativeWindowType cInterfaceEGLX11::InitializePlatform(EGLNativeWindowType host_window,
|
||||
EGLConfig config)
|
||||
void GLContextEGLX11::Update()
|
||||
{
|
||||
m_render_window->UpdateDimensions();
|
||||
m_backbuffer_width = m_render_window->GetWidth();
|
||||
m_backbuffer_height = m_render_window->GetHeight();
|
||||
}
|
||||
|
||||
EGLDisplay GLContextEGLX11::OpenEGLDisplay()
|
||||
{
|
||||
return eglGetDisplay(static_cast<Display*>(m_host_display));
|
||||
}
|
||||
|
||||
EGLNativeWindowType GLContextEGLX11::GetEGLNativeWindow(EGLConfig config)
|
||||
{
|
||||
EGLint vid;
|
||||
eglGetConfigAttrib(egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid);
|
||||
eglGetConfigAttrib(m_egl_display, config, EGL_NATIVE_VISUAL_ID, &vid);
|
||||
|
||||
XVisualInfo visTemplate;
|
||||
XVisualInfo visTemplate = {};
|
||||
visTemplate.visualid = vid;
|
||||
|
||||
XVisualInfo* vi;
|
||||
int nVisuals;
|
||||
vi = XGetVisualInfo(dpy, VisualIDMask, &visTemplate, &nVisuals);
|
||||
XVisualInfo* vi =
|
||||
XGetVisualInfo(static_cast<Display*>(m_host_display), VisualIDMask, &visTemplate, &nVisuals);
|
||||
|
||||
XWindowAttributes attribs;
|
||||
if (!XGetWindowAttributes(dpy, (Window)host_window, &attribs))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Window attribute retrieval failed");
|
||||
return 0;
|
||||
}
|
||||
if (m_render_window)
|
||||
m_render_window.reset();
|
||||
|
||||
s_backbuffer_width = attribs.width;
|
||||
s_backbuffer_height = attribs.height;
|
||||
m_render_window = GLX11Window::Create(static_cast<Display*>(m_host_display),
|
||||
reinterpret_cast<Window>(m_host_window), vi);
|
||||
m_backbuffer_width = m_render_window->GetWidth();
|
||||
m_backbuffer_height = m_render_window->GetHeight();
|
||||
|
||||
return (EGLNativeWindowType)XWindow.CreateXWindow((Window)host_window, vi);
|
||||
}
|
||||
|
||||
void cInterfaceEGLX11::ShutdownPlatform()
|
||||
{
|
||||
XWindow.DestroyXWindow();
|
||||
XCloseDisplay(dpy);
|
||||
XFree(vi);
|
||||
|
||||
return reinterpret_cast<EGLNativeWindowType>(m_render_window->GetWindow());
|
||||
}
|
||||
|
|
|
@ -7,17 +7,18 @@
|
|||
#include <X11/Xlib.h>
|
||||
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
#include "Common/GL/GLInterface/X11_Util.h"
|
||||
#include "Common/GL/GLX11Window.h"
|
||||
|
||||
class cInterfaceEGLX11 : public cInterfaceEGL
|
||||
class GLContextEGLX11 final : public GLContextEGL
|
||||
{
|
||||
private:
|
||||
cX11Window XWindow;
|
||||
Display* dpy;
|
||||
public:
|
||||
~GLContextEGLX11() override;
|
||||
|
||||
void Update() override;
|
||||
|
||||
protected:
|
||||
EGLDisplay OpenDisplay() override;
|
||||
EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window,
|
||||
EGLConfig config) override;
|
||||
void ShutdownPlatform() override;
|
||||
EGLDisplay OpenEGLDisplay() override;
|
||||
EGLNativeWindowType GetEGLNativeWindow(EGLConfig config) override;
|
||||
|
||||
std::unique_ptr<GLX11Window> m_render_window;
|
||||
};
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "Common/GL/GLInterface/AGL.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "Common/GL/GLInterface/WGL.h"
|
||||
#elif HAVE_X11
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
#include "Common/GL/GLInterface/EGLX11.h"
|
||||
#else
|
||||
#include "Common/GL/GLInterface/GLX.h"
|
||||
#endif
|
||||
#elif defined(USE_EGL) && USE_EGL && defined(USE_HEADLESS)
|
||||
#include "Common/GL/GLInterface/EGL.h"
|
||||
#elif ANDROID
|
||||
#include "Common/GL/GLInterface/EGLAndroid.h"
|
||||
#elif defined(__HAIKU__)
|
||||
#include "Common/GL/GLInterface/BGL.h"
|
||||
#else
|
||||
#error Platform doesnt have a GLInterface
|
||||
#endif
|
||||
|
||||
std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface()
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
return std::make_unique<cInterfaceAGL>();
|
||||
#elif defined(_WIN32)
|
||||
return std::make_unique<cInterfaceWGL>();
|
||||
#elif defined(USE_EGL) && defined(USE_HEADLESS)
|
||||
return std::make_unique<cInterfaceEGL>();
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
#if defined(USE_EGL) && USE_EGL
|
||||
return std::make_unique<cInterfaceEGLX11>();
|
||||
#else
|
||||
return std::make_unique<cInterfaceGLX>();
|
||||
#endif
|
||||
#elif ANDROID
|
||||
return std::make_unique<cInterfaceEGLAndroid>();
|
||||
#elif defined(__HAIKU__)
|
||||
return std::make_unique<cInterfaceBGL>();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
|
@ -30,43 +30,57 @@ static int ctxErrorHandler(Display* dpy, XErrorEvent* ev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void cInterfaceGLX::SwapInterval(int Interval)
|
||||
GLContextGLX::~GLContextGLX()
|
||||
{
|
||||
if (!m_has_handle)
|
||||
DestroyWindowSurface();
|
||||
if (m_context)
|
||||
{
|
||||
if (glXGetCurrentContext() == m_context)
|
||||
glXMakeCurrent(m_display, None, nullptr);
|
||||
|
||||
glXDestroyContext(m_display, m_context);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContextGLX::IsHeadless() const
|
||||
{
|
||||
return !m_render_window;
|
||||
}
|
||||
|
||||
void GLContextGLX::SwapInterval(int Interval)
|
||||
{
|
||||
if (!m_drawable)
|
||||
return;
|
||||
|
||||
// Try EXT_swap_control, then MESA_swap_control.
|
||||
if (glXSwapIntervalEXTPtr)
|
||||
glXSwapIntervalEXTPtr(dpy, win, Interval);
|
||||
glXSwapIntervalEXTPtr(m_display, m_drawable, Interval);
|
||||
else if (glXSwapIntervalMESAPtr)
|
||||
glXSwapIntervalMESAPtr(static_cast<unsigned int>(Interval));
|
||||
else
|
||||
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
|
||||
}
|
||||
|
||||
void* cInterfaceGLX::GetFuncAddress(const std::string& name)
|
||||
void* GLContextGLX::GetFuncAddress(const std::string& name)
|
||||
{
|
||||
return (void*)glXGetProcAddress((const GLubyte*)name.c_str());
|
||||
return reinterpret_cast<void*>(glXGetProcAddress(reinterpret_cast<const GLubyte*>(name.c_str())));
|
||||
}
|
||||
|
||||
void cInterfaceGLX::Swap()
|
||||
void GLContextGLX::Swap()
|
||||
{
|
||||
glXSwapBuffers(dpy, win);
|
||||
glXSwapBuffers(m_display, m_drawable);
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
|
||||
bool GLContextGLX::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
|
||||
{
|
||||
m_has_handle = !!window_handle;
|
||||
m_host_window = (Window)window_handle;
|
||||
|
||||
dpy = XOpenDisplay(nullptr);
|
||||
int screen = DefaultScreen(dpy);
|
||||
m_display = static_cast<Display*>(display_handle);
|
||||
int screen = DefaultScreen(m_display);
|
||||
|
||||
// checking glx version
|
||||
int glxMajorVersion, glxMinorVersion;
|
||||
glXQueryVersion(dpy, &glxMajorVersion, &glxMinorVersion);
|
||||
glXQueryVersion(m_display, &glxMajorVersion, &glxMinorVersion);
|
||||
if (glxMajorVersion < 1 || (glxMajorVersion == 1 && glxMinorVersion < 4))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "glX-Version %d.%d detected, but need at least 1.4", glxMajorVersion,
|
||||
|
@ -107,54 +121,53 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
|
|||
stereo ? True : False,
|
||||
None};
|
||||
int fbcount = 0;
|
||||
GLXFBConfig* fbc = glXChooseFBConfig(dpy, screen, visual_attribs, &fbcount);
|
||||
GLXFBConfig* fbc = glXChooseFBConfig(m_display, screen, visual_attribs, &fbcount);
|
||||
if (!fbc || !fbcount)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Failed to retrieve a framebuffer config");
|
||||
return false;
|
||||
}
|
||||
fbconfig = *fbc;
|
||||
m_fbconfig = *fbc;
|
||||
XFree(fbc);
|
||||
|
||||
s_glxError = false;
|
||||
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
|
||||
|
||||
// Create a GLX context.
|
||||
// We try to get a 4.0 core profile, else we try 3.3, else try it with anything we get.
|
||||
std::array<int, 9> context_attribs = {
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 0,
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None}};
|
||||
ctx = nullptr;
|
||||
if (core)
|
||||
{
|
||||
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, &context_attribs[0]);
|
||||
XSync(dpy, False);
|
||||
m_attribs.insert(m_attribs.end(), context_attribs.begin(), context_attribs.end());
|
||||
for (const auto& version : s_desktop_opengl_versions)
|
||||
{
|
||||
std::array<int, 9> context_attribs = {
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, version.first, GLX_CONTEXT_MINOR_VERSION_ARB,
|
||||
version.second, GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None}};
|
||||
|
||||
s_glxError = false;
|
||||
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs[0]);
|
||||
XSync(m_display, False);
|
||||
m_attribs.insert(m_attribs.end(), context_attribs.begin(), context_attribs.end());
|
||||
if (!m_context || s_glxError)
|
||||
continue;
|
||||
|
||||
// Got a context.
|
||||
INFO_LOG(VIDEO, "Created a GLX context with version %d.%d", version.first, version.second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (core && (!ctx || s_glxError))
|
||||
{
|
||||
std::array<int, 9> context_attribs_33 = {
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3,
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB,
|
||||
GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, None}};
|
||||
s_glxError = false;
|
||||
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, &context_attribs_33[0]);
|
||||
XSync(dpy, False);
|
||||
m_attribs.clear();
|
||||
m_attribs.insert(m_attribs.end(), context_attribs_33.begin(), context_attribs_33.end());
|
||||
}
|
||||
if (!ctx || s_glxError)
|
||||
|
||||
// Failed to create any core contexts, try for anything.
|
||||
if (!m_context || s_glxError)
|
||||
{
|
||||
std::array<int, 5> context_attribs_legacy = {
|
||||
{GLX_CONTEXT_MAJOR_VERSION_ARB, 1, GLX_CONTEXT_MINOR_VERSION_ARB, 0, None}};
|
||||
s_glxError = false;
|
||||
ctx = glXCreateContextAttribs(dpy, fbconfig, 0, True, &context_attribs_legacy[0]);
|
||||
XSync(dpy, False);
|
||||
m_context = glXCreateContextAttribs(m_display, m_fbconfig, 0, True, &context_attribs_legacy[0]);
|
||||
XSync(m_display, False);
|
||||
m_attribs.clear();
|
||||
m_attribs.insert(m_attribs.end(), context_attribs_legacy.begin(), context_attribs_legacy.end());
|
||||
}
|
||||
if (!ctx || s_glxError)
|
||||
if (!m_context || s_glxError)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Unable to create GL context.");
|
||||
XSetErrorHandler(oldHandler);
|
||||
|
@ -168,7 +181,7 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
|
|||
m_supports_pbuffer = false;
|
||||
|
||||
std::string tmp;
|
||||
std::istringstream buffer(glXQueryExtensionsString(dpy, screen));
|
||||
std::istringstream buffer(glXQueryExtensionsString(m_display, screen));
|
||||
while (buffer >> tmp)
|
||||
{
|
||||
if (tmp == "GLX_SGIX_pbuffer")
|
||||
|
@ -191,7 +204,7 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
|
|||
}
|
||||
}
|
||||
|
||||
if (!CreateWindowSurface())
|
||||
if (!CreateWindowSurface(reinterpret_cast<Window>(window_handle)))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed\n");
|
||||
XSetErrorHandler(oldHandler);
|
||||
|
@ -199,119 +212,95 @@ bool cInterfaceGLX::Create(void* window_handle, bool stereo, bool core)
|
|||
}
|
||||
|
||||
XSetErrorHandler(oldHandler);
|
||||
return true;
|
||||
m_opengl_mode = Mode::OpenGL;
|
||||
return MakeCurrent();
|
||||
}
|
||||
|
||||
bool cInterfaceGLX::Create(cInterfaceBase* main_context)
|
||||
std::unique_ptr<GLContext> GLContextGLX::CreateSharedContext()
|
||||
{
|
||||
cInterfaceGLX* glx_context = static_cast<cInterfaceGLX*>(main_context);
|
||||
|
||||
m_has_handle = false;
|
||||
m_supports_pbuffer = glx_context->m_supports_pbuffer;
|
||||
dpy = glx_context->dpy;
|
||||
fbconfig = glx_context->fbconfig;
|
||||
s_glxError = false;
|
||||
XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler);
|
||||
|
||||
ctx = glXCreateContextAttribs(dpy, fbconfig, glx_context->ctx, True, &glx_context->m_attribs[0]);
|
||||
XSync(dpy, False);
|
||||
GLXContext new_glx_context =
|
||||
glXCreateContextAttribs(m_display, m_fbconfig, m_context, True, &m_attribs[0]);
|
||||
XSync(m_display, False);
|
||||
|
||||
if (!ctx || s_glxError)
|
||||
if (!new_glx_context || s_glxError)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Unable to create GL context.");
|
||||
XSetErrorHandler(oldHandler);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_supports_pbuffer && !CreateWindowSurface())
|
||||
std::unique_ptr<GLContextGLX> new_context = std::make_unique<GLContextGLX>();
|
||||
new_context->m_context = new_glx_context;
|
||||
new_context->m_opengl_mode = m_opengl_mode;
|
||||
new_context->m_supports_pbuffer = m_supports_pbuffer;
|
||||
new_context->m_display = m_display;
|
||||
new_context->m_fbconfig = m_fbconfig;
|
||||
new_context->m_is_shared = true;
|
||||
|
||||
if (m_supports_pbuffer && !new_context->CreateWindowSurface(None))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed\n");
|
||||
ERROR_LOG(VIDEO, "Error: CreateWindowSurface failed");
|
||||
XSetErrorHandler(oldHandler);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
XSetErrorHandler(oldHandler);
|
||||
return true;
|
||||
return new_context;
|
||||
}
|
||||
|
||||
std::unique_ptr<cInterfaceBase> cInterfaceGLX::CreateSharedContext()
|
||||
bool GLContextGLX::CreateWindowSurface(Window window_handle)
|
||||
{
|
||||
std::unique_ptr<cInterfaceBase> context = std::make_unique<cInterfaceGLX>();
|
||||
if (!context->Create(this))
|
||||
return nullptr;
|
||||
return context;
|
||||
}
|
||||
|
||||
bool cInterfaceGLX::CreateWindowSurface()
|
||||
{
|
||||
if (m_has_handle)
|
||||
if (window_handle)
|
||||
{
|
||||
// Get an appropriate visual
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(dpy, fbconfig);
|
||||
|
||||
XWindow.Initialize(dpy);
|
||||
|
||||
XWindowAttributes attribs;
|
||||
if (!XGetWindowAttributes(dpy, m_host_window, &attribs))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Window attribute retrieval failed");
|
||||
XVisualInfo* vi = glXGetVisualFromFBConfig(m_display, m_fbconfig);
|
||||
m_render_window = GLX11Window::Create(m_display, window_handle, vi);
|
||||
if (!m_render_window)
|
||||
return false;
|
||||
}
|
||||
|
||||
s_backbuffer_width = attribs.width;
|
||||
s_backbuffer_height = attribs.height;
|
||||
|
||||
win = XWindow.CreateXWindow(m_host_window, vi);
|
||||
m_backbuffer_width = m_render_window->GetWidth();
|
||||
m_backbuffer_height = m_render_window->GetHeight();
|
||||
m_drawable = static_cast<GLXDrawable>(m_render_window->GetWindow());
|
||||
XFree(vi);
|
||||
}
|
||||
else if (m_supports_pbuffer)
|
||||
{
|
||||
win = m_pbuffer = glXCreateGLXPbufferSGIX(dpy, fbconfig, 1, 1, nullptr);
|
||||
m_pbuffer = glXCreateGLXPbufferSGIX(m_display, m_fbconfig, 1, 1, nullptr);
|
||||
if (!m_pbuffer)
|
||||
return false;
|
||||
|
||||
m_drawable = static_cast<GLXDrawable>(m_pbuffer);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cInterfaceGLX::DestroyWindowSurface()
|
||||
void GLContextGLX::DestroyWindowSurface()
|
||||
{
|
||||
if (m_has_handle)
|
||||
m_render_window.reset();
|
||||
if (m_supports_pbuffer && m_pbuffer)
|
||||
{
|
||||
XWindow.DestroyXWindow();
|
||||
}
|
||||
else if (m_supports_pbuffer && m_pbuffer)
|
||||
{
|
||||
glXDestroyGLXPbufferSGIX(dpy, m_pbuffer);
|
||||
glXDestroyGLXPbufferSGIX(m_display, m_pbuffer);
|
||||
m_pbuffer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool cInterfaceGLX::MakeCurrent()
|
||||
bool GLContextGLX::MakeCurrent()
|
||||
{
|
||||
return glXMakeCurrent(dpy, win, ctx);
|
||||
return glXMakeCurrent(m_display, m_drawable, m_context);
|
||||
}
|
||||
|
||||
bool cInterfaceGLX::ClearCurrent()
|
||||
bool GLContextGLX::ClearCurrent()
|
||||
{
|
||||
return glXMakeCurrent(dpy, None, nullptr);
|
||||
return glXMakeCurrent(m_display, None, nullptr);
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceGLX::Shutdown()
|
||||
void GLContextGLX::Update()
|
||||
{
|
||||
DestroyWindowSurface();
|
||||
if (ctx)
|
||||
{
|
||||
glXDestroyContext(dpy, ctx);
|
||||
|
||||
// Don't close the display connection if we are a shared context.
|
||||
// Saves doing reference counting on this object, and the main context will always
|
||||
// be shut down last anyway.
|
||||
if (m_has_handle)
|
||||
{
|
||||
XCloseDisplay(dpy);
|
||||
ctx = nullptr;
|
||||
}
|
||||
}
|
||||
m_render_window->UpdateDimensions();
|
||||
m_backbuffer_width = m_render_window->GetWidth();
|
||||
m_backbuffer_height = m_render_window->GetHeight();
|
||||
}
|
||||
|
|
|
@ -10,35 +10,41 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/GL/GLInterface/X11_Util.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/GL/GLX11Window.h"
|
||||
|
||||
class cInterfaceGLX : public cInterfaceBase
|
||||
class GLContextGLX final : public GLContext
|
||||
{
|
||||
private:
|
||||
Window m_host_window;
|
||||
cX11Window XWindow;
|
||||
Display* dpy;
|
||||
Window win;
|
||||
GLXContext ctx;
|
||||
GLXFBConfig fbconfig;
|
||||
bool m_has_handle;
|
||||
public:
|
||||
~GLContextGLX() override;
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
std::unique_ptr<GLContext> CreateSharedContext() override;
|
||||
|
||||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
|
||||
void Update() override;
|
||||
|
||||
void SwapInterval(int Interval) override;
|
||||
void Swap() override;
|
||||
|
||||
void* GetFuncAddress(const std::string& name) override;
|
||||
|
||||
protected:
|
||||
bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;
|
||||
|
||||
Display* m_display = nullptr;
|
||||
std::unique_ptr<GLX11Window> m_render_window;
|
||||
|
||||
GLXDrawable m_drawable = {};
|
||||
GLXContext m_context = nullptr;
|
||||
GLXFBConfig m_fbconfig = {};
|
||||
bool m_supports_pbuffer = false;
|
||||
GLXPbufferSGIX m_pbuffer = 0;
|
||||
std::vector<int> m_attribs;
|
||||
|
||||
bool CreateWindowSurface();
|
||||
bool CreateWindowSurface(Window window_handle);
|
||||
void DestroyWindowSurface();
|
||||
|
||||
public:
|
||||
friend class cX11Window;
|
||||
void SwapInterval(int Interval) override;
|
||||
void Swap() override;
|
||||
void* GetFuncAddress(const std::string& name) override;
|
||||
bool Create(void* window_handle, bool stereo, bool core) override;
|
||||
bool Create(cInterfaceBase* main_context) override;
|
||||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
void Shutdown() override;
|
||||
std::unique_ptr<cInterfaceBase> CreateSharedContext() override;
|
||||
};
|
||||
|
|
|
@ -130,8 +130,8 @@ static PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB = nullptr;
|
|||
|
||||
static void LoadWGLExtensions()
|
||||
{
|
||||
wglSwapIntervalEXT = reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(
|
||||
GLInterface->GetFuncAddress("wglSwapIntervalEXT"));
|
||||
wglSwapIntervalEXT =
|
||||
reinterpret_cast<PFNWGLSWAPINTERVALEXTPROC>(wglGetProcAddress("wglSwapIntervalEXT"));
|
||||
wglCreateContextAttribsARB = reinterpret_cast<PFNWGLCREATECONTEXTATTRIBSARBPROC>(
|
||||
wglGetProcAddress("wglCreateContextAttribsARB"));
|
||||
wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(
|
||||
|
@ -157,19 +157,57 @@ static void ClearWGLExtensionPointers()
|
|||
wglDestroyPbufferARB = nullptr;
|
||||
}
|
||||
|
||||
void cInterfaceWGL::SwapInterval(int Interval)
|
||||
GLContextWGL::~GLContextWGL()
|
||||
{
|
||||
if (m_rc)
|
||||
{
|
||||
if (wglGetCurrentContext() == m_rc && !wglMakeCurrent(m_dc, nullptr))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
|
||||
if (!wglDeleteContext(m_rc))
|
||||
ERROR_LOG(VIDEO, "Attempt to release rendering context failed.");
|
||||
|
||||
m_rc = nullptr;
|
||||
}
|
||||
|
||||
if (m_dc)
|
||||
{
|
||||
if (m_pbuffer_handle)
|
||||
{
|
||||
wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(m_pbuffer_handle), m_dc);
|
||||
m_dc = nullptr;
|
||||
|
||||
wglDestroyPbufferARB(static_cast<HPBUFFERARB>(m_pbuffer_handle));
|
||||
m_pbuffer_handle = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ReleaseDC(m_window_handle, m_dc))
|
||||
ERROR_LOG(VIDEO, "Attempt to release device context failed.");
|
||||
|
||||
m_dc = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContextWGL::IsHeadless() const
|
||||
{
|
||||
return !m_window_handle;
|
||||
}
|
||||
|
||||
void GLContextWGL::SwapInterval(int interval)
|
||||
{
|
||||
if (wglSwapIntervalEXT)
|
||||
wglSwapIntervalEXT(Interval);
|
||||
wglSwapIntervalEXT(interval);
|
||||
else
|
||||
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
|
||||
}
|
||||
void cInterfaceWGL::Swap()
|
||||
void GLContextWGL::Swap()
|
||||
{
|
||||
SwapBuffers(m_dc);
|
||||
}
|
||||
|
||||
void* cInterfaceWGL::GetFuncAddress(const std::string& name)
|
||||
void* GLContextWGL::GetFuncAddress(const std::string& name)
|
||||
{
|
||||
FARPROC func = wglGetProcAddress(name.c_str());
|
||||
if (func == nullptr)
|
||||
|
@ -183,24 +221,9 @@ void* cInterfaceWGL::GetFuncAddress(const std::string& name)
|
|||
return func;
|
||||
}
|
||||
|
||||
// Draw messages on top of the screen
|
||||
bool cInterfaceWGL::PeekMessages()
|
||||
{
|
||||
// TODO: peekmessage
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.message == WM_QUIT)
|
||||
return FALSE;
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Create rendering window.
|
||||
// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize()
|
||||
bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
|
||||
bool GLContextWGL::Initialize(void* display_handle, void* window_handle, bool stereo, bool core)
|
||||
{
|
||||
if (!window_handle)
|
||||
return false;
|
||||
|
@ -216,8 +239,8 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
|
|||
// Control window size and picture scaling
|
||||
int twidth = window_rect.right - window_rect.left;
|
||||
int theight = window_rect.bottom - window_rect.top;
|
||||
s_backbuffer_width = twidth;
|
||||
s_backbuffer_height = theight;
|
||||
m_backbuffer_width = twidth;
|
||||
m_backbuffer_height = theight;
|
||||
|
||||
const DWORD stereo_flag = stereo ? PFD_STEREO : 0;
|
||||
|
||||
|
@ -274,8 +297,7 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
|
|||
}
|
||||
|
||||
// WGL only supports desktop GL, for now.
|
||||
if (s_opengl_mode == GLInterfaceMode::MODE_DETECT)
|
||||
s_opengl_mode = GLInterfaceMode::MODE_OPENGL;
|
||||
m_opengl_mode = Mode::OpenGL;
|
||||
|
||||
if (core)
|
||||
{
|
||||
|
@ -306,7 +328,6 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
|
|||
{
|
||||
wglDeleteContext(m_rc);
|
||||
m_rc = core_context;
|
||||
m_core = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -314,38 +335,35 @@ bool cInterfaceWGL::Create(void* window_handle, bool stereo, bool core)
|
|||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return MakeCurrent();
|
||||
}
|
||||
|
||||
bool cInterfaceWGL::Create(cInterfaceBase* main_context)
|
||||
std::unique_ptr<GLContext> GLContextWGL::CreateSharedContext()
|
||||
{
|
||||
cInterfaceWGL* wgl_main_context = static_cast<cInterfaceWGL*>(main_context);
|
||||
|
||||
// WGL does not support surfaceless contexts, so we use a 1x1 pbuffer instead.
|
||||
if (!CreatePBuffer(wgl_main_context->m_dc, 1, 1, &m_pbuffer_handle, &m_dc))
|
||||
return false;
|
||||
HANDLE pbuffer;
|
||||
HDC dc;
|
||||
if (!CreatePBuffer(m_dc, 1, 1, &pbuffer, &dc))
|
||||
return nullptr;
|
||||
|
||||
m_rc = CreateCoreContext(m_dc, wgl_main_context->m_rc);
|
||||
if (!m_rc)
|
||||
return false;
|
||||
|
||||
m_core = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<cInterfaceBase> cInterfaceWGL::CreateSharedContext()
|
||||
{
|
||||
std::unique_ptr<cInterfaceWGL> context = std::make_unique<cInterfaceWGL>();
|
||||
if (!context->Create(this))
|
||||
HGLRC rc = CreateCoreContext(dc, m_rc);
|
||||
if (!rc)
|
||||
{
|
||||
context->Shutdown();
|
||||
wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(pbuffer), dc);
|
||||
wglDestroyPbufferARB(static_cast<HPBUFFERARB>(pbuffer));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::move(context);
|
||||
std::unique_ptr<GLContextWGL> context = std::make_unique<GLContextWGL>();
|
||||
context->m_pbuffer_handle = pbuffer;
|
||||
context->m_dc = dc;
|
||||
context->m_rc = rc;
|
||||
context->m_opengl_mode = m_opengl_mode;
|
||||
context->m_is_shared = true;
|
||||
return context;
|
||||
}
|
||||
|
||||
HGLRC cInterfaceWGL::CreateCoreContext(HDC dc, HGLRC share_context)
|
||||
HGLRC GLContextWGL::CreateCoreContext(HDC dc, HGLRC share_context)
|
||||
{
|
||||
if (!wglCreateContextAttribsARB)
|
||||
{
|
||||
|
@ -353,12 +371,7 @@ HGLRC cInterfaceWGL::CreateCoreContext(HDC dc, HGLRC share_context)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// List of versions to attempt context creation for. (4.5-3.2, geometry shaders is a minimum
|
||||
// requirement since we're using core profile)
|
||||
static constexpr std::array<std::pair<int, int>, 8> try_versions = {
|
||||
{{4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}}};
|
||||
|
||||
for (const auto& version : try_versions)
|
||||
for (const auto& version : s_desktop_opengl_versions)
|
||||
{
|
||||
// Construct list of attributes. Prefer a forward-compatible, core context.
|
||||
std::array<int, 5 * 2> attribs = {WGL_CONTEXT_PROFILE_MASK_ARB,
|
||||
|
@ -402,8 +415,8 @@ HGLRC cInterfaceWGL::CreateCoreContext(HDC dc, HGLRC share_context)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
bool cInterfaceWGL::CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE* pbuffer_handle,
|
||||
HDC* pbuffer_dc)
|
||||
bool GLContextWGL::CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE* pbuffer_handle,
|
||||
HDC* pbuffer_dc)
|
||||
{
|
||||
if (!wglChoosePixelFormatARB || !wglCreatePbufferARB || !wglGetPbufferDCARB ||
|
||||
!wglReleasePbufferDCARB || !wglDestroyPbufferARB)
|
||||
|
@ -462,57 +475,23 @@ bool cInterfaceWGL::CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE
|
|||
return true;
|
||||
}
|
||||
|
||||
bool cInterfaceWGL::MakeCurrent()
|
||||
bool GLContextWGL::MakeCurrent()
|
||||
{
|
||||
return wglMakeCurrent(m_dc, m_rc) == TRUE;
|
||||
}
|
||||
|
||||
bool cInterfaceWGL::ClearCurrent()
|
||||
bool GLContextWGL::ClearCurrent()
|
||||
{
|
||||
return wglMakeCurrent(m_dc, nullptr) == TRUE;
|
||||
}
|
||||
|
||||
// Update window width, size and etc. Called from Render.cpp
|
||||
void cInterfaceWGL::Update()
|
||||
void GLContextWGL::Update()
|
||||
{
|
||||
RECT rcWindow;
|
||||
GetClientRect(m_window_handle, &rcWindow);
|
||||
|
||||
// Get the new window width and height
|
||||
s_backbuffer_width = rcWindow.right - rcWindow.left;
|
||||
s_backbuffer_height = rcWindow.bottom - rcWindow.top;
|
||||
}
|
||||
|
||||
// Close backend
|
||||
void cInterfaceWGL::Shutdown()
|
||||
{
|
||||
if (m_rc)
|
||||
{
|
||||
if (!wglMakeCurrent(m_dc, nullptr))
|
||||
NOTICE_LOG(VIDEO, "Could not release drawing context.");
|
||||
|
||||
if (!wglDeleteContext(m_rc))
|
||||
ERROR_LOG(VIDEO, "Attempt to release rendering context failed.");
|
||||
|
||||
m_rc = nullptr;
|
||||
}
|
||||
|
||||
if (m_dc)
|
||||
{
|
||||
if (m_pbuffer_handle)
|
||||
{
|
||||
wglReleasePbufferDCARB(static_cast<HPBUFFERARB>(m_pbuffer_handle), m_dc);
|
||||
m_dc = nullptr;
|
||||
|
||||
wglDestroyPbufferARB(static_cast<HPBUFFERARB>(m_pbuffer_handle));
|
||||
m_pbuffer_handle = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ReleaseDC(m_window_handle, m_dc))
|
||||
ERROR_LOG(VIDEO, "Attempt to release device context failed.");
|
||||
|
||||
m_dc = nullptr;
|
||||
}
|
||||
}
|
||||
m_backbuffer_width = rcWindow.right - rcWindow.left;
|
||||
m_backbuffer_height = rcWindow.bottom - rcWindow.top;
|
||||
}
|
||||
|
|
|
@ -6,26 +6,30 @@
|
|||
|
||||
#include <windows.h>
|
||||
#include <string>
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
class cInterfaceWGL : public cInterfaceBase
|
||||
class GLContextWGL final : public GLContext
|
||||
{
|
||||
public:
|
||||
void SwapInterval(int interval) override;
|
||||
void Swap() override;
|
||||
void* GetFuncAddress(const std::string& name) override;
|
||||
bool Create(void* window_handle, bool stereo, bool core) override;
|
||||
bool Create(cInterfaceBase* main_context) override;
|
||||
~GLContextWGL();
|
||||
|
||||
bool IsHeadless() const;
|
||||
|
||||
std::unique_ptr<GLContext> CreateSharedContext() override;
|
||||
|
||||
bool MakeCurrent() override;
|
||||
bool ClearCurrent() override;
|
||||
void Shutdown() override;
|
||||
|
||||
void Update() override;
|
||||
bool PeekMessages() override;
|
||||
|
||||
std::unique_ptr<cInterfaceBase> CreateSharedContext() override;
|
||||
void Swap() override;
|
||||
void SwapInterval(int interval) override;
|
||||
|
||||
void* GetFuncAddress(const std::string& name) override;
|
||||
|
||||
protected:
|
||||
bool Initialize(void* display_handle, void* window_handle, bool stereo, bool core) override;
|
||||
|
||||
private:
|
||||
static HGLRC CreateCoreContext(HDC dc, HGLRC share_context);
|
||||
static bool CreatePBuffer(HDC onscreen_dc, int width, int height, HANDLE* pbuffer_handle,
|
||||
HDC* pbuffer_dc);
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
// Copyright 2012 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/GL/GLInterface/X11_Util.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/Thread.h"
|
||||
|
||||
void cX11Window::Initialize(Display* _dpy)
|
||||
{
|
||||
dpy = _dpy;
|
||||
}
|
||||
|
||||
Window cX11Window::CreateXWindow(Window parent, XVisualInfo* vi)
|
||||
{
|
||||
XSetWindowAttributes attr;
|
||||
|
||||
colormap = XCreateColormap(dpy, parent, vi->visual, AllocNone);
|
||||
|
||||
// Setup window attributes
|
||||
attr.colormap = colormap;
|
||||
|
||||
XWindowAttributes attribs;
|
||||
if (!XGetWindowAttributes(dpy, parent, &attribs))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Window attribute retrieval failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create the window
|
||||
win = XCreateWindow(dpy, parent, 0, 0, attribs.width, attribs.height, 0, vi->depth, InputOutput,
|
||||
vi->visual, CWColormap, &attr);
|
||||
XSelectInput(dpy, parent, StructureNotifyMask);
|
||||
XMapWindow(dpy, win);
|
||||
XSync(dpy, True);
|
||||
|
||||
xEventThread = std::thread(&cX11Window::XEventThread, this);
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
void cX11Window::DestroyXWindow(void)
|
||||
{
|
||||
XUnmapWindow(dpy, win);
|
||||
win = 0;
|
||||
if (xEventThread.joinable())
|
||||
xEventThread.join();
|
||||
XFreeColormap(dpy, colormap);
|
||||
}
|
||||
|
||||
void cX11Window::XEventThread()
|
||||
{
|
||||
while (win)
|
||||
{
|
||||
XEvent event;
|
||||
for (int num_events = XPending(dpy); num_events > 0; num_events--)
|
||||
{
|
||||
XNextEvent(dpy, &event);
|
||||
switch (event.type)
|
||||
{
|
||||
case ConfigureNotify:
|
||||
XResizeWindow(dpy, win, event.xconfigure.width, event.xconfigure.height);
|
||||
GLInterface->SetBackBufferDimensions(event.xconfigure.width, event.xconfigure.height);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Common::SleepCurrentThread(20);
|
||||
}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
class cX11Window
|
||||
{
|
||||
private:
|
||||
void XEventThread();
|
||||
std::thread xEventThread;
|
||||
Colormap colormap;
|
||||
|
||||
public:
|
||||
void Initialize(Display* dpy);
|
||||
Window CreateXWindow(Window parent, XVisualInfo* vi);
|
||||
void DestroyXWindow();
|
||||
|
||||
Display* dpy;
|
||||
Window win;
|
||||
};
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
enum class GLInterfaceMode
|
||||
{
|
||||
MODE_DETECT,
|
||||
MODE_OPENGL,
|
||||
MODE_OPENGLES2,
|
||||
MODE_OPENGLES3,
|
||||
};
|
||||
|
||||
class cInterfaceBase
|
||||
{
|
||||
protected:
|
||||
// Window dimensions.
|
||||
u32 s_backbuffer_width = 0;
|
||||
u32 s_backbuffer_height = 0;
|
||||
bool m_core = false;
|
||||
bool m_is_shared = false;
|
||||
|
||||
GLInterfaceMode s_opengl_mode = GLInterfaceMode::MODE_DETECT;
|
||||
|
||||
public:
|
||||
virtual ~cInterfaceBase() {}
|
||||
virtual void Swap() {}
|
||||
virtual void SetMode(GLInterfaceMode mode) { s_opengl_mode = GLInterfaceMode::MODE_OPENGL; }
|
||||
virtual GLInterfaceMode GetMode() { return s_opengl_mode; }
|
||||
virtual void* GetFuncAddress(const std::string& name) { return nullptr; }
|
||||
virtual bool Create(void* window_handle, bool stereo = false, bool core = true) { return true; }
|
||||
virtual bool Create(cInterfaceBase* main_context) { return true; }
|
||||
virtual bool MakeCurrent() { return true; }
|
||||
virtual bool ClearCurrent() { return true; }
|
||||
virtual void Shutdown() {}
|
||||
virtual void SwapInterval(int Interval) {}
|
||||
virtual u32 GetBackBufferWidth() { return s_backbuffer_width; }
|
||||
virtual u32 GetBackBufferHeight() { return s_backbuffer_height; }
|
||||
virtual void SetBackBufferDimensions(u32 W, u32 H)
|
||||
{
|
||||
s_backbuffer_width = W;
|
||||
s_backbuffer_height = H;
|
||||
}
|
||||
virtual void Update() {}
|
||||
virtual bool PeekMessages() { return false; }
|
||||
virtual void UpdateHandle(void* window_handle) {}
|
||||
virtual void UpdateSurface() {}
|
||||
virtual std::unique_ptr<cInterfaceBase> CreateSharedContext() { return nullptr; }
|
||||
};
|
||||
|
||||
extern std::unique_ptr<cInterfaceBase> GLInterface;
|
||||
|
||||
// This function has to be defined along the Host_ functions from Core/Host.h.
|
||||
// Current canonical implementation: DolphinWX/GLInterface/GLInterface.cpp.
|
||||
std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface();
|
|
@ -5,19 +5,12 @@
|
|||
#include <memory>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
std::unique_ptr<cInterfaceBase> GLInterface;
|
||||
|
||||
namespace GLUtil
|
||||
{
|
||||
void InitInterface()
|
||||
{
|
||||
GLInterface = HostGL_CreateGLInterface();
|
||||
}
|
||||
|
||||
GLuint CompileProgram(const std::string& vertexShader, const std::string& fragmentShader)
|
||||
{
|
||||
// generate objects
|
||||
|
@ -103,11 +96,11 @@ GLuint CompileProgram(const std::string& vertexShader, const std::string& fragme
|
|||
return programID;
|
||||
}
|
||||
|
||||
void EnablePrimitiveRestart()
|
||||
void EnablePrimitiveRestart(const GLContext* context)
|
||||
{
|
||||
constexpr GLuint PRIMITIVE_RESTART_INDEX = 65535;
|
||||
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
|
||||
if (context->IsGLES())
|
||||
{
|
||||
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
|
||||
}
|
||||
|
@ -125,4 +118,4 @@ void EnablePrimitiveRestart()
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace GLUtil
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
|
||||
#include "Common/GL/GLExtensions/GLExtensions.h"
|
||||
|
||||
class GLContext;
|
||||
|
||||
namespace GLUtil
|
||||
{
|
||||
void InitInterface();
|
||||
GLuint CompileProgram(const std::string& vertexShader, const std::string& fragmentShader);
|
||||
void EnablePrimitiveRestart();
|
||||
}
|
||||
void EnablePrimitiveRestart(const GLContext* context);
|
||||
} // namespace GLUtil
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2012 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/GL/GLX11Window.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
GLX11Window::GLX11Window(Display* display, Window parent_window, Colormap color_map, Window window,
|
||||
int width, int height)
|
||||
: m_display(display), m_parent_window(parent_window), m_color_map(color_map), m_window(window),
|
||||
m_width(width), m_height(height)
|
||||
{
|
||||
}
|
||||
|
||||
GLX11Window::~GLX11Window()
|
||||
{
|
||||
XUnmapWindow(m_display, m_window);
|
||||
XDestroyWindow(m_display, m_window);
|
||||
XFreeColormap(m_display, m_color_map);
|
||||
}
|
||||
|
||||
void GLX11Window::UpdateDimensions()
|
||||
{
|
||||
XWindowAttributes attribs;
|
||||
XGetWindowAttributes(m_display, m_parent_window, &attribs);
|
||||
XResizeWindow(m_display, m_window, attribs.width, attribs.height);
|
||||
m_width = attribs.width;
|
||||
m_height = attribs.height;
|
||||
}
|
||||
|
||||
std::unique_ptr<GLX11Window> GLX11Window::Create(Display* display, Window parent_window,
|
||||
XVisualInfo* vi)
|
||||
{
|
||||
// Set color map for the new window based on the visual.
|
||||
Colormap color_map = XCreateColormap(display, parent_window, vi->visual, AllocNone);
|
||||
XSetWindowAttributes attribs = {};
|
||||
attribs.colormap = color_map;
|
||||
|
||||
// Get the dimensions from the parent window.
|
||||
XWindowAttributes parent_attribs = {};
|
||||
XGetWindowAttributes(display, parent_window, &parent_attribs);
|
||||
|
||||
// Create the window
|
||||
Window window =
|
||||
XCreateWindow(display, parent_window, 0, 0, parent_attribs.width, parent_attribs.height, 0,
|
||||
vi->depth, InputOutput, vi->visual, CWColormap, &attribs);
|
||||
XSelectInput(display, parent_window, StructureNotifyMask);
|
||||
XMapWindow(display, window);
|
||||
XSync(display, True);
|
||||
|
||||
return std::make_unique<GLX11Window>(display, parent_window, color_map, window,
|
||||
parent_attribs.width, parent_attribs.height);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
class GLX11Window
|
||||
{
|
||||
public:
|
||||
GLX11Window(Display* display, Window parent_window, Colormap color_map, Window window, int width,
|
||||
int height);
|
||||
~GLX11Window();
|
||||
|
||||
Display* GetDisplay() const { return m_display; }
|
||||
Window GetParentWindow() const { return m_parent_window; }
|
||||
Window GetWindow() const { return m_window; }
|
||||
int GetWidth() const { return m_width; }
|
||||
int GetHeight() const { return m_height; }
|
||||
|
||||
void UpdateDimensions();
|
||||
|
||||
static std::unique_ptr<GLX11Window> Create(Display* display, Window parent_window,
|
||||
XVisualInfo* vi);
|
||||
|
||||
private:
|
||||
Display* m_display;
|
||||
Window m_parent_window;
|
||||
Colormap m_color_map;
|
||||
Window m_window;
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2018 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
enum class WindowSystemType
|
||||
{
|
||||
Headless,
|
||||
Windows,
|
||||
MacOS,
|
||||
Android,
|
||||
X11,
|
||||
Wayland
|
||||
};
|
||||
|
||||
struct WindowSystemInfo
|
||||
{
|
||||
WindowSystemInfo() = default;
|
||||
WindowSystemInfo(WindowSystemType type_, void* display_connection_, void* render_surface_)
|
||||
: type(type_), display_connection(display_connection_), render_surface(render_surface_)
|
||||
{
|
||||
}
|
||||
|
||||
// Window system type. Determines which GL context or Vulkan WSI is used.
|
||||
WindowSystemType type = WindowSystemType::Headless;
|
||||
|
||||
// Connection to a display server. This is used on X11 and Wayland platforms.
|
||||
void* display_connection = nullptr;
|
||||
|
||||
// Render surface. This is a pointer to the native window handle, which depends
|
||||
// on the platform. e.g. HWND for Windows, Window for X11. If the surface is
|
||||
// set to nullptr, the video backend will run in headless mode.
|
||||
void* render_surface = nullptr;
|
||||
};
|
|
@ -222,7 +222,7 @@ static GPUDeterminismMode ParseGPUDeterminismMode(const std::string& mode)
|
|||
}
|
||||
|
||||
// Boot the ISO or file
|
||||
bool BootCore(std::unique_ptr<BootParameters> boot)
|
||||
bool BootCore(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
|
||||
{
|
||||
if (!boot)
|
||||
return false;
|
||||
|
@ -403,12 +403,14 @@ bool BootCore(std::unique_ptr<BootParameters> boot)
|
|||
std::holds_alternative<BootParameters::Disc>(boot->parameters);
|
||||
if (load_ipl)
|
||||
{
|
||||
return Core::Init(std::make_unique<BootParameters>(
|
||||
BootParameters::IPL{StartUp.m_region,
|
||||
std::move(std::get<BootParameters::Disc>(boot->parameters))},
|
||||
boot->savestate_path));
|
||||
return Core::Init(
|
||||
std::make_unique<BootParameters>(
|
||||
BootParameters::IPL{StartUp.m_region,
|
||||
std::move(std::get<BootParameters::Disc>(boot->parameters))},
|
||||
boot->savestate_path),
|
||||
wsi);
|
||||
}
|
||||
return Core::Init(std::move(boot));
|
||||
return Core::Init(std::move(boot), wsi);
|
||||
}
|
||||
|
||||
// SYSCONF can be modified during emulation by the user and internally, which makes it
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
#include <memory>
|
||||
|
||||
struct BootParameters;
|
||||
struct WindowSystemInfo;
|
||||
|
||||
namespace BootManager
|
||||
{
|
||||
bool BootCore(std::unique_ptr<BootParameters> parameters);
|
||||
bool BootCore(std::unique_ptr<BootParameters> parameters, const WindowSystemInfo& wsi);
|
||||
|
||||
// Synchronise Dolphin's configuration with the SYSCONF (which may have changed during emulation),
|
||||
// and restore settings that were overriden by per-game INIs or for some other reason.
|
||||
void RestoreConfig();
|
||||
}
|
||||
} // namespace BootManager
|
||||
|
|
|
@ -89,7 +89,6 @@ static bool s_is_stopping = false;
|
|||
static bool s_hardware_initialized = false;
|
||||
static bool s_is_started = false;
|
||||
static Common::Flag s_is_booting;
|
||||
static void* s_window_handle = nullptr;
|
||||
static std::thread s_emu_thread;
|
||||
static StateChangedCallbackFunc s_on_state_changed_callback;
|
||||
|
||||
|
@ -108,7 +107,7 @@ static std::queue<HostJob> s_host_jobs_queue;
|
|||
|
||||
static thread_local bool tls_is_cpu_thread = false;
|
||||
|
||||
static void EmuThread(std::unique_ptr<BootParameters> boot);
|
||||
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi);
|
||||
|
||||
bool GetIsThrottlerTempDisabled()
|
||||
{
|
||||
|
@ -191,7 +190,7 @@ bool WantsDeterminism()
|
|||
|
||||
// This is called from the GUI thread. See the booting call schedule in
|
||||
// BootManager.cpp
|
||||
bool Init(std::unique_ptr<BootParameters> boot)
|
||||
bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi)
|
||||
{
|
||||
if (s_emu_thread.joinable())
|
||||
{
|
||||
|
@ -215,10 +214,8 @@ bool Init(std::unique_ptr<BootParameters> boot)
|
|||
|
||||
Host_UpdateMainFrame(); // Disable any menus or buttons at boot
|
||||
|
||||
s_window_handle = Host_GetRenderHandle();
|
||||
|
||||
// Start the emu thread
|
||||
s_emu_thread = std::thread(EmuThread, std::move(boot));
|
||||
s_emu_thread = std::thread(EmuThread, std::move(boot), wsi);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -389,7 +386,7 @@ static void FifoPlayerThread(const std::optional<std::string>& savestate_path,
|
|||
// Initialize and create emulation thread
|
||||
// Call browser: Init():s_emu_thread().
|
||||
// See the BootManager.cpp file description for a complete call schedule.
|
||||
static void EmuThread(std::unique_ptr<BootParameters> boot)
|
||||
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi)
|
||||
{
|
||||
const SConfig& core_parameter = SConfig::GetInstance();
|
||||
s_is_booting.Set();
|
||||
|
@ -441,7 +438,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
|
|||
g_video_backend->InitBackendInfo();
|
||||
g_Config.Refresh();
|
||||
|
||||
if (!g_video_backend->Initialize(s_window_handle))
|
||||
if (!g_video_backend->Initialize(wsi))
|
||||
{
|
||||
PanicAlert("Failed to initialize video backend!");
|
||||
return;
|
||||
|
@ -462,7 +459,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
|
|||
bool init_controllers = false;
|
||||
if (!g_controller_interface.IsInit())
|
||||
{
|
||||
g_controller_interface.Initialize(s_window_handle);
|
||||
g_controller_interface.Initialize(wsi.display_connection);
|
||||
Pad::Initialize();
|
||||
Keyboard::Initialize();
|
||||
init_controllers = true;
|
||||
|
@ -958,4 +955,4 @@ void DoFrameStep()
|
|||
}
|
||||
}
|
||||
|
||||
} // Core
|
||||
} // namespace Core
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
|
||||
struct BootParameters;
|
||||
struct WindowSystemInfo;
|
||||
|
||||
namespace Core
|
||||
{
|
||||
|
@ -35,7 +36,7 @@ enum class State
|
|||
Starting,
|
||||
};
|
||||
|
||||
bool Init(std::unique_ptr<BootParameters> boot);
|
||||
bool Init(std::unique_ptr<BootParameters> boot, const WindowSystemInfo& wsi);
|
||||
void Stop();
|
||||
void Shutdown();
|
||||
|
||||
|
@ -104,4 +105,4 @@ void HostDispatchJobs();
|
|||
|
||||
void DoFrameStep();
|
||||
|
||||
} // namespace
|
||||
} // namespace Core
|
||||
|
|
|
@ -44,6 +44,3 @@ void Host_UpdateMainFrame();
|
|||
void Host_UpdateTitle(const std::string& title);
|
||||
void Host_YieldToUI();
|
||||
void Host_UpdateProgressDialog(const char* caption, int position, int total);
|
||||
|
||||
// TODO (neobrain): Remove this from host!
|
||||
void* Host_GetRenderHandle();
|
||||
|
|
|
@ -71,6 +71,10 @@ public:
|
|||
}
|
||||
virtual void Shutdown() {}
|
||||
virtual ~Platform() {}
|
||||
|
||||
virtual WindowSystemType GetWindowSystem() const { return WindowSystemType::Headless; }
|
||||
virtual void* GetDisplayHandle() const { return nullptr; }
|
||||
virtual void* GetWindowHandle() const { return nullptr; }
|
||||
};
|
||||
|
||||
static Platform* platform;
|
||||
|
@ -91,12 +95,6 @@ void Host_Message(HostMessageID id)
|
|||
updateMainFrameEvent.Set();
|
||||
}
|
||||
|
||||
static void* s_window_handle = nullptr;
|
||||
void* Host_GetRenderHandle()
|
||||
{
|
||||
return s_window_handle;
|
||||
}
|
||||
|
||||
void Host_UpdateTitle(const std::string& title)
|
||||
{
|
||||
platform->SetTitle(title);
|
||||
|
@ -187,7 +185,6 @@ class PlatformX11 : public Platform
|
|||
}
|
||||
XMapRaised(dpy, win);
|
||||
XFlush(dpy);
|
||||
s_window_handle = (void*)win;
|
||||
|
||||
if (SConfig::GetInstance().bDisableScreenSaver)
|
||||
X11Utils::InhibitScreensaver(win, true);
|
||||
|
@ -213,9 +210,6 @@ class PlatformX11 : public Platform
|
|||
void MainLoop() override
|
||||
{
|
||||
bool fullscreen = SConfig::GetInstance().bFullscreen;
|
||||
int last_window_width = SConfig::GetInstance().iRenderWindowWidth;
|
||||
int last_window_height = SConfig::GetInstance().iRenderWindowHeight;
|
||||
|
||||
if (fullscreen)
|
||||
{
|
||||
rendererIsFullscreen = X11Utils::ToggleFullscreen(dpy, win);
|
||||
|
@ -315,14 +309,8 @@ class PlatformX11 : public Platform
|
|||
break;
|
||||
case ConfigureNotify:
|
||||
{
|
||||
if (last_window_width != event.xconfigure.width ||
|
||||
last_window_height != event.xconfigure.height)
|
||||
{
|
||||
last_window_width = event.xconfigure.width;
|
||||
last_window_height = event.xconfigure.height;
|
||||
if (g_renderer)
|
||||
g_renderer->ResizeSurface(last_window_width, last_window_height);
|
||||
}
|
||||
if (g_renderer)
|
||||
g_renderer->ResizeSurface();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -354,6 +342,10 @@ class PlatformX11 : public Platform
|
|||
|
||||
XCloseDisplay(dpy);
|
||||
}
|
||||
|
||||
WindowSystemType GetWindowSystem() const override { return WindowSystemType::X11; }
|
||||
void* GetDisplayHandle() const override { return static_cast<void*>(dpy); }
|
||||
void* GetWindowHandle() const override { return reinterpret_cast<void*>(win); }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -433,7 +425,10 @@ int main(int argc, char* argv[])
|
|||
|
||||
DolphinAnalytics::Instance()->ReportDolphinStart("nogui");
|
||||
|
||||
if (!BootManager::BootCore(std::move(boot)))
|
||||
WindowSystemInfo wsi(platform->GetWindowSystem(), platform->GetDisplayHandle(),
|
||||
platform->GetWindowHandle());
|
||||
|
||||
if (!BootManager::BootCore(std::move(boot), wsi))
|
||||
{
|
||||
fprintf(stderr, "Could not boot the specified file\n");
|
||||
return 1;
|
||||
|
|
|
@ -30,14 +30,10 @@ Host* Host::GetInstance()
|
|||
return s_instance;
|
||||
}
|
||||
|
||||
void* Host::GetRenderHandle()
|
||||
{
|
||||
return m_render_handle;
|
||||
}
|
||||
|
||||
void Host::SetRenderHandle(void* handle)
|
||||
{
|
||||
m_render_handle = handle;
|
||||
if (g_renderer)
|
||||
g_renderer->ChangeSurface(handle);
|
||||
}
|
||||
|
||||
bool Host::GetRenderFocus()
|
||||
|
@ -72,7 +68,7 @@ void Host::SetRenderFullscreen(bool fullscreen)
|
|||
void Host::ResizeSurface(int new_width, int new_height)
|
||||
{
|
||||
if (g_renderer)
|
||||
g_renderer->ResizeSurface(new_width, new_height);
|
||||
g_renderer->ResizeSurface();
|
||||
}
|
||||
|
||||
void Host_Message(HostMessageID id)
|
||||
|
@ -94,11 +90,6 @@ void Host_UpdateTitle(const std::string& title)
|
|||
emit Host::GetInstance()->RequestTitle(QString::fromStdString(title));
|
||||
}
|
||||
|
||||
void* Host_GetRenderHandle()
|
||||
{
|
||||
return Host::GetInstance()->GetRenderHandle();
|
||||
}
|
||||
|
||||
bool Host_RendererHasFocus()
|
||||
{
|
||||
return Host::GetInstance()->GetRenderFocus();
|
||||
|
|
|
@ -20,7 +20,6 @@ class Host final : public QObject
|
|||
public:
|
||||
static Host* GetInstance();
|
||||
|
||||
void* GetRenderHandle();
|
||||
bool GetRenderFocus();
|
||||
bool GetRenderFullscreen();
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QProgressDialog>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWindow>
|
||||
|
||||
#include <future>
|
||||
#include <optional>
|
||||
|
@ -26,7 +27,12 @@
|
|||
#include "QtUtils/SignalDaemon.h"
|
||||
#endif
|
||||
|
||||
#ifndef WIN32
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
#include "Common/Version.h"
|
||||
#include "Common/WindowSystemInfo.h"
|
||||
|
||||
#include "Core/Boot/Boot.h"
|
||||
#include "Core/BootManager.h"
|
||||
|
@ -98,7 +104,6 @@
|
|||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
#if defined(HAVE_XRANDR) && HAVE_XRANDR
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include "UICommon/X11Utils.h"
|
||||
#endif
|
||||
|
||||
|
@ -119,6 +124,45 @@ static void InstallSignalHandler()
|
|||
}
|
||||
#endif
|
||||
|
||||
static WindowSystemType GetWindowSystemType()
|
||||
{
|
||||
// Determine WSI type based on Qt platform.
|
||||
QString platform_name = QGuiApplication::platformName();
|
||||
if (platform_name == QStringLiteral("windows"))
|
||||
return WindowSystemType::Windows;
|
||||
else if (platform_name == QStringLiteral("cocoa"))
|
||||
return WindowSystemType::MacOS;
|
||||
else if (platform_name == QStringLiteral("xcb"))
|
||||
return WindowSystemType::X11;
|
||||
else if (platform_name == QStringLiteral("wayland"))
|
||||
return WindowSystemType::Wayland;
|
||||
|
||||
QMessageBox::critical(
|
||||
nullptr, QStringLiteral("Error"),
|
||||
QString::asprintf("Unknown Qt platform: %s", platform_name.toStdString().c_str()));
|
||||
return WindowSystemType::Headless;
|
||||
}
|
||||
|
||||
static WindowSystemInfo GetWindowSystemInfo(QWindow* window)
|
||||
{
|
||||
WindowSystemInfo wsi;
|
||||
wsi.type = GetWindowSystemType();
|
||||
|
||||
// Our Win32 Qt external doesn't have the private API.
|
||||
#if defined(WIN32) || defined(__APPLE__)
|
||||
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
|
||||
#else
|
||||
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
|
||||
wsi.display_connection = pni->nativeResourceForWindow("display", window);
|
||||
if (wsi.type == WindowSystemType::Wayland)
|
||||
wsi.render_surface = window ? pni->nativeResourceForWindow("surface", window) : nullptr;
|
||||
else
|
||||
wsi.render_surface = window ? reinterpret_cast<void*>(window->winId()) : nullptr;
|
||||
#endif
|
||||
|
||||
return wsi;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<BootParameters> boot_parameters) : QMainWindow(nullptr)
|
||||
{
|
||||
setWindowTitle(QString::fromStdString(Common::scm_rev_str));
|
||||
|
@ -797,14 +841,19 @@ void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
|
|||
m_pending_boot = std::move(parameters);
|
||||
return;
|
||||
}
|
||||
|
||||
// We need the render widget before booting.
|
||||
ShowRenderWidget();
|
||||
|
||||
// Boot up, show an error if it fails to load the game.
|
||||
if (!BootManager::BootCore(std::move(parameters)))
|
||||
if (!BootManager::BootCore(std::move(parameters),
|
||||
GetWindowSystemInfo(m_render_widget->windowHandle())))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok);
|
||||
HideRenderWidget();
|
||||
return;
|
||||
}
|
||||
|
||||
ShowRenderWidget();
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
if (!NetPlay::IsNetPlayRunning())
|
||||
Discord::UpdateDiscordPresence();
|
||||
|
|
|
@ -55,8 +55,6 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
|||
connect(this, &RenderWidget::FocusChanged, Host::GetInstance(), &Host::SetRenderFocus,
|
||||
Qt::DirectConnection);
|
||||
|
||||
emit HandleChanged((void*)winId());
|
||||
|
||||
m_mouse_timer = new QTimer(this);
|
||||
connect(m_mouse_timer, &QTimer::timeout, this, &RenderWidget::HandleCursorTimer);
|
||||
m_mouse_timer->setSingleShot(true);
|
||||
|
@ -70,6 +68,9 @@ RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
|||
OnKeepOnTopChanged(Settings::Instance().IsKeepWindowOnTopEnabled());
|
||||
m_mouse_timer->start(MOUSE_HIDE_DELAY);
|
||||
|
||||
// We need a native window to render into.
|
||||
setAttribute(Qt::WA_NativeWindow);
|
||||
|
||||
SetFillBackground(true);
|
||||
}
|
||||
|
||||
|
@ -144,7 +145,7 @@ bool RenderWidget::event(QEvent* event)
|
|||
}
|
||||
break;
|
||||
case QEvent::WinIdChange:
|
||||
emit HandleChanged((void*)winId());
|
||||
emit HandleChanged(reinterpret_cast<void*>(winId()));
|
||||
break;
|
||||
case QEvent::WindowActivate:
|
||||
if (SConfig::GetInstance().m_PauseOnFocusLost && Core::GetState() == Core::State::Paused)
|
||||
|
|
|
@ -24,8 +24,10 @@ if ((DEFINED CMAKE_ANDROID_ARCH_ABI AND CMAKE_ANDROID_ARCH_ABI MATCHES "x86|x86_
|
|||
target_link_libraries(uicommon PRIVATE bdisasm)
|
||||
endif()
|
||||
|
||||
if(USE_X11)
|
||||
if(ENABLE_X11 AND X11_FOUND)
|
||||
target_include_directories(uicommon PRIVATE ${X11_INCLUDE_DIR})
|
||||
target_sources(uicommon PRIVATE X11Utils.cpp)
|
||||
target_link_libraries(uicommon PUBLIC ${XRANDR_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(LIBUSB_FOUND)
|
||||
|
|
|
@ -429,10 +429,13 @@ HRESULT Create(HWND wnd)
|
|||
// prevent DXGI from responding to Alt+Enter, unfortunately DXGI_MWA_NO_ALT_ENTER
|
||||
// does not work so we disable all monitoring of window messages. However this
|
||||
// may make it more difficult for DXGI to handle display mode changes.
|
||||
hr = s_dxgi_factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
|
||||
if (FAILED(hr))
|
||||
MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"),
|
||||
MB_OK | MB_ICONERROR);
|
||||
if (wnd)
|
||||
{
|
||||
hr = s_dxgi_factory->MakeWindowAssociation(wnd, DXGI_MWA_NO_WINDOW_CHANGES);
|
||||
if (FAILED(hr))
|
||||
MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 11 backend"),
|
||||
MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
SetDebugObjectName(context, "device context");
|
||||
|
||||
|
|
|
@ -225,6 +225,11 @@ void Renderer::Create3DVisionTexture(int width, int height)
|
|||
DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, &sys_data);
|
||||
}
|
||||
|
||||
bool Renderer::IsHeadless() const
|
||||
{
|
||||
return D3D::swapchain == nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
|
||||
{
|
||||
return std::make_unique<DXTexture>(config);
|
||||
|
@ -698,12 +703,12 @@ void Renderer::CheckForSurfaceChange()
|
|||
if (!m_surface_changed.TestAndClear())
|
||||
return;
|
||||
|
||||
m_surface_handle = m_new_surface_handle;
|
||||
m_new_surface_handle = nullptr;
|
||||
|
||||
SAFE_RELEASE(m_screenshot_texture);
|
||||
SAFE_RELEASE(m_3d_vision_texture);
|
||||
|
||||
D3D::Reset(reinterpret_cast<HWND>(m_new_surface_handle));
|
||||
m_new_surface_handle = nullptr;
|
||||
|
||||
UpdateBackbufferSize();
|
||||
}
|
||||
|
||||
|
@ -714,9 +719,6 @@ void Renderer::CheckForSurfaceResize()
|
|||
if (!m_surface_resized.TestAndClear() && !exclusive_fullscreen_changed)
|
||||
return;
|
||||
|
||||
m_backbuffer_width = m_new_backbuffer_width;
|
||||
m_backbuffer_height = m_new_backbuffer_height;
|
||||
|
||||
SAFE_RELEASE(m_screenshot_texture);
|
||||
SAFE_RELEASE(m_3d_vision_texture);
|
||||
m_last_fullscreen_state = fullscreen_state;
|
||||
|
|
|
@ -22,6 +22,9 @@ public:
|
|||
~Renderer() override;
|
||||
|
||||
StateCache& GetStateCache() { return m_state_cache; }
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace DX11
|
|||
{
|
||||
class VideoBackend : public VideoBackendBase
|
||||
{
|
||||
bool Initialize(void*) override;
|
||||
bool Initialize(const WindowSystemInfo& wsi) override;
|
||||
void Shutdown() override;
|
||||
|
||||
std::string GetName() const override;
|
||||
|
@ -19,4 +19,4 @@ class VideoBackend : public VideoBackendBase
|
|||
|
||||
void InitBackendInfo() override;
|
||||
};
|
||||
}
|
||||
} // namespace DX11
|
||||
|
|
|
@ -127,14 +127,11 @@ void VideoBackend::InitBackendInfo()
|
|||
DX11::D3D::UnloadD3D();
|
||||
}
|
||||
|
||||
bool VideoBackend::Initialize(void* window_handle)
|
||||
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
||||
{
|
||||
if (window_handle == nullptr)
|
||||
return false;
|
||||
|
||||
InitializeShared();
|
||||
|
||||
if (FAILED(D3D::Create(reinterpret_cast<HWND>(window_handle))))
|
||||
if (FAILED(D3D::Create(reinterpret_cast<HWND>(wsi.render_surface))))
|
||||
{
|
||||
PanicAlert("Failed to create D3D device.");
|
||||
return false;
|
||||
|
@ -188,4 +185,4 @@ void VideoBackend::Shutdown()
|
|||
|
||||
D3D::Close();
|
||||
}
|
||||
}
|
||||
} // namespace DX11
|
||||
|
|
|
@ -54,7 +54,7 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.AAModes = {1};
|
||||
}
|
||||
|
||||
bool VideoBackend::Initialize(void* window_handle)
|
||||
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
||||
{
|
||||
InitializeShared();
|
||||
|
||||
|
@ -80,4 +80,4 @@ void VideoBackend::Shutdown()
|
|||
|
||||
ShutdownShared();
|
||||
}
|
||||
}
|
||||
} // namespace Null
|
||||
|
|
|
@ -24,6 +24,11 @@ Renderer::~Renderer()
|
|||
UpdateActiveConfig();
|
||||
}
|
||||
|
||||
bool Renderer::IsHeadless() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config)
|
||||
{
|
||||
return std::make_unique<NullTexture>(config);
|
||||
|
|
|
@ -14,6 +14,8 @@ public:
|
|||
Renderer();
|
||||
~Renderer() override;
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Null
|
|||
{
|
||||
class VideoBackend : public VideoBackendBase
|
||||
{
|
||||
bool Initialize(void* window_handle) override;
|
||||
bool Initialize(const WindowSystemInfo& wsi) override;
|
||||
void Shutdown() override;
|
||||
|
||||
std::string GetName() const override { return "Null"; }
|
||||
|
@ -22,4 +22,4 @@ class VideoBackend : public VideoBackendBase
|
|||
}
|
||||
void InitBackendInfo() override;
|
||||
};
|
||||
}
|
||||
} // namespace Null
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
|
@ -414,7 +413,7 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms
|
|||
glBindBuffer(GL_ARRAY_BUFFER,
|
||||
static_cast<VertexManager*>(g_vertex_manager.get())->GetVertexBufferHandle());
|
||||
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
|
||||
if (!static_cast<Renderer*>(g_renderer.get())->IsGLES())
|
||||
glEnable(GL_PROGRAM_POINT_SIZE);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/OGL/FramebufferManager.h"
|
||||
|
|
|
@ -6,25 +6,23 @@
|
|||
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "Common/GL/GLExtensions/GLExtensions.h"
|
||||
|
||||
#include "VideoBackends/OGL/PerfQuery.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
std::unique_ptr<PerfQueryBase> GetPerfQuery()
|
||||
{
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 &&
|
||||
GLExtensions::Supports("GL_NV_occlusion_query_samples"))
|
||||
const bool is_gles = static_cast<Renderer*>(g_renderer.get())->IsGLES();
|
||||
if (is_gles && GLExtensions::Supports("GL_NV_occlusion_query_samples"))
|
||||
return std::make_unique<PerfQueryGLESNV>();
|
||||
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
|
||||
else if (is_gles)
|
||||
return std::make_unique<PerfQueryGL>(GL_ANY_SAMPLES_PASSED);
|
||||
|
||||
return std::make_unique<PerfQueryGL>(GL_SAMPLES_PASSED);
|
||||
else
|
||||
return std::make_unique<PerfQueryGL>(GL_SAMPLES_PASSED);
|
||||
}
|
||||
|
||||
PerfQuery::PerfQuery() : m_query_read_pos()
|
||||
|
@ -266,4 +264,4 @@ void PerfQueryGLESNV::FlushResults()
|
|||
FlushOne();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace OGL
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
@ -805,7 +805,8 @@ void ProgramShaderCache::CreateHeader()
|
|||
|
||||
bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
|
||||
{
|
||||
std::unique_ptr<cInterfaceBase> context = GLInterface->CreateSharedContext();
|
||||
std::unique_ptr<GLContext> context =
|
||||
static_cast<Renderer*>(g_renderer.get())->GetMainGLContext()->CreateSharedContext();
|
||||
if (!context)
|
||||
{
|
||||
PanicAlert("Failed to create shared context for shader compiling.");
|
||||
|
@ -818,20 +819,20 @@ bool SharedContextAsyncShaderCompiler::WorkerThreadInitMainThread(void** param)
|
|||
|
||||
bool SharedContextAsyncShaderCompiler::WorkerThreadInitWorkerThread(void* param)
|
||||
{
|
||||
cInterfaceBase* context = static_cast<cInterfaceBase*>(param);
|
||||
GLContext* context = static_cast<GLContext*>(param);
|
||||
if (!context->MakeCurrent())
|
||||
return false;
|
||||
|
||||
s_is_shared_context = true;
|
||||
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
|
||||
GLUtil::EnablePrimitiveRestart();
|
||||
GLUtil::EnablePrimitiveRestart(context);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SharedContextAsyncShaderCompiler::WorkerThreadExit(void* param)
|
||||
{
|
||||
cInterfaceBase* context = static_cast<cInterfaceBase*>(param);
|
||||
GLContext* context = static_cast<GLContext*>(param);
|
||||
context->ClearCurrent();
|
||||
delete context;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "Common/Assert.h"
|
||||
#include "Common/Atomic.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "Common/Logging/LogManager.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
@ -353,9 +353,10 @@ static void InitDriverInfo()
|
|||
}
|
||||
|
||||
// Init functions
|
||||
Renderer::Renderer()
|
||||
: ::Renderer(static_cast<int>(std::max(GLInterface->GetBackBufferWidth(), 1u)),
|
||||
static_cast<int>(std::max(GLInterface->GetBackBufferHeight(), 1u)))
|
||||
Renderer::Renderer(std::unique_ptr<GLContext> main_gl_context)
|
||||
: ::Renderer(static_cast<int>(std::max(main_gl_context->GetBackBufferWidth(), 1u)),
|
||||
static_cast<int>(std::max(main_gl_context->GetBackBufferHeight(), 1u))),
|
||||
m_main_gl_context(std::move(main_gl_context))
|
||||
{
|
||||
bool bSuccess = true;
|
||||
|
||||
|
@ -365,7 +366,7 @@ Renderer::Renderer()
|
|||
|
||||
InitDriverInfo();
|
||||
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
|
||||
if (!m_main_gl_context->IsGLES())
|
||||
{
|
||||
if (!GLExtensions::Supports("GL_ARB_framebuffer_object"))
|
||||
{
|
||||
|
@ -500,7 +501,7 @@ Renderer::Renderer()
|
|||
g_Config.backend_info.bSupportsBPTCTextures =
|
||||
GLExtensions::Supports("GL_ARB_texture_compression_bptc");
|
||||
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
|
||||
if (m_main_gl_context->IsGLES())
|
||||
{
|
||||
g_ogl_config.SupportedESPointSize =
|
||||
GLExtensions::Supports("GL_OES_geometry_point_size") ?
|
||||
|
@ -730,10 +731,9 @@ Renderer::Renderer()
|
|||
|
||||
if (!g_ogl_config.bSupportsGLBufferStorage && !g_ogl_config.bSupportsGLPinnedMemory)
|
||||
{
|
||||
OSD::AddMessage(
|
||||
StringFromFormat("Your OpenGL driver does not support %s_buffer_storage.",
|
||||
GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 ? "EXT" : "ARB"),
|
||||
60000);
|
||||
OSD::AddMessage(StringFromFormat("Your OpenGL driver does not support %s_buffer_storage.",
|
||||
m_main_gl_context->IsGLES() ? "EXT" : "ARB"),
|
||||
60000);
|
||||
OSD::AddMessage("This device's performance will be terrible.", 60000);
|
||||
OSD::AddMessage("Please ask your device vendor for an updated OpenGL driver.", 60000);
|
||||
}
|
||||
|
@ -761,7 +761,7 @@ Renderer::Renderer()
|
|||
// Handle VSync on/off
|
||||
s_vsync = g_ActiveConfig.IsVSync();
|
||||
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
|
||||
GLInterface->SwapInterval(s_vsync);
|
||||
m_main_gl_context->SwapInterval(s_vsync);
|
||||
|
||||
// Because of the fixed framebuffer size we need to disable the resolution
|
||||
// options while running
|
||||
|
@ -796,7 +796,7 @@ Renderer::Renderer()
|
|||
glClearDepthf(1.0f);
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart)
|
||||
GLUtil::EnablePrimitiveRestart();
|
||||
GLUtil::EnablePrimitiveRestart(m_main_gl_context.get());
|
||||
IndexGenerator::Init();
|
||||
|
||||
UpdateActiveConfig();
|
||||
|
@ -805,6 +805,11 @@ Renderer::Renderer()
|
|||
|
||||
Renderer::~Renderer() = default;
|
||||
|
||||
bool Renderer::IsHeadless() const
|
||||
{
|
||||
return m_main_gl_context->IsHeadless();
|
||||
}
|
||||
|
||||
void Renderer::Shutdown()
|
||||
{
|
||||
::Renderer::Shutdown();
|
||||
|
@ -1044,7 +1049,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
|||
|
||||
std::unique_ptr<u32[]> colorMap(new u32[targetPixelRcWidth * targetPixelRcHeight]);
|
||||
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
|
||||
if (IsGLES())
|
||||
// XXX: Swap colours
|
||||
glReadPixels(targetPixelRc.left, targetPixelRc.bottom, targetPixelRcWidth,
|
||||
targetPixelRcHeight, GL_RGBA, GL_UNSIGNED_BYTE, colorMap.get());
|
||||
|
@ -1351,7 +1356,7 @@ void Renderer::ApplyBlendingState(const BlendingState state, bool force)
|
|||
GL_XOR, GL_OR, GL_NOR, GL_EQUIV, GL_INVERT, GL_OR_REVERSE,
|
||||
GL_COPY_INVERTED, GL_OR_INVERTED, GL_NAND, GL_SET};
|
||||
|
||||
if (GLInterface->GetMode() != GLInterfaceMode::MODE_OPENGL)
|
||||
if (IsGLES())
|
||||
{
|
||||
// Logic ops aren't available in GLES3
|
||||
}
|
||||
|
@ -1421,7 +1426,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
|||
OSD::DrawMessages();
|
||||
|
||||
// Swap the back and front buffers, presenting the image.
|
||||
GLInterface->Swap();
|
||||
m_main_gl_context->Swap();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1466,7 +1471,7 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region
|
|||
{
|
||||
s_vsync = g_ActiveConfig.IsVSync();
|
||||
if (!DriverDetails::HasBug(DriverDetails::BUG_BROKEN_VSYNC))
|
||||
GLInterface->SwapInterval(s_vsync);
|
||||
m_main_gl_context->SwapInterval(s_vsync);
|
||||
}
|
||||
|
||||
// Clean out old stuff from caches. It's not worth it to clean out the shader caches.
|
||||
|
@ -1500,14 +1505,12 @@ void Renderer::CheckForSurfaceChange()
|
|||
if (!m_surface_changed.TestAndClear())
|
||||
return;
|
||||
|
||||
m_surface_handle = m_new_surface_handle;
|
||||
m_main_gl_context->UpdateSurface(m_new_surface_handle);
|
||||
m_new_surface_handle = nullptr;
|
||||
GLInterface->UpdateHandle(m_surface_handle);
|
||||
GLInterface->UpdateSurface();
|
||||
|
||||
// With a surface change, the window likely has new dimensions.
|
||||
m_backbuffer_width = GLInterface->GetBackBufferWidth();
|
||||
m_backbuffer_height = GLInterface->GetBackBufferHeight();
|
||||
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
|
||||
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
|
||||
}
|
||||
|
||||
void Renderer::CheckForSurfaceResize()
|
||||
|
@ -1515,9 +1518,9 @@ void Renderer::CheckForSurfaceResize()
|
|||
if (!m_surface_resized.TestAndClear())
|
||||
return;
|
||||
|
||||
GLInterface->Update();
|
||||
m_backbuffer_width = m_new_backbuffer_width;
|
||||
m_backbuffer_height = m_new_backbuffer_height;
|
||||
m_main_gl_context->Update();
|
||||
m_backbuffer_width = m_main_gl_context->GetBackBufferWidth();
|
||||
m_backbuffer_height = m_main_gl_context->GetBackBufferHeight();
|
||||
}
|
||||
|
||||
void Renderer::DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc,
|
||||
|
@ -1538,7 +1541,7 @@ void Renderer::ResetAPIState()
|
|||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
|
||||
if (!IsGLES())
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
if (g_ActiveConfig.backend_info.bSupportsDepthClamp)
|
||||
{
|
||||
|
@ -1717,4 +1720,4 @@ std::unique_ptr<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCom
|
|||
{
|
||||
return std::make_unique<SharedContextAsyncShaderCompiler>();
|
||||
}
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
#include <array>
|
||||
#include <string>
|
||||
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/GL/GLExtensions/GLExtensions.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
struct XFBSourceBase;
|
||||
|
@ -81,9 +82,11 @@ extern VideoConfig g_ogl_config;
|
|||
class Renderer : public ::Renderer
|
||||
{
|
||||
public:
|
||||
Renderer();
|
||||
Renderer(std::unique_ptr<GLContext> main_gl_context);
|
||||
~Renderer() override;
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
void Init();
|
||||
void Shutdown() override;
|
||||
|
||||
|
@ -141,6 +144,10 @@ public:
|
|||
|
||||
std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler() override;
|
||||
|
||||
// Only call methods from this on the GPU thread.
|
||||
GLContext* GetMainGLContext() const { return m_main_gl_context.get(); }
|
||||
bool IsGLES() const { return m_main_gl_context->IsGLES(); }
|
||||
|
||||
private:
|
||||
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
|
||||
const TargetRectangle& targetPixelRc, const void* data);
|
||||
|
@ -159,10 +166,11 @@ private:
|
|||
void ApplyDepthState(const DepthState state, bool force = false);
|
||||
void UploadUtilityUniforms(const void* uniforms, u32 uniforms_size);
|
||||
|
||||
std::unique_ptr<GLContext> m_main_gl_context;
|
||||
std::array<const AbstractTexture*, 8> m_bound_textures{};
|
||||
const OGLPipeline* m_graphics_pipeline = nullptr;
|
||||
RasterizationState m_current_rasterization_state = {};
|
||||
DepthState m_current_depth_state = {};
|
||||
BlendingState m_current_blend_state = {};
|
||||
};
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include "VideoBackends/OGL/SamplerCache.h"
|
||||
#include "VideoBackends/OGL/Render.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "VideoCommon/SamplerCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
|
@ -99,7 +99,7 @@ void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params)
|
|||
glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, params.min_lod / 16.f);
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, params.max_lod / 16.f);
|
||||
|
||||
if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL)
|
||||
if (!static_cast<Renderer*>(g_renderer.get())->IsGLES())
|
||||
glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.lod_bias / 256.f);
|
||||
|
||||
if (params.anisotropic_filtering && g_ogl_config.bSupportsAniso)
|
||||
|
@ -117,4 +117,4 @@ void SamplerCache::Clear()
|
|||
p.second = 0;
|
||||
m_cache.clear();
|
||||
}
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include <vector>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#include <string>
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
|
||||
class GLContext;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
class VideoBackend : public VideoBackendBase
|
||||
{
|
||||
bool Initialize(void*) override;
|
||||
bool Initialize(const WindowSystemInfo& wsi) override;
|
||||
void Shutdown() override;
|
||||
|
||||
std::string GetName() const override;
|
||||
|
@ -20,7 +22,7 @@ class VideoBackend : public VideoBackendBase
|
|||
void InitBackendInfo() override;
|
||||
|
||||
private:
|
||||
bool InitializeGLExtensions();
|
||||
bool InitializeGLExtensions(GLContext* context);
|
||||
bool FillBackendInfo();
|
||||
};
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -39,10 +39,12 @@ Make AA apply instantly during gameplay if possible
|
|||
#include <vector>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
|
||||
#include "VideoBackends/OGL/BoundingBox.h"
|
||||
#include "VideoBackends/OGL/PerfQuery.h"
|
||||
#include "VideoBackends/OGL/ProgramShaderCache.h"
|
||||
|
@ -66,7 +68,7 @@ std::string VideoBackend::GetName() const
|
|||
|
||||
std::string VideoBackend::GetDisplayName() const
|
||||
{
|
||||
if (GLInterface != nullptr && GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3)
|
||||
if (g_renderer && static_cast<Renderer*>(g_renderer.get())->IsGLES())
|
||||
return _trans("OpenGL ES");
|
||||
else
|
||||
return _trans("OpenGL");
|
||||
|
@ -108,10 +110,10 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.AAModes = {1, 2, 4, 8};
|
||||
}
|
||||
|
||||
bool VideoBackend::InitializeGLExtensions()
|
||||
bool VideoBackend::InitializeGLExtensions(GLContext* context)
|
||||
{
|
||||
// Init extension support.
|
||||
if (!GLExtensions::Init())
|
||||
if (!GLExtensions::Init(context))
|
||||
{
|
||||
// OpenGL 2.0 is required for all shader based drawings. There is no way to get this by
|
||||
// extensions
|
||||
|
@ -157,20 +159,20 @@ bool VideoBackend::FillBackendInfo()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool VideoBackend::Initialize(void* window_handle)
|
||||
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
||||
{
|
||||
InitializeShared();
|
||||
|
||||
GLUtil::InitInterface();
|
||||
GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
|
||||
if (!GLInterface->Create(window_handle, g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer))
|
||||
std::unique_ptr<GLContext> main_gl_context =
|
||||
GLContext::Create(wsi, g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer, true, false,
|
||||
Config::Get(Config::GFX_PREFER_GLES));
|
||||
if (!main_gl_context)
|
||||
return false;
|
||||
|
||||
GLInterface->MakeCurrent();
|
||||
if (!InitializeGLExtensions() || !FillBackendInfo())
|
||||
if (!InitializeGLExtensions(main_gl_context.get()) || !FillBackendInfo())
|
||||
return false;
|
||||
|
||||
g_renderer = std::make_unique<Renderer>();
|
||||
g_renderer = std::make_unique<Renderer>(std::move(main_gl_context));
|
||||
g_vertex_manager = std::make_unique<VertexManager>();
|
||||
g_perf_query = GetPerfQuery();
|
||||
ProgramShaderCache::Init();
|
||||
|
@ -196,9 +198,6 @@ void VideoBackend::Shutdown()
|
|||
g_perf_query.reset();
|
||||
g_vertex_manager.reset();
|
||||
g_renderer.reset();
|
||||
GLInterface->ClearCurrent();
|
||||
GLInterface->Shutdown();
|
||||
GLInterface.reset();
|
||||
ShutdownShared();
|
||||
}
|
||||
}
|
||||
} // namespace OGL
|
||||
|
|
|
@ -4,52 +4,51 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
#include "Common/GL/GLUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
|
||||
#include "VideoBackends/Software/SWOGLWindow.h"
|
||||
#include "VideoBackends/Software/SWTexture.h"
|
||||
|
||||
std::unique_ptr<SWOGLWindow> SWOGLWindow::s_instance;
|
||||
SWOGLWindow::SWOGLWindow() = default;
|
||||
SWOGLWindow::~SWOGLWindow() = default;
|
||||
|
||||
void SWOGLWindow::Init(void* window_handle)
|
||||
std::unique_ptr<SWOGLWindow> SWOGLWindow::Create(const WindowSystemInfo& wsi)
|
||||
{
|
||||
GLUtil::InitInterface();
|
||||
GLInterface->SetMode(GLInterfaceMode::MODE_DETECT);
|
||||
if (!GLInterface->Create(window_handle))
|
||||
std::unique_ptr<SWOGLWindow> window = std::unique_ptr<SWOGLWindow>(new SWOGLWindow());
|
||||
if (!window->Initialize(wsi))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GLInterface::Create failed.");
|
||||
PanicAlert("Failed to create OpenGL window");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
s_instance.reset(new SWOGLWindow());
|
||||
return window;
|
||||
}
|
||||
|
||||
void SWOGLWindow::Shutdown()
|
||||
bool SWOGLWindow::IsHeadless() const
|
||||
{
|
||||
GLInterface->Shutdown();
|
||||
GLInterface.reset();
|
||||
|
||||
s_instance.reset();
|
||||
return m_gl_context->IsHeadless();
|
||||
}
|
||||
|
||||
void SWOGLWindow::Prepare()
|
||||
bool SWOGLWindow::Initialize(const WindowSystemInfo& wsi)
|
||||
{
|
||||
if (m_init)
|
||||
return;
|
||||
m_init = true;
|
||||
m_gl_context = GLContext::Create(wsi);
|
||||
if (!m_gl_context)
|
||||
return false;
|
||||
|
||||
// Init extension support.
|
||||
if (!GLExtensions::Init())
|
||||
if (!GLExtensions::Init(m_gl_context.get()))
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GLExtensions::Init failed!Does your video card support OpenGL 2.0?");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
else if (GLExtensions::Version() < 310)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "OpenGL Version %d detected, but at least 3.1 is required.",
|
||||
GLExtensions::Version());
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string frag_shader = "in vec2 TexCoord;\n"
|
||||
|
@ -66,10 +65,9 @@ void SWOGLWindow::Prepare()
|
|||
" TexCoord = vec2(rawpos.x, -rawpos.y);\n"
|
||||
"}\n";
|
||||
|
||||
std::string header = GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL ?
|
||||
"#version 140\n" :
|
||||
"#version 300 es\n"
|
||||
"precision highp float;\n";
|
||||
std::string header = m_gl_context->IsGLES() ? "#version 300 es\n"
|
||||
"precision highp float;\n" :
|
||||
"#version 140\n";
|
||||
|
||||
m_image_program = GLUtil::CompileProgram(header + vertex_shader, header + frag_shader);
|
||||
|
||||
|
@ -83,6 +81,7 @@ void SWOGLWindow::Prepare()
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glGenVertexArrays(1, &m_image_vao);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color)
|
||||
|
@ -93,10 +92,10 @@ void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color)
|
|||
void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region)
|
||||
{
|
||||
SW::SWTexture* sw_image = static_cast<SW::SWTexture*>(image);
|
||||
GLInterface->Update(); // just updates the render window position and the backbuffer size
|
||||
m_gl_context->Update(); // just updates the render window position and the backbuffer size
|
||||
|
||||
GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth();
|
||||
GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight();
|
||||
GLsizei glWidth = (GLsizei)m_gl_context->GetBackBufferWidth();
|
||||
GLsizei glHeight = (GLsizei)m_gl_context->GetBackBufferHeight();
|
||||
|
||||
glViewport(0, 0, glWidth, glHeight);
|
||||
|
||||
|
@ -123,10 +122,5 @@ void SWOGLWindow::ShowImage(AbstractTexture* image, const EFBRectangle& xfb_regi
|
|||
// }
|
||||
m_text.clear();
|
||||
|
||||
GLInterface->Swap();
|
||||
}
|
||||
|
||||
int SWOGLWindow::PeekMessages()
|
||||
{
|
||||
return GLInterface->PeekMessages();
|
||||
m_gl_context->Swap();
|
||||
}
|
||||
|
|
|
@ -11,14 +11,18 @@
|
|||
#include "Common/CommonTypes.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
class GLContext;
|
||||
|
||||
class AbstractTexture;
|
||||
struct WindowSystemInfo;
|
||||
|
||||
class SWOGLWindow
|
||||
{
|
||||
public:
|
||||
static void Init(void* window_handle);
|
||||
static void Shutdown();
|
||||
void Prepare();
|
||||
~SWOGLWindow();
|
||||
|
||||
GLContext* GetContext() const { return m_gl_context.get(); }
|
||||
bool IsHeadless() const;
|
||||
|
||||
// Will be printed on the *next* image
|
||||
void PrintText(const std::string& text, int x, int y, u32 color);
|
||||
|
@ -26,12 +30,13 @@ public:
|
|||
// Image to show, will be swapped immediately
|
||||
void ShowImage(AbstractTexture* image, const EFBRectangle& xfb_region);
|
||||
|
||||
int PeekMessages();
|
||||
|
||||
static std::unique_ptr<SWOGLWindow> s_instance;
|
||||
static std::unique_ptr<SWOGLWindow> Create(const WindowSystemInfo& wsi);
|
||||
|
||||
private:
|
||||
SWOGLWindow() {}
|
||||
SWOGLWindow();
|
||||
|
||||
bool Initialize(const WindowSystemInfo& wsi);
|
||||
|
||||
struct TextData
|
||||
{
|
||||
std::string text;
|
||||
|
@ -40,7 +45,9 @@ private:
|
|||
};
|
||||
std::vector<TextData> m_text;
|
||||
|
||||
bool m_init{false};
|
||||
u32 m_image_program = 0;
|
||||
u32 m_image_texture = 0;
|
||||
u32 m_image_vao = 0;
|
||||
|
||||
u32 m_image_program, m_image_texture, m_image_vao;
|
||||
std::unique_ptr<GLContext> m_gl_context;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
@ -23,11 +24,17 @@
|
|||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
SWRenderer::SWRenderer()
|
||||
: ::Renderer(static_cast<int>(MAX_XFB_WIDTH), static_cast<int>(MAX_XFB_HEIGHT))
|
||||
SWRenderer::SWRenderer(std::unique_ptr<SWOGLWindow> window)
|
||||
: ::Renderer(static_cast<int>(MAX_XFB_WIDTH), static_cast<int>(MAX_XFB_HEIGHT)),
|
||||
m_window(std::move(window))
|
||||
{
|
||||
}
|
||||
|
||||
bool SWRenderer::IsHeadless() const
|
||||
{
|
||||
return m_window->IsHeadless();
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractTexture> SWRenderer::CreateTexture(const TextureConfig& config)
|
||||
{
|
||||
return std::make_unique<SW::SWTexture>(config);
|
||||
|
@ -49,7 +56,7 @@ SWRenderer::CreateFramebuffer(const AbstractTexture* color_attachment,
|
|||
|
||||
void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 color)
|
||||
{
|
||||
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
||||
m_window->PrintText(pstr, left, top, color);
|
||||
}
|
||||
|
||||
class SWShader final : public AbstractShader
|
||||
|
@ -94,7 +101,7 @@ void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_regi
|
|||
if (!IsHeadless())
|
||||
{
|
||||
DrawDebugText();
|
||||
SWOGLWindow::s_instance->ShowImage(texture, xfb_region);
|
||||
m_window->ShowImage(texture, xfb_region);
|
||||
}
|
||||
|
||||
UpdateActiveConfig();
|
||||
|
|
|
@ -4,14 +4,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
class SWOGLWindow;
|
||||
|
||||
class SWRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
SWRenderer();
|
||||
SWRenderer(std::unique_ptr<SWOGLWindow> window);
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
|
@ -40,4 +46,7 @@ public:
|
|||
u32 color, u32 z) override;
|
||||
|
||||
void ReinterpretPixelData(unsigned int convtype) override {}
|
||||
|
||||
private:
|
||||
std::unique_ptr<SWOGLWindow> m_window;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Common/GL/GLContext.h"
|
||||
|
||||
#include "VideoBackends/Software/Clipper.h"
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
|
@ -78,20 +78,19 @@ void VideoSoftware::InitBackendInfo()
|
|||
g_Config.backend_info.AAModes = {1};
|
||||
}
|
||||
|
||||
bool VideoSoftware::Initialize(void* window_handle)
|
||||
bool VideoSoftware::Initialize(const WindowSystemInfo& wsi)
|
||||
{
|
||||
InitializeShared();
|
||||
|
||||
SWOGLWindow::Init(window_handle);
|
||||
std::unique_ptr<SWOGLWindow> window = SWOGLWindow::Create(wsi);
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
Clipper::Init();
|
||||
Rasterizer::Init();
|
||||
DebugUtil::Init();
|
||||
|
||||
GLInterface->MakeCurrent();
|
||||
SWOGLWindow::s_instance->Prepare();
|
||||
|
||||
g_renderer = std::make_unique<SWRenderer>();
|
||||
g_renderer = std::make_unique<SWRenderer>(std::move(window));
|
||||
g_vertex_manager = std::make_unique<SWVertexLoader>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
|
@ -108,7 +107,6 @@ void VideoSoftware::Shutdown()
|
|||
g_renderer->Shutdown();
|
||||
|
||||
DebugUtil::Shutdown();
|
||||
SWOGLWindow::Shutdown();
|
||||
g_framebuffer_manager.reset();
|
||||
g_texture_cache.reset();
|
||||
g_perf_query.reset();
|
||||
|
@ -116,4 +114,4 @@ void VideoSoftware::Shutdown()
|
|||
g_renderer.reset();
|
||||
ShutdownShared();
|
||||
}
|
||||
}
|
||||
} // namespace SW
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace SW
|
|||
{
|
||||
class VideoSoftware : public VideoBackendBase
|
||||
{
|
||||
bool Initialize(void* window_handle) override;
|
||||
bool Initialize(const WindowSystemInfo& wsi) override;
|
||||
void Shutdown() override;
|
||||
|
||||
std::string GetName() const override;
|
||||
|
@ -19,4 +19,4 @@ class VideoSoftware : public VideoBackendBase
|
|||
|
||||
void InitBackendInfo() override;
|
||||
};
|
||||
}
|
||||
} // namespace SW
|
||||
|
|
|
@ -70,6 +70,11 @@ Renderer* Renderer::GetInstance()
|
|||
return static_cast<Renderer*>(g_renderer.get());
|
||||
}
|
||||
|
||||
bool Renderer::IsHeadless() const
|
||||
{
|
||||
return m_swap_chain == nullptr;
|
||||
}
|
||||
|
||||
bool Renderer::Initialize()
|
||||
{
|
||||
BindEFBToStateTracker();
|
||||
|
@ -860,12 +865,9 @@ void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_r
|
|||
|
||||
void Renderer::CheckForSurfaceChange()
|
||||
{
|
||||
if (!m_surface_changed.TestAndClear())
|
||||
if (!m_surface_changed.TestAndClear() || !m_swap_chain)
|
||||
return;
|
||||
|
||||
m_surface_handle = m_new_surface_handle;
|
||||
m_new_surface_handle = nullptr;
|
||||
|
||||
// Submit the current draws up until rendering the XFB.
|
||||
g_command_buffer_mgr->ExecuteCommandBuffer(false, false);
|
||||
g_command_buffer_mgr->WaitForGPUIdle();
|
||||
|
@ -873,37 +875,10 @@ void Renderer::CheckForSurfaceChange()
|
|||
// Clear the present failed flag, since we don't want to resize after recreating.
|
||||
g_command_buffer_mgr->CheckLastPresentFail();
|
||||
|
||||
// Did we previously have a swap chain?
|
||||
if (m_swap_chain)
|
||||
{
|
||||
if (!m_surface_handle)
|
||||
{
|
||||
// If there is no surface now, destroy the swap chain.
|
||||
m_swap_chain.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recreate the surface. If this fails we're in trouble.
|
||||
if (!m_swap_chain->RecreateSurface(m_surface_handle))
|
||||
PanicAlert("Failed to recreate Vulkan surface. Cannot continue.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Previously had no swap chain. So create one.
|
||||
VkSurfaceKHR surface =
|
||||
SwapChain::CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_surface_handle);
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
{
|
||||
m_swap_chain = SwapChain::Create(m_surface_handle, surface, g_ActiveConfig.IsVSync());
|
||||
if (!m_swap_chain)
|
||||
PanicAlert("Failed to create swap chain.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PanicAlert("Failed to create surface.");
|
||||
}
|
||||
}
|
||||
// Recreate the surface. If this fails we're in trouble.
|
||||
if (!m_swap_chain->RecreateSurface(m_new_surface_handle))
|
||||
PanicAlert("Failed to recreate Vulkan surface. Cannot continue.");
|
||||
m_new_surface_handle = nullptr;
|
||||
|
||||
// Handle case where the dimensions are now different.
|
||||
OnSwapChainResized();
|
||||
|
@ -914,9 +889,6 @@ void Renderer::CheckForSurfaceResize()
|
|||
if (!m_surface_resized.TestAndClear())
|
||||
return;
|
||||
|
||||
m_backbuffer_width = m_new_backbuffer_width;
|
||||
m_backbuffer_height = m_new_backbuffer_height;
|
||||
|
||||
// If we don't have a surface, how can we resize the swap chain?
|
||||
// CheckForSurfaceChange should handle this case.
|
||||
if (!m_swap_chain)
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
|
||||
static Renderer* GetInstance();
|
||||
|
||||
bool IsHeadless() const override;
|
||||
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override;
|
||||
std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) override;
|
||||
|
|
|
@ -25,8 +25,9 @@
|
|||
|
||||
namespace Vulkan
|
||||
{
|
||||
SwapChain::SwapChain(void* native_handle, VkSurfaceKHR surface, bool vsync)
|
||||
: m_native_handle(native_handle), m_surface(surface), m_vsync_enabled(vsync)
|
||||
SwapChain::SwapChain(void* display_handle, void* native_handle, VkSurfaceKHR surface, bool vsync)
|
||||
: m_display_handle(display_handle), m_native_handle(native_handle), m_surface(surface),
|
||||
m_vsync_enabled(vsync)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -37,7 +38,7 @@ SwapChain::~SwapChain()
|
|||
DestroySurface();
|
||||
}
|
||||
|
||||
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)
|
||||
VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* display_handle, void* hwnd)
|
||||
{
|
||||
#if defined(VK_USE_PLATFORM_WIN32_KHR)
|
||||
VkWin32SurfaceCreateInfoKHR surface_create_info = {
|
||||
|
@ -59,15 +60,11 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)
|
|||
return surface;
|
||||
|
||||
#elif defined(VK_USE_PLATFORM_XLIB_KHR)
|
||||
// Assuming the display handles are compatible, or shared. This matches what we do in the
|
||||
// GL backend, but it's not ideal.
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
|
||||
VkXlibSurfaceCreateInfoKHR surface_create_info = {
|
||||
VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
||||
nullptr, // const void* pNext
|
||||
0, // VkXlibSurfaceCreateFlagsKHR flags
|
||||
display, // Display* dpy
|
||||
static_cast<Display*>(display_handle), // Display* dpy
|
||||
reinterpret_cast<Window>(hwnd) // Window window
|
||||
};
|
||||
|
||||
|
@ -83,8 +80,7 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)
|
|||
|
||||
#elif defined(VK_USE_PLATFORM_XCB_KHR)
|
||||
// If we ever switch to using xcb, we should pass the display handle as well.
|
||||
Display* display = XOpenDisplay(nullptr);
|
||||
xcb_connection_t* connection = XGetXCBConnection(display);
|
||||
xcb_connection_t* connection = XGetXCBConnection(display_handle);
|
||||
|
||||
VkXcbSurfaceCreateInfoKHR surface_create_info = {
|
||||
VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, // VkStructureType sType
|
||||
|
@ -127,10 +123,11 @@ VkSurfaceKHR SwapChain::CreateVulkanSurface(VkInstance instance, void* hwnd)
|
|||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<SwapChain> SwapChain::Create(void* native_handle, VkSurfaceKHR surface, bool vsync)
|
||||
std::unique_ptr<SwapChain> SwapChain::Create(void* display_handle, void* native_handle,
|
||||
VkSurfaceKHR surface, bool vsync)
|
||||
{
|
||||
std::unique_ptr<SwapChain> swap_chain =
|
||||
std::make_unique<SwapChain>(native_handle, surface, vsync);
|
||||
std::make_unique<SwapChain>(display_handle, native_handle, surface, vsync);
|
||||
|
||||
if (!swap_chain->CreateSwapChain() || !swap_chain->CreateRenderPass() ||
|
||||
!swap_chain->SetupSwapChainImages())
|
||||
|
@ -467,7 +464,8 @@ bool SwapChain::RecreateSurface(void* native_handle)
|
|||
|
||||
// Re-create the surface with the new native handle
|
||||
m_native_handle = native_handle;
|
||||
m_surface = CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), native_handle);
|
||||
m_surface =
|
||||
CreateVulkanSurface(g_vulkan_context->GetVulkanInstance(), m_display_handle, native_handle);
|
||||
if (m_surface == VK_NULL_HANDLE)
|
||||
return false;
|
||||
|
||||
|
@ -499,4 +497,4 @@ void SwapChain::DestroySurface()
|
|||
vkDestroySurfaceKHR(g_vulkan_context->GetVulkanInstance(), m_surface, nullptr);
|
||||
m_surface = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -19,15 +19,17 @@ class ObjectCache;
|
|||
class SwapChain
|
||||
{
|
||||
public:
|
||||
SwapChain(void* native_handle, VkSurfaceKHR surface, bool vsync);
|
||||
SwapChain(void* display_handle, void* native_handle, VkSurfaceKHR surface, bool vsync);
|
||||
~SwapChain();
|
||||
|
||||
// Creates a vulkan-renderable surface for the specified window handle.
|
||||
static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, void* hwnd);
|
||||
static VkSurfaceKHR CreateVulkanSurface(VkInstance instance, void* display_handle, void* hwnd);
|
||||
|
||||
// Create a new swap chain from a pre-existing surface.
|
||||
static std::unique_ptr<SwapChain> Create(void* native_handle, VkSurfaceKHR surface, bool vsync);
|
||||
static std::unique_ptr<SwapChain> Create(void* display_handle, void* native_handle,
|
||||
VkSurfaceKHR surface, bool vsync);
|
||||
|
||||
void* GetDisplayHandle() const { return m_display_handle; }
|
||||
void* GetNativeHandle() const { return m_native_handle; }
|
||||
VkSurfaceKHR GetSurface() const { return m_surface; }
|
||||
VkSurfaceFormatKHR GetSurfaceFormat() const { return m_surface_format; }
|
||||
|
@ -81,6 +83,7 @@ private:
|
|||
VkFramebuffer framebuffer;
|
||||
};
|
||||
|
||||
void* m_display_handle;
|
||||
void* m_native_handle;
|
||||
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
|
||||
VkSurfaceFormatKHR m_surface_format = {};
|
||||
|
|
|
@ -12,11 +12,11 @@ namespace Vulkan
|
|||
class VideoBackend : public VideoBackendBase
|
||||
{
|
||||
public:
|
||||
bool Initialize(void* window_handle) override;
|
||||
bool Initialize(const WindowSystemInfo& wsi) override;
|
||||
void Shutdown() override;
|
||||
|
||||
std::string GetName() const override { return "Vulkan"; }
|
||||
std::string GetDisplayName() const override { return _trans("Vulkan"); }
|
||||
void InitBackendInfo() override;
|
||||
};
|
||||
}
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -89,7 +89,7 @@ static bool ShouldEnableDebugReports(bool enable_validation_layers)
|
|||
return enable_validation_layers || IsHostGPULoggingEnabled();
|
||||
}
|
||||
|
||||
bool VideoBackend::Initialize(void* window_handle)
|
||||
bool VideoBackend::Initialize(const WindowSystemInfo& wsi)
|
||||
{
|
||||
if (!LoadVulkanLibrary())
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ bool VideoBackend::Initialize(void* window_handle)
|
|||
|
||||
// Create Vulkan instance, needed before we can create a surface, or enumerate devices.
|
||||
// We use this instance to fill in backend info, then re-use it for the actual device.
|
||||
bool enable_surface = window_handle != nullptr;
|
||||
bool enable_surface = wsi.render_surface != nullptr;
|
||||
bool enable_debug_reports = ShouldEnableDebugReports(enable_validation_layer);
|
||||
VkInstance instance = VulkanContext::CreateVulkanInstance(enable_surface, enable_debug_reports,
|
||||
enable_validation_layer);
|
||||
|
@ -146,7 +146,7 @@ bool VideoBackend::Initialize(void* window_handle)
|
|||
VkSurfaceKHR surface = VK_NULL_HANDLE;
|
||||
if (enable_surface)
|
||||
{
|
||||
surface = SwapChain::CreateVulkanSurface(instance, window_handle);
|
||||
surface = SwapChain::CreateVulkanSurface(instance, wsi.display_connection, wsi.render_surface);
|
||||
if (surface == VK_NULL_HANDLE)
|
||||
{
|
||||
PanicAlert("Failed to create Vulkan surface.");
|
||||
|
@ -209,7 +209,8 @@ bool VideoBackend::Initialize(void* window_handle)
|
|||
std::unique_ptr<SwapChain> swap_chain;
|
||||
if (surface != VK_NULL_HANDLE)
|
||||
{
|
||||
swap_chain = SwapChain::Create(window_handle, surface, g_Config.IsVSync());
|
||||
swap_chain =
|
||||
SwapChain::Create(wsi.display_connection, wsi.render_surface, surface, g_Config.IsVSync());
|
||||
if (!swap_chain)
|
||||
{
|
||||
PanicAlert("Failed to create Vulkan swap chain.");
|
||||
|
@ -271,4 +272,4 @@ void VideoBackend::Shutdown()
|
|||
ShutdownShared();
|
||||
UnloadVulkanLibrary();
|
||||
}
|
||||
}
|
||||
} // namespace Vulkan
|
||||
|
|
|
@ -35,8 +35,6 @@ const u32 m_os = OS_ALL | OS_LINUX;
|
|||
const u32 m_os = OS_ALL | OS_FREEBSD;
|
||||
#elif __OpenBSD__
|
||||
const u32 m_os = OS_ALL | OS_OPENBSD;
|
||||
#elif __HAIKU__
|
||||
const u32 m_os = OS_ALL | OS_HAIKU;
|
||||
#endif
|
||||
|
||||
static API m_api = API_OPENGL;
|
||||
|
|
|
@ -27,7 +27,6 @@ enum OS
|
|||
OS_ANDROID = (1 << 4),
|
||||
OS_FREEBSD = (1 << 5),
|
||||
OS_OPENBSD = (1 << 6),
|
||||
OS_HAIKU = (1 << 7),
|
||||
};
|
||||
// Enum of known vendors
|
||||
// Tegra and Nvidia are separated out due to such substantial differences
|
||||
|
|
|
@ -86,7 +86,6 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height)
|
|||
if (SConfig::GetInstance().bWii)
|
||||
m_aspect_wide = Config::Get(Config::SYSCONF_WIDESCREEN);
|
||||
|
||||
m_surface_handle = Host_GetRenderHandle();
|
||||
m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits;
|
||||
m_last_efb_multisamples = g_ActiveConfig.iMultisamples;
|
||||
}
|
||||
|
@ -408,7 +407,7 @@ float Renderer::CalculateDrawAspectRatio() const
|
|||
|
||||
bool Renderer::IsHeadless() const
|
||||
{
|
||||
return !m_surface_handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::ChangeSurface(void* new_surface_handle)
|
||||
|
@ -418,11 +417,9 @@ void Renderer::ChangeSurface(void* new_surface_handle)
|
|||
m_surface_changed.Set();
|
||||
}
|
||||
|
||||
void Renderer::ResizeSurface(int new_width, int new_height)
|
||||
void Renderer::ResizeSurface()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_swap_mutex);
|
||||
m_new_backbuffer_width = new_width;
|
||||
m_new_backbuffer_height = new_height;
|
||||
m_surface_resized.Set();
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,8 @@ public:
|
|||
|
||||
using ClearColor = std::array<float, 4>;
|
||||
|
||||
virtual bool IsHeadless() const = 0;
|
||||
|
||||
virtual void SetPipeline(const AbstractPipeline* pipeline) {}
|
||||
virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {}
|
||||
virtual void SetTexture(u32 index, const AbstractTexture* texture) {}
|
||||
|
@ -134,7 +136,6 @@ public:
|
|||
|
||||
const TargetRectangle& GetTargetRectangle() const { return m_target_rectangle; }
|
||||
float CalculateDrawAspectRatio() const;
|
||||
bool IsHeadless() const;
|
||||
|
||||
std::tuple<float, float> ScaleToDisplayAspectRatio(int width, int height) const;
|
||||
void UpdateDrawRectangle();
|
||||
|
@ -182,7 +183,7 @@ public:
|
|||
// 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(int new_width, int new_height);
|
||||
void ResizeSurface();
|
||||
bool UseVertexDepthRange() const;
|
||||
|
||||
virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler();
|
||||
|
@ -228,15 +229,12 @@ protected:
|
|||
// Backbuffer (window) size and render area
|
||||
int m_backbuffer_width = 0;
|
||||
int m_backbuffer_height = 0;
|
||||
int m_new_backbuffer_width = 0;
|
||||
int m_new_backbuffer_height = 0;
|
||||
TargetRectangle m_target_rectangle = {};
|
||||
|
||||
FPSCounter m_fps_counter;
|
||||
|
||||
std::unique_ptr<PostProcessingShaderImplementation> m_post_processor;
|
||||
|
||||
void* m_surface_handle = nullptr;
|
||||
void* m_new_surface_handle = nullptr;
|
||||
Common::Flag m_surface_changed;
|
||||
Common::Flag m_surface_resized;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/WindowSystemInfo.h"
|
||||
#include "VideoCommon/PerfQueryBase.h"
|
||||
|
||||
namespace MMIO
|
||||
|
@ -35,7 +36,7 @@ class VideoBackendBase
|
|||
{
|
||||
public:
|
||||
virtual ~VideoBackendBase() {}
|
||||
virtual bool Initialize(void* window_handle) = 0;
|
||||
virtual bool Initialize(const WindowSystemInfo& wsi) = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
|
||||
virtual std::string GetName() const = 0;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
#include "Core/Host.h"
|
||||
|
||||
void Host_NotifyMapLoaded()
|
||||
|
@ -20,10 +19,6 @@ void Host_RefreshDSPDebuggerWindow()
|
|||
void Host_Message(HostMessageID)
|
||||
{
|
||||
}
|
||||
void* Host_GetRenderHandle()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
void Host_UpdateTitle(const std::string&)
|
||||
{
|
||||
}
|
||||
|
@ -54,7 +49,3 @@ void Host_YieldToUI()
|
|||
void Host_UpdateProgressDialog(const char* caption, int position, int total)
|
||||
{
|
||||
}
|
||||
std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue