From 247e764b97a45e2d34adb4fb6f3fce8f48ffa3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Oct 2026 15:04:00 +0100 Subject: [PATCH] UI: Don't use draw objects from before a device loss The system info screen's "Copy summary" kept the draw context it was created with, and the GPU driver test screen kept its pipelines and sampler, using and finally releasing them into a deleted context after Android lost the surface. Look up the draw context when clicked, and release the test objects on device loss (they're recreated on draw). Co-Authored-By: Claude Opus 5.5 (1M context) --- UI/GPUDriverTestScreen.cpp | 85 +++++++++++++++++--------------------- UI/GPUDriverTestScreen.h | 2 + UI/SystemInfoScreen.cpp | 2 +- 3 files changed, 41 insertions(+), 48 deletions(-) diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 8113f73507..673d20becb 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -239,61 +239,48 @@ GPUDriverTestScreen::GPUDriverTestScreen() { } GPUDriverTestScreen::~GPUDriverTestScreen() { - if (discardWriteDepthStencil_) - discardWriteDepthStencil_->Release(); - if (discardWriteDepth_) - discardWriteDepth_->Release(); - if (discardWriteStencil_) - discardWriteStencil_->Release(); + DestroyDeviceObjects(); +} - if (drawTestStencilEqualDepthAlways_) - drawTestStencilEqualDepthAlways_->Release(); - if (drawTestStencilNotEqualDepthAlways_) - drawTestStencilNotEqualDepthAlways_->Release(); - if (drawTestStencilEqual_) - drawTestStencilEqual_->Release(); - if (drawTestStencilNotEqual_) - drawTestStencilNotEqual_->Release(); - if (drawTestStencilAlwaysDepthLessEqual_) - drawTestStencilAlwaysDepthLessEqual_->Release(); - if (drawTestStencilAlwaysDepthGreater_) - drawTestStencilAlwaysDepthGreater_->Release(); - if (drawTestDepthLessEqual_) - drawTestDepthLessEqual_->Release(); - if (drawTestDepthGreater_) - drawTestDepthGreater_->Release(); +template +static void ReleaseAndClear(T *&obj) { + if (obj) { + obj->Release(); + obj = nullptr; + } +} - if (discardFragShader_) - discardFragShader_->Release(); +void GPUDriverTestScreen::deviceLost() { + UIBaseDialogScreen::deviceLost(); + DestroyDeviceObjects(); +} - // Shader test - if (adrenoLogicDiscardPipeline_) - adrenoLogicDiscardPipeline_->Release(); - if (flatShadingPipeline_) - flatShadingPipeline_->Release(); - - if (adrenoLogicDiscardFragShader_) - adrenoLogicDiscardFragShader_->Release(); - if (adrenoLogicDiscardVertShader_) - adrenoLogicDiscardVertShader_->Release(); - if (flatFragShader_) - flatFragShader_->Release(); - if (flatVertShader_) - flatVertShader_->Release(); - - if (samplerNearest_) - samplerNearest_->Release(); +// Everything is created again on the next draw, from the new draw context. +void GPUDriverTestScreen::DestroyDeviceObjects() { + ReleaseAndClear(discardWriteDepthStencil_); + ReleaseAndClear(discardWriteDepth_); + ReleaseAndClear(discardWriteStencil_); + ReleaseAndClear(drawTestStencilEqualDepthAlways_); + ReleaseAndClear(drawTestStencilNotEqualDepthAlways_); + ReleaseAndClear(drawTestStencilEqual_); + ReleaseAndClear(drawTestStencilNotEqual_); + ReleaseAndClear(drawTestStencilAlwaysDepthLessEqual_); + ReleaseAndClear(drawTestStencilAlwaysDepthGreater_); + ReleaseAndClear(drawTestDepthLessEqual_); + ReleaseAndClear(drawTestDepthGreater_); + ReleaseAndClear(discardFragShader_); + ReleaseAndClear(adrenoLogicDiscardPipeline_); + ReleaseAndClear(flatShadingPipeline_); + ReleaseAndClear(adrenoLogicDiscardFragShader_); + ReleaseAndClear(adrenoLogicDiscardVertShader_); + ReleaseAndClear(flatFragShader_); + ReleaseAndClear(flatVertShader_); + ReleaseAndClear(samplerNearest_); } void GPUDriverTestScreen::CreateViews() { using namespace Draw; - if (!samplerNearest_) { - DrawContext *draw = screenManager()->getDrawContext(); - SamplerStateDesc nearestDesc{}; - samplerNearest_ = draw->CreateSamplerState(nearestDesc); - } - // Don't bother with views for now. using namespace UI; auto di = GetI18NCategory(I18NCat::DIALOG); @@ -631,6 +618,10 @@ void GPUDriverTestScreen::ShaderTest(UIContext &dc) { } void GPUDriverTestScreen::DrawForeground(UIContext &dc) { + if (!samplerNearest_) { + Draw::SamplerStateDesc nearestDesc{}; + samplerNearest_ = screenManager()->getDrawContext()->CreateSamplerState(nearestDesc); + } switch (tabHolder_->GetCurrentTab()) { case 0: DiscardTest(dc); diff --git a/UI/GPUDriverTestScreen.h b/UI/GPUDriverTestScreen.h index 95ee4f1099..f4070b9def 100644 --- a/UI/GPUDriverTestScreen.h +++ b/UI/GPUDriverTestScreen.h @@ -18,12 +18,14 @@ public: void CreateViews() override; void DrawForeground(UIContext &dc) override; + void deviceLost() override; const char *tag() const override { return "GPUDriverTest"; } private: void DiscardTest(UIContext &dc); void ShaderTest(UIContext &dc); + void DestroyDeviceObjects(); // Common objects Draw::SamplerState *samplerNearest_ = nullptr; diff --git a/UI/SystemInfoScreen.cpp b/UI/SystemInfoScreen.cpp index ed6637ef5c..ca3960adec 100644 --- a/UI/SystemInfoScreen.cpp +++ b/UI/SystemInfoScreen.cpp @@ -129,7 +129,7 @@ void SystemInfoScreen::CreateDeviceInfoTab(UI::LinearLayout *deviceSpecs) { Draw::DrawContext *draw = screenManager()->getDrawContext(); - systemInfo->Add(new Choice(si->T("Copy summary to clipboard"), ImageID("I_FILE_COPY")))->OnClick.Add([draw](UI::EventParams &e) { CopySummaryToClipboard(draw); }); + systemInfo->Add(new Choice(si->T("Copy summary to clipboard"), ImageID("I_FILE_COPY")))->OnClick.Add([this](UI::EventParams &e) { CopySummaryToClipboard(screenManager()->getDrawContext()); }); systemInfo->Add(new InfoItem(si->T("System Name"), System_GetProperty(SYSPROP_NAME))); #if PPSSPP_PLATFORM(ANDROID) systemInfo->Add(new InfoItem(si->T("System Version"), StringFromInt(System_GetPropertyInt(SYSPROP_SYSTEMVERSION))));