diff --git a/NativeApp.cpp b/NativeApp.cpp index ba97f9e..b39892a 100644 --- a/NativeApp.cpp +++ b/NativeApp.cpp @@ -65,7 +65,6 @@ KeyInput input_state; OnScreenMessages osm; - namespace OpenEmuCoreThread { OpenEmuGLContext *ctx; @@ -80,10 +79,12 @@ namespace OpenEmuCoreThread { }; static std::thread emuThread; - std::atomic emuThreadState(EmuThreadState::DISABLED); + static bool threadStarted = false; + static std::atomic emuThreadState(EmuThreadState::DISABLED); static void EmuFrame() { ctx->SetRenderTarget(); + if (ctx->GetDrawContext()) { ctx->GetDrawContext()->BeginFrame(); } @@ -106,6 +107,7 @@ namespace OpenEmuCoreThread { while (true) { switch ((EmuThreadState)emuThreadState) { case EmuThreadState::START_REQUESTED: + threadStarted = true; emuThreadState = EmuThreadState::RUNNING; /* fallthrough */ case EmuThreadState::RUNNING: @@ -115,7 +117,7 @@ namespace OpenEmuCoreThread { emuThreadState = EmuThreadState::PAUSED; /* fallthrough */ case EmuThreadState::PAUSED: - sleep(1); + usleep(1000); break; default: case EmuThreadState::QUIT_REQUESTED: @@ -157,14 +159,17 @@ namespace OpenEmuCoreThread { return; } emuThreadState = EmuThreadState::PAUSE_REQUESTED; - ctx->ThreadFrame(); + while (emuThreadState != EmuThreadState::PAUSED) { - sleep(1); + //We need to process frames until the thread Pauses give 10 ms between loops + ctx->ThreadFrame(); + emuThreadState = EmuThreadState::PAUSE_REQUESTED; + usleep(10000); } } - } // namespace OpenEmuCoreThread + // Here's where we store the OpenEmu framebuffer to bind for final rendering int framebuffer = 0; @@ -236,14 +241,12 @@ int NativeMix(short *audio, int num_samples) void NativeInit(int argc, const char *argv[], const char *savegame_directory, const char *external_directory, const char *installID, bool fs) { VFSRegister("", new DirectoryAssetReader("assets/")); - //VFSRegister("", new DirectoryAssetReader(savegame_directory)); VFSRegister("", new DirectoryAssetReader(external_directory)); if (host == nullptr) { host = new NativeHost(); } - //g_Config.internalDataDirectory = savegame_directory; g_Config.externalDirectory = external_directory; logger = new AndroidLogger(); @@ -259,14 +262,25 @@ void NativeInit(int argc, const char *argv[], const char *savegame_directory, co } } +void NativeSetThreadState(OpenEmuCoreThread::EmuThreadState threadState) { + if(threadState == OpenEmuCoreThread::EmuThreadState::PAUSE_REQUESTED && OpenEmuCoreThread::threadStarted) + OpenEmuCoreThread::EmuThreadPause(); + else if(threadState == OpenEmuCoreThread::EmuThreadState::START_REQUESTED && !OpenEmuCoreThread::threadStarted) + OpenEmuCoreThread::EmuThreadStart(); + else + OpenEmuCoreThread::emuThreadState = threadState; +} + bool NativeInitGraphics(GraphicsContext *graphicsContext) { + //Set the Core Thread graphics Context + OpenEmuCoreThread::ctx = static_cast(graphicsContext); + // Save framebuffer and set ppsspp default graphics framebuffer object glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &framebuffer); - - static_cast(graphicsContext)->SetRenderFBO(framebuffer); - - Core_SetGraphicsContext(graphicsContext); + OpenEmuCoreThread::ctx->SetRenderFBO(framebuffer); + + Core_SetGraphicsContext(OpenEmuCoreThread::ctx); if (gpu) gpu->DeviceRestore(); @@ -278,19 +292,11 @@ void NativeResized(){} void NativeRender(GraphicsContext *ctx) { - static_cast(ctx)->SetRenderTarget(); + if(OpenEmuCoreThread::emuThreadState == OpenEmuCoreThread::EmuThreadState::PAUSED) + return; - OpenEmuCoreThread::ctx = static_cast(ctx); - - if (OpenEmuCoreThread::emuThreadState != OpenEmuCoreThread::EmuThreadState::RUNNING) { - OpenEmuCoreThread::EmuThreadStart(); - } - - if (!ctx->ThreadFrame()) { - return; - } - - ctx->SwapBuffers(); + OpenEmuCoreThread::ctx->ThreadFrame(); + OpenEmuCoreThread::ctx->SwapBuffers(); } void NativeUpdate() {} diff --git a/PPSSPP.xcodeproj/project.pbxproj b/PPSSPP.xcodeproj/project.pbxproj index 15f7e6b..938ebac 100644 --- a/PPSSPP.xcodeproj/project.pbxproj +++ b/PPSSPP.xcodeproj/project.pbxproj @@ -7719,7 +7719,7 @@ ENABLE_TESTABILITY = YES; GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; + GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( USE_FFMPEG, _M_X64, @@ -7799,7 +7799,7 @@ ENABLE_TESTABILITY = NO; GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; + GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( USE_FFMPEG, _M_X64, diff --git a/PPSSPPGameCore.mm b/PPSSPPGameCore.mm index 4800eb8..d6505f4 100644 --- a/PPSSPPGameCore.mm +++ b/PPSSPPGameCore.mm @@ -28,11 +28,11 @@ #import #import +#include "gfx/OpenEmuGLContext.h" + #include "base/NativeApp.h" #include "base/timeutil.h" -#include "gfx/OpenEmuGLContext.h" - #include "Core/Core.h" #include "Core/Config.h" #include "Core/CoreParameter.h" @@ -41,8 +41,10 @@ #include "Core/Host.h" #include "Core/SaveState.h" #include "Core/System.h" + #include "Common/GraphicsContext.h" #include "Common/LogManager.h" + #include "thin3d/thin3d_create.h" #include "thin3d/GLRenderManager.h" #include "thin3d/DataFormatGL.h" @@ -53,6 +55,26 @@ +namespace SaveState { + struct SaveStart { + void DoState(PointerWrap &p); + }; +} // namespace SaveState + +namespace OpenEmuCoreThread { + enum class EmuThreadState { + DISABLED, + START_REQUESTED, + RUNNING, + PAUSE_REQUESTED, + PAUSED, + QUIT_REQUESTED, + STOPPED, + }; +} //namespace OpenEmuThreadCore + +void NativeSetThreadState(OpenEmuCoreThread::EmuThreadState threadState); + @interface PPSSPPGameCore () { CoreParameter _coreParam; @@ -65,6 +87,7 @@ @end PPSSPPGameCore *_current = 0; + @implementation PPSSPPGameCore @@ -107,7 +130,7 @@ PPSSPPGameCore *_current = 0; g_Config.flash0Directory = directoryString.fileSystemRepresentation; g_Config.internalDataDirectory = directoryString.fileSystemRepresentation; g_Config.iGPUBackend = (int)GPUBackend::OPENGL; - + _coreParam.cpuCore = CPUCore::JIT; _coreParam.gpuCore = GPUCORE_GLES; _coreParam.enableSound = true; @@ -149,7 +172,7 @@ PPSSPPGameCore *_current = 0; // This is where PPSSPP will look for ppge_atlas.zim NSString *resourcePath = [[[[self owner] bundle] resourcePath] stringByAppendingString:@"/"]; - OEgraphicsContext = OpenEmuGLContext::CreateGraphicsContext(); //new OpenEmuGLContext(); + OEgraphicsContext = OpenEmuGLContext::CreateGraphicsContext(); NativeInit(0, nil, nil, resourcePath.fileSystemRepresentation, nil, false); @@ -175,6 +198,10 @@ PPSSPPGameCore *_current = 0; host->BootDone(); host->UpdateDisassembly(); + + //Start the Emulator Thread + NativeSetThreadState(OpenEmuCoreThread::EmuThreadState::START_REQUESTED); + } else { u64 cyclesBefore, cyclesAfter; //before and after timing marks to calculate a frame interval cyclesBefore = CoreTiming::GetTicks(); @@ -249,20 +276,28 @@ static void _OESaveStateCallback(bool status, std::string message, void *cbUserD { void (^block)(BOOL, NSError *) = (__bridge_transfer void(^)(BOOL, NSError *))cbUserData; + //Unpause the EmuThread by requesting it to start again + NativeSetThreadState(OpenEmuCoreThread::EmuThreadState::START_REQUESTED); + block(status, nil); } - (void)saveStateToFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block { SaveState::Save(fileName.fileSystemRepresentation, _OESaveStateCallback, (__bridge_retained void *)[block copy]); - if(_isInitialized) SaveState::Process(); + if(_isInitialized) + SaveState::Process(); } - - (void)loadStateFromFileAtPath:(NSString *)fileName completionHandler:(void (^)(BOOL, NSError *))block { SaveState::Load(fileName.fileSystemRepresentation, _OESaveStateCallback, (__bridge_retained void *)[block copy]); - if(_isInitialized) SaveState::Process(); + if(_isInitialized){ + //We need to pause our EmuThread so we don't try to process the save state in the middle of a Frame Render + NativeSetThreadState(OpenEmuCoreThread::EmuThreadState::PAUSE_REQUESTED); + + SaveState::Process(); + } } # pragma mark - Input