Create GL context abstraction layer
This commit is contained in:
parent
69e818555d
commit
ce10d9bd02
|
@ -23,6 +23,10 @@ extern "C" GLEWContext* glewGetContext();
|
|||
// required.
|
||||
typedef struct WGLEWContextStruct WGLEWContext;
|
||||
extern "C" WGLEWContext* wglewGetContext();
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
#elif XE_PLATFORM_LINUX
|
||||
typedef struct GLXEWContextStruct GLXEWContext;
|
||||
extern "C" GLXEWContext* glxewGetContext();
|
||||
|
||||
#endif
|
||||
|
||||
#endif // XENIA_UI_GL_GL_H_
|
||||
|
|
|
@ -17,13 +17,10 @@
|
|||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/platform_win.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/ui/gl/gl_immediate_drawer.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
// TODO(benvanik): move win32 code to _win?
|
||||
#include "third_party/GL/wglew.h"
|
||||
|
||||
DEFINE_bool(thread_safe_gl, false,
|
||||
"Only allow one GL context to be active at a time.");
|
||||
|
@ -43,14 +40,10 @@ namespace xe {
|
|||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
static std::recursive_mutex global_gl_mutex_;
|
||||
|
||||
thread_local GLEWContext* tls_glew_context_ = nullptr;
|
||||
thread_local WGLEWContext* tls_wglew_context_ = nullptr;
|
||||
extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; }
|
||||
extern "C" WGLEWContext* wglewGetContext() { return tls_wglew_context_; }
|
||||
std::recursive_mutex GLContext::global_gl_mutex_;
|
||||
|
||||
void FatalGLError(std::string error) {
|
||||
void GLContext::FatalGLError(std::string error) {
|
||||
xe::FatalError(
|
||||
error +
|
||||
"\nEnsure you have the latest drivers for your GPU and that it supports "
|
||||
|
@ -58,223 +51,11 @@ void FatalGLError(std::string error) {
|
|||
"of supported GPUs.");
|
||||
}
|
||||
|
||||
std::unique_ptr<GLContext> GLContext::Create(GraphicsProvider* provider,
|
||||
Window* target_window,
|
||||
GLContext* share_context) {
|
||||
auto context =
|
||||
std::unique_ptr<GLContext>(new GLContext(provider, target_window));
|
||||
if (!context->Initialize(share_context)) {
|
||||
return nullptr;
|
||||
}
|
||||
context->AssertExtensionsPresent();
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
GLContext::GLContext(GraphicsProvider* provider, Window* target_window)
|
||||
: GraphicsContext(provider, target_window) {
|
||||
glew_context_.reset(new GLEWContext());
|
||||
wglew_context_.reset(new WGLEWContext());
|
||||
}
|
||||
: GraphicsContext(provider, target_window) { }
|
||||
|
||||
GLContext::~GLContext() {
|
||||
MakeCurrent();
|
||||
blitter_.Shutdown();
|
||||
immediate_drawer_.reset();
|
||||
ClearCurrent();
|
||||
if (glrc_) {
|
||||
wglDeleteContext(glrc_);
|
||||
}
|
||||
if (dc_) {
|
||||
ReleaseDC(HWND(target_window_->native_handle()), dc_);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContext::Initialize(GLContext* share_context) {
|
||||
dc_ = GetDC(HWND(target_window_->native_handle()));
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = {0};
|
||||
pfd.nSize = sizeof(pfd);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
|
||||
pfd.iPixelType = PFD_TYPE_RGBA;
|
||||
pfd.cColorBits = 32;
|
||||
pfd.cDepthBits = 32;
|
||||
pfd.iLayerType = PFD_MAIN_PLANE;
|
||||
int pixel_format = ChoosePixelFormat(dc_, &pfd);
|
||||
if (!pixel_format) {
|
||||
FatalGLError("Unable to choose pixel format.");
|
||||
return false;
|
||||
}
|
||||
if (!SetPixelFormat(dc_, pixel_format, &pfd)) {
|
||||
FatalGLError("Unable to set pixel format.");
|
||||
return false;
|
||||
}
|
||||
|
||||
HGLRC temp_context = wglCreateContext(dc_);
|
||||
if (!temp_context) {
|
||||
FatalGLError("Unable to create temporary GL context.");
|
||||
return false;
|
||||
}
|
||||
wglMakeCurrent(dc_, temp_context);
|
||||
|
||||
tls_glew_context_ = glew_context_.get();
|
||||
tls_wglew_context_ = wglew_context_.get();
|
||||
if (glewInit() != GLEW_OK) {
|
||||
FatalGLError("Unable to initialize GLEW.");
|
||||
return false;
|
||||
}
|
||||
if (wglewInit() != GLEW_OK) {
|
||||
FatalGLError("Unable to initialize WGLEW.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WGLEW_ARB_create_context) {
|
||||
FatalGLError("WGL_ARG_create_context not supported by GL ICD.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GLEW_ARB_robustness) {
|
||||
robust_access_supported_ = true;
|
||||
}
|
||||
|
||||
int context_flags = 0;
|
||||
if (FLAGS_gl_debug) {
|
||||
context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
}
|
||||
if (robust_access_supported_) {
|
||||
context_flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||
}
|
||||
|
||||
int attrib_list[] = {
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
||||
4,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB,
|
||||
5,
|
||||
WGL_CONTEXT_FLAGS_ARB,
|
||||
context_flags,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB,
|
||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||
WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
robust_access_supported_ ? WGL_LOSE_CONTEXT_ON_RESET_ARB : 0,
|
||||
0};
|
||||
|
||||
glrc_ = wglCreateContextAttribsARB(
|
||||
dc_, share_context ? share_context->glrc_ : nullptr, attrib_list);
|
||||
wglMakeCurrent(nullptr, nullptr);
|
||||
wglDeleteContext(temp_context);
|
||||
if (!glrc_) {
|
||||
FatalGLError("Unable to create real GL context.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MakeCurrent()) {
|
||||
FatalGLError("Could not make real GL context current.");
|
||||
return false;
|
||||
}
|
||||
|
||||
XELOGI("Successfully created OpenGL context:");
|
||||
XELOGI(" GL_VENDOR: %s", glGetString(GL_VENDOR));
|
||||
XELOGI(" GL_VERSION: %s", glGetString(GL_VERSION));
|
||||
XELOGI(" GL_RENDERER: %s", glGetString(GL_RENDERER));
|
||||
XELOGI(" GL_SHADING_LANGUAGE_VERSION: %s",
|
||||
glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
|
||||
while (glGetError()) {
|
||||
// Clearing errors.
|
||||
}
|
||||
|
||||
SetupDebugging();
|
||||
|
||||
if (!blitter_.Initialize()) {
|
||||
FatalGLError("Unable to initialize blitter.");
|
||||
ClearCurrent();
|
||||
return false;
|
||||
}
|
||||
|
||||
immediate_drawer_ = std::make_unique<GLImmediateDrawer>(this);
|
||||
|
||||
ClearCurrent();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<GLContext> GLContext::CreateOffscreen(
|
||||
GraphicsProvider* provider, GLContext* parent_context) {
|
||||
assert_not_null(parent_context->glrc_);
|
||||
|
||||
HGLRC new_glrc = nullptr;
|
||||
{
|
||||
GraphicsContextLock context_lock(parent_context);
|
||||
|
||||
int context_flags = 0;
|
||||
if (FLAGS_gl_debug) {
|
||||
context_flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
}
|
||||
|
||||
bool robust_access_supported = parent_context->robust_access_supported_;
|
||||
if (robust_access_supported) {
|
||||
context_flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
|
||||
}
|
||||
|
||||
int attrib_list[] = {
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB,
|
||||
4,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB,
|
||||
5,
|
||||
WGL_CONTEXT_FLAGS_ARB,
|
||||
context_flags,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB,
|
||||
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||
WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
|
||||
robust_access_supported ? WGL_LOSE_CONTEXT_ON_RESET_ARB : 0,
|
||||
0};
|
||||
new_glrc = wglCreateContextAttribsARB(parent_context->dc_,
|
||||
parent_context->glrc_, attrib_list);
|
||||
if (!new_glrc) {
|
||||
FatalGLError("Could not create shared context.");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
auto new_context = std::unique_ptr<GLContext>(
|
||||
new GLContext(provider, parent_context->target_window_));
|
||||
new_context->glrc_ = new_glrc;
|
||||
new_context->dc_ =
|
||||
GetDC(HWND(parent_context->target_window_->native_handle()));
|
||||
new_context->robust_access_supported_ =
|
||||
parent_context->robust_access_supported_;
|
||||
if (!new_context->MakeCurrent()) {
|
||||
FatalGLError("Could not make new GL context current.");
|
||||
return nullptr;
|
||||
}
|
||||
if (!glGetString(GL_EXTENSIONS)) {
|
||||
new_context->ClearCurrent();
|
||||
FatalGLError("New GL context did not have extensions.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (glewInit() != GLEW_OK) {
|
||||
new_context->ClearCurrent();
|
||||
FatalGLError("Unable to initialize GLEW on shared context.");
|
||||
return nullptr;
|
||||
}
|
||||
if (wglewInit() != GLEW_OK) {
|
||||
new_context->ClearCurrent();
|
||||
FatalGLError("Unable to initialize WGLEW on shared context.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
new_context->SetupDebugging();
|
||||
|
||||
if (!new_context->blitter_.Initialize()) {
|
||||
FatalGLError("Unable to initialize blitter on shared context.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
new_context->ClearCurrent();
|
||||
|
||||
return new_context;
|
||||
}
|
||||
|
||||
void GLContext::AssertExtensionsPresent() {
|
||||
if (!MakeCurrent()) {
|
||||
|
@ -436,39 +217,7 @@ ImmediateDrawer* GLContext::immediate_drawer() {
|
|||
return immediate_drawer_.get();
|
||||
}
|
||||
|
||||
bool GLContext::is_current() {
|
||||
return tls_glew_context_ == glew_context_.get();
|
||||
}
|
||||
|
||||
bool GLContext::MakeCurrent() {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
if (FLAGS_thread_safe_gl) {
|
||||
global_gl_mutex_.lock();
|
||||
}
|
||||
|
||||
if (!wglMakeCurrent(dc_, glrc_)) {
|
||||
if (FLAGS_thread_safe_gl) {
|
||||
global_gl_mutex_.unlock();
|
||||
}
|
||||
FatalGLError("Unable to make GL context current.");
|
||||
return false;
|
||||
}
|
||||
tls_glew_context_ = glew_context_.get();
|
||||
tls_wglew_context_ = wglew_context_.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext::ClearCurrent() {
|
||||
if (!FLAGS_disable_gl_context_reset) {
|
||||
wglMakeCurrent(nullptr, nullptr);
|
||||
}
|
||||
tls_glew_context_ = nullptr;
|
||||
tls_wglew_context_ = nullptr;
|
||||
|
||||
if (FLAGS_thread_safe_gl) {
|
||||
global_gl_mutex_.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContext::WasLost() {
|
||||
if (!robust_access_supported_) {
|
||||
|
@ -484,7 +233,7 @@ bool GLContext::WasLost() {
|
|||
if (status != GL_NO_ERROR) {
|
||||
// Graphics card reset.
|
||||
XELOGE("============= TDR detected on context %p! Context %s =============",
|
||||
glrc_, status == GL_GUILTY_CONTEXT_RESET ? "guilty" : "innocent");
|
||||
handle(), status == GL_GUILTY_CONTEXT_RESET ? "guilty" : "innocent");
|
||||
context_lost_ = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -492,24 +241,6 @@ bool GLContext::WasLost() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void GLContext::BeginSwap() {
|
||||
SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLContext::BeginSwap");
|
||||
float clear_color[] = {238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.0f};
|
||||
if (FLAGS_random_clear_color) {
|
||||
clear_color[0] =
|
||||
rand() / static_cast<float>(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
|
||||
clear_color[1] = 1.0f;
|
||||
clear_color[2] = 0.0f;
|
||||
clear_color[3] = 1.0f;
|
||||
}
|
||||
glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color);
|
||||
}
|
||||
|
||||
void GLContext::EndSwap() {
|
||||
SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLContext::EndSwap");
|
||||
SwapBuffers(dc_);
|
||||
}
|
||||
|
||||
std::unique_ptr<RawImage> GLContext::Capture() {
|
||||
GraphicsContextLock lock(this);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <gflags/gflags.h>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "xenia/ui/gl/blitter.h"
|
||||
#include "xenia/ui/gl/gl.h"
|
||||
|
@ -44,11 +45,25 @@ class GLContext : public GraphicsContext {
|
|||
|
||||
void BeginSwap() override;
|
||||
void EndSwap() override;
|
||||
|
||||
std::unique_ptr<RawImage> Capture() override;
|
||||
|
||||
Blitter* blitter() { return &blitter_; }
|
||||
|
||||
protected:
|
||||
Blitter blitter_;
|
||||
std::unique_ptr<GLImmediateDrawer> immediate_drawer_;
|
||||
|
||||
static std::recursive_mutex global_gl_mutex_;
|
||||
bool context_lost_ = false;
|
||||
bool robust_access_supported_ = false;
|
||||
static void FatalGLError(std::string error);
|
||||
virtual bool Initialize(GLContext* share_context) = 0;
|
||||
virtual void* handle() = 0;
|
||||
GLContext(GraphicsProvider* provider, Window* target_window);
|
||||
void SetupDebugging();
|
||||
void AssertExtensionsPresent();
|
||||
void DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||
GLsizei length, const GLchar* message);
|
||||
private:
|
||||
friend class GLProvider;
|
||||
|
||||
|
@ -59,31 +74,15 @@ class GLContext : public GraphicsContext {
|
|||
GLContext* parent_context);
|
||||
|
||||
private:
|
||||
GLContext(GraphicsProvider* provider, Window* target_window);
|
||||
|
||||
bool Initialize(GLContext* share_context);
|
||||
void AssertExtensionsPresent();
|
||||
|
||||
void SetupDebugging();
|
||||
void DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||
GLsizei length, const GLchar* message);
|
||||
static void GLAPIENTRY DebugMessageThunk(GLenum source, GLenum type,
|
||||
GLuint id, GLenum severity,
|
||||
GLsizei length,
|
||||
const GLchar* message,
|
||||
GLvoid* user_param);
|
||||
|
||||
HDC dc_ = nullptr;
|
||||
HGLRC glrc_ = nullptr;
|
||||
|
||||
std::unique_ptr<GLEWContext> glew_context_;
|
||||
std::unique_ptr<WGLEWContext> wglew_context_;
|
||||
|
||||
Blitter blitter_;
|
||||
std::unique_ptr<GLImmediateDrawer> immediate_drawer_;
|
||||
|
||||
bool context_lost_ = false;
|
||||
bool robust_access_supported_ = false;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
|
|
Loading…
Reference in New Issue