Make OpenGL always draw something. Where there is no game, display the PPSSPP logo screen.

Add hack for X11 user which can have a crash when opening the first dialog and Gl is drawing.
Remove the "open file" dialog automatic display on startup, very annoying.
This commit is contained in:
Xele02 2013-02-05 22:22:14 +01:00
parent 29347b7bbb
commit 19a3cb9f8e
10 changed files with 347 additions and 104 deletions

View File

@ -17,22 +17,72 @@
#include "gfx_es2/fbo.h"
#include "gfx_es2/gl_state.h"
#include "GPU/GPUState.h"
#include "android/jni/ui_atlas.h"
#include "native/util/random/rng.h"
#include "native/base/timeutil.h"
#include "native/base/colorutil.h"
#include "qtemugl.h"
#include "QtHost.h"
void EmuThread_Start(QString filename, QtEmuGL* w)
namespace
{
static const int symbols[4] = {
I_CROSS,
I_CIRCLE,
I_SQUARE,
I_TRIANGLE
};
static const uint32_t colors[4] = {
/*
0xFF6666FF, // blue
0xFFFF6666, // red
0xFFFF66FF, // pink
0xFF66FF66, // green
*/
0xC0FFFFFF,
0xC0FFFFFF,
0xC0FFFFFF,
0xC0FFFFFF,
};
static void DrawBackground(float alpha) {
static float xbase[100] = {0};
static float ybase[100] = {0};
if (xbase[0] == 0.0f) {
GMRng rng;
for (int i = 0; i < 100; i++) {
xbase[i] = rng.F() * dp_xres;
ybase[i] = rng.F() * dp_yres;
}
}
glClearColor(0.1f,0.2f,0.43f,1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
ui_draw2d.DrawImageStretch(I_BG, 0, 0, dp_xres, dp_yres);
float t = time_now();
for (int i = 0; i < 100; i++) {
float x = xbase[i];
float y = ybase[i] + 40*cos(i * 7.2 + t * 1.3);
float angle = sin(i + t);
int n = i & 3;
ui_draw2d.DrawImageRotated(symbols[n], x, y, 1.0f, angle, colorAlpha(colors[n], alpha * 0.1f));
}
}
}
void EmuThread_Start(QtEmuGL* w)
{
//_dbg_clear_();
fileToStart = filename;
glWindow = w;
glWindow->doneCurrent();
glWindow->start_rendering();
}
void EmuThread_Stop()
{
// DSound_UpdateSound();
Core_Stop();
if(glWindow)
{
glWindow->stop_rendering();
@ -40,6 +90,31 @@ void EmuThread_Stop()
host->UpdateUI();
}
void EmuThread_StartGame(QString filename)
{
if(glWindow)
{
glWindow->start_game(filename);
}
}
void EmuThread_StopGame()
{
if(glWindow)
{
glWindow->stop_game();
}
}
void EmuThread_LockDraw(bool value)
{
if(glWindow)
{
glWindow->LockDraw(value);
}
}
void EmuThread::init(InputState *inputState)
{
input_state = inputState;
@ -50,8 +125,6 @@ void EmuThread::run()
running = true;
setCurrentThreadName("EmuThread");
g_State.bEmuThreadStarted = true;
host->UpdateUI();
host->InitGL();
@ -64,80 +137,181 @@ void EmuThread::run()
INFO_LOG(BOOT, "Starting up hardware.");
CoreParameter coreParameter;
coreParameter.fileToStart = fileToStart.toStdString();
coreParameter.enableSound = true;
coreParameter.gpuCore = GPU_GLES;
coreParameter.cpuCore = (CPUCore)g_Config.iCpuCore;
coreParameter.enableDebugging = true;
coreParameter.printfEmuLog = false;
coreParameter.headLess = false;
coreParameter.renderWidth = 480 * g_Config.iWindowZoom;
coreParameter.renderHeight = 272 * g_Config.iWindowZoom;
coreParameter.outputWidth = dp_xres;
coreParameter.outputHeight = dp_yres;
coreParameter.pixelWidth = pixel_xres;
coreParameter.pixelHeight = pixel_yres;
coreParameter.startPaused = !g_Config.bAutoRun;
std::string error_string;
if (!PSP_Init(coreParameter, &error_string))
{
ERROR_LOG(BOOT, "Error loading: %s", error_string.c_str());
FinalShutdown();
return;
}
LayoutGamepad(dp_xres, dp_yres);
_dbg_update_();
host->UpdateDisassembly();
Core_EnableStepping(coreParameter.startPaused ? TRUE : FALSE);
g_State.bBooted = true;
#ifdef _DEBUG
host->UpdateMemView();
#endif
host->BootDone();
QElapsedTimer timer;
while(running) {
//UpdateGamepad(*input_state);
timer.start();
UpdateInputState(input_state);
gameMutex.lock();
bool gRun = gameRunning;
gameMutex.unlock();
for (int i = 0; i < controllistCount; i++) {
if (input_state->pad_buttons_down & controllist[i].emu_id) {
__CtrlButtonDown(controllist[i].psp_id);
if(gRun)
{
gameMutex.lock();
glWindow->makeCurrent();
if(needInitGame)
{
g_State.bEmuThreadStarted = true;
CoreParameter coreParameter;
coreParameter.fileToStart = fileToStart.toStdString();
coreParameter.enableSound = true;
coreParameter.gpuCore = GPU_GLES;
coreParameter.cpuCore = (CPUCore)g_Config.iCpuCore;
coreParameter.enableDebugging = true;
coreParameter.printfEmuLog = false;
coreParameter.headLess = false;
coreParameter.renderWidth = 480 * g_Config.iWindowZoom;
coreParameter.renderHeight = 272 * g_Config.iWindowZoom;
coreParameter.outputWidth = dp_xres;
coreParameter.outputHeight = dp_yres;
coreParameter.pixelWidth = pixel_xres;
coreParameter.pixelHeight = pixel_yres;
coreParameter.startPaused = !g_Config.bAutoRun;
std::string error_string;
if (!PSP_Init(coreParameter, &error_string))
{
ERROR_LOG(BOOT, "Error loading: %s", error_string.c_str());
FinalShutdown();
return;
}
LayoutGamepad(dp_xres, dp_yres);
_dbg_update_();
host->UpdateDisassembly();
Core_EnableStepping(coreParameter.startPaused ? TRUE : FALSE);
g_State.bBooted = true;
#ifdef _DEBUG
host->UpdateMemView();
#endif
host->BootDone();
needInitGame = false;
}
if (input_state->pad_buttons_up & controllist[i].emu_id) {
__CtrlButtonUp(controllist[i].psp_id);
UpdateInputState(input_state);
for (int i = 0; i < controllistCount; i++) {
if (input_state->pad_buttons_down & controllist[i].emu_id) {
__CtrlButtonDown(controllist[i].psp_id);
}
if (input_state->pad_buttons_up & controllist[i].emu_id) {
__CtrlButtonUp(controllist[i].psp_id);
}
}
__CtrlSetAnalog(input_state->pad_lstick_x, input_state->pad_lstick_y);
EndInputState(input_state);
glstate.Restore();
glViewport(0, 0, pixel_xres, pixel_yres);
Matrix4x4 ortho;
ortho.setOrtho(0.0f, dp_xres, dp_yres, 0.0f, -1.0f, 1.0f);
glsl_bind(UIShader_Get());
glUniformMatrix4fv(UIShader_Get()->u_worldviewproj, 1, GL_FALSE, ortho.getReadPtr());
ReapplyGfxState();
Core_Run();
// Hopefully coreState is now CORE_NEXTFRAME
if (coreState == CORE_NEXTFRAME) {
// set back to running for the next frame
coreState = CORE_RUNNING;
qint64 time = timer.elapsed();
const int frameTime = (1.0f/60.0f) * 1000;
gameMutex.unlock();
if(time < frameTime)
{
glWindow->doneCurrent();
msleep(frameTime-time);
glWindow->makeCurrent();
}
gameMutex.lock();
timer.start();
}
fbo_unbind();
UIShader_Prepare();
uiTexture->Bind(0);
glViewport(0, 0, pixel_xres, pixel_yres);
ui_draw2d.Begin(DBMODE_NORMAL);
//if (g_Config.bShowTouchControls)
// DrawGamepad(ui_draw2d);
glsl_bind(UIShader_Get());
ui_draw2d.End();
ui_draw2d.Flush(UIShader_Get());
// Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it?
#if defined(USING_GLES2)
bool hasDiscard = false; // TODO
if (hasDiscard) {
//glDiscardFramebuffer(GL_COLOR_EXT | GL_DEPTH_EXT | GL_STENCIL_EXT);
}
#endif
glWindow->swapBuffers();
glWindow->doneCurrent();
gameMutex.unlock();
}
__CtrlSetAnalog(input_state->pad_lstick_x, input_state->pad_lstick_y);
else
{
gameMutex.lock();
glWindow->makeCurrent();
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
EndInputState(input_state);
time_update();
float t = (float)frames_ / 60.0f;
frames_++;
glstate.Restore();
glViewport(0, 0, pixel_xres, pixel_yres);
Matrix4x4 ortho;
ortho.setOrtho(0.0f, dp_xres, dp_yres, 0.0f, -1.0f, 1.0f);
glsl_bind(UIShader_Get());
glUniformMatrix4fv(UIShader_Get()->u_worldviewproj, 1, GL_FALSE, ortho.getReadPtr());
float alpha = t;
if (t > 1.0f) alpha = 1.0f;
float alphaText = alpha;
//if (t > 2.0f) alphaText = 3.0f - t;
glstate.Restore();
glViewport(0, 0, pixel_xres, pixel_yres);
Matrix4x4 ortho;
ortho.setOrtho(0.0f, dp_xres, dp_yres, 0.0f, -1.0f, 1.0f);
glsl_bind(UIShader_Get());
glUniformMatrix4fv(UIShader_Get()->u_worldviewproj, 1, GL_FALSE, ortho.getReadPtr());
ReapplyGfxState();
ReapplyGfxState();
Core_Run();
UIShader_Prepare();
UIBegin();
DrawBackground(alpha);
// Hopefully coreState is now CORE_NEXTFRAME
if (coreState == CORE_NEXTFRAME) {
// set back to running for the next frame
coreState = CORE_RUNNING;
ui_draw2d.SetFontScale(1.5f, 1.5f);
ui_draw2d.DrawText(UBUNTU48, "PPSSPP", dp_xres / 2, dp_yres / 2 - 30, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
ui_draw2d.SetFontScale(1.0f, 1.0f);
ui_draw2d.DrawText(UBUNTU24, "Created by Henrik Rydgard", dp_xres / 2, dp_yres / 2 + 40, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
ui_draw2d.DrawText(UBUNTU24, "Free Software under GPL 2.0", dp_xres / 2, dp_yres / 2 + 70, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
ui_draw2d.DrawText(UBUNTU24, "www.ppsspp.org", dp_xres / 2, dp_yres / 2 + 130, colorAlpha(0xFFFFFFFF, alphaText), ALIGN_CENTER);
UIEnd();
glsl_bind(UIShader_Get());
ui_draw2d.Flush(UIShader_Get());
glWindow->swapBuffers();
glWindow->doneCurrent();
gameMutex.unlock();
qint64 time = timer.elapsed();
const int frameTime = (1.0f/60.0f) * 1000;
if(time < frameTime)
@ -147,41 +321,18 @@ void EmuThread::run()
timer.start();
}
fbo_unbind();
UIShader_Prepare();
uiTexture->Bind(0);
glViewport(0, 0, pixel_xres, pixel_yres);
ui_draw2d.Begin(DBMODE_NORMAL);
//if (g_Config.bShowTouchControls)
// DrawGamepad(ui_draw2d);
glsl_bind(UIShader_Get());
ui_draw2d.End();
ui_draw2d.Flush(UIShader_Get());
// Tiled renderers like PowerVR should benefit greatly from this. However - seems I can't call it?
#if defined(USING_GLES2)
bool hasDiscard = false; // TODO
if (hasDiscard) {
//glDiscardFramebuffer(GL_COLOR_EXT | GL_DEPTH_EXT | GL_STENCIL_EXT);
}
#endif
glWindow->swapBuffers();
}
glWindow->doneCurrent();
if(gameRunning)
{
stopGame();
}
}
void EmuThread::Shutdown()
{
host->PrepareShutdown();
PSP_Shutdown();
FinalShutdown();
}
void EmuThread::FinalShutdown()
@ -189,7 +340,6 @@ void EmuThread::FinalShutdown()
host->ShutdownGL();
delete uiTexture;
uiTexture = NULL;
@ -197,10 +347,6 @@ void EmuThread::FinalShutdown()
gl_lost_manager_shutdown();
// TODO
//The CPU should return when a game is stopped and cleanup should be done here,
//so we can restart the plugins (or load new ones) for the next game
g_State.bEmuThreadStarted = false;
//_endthreadex(0);
//return 0;
}
@ -210,4 +356,31 @@ void EmuThread::setRunning(bool value)
running = false;
}
void EmuThread::startGame(QString filename)
{
gameMutex.lock();
needInitGame = true;
gameRunning = true;
fileToStart = filename;
gameMutex.unlock();
}
void EmuThread::stopGame()
{
Core_Stop();
gameMutex.lock();
gameRunning = false;
PSP_Shutdown();
// TODO
//The CPU should return when a game is stopped and cleanup should be done here,
//so we can restart the plugins (or load new ones) for the next game
g_State.bEmuThreadStarted = false;
frames_ = 0;
gameMutex.unlock();
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <QThread>
#include <QMutex>
#include "input/input_state.h"
class QtEmuGL;
@ -7,17 +8,27 @@ class QtEmuGL;
class EmuThread : public QThread
{
public:
EmuThread() : running(false) {}
EmuThread() : running(false), gameRunning(false), needInitGame(false), frames_(0) {}
void init(InputState* inputState);
void run();
void FinalShutdown();
void setRunning(bool value);
void startGame(QString filename);
void stopGame();
QMutex gameMutex;
public slots:
void Shutdown();
private:
InputState* input_state;
bool running;
bool gameRunning;
bool needInitGame;
int frames_;
};
void EmuThread_Start(QString filename, QtEmuGL* w);
void EmuThread_Start(QtEmuGL* w);
void EmuThread_Stop();
void EmuThread_StartGame(QString filename);
void EmuThread_StopGame();
void EmuThread_LockDraw(bool value);

View File

@ -1,6 +1,8 @@
#include "controls.h"
#include "ui_controls.h"
#include "Core/Config.h"
#include "EmuThread.h"
#include <QTimer>
Controls_ controllist[] = {
{"Edit_Start", "Start", Qt::Key_1, PAD_BUTTON_START, CTRL_START},
@ -43,6 +45,12 @@ Controls::~Controls()
void Controls::showEvent(QShowEvent*)
{
#ifdef Q_WS_X11
// Hack to remove the X11 crash with threaded opengl when opening the first dialog
EmuThread_LockDraw(true);
QTimer::singleShot(100, this, SLOT(releaseLock()));
#endif
for(int i = 0; i < controllistCount; i++)
{
if(g_Config.iMappingMap.find(i) != g_Config.iMappingMap.end())
@ -62,6 +70,11 @@ void Controls::showEvent(QShowEvent*)
}
}
void Controls::releaseLock()
{
EmuThread_LockDraw(false);
}
void Controls::on_buttonBox_accepted()
{
for(int i = 0; i < controllistCount; i++)

View File

@ -32,6 +32,7 @@ public:
void showEvent(QShowEvent *);
private slots:
void releaseLock();
void on_buttonBox_accepted();
private:

View File

@ -2,6 +2,7 @@
#include "ui_gamepaddialog.h"
#include <QTimer>
#include "Core/Config.h"
#include "EmuThread.h"
// Input
struct GamePadInfo
@ -96,6 +97,20 @@ GamePadDialog::~GamePadDialog()
delete ui;
}
void GamePadDialog::showEvent(QShowEvent *)
{
#ifdef Q_WS_X11
// Hack to remove the X11 crash with threaded opengl when opening the first dialog
EmuThread_LockDraw(true);
QTimer::singleShot(100, this, SLOT(releaseLock()));
#endif
}
void GamePadDialog::releaseLock()
{
EmuThread_LockDraw(false);
}
void GamePadDialog::on_refreshListBtn_clicked()
{
#if QT_HAS_SDL

View File

@ -23,7 +23,10 @@ public:
void SetViewMode();
void SetCalibMode();
void CalibNextButton();
protected:
void showEvent(QShowEvent *);
private slots:
void releaseLock();
void on_refreshListBtn_clicked();
void on_SelectPadBtn_clicked();

View File

@ -55,16 +55,16 @@ MainWindow::MainWindow(QWidget *parent) :
if (zoom > 4) zoom = 4;
SetZoom(zoom);
EmuThread_Start(w);
if (!fileToStart.isNull())
{
SetPlaying(fileToStart);
//Update();
UpdateMenus();
EmuThread_Start(fileToStart, w);
EmuThread_StartGame(fileToStart);
}
else
BrowseAndBoot();
if (!fileToStart.isNull() && stateToLoad != NULL)
SaveState::Load(stateToLoad);
@ -195,7 +195,7 @@ void MainWindow::BrowseAndBoot(void)
{
QFileInfo info(filename);
g_Config.currentDirectory = info.absolutePath().toStdString();
EmuThread_Start(filename, w);
EmuThread_StartGame(filename);
}
}
@ -324,7 +324,7 @@ void MainWindow::on_action_EmulationStop_triggered()
if (memoryWindow[i])
SendMessage(memoryWindow[i]->GetDlgHandle(), WM_CLOSE, 0, 0);*/
EmuThread_Stop();
EmuThread_StopGame();
SetPlaying(0);
//Update();
UpdateMenus();
@ -485,6 +485,7 @@ void MainWindow::on_action_OptionsHardwareTransform_triggered()
void MainWindow::on_action_FileExit_triggered()
{
on_action_EmulationStop_triggered();
EmuThread_Stop();
QApplication::exit(0);
}

View File

@ -38,6 +38,28 @@ void QtEmuGL::stop_rendering()
thread.Shutdown();
}
void QtEmuGL::start_game(QString filename)
{
thread.startGame(filename);
}
void QtEmuGL::stop_game()
{
thread.stopGame();
}
void QtEmuGL::LockDraw(bool value)
{
if(value)
{
thread.gameMutex.lock();
}
else
{
thread.gameMutex.unlock();
}
}
void QtEmuGL::resizeEvent(QResizeEvent *evt)
{
// TODO

View File

@ -16,6 +16,9 @@ public:
void start_rendering();
void stop_rendering();
void start_game(QString filename);
void stop_game();
void LockDraw(bool value);
protected:
void initializeGL();

View File

@ -451,6 +451,7 @@ static const char *credits[] =
"soywiz",
"kovensky",
"raven02",
"xele",
"",
"Written in C++ for speed and portability",
"",