Rough fix for threaded GL for Qt.

This commit is contained in:
Henrik Rydgård 2018-01-31 12:05:18 +01:00
parent 3a988400a7
commit 98cfaef6ec
2 changed files with 117 additions and 23 deletions

View File

@ -29,6 +29,7 @@
#include "QtMain.h"
#include "gfx_es2/gpu_features.h"
#include "math/math_util.h"
#include "thread/threadutil.h"
#include <string.h>
@ -188,31 +189,64 @@ static int mainInternal(QApplication &a)
return a.exec();
}
void MainUI::EmuThreadFunc() {
ILOG("In emu thread");
setCurrentThreadName("Emu");
// There's no real requirement that NativeInit happen on this thread.
// We just call the update/render loop here.
emuThreadState = (int)EmuThreadState::RUNNING;
while (emuThreadState != (int)EmuThreadState::QUIT_REQUESTED) {
#ifdef SDL
SDL_PumpEvents();
#endif
updateAccelerometer();
time_update();
UpdateRunLoop();
}
emuThreadState = (int)EmuThreadState::STOPPED;
}
void MainUI::EmuThreadStart() {
emuThreadState = (int)EmuThreadState::START_REQUESTED;
emuThread = std::thread([&]() { this->EmuThreadFunc(); } );
}
void MainUI::EmuThreadStop() {
emuThreadState = (int)EmuThreadState::QUIT_REQUESTED;
emuThread.join();
emuThread = std::thread();
}
MainUI::MainUI(QWidget *parent):
QGLWidget(parent)
QGLWidget(parent)
{
setAttribute(Qt::WA_AcceptTouchEvents);
emuThreadState = (int)EmuThreadState::DISABLED;
setAttribute(Qt::WA_AcceptTouchEvents);
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
setAttribute(Qt::WA_LockLandscapeOrientation);
setAttribute(Qt::WA_LockLandscapeOrientation);
#endif
#if defined(MOBILE_DEVICE)
acc = new QAccelerometer(this);
acc->start();
acc = new QAccelerometer(this);
acc->start();
#endif
setFocus();
setFocusPolicy(Qt::StrongFocus);
startTimer(16);
setFocus();
setFocusPolicy(Qt::StrongFocus);
startTimer(16);
}
MainUI::~MainUI()
{
if (useThread_) {
EmuThreadStop();
}
#if defined(MOBILE_DEVICE)
delete acc;
delete acc;
#endif
NativeShutdownGraphics();
graphicsContext->Shutdown();
delete graphicsContext;
graphicsContext = nullptr;
NativeShutdownGraphics();
graphicsContext->Shutdown();
delete graphicsContext;
graphicsContext = nullptr;
}
QString MainUI::InputBoxGetQString(QString title, QString defaultValue)
@ -330,18 +364,36 @@ void MainUI::initializeGL()
if (gl_extensions.IsCoreContext)
glGetError();
#endif
ILOG("Initializing graphics context");
graphicsContext = new QtDummyGraphicsContext();
NativeInitGraphics(graphicsContext);
// OpenGL uses a background thread to do the main processing and only renders on the gl thread.
useThread_ = g_Config.iGPUBackend == (int)GPUBackend::OPENGL;
if (useThread_) {
ILOG("Using thread, starting emu thread");
EmuThreadStart();
graphicsContext->ThreadStart();
} else {
ILOG("Not using thread, backend=%d", (int)g_Config.iGPUBackend);
}
}
void MainUI::paintGL()
{
#ifdef SDL
SDL_PumpEvents();
#endif
updateAccelerometer();
time_update();
UpdateRunLoop();
if (useThread_) {
graphicsContext->ThreadFrame();
// Do the rest in EmuThreadFunc
} else {
#ifdef SDL
SDL_PumpEvents();
#endif
updateAccelerometer();
time_update();
UpdateRunLoop();
}
}
void MainUI::updateAccelerometer()
@ -454,14 +506,17 @@ int main(int argc, char *argv[])
#endif
savegame_dir += "/";
external_dir += "/";
bool fullscreenCLI=false;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i],"--fullscreen"))
fullscreenCLI=true;
}
NativeInit(argc, (const char **)argv, savegame_dir.c_str(), external_dir.c_str(), nullptr, fullscreenCLI);
// TODO: Support other backends than GL, like Vulkan, in the Qt backend.
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
int ret = mainInternal(a);
NativeShutdownGraphics();

View File

@ -19,6 +19,8 @@ QTM_USE_NAMESPACE
#endif
#include <cassert>
#include <atomic>
#include <thread>
#include "base/display.h"
#include "base/logging.h"
@ -37,6 +39,7 @@ QTM_USE_NAMESPACE
#include "Core/Core.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "thin3d/GLRenderManager.h"
// Input
void SimulateGamepad();
@ -47,21 +50,48 @@ public:
CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext();
SetGPUBackend(GPUBackend::OPENGL);
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
bool success = draw_->CreatePresets();
assert(success);
}
~QtDummyGraphicsContext() {
delete draw_;
draw_ = nullptr;
renderManager_ = nullptr;
}
Draw::DrawContext *GetDrawContext() override {
return draw_;
}
void ThreadStart() override {
renderManager_->ThreadStart();
}
bool ThreadFrame() override {
return renderManager_->ThreadFrame();
}
void ThreadEnd() override {
renderManager_->ThreadEnd();
}
private:
Draw::DrawContext *draw_;
Draw::DrawContext *draw_ = nullptr;
GLRenderManager *renderManager_ = nullptr;
};
//GUI
enum class EmuThreadState {
DISABLED,
START_REQUESTED,
RUNNING,
QUIT_REQUESTED,
STOPPED,
};
// GUI, thread manager
class MainUI : public QGLWidget
{
Q_OBJECT
@ -87,6 +117,10 @@ protected:
void updateAccelerometer();
void EmuThreadFunc();
void EmuThreadStart();
void EmuThreadStop();
private:
QtDummyGraphicsContext *graphicsContext;
@ -94,6 +128,11 @@ private:
#if defined(MOBILE_DEVICE)
QAccelerometer* acc;
#endif
std::thread emuThread;
std::atomic<int> emuThreadState;
bool useThread_ = false;
};
extern MainUI* emugl;