Massive refactoring of xenia::ui and GL swap behavior.
This seems to dramatically improve most games (especially with --vsync=false), though it may cause swap issues with others. New code should be easier to port, and enables elemental-forms to be drawn for any emulator UI.
This commit is contained in:
@@ -11,7 +11,6 @@
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/gpu/gl4/gl4_gpu_flags.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
|
||||
@@ -28,7 +28,7 @@ GL4ElementalRenderer::GL4Bitmap::GL4Bitmap(GLContext* context,
|
||||
: context_(context), renderer_(renderer) {}
|
||||
|
||||
GL4ElementalRenderer::GL4Bitmap::~GL4Bitmap() {
|
||||
GLContextLock lock(context_);
|
||||
GraphicsContextLock lock(context_);
|
||||
|
||||
// Must flush and unbind before we delete the texture.
|
||||
renderer_->FlushBitmap(this);
|
||||
@@ -69,7 +69,7 @@ GL4ElementalRenderer::GL4ElementalRenderer(GLContext* context)
|
||||
vertex_buffer_(max_vertex_batch_size() * sizeof(Vertex)) {}
|
||||
|
||||
GL4ElementalRenderer::~GL4ElementalRenderer() {
|
||||
GLContextLock lock(context_);
|
||||
GraphicsContextLock lock(context_);
|
||||
vertex_buffer_.Shutdown();
|
||||
glDeleteVertexArrays(1, &vao_);
|
||||
glDeleteProgram(program_);
|
||||
@@ -77,6 +77,7 @@ GL4ElementalRenderer::~GL4ElementalRenderer() {
|
||||
|
||||
std::unique_ptr<GL4ElementalRenderer> GL4ElementalRenderer::Create(
|
||||
GLContext* context) {
|
||||
GraphicsContextLock lock(context);
|
||||
auto renderer = std::make_unique<GL4ElementalRenderer>(context);
|
||||
if (!renderer->Initialize()) {
|
||||
XELOGE("Failed to initialize TurboBadger GL4 renderer");
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/profiling.h"
|
||||
#include "xenia/ui/gl/gl_profiler_display.h"
|
||||
#include "xenia/ui/gl/gl4_elemental_renderer.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
DEFINE_bool(thread_safe_gl, false,
|
||||
"Only allow one GL context to be active at a time.");
|
||||
@@ -40,11 +43,20 @@ thread_local WGLEWContext* tls_wglew_context_ = nullptr;
|
||||
extern "C" GLEWContext* glewGetContext() { return tls_glew_context_; }
|
||||
extern "C" WGLEWContext* wglewGetContext() { return tls_wglew_context_; }
|
||||
|
||||
GLContext::GLContext() : hwnd_(nullptr), dc_(nullptr), glrc_(nullptr) {}
|
||||
std::unique_ptr<GLContext> GLContext::Create(Window* target_window) {
|
||||
auto context = std::unique_ptr<GLContext>(new GLContext(target_window));
|
||||
if (!context->Initialize(target_window)) {
|
||||
return nullptr;
|
||||
}
|
||||
context->AssertExtensionsPresent();
|
||||
return context;
|
||||
}
|
||||
|
||||
GLContext::GLContext(HWND hwnd, HGLRC glrc)
|
||||
: hwnd_(hwnd), dc_(nullptr), glrc_(glrc) {
|
||||
dc_ = GetDC(hwnd);
|
||||
GLContext::GLContext(Window* target_window) : GraphicsContext(target_window) {}
|
||||
|
||||
GLContext::GLContext(Window* target_window, HGLRC glrc)
|
||||
: GraphicsContext(target_window), glrc_(glrc) {
|
||||
dc_ = GetDC(HWND(target_window_->native_handle()));
|
||||
}
|
||||
|
||||
GLContext::~GLContext() {
|
||||
@@ -55,13 +67,13 @@ GLContext::~GLContext() {
|
||||
wglDeleteContext(glrc_);
|
||||
}
|
||||
if (dc_) {
|
||||
ReleaseDC(hwnd_, dc_);
|
||||
ReleaseDC(HWND(target_window_->native_handle()), dc_);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLContext::Initialize(HWND hwnd) {
|
||||
hwnd_ = hwnd;
|
||||
dc_ = GetDC(hwnd);
|
||||
bool GLContext::Initialize(Window* target_window) {
|
||||
target_window_ = target_window;
|
||||
dc_ = GetDC(HWND(target_window_->native_handle()));
|
||||
|
||||
PIXELFORMATDESCRIPTOR pfd = {0};
|
||||
pfd.nSize = sizeof(pfd);
|
||||
@@ -152,12 +164,12 @@ bool GLContext::Initialize(HWND hwnd) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<GLContext> GLContext::CreateShared() {
|
||||
std::unique_ptr<GraphicsContext> GLContext::CreateShared() {
|
||||
assert_not_null(glrc_);
|
||||
|
||||
HGLRC new_glrc = nullptr;
|
||||
{
|
||||
GLContextLock context_lock(this);
|
||||
GraphicsContextLock context_lock(this);
|
||||
|
||||
int context_flags = 0;
|
||||
// int profile = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||
@@ -178,7 +190,8 @@ std::unique_ptr<GLContext> GLContext::CreateShared() {
|
||||
}
|
||||
}
|
||||
|
||||
auto new_context = std::make_unique<GLContext>(hwnd_, new_glrc);
|
||||
auto new_context =
|
||||
std::unique_ptr<GLContext>(new GLContext(target_window_, new_glrc));
|
||||
if (!new_context->MakeCurrent()) {
|
||||
XELOGE("Could not make new GL context current");
|
||||
return nullptr;
|
||||
@@ -205,7 +218,7 @@ std::unique_ptr<GLContext> GLContext::CreateShared() {
|
||||
|
||||
new_context->ClearCurrent();
|
||||
|
||||
return new_context;
|
||||
return std::unique_ptr<GraphicsContext>(new_context.release());
|
||||
}
|
||||
|
||||
void FatalGLError(std::string error) {
|
||||
@@ -369,6 +382,14 @@ void GLContext::SetupDebugging() {
|
||||
this);
|
||||
}
|
||||
|
||||
std::unique_ptr<ProfilerDisplay> GLContext::CreateProfilerDisplay() {
|
||||
return std::make_unique<GLProfilerDisplay>(target_window_);
|
||||
}
|
||||
|
||||
std::unique_ptr<el::graphics::Renderer> GLContext::CreateElementalRenderer() {
|
||||
return GL4ElementalRenderer::Create(this);
|
||||
}
|
||||
|
||||
bool GLContext::MakeCurrent() {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
if (FLAGS_thread_safe_gl) {
|
||||
@@ -399,6 +420,17 @@ void GLContext::ClearCurrent() {
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::BeginSwap() {
|
||||
SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLContext::BeginSwap");
|
||||
float clear_color[] = {rand() / (float)RAND_MAX, 1.0f, 0, 1.0f};
|
||||
glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color);
|
||||
}
|
||||
|
||||
void GLContext::EndSwap() {
|
||||
SCOPE_profile_cpu_i("gpu", "xe::ui::gl::GLContext::EndSwap");
|
||||
SwapBuffers(dc());
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "xenia/ui/gl/blitter.h"
|
||||
#include "xenia/ui/gl/gl.h"
|
||||
#include "xenia/ui/graphics_context.h"
|
||||
|
||||
DECLARE_bool(thread_safe_gl);
|
||||
|
||||
@@ -23,25 +24,33 @@ namespace xe {
|
||||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
class GLContext {
|
||||
class GLContext : public GraphicsContext {
|
||||
public:
|
||||
GLContext();
|
||||
GLContext(HWND hwnd, HGLRC glrc);
|
||||
~GLContext();
|
||||
static std::unique_ptr<GLContext> Create(Window* target_window);
|
||||
|
||||
bool Initialize(HWND hwnd);
|
||||
void AssertExtensionsPresent();
|
||||
~GLContext() override;
|
||||
|
||||
HDC dc() const { return dc_; }
|
||||
|
||||
std::unique_ptr<GLContext> CreateShared();
|
||||
std::unique_ptr<GraphicsContext> CreateShared() override;
|
||||
std::unique_ptr<ProfilerDisplay> CreateProfilerDisplay() override;
|
||||
std::unique_ptr<el::graphics::Renderer> CreateElementalRenderer() override;
|
||||
|
||||
bool MakeCurrent();
|
||||
void ClearCurrent();
|
||||
bool MakeCurrent() override;
|
||||
void ClearCurrent() override;
|
||||
|
||||
void BeginSwap() override;
|
||||
void EndSwap() override;
|
||||
|
||||
Blitter* blitter() { return &blitter_; }
|
||||
|
||||
private:
|
||||
GLContext(Window* target_window);
|
||||
GLContext(Window* target_window, HGLRC glrc);
|
||||
|
||||
bool Initialize(Window* target_window);
|
||||
void AssertExtensionsPresent();
|
||||
|
||||
void SetupDebugging();
|
||||
void DebugMessage(GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||
GLsizei length, const GLchar* message);
|
||||
@@ -49,9 +58,8 @@ class GLContext {
|
||||
DebugMessageThunk(GLenum source, GLenum type, GLuint id, GLenum severity,
|
||||
GLsizei length, const GLchar* message, GLvoid* user_param);
|
||||
|
||||
HWND hwnd_;
|
||||
HDC dc_;
|
||||
HGLRC glrc_;
|
||||
HDC dc_ = nullptr;
|
||||
HGLRC glrc_ = nullptr;
|
||||
|
||||
GLEWContext glew_context_;
|
||||
WGLEWContext wglew_context_;
|
||||
@@ -59,16 +67,6 @@ class GLContext {
|
||||
Blitter blitter_;
|
||||
};
|
||||
|
||||
struct GLContextLock {
|
||||
GLContextLock(GLContext* context) : context_(context) {
|
||||
context_->MakeCurrent();
|
||||
}
|
||||
~GLContextLock() { context_->ClearCurrent(); }
|
||||
|
||||
private:
|
||||
GLContext* context_;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
@@ -132,47 +132,56 @@ const uint8_t profiler_font[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
GLProfilerDisplay::GLProfilerDisplay(xe::ui::gl::WGLControl* control)
|
||||
: control_(control),
|
||||
program_(0),
|
||||
vao_(0),
|
||||
font_texture_(0),
|
||||
font_handle_(0),
|
||||
GLProfilerDisplay::GLProfilerDisplay(xe::ui::Window* window)
|
||||
: window_(window),
|
||||
vertex_buffer_(MICROPROFILE_MAX_VERTICES * sizeof(Vertex) * 10,
|
||||
sizeof(Vertex)),
|
||||
draw_command_count_(0) {
|
||||
sizeof(Vertex)) {
|
||||
if (!SetupFont() || !SetupState() || !SetupShaders()) {
|
||||
// Hrm.
|
||||
assert_always();
|
||||
}
|
||||
|
||||
window_->on_painted.AddListener([this](UIEvent& e) { Profiler::Present(); });
|
||||
|
||||
// Pass through mouse events.
|
||||
control->on_mouse_down.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseDown(e.button() == xe::ui::MouseEvent::Button::kLeft,
|
||||
e.button() == xe::ui::MouseEvent::Button::kRight);
|
||||
e.set_handled(true);
|
||||
window_->on_mouse_down.AddListener([](xe::ui::MouseEvent& e) {
|
||||
if (Profiler::is_enabled()) {
|
||||
Profiler::OnMouseDown(e.button() == xe::ui::MouseEvent::Button::kLeft,
|
||||
e.button() == xe::ui::MouseEvent::Button::kRight);
|
||||
e.set_handled(true);
|
||||
}
|
||||
});
|
||||
control->on_mouse_up.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseUp();
|
||||
e.set_handled(true);
|
||||
window_->on_mouse_up.AddListener([](xe::ui::MouseEvent& e) {
|
||||
if (Profiler::is_enabled()) {
|
||||
Profiler::OnMouseUp();
|
||||
e.set_handled(true);
|
||||
}
|
||||
});
|
||||
control->on_mouse_move.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseMove(e.x(), e.y());
|
||||
e.set_handled(true);
|
||||
window_->on_mouse_move.AddListener([](xe::ui::MouseEvent& e) {
|
||||
if (Profiler::is_enabled()) {
|
||||
Profiler::OnMouseMove(e.x(), e.y());
|
||||
e.set_handled(true);
|
||||
}
|
||||
});
|
||||
control->on_mouse_wheel.AddListener([](xe::ui::MouseEvent& e) {
|
||||
Profiler::OnMouseWheel(e.x(), e.y(), -e.dy());
|
||||
e.set_handled(true);
|
||||
window_->on_mouse_wheel.AddListener([](xe::ui::MouseEvent& e) {
|
||||
if (Profiler::is_enabled()) {
|
||||
Profiler::OnMouseWheel(e.x(), e.y(), -e.dy());
|
||||
e.set_handled(true);
|
||||
}
|
||||
});
|
||||
|
||||
// Watch for toggle/mode keys and such.
|
||||
control->on_key_down.AddListener([](xe::ui::KeyEvent& e) {
|
||||
Profiler::OnKeyDown(e.key_code());
|
||||
// e.set_handled(true);
|
||||
window_->on_key_down.AddListener([](xe::ui::KeyEvent& e) {
|
||||
if (Profiler::is_enabled()) {
|
||||
Profiler::OnKeyDown(e.key_code());
|
||||
e.set_handled(true);
|
||||
}
|
||||
});
|
||||
control->on_key_up.AddListener([](xe::ui::KeyEvent& e) {
|
||||
Profiler::OnKeyUp(e.key_code());
|
||||
// e.set_handled(true);
|
||||
window_->on_key_up.AddListener([](xe::ui::KeyEvent& e) {
|
||||
if (Profiler::is_enabled()) {
|
||||
Profiler::OnKeyUp(e.key_code());
|
||||
e.set_handled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -336,9 +345,9 @@ GLProfilerDisplay::~GLProfilerDisplay() {
|
||||
glDeleteProgram(program_);
|
||||
}
|
||||
|
||||
uint32_t GLProfilerDisplay::width() const { return control_->width(); }
|
||||
uint32_t GLProfilerDisplay::width() const { return window_->width(); }
|
||||
|
||||
uint32_t GLProfilerDisplay::height() const { return control_->height(); }
|
||||
uint32_t GLProfilerDisplay::height() const { return window_->height(); }
|
||||
|
||||
void GLProfilerDisplay::Begin() {
|
||||
glEnablei(GL_BLEND, 0);
|
||||
@@ -347,7 +356,7 @@ void GLProfilerDisplay::Begin() {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
glViewport(0, 0, control_->width(), control_->height());
|
||||
glViewport(0, 0, width(), height());
|
||||
|
||||
float left = 0.0f;
|
||||
float right = float(width());
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
|
||||
#include "xenia/profiling.h"
|
||||
#include "xenia/ui/gl/circular_buffer.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/gl/wgl_control.h"
|
||||
#include "xenia/ui/window.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
@@ -21,7 +20,7 @@ namespace gl {
|
||||
|
||||
class GLProfilerDisplay : public ProfilerDisplay {
|
||||
public:
|
||||
GLProfilerDisplay(xe::ui::gl::WGLControl* control);
|
||||
GLProfilerDisplay(xe::ui::Window* window);
|
||||
virtual ~GLProfilerDisplay();
|
||||
|
||||
uint32_t width() const override;
|
||||
@@ -54,11 +53,11 @@ class GLProfilerDisplay : public ProfilerDisplay {
|
||||
void EndVertices(GLenum prim_type);
|
||||
void Flush();
|
||||
|
||||
xe::ui::gl::WGLControl* control_;
|
||||
GLuint program_;
|
||||
GLuint vao_;
|
||||
GLuint font_texture_;
|
||||
GLuint64 font_handle_;
|
||||
xe::ui::Window* window_ = nullptr;
|
||||
GLuint program_ = 0;
|
||||
GLuint vao_ = 0;
|
||||
GLuint font_texture_ = 0;
|
||||
GLuint64 font_handle_ = 0;
|
||||
CircularBuffer vertex_buffer_;
|
||||
|
||||
static const size_t kMaxCommands = 32;
|
||||
@@ -67,13 +66,13 @@ class GLProfilerDisplay : public ProfilerDisplay {
|
||||
size_t vertex_offset;
|
||||
size_t vertex_count;
|
||||
} draw_commands_[kMaxCommands];
|
||||
uint32_t draw_command_count_;
|
||||
uint32_t draw_command_count_ = 0;
|
||||
|
||||
CircularBuffer::Allocation current_allocation_;
|
||||
|
||||
struct {
|
||||
uint16_t char_offsets[256];
|
||||
} font_description_;
|
||||
} font_description_ = {0};
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/gl/wgl_control.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/profiling.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
WGLControl::WGLControl(Loop* loop)
|
||||
: xe::ui::win32::Win32Control(Flags::kFlagOwnPaint), loop_(loop) {}
|
||||
|
||||
WGLControl::~WGLControl() = default;
|
||||
|
||||
bool WGLControl::Create() {
|
||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||
|
||||
WNDCLASSEX wcex;
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wcex.lpfnWndProc = Win32Control::WndProcThunk;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = nullptr;
|
||||
wcex.hIconSm = nullptr;
|
||||
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = nullptr;
|
||||
wcex.lpszClassName = L"XeniaWglClass";
|
||||
if (!RegisterClassEx(&wcex)) {
|
||||
XELOGE("WGL RegisterClassEx failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create window.
|
||||
DWORD window_style = WS_CHILD | WS_VISIBLE | SS_NOTIFY;
|
||||
DWORD window_ex_style = 0;
|
||||
hwnd_ =
|
||||
CreateWindowEx(window_ex_style, L"XeniaWglClass", L"Xenia", window_style,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
parent_hwnd(), nullptr, hInstance, this);
|
||||
if (!hwnd_) {
|
||||
XELOGE("WGL CreateWindow failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!context_.Initialize(hwnd_)) {
|
||||
XEFATAL(
|
||||
"Unable to initialize GL context. Xenia requires OpenGL 4.5. Ensure "
|
||||
"you have the latest drivers for your GPU and that it supports OpenGL "
|
||||
"4.5. See http://xenia.jp/faq/ for more information.");
|
||||
return false;
|
||||
}
|
||||
|
||||
context_.AssertExtensionsPresent();
|
||||
|
||||
SetFocus(hwnd_);
|
||||
|
||||
OnCreate();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WGLControl::OnLayout(UIEvent& e) { Control::ResizeToFill(); }
|
||||
|
||||
LRESULT WGLControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_PAINT: {
|
||||
invalidated_ = false;
|
||||
ValidateRect(hWnd, nullptr);
|
||||
SCOPE_profile_cpu_i("gpu", "xe::gpu::gl4::WGLControl::WM_PAINT");
|
||||
{
|
||||
GLContextLock context_lock(&context_);
|
||||
|
||||
float clear_color[] = {rand() / (float)RAND_MAX, 1.0f, 0, 1.0f};
|
||||
glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color);
|
||||
|
||||
if (current_paint_callback_) {
|
||||
current_paint_callback_();
|
||||
current_paint_callback_ = nullptr;
|
||||
}
|
||||
|
||||
UIEvent e(this);
|
||||
OnPaint(e);
|
||||
|
||||
// TODO(benvanik): profiler present.
|
||||
Profiler::Present();
|
||||
}
|
||||
{
|
||||
SCOPE_profile_cpu_i("gpu", "xe::gpu::gl4::WGLControl::SwapBuffers");
|
||||
SwapBuffers(context_.dc());
|
||||
}
|
||||
return 0;
|
||||
} break;
|
||||
}
|
||||
return Win32Control::WndProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void WGLControl::SynchronousRepaint(std::function<void()> paint_callback) {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
|
||||
// We may already have a pending paint from a previous request when we
|
||||
// were minimized. We just overwrite it.
|
||||
current_paint_callback_ = std::move(paint_callback);
|
||||
|
||||
// This will not return until the WM_PAINT has completed.
|
||||
// Note, if we are minimized this won't do anything.
|
||||
RedrawWindow(hwnd(), nullptr, nullptr,
|
||||
RDW_INTERNALPAINT | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
@@ -1,51 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_GL_WGL_CONTROL_H_
|
||||
#define XENIA_UI_GL_WGL_CONTROL_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
#include "xenia/ui/win32/win32_control.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
class WGLControl : public xe::ui::win32::Win32Control {
|
||||
public:
|
||||
WGLControl(Loop* loop);
|
||||
~WGLControl() override;
|
||||
|
||||
GLContext* context() { return &context_; }
|
||||
|
||||
void SynchronousRepaint(std::function<void()> paint_callback);
|
||||
|
||||
protected:
|
||||
bool Create() override;
|
||||
|
||||
void OnLayout(UIEvent& e) override;
|
||||
|
||||
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) override;
|
||||
|
||||
private:
|
||||
Loop* loop_;
|
||||
GLContext context_;
|
||||
std::function<void()> current_paint_callback_;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_GL_WGL_CONTROL_H_
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2015 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include "xenia/ui/gl/wgl_elemental_control.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "el/util/math.h"
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/profiling.h"
|
||||
#include "xenia/ui/gl/circular_buffer.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/gl/gl.h"
|
||||
#include "xenia/ui/gl/gl4_elemental_renderer.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
WGLElementalControl::WGLElementalControl(Loop* loop)
|
||||
: ElementalControl(loop, Flags::kFlagOwnPaint), loop_(loop) {}
|
||||
|
||||
WGLElementalControl::~WGLElementalControl() = default;
|
||||
|
||||
bool WGLElementalControl::Create() {
|
||||
HINSTANCE hInstance = GetModuleHandle(nullptr);
|
||||
|
||||
WNDCLASSEX wcex;
|
||||
wcex.cbSize = sizeof(WNDCLASSEX);
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
|
||||
wcex.lpfnWndProc = Win32Control::WndProcThunk;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = 0;
|
||||
wcex.hInstance = hInstance;
|
||||
wcex.hIcon = nullptr;
|
||||
wcex.hIconSm = nullptr;
|
||||
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = nullptr;
|
||||
wcex.lpszClassName = L"XeniaWglElementalClass";
|
||||
if (!RegisterClassEx(&wcex)) {
|
||||
XELOGE("WGL RegisterClassEx failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create window.
|
||||
DWORD window_style = WS_CHILD | WS_VISIBLE | SS_NOTIFY;
|
||||
DWORD window_ex_style = 0;
|
||||
hwnd_ =
|
||||
CreateWindowEx(window_ex_style, L"XeniaWglElementalClass", L"Xenia",
|
||||
window_style, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, parent_hwnd(), nullptr, hInstance, this);
|
||||
if (!hwnd_) {
|
||||
XELOGE("WGL CreateWindow failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!context_.Initialize(hwnd_)) {
|
||||
XEFATAL(
|
||||
"Unable to initialize GL context. Xenia requires OpenGL 4.5. Ensure "
|
||||
"you have the latest drivers for your GPU and that it supports OpenGL "
|
||||
"4.5. See http://xenia.jp/faq/ for more information.");
|
||||
return false;
|
||||
}
|
||||
|
||||
context_.AssertExtensionsPresent();
|
||||
|
||||
SetFocus(hwnd_);
|
||||
|
||||
return super::Create();
|
||||
}
|
||||
|
||||
std::unique_ptr<el::graphics::Renderer> WGLElementalControl::CreateRenderer() {
|
||||
return GL4ElementalRenderer::Create(&context_);
|
||||
}
|
||||
|
||||
void WGLElementalControl::OnLayout(UIEvent& e) {
|
||||
Control::ResizeToFill();
|
||||
super::OnLayout(e);
|
||||
}
|
||||
|
||||
LRESULT WGLElementalControl::WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_PAINT: {
|
||||
invalidated_ = false;
|
||||
ValidateRect(hWnd, nullptr);
|
||||
SCOPE_profile_cpu_i("gpu", "xe::ui::gl::WGLElementalControl::WM_PAINT");
|
||||
{
|
||||
GLContextLock context_lock(&context_);
|
||||
|
||||
float clear_color[] = {rand() / (float)RAND_MAX, 1.0f, 0, 1.0f};
|
||||
glClearNamedFramebufferfv(0, GL_COLOR, 0, clear_color);
|
||||
|
||||
if (current_paint_callback_) {
|
||||
current_paint_callback_();
|
||||
current_paint_callback_ = nullptr;
|
||||
}
|
||||
|
||||
UIEvent e(this);
|
||||
OnPaint(e);
|
||||
|
||||
// TODO(benvanik): profiler present.
|
||||
Profiler::Present();
|
||||
}
|
||||
{
|
||||
SCOPE_profile_cpu_i("gpu",
|
||||
"xe::ui::gl::WGLElementalControl::SwapBuffers");
|
||||
SwapBuffers(context_.dc());
|
||||
}
|
||||
return 0;
|
||||
} break;
|
||||
}
|
||||
return Win32Control::WndProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void WGLElementalControl::SynchronousRepaint(
|
||||
std::function<void()> paint_callback) {
|
||||
SCOPE_profile_cpu_f("gpu");
|
||||
|
||||
// We may already have a pending paint from a previous request when we
|
||||
// were minimized. We just overwrite it.
|
||||
current_paint_callback_ = std::move(paint_callback);
|
||||
|
||||
// This will not return until the WM_PAINT has completed.
|
||||
// Note, if we are minimized this won't do anything.
|
||||
RedrawWindow(hwnd(), nullptr, nullptr,
|
||||
RDW_INTERNALPAINT | RDW_UPDATENOW | RDW_ALLCHILDREN);
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2014 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_UI_GL_WGL_ELEMENTAL_CONTROL_H_
|
||||
#define XENIA_UI_GL_WGL_ELEMENTAL_CONTROL_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "xenia/base/threading.h"
|
||||
#include "xenia/ui/elemental_control.h"
|
||||
#include "xenia/ui/gl/gl_context.h"
|
||||
#include "xenia/ui/loop.h"
|
||||
|
||||
namespace xe {
|
||||
namespace ui {
|
||||
namespace gl {
|
||||
|
||||
class WGLElementalControl : public ElementalControl {
|
||||
public:
|
||||
WGLElementalControl(Loop* loop);
|
||||
~WGLElementalControl() override;
|
||||
|
||||
GLContext* context() { return &context_; }
|
||||
|
||||
void SynchronousRepaint(std::function<void()> paint_callback);
|
||||
|
||||
protected:
|
||||
using super = ElementalControl;
|
||||
|
||||
std::unique_ptr<el::graphics::Renderer> CreateRenderer() override;
|
||||
|
||||
bool Create() override;
|
||||
|
||||
void OnLayout(UIEvent& e) override;
|
||||
|
||||
LRESULT WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) override;
|
||||
|
||||
private:
|
||||
Loop* loop_;
|
||||
GLContext context_;
|
||||
std::function<void()> current_paint_callback_;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace ui
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_UI_GL_WGL_ELEMENTAL_CONTROL_H_
|
||||
Reference in New Issue
Block a user