Skip to content

Commit

Permalink
OpenGL: Now run GL on a secondary thread. Sync issues remain.
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Jan 27, 2018
1 parent e4752a8 commit af64319
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 34 deletions.
5 changes: 1 addition & 4 deletions Common/GraphicsContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ class GraphicsContext {
public:
virtual ~GraphicsContext() {}

// Threaded backends (that need to do init on the final render thread, like GL)
// call this from the render thread. Init() should block until InitFromThread is done.
// Other backends can ignore this.
virtual bool InitFromThread() { return true; }
virtual bool InitFromRenderThread(std::string *errorMessage) { return true; }

virtual void Shutdown() = 0;
virtual void SwapInterval(int interval) = 0;
Expand Down
1 change: 0 additions & 1 deletion GPU/GLES/FramebufferManagerGLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ void FramebufferManagerGLES::CompilePostShader() {
postShaderProgram_ = nullptr;
usePostShader_ = false;
}
glsl_unbind();
}

void FramebufferManagerGLES::Bind2DShader() {
Expand Down
2 changes: 1 addition & 1 deletion UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ void EmuScreen::bootComplete() {

#if !PPSSPP_PLATFORM(UWP)
if (GetGPUBackend() == GPUBackend::OPENGL) {
const char *renderer = (const char*)glGetString(GL_RENDERER);
const char *renderer = gl_extensions.model;
if (strstr(renderer, "Chainfire3D") != 0) {
osm.Show(sc->T("Chainfire3DWarning", "WARNING: Chainfire3D detected, may cause problems"), 10.0f, 0xFF30a0FF, -1, true);
} else if (strstr(renderer, "GLTools") != 0) {
Expand Down
46 changes: 36 additions & 10 deletions Windows/EmuThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ static std::thread renderThread;
static std::atomic<int> renderThreadReady;

static bool useRenderThread;
static bool renderThreadFailed;
static bool renderThreadSucceeded;
static std::string g_error_message;

extern std::vector<std::wstring> GetWideCmdLine();

Expand Down Expand Up @@ -85,15 +88,23 @@ bool EmuThread_Ready() {

void RenderThreadFunc() {
setCurrentThreadName("Render");
renderThreadFailed = false;
renderThreadSucceeded = false;
while (!g_graphicsContext) {
sleep_ms(50);
sleep_ms(10);
continue;
}
g_graphicsContext->InitFromThread();
while (true) {
g_graphicsContext->ThreadFrame();
break;

std::string error_message;
if (!g_graphicsContext->InitFromRenderThread(&error_message)) {
g_error_message = error_message;
renderThreadFailed = true;
return;
} else {
renderThreadSucceeded = true;
}

g_graphicsContext->ThreadFrame();
}

void EmuThreadFunc() {
Expand All @@ -119,10 +130,25 @@ void EmuThreadFunc() {

host->UpdateUI();

GraphicsContext *graphicsContext = nullptr;

std::string error_string;
if (!host->InitGraphics(&error_string, &graphicsContext)) {
bool success = host->InitGraphics(&error_string, &g_graphicsContext);

if (success) {
if (!useRenderThread) {
// This is also the render thread.
success = g_graphicsContext->InitFromRenderThread(&error_string);
} else {
while (!renderThreadFailed && !renderThreadSucceeded) {
sleep_ms(10);
}
success = renderThreadSucceeded;
if (!success) {
error_string = g_error_message;
}
}
}

if (!success) {
// Before anything: are we restarting right now?
if (performingRestart) {
// Okay, switching graphics didn't work out. Probably a driver bug - fallback to restart.
Expand Down Expand Up @@ -171,7 +197,7 @@ void EmuThreadFunc() {
exit(1);
}

NativeInitGraphics(graphicsContext);
NativeInitGraphics(g_graphicsContext);
NativeResized();

INFO_LOG(BOOT, "Done.");
Expand All @@ -194,7 +220,7 @@ void EmuThreadFunc() {
// This way they can load a new game.
if (!Core_IsActive())
UpdateUIState(UISTATE_MENU);
Core_Run(graphicsContext);
Core_Run(g_graphicsContext);
}

shutdown:
Expand Down
26 changes: 20 additions & 6 deletions Windows/GPU/WindowsGLContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "gfx/gl_common.h"
#include "gfx/gl_debug_log.h"
#include "gfx_es2/gpu_features.h"
#include "thin3d/GLRenderManager.h"
#include "GL/gl.h"
#include "GL/wglew.h"
#include "Core/Config.h"
Expand All @@ -34,7 +35,8 @@
#include "Windows/GPU/WindowsGLContext.h"

void WindowsGLContext::SwapBuffers() {
::SwapBuffers(hDC);
renderManager_->Swap();

// Used during fullscreen switching to prevent rendering.
if (pauseRequested) {
SetEvent(pauseEvent);
Expand Down Expand Up @@ -151,10 +153,16 @@ void DebugCallbackARB(GLenum source, GLenum type, GLuint id, GLenum severity,
}

bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_message) {
hInst_ = hInst;
hWnd_ = window;
*error_message = "ok";
return true;
}

bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
glslang::InitializeProcess();

*error_message = "ok";
hWnd = window;
GLuint PixelFormat;

// TODO: Change to use WGL_ARB_pixel_format instead
Expand All @@ -179,7 +187,7 @@ bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_mes
0, 0, 0 // Layer Masks Ignored
};

hDC = GetDC(hWnd);
hDC = GetDC(hWnd_);

if (!hDC) {
*error_message = "Failed to get a device context.";
Expand Down Expand Up @@ -239,7 +247,7 @@ bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_mes
std::wstring title = ConvertUTF8ToWString(err->T("OpenGLDriverError", "OpenGL driver error"));
std::wstring combined = versionDetected + error;

bool yes = IDYES == MessageBox(hWnd, combined.c_str(), title.c_str(), MB_ICONERROR | MB_YESNO);
bool yes = IDYES == MessageBox(hWnd_, combined.c_str(), title.c_str(), MB_ICONERROR | MB_YESNO);

if (yes) {
// Change the config to D3D and restart.
Expand Down Expand Up @@ -362,8 +370,10 @@ bool WindowsGLContext::Init(HINSTANCE hInst, HWND window, std::string *error_mes

CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext();
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
SetGPUBackend(GPUBackend::OPENGL);
bool success = draw_->CreatePresets(); // if we get this far, there will always be a GLSL compiler capable of compiling these.
renderManager_->SetSwapFunction([&]() {::SwapBuffers(hDC); });
assert(success);
CHECK_GL_ERROR_IF_DEBUG();
return true; // Success
Expand Down Expand Up @@ -393,16 +403,20 @@ void WindowsGLContext::Shutdown() {
hRC = NULL;
}

if (hDC && !ReleaseDC(hWnd,hDC)) {
if (hDC && !ReleaseDC(hWnd_, hDC)) {
DWORD err = GetLastError();
if (err != ERROR_DC_NOT_FOUND) {
MessageBox(NULL, L"Release device context failed.", L"SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
hDC = NULL;
}
hWnd = NULL;
hWnd_ = NULL;
glslang::FinalizeProcess();
}

void WindowsGLContext::Resize() {
}

void WindowsGLContext::ThreadFrame() {
renderManager_->ThreadFunc();
}
11 changes: 10 additions & 1 deletion Windows/GPU/WindowsGLContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ namespace Draw {
class DrawContext;
}

class GLRenderManager;

class WindowsGLContext : public WindowsGraphicsContext {
public:
bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override;

bool InitFromRenderThread(std::string *errorMessage) override;

void Shutdown() override;
void SwapInterval(int interval) override;
void SwapBuffers() override;
Expand All @@ -21,13 +25,18 @@ class WindowsGLContext : public WindowsGraphicsContext {
void Resume() override;
void Resize() override;

void ThreadFrame() override;

Draw::DrawContext *GetDrawContext() override { return draw_; }

private:
bool renderThread_;
Draw::DrawContext *draw_;
GLRenderManager *renderManager_;
HINSTANCE hInst_;
HDC hDC; // Private GDI Device Context
HGLRC hRC; // Permanent Rendering Context
HWND hWnd; // Holds Our Window Handle
HWND hWnd_; // Holds Our Window Handle
volatile bool pauseRequested;
volatile bool resumeRequested;
HANDLE pauseEvent;
Expand Down
4 changes: 3 additions & 1 deletion Windows/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,9 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
}

// Emu thread (and render thread, if any) is always running!
EmuThread_Start(false); // g_Config.iGPUBackend == GPU_BACKEND_VULKAN);
// Only OpenGL uses an externally managed render thread (due to GL's single-threaded context design). Vulkan
// manages its own render thread.
EmuThread_Start(g_Config.iGPUBackend == (int)GPUBackend::OPENGL);
InputDevice::BeginPolling();

HACCEL hAccelTable = LoadAccelerators(_hInstance, (LPCTSTR)IDR_ACCELS);
Expand Down
25 changes: 17 additions & 8 deletions ext/native/thin3d/GLRenderManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ GLRenderManager::GLRenderManager() {
}

if (!useThread_) {
queueRunner_.CreateDeviceObjects();
// The main thread is also the render thread.
ThreadStartup();
}
}

Expand All @@ -54,16 +55,22 @@ GLRenderManager::~GLRenderManager() {
}

if (!useThread_) {
queueRunner_.DestroyDeviceObjects();
// The main thread is also the render thread.
ThreadEnd();
}
}

void GLRenderManager::ThreadStartup() {
queueRunner_.CreateDeviceObjects();
}

void GLRenderManager::ThreadEnd() {
queueRunner_.DestroyDeviceObjects();
}

void GLRenderManager::ThreadFunc() {
setCurrentThreadName("RenderMan");
ThreadStartup();
int threadFrame = threadInitFrame_;
bool nextFrame = false;
bool firstFrame = true;
queueRunner_.CreateDeviceObjects();
while (true) {
{
if (nextFrame) {
Expand Down Expand Up @@ -344,7 +351,9 @@ void GLRenderManager::EndSubmitFrame(int frame) {
Submit(frame, true);

if (!frameData.skipSwap) {
// glSwapBuffers();
if (swapFunction_) {
swapFunction_();
}
} else {
frameData.skipSwap = false;
}
Expand Down Expand Up @@ -540,4 +549,4 @@ size_t GLPushBuffer::GetTotalSize() const {
sum += size_ * (buffers_.size() - 1);
sum += offset_;
return sum;
}
}
23 changes: 21 additions & 2 deletions ext/native/thin3d/GLRenderManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <thread>
#include <unordered_map>
#include <vector>
#include <functional>
#include <set>
#include <string>
#include <mutex>
Expand Down Expand Up @@ -622,7 +623,20 @@ class GLRenderManager {
frameData_[frame].activePushBuffers.erase(iter);
}

void SetSwapFunction(std::function<void()> swapFunction) {
swapFunction_ = swapFunction;
}

void Swap() {
if (!useThread_ && swapFunction_) {
swapFunction_();
}
}

private:
void ThreadStartup();
void ThreadEnd();

void BeginSubmitFrame(int frame);
void EndSubmitFrame(int frame);
void Submit(int frame, bool triggerFence);
Expand Down Expand Up @@ -668,17 +682,22 @@ class GLRenderManager {

// Execution time state
bool run_ = true;
// Thread is managed elsewhere, and should call ThreadFunc.
// Thread is managed elsewhere, and should call ThreadFrame.
std::mutex mutex_;
int threadInitFrame_ = 0;
GLQueueRunner queueRunner_;

bool nextFrame = false;
bool firstFrame = true;

GLDeleter deleter_;

bool useThread_ = false;
bool useThread_ = true;

int curFrame_ = 0;

std::function<void()> swapFunction_;

int targetWidth_ = 0;
int targetHeight_ = 0;
};
Expand Down

0 comments on commit af64319

Please sign in to comment.