diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index 8c08b0a510d4..ef818e70fb74 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -1068,7 +1068,7 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() { { bool result = param.GetSize(param.GetPspParam()); // TODO: According to JPCSP, should test/verify this part but seems edge casey. - if (MemoryStick_State() != PSP_MEMORYSTICK_STATE_DRIVER_READY) { + if (MemoryStick_State() != PSP_MEMORYSTICK_STATE_INSERTED) { param.GetPspParam()->common.result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_MEMSTICK; } else if (result) { param.GetPspParam()->common.result = 0; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 507eede6766b..ee8113837ba7 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -534,6 +534,10 @@ void GPU_DX9::DeviceLost() { framebufferManager_.DeviceLost(); } +void GPU_DX9::DeviceRestore() { + // Nothing needed. +} + void GPU_DX9::InitClear() { ScheduleEvent(GPU_EVENT_INIT_CLEAR); } diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index 5c825b649369..65f1806749f3 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -56,6 +56,7 @@ class GPU_DX9 : public GPUCommon { bool PerformStencilUpload(u32 dest, int size) override; void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. + void DeviceRestore() override; void DumpNextFrame() override; void DoState(PointerWrap &p) override; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index f80ed13baf1d..c77d945bce09 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -207,14 +207,18 @@ void DrawEngineGLES::DestroyDeviceObjects() { } } -void DrawEngineGLES::GLRestore() { - ILOG("TransformDrawEngine::GLRestore()"); +void DrawEngineGLES::GLLost() { + ILOG("TransformDrawEngine::GLLost()"); // The objects have already been deleted. bufferNameCache_.clear(); bufferNameInfo_.clear(); freeSizedBuffers_.clear(); bufferNameCacheSize_ = 0; ClearTrackedVertexArrays(); +} + +void DrawEngineGLES::GLRestore() { + ILOG("TransformDrawEngine::GLRestore()"); InitDeviceObjects(); } diff --git a/GPU/GLES/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index e2b6218c8b7e..2aa398575b3f 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -129,6 +129,7 @@ class DrawEngineGLES : public DrawEngineCommon, public GfxResourceHolder { void RestoreVAO(); void InitDeviceObjects(); void DestroyDeviceObjects(); + void GLLost() override; void GLRestore() override; void Resized(); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index f21dc9227b3b..30f0672a8d2d 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -651,6 +651,10 @@ void GPU_GLES::DeviceLost() { fragmentTestCache_.Clear(false); depalShaderCache_.Clear(); framebufferManager_.DeviceLost(); +} + +void GPU_GLES::DeviceRestore() { + ILOG("GPU_GLES: DeviceRestore"); UpdateVsyncInterval(true); } diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index ffd9c978d4a5..64d682a80e30 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -60,6 +60,7 @@ class GPU_GLES : public GPUCommon { bool PerformStencilUpload(u32 dest, int size) override; void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. + void DeviceRestore() override; void DumpNextFrame() override; void DoState(PointerWrap &p) override; diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index 7d8dc0b2ccf0..3f985181cd3f 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -268,6 +268,7 @@ class GPUInterface { virtual void EnableInterrupts(bool enable) = 0; virtual void DeviceLost() = 0; + virtual void DeviceRestore() = 0; virtual void ReapplyGfxState() = 0; virtual void SyncThread(bool force = false) = 0; virtual void SyncBeginFrame() = 0; diff --git a/GPU/Null/NullGpu.h b/GPU/Null/NullGpu.h index fb8fd46e8113..b3e5504735a6 100644 --- a/GPU/Null/NullGpu.h +++ b/GPU/Null/NullGpu.h @@ -43,6 +43,7 @@ class NullGPU : public GPUCommon { void ClearCacheNextFrame() override {} void DeviceLost() override {} + void DeviceRestore() override {} void DumpNextFrame() override {} void Resized() override {} diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index 535edcf5d1f6..27a262af24ec 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -78,6 +78,10 @@ void SoftGPU::DeviceLost() { // Handled by thin3d. } +void SoftGPU::DeviceRestore() { + // Handled by thin3d. +} + SoftGPU::~SoftGPU() { vformat->Release(); vformat = nullptr; diff --git a/GPU/Software/SoftGpu.h b/GPU/Software/SoftGpu.h index 510cf8cc5eb0..053ee9b546de 100644 --- a/GPU/Software/SoftGpu.h +++ b/GPU/Software/SoftGpu.h @@ -69,6 +69,7 @@ class SoftGPU : public GPUCommon { void ClearCacheNextFrame() override {} void DeviceLost() override; + void DeviceRestore() override; void DumpNextFrame() override {} void Resized() override {} diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 97922f20c76d..7b8969682b28 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -1947,6 +1947,10 @@ void GPU_Vulkan::DeviceLost() { // TODO } +void GPU_Vulkan::DeviceRestore() { + // TODO +} + void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { const DrawEngineVulkanStats &drawStats = drawEngine_.GetStats(); float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; diff --git a/GPU/Vulkan/GPU_Vulkan.h b/GPU/Vulkan/GPU_Vulkan.h index 60c8f5fcaab9..7aa67b18fa5e 100644 --- a/GPU/Vulkan/GPU_Vulkan.h +++ b/GPU/Vulkan/GPU_Vulkan.h @@ -62,6 +62,7 @@ class GPU_Vulkan : public GPUCommon { bool PerformStencilUpload(u32 dest, int size) override; void ClearCacheNextFrame() override; void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. + void DeviceRestore() override; void DumpNextFrame() override; void DoState(PointerWrap &p) override; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 28ea79d11b19..78119427f303 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1097,6 +1097,12 @@ void EmuScreen::deviceLost() { ILOG("EmuScreen::deviceLost()"); if (gpu) gpu->DeviceLost(); +} + +void EmuScreen::deviceRestore() { + ILOG("EmuScreen::deviceRestore()"); + if (gpu) + gpu->DeviceRestore(); RecreateViews(); } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index f530b7e4d566..15d08da81ef9 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -38,6 +38,7 @@ class EmuScreen : public UIScreen { void update(InputState &input) override; void render() override; void deviceLost() override; + void deviceRestore() override; void dialogFinished(const Screen *dialog, DialogResult result) override; void sendMessage(const char *msg, const char *value) override; diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index d2d9721f613f..302107dd90ab 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -604,7 +604,7 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { // ILOG("Completed writing info for %s", info_->GetTitle().c_str()); } - virtual float priority() { + float priority() override { return info_->lastAccessedTime; } diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 9de11c395f6c..925b19efcdf4 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -808,11 +808,16 @@ void NativeUpdate(InputState &input) { screenManager->update(input); } -void NativeDeviceRestore() { +void NativeDeviceLost() { if (g_gameInfoCache) g_gameInfoCache->Clear(); screenManager->deviceLost(); + gl_lost(); +} +void NativeDeviceRestore() { + NativeDeviceLost(); + screenManager->deviceRestore(); if (GetGPUBackend() == GPUBackend::OPENGL) { gl_restore(); } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 240ab8bda815..091c48a38f68 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -697,6 +697,7 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayRender(JNIEnv *env, extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayShutdown(JNIEnv *env, jobject obj) { ILOG("NativeApp.displayShutdown()"); if (renderer_inited) { + NativeDeviceLost(); NativeShutdownGraphics(); renderer_inited = false; NativeMessageReceived("recreateviews", ""); diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 99899c821d38..5190bf9566c3 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -584,11 +584,11 @@ protected void onStop() { Log.i(TAG, "onStop - do nothing special"); } - @Override + @Override protected void onDestroy() { super.onDestroy(); - if (javaGL) { - Log.i(TAG, "onDestroy"); + if (javaGL) { + Log.i(TAG, "onDestroy"); mGLSurfaceView.onDestroy(); nativeRenderer.onDestroyed(); NativeApp.audioShutdown(); @@ -597,8 +597,8 @@ protected void onDestroy() { audioFocusChangeListener = null; audioManager = null; unregisterCallbacks(); - } - if (shuttingDown) { + } + if (shuttingDown || isFinishing()) { NativeApp.shutdown(); } } diff --git a/ext/native/gfx/gl_lost_manager.cpp b/ext/native/gfx/gl_lost_manager.cpp index 3057b37ccb01..61e68f20dd79 100644 --- a/ext/native/gfx/gl_lost_manager.cpp +++ b/ext/native/gfx/gl_lost_manager.cpp @@ -47,7 +47,6 @@ void gl_restore() { return; } - // TODO: We should really do this when we get the context back, not during gl_lost... ILOG("gl_restore() restoring %i items:", (int)holders->size()); for (size_t i = 0; i < holders->size(); i++) { ILOG("gl_restore(%i / %i, %p, %08x)", (int)(i + 1), (int)holders->size(), (*holders)[i], *((uint32_t *)((*holders)[i]))); @@ -57,6 +56,23 @@ void gl_restore() { inRestore = false; } +void gl_lost() { + inLost = true; + if (!holders) { + WLOG("GL resource holder not initialized, cannot process restore request"); + inLost = false; + return; + } + + ILOG("gl_lost() clearing %i items:", (int)holders->size()); + for (size_t i = 0; i < holders->size(); i++) { + ILOG("gl_lost(%i / %i, %p, %08x)", (int)(i + 1), (int)holders->size(), (*holders)[i], *((uint32_t *)((*holders)[i]))); + (*holders)[i]->GLLost(); + } + ILOG("gl_lost() completed on %i items:", (int)holders->size()); + inLost = false; +} + void gl_lost_manager_init() { if (holders) { FLOG("Double GL lost manager init"); diff --git a/ext/native/gfx/gl_lost_manager.h b/ext/native/gfx/gl_lost_manager.h index 29ade49d6634..cfb09601a240 100644 --- a/ext/native/gfx/gl_lost_manager.h +++ b/ext/native/gfx/gl_lost_manager.h @@ -7,6 +7,7 @@ class GfxResourceHolder { public: virtual ~GfxResourceHolder() {} virtual void GLRestore() = 0; + virtual void GLLost() = 0; }; void gl_lost_manager_init(); @@ -15,5 +16,8 @@ void gl_lost_manager_shutdown(); void register_gl_resource_holder(GfxResourceHolder *holder); void unregister_gl_resource_holder(GfxResourceHolder *holder); +// Notifies all objects it's time to forget / delete things. +void gl_lost(); + // Notifies all objects that it's time to be restored. void gl_restore(); diff --git a/ext/native/gfx_es2/glsl_program.cpp b/ext/native/gfx_es2/glsl_program.cpp index 2616a27a5c0d..cc85acb820f7 100644 --- a/ext/native/gfx_es2/glsl_program.cpp +++ b/ext/native/gfx_es2/glsl_program.cpp @@ -220,7 +220,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) { return true; } -void GLSLProgram::GLRestore() { +void GLSLProgram::GLLost() { // Quoth http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html; // "Note that when the EGL context is lost, all OpenGL resources associated with that context will be automatically deleted. // You do not need to call the corresponding "glDelete" methods such as glDeleteTextures to manually delete these lost resources." @@ -228,9 +228,12 @@ void GLSLProgram::GLRestore() { // glDeleteShader(this->vsh_); // glDeleteShader(this->fsh_); // glDeleteProgram(this->program_); - this->program_ = 0; - this->vsh_ = 0; - this->fsh_ = 0; + program_ = 0; + vsh_ = 0; + fsh_ = 0; +} + +void GLSLProgram::GLRestore() { ILOG("Restoring GLSL program %s/%s", strlen(this->vshader_filename) > 0 ? this->vshader_filename : "(mem)", strlen(this->fshader_filename) > 0 ? this->fshader_filename : "(mem)"); diff --git a/ext/native/gfx_es2/glsl_program.h b/ext/native/gfx_es2/glsl_program.h index 7a0dad0801a3..c3fa90991847 100644 --- a/ext/native/gfx_es2/glsl_program.h +++ b/ext/native/gfx_es2/glsl_program.h @@ -43,6 +43,7 @@ struct GLSLProgram : public GfxResourceHolder { GLuint fsh_; GLuint program_; + void GLLost() override; void GLRestore() override; }; diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 898e19a9488c..3b636d7177bf 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -207,8 +207,12 @@ class Thin3DGLBuffer : public Thin3DBuffer, GfxResourceHolder { glBindBuffer(target_, buffer_); } + void GLLost() override { + buffer_ = 0; + } + void GLRestore() override { - ILOG("Recreating vertex buffer after glLost"); + ILOG("Recreating vertex buffer after gl_restore"); knownSize_ = 0; // Will cause a new glBufferData call. Should genBuffers again though? glGenBuffers(1, &buffer_); } @@ -235,6 +239,10 @@ class Thin3DGLShader : public Thin3DShader { } const std::string &GetSource() const { return source_; } + void Unset() { + shader_ = 0; + } + ~Thin3DGLShader() { glDeleteShader(shader_); } @@ -257,7 +265,7 @@ bool Thin3DGLShader::Compile(const char *source) { source = temp.c_str(); } - glShaderSource(shader_, 1, &source, 0); + glShaderSource(shader_, 1, &source, nullptr); glCompileShader(shader_); GLint success = 0; glGetShaderiv(shader_, GL_COMPILE_STATUS, &success); @@ -283,6 +291,7 @@ class Thin3DGLVertexFormat : public Thin3DVertexFormat, GfxResourceHolder { void Unapply(); void Compile(); void GLRestore() override; + void GLLost() override; bool RequiresBuffer() override { return id_ != 0; } @@ -323,6 +332,12 @@ class Thin3DGLShaderSet : public Thin3DShaderSet, GfxResourceHolder { void SetVector(const char *name, float *value, int n) override; void SetMatrix4x4(const char *name, const float value[16]) override; + void GLLost() override { + program_ = 0; + vshader->Unset(); + fshader->Unset(); + } + void GLRestore() override { vshader->Compile(vshader->GetSource().c_str()); fshader->Compile(fshader->GetSource().c_str()); @@ -550,15 +565,19 @@ class Thin3DGLTexture : public Thin3DTexture, GfxResourceHolder { glBindTexture(target_, tex_); } - void GLRestore() override { + void GLLost() override { // We can assume that the texture is gone. tex_ = 0; generatedMips_ = false; + } + + void GLRestore() override { if (!filename_.empty()) { if (LoadFromFile(filename_.c_str())) { ILOG("Reloaded lost texture %s", filename_.c_str()); } else { ELOG("Failed to reload lost texture %s", filename_.c_str()); + tex_ = 0; } } else { WLOG("Texture %p cannot be restored - has no filename", this); @@ -663,6 +682,10 @@ void Thin3DGLVertexFormat::Compile() { lastBase_ = -1; } +void Thin3DGLVertexFormat::GLLost() { + id_ = 0; +} + void Thin3DGLVertexFormat::GLRestore() { Compile(); } diff --git a/ext/native/ui/screen.cpp b/ext/native/ui/screen.cpp index d13d8eca8be9..6cb9fa0a5fd7 100644 --- a/ext/native/ui/screen.cpp +++ b/ext/native/ui/screen.cpp @@ -147,6 +147,14 @@ void ScreenManager::deviceLost() { // TODO: Change this when it becomes necessary. } +void ScreenManager::deviceRestore() { + for (size_t i = 0; i < stack_.size(); i++) { + stack_[i].screen->deviceRestore(); + } + // Dialogs too? Nah, they should only use the standard UI texture anyway. + // TODO: Change this when it becomes necessary. +} + Screen *ScreenManager::topScreen() const { if (!stack_.empty()) return stack_.back().screen; diff --git a/ext/native/ui/screen.h b/ext/native/ui/screen.h index 5a018beb6504..248f9f5f50b5 100644 --- a/ext/native/ui/screen.h +++ b/ext/native/ui/screen.h @@ -50,6 +50,7 @@ class Screen { virtual void render() {} virtual void postRender() {} virtual void deviceLost() {} + virtual void deviceRestore() {} virtual void resized() {} virtual void dialogFinished(const Screen *dialog, DialogResult result) {} virtual bool touch(const TouchInput &touch) { return false; } @@ -103,6 +104,7 @@ class ScreenManager { void render(); void resized(); void deviceLost(); + void deviceRestore(); void shutdown(); // Push a dialog box in front. Currently 1-level only.