Create GL context abstraction layer
This commit is contained in:
parent
69e818555d
commit
ce10d9bd02
|
@ -23,6 +23,10 @@ extern "C" GLEWContext* glewGetContext();
|
||||||
// required.
|
// required.
|
||||||
typedef struct WGLEWContextStruct WGLEWContext;
|
typedef struct WGLEWContextStruct WGLEWContext;
|
||||||
extern "C" WGLEWContext* wglewGetContext();
|
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_
|
#endif // XENIA_UI_GL_GL_H_
|
||||||
|
|
|
@ -17,13 +17,10 @@
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/base/platform_win.h"
|
|
||||||
#include "xenia/base/profiling.h"
|
#include "xenia/base/profiling.h"
|
||||||
#include "xenia/ui/gl/gl_immediate_drawer.h"
|
#include "xenia/ui/gl/gl_immediate_drawer.h"
|
||||||
#include "xenia/ui/window.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,
|
DEFINE_bool(thread_safe_gl, false,
|
||||||
"Only allow one GL context to be active at a time.");
|
"Only allow one GL context to be active at a time.");
|
||||||
|
@ -43,14 +40,10 @@ namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace gl {
|
namespace gl {
|
||||||
|
|
||||||
static std::recursive_mutex global_gl_mutex_;
|
|
||||||
|
|
||||||
thread_local GLEWContext* tls_glew_context_ = nullptr;
|
std::recursive_mutex GLContext::global_gl_mutex_;
|
||||||
thread_local WGLEWContext* tls_wglew_context_ = nullptr;
|
|
||||||
extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; }
|
|
||||||
extern "C" WGLEWContext* wglewGetContext() { return tls_wglew_context_; }
|
|
||||||
|
|
||||||
void FatalGLError(std::string error) {
|
void GLContext::FatalGLError(std::string error) {
|
||||||
xe::FatalError(
|
xe::FatalError(
|
||||||
error +
|
error +
|
||||||
"\nEnsure you have the latest drivers for your GPU and that it supports "
|
"\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.");
|
"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)
|
GLContext::GLContext(GraphicsProvider* provider, Window* target_window)
|
||||||
: GraphicsContext(provider, target_window) {
|
: GraphicsContext(provider, target_window) { }
|
||||||
glew_context_.reset(new GLEWContext());
|
|
||||||
wglew_context_.reset(new WGLEWContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
void GLContext::AssertExtensionsPresent() {
|
||||||
if (!MakeCurrent()) {
|
if (!MakeCurrent()) {
|
||||||
|
@ -436,39 +217,7 @@ ImmediateDrawer* GLContext::immediate_drawer() {
|
||||||
return immediate_drawer_.get();
|
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() {
|
bool GLContext::WasLost() {
|
||||||
if (!robust_access_supported_) {
|
if (!robust_access_supported_) {
|
||||||
|
@ -484,7 +233,7 @@ bool GLContext::WasLost() {
|
||||||
if (status != GL_NO_ERROR) {
|
if (status != GL_NO_ERROR) {
|
||||||
// Graphics card reset.
|
// Graphics card reset.
|
||||||
XELOGE("============= TDR detected on context %p! Context %s =============",
|
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;
|
context_lost_ = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -492,24 +241,6 @@ bool GLContext::WasLost() {
|
||||||
return false;
|
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() {
|
std::unique_ptr<RawImage> GLContext::Capture() {
|
||||||
GraphicsContextLock lock(this);
|
GraphicsContextLock lock(this);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "xenia/ui/gl/blitter.h"
|
#include "xenia/ui/gl/blitter.h"
|
||||||
#include "xenia/ui/gl/gl.h"
|
#include "xenia/ui/gl/gl.h"
|
||||||
|
@ -44,11 +45,25 @@ class GLContext : public GraphicsContext {
|
||||||
|
|
||||||
void BeginSwap() override;
|
void BeginSwap() override;
|
||||||
void EndSwap() override;
|
void EndSwap() override;
|
||||||
|
|
||||||
std::unique_ptr<RawImage> Capture() override;
|
std::unique_ptr<RawImage> Capture() override;
|
||||||
|
|
||||||
Blitter* blitter() { return &blitter_; }
|
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:
|
private:
|
||||||
friend class GLProvider;
|
friend class GLProvider;
|
||||||
|
|
||||||
|
@ -59,31 +74,15 @@ class GLContext : public GraphicsContext {
|
||||||
GLContext* parent_context);
|
GLContext* parent_context);
|
||||||
|
|
||||||
private:
|
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,
|
static void GLAPIENTRY DebugMessageThunk(GLenum source, GLenum type,
|
||||||
GLuint id, GLenum severity,
|
GLuint id, GLenum severity,
|
||||||
GLsizei length,
|
GLsizei length,
|
||||||
const GLchar* message,
|
const GLchar* message,
|
||||||
GLvoid* user_param);
|
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
|
} // namespace gl
|
||||||
|
|
Loading…
Reference in New Issue