diff --git a/Common/UI/Screen.cpp b/Common/UI/Screen.cpp index 41d9d084a1..6fe0ffc7ba 100644 --- a/Common/UI/Screen.cpp +++ b/Common/UI/Screen.cpp @@ -155,9 +155,10 @@ void ScreenManager::deviceLost() { iter.screen->deviceLost(); } -void ScreenManager::deviceRestored() { +void ScreenManager::deviceRestored(Draw::DrawContext *draw) { + draw_ = draw; for (auto &iter : stack_) - iter.screen->deviceRestored(); + iter.screen->deviceRestored(draw); } void ScreenManager::resized() { diff --git a/Common/UI/Screen.h b/Common/UI/Screen.h index 156fd57c3f..478680da03 100644 --- a/Common/UI/Screen.h +++ b/Common/UI/Screen.h @@ -81,7 +81,7 @@ public: virtual void dialogFinished(const Screen *dialog, DialogResult result) {} virtual void sendMessage(UIMessage message, const char *value) {} virtual void deviceLost() {} - virtual void deviceRestored() {} + virtual void deviceRestored(Draw::DrawContext *draw) {} virtual ScreenRenderRole renderRole(bool isTop) const { return ScreenRenderRole::NONE; } virtual bool wantBrightBackground() const { return false; } // special hack for DisplayLayoutScreen. @@ -136,9 +136,7 @@ public: void setUIContext(UIContext *context) { uiContext_ = context; } UIContext *getUIContext() { return uiContext_; } - - void setDrawContext(Draw::DrawContext *context) { thin3DContext_ = context; } - Draw::DrawContext *getDrawContext() { return thin3DContext_; } + Draw::DrawContext *getDrawContext() { return draw_; } void setPostRenderCallback(PostRenderCallback cb, void *userdata) { postRenderCb_ = cb; @@ -150,7 +148,7 @@ public: void shutdown(); void deviceLost(); - void deviceRestored(); + void deviceRestored(Draw::DrawContext *draw); // Push a dialog box in front. Currently 1-level only. void push(Screen *screen, int layerFlags = 0); @@ -190,7 +188,7 @@ private: void processFinishDialog(); UIContext *uiContext_ = nullptr; - Draw::DrawContext *thin3DContext_ = nullptr; + Draw::DrawContext *draw_ = nullptr; PostRenderCallback postRenderCb_ = nullptr; void *postRenderUserdata_ = nullptr; diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 364153b6bf..9412008276 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -190,9 +190,9 @@ void UIScreen::deviceLost() { root_->DeviceLost(); } -void UIScreen::deviceRestored() { +void UIScreen::deviceRestored(Draw::DrawContext *draw) { if (root_) - root_->DeviceRestored(screenManager()->getDrawContext()); + root_->DeviceRestored(draw); } void UIScreen::SetupViewport() { diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 2918d2676e..c8ba768ad7 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -38,7 +38,7 @@ public: void update() override; ScreenRenderFlags render(ScreenRenderMode mode) override; void deviceLost() override; - void deviceRestored() override; + void deviceRestored(Draw::DrawContext *draw) override; virtual void touch(const TouchInput &touch); virtual bool key(const KeyInput &key); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b5bfa32c4d..ad8ced0bf0 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -446,10 +446,10 @@ void EmuScreen::bootComplete() { } EmuScreen::~EmuScreen() { - Draw::DrawContext *draw = screenManager()->getDrawContext(); - ImGui_ImplThin3d_Shutdown(draw); - - ImGui::DestroyContext(); + if (imguiInited_) { + ImGui_ImplThin3d_Shutdown(); + ImGui::DestroyContext(); + } std::string gameID = g_paramSFO.GetValueString("DISC_ID"); g_Config.TimeTracker().Stop(gameID); @@ -1182,6 +1182,21 @@ void EmuScreen::CreateViews() { loadingBG->SetVisibility(V_INVISIBLE); } +void EmuScreen::deviceLost() { + UIScreen::deviceLost(); + + if (imguiInited_) { + ImGui_ImplThin3d_DestroyDeviceObjects(); + } +} + +void EmuScreen::deviceRestored(Draw::DrawContext *draw) { + UIScreen::deviceRestored(draw); + if (imguiInited_) { + ImGui_ImplThin3d_CreateDeviceObjects(draw); + } +} + UI::EventReturn EmuScreen::OnDevTools(UI::EventParams ¶ms) { DevMenuScreen *devMenu = new DevMenuScreen(gamePath_, I18NCat::DEVELOPER); if (params.v) diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index d40407add8..2abca66c16 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -58,6 +58,9 @@ public: bool key(const KeyInput &key) override; void touch(const TouchInput &key) override; + void deviceLost() override; + void deviceRestored(Draw::DrawContext *draw) override; + protected: void darken(); void focusChanged(ScreenFocusChange focusChange) override; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index f29cc45f28..770a2b4ac4 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -830,9 +830,8 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { uiContext->Text()->SetFont("Tahoma", 20, 0); g_screenManager->setUIContext(uiContext); - g_screenManager->setDrawContext(g_draw); g_screenManager->setPostRenderCallback(&CallbackPostRender, nullptr); - g_screenManager->deviceRestored(); + g_screenManager->deviceRestored(g_draw); #ifdef _WIN32 winAudioBackend = CreateAudioBackend((AudioBackendType)g_Config.iAudioBackend); diff --git a/ext/imgui/imgui_impl_thin3d.cpp b/ext/imgui/imgui_impl_thin3d.cpp index 59f1261c17..c4f9c888cf 100644 --- a/ext/imgui/imgui_impl_thin3d.cpp +++ b/ext/imgui/imgui_impl_thin3d.cpp @@ -7,10 +7,6 @@ #include "Common/System/Display.h" #include "Common/Math/lin/matrix4x4.h" -// Forward Declarations -bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw); -void ImGui_ImplThin3d_DestroyDeviceObjects(Draw::DrawContext *draw); - Lin::Matrix4x4 g_drawMatrix; struct ImGui_ImplThin3d_Data { @@ -122,90 +118,6 @@ void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *d draw->SetScissorRect(0, 0, fb_width, fb_height); } -bool ImGui_ImplThin3d_CreateFontsTexture(Draw::DrawContext *draw) { - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); - - // Destroy existing texture (if any) - if (bd->fontImage) { - ImGui_ImplThin3d_DestroyFontsTexture(draw); - } - - unsigned char* pixels; - int width, height; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - size_t upload_size = width * height * 4 * sizeof(char); - - // Create the Image: - { - Draw::TextureDesc desc; - desc.width = width; - desc.height = height; - desc.mipLevels = 1; - desc.format = Draw::DataFormat::R8G8B8A8_UNORM; - desc.type = Draw::TextureType::LINEAR2D; - desc.depth = 1; - desc.tag = "imgui-font"; - desc.initData.push_back((const uint8_t *)pixels); - bd->fontImage = draw->CreateTexture(desc); - } - - // Store our identifier - - io.Fonts->SetTexID((ImTextureID)bd->fontImage); - return true; -} - -// You probably never need to call this, as it is called by ImGui_ImplThin3d_CreateFontsTexture() and ImGui_ImplThin3d_Shutdown(). -void ImGui_ImplThin3d_DestroyFontsTexture(Draw::DrawContext *draw) { - ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); - if (bd->fontImage) { - bd->fontImage->Release(); - io.Fonts->SetTexID(0); - } -} - -static void ImGui_ImplThin3d_CreatePipeline(Draw::DrawContext *draw) { - ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); - - using namespace Draw; - - static const Draw::InputLayoutDesc ilDesc = { - sizeof(ImDrawVert), - { - { SEM_POSITION, DataFormat::R32G32_FLOAT, offsetof(ImDrawVert, pos) }, - { SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, offsetof(ImDrawVert, uv) }, - { SEM_COLOR0, DataFormat::R8G8B8A8_UNORM, offsetof(ImDrawVert, col) }, - }, - }; - InputLayout *inputLayout = draw->CreateInputLayout(ilDesc); - - BlendState *blend = draw->CreateBlendState({ true, 0xF, - BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD, - BlendFactor::ONE, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD, - }); - - DepthStencilStateDesc dsDesc{}; - DepthStencilState *depthStencil = draw->CreateDepthStencilState(dsDesc); - RasterState *rasterNoCull = draw->CreateRasterState({}); - - ShaderModule *vs_texture_color_2d = draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D); - ShaderModule *fs_texture_color_2d = draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D); - - PipelineDesc pipelineDesc{ - Primitive::TRIANGLE_LIST, - { vs_texture_color_2d, fs_texture_color_2d }, - inputLayout, - depthStencil, - blend, - rasterNoCull, - &vsTexColBufDesc - }; - - bd->pipeline = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline"); -} - bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) { ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); @@ -222,19 +134,87 @@ bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw) { bd->fontSampler = draw->CreateSamplerState(desc); } - ImGui_ImplThin3d_CreatePipeline(draw); - ImGui_ImplThin3d_CreateFontsTexture(draw); + if (!bd->pipeline) { + ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); + + using namespace Draw; + + static const Draw::InputLayoutDesc ilDesc = { + sizeof(ImDrawVert), + { + { SEM_POSITION, DataFormat::R32G32_FLOAT, offsetof(ImDrawVert, pos) }, + { SEM_TEXCOORD0, DataFormat::R32G32_FLOAT, offsetof(ImDrawVert, uv) }, + { SEM_COLOR0, DataFormat::R8G8B8A8_UNORM, offsetof(ImDrawVert, col) }, + }, + }; + InputLayout *inputLayout = draw->CreateInputLayout(ilDesc); + + BlendState *blend = draw->CreateBlendState({ true, 0xF, + BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD, + BlendFactor::ONE, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendOp::ADD, + }); + + DepthStencilStateDesc dsDesc{}; + DepthStencilState *depthStencil = draw->CreateDepthStencilState(dsDesc); + RasterState *rasterNoCull = draw->CreateRasterState({}); + + ShaderModule *vs_texture_color_2d = draw->GetVshaderPreset(VS_TEXTURE_COLOR_2D); + ShaderModule *fs_texture_color_2d = draw->GetFshaderPreset(FS_TEXTURE_COLOR_2D); + + PipelineDesc pipelineDesc{ + Primitive::TRIANGLE_LIST, + { vs_texture_color_2d, fs_texture_color_2d }, + inputLayout, + depthStencil, + blend, + rasterNoCull, + &vsTexColBufDesc + }; + + bd->pipeline = draw->CreateGraphicsPipeline(pipelineDesc, "imgui-pipeline"); + } + + if (!bd->fontImage) { + ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); + + unsigned char* pixels; + int width, height; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + size_t upload_size = width * height * 4 * sizeof(char); + + Draw::TextureDesc desc; + desc.width = width; + desc.height = height; + desc.mipLevels = 1; + desc.format = Draw::DataFormat::R8G8B8A8_UNORM; + desc.type = Draw::TextureType::LINEAR2D; + desc.depth = 1; + desc.tag = "imgui-font"; + desc.initData.push_back((const uint8_t *)pixels); + bd->fontImage = draw->CreateTexture(desc); + io.Fonts->SetTexID((ImTextureID)bd->fontImage); + } return true; } -void ImGui_ImplThin3d_DestroyDeviceObjects(Draw::DrawContext *draw) { +void ImGui_ImplThin3d_DestroyDeviceObjects() { + ImGuiIO& io = ImGui::GetIO(); ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); - ImGui_ImplThin3d_DestroyFontsTexture(draw); - bd->pipeline->Release(); - bd->pipeline = nullptr; - bd->fontSampler->Release(); - bd->fontSampler = nullptr; + if (bd->fontImage) { + bd->fontImage->Release(); + bd->fontImage = nullptr; + io.Fonts->SetTexID(0); + } + if (bd->pipeline) { + bd->pipeline->Release(); + bd->pipeline = nullptr; + } + if (bd->fontSampler) { + bd->fontSampler->Release(); + bd->fontSampler = nullptr; + } } bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw) { @@ -251,12 +231,12 @@ bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw) { return true; } -void ImGui_ImplThin3d_Shutdown(Draw::DrawContext *draw) { +void ImGui_ImplThin3d_Shutdown() { ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); - ImGui_ImplThin3d_DestroyDeviceObjects(draw); + ImGui_ImplThin3d_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; @@ -266,8 +246,9 @@ void ImGui_ImplThin3d_Shutdown(Draw::DrawContext *draw) { void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix) { ImGui_ImplThin3d_Data* bd = ImGui_ImplThin3d_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplThin3d_Init()?"); - if (!bd->fontImage) - ImGui_ImplThin3d_CreateFontsTexture(draw); + + // This one checks if objects already have been created, so ok to call every time. + ImGui_ImplThin3d_CreateDeviceObjects(draw); g_drawMatrix = drawMatrix; } diff --git a/ext/imgui/imgui_impl_thin3d.h b/ext/imgui/imgui_impl_thin3d.h index 090f98f145..c06090d35c 100644 --- a/ext/imgui/imgui_impl_thin3d.h +++ b/ext/imgui/imgui_impl_thin3d.h @@ -35,12 +35,11 @@ // Called by user code IMGUI_IMPL_API bool ImGui_ImplThin3d_Init(Draw::DrawContext *draw); -IMGUI_IMPL_API void ImGui_ImplThin3d_Shutdown(Draw::DrawContext *draw); +IMGUI_IMPL_API void ImGui_ImplThin3d_Shutdown(); IMGUI_IMPL_API void ImGui_ImplThin3d_NewFrame(Draw::DrawContext *draw, Lin::Matrix4x4 drawMatrix); IMGUI_IMPL_API void ImGui_ImplThin3d_RenderDrawData(ImDrawData* draw_data, Draw::DrawContext *draw); -IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateFontsTexture(Draw::DrawContext *draw); -IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyFontsTexture(Draw::DrawContext *draw); -IMGUI_IMPL_API void ImGui_ImplThin3d_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) +IMGUI_IMPL_API bool ImGui_ImplThin3d_CreateDeviceObjects(Draw::DrawContext *draw); +IMGUI_IMPL_API void ImGui_ImplThin3d_DestroyDeviceObjects(); IMGUI_IMPL_API ImTextureID ImGui_ImplThin3d_AddTexture(Draw::Texture *texture); IMGUI_IMPL_API Draw::Texture *ImGui_ImplThin3d_RemoveTexture(ImTextureID texture);