Android: Add both a lost and restore phase.

Lost = delete, restore = create.  Let's stick to never overlapping.

May help #8912.
This commit is contained in:
Unknown W. Brackets 2016-09-10 20:29:58 -07:00
parent 29f5763d32
commit 92d930887f
23 changed files with 109 additions and 10 deletions

View File

@ -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);
}

View File

@ -56,6 +56,7 @@ public:
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;

View File

@ -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();
}

View File

@ -129,6 +129,7 @@ public:
void RestoreVAO();
void InitDeviceObjects();
void DestroyDeviceObjects();
void GLLost() override;
void GLRestore() override;
void Resized();

View File

@ -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);
}

View File

@ -60,6 +60,7 @@ public:
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;

View File

@ -268,6 +268,7 @@ public:
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;

View File

@ -43,6 +43,7 @@ public:
void ClearCacheNextFrame() override {}
void DeviceLost() override {}
void DeviceRestore() override {}
void DumpNextFrame() override {}
void Resized() override {}

View File

@ -78,6 +78,10 @@ void SoftGPU::DeviceLost() {
// Handled by thin3d.
}
void SoftGPU::DeviceRestore() {
// Handled by thin3d.
}
SoftGPU::~SoftGPU() {
vformat->Release();
vformat = nullptr;

View File

@ -69,6 +69,7 @@ public:
void ClearCacheNextFrame() override {}
void DeviceLost() override;
void DeviceRestore() override;
void DumpNextFrame() override {}
void Resized() override {}

View File

@ -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;

View File

@ -62,6 +62,7 @@ public:
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;

View File

@ -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();
}

View File

@ -38,6 +38,7 @@ public:
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;

View File

@ -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();
}

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) {
ILOG("NativeApp.displayShutdown()");
if (renderer_inited) {
NativeDeviceLost();
NativeShutdownGraphics();
renderer_inited = false;
NativeMessageReceived("recreateviews", "");

View File

@ -57,6 +57,24 @@ 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;
}
// TODO: We should really do this when we get the context back, not during gl_lost...
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");

View File

@ -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();

View File

@ -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)");

View File

@ -43,6 +43,7 @@ struct GLSLProgram : public GfxResourceHolder {
GLuint fsh_;
GLuint program_;
void GLLost() override;
void GLRestore() override;
};

View File

@ -207,8 +207,12 @@ public:
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 @@ public:
}
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 @@ public:
void Unapply();
void Compile();
void GLRestore() override;
void GLLost() override;
bool RequiresBuffer() override {
return id_ != 0;
}
@ -323,6 +332,12 @@ public:
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 @@ public:
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();
}

View File

@ -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;

View File

@ -50,6 +50,7 @@ public:
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 @@ public:
void render();
void resized();
void deviceLost();
void deviceRestore();
void shutdown();
// Push a dialog box in front. Currently 1-level only.