mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Change the GraphicsContext interface to be more consistent
This commit is contained in:
1 parent
28a2c7bca6
commit
7f218acc53
51 files changed
+680
-628
No files matched your search
@@ -2,7 +2,5 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.InAppPurchase</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+42
-17
@@ -45,27 +45,43 @@ class IOSGLESContext : public GraphicsContext {
|
||||
public:
|
||||
IOSGLESContext() {
|
||||
CheckGLExtensions();
|
||||
draw_ = Draw::T3DCreateGLContext(false);
|
||||
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
renderManager_->SetInflightFrames(g_Config.iInflightFrames);
|
||||
SetGPUBackend(GPUBackend::OPENGL);
|
||||
bool success = draw_->CreatePresets();
|
||||
_assert_msg_(success, "Failed to compile preset shaders");
|
||||
}
|
||||
~IOSGLESContext() {
|
||||
delete draw_;
|
||||
}
|
||||
bool NeedsRenderThread() const override { return true; }
|
||||
|
||||
bool InitAPI(void *wnd, std::string *deviceNameSetting, std::string *error_message) override {
|
||||
// Nothing to do here, we already initialized in the constructor.
|
||||
return true;
|
||||
}
|
||||
bool InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *error_message) override {
|
||||
draw_ = Draw::T3DCreateGLContext(false);
|
||||
renderManager_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
renderManager_->SetInflightFrames(g_Config.iInflightFrames);
|
||||
bool success = draw_->CreatePresets();
|
||||
_assert_msg_(success, "Failed to compile preset shaders");
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShutdownSurface() override {
|
||||
// Nothing to do here, we already initialized in the constructor.
|
||||
if (draw_) {
|
||||
delete draw_;
|
||||
draw_ = nullptr;
|
||||
}
|
||||
renderManager_ = nullptr;
|
||||
}
|
||||
void ShutdownAPI() override {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
bool NeedsSeparateEmuThread() const override { return true; }
|
||||
Draw::DrawContext *GetDrawContext() override {
|
||||
return draw_;
|
||||
}
|
||||
|
||||
void Resize() override {}
|
||||
void Shutdown() override {}
|
||||
|
||||
void BeginShutdown() {
|
||||
renderManager_->SetSkipGLCalls();
|
||||
}
|
||||
|
||||
void ThreadStart() override {
|
||||
renderManager_->ThreadStart(draw_);
|
||||
@@ -83,6 +99,11 @@ public:
|
||||
renderManager_->StartThread();
|
||||
}
|
||||
|
||||
protected:
|
||||
void BeginShutdown() {
|
||||
renderManager_->SetSkipGLCalls();
|
||||
}
|
||||
|
||||
private:
|
||||
Draw::DrawContext *draw_;
|
||||
GLRenderManager *renderManager_;
|
||||
@@ -223,9 +244,14 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
|
||||
graphicsContext = new IOSGLESContext();
|
||||
|
||||
graphicsContext->GetDrawContext()->SetErrorCallback([](const char *shortDesc, const char *details, void *userdata) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, details, 0.0f, "error_callback");
|
||||
}, nullptr);
|
||||
std::string errorMessage;
|
||||
if (!graphicsContext->InitAPI(nullptr, nullptr, &errorMessage)) {
|
||||
ERROR_LOG(Log::G3D, "InitAPI failed: %s", errorMessage.c_str());
|
||||
}
|
||||
|
||||
if (!graphicsContext->InitSurface(WINDOWSYSTEM_NONE, nullptr, nullptr, &errorMessage)) {
|
||||
ERROR_LOG(Log::G3D, "InitAPI failed: %s", errorMessage.c_str());
|
||||
}
|
||||
|
||||
graphicsContext->ThreadStart();
|
||||
|
||||
@@ -350,14 +376,13 @@ void GLRenderLoop(IOSGLESContext *graphicsContext) {
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
graphicsContext->BeginShutdown();
|
||||
// Skipping GL calls here because the old context is lost.
|
||||
graphicsContext->ThreadFrameUntilCondition([]() -> bool {
|
||||
return !renderLoopRunning;
|
||||
});
|
||||
graphicsContext->ThreadEnd();
|
||||
|
||||
graphicsContext->Shutdown();
|
||||
graphicsContext->ShutdownSurface();
|
||||
graphicsContext->ShutdownAPI();
|
||||
delete graphicsContext;
|
||||
graphicsContext = nullptr;
|
||||
INFO_LOG(Log::System, "Done shutting down GL");
|
||||
|
||||
+93
-104
@@ -17,6 +17,7 @@
|
||||
#include "Common/System/Request.h"
|
||||
#include "Common/GraphicsContext.h"
|
||||
#include "Common/Thread/ThreadUtil.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
@@ -38,94 +39,28 @@ class IOSVulkanContext : public GraphicsContext {
|
||||
public:
|
||||
IOSVulkanContext() {}
|
||||
~IOSVulkanContext() {
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
delete vulkan_;
|
||||
vulkan_ = nullptr;
|
||||
}
|
||||
|
||||
bool InitAPI();
|
||||
bool InitAPI(void *wnd, std::string *deviceName, std::string *errorMessage) override;
|
||||
void ShutdownAPI() override;
|
||||
|
||||
bool InitFromRenderThread(CAMetalLayer *layer, int desiredBackbufferSizeX, int desiredBackbufferSizeY);
|
||||
void ShutdownFromRenderThread() override; // Inverses InitFromRenderThread.
|
||||
bool InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *error_message) override;
|
||||
void ShutdownSurface() override;
|
||||
|
||||
void Shutdown() override;
|
||||
void Resize() override {}
|
||||
|
||||
void *GetAPIContext() override { return g_Vulkan; }
|
||||
void *GetAPIContext() override { return vulkan_; }
|
||||
Draw::DrawContext *GetDrawContext() override { return draw_; }
|
||||
|
||||
private:
|
||||
VulkanContext *g_Vulkan = nullptr;
|
||||
VulkanContext *vulkan_ = nullptr;
|
||||
Draw::DrawContext *draw_ = nullptr;
|
||||
GraphicsContextState state_ = GraphicsContextState::PENDING;
|
||||
};
|
||||
|
||||
bool IOSVulkanContext::InitFromRenderThread(CAMetalLayer *layer, int desiredBackbufferSizeX, int desiredBackbufferSizeY) {
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::InitFromRenderThread: desiredwidth=%d desiredheight=%d", desiredBackbufferSizeX, desiredBackbufferSizeY);
|
||||
if (!g_Vulkan) {
|
||||
ERROR_LOG(Log::G3D, "IOSVulkanContext::InitFromRenderThread: No Vulkan context");
|
||||
return false;
|
||||
}
|
||||
|
||||
VkResult res = g_Vulkan->InitSurface(WINDOWSYSTEM_METAL_EXT, (__bridge void *)layer, nullptr);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(Log::G3D, "g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useMultiThreading = g_Config.bRenderMultiThreading;
|
||||
if (g_Config.iInflightFrames == 1) {
|
||||
useMultiThreading = false;
|
||||
}
|
||||
|
||||
draw_ = Draw::T3DCreateVulkanContext(g_Vulkan, useMultiThreading);
|
||||
|
||||
VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_);
|
||||
|
||||
// This MUST run on the main thread. We're taking our chances with a dispatch_sync here.
|
||||
g_Vulkan->InitSwapchain(presentMode);
|
||||
|
||||
if (false) {
|
||||
delete draw_;
|
||||
ERROR_LOG(Log::G3D, "InitSwapchain failed");
|
||||
g_Vulkan->DestroySwapchain();
|
||||
g_Vulkan->DestroySurface();
|
||||
g_Vulkan->DestroyDevice();
|
||||
g_Vulkan->DestroyInstance();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetGPUBackend(GPUBackend::VULKAN);
|
||||
bool shaderSuccess = draw_->CreatePresets(); // Doesn't fail, we ship the compiler.
|
||||
_assert_msg_(shaderSuccess, "Failed to compile preset shaders");
|
||||
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
|
||||
|
||||
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
renderManager->SetInflightFrames(g_Config.iInflightFrames);
|
||||
return true;
|
||||
}
|
||||
|
||||
void IOSVulkanContext::ShutdownFromRenderThread() {
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown");
|
||||
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight());
|
||||
delete draw_;
|
||||
draw_ = nullptr;
|
||||
g_Vulkan->WaitUntilQueueIdle();
|
||||
g_Vulkan->PerformPendingDeletes();
|
||||
g_Vulkan->DestroySwapchain();
|
||||
g_Vulkan->DestroySurface();
|
||||
INFO_LOG(Log::G3D, "Done with ShutdownFromRenderThread");
|
||||
}
|
||||
|
||||
void IOSVulkanContext::Shutdown() {
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown");
|
||||
g_Vulkan->DestroyDevice();
|
||||
g_Vulkan->DestroyInstance();
|
||||
// We keep the g_Vulkan context around to avoid invalidating a ton of pointers around the app.
|
||||
finalize_glslang();
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown completed");
|
||||
}
|
||||
|
||||
bool IOSVulkanContext::InitAPI() {
|
||||
bool IOSVulkanContext::InitAPI(void *wnd, std::string *deviceName, std::string *errorMessage) {
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::Init");
|
||||
init_glslang();
|
||||
|
||||
@@ -136,36 +71,92 @@ bool IOSVulkanContext::InitAPI() {
|
||||
INFO_LOG(Log::G3D, "Creating Vulkan context");
|
||||
Version gitVer(PPSSPP_GIT_VERSION);
|
||||
|
||||
std::string errorStr;
|
||||
if (!VulkanLoad(&errorStr)) {
|
||||
ERROR_LOG(Log::G3D, "Failed to load Vulkan driver library: %s", errorStr.c_str());
|
||||
if (!VulkanLoad(errorMessage)) {
|
||||
ERROR_LOG(Log::G3D, "Failed to load Vulkan driver library: %s", errorMessage->c_str());
|
||||
state_ = GraphicsContextState::FAILED_INIT;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_Vulkan) {
|
||||
if (!vulkan_) {
|
||||
// TODO: Assert if g_Vulkan already exists here?
|
||||
g_Vulkan = new VulkanContext();
|
||||
vulkan_ = new VulkanContext();
|
||||
}
|
||||
|
||||
VulkanContext::CreateInfo info{};
|
||||
InitVulkanCreateInfoFromConfig(&info);
|
||||
if (!g_Vulkan->CreateInstanceAndDevice(info)) {
|
||||
delete g_Vulkan;
|
||||
g_Vulkan = nullptr;
|
||||
if (!vulkan_->CreateInstanceAndDevice(info, &g_Config.sVulkanDevice)) {
|
||||
delete vulkan_;
|
||||
vulkan_ = nullptr;
|
||||
state_ = GraphicsContextState::FAILED_INIT;
|
||||
return false;
|
||||
}
|
||||
|
||||
g_Vulkan->SetCbGetDrawSize([]() {
|
||||
INFO_LOG(Log::G3D, "Vulkan device created!");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IOSVulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2, std::string *errorMessage) {
|
||||
_dbg_assert_(winsys == WINDOWSYSTEM_METAL_EXT);
|
||||
CAMetalLayer *layer = (__bridge CAMetalLayer *)data1;
|
||||
|
||||
_assert_(vulkan_);
|
||||
|
||||
VkResult res = vulkan_->InitSurface(winsys, data1, nullptr);
|
||||
if (res != VK_SUCCESS) {
|
||||
ERROR_LOG(Log::G3D, "g_Vulkan->InitSurface failed: '%s'", VulkanResultToString(res));
|
||||
*errorMessage = StringFromFormat("InitSurface failed: %s", VulkanResultToString(res));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool useMultiThreading = g_Config.bRenderMultiThreading;
|
||||
if (g_Config.iInflightFrames == 1) {
|
||||
useMultiThreading = false;
|
||||
}
|
||||
|
||||
draw_ = Draw::T3DCreateVulkanContext(vulkan_, useMultiThreading);
|
||||
|
||||
VkPresentModeKHR presentMode = ConfigPresentModeToVulkan(draw_);
|
||||
|
||||
// This MUST run on the main thread. We're taking our chances with a dispatch_sync here.
|
||||
vulkan_->InitSwapchain(presentMode);
|
||||
|
||||
SetGPUBackend(GPUBackend::VULKAN);
|
||||
bool shaderSuccess = draw_->CreatePresets(); // Doesn't fail, we ship the compiler.
|
||||
_assert_msg_(shaderSuccess, "Failed to compile preset shaders");
|
||||
draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
|
||||
|
||||
VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
|
||||
renderManager->SetInflightFrames(g_Config.iInflightFrames);
|
||||
|
||||
vulkan_->SetCbGetDrawSize([]() {
|
||||
return VkExtent2D {(uint32_t)g_display.pixel_xres, (uint32_t)g_display.pixel_yres};
|
||||
});
|
||||
|
||||
INFO_LOG(Log::G3D, "Vulkan device created!");
|
||||
state_ = GraphicsContextState::INITIALIZED;
|
||||
return true;
|
||||
}
|
||||
|
||||
void IOSVulkanContext::ShutdownSurface() {
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown");
|
||||
draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight());
|
||||
delete draw_;
|
||||
draw_ = nullptr;
|
||||
vulkan_->WaitUntilQueueIdle();
|
||||
vulkan_->PerformPendingDeletes();
|
||||
vulkan_->DestroySwapchain();
|
||||
vulkan_->DestroySurface();
|
||||
INFO_LOG(Log::G3D, "Done with ShutdownFromRenderThread");
|
||||
}
|
||||
|
||||
void IOSVulkanContext::ShutdownAPI() {
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown");
|
||||
vulkan_->DestroyDevice();
|
||||
vulkan_->DestroyInstance();
|
||||
// We keep the g_Vulkan context around to avoid invalidating a ton of pointers around the app.
|
||||
finalize_glslang();
|
||||
INFO_LOG(Log::G3D, "IOSVulkanContext::Shutdown completed");
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark PPSSPPViewControllerMetal
|
||||
@@ -189,16 +180,10 @@ static std::thread g_renderLoopThread;
|
||||
|
||||
// Should be very similar to the Android one, probably mergeable.
|
||||
// This is the EmuThread for iOS.
|
||||
void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLayer) {
|
||||
static void VulkanRenderLoop(GraphicsContext *graphicsContext, CAMetalLayer *metalLayer) {
|
||||
SetCurrentThreadName("EmuThreadVulkan");
|
||||
INFO_LOG(Log::G3D, "Entering EmuThreadVulkan");
|
||||
|
||||
if (!graphicsContext) {
|
||||
ERROR_LOG(Log::G3D, "runVulkanRenderLoop: Tried to enter without a created graphics context.");
|
||||
renderLoopRunning = false;
|
||||
exitRenderLoop = false;
|
||||
return;
|
||||
}
|
||||
_assert_(graphicsContext);
|
||||
|
||||
if (exitRenderLoop) {
|
||||
WARN_LOG(Log::G3D, "runVulkanRenderLoop: ExitRenderLoop requested at start, skipping the whole thing.");
|
||||
@@ -210,13 +195,10 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
|
||||
// This is up here to prevent race conditions, in case we pause during init.
|
||||
renderLoopRunning = true;
|
||||
|
||||
int desiredBackbufferSizeX = g_display.pixel_xres;
|
||||
int desiredBackbufferSizeY = g_display.pixel_yres;
|
||||
|
||||
//WARN_LOG(G3D, "runVulkanRenderLoop. desiredBackbufferSizeX=%d desiredBackbufferSizeY=%d",
|
||||
// desiredBackbufferSizeX, desiredBackbufferSizeY);
|
||||
|
||||
if (!graphicsContext->InitFromRenderThread(metalLayer, desiredBackbufferSizeX, desiredBackbufferSizeY)) {
|
||||
std::string errorMessage;
|
||||
if (!graphicsContext->InitSurface(WINDOWSYSTEM_METAL_EXT, (__bridge void *)metalLayer, nullptr, &errorMessage)) {
|
||||
// On Android, if we get here, really no point in continuing.
|
||||
// The UI is supposed to render on any device both on OpenGL and Vulkan. If either of those don't work
|
||||
// on a device, we blacklist it. Hopefully we should have already failed in InitAPI anyway and reverted to GL back then.
|
||||
@@ -249,7 +231,7 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
|
||||
|
||||
// Shut the graphics context down to the same state it was in when we entered the render thread.
|
||||
INFO_LOG(Log::G3D, "Shutting down graphics context...");
|
||||
graphicsContext->ShutdownFromRenderThread();
|
||||
graphicsContext->ShutdownSurface();
|
||||
renderLoopRunning = false;
|
||||
exitRenderLoop = false;
|
||||
|
||||
@@ -284,6 +266,7 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
|
||||
_assert_(g_renderLoopThread.joinable());
|
||||
exitRenderLoop = true;
|
||||
g_renderLoopThread.join();
|
||||
|
||||
_assert_(!g_renderLoopThread.joinable());
|
||||
}
|
||||
|
||||
@@ -312,8 +295,10 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
|
||||
|
||||
g_Config.Save("shutdown vk");
|
||||
|
||||
// Hopefully requestExitVulkanRenderLoop has been called from willResignActive here...
|
||||
|
||||
if (graphicsContext) {
|
||||
graphicsContext->Shutdown();
|
||||
graphicsContext->ShutdownAPI();
|
||||
delete graphicsContext;
|
||||
graphicsContext = NULL;
|
||||
}
|
||||
@@ -344,13 +329,17 @@ void VulkanRenderLoop(IOSVulkanContext *graphicsContext, CAMetalLayer *metalLaye
|
||||
// self.view.clipsToBounds = YES;
|
||||
|
||||
graphicsContext = new IOSVulkanContext();
|
||||
std::string errorMessage;
|
||||
if (!graphicsContext->InitAPI(nullptr, &g_Config.sVulkanDevice, &errorMessage)) {
|
||||
ERROR_LOG(Log::System, "Failed to initialize Vulkan, switching to OpenGL: %s", errorMessage.c_str());
|
||||
g_Config.iGPUBackend = (int)GPUBackend::OPENGL;
|
||||
SetGPUBackend(GPUBackend::OPENGL);
|
||||
delete graphicsContext;
|
||||
// TODO: What to do here?
|
||||
}
|
||||
|
||||
[self updateResolutionWithView:self.view];
|
||||
|
||||
if (!graphicsContext->InitAPI()) {
|
||||
_assert_msg_(false, "Failed to init Vulkan");
|
||||
}
|
||||
|
||||
if ([[GCController controllers] count] > 0) {
|
||||
[self setupController:[[GCController controllers] firstObject]];
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user