Merge pull request #8968 from unknownbrackets/gl-lost

Android: Add both a lost and restore phase
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2016-09-11 10:36:58 +02:00
commit 8e4bcd7ce4
26 files changed
+115 -18

No files matched your search

+1 -1
View File
@@ -1068,7 +1068,7 @@ void PSPSaveDialog::ExecuteNotVisibleIOAction() {
{ {
bool result = param.GetSize(param.GetPspParam()); bool result = param.GetSize(param.GetPspParam());
// TODO: According to JPCSP, should test/verify this part but seems edge casey. // 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; param.GetPspParam()->common.result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_MEMSTICK;
} else if (result) { } else if (result) {
param.GetPspParam()->common.result = 0; param.GetPspParam()->common.result = 0;
+4
View File
@@ -534,6 +534,10 @@ void GPU_DX9::DeviceLost() {
framebufferManager_.DeviceLost(); framebufferManager_.DeviceLost();
} }
void GPU_DX9::DeviceRestore() {
// Nothing needed.
}
void GPU_DX9::InitClear() { void GPU_DX9::InitClear() {
ScheduleEvent(GPU_EVENT_INIT_CLEAR); ScheduleEvent(GPU_EVENT_INIT_CLEAR);
} }
+1
View File
@@ -56,6 +56,7 @@ public:
bool PerformStencilUpload(u32 dest, int size) override; bool PerformStencilUpload(u32 dest, int size) override;
void ClearCacheNextFrame() override; void ClearCacheNextFrame() override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceRestore() override;
void DumpNextFrame() override; void DumpNextFrame() override;
void DoState(PointerWrap &p) override; void DoState(PointerWrap &p) override;
+6 -2
View File
@@ -207,14 +207,18 @@ void DrawEngineGLES::DestroyDeviceObjects() {
} }
} }
void DrawEngineGLES::GLRestore() { void DrawEngineGLES::GLLost() {
ILOG("TransformDrawEngine::GLRestore()"); ILOG("TransformDrawEngine::GLLost()");
// The objects have already been deleted. // The objects have already been deleted.
bufferNameCache_.clear(); bufferNameCache_.clear();
bufferNameInfo_.clear(); bufferNameInfo_.clear();
freeSizedBuffers_.clear(); freeSizedBuffers_.clear();
bufferNameCacheSize_ = 0; bufferNameCacheSize_ = 0;
ClearTrackedVertexArrays(); ClearTrackedVertexArrays();
}
void DrawEngineGLES::GLRestore() {
ILOG("TransformDrawEngine::GLRestore()");
InitDeviceObjects(); InitDeviceObjects();
} }
+1
View File
@@ -129,6 +129,7 @@ public:
void RestoreVAO(); void RestoreVAO();
void InitDeviceObjects(); void InitDeviceObjects();
void DestroyDeviceObjects(); void DestroyDeviceObjects();
void GLLost() override;
void GLRestore() override; void GLRestore() override;
void Resized(); void Resized();
+4
View File
@@ -651,6 +651,10 @@ void GPU_GLES::DeviceLost() {
fragmentTestCache_.Clear(false); fragmentTestCache_.Clear(false);
depalShaderCache_.Clear(); depalShaderCache_.Clear();
framebufferManager_.DeviceLost(); framebufferManager_.DeviceLost();
}
void GPU_GLES::DeviceRestore() {
ILOG("GPU_GLES: DeviceRestore");
UpdateVsyncInterval(true); UpdateVsyncInterval(true);
} }
+1
View File
@@ -60,6 +60,7 @@ public:
bool PerformStencilUpload(u32 dest, int size) override; bool PerformStencilUpload(u32 dest, int size) override;
void ClearCacheNextFrame() override; void ClearCacheNextFrame() override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceRestore() override;
void DumpNextFrame() override; void DumpNextFrame() override;
void DoState(PointerWrap &p) override; void DoState(PointerWrap &p) override;
+1
View File
@@ -268,6 +268,7 @@ public:
virtual void EnableInterrupts(bool enable) = 0; virtual void EnableInterrupts(bool enable) = 0;
virtual void DeviceLost() = 0; virtual void DeviceLost() = 0;
virtual void DeviceRestore() = 0;
virtual void ReapplyGfxState() = 0; virtual void ReapplyGfxState() = 0;
virtual void SyncThread(bool force = false) = 0; virtual void SyncThread(bool force = false) = 0;
virtual void SyncBeginFrame() = 0; virtual void SyncBeginFrame() = 0;
+1
View File
@@ -43,6 +43,7 @@ public:
void ClearCacheNextFrame() override {} void ClearCacheNextFrame() override {}
void DeviceLost() override {} void DeviceLost() override {}
void DeviceRestore() override {}
void DumpNextFrame() override {} void DumpNextFrame() override {}
void Resized() override {} void Resized() override {}
+4
View File
@@ -78,6 +78,10 @@ void SoftGPU::DeviceLost() {
// Handled by thin3d. // Handled by thin3d.
} }
void SoftGPU::DeviceRestore() {
// Handled by thin3d.
}
SoftGPU::~SoftGPU() { SoftGPU::~SoftGPU() {
vformat->Release(); vformat->Release();
vformat = nullptr; vformat = nullptr;
+1
View File
@@ -69,6 +69,7 @@ public:
void ClearCacheNextFrame() override {} void ClearCacheNextFrame() override {}
void DeviceLost() override; void DeviceLost() override;
void DeviceRestore() override;
void DumpNextFrame() override {} void DumpNextFrame() override {}
void Resized() override {} void Resized() override {}
+4
View File
@@ -1947,6 +1947,10 @@ void GPU_Vulkan::DeviceLost() {
// TODO // TODO
} }
void GPU_Vulkan::DeviceRestore() {
// TODO
}
void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) { void GPU_Vulkan::GetStats(char *buffer, size_t bufsize) {
const DrawEngineVulkanStats &drawStats = drawEngine_.GetStats(); const DrawEngineVulkanStats &drawStats = drawEngine_.GetStats();
float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f; float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f;
+1
View File
@@ -62,6 +62,7 @@ public:
bool PerformStencilUpload(u32 dest, int size) override; bool PerformStencilUpload(u32 dest, int size) override;
void ClearCacheNextFrame() override; void ClearCacheNextFrame() override;
void DeviceLost() override; // Only happens on Android. Drop all textures and shaders. void DeviceLost() override; // Only happens on Android. Drop all textures and shaders.
void DeviceRestore() override;
void DumpNextFrame() override; void DumpNextFrame() override;
void DoState(PointerWrap &p) override; void DoState(PointerWrap &p) override;
+6
View File
@@ -1097,6 +1097,12 @@ void EmuScreen::deviceLost() {
ILOG("EmuScreen::deviceLost()"); ILOG("EmuScreen::deviceLost()");
if (gpu) if (gpu)
gpu->DeviceLost(); gpu->DeviceLost();
}
void EmuScreen::deviceRestore() {
ILOG("EmuScreen::deviceRestore()");
if (gpu)
gpu->DeviceRestore();
RecreateViews(); RecreateViews();
} }
+1
View File
@@ -38,6 +38,7 @@ public:
void update(InputState &input) override; void update(InputState &input) override;
void render() override; void render() override;
void deviceLost() override; void deviceLost() override;
void deviceRestore() override;
void dialogFinished(const Screen *dialog, DialogResult result) override; void dialogFinished(const Screen *dialog, DialogResult result) override;
void sendMessage(const char *msg, const char *value) override; void sendMessage(const char *msg, const char *value) override;
+1 -1
View File
@@ -604,7 +604,7 @@ handleELF:
// ILOG("Completed writing info for %s", info_->GetTitle().c_str()); // ILOG("Completed writing info for %s", info_->GetTitle().c_str());
} }
virtual float priority() { float priority() override {
return info_->lastAccessedTime; return info_->lastAccessedTime;
} }
+6 -1
View File
@@ -808,11 +808,16 @@ void NativeUpdate(InputState &input) {
screenManager->update(input); screenManager->update(input);
} }
void NativeDeviceRestore() { void NativeDeviceLost() {
if (g_gameInfoCache) if (g_gameInfoCache)
g_gameInfoCache->Clear(); g_gameInfoCache->Clear();
screenManager->deviceLost(); screenManager->deviceLost();
gl_lost();
}
void NativeDeviceRestore() {
NativeDeviceLost();
screenManager->deviceRestore();
if (GetGPUBackend() == GPUBackend::OPENGL) { if (GetGPUBackend() == GPUBackend::OPENGL) {
gl_restore(); gl_restore();
} }
+1
View File
@@ -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) { extern "C" void Java_org_ppsspp_ppsspp_NativeRenderer_displayShutdown(JNIEnv *env, jobject obj) {
ILOG("NativeApp.displayShutdown()"); ILOG("NativeApp.displayShutdown()");
if (renderer_inited) { if (renderer_inited) {
NativeDeviceLost();
NativeShutdownGraphics(); NativeShutdownGraphics();
renderer_inited = false; renderer_inited = false;
NativeMessageReceived("recreateviews", ""); NativeMessageReceived("recreateviews", "");
@@ -584,11 +584,11 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
Log.i(TAG, "onStop - do nothing special"); Log.i(TAG, "onStop - do nothing special");
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
if (javaGL) { if (javaGL) {
Log.i(TAG, "onDestroy"); Log.i(TAG, "onDestroy");
mGLSurfaceView.onDestroy(); mGLSurfaceView.onDestroy();
nativeRenderer.onDestroyed(); nativeRenderer.onDestroyed();
NativeApp.audioShutdown(); NativeApp.audioShutdown();
@@ -597,8 +597,8 @@ public class NativeActivity extends Activity implements SurfaceHolder.Callback {
audioFocusChangeListener = null; audioFocusChangeListener = null;
audioManager = null; audioManager = null;
unregisterCallbacks(); unregisterCallbacks();
} }
if (shuttingDown) { if (shuttingDown || isFinishing()) {
NativeApp.shutdown(); NativeApp.shutdown();
} }
} }
+17 -1
View File
@@ -47,7 +47,6 @@ void gl_restore() {
return; 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()); ILOG("gl_restore() restoring %i items:", (int)holders->size());
for (size_t i = 0; i < holders->size(); i++) { 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]))); 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; 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() { void gl_lost_manager_init() {
if (holders) { if (holders) {
FLOG("Double GL lost manager init"); FLOG("Double GL lost manager init");
+4
View File
@@ -7,6 +7,7 @@ class GfxResourceHolder {
public: public:
virtual ~GfxResourceHolder() {} virtual ~GfxResourceHolder() {}
virtual void GLRestore() = 0; virtual void GLRestore() = 0;
virtual void GLLost() = 0;
}; };
void gl_lost_manager_init(); void gl_lost_manager_init();
@@ -15,5 +16,8 @@ void gl_lost_manager_shutdown();
void register_gl_resource_holder(GfxResourceHolder *holder); void register_gl_resource_holder(GfxResourceHolder *holder);
void unregister_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. // Notifies all objects that it's time to be restored.
void gl_restore(); void gl_restore();
+7 -4
View File
@@ -220,7 +220,7 @@ bool glsl_recompile(GLSLProgram *program, std::string *error_message) {
return true; return true;
} }
void GLSLProgram::GLRestore() { void GLSLProgram::GLLost() {
// Quoth http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html; // 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. // "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." // 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->vsh_);
// glDeleteShader(this->fsh_); // glDeleteShader(this->fsh_);
// glDeleteProgram(this->program_); // glDeleteProgram(this->program_);
this->program_ = 0; program_ = 0;
this->vsh_ = 0; vsh_ = 0;
this->fsh_ = 0; fsh_ = 0;
}
void GLSLProgram::GLRestore() {
ILOG("Restoring GLSL program %s/%s", ILOG("Restoring GLSL program %s/%s",
strlen(this->vshader_filename) > 0 ? this->vshader_filename : "(mem)", strlen(this->vshader_filename) > 0 ? this->vshader_filename : "(mem)",
strlen(this->fshader_filename) > 0 ? this->fshader_filename : "(mem)"); strlen(this->fshader_filename) > 0 ? this->fshader_filename : "(mem)");
+1
View File
@@ -43,6 +43,7 @@ struct GLSLProgram : public GfxResourceHolder {
GLuint fsh_; GLuint fsh_;
GLuint program_; GLuint program_;
void GLLost() override;
void GLRestore() override; void GLRestore() override;
}; };
+26 -3
View File
@@ -207,8 +207,12 @@ public:
glBindBuffer(target_, buffer_); glBindBuffer(target_, buffer_);
} }
void GLLost() override {
buffer_ = 0;
}
void GLRestore() override { 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? knownSize_ = 0; // Will cause a new glBufferData call. Should genBuffers again though?
glGenBuffers(1, &buffer_); glGenBuffers(1, &buffer_);
} }
@@ -235,6 +239,10 @@ public:
} }
const std::string &GetSource() const { return source_; } const std::string &GetSource() const { return source_; }
void Unset() {
shader_ = 0;
}
~Thin3DGLShader() { ~Thin3DGLShader() {
glDeleteShader(shader_); glDeleteShader(shader_);
} }
@@ -257,7 +265,7 @@ bool Thin3DGLShader::Compile(const char *source) {
source = temp.c_str(); source = temp.c_str();
} }
glShaderSource(shader_, 1, &source, 0); glShaderSource(shader_, 1, &source, nullptr);
glCompileShader(shader_); glCompileShader(shader_);
GLint success = 0; GLint success = 0;
glGetShaderiv(shader_, GL_COMPILE_STATUS, &success); glGetShaderiv(shader_, GL_COMPILE_STATUS, &success);
@@ -283,6 +291,7 @@ public:
void Unapply(); void Unapply();
void Compile(); void Compile();
void GLRestore() override; void GLRestore() override;
void GLLost() override;
bool RequiresBuffer() override { bool RequiresBuffer() override {
return id_ != 0; return id_ != 0;
} }
@@ -323,6 +332,12 @@ public:
void SetVector(const char *name, float *value, int n) override; void SetVector(const char *name, float *value, int n) override;
void SetMatrix4x4(const char *name, const float value[16]) override; void SetMatrix4x4(const char *name, const float value[16]) override;
void GLLost() override {
program_ = 0;
vshader->Unset();
fshader->Unset();
}
void GLRestore() override { void GLRestore() override {
vshader->Compile(vshader->GetSource().c_str()); vshader->Compile(vshader->GetSource().c_str());
fshader->Compile(fshader->GetSource().c_str()); fshader->Compile(fshader->GetSource().c_str());
@@ -550,15 +565,19 @@ public:
glBindTexture(target_, tex_); glBindTexture(target_, tex_);
} }
void GLRestore() override { void GLLost() override {
// We can assume that the texture is gone. // We can assume that the texture is gone.
tex_ = 0; tex_ = 0;
generatedMips_ = false; generatedMips_ = false;
}
void GLRestore() override {
if (!filename_.empty()) { if (!filename_.empty()) {
if (LoadFromFile(filename_.c_str())) { if (LoadFromFile(filename_.c_str())) {
ILOG("Reloaded lost texture %s", filename_.c_str()); ILOG("Reloaded lost texture %s", filename_.c_str());
} else { } else {
ELOG("Failed to reload lost texture %s", filename_.c_str()); ELOG("Failed to reload lost texture %s", filename_.c_str());
tex_ = 0;
} }
} else { } else {
WLOG("Texture %p cannot be restored - has no filename", this); WLOG("Texture %p cannot be restored - has no filename", this);
@@ -663,6 +682,10 @@ void Thin3DGLVertexFormat::Compile() {
lastBase_ = -1; lastBase_ = -1;
} }
void Thin3DGLVertexFormat::GLLost() {
id_ = 0;
}
void Thin3DGLVertexFormat::GLRestore() { void Thin3DGLVertexFormat::GLRestore() {
Compile(); Compile();
} }
+8
View File
@@ -147,6 +147,14 @@ void ScreenManager::deviceLost() {
// TODO: Change this when it becomes necessary. // 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 { Screen *ScreenManager::topScreen() const {
if (!stack_.empty()) if (!stack_.empty())
return stack_.back().screen; return stack_.back().screen;
+2
View File
@@ -50,6 +50,7 @@ public:
virtual void render() {} virtual void render() {}
virtual void postRender() {} virtual void postRender() {}
virtual void deviceLost() {} virtual void deviceLost() {}
virtual void deviceRestore() {}
virtual void resized() {} virtual void resized() {}
virtual void dialogFinished(const Screen *dialog, DialogResult result) {} virtual void dialogFinished(const Screen *dialog, DialogResult result) {}
virtual bool touch(const TouchInput &touch) { return false; } virtual bool touch(const TouchInput &touch) { return false; }
@@ -103,6 +104,7 @@ public:
void render(); void render();
void resized(); void resized();
void deviceLost(); void deviceLost();
void deviceRestore();
void shutdown(); void shutdown();
// Push a dialog box in front. Currently 1-level only. // Push a dialog box in front. Currently 1-level only.