Merge pull request #10580 from hrydgard/gl-render-manager-fixes

GL render manager fixes
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2018-02-04 21:11:57 +01:00
commit f999830027
18 files changed
+502 -383

No files matched your search

+3 -1
View File
@@ -776,7 +776,9 @@ elseif(TARGET SDL2::SDL2)
set(nativeExtra ${nativeExtra}
SDL/SDLJoystick.h
SDL/SDLJoystick.cpp
SDL/SDLMain.cpp)
SDL/SDLMain.cpp
SDL/SDLGLGraphicsContext.cpp
SDL/SDLVulkanGraphicsContext.cpp)
set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2)
if(APPLE)
set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm)
+1 -1
View File
@@ -359,7 +359,7 @@ void VulkanDeviceAllocator::ExecuteFree(FreeInfo *userdata) {
slab.allocSizes.erase(it);
} else {
// Ack, a double free?
_assert_msg_(G3D, false, "Double free? Block missing at offset %d", userdata->offset);
_assert_msg_(G3D, false, "Double free? Block missing at offset %d", (int)userdata->offset);
}
found = true;
break;
+10 -10
View File
@@ -395,8 +395,8 @@ void PSPSaveDialog::DisplaySaveDataInfo1()
} else {
char title[512];
char time[512];
char saveTitle[512];
char saveDetail[512];
char saveTitle[1024];
char saveDetail[1024];
char am_pm[] = "AM";
char hour_time[10] ;
@@ -421,27 +421,27 @@ void PSPSaveDialog::DisplaySaveDataInfo1()
snprintf(hour_time,10,"%02d:%02d %s", hour, min, am_pm);
}
snprintf(title, 512, "%s", param.GetFileInfo(currentSelectedSave).title);
snprintf(title, sizeof(title), "%s", param.GetFileInfo(currentSelectedSave).title);
int day = param.GetFileInfo(currentSelectedSave).modif_time.tm_mday;
int month = param.GetFileInfo(currentSelectedSave).modif_time.tm_mon + 1;
int year = param.GetFileInfo(currentSelectedSave).modif_time.tm_year + 1900;
s64 sizeK = param.GetFileInfo(currentSelectedSave).size / 1024;
switch (g_Config.iDateFormat) {
case 1:
snprintf(time, 512, "%d/%02d/%02d %s %lld KB", year, month, day, hour_time, sizeK);
snprintf(time, sizeof(time), "%d/%02d/%02d %s %lld KB", year, month, day, hour_time, sizeK);
break;
case 2:
snprintf(time, 512, "%02d/%02d/%d %s %lld KB", month, day, year, hour_time, sizeK);
snprintf(time, sizeof(time), "%02d/%02d/%d %s %lld KB", month, day, year, hour_time, sizeK);
break;
case 3:
snprintf(time, 512, "%02d/%02d/%d %s %lld KB", day, month, year, hour_time, sizeK);
snprintf(time, sizeof(time), "%02d/%02d/%d %s %lld KB", day, month, year, hour_time, sizeK);
break;
default:
snprintf(time, 512, "%d/%02d/%02d %s %lld KB", year, month, day, hour_time, sizeK);
snprintf(time, sizeof(time), "%d/%02d/%02d %s %lld KB", year, month, day, hour_time, sizeK);
}
snprintf(saveTitle, 512, "%s", param.GetFileInfo(currentSelectedSave).saveTitle);
snprintf(saveDetail, 512, "%s", param.GetFileInfo(currentSelectedSave).saveDetail);
snprintf(saveTitle, sizeof(saveTitle), "%s", param.GetFileInfo(currentSelectedSave).saveTitle);
snprintf(saveDetail, sizeof(saveDetail), "%s", param.GetFileInfo(currentSelectedSave).saveDetail);
PPGeDrawRect(180, 136, 480, 137, CalcFadedColor(0xFFFFFFFF));
std::string titleTxt = title;
std::string timeTxt = time;
+24 -22
View File
@@ -140,8 +140,7 @@ float CalculateDPIScale()
#endif
}
static int mainInternal(QApplication &a)
{
static int mainInternal(QApplication &a) {
#ifdef MOBILE_DEVICE
emugl = new MainUI();
emugl->resize(pixel_xres, pixel_yres);
@@ -186,15 +185,19 @@ static int mainInternal(QApplication &a)
QScopedPointer<MainAudio> audio(new MainAudio());
audio->run();
#endif
return a.exec();
int retval = a.exec();
delete emugl;
return retval;
}
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.
// There's no real requirement that NativeInit happen on this thread, though it can't hurt...
// We just call the update/render loop here. NativeInitGraphics should be here though.
NativeInitGraphics(graphicsContext);
emuThreadState = (int)EmuThreadState::RUNNING;
while (emuThreadState != (int)EmuThreadState::QUIT_REQUESTED) {
#ifdef SDL
@@ -204,6 +207,8 @@ void MainUI::EmuThreadFunc() {
time_update();
UpdateRunLoop();
}
NativeShutdownGraphics();
emuThreadState = (int)EmuThreadState::STOPPED;
}
@@ -237,13 +242,14 @@ MainUI::MainUI(QWidget *parent):
MainUI::~MainUI()
{
if (useThread_) {
ILOG("MainUI::Destructor");
if (emuThreadState != (int)EmuThreadState::DISABLED) {
ILOG("EmuThreadStop");
EmuThreadStop();
}
#if defined(MOBILE_DEVICE)
delete acc;
#endif
NativeShutdownGraphics();
graphicsContext->Shutdown();
delete graphicsContext;
graphicsContext = nullptr;
@@ -365,34 +371,30 @@ void MainUI::initializeGL()
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;
graphicsContext = new QtDummyGraphicsContext();
if (useThread_) {
if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
ILOG("Using thread, starting emu thread");
EmuThreadStart();
graphicsContext->ThreadStart();
} else {
ILOG("Not using thread, backend=%d", (int)g_Config.iGPUBackend);
}
graphicsContext->ThreadStart();
}
void MainUI::paintGL()
{
if (useThread_) {
#ifdef SDL
SDL_PumpEvents();
#endif
updateAccelerometer();
if (emuThreadState == (int)EmuThreadState::DISABLED) {
UpdateRunLoop();
} else {
graphicsContext->ThreadFrame();
// Do the rest in EmuThreadFunc
} else {
#ifdef SDL
SDL_PumpEvents();
#endif
updateAccelerometer();
time_update();
UpdateRunLoop();
}
}
@@ -518,8 +520,8 @@ int main(int argc, char *argv[])
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
int ret = mainInternal(a);
ILOG("Left mainInternal here.");
NativeShutdownGraphics();
#ifdef SDL
SDL_PauseAudio(1);
SDL_CloseAudio();
-2
View File
@@ -131,8 +131,6 @@ private:
std::thread emuThread;
std::atomic<int> emuThreadState;
bool useThread_ = false;
};
extern MainUI* emugl;
+13 -2
View File
@@ -72,6 +72,17 @@ void MainWindow::newFrame()
updateMenus();
}
std::unique_lock<std::mutex> lock(msgMutex_);
while (!msgQueue_.empty()) {
MainWindowMsg msg = msgQueue_.front();
msgQueue_.pop();
switch (msg) {
case MainWindowMsg::BOOT_DONE:
bootDone();
break;
}
}
}
void MainWindow::updateMenus()
@@ -128,8 +139,7 @@ void MainWindow::updateMenus()
emit updateMenu();
}
/* SLOTS */
void MainWindow::Boot()
void MainWindow::bootDone()
{
dialogDisasm = new Debugger_Disasm(currentDebugMIPS, this, this);
if(g_Config.bShowDebuggerOnLoad)
@@ -149,6 +159,7 @@ void MainWindow::Boot()
updateMenus();
}
/* SIGNALS */
void MainWindow::openAct()
{
QString filename = QFileDialog::getOpenFileName(NULL, "Load File", g_Config.currentDirectory.c_str(), "PSP ROMs (*.pbp *.elf *.iso *.cso *.prx)");
+18 -5
View File
@@ -1,5 +1,7 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#pragma once
#include <queue>
#include <mutex>
#include <QtCore>
#include <QMenuBar>
@@ -21,6 +23,11 @@ extern bool g_TakeScreenshot;
class MenuAction;
class MenuTree;
// hacky, should probably use qt signals or something, but whatever..
enum class MainWindowMsg {
BOOT_DONE
};
class MainWindow : public QMainWindow
{
Q_OBJECT
@@ -38,6 +45,11 @@ public:
void ShowMemory(u32 addr);
void updateMenus();
void Notify(MainWindowMsg msg) {
std::unique_lock<std::mutex> lock(msgMutex_);
msgQueue_.push(msg);
}
protected:
void changeEvent(QEvent *e)
{
@@ -54,7 +66,6 @@ signals:
void updateMenu();
public slots:
void Boot();
void newFrame();
private slots:
@@ -136,6 +147,7 @@ private slots:
void langChanged(QAction *action) { loadLanguage(action->data().toString(), true); }
private:
void bootDone();
void SetWindowScale(int zoom);
void SetGameTitle(QString text);
void loadLanguage(const QString &language, bool retranslate);
@@ -155,6 +167,9 @@ private:
QActionGroup *anisotropicGroup, *screenGroup, *displayLayoutGroup,
*defaultLogGroup, *g3dLogGroup, *hleLogGroup;
std::queue<MainWindowMsg> msgQueue_;
std::mutex msgMutex_;
};
class MenuAction : public QAction
@@ -275,5 +290,3 @@ public slots:
private:
const char *_text;
};
#endif // MAINWINDOW_H
+142
View File
@@ -0,0 +1,142 @@
#include "SDLGLGraphicsContext.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "base/NativeApp.h"
#include "base/display.h"
#include "gfx_es2/gpu_features.h"
class GLRenderManager;
// Returns 0 on success.
int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) {
struct GLVersionPair {
int major;
int minor;
};
GLVersionPair attemptVersions[] = {
#ifdef USING_GLES2
{3, 2}, {3, 1}, {3, 0}, {2, 0},
#else
{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0},
{3, 3}, {3, 2}, {3, 1}, {3, 0},
#endif
};
#ifdef USING_GLES2
mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN;
#else
mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
#endif
SDL_GLContext glContext = nullptr;
for (size_t i = 0; i < ARRAY_SIZE(attemptVersions); ++i) {
const auto &ver = attemptVersions[i];
// Make sure to request a somewhat modern GL context at least - the
// latest supported by MacOS X (really, really sad...)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, ver.major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, ver.minor);
#ifdef USING_GLES2
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SetGLCoreContext(false);
#else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SetGLCoreContext(true);
#endif
window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode);
if (!window) {
NativeShutdown();
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
continue;
}
glContext = SDL_GL_CreateContext(window);
if (glContext != nullptr) {
// Victory, got one.
break;
}
// Let's keep trying. To be safe, destroy the window - docs say needed to change profile.
// in practice, it doesn't seem to matter, but maybe it differs by platform.
SDL_DestroyWindow(window);
}
if (glContext == nullptr) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SetGLCoreContext(false);
window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode);
if (window == nullptr) {
NativeShutdown();
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
SDL_Quit();
return 2;
}
glContext = SDL_GL_CreateContext(window);
if (glContext == nullptr) {
NativeShutdown();
fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError());
SDL_Quit();
return 2;
}
}
#ifdef USING_EGL
EGL_Init();
#endif
#ifndef USING_GLES2
// Some core profile drivers elide certain extensions from GL_EXTENSIONS/etc.
// glewExperimental allows us to force GLEW to search for the pointers anyway.
if (gl_extensions.IsCoreContext) {
glewExperimental = true;
}
if (GLEW_OK != glewInit()) {
printf("Failed to initialize glew!\n");
return 1;
}
// Unfortunately, glew will generate an invalid enum error, ignore.
if (gl_extensions.IsCoreContext)
glGetError();
if (GLEW_VERSION_2_0) {
printf("OpenGL 2.0 or higher.\n");
} else {
printf("Sorry, this program requires OpenGL 2.0.\n");
return 1;
}
#endif
// Finally we can do the regular initialization.
CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext();
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
SetGPUBackend(GPUBackend::OPENGL);
bool success = draw_->CreatePresets();
assert(success);
renderManager_->SetSwapFunction([&]() {
#ifdef USING_EGL
eglSwapBuffers(g_eglDisplay, g_eglSurface);
#else
SDL_GL_SwapWindow(window_);
#endif
});
window_ = window;
return 0;
}
void SDLGLGraphicsContext::Shutdown() {
}
void SDLGLGraphicsContext::ShutdownFromRenderThread() {
delete draw_;
draw_ = nullptr;
#ifdef USING_EGL
EGL_Close();
#else
SDL_GL_DeleteContext(glContext);
#endif
}
+48
View File
@@ -0,0 +1,48 @@
#if !defined(__APPLE__)
#include "SDL_syswm.h"
#endif
#include "SDL.h"
#include "thin3d/GLRenderManager.h"
#include "gfx/gl_common.h"
#include "Common/GraphicsContext.h"
class SDLGLGraphicsContext : public DummyGraphicsContext {
public:
SDLGLGraphicsContext() {
}
// Returns 0 on success.
int Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message);
void Shutdown() override;
void ShutdownFromRenderThread() override;
void SwapBuffers() override {
renderManager_->Swap();
}
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_ = nullptr;
SDL_Window *window_;
SDL_GLContext glContext = nullptr;
GLRenderManager *renderManager_ = nullptr;
};
+30 -333
View File
@@ -24,20 +24,15 @@ SDLJoystick *joystick = NULL;
#include "base/logging.h"
#include "base/timeutil.h"
#include "ext/glslang/glslang/Public/ShaderLang.h"
#include "gfx/gl_common.h"
#include "gfx_es2/gpu_features.h"
#include "input/input_state.h"
#include "input/keycodes.h"
#include "net/resolve.h"
#include "base/NKCodeFromSDL.h"
#include "util/const_map.h"
#include "util/text/utf8.h"
#include "util/text/parsers.h"
#include "math/math_util.h"
#include "thin3d/GLRenderManager.h"
#include "thread/threadutil.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanDebug.h"
#include "math.h"
#if !defined(__APPLE__)
@@ -61,6 +56,9 @@ SDLJoystick *joystick = NULL;
#include "Core/Core.h"
#include "Core/Config.h"
#include "Common/GraphicsContext.h"
#include "SDLGLGraphicsContext.h"
#include "SDLVulkanGraphicsContext.h"
GlobalUIState lastUIState = UISTATE_MENU;
GlobalUIState GetUIState();
@@ -72,8 +70,6 @@ static int g_QuitRequested = 0;
static int g_DesktopWidth = 0;
static int g_DesktopHeight = 0;
static VulkanLogOptions g_LogOptions;
#if defined(USING_EGL)
static EGLDisplay g_eglDisplay = NULL;
@@ -202,318 +198,6 @@ void EGL_Close() {
}
#endif
class GLRenderManager;
class SDLGLGraphicsContext : public DummyGraphicsContext {
public:
SDLGLGraphicsContext() {
}
~SDLGLGraphicsContext() {
delete draw_;
}
// Returns 0 on success.
int Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message);
void Shutdown() override {
#ifdef USING_EGL
EGL_Close();
#else
SDL_GL_DeleteContext(glContext);
#endif
}
void SwapBuffers() override {
renderManager_->Swap();
}
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_ = nullptr;
SDL_Window *window_;
SDL_GLContext glContext = nullptr;
GLRenderManager *renderManager_ = nullptr;
};
// Returns 0 on success.
int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) {
struct GLVersionPair {
int major;
int minor;
};
GLVersionPair attemptVersions[] = {
#ifdef USING_GLES2
{3, 2}, {3, 1}, {3, 0}, {2, 0},
#else
{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0},
{3, 3}, {3, 2}, {3, 1}, {3, 0},
#endif
};
#ifdef USING_GLES2
mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN;
#else
mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
#endif
SDL_GLContext glContext = nullptr;
for (size_t i = 0; i < ARRAY_SIZE(attemptVersions); ++i) {
const auto &ver = attemptVersions[i];
// Make sure to request a somewhat modern GL context at least - the
// latest supported by MacOS X (really, really sad...)
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, ver.major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, ver.minor);
#ifdef USING_GLES2
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SetGLCoreContext(false);
#else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SetGLCoreContext(true);
#endif
window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode);
if (!window) {
NativeShutdown();
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
continue;
}
glContext = SDL_GL_CreateContext(window);
if (glContext != nullptr) {
// Victory, got one.
break;
}
// Let's keep trying. To be safe, destroy the window - docs say needed to change profile.
// in practice, it doesn't seem to matter, but maybe it differs by platform.
SDL_DestroyWindow(window);
}
if (glContext == nullptr) {
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SetGLCoreContext(false);
window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode);
if (window == nullptr) {
NativeShutdown();
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
SDL_Quit();
return 2;
}
glContext = SDL_GL_CreateContext(window);
if (glContext == nullptr) {
NativeShutdown();
fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError());
SDL_Quit();
return 2;
}
}
#ifdef USING_EGL
EGL_Init();
#endif
#ifndef USING_GLES2
// Some core profile drivers elide certain extensions from GL_EXTENSIONS/etc.
// glewExperimental allows us to force GLEW to search for the pointers anyway.
if (gl_extensions.IsCoreContext) {
glewExperimental = true;
}
if (GLEW_OK != glewInit()) {
printf("Failed to initialize glew!\n");
return 1;
}
// Unfortunately, glew will generate an invalid enum error, ignore.
if (gl_extensions.IsCoreContext)
glGetError();
if (GLEW_VERSION_2_0) {
printf("OpenGL 2.0 or higher.\n");
} else {
printf("Sorry, this program requires OpenGL 2.0.\n");
return 1;
}
#endif
// Finally we can do the regular initialization.
CheckGLExtensions();
draw_ = Draw::T3DCreateGLContext();
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
SetGPUBackend(GPUBackend::OPENGL);
bool success = draw_->CreatePresets();
assert(success);
renderManager_->SetSwapFunction([&]() {
#ifdef USING_EGL
eglSwapBuffers(g_eglDisplay, g_eglSurface);
#else
SDL_GL_SwapWindow(window_);
#endif
});
window_ = window;
return 0;
}
class SDLVulkanGraphicsContext : public GraphicsContext {
public:
SDLVulkanGraphicsContext() {}
~SDLVulkanGraphicsContext() {
delete draw_;
}
bool Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message);
void Shutdown() override;
void SwapBuffers() override {
// We don't do it this way.
}
void Resize() override {
/*
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
vulkan_->DestroyObjects();
// TODO: Take from real window dimensions
int width = 1024;
int height = 768;
vulkan_->ReinitSurface(width, height);
vulkan_->InitObjects();
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
*/
}
void SwapInterval(int interval) override {
}
void *GetAPIContext() override {
return vulkan_;
}
Draw::DrawContext *GetDrawContext() override {
return draw_;
}
private:
Draw::DrawContext *draw_ = nullptr;
VulkanContext *vulkan_ = nullptr;
};
bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) {
window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode);
if (!window) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
exit(1);
}
init_glslang();
g_LogOptions.breakOnError = true;
g_LogOptions.breakOnWarning = true;
g_LogOptions.msgBoxOnError = false;
Version gitVer(PPSSPP_GIT_VERSION);
vulkan_ = new VulkanContext();
if (vulkan_->InitError().size()) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
return false;
}
int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX;
// vulkanFlags |= VULKAN_FLAG_VALIDATE;
VulkanContext::CreateInfo info{};
info.app_name = "PPSSPP";
info.app_ver = gitVer.ToInteger();
info.flags = vulkanFlags;
if (VK_SUCCESS != vulkan_->CreateInstance(info)) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
return false;
}
vulkan_->ChooseDevice(vulkan_->GetBestPhysicalDevice());
if (vulkan_->CreateDevice() != VK_SUCCESS) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
return false;
}
#if !defined(__APPLE__)
SDL_SysWMinfo sys_info{};
SDL_VERSION(&sys_info.version); //Set SDL version
if (!SDL_GetWindowWMInfo(window, &sys_info)) {
fprintf(stderr, "Error getting SDL window wm info: %s\n", SDL_GetError());
exit(1);
}
switch (sys_info.subsystem) {
case SDL_SYSWM_X11:
#if defined(VK_USE_PLATFORM_XLIB_KHR)
vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void*)sys_info.info.x11.display,
(void *)(intptr_t)sys_info.info.x11.window, pixel_xres, pixel_yres);
#elif defined(VK_USE_PLATFORM_XCB_KHR)
vulkan_->InitSurface(WINDOWSYSTEM_XCB, (void*)XGetXCBConnection(sys_info.info.x11.display),
(void *)(intptr_t)sys_info.info.x11.window, pixel_xres, pixel_yres);
#endif
break;
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
case SDL_SYSWM_WAYLAND:
vulkan_->InitSurface(WINDOWSYSTEM_WAYLAND, (void*)sys_info.info.wl.display,
(void *)sys_info.info.wl.surface, pixel_xres, pixel_yres);
break;
#endif
default:
fprintf(stderr, "Vulkan subsystem %d not supported\n", sys_info.subsystem);
exit(1);
break;
}
#endif
if (!vulkan_->InitObjects()) {
*error_message = vulkan_->InitError();
Shutdown();
return false;
}
draw_ = Draw::T3DCreateVulkanContext(vulkan_, false);
SetGPUBackend(GPUBackend::VULKAN);
bool success = draw_->CreatePresets();
assert(success);
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
return true;
}
void SDLVulkanGraphicsContext::Shutdown() {
if (draw_)
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
delete draw_;
draw_ = nullptr;
vulkan_->WaitUntilQueueIdle();
vulkan_->DestroyObjects();
vulkan_->DestroyDevice();
vulkan_->DestroyDebugMsgCallback();
vulkan_->DestroyInstance();
delete vulkan_;
vulkan_ = nullptr;
finalize_glslang();
}
int getDisplayNumber(void) {
int displayNumber = 0;
@@ -522,8 +206,7 @@ int getDisplayNumber(void) {
//get environment
displayNumberStr=getenv("SDL_VIDEO_FULLSCREEN_HEAD");
if (displayNumberStr)
{
if (displayNumberStr) {
displayNumber = atoi(displayNumberStr);
}
@@ -725,21 +408,26 @@ enum class EmuThreadState {
static std::thread emuThread;
static std::atomic<int> emuThreadState((int)EmuThreadState::DISABLED);
static void EmuThreadFunc() {
static void EmuThreadFunc(GraphicsContext *graphicsContext) {
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;
NativeInitGraphics(graphicsContext);
while (emuThreadState != (int)EmuThreadState::QUIT_REQUESTED) {
UpdateRunLoop();
}
emuThreadState = (int)EmuThreadState::STOPPED;
NativeShutdownGraphics();
}
static void EmuThreadStart() {
static void EmuThreadStart(GraphicsContext *context) {
emuThreadState = (int)EmuThreadState::START_REQUESTED;
emuThread = std::thread(&EmuThreadFunc);
emuThread = std::thread(&EmuThreadFunc, context);
}
static void EmuThreadStop() {
@@ -923,6 +611,9 @@ int main(int argc, char *argv[]) {
GraphicsContext *graphicsContext = nullptr;
SDL_Window *window = nullptr;
bool useEmuThread;
std::string error_message;
if (g_Config.iGPUBackend == (int)GPUBackend::OPENGL) {
SDLGLGraphicsContext *ctx = new SDLGLGraphicsContext();
@@ -930,6 +621,7 @@ int main(int argc, char *argv[]) {
printf("GL init error '%s'\n", error_message.c_str());
}
graphicsContext = ctx;
useEmuThread = true;
} else if (g_Config.iGPUBackend == (int)GPUBackend::VULKAN) {
SDLVulkanGraphicsContext *ctx = new SDLVulkanGraphicsContext();
if (!ctx->Init(window, x, y, mode, &error_message)) {
@@ -943,6 +635,7 @@ int main(int argc, char *argv[]) {
} else {
graphicsContext = ctx;
}
useEmuThread = false;
}
// Since we render from the main thread, there's nothing done here, but we call it to avoid confusion.
@@ -956,9 +649,10 @@ int main(int argc, char *argv[]) {
SDL_ShowCursor(SDL_DISABLE);
#endif
NativeInitGraphics(graphicsContext);
NativeResized();
if (!useEmuThread) {
NativeInitGraphics(graphicsContext);
NativeResized();
}
SDL_AudioSpec fmt, ret_fmt;
memset(&fmt, 0, sizeof(fmt));
@@ -996,8 +690,8 @@ int main(int argc, char *argv[]) {
int framecount = 0;
bool mouseDown = false;
if (GetGPUBackend() == GPUBackend::OPENGL) {
EmuThreadStart();
if (useEmuThread) {
EmuThreadStart(graphicsContext);
}
graphicsContext->ThreadStart();
@@ -1198,14 +892,16 @@ int main(int argc, char *argv[]) {
framecount++;
}
graphicsContext->ThreadEnd();
graphicsContext->ShutdownFromRenderThread();
EmuThreadStop();
delete joystick;
NativeShutdownGraphics();
if (!useEmuThread) {
NativeShutdownGraphics();
}
graphicsContext->Shutdown();
graphicsContext->ThreadEnd();
graphicsContext->ShutdownFromRenderThread();
NativeShutdown();
delete graphicsContext;
@@ -1217,5 +913,6 @@ int main(int argc, char *argv[]) {
#endif
glslang::FinalizeProcess();
ILOG("Leaving main");
return 0;
}
+111
View File
@@ -0,0 +1,111 @@
#include "Core/Config.h"
#include "base/NativeApp.h"
#include "base/display.h"
#include "thin3d/thin3d.h"
#include "util/text/parsers.h"
#include "Core/System.h"
#include "SDLVulkanGraphicsContext.h"
bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) {
window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode);
if (!window) {
fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError());
exit(1);
}
init_glslang();
g_LogOptions.breakOnError = true;
g_LogOptions.breakOnWarning = true;
g_LogOptions.msgBoxOnError = false;
Version gitVer(PPSSPP_GIT_VERSION);
vulkan_ = new VulkanContext();
if (vulkan_->InitError().size()) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
return false;
}
int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX;
// vulkanFlags |= VULKAN_FLAG_VALIDATE;
VulkanContext::CreateInfo info{};
info.app_name = "PPSSPP";
info.app_ver = gitVer.ToInteger();
info.flags = vulkanFlags;
if (VK_SUCCESS != vulkan_->CreateInstance(info)) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
return false;
}
vulkan_->ChooseDevice(vulkan_->GetBestPhysicalDevice());
if (vulkan_->CreateDevice() != VK_SUCCESS) {
*error_message = vulkan_->InitError();
delete vulkan_;
vulkan_ = nullptr;
return false;
}
#if !defined(__APPLE__)
SDL_SysWMinfo sys_info{};
SDL_VERSION(&sys_info.version); //Set SDL version
if (!SDL_GetWindowWMInfo(window, &sys_info)) {
fprintf(stderr, "Error getting SDL window wm info: %s\n", SDL_GetError());
exit(1);
}
switch (sys_info.subsystem) {
case SDL_SYSWM_X11:
#if defined(VK_USE_PLATFORM_XLIB_KHR)
vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void*)sys_info.info.x11.display,
(void *)(intptr_t)sys_info.info.x11.window, pixel_xres, pixel_yres);
#elif defined(VK_USE_PLATFORM_XCB_KHR)
vulkan_->InitSurface(WINDOWSYSTEM_XCB, (void*)XGetXCBConnection(sys_info.info.x11.display),
(void *)(intptr_t)sys_info.info.x11.window, pixel_xres, pixel_yres);
#endif
break;
#if defined(VK_USE_PLATFORM_WAYLAND_KHR)
case SDL_SYSWM_WAYLAND:
vulkan_->InitSurface(WINDOWSYSTEM_WAYLAND, (void*)sys_info.info.wl.display,
(void *)sys_info.info.wl.surface, pixel_xres, pixel_yres);
break;
#endif
default:
fprintf(stderr, "Vulkan subsystem %d not supported\n", sys_info.subsystem);
exit(1);
break;
}
#endif
if (!vulkan_->InitObjects()) {
*error_message = vulkan_->InitError();
Shutdown();
return false;
}
draw_ = Draw::T3DCreateVulkanContext(vulkan_, false);
SetGPUBackend(GPUBackend::VULKAN);
bool success = draw_->CreatePresets();
assert(success);
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
return true;
}
void SDLVulkanGraphicsContext::Shutdown() {
if (draw_)
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
delete draw_;
draw_ = nullptr;
vulkan_->WaitUntilQueueIdle();
vulkan_->DestroyObjects();
vulkan_->DestroyDevice();
vulkan_->DestroyDebugMsgCallback();
vulkan_->DestroyInstance();
delete vulkan_;
vulkan_ = nullptr;
finalize_glslang();
}
+53
View File
@@ -0,0 +1,53 @@
#include "SDL.h"
#if !defined(__APPLE__)
#include "SDL_syswm.h"
#endif
#include "Common/GraphicsContext.h"
#include "Common/Vulkan/VulkanContext.h"
#include "Common/Vulkan/VulkanDebug.h"
#include "thin3d/thin3d.h"
class SDLVulkanGraphicsContext : public GraphicsContext {
public:
SDLVulkanGraphicsContext() {}
~SDLVulkanGraphicsContext() {
delete draw_;
}
bool Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message);
void Shutdown() override;
void SwapBuffers() override {
// We don't do it this way.
}
void Resize() override {
/*
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
vulkan_->DestroyObjects();
// TODO: Take from real window dimensions
int width = 1024;
int height = 768;
vulkan_->ReinitSurface(width, height);
vulkan_->InitObjects();
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
*/
}
void SwapInterval(int interval) override {
}
void *GetAPIContext() override {
return vulkan_;
}
Draw::DrawContext *GetDrawContext() override {
return draw_;
}
private:
Draw::DrawContext *draw_ = nullptr;
VulkanContext *vulkan_ = nullptr;
VulkanLogOptions g_LogOptions;
};
+3
View File
@@ -471,6 +471,9 @@ void SystemInfoScreen::CreateViews() {
#else
buildConfig->Add(new InfoItem("NDEBUG", ""));
#endif
#ifdef USE_ADDRESS_SANITIZER
buildConfig->Add(new InfoItem("USE_ADDRESS_SANITIZER", ""));
#endif
#ifdef USING_GLES2
buildConfig->Add(new InfoItem("USING_GLES2", ""));
#endif
+5 -2
View File
@@ -110,7 +110,7 @@ public:
// this is sent from EMU thread! Make sure that Host handles it properly!
virtual void BootDone() {
g_symbolMap->SortSymbols();
mainWindow->Boot();
mainWindow->Notify(MainWindowMsg::BOOT_DONE);
}
virtual bool IsDebuggingEnabled() {
@@ -121,7 +121,10 @@ public:
#endif
}
virtual bool AttemptLoadSymbolMap() {
return g_symbolMap->LoadSymbolMap(SymbolMapFilename(PSP_CoreParameter().fileToStart));
return false;
// TODO: Make this work with Qt and threaded GL... not sure what's so broken.
// auto fn = SymbolMapFilename(PSP_CoreParameter().fileToStart);
// return g_symbolMap->LoadSymbolMap(fn);
}
virtual void PrepareShutdown() {
g_symbolMap->SaveSymbolMap(SymbolMapFilename(PSP_CoreParameter().fileToStart));
+6
View File
@@ -140,6 +140,12 @@ void TextDrawerQt::ClearCache() {
}
cache_.clear();
sizeCache_.clear();
// Also wipe the font map.
for (auto iter : fontMap_) {
delete iter.second;
}
fontMap_.clear();
fontHash_ = 0;
}
void TextDrawerQt::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) {
+23 -1
View File
@@ -54,8 +54,11 @@ GLRenderManager::GLRenderManager() {
GLRenderManager::~GLRenderManager() {
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
_assert_(frameData_[i].deleter.IsEmpty());
}
// Was anything deleted during shutdown?
deleter_.Perform();
// _assert_(deleter_.IsEmpty());
if (!useThread_) {
// The main thread is also the render thread.
@@ -69,10 +72,29 @@ void GLRenderManager::ThreadStart() {
}
void GLRenderManager::ThreadEnd() {
ILOG("ThreadEnd");
// Wait for any shutdown to complete in StopThread().
std::unique_lock<std::mutex> lock(mutex_);
queueRunner_.DestroyDeviceObjects();
VLOG("PULL: Quitting");
// Good point to run all the deleters to get rid of leftover objects.
for (int i = 0; i < MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].deleter.Perform();
for (int j = 0; j < (int)frameData_[i].steps.size(); j++) {
delete frameData_[i].steps[j];
}
frameData_[i].steps.clear();
frameData_[i].initSteps.clear();
}
deleter_.Perform();
for (int i = 0; i < (int)steps_.size(); i++) {
delete steps_[i];
}
steps_.clear();
initSteps_.clear();
}
bool GLRenderManager::ThreadFrame() {
+9 -2
View File
@@ -10,6 +10,7 @@
#include <condition_variable>
#include <cassert>
#include "base/logging.h"
#include "gfx/gl_common.h"
#include "math/dataconv.h"
#include "Common/Log.h"
@@ -152,9 +153,12 @@ class GLDeleter {
public:
void Perform();
bool IsEmpty() const {
return shaders.empty() && programs.empty() && buffers.empty() && textures.empty() && inputLayouts.empty() && framebuffers.empty();
}
void Take(GLDeleter &other) {
deleterMutex_.lock();
_assert_msg_(G3D, shaders.empty() && programs.empty() && buffers.empty() && textures.empty() && inputLayouts.empty() && framebuffers.empty(), "Deleter already has stuff");
_assert_msg_(G3D, IsEmpty(), "Deleter already has stuff");
shaders = std::move(other.shaders);
programs = std::move(other.programs);
buffers = std::move(other.buffers);
@@ -193,6 +197,9 @@ public:
int semanticsMask_ = 0;
};
// Note: The GLRenderManager is created and destroyed on the render thread, and the latter
// happens after the emu thread has been destroyed. Therefore, it's safe to run wild deleting stuff
// directly in the destructor.
class GLRenderManager {
public:
GLRenderManager();
@@ -701,7 +708,7 @@ private:
// Swapchain.
bool hasBegun = false;
uint32_t curSwapchainImage = -1;
GLDeleter deleter;
std::set<GLPushBuffer *> activePushBuffers;
};
+3 -2
View File
@@ -297,6 +297,7 @@ public:
OpenGLPipeline(GLRenderManager *render) : render_(render) {
}
~OpenGLPipeline() {
ILOG("OpenGLPipeline released");
for (auto &iter : shaders) {
iter->Release();
}
@@ -477,7 +478,7 @@ private:
OpenGLTexture *boundTextures_[8]{};
int maxTextures_ = 0;
DeviceCaps caps_{};
// Bound state
OpenGLPipeline *curPipeline_ = nullptr;
OpenGLBuffer *curVBuffers_[4]{};
@@ -519,7 +520,7 @@ OpenGLContext::OpenGLContext() {
default:
caps_.vendor = GPUVendor::VENDOR_UNKNOWN;
break;
}
}
for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {
frameData_[i].push = new GLPushBuffer(&renderManager_, GL_ARRAY_BUFFER, 64 * 1024);
renderManager_.RegisterPushBuffer(i, frameData_[i].push);