Merge pull request #7450 from stenzek/glcontext

GLInterface refactoring/cleanup and runtime platform selection
This commit is contained in:
Stenzek 2018-10-24 14:51:21 +11:00 committed by GitHub
commit c4d1e4adff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
83 changed files with 1304 additions and 1343 deletions

54
CMake/FindEGL.cmake Normal file
View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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()

View File

@ -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>

View File

@ -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>

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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];
}

View File

@ -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());
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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()
{
}

View File

@ -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;
};

View File

@ -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());
}

View File

@ -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;
};

View File

@ -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
}

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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;

View File

@ -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();

View File

@ -20,7 +20,6 @@ class Host final : public QObject
public:
static Host* GetInstance();
void* GetRenderHandle();
bool GetRenderFocus();
bool GetRenderFullscreen();

View File

@ -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();

View File

@ -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)

View File

@ -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)

View File

@ -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");

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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"

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -10,7 +10,6 @@
#include <vector>
#include "Common/Assert.h"
#include "Common/GL/GLInterfaceBase.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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();

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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 = {};

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}