diff --git a/Common/GPU/Vulkan/VulkanFramebuffer.cpp b/Common/GPU/Vulkan/VulkanFramebuffer.cpp index 3babe92fa0c0..3f77f24efe6c 100644 --- a/Common/GPU/Vulkan/VulkanFramebuffer.cpp +++ b/Common/GPU/Vulkan/VulkanFramebuffer.cpp @@ -291,7 +291,7 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas _dbg_assert_(!(isBackbuffer && multisample)); if (isBackbuffer) { - _dbg_assert_(key.depthLoadAction == VKRRenderPassLoadAction::CLEAR); + _dbg_assert_(key.depthLoadAction != VKRRenderPassLoadAction::KEEP); } if (multiview) { diff --git a/Common/System/System.h b/Common/System/System.h index 1568e43ed5b1..643e6218213f 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -224,6 +224,7 @@ enum class UIMessage { REQUEST_GAME_PAUSE, REQUEST_GAME_RESET, REQUEST_GAME_STOP, + GAME_SELECTED, SHOW_CONTROL_MAPPING, SHOW_CHAT_SCREEN, SHOW_DISPLAY_LAYOUT_EDITOR, diff --git a/Common/UI/Screen.cpp b/Common/UI/Screen.cpp index 20a2744892c6..b1fe507cfe4a 100644 --- a/Common/UI/Screen.cpp +++ b/Common/UI/Screen.cpp @@ -60,6 +60,7 @@ void ScreenManager::update() { // NOTE: This is not a full UIScreen update, to avoid double global event processing. overlayScreen_->update(); } + // The background screen doesn't need updating. if (stack_.size()) { stack_.back().screen->update(); } @@ -161,7 +162,8 @@ void ScreenManager::render() { // Start at the end, collect screens to form the transparency stack. // Then we'll iterate them in reverse order. // Note that we skip the overlay screen, we handle it separately. - + // Additionally, we pick up a "background" screen. Normally it will be either + // the EmuScreen or the actual global background screen. auto iter = stack_.end(); Screen *coveringScreen = nullptr; Screen *backgroundScreen = nullptr; @@ -179,7 +181,13 @@ void ScreenManager::render() { } } while (iter != stack_.begin()); - // OK, now we iterate backwards over our little pile of screens. + // Confusing-looking expression, argh! Note the '_' + if (backgroundScreen_ && !backgroundScreen) { + layers.push_back(backgroundScreen_); + backgroundScreen = backgroundScreen_; + } + + // OK, now we iterate backwards over our little pile of collected screens. bool first = true; for (int i = (int)layers.size() - 1; i >= 0; i--) { ScreenRenderMode mode = ScreenRenderMode::DEFAULT; @@ -240,8 +248,13 @@ void ScreenManager::sendMessage(UIMessage message, const char *value) { touch(input); } - if (!stack_.empty()) + if (backgroundScreen_) { + backgroundScreen_->sendMessage(message, value); + } + + if (!stack_.empty()) { stack_.back().screen->sendMessage(message, value); + } } Screen *ScreenManager::topScreen() const { @@ -375,10 +388,16 @@ void ScreenManager::processFinishDialog() { } } -void ScreenManager::SetOverlayScreen(Screen *screen) { +void ScreenManager::SetBackgroundOverlayScreens(Screen *backgroundScreen, Screen *overlayScreen) { + if (backgroundScreen_) { + delete backgroundScreen_; + } + backgroundScreen_ = backgroundScreen; + backgroundScreen_->setScreenManager(this); + if (overlayScreen_) { delete overlayScreen_; } - overlayScreen_ = screen; + overlayScreen_ = overlayScreen; overlayScreen_->setScreenManager(this); } diff --git a/Common/UI/Screen.h b/Common/UI/Screen.h index 5582799cccd4..ed5b2a957aa7 100644 --- a/Common/UI/Screen.h +++ b/Common/UI/Screen.h @@ -71,7 +71,8 @@ class Screen { virtual void sendMessage(UIMessage message, const char *value) {} virtual void deviceLost() {} virtual void deviceRestored() {} - virtual bool canBeBackground() { return false; } + virtual bool canBeBackground() const { return false; } + virtual bool wantBrightBackground() const { return false; } // special hack for DisplayLayoutScreen. virtual void focusChanged(ScreenFocusChange focusChange); @@ -86,10 +87,6 @@ class Screen { ScreenManager *screenManager() { return screenManager_; } void setScreenManager(ScreenManager *sm) { screenManager_ = sm; } - // This one is icky to use because you can't know what's in it until you know - // what screen it is. - virtual void *dialogData() { return 0; } - virtual const char *tag() const = 0; virtual bool isTransparent() const { return false; } @@ -161,7 +158,7 @@ class ScreenManager { void getFocusPosition(float &x, float &y, float &z); // Will delete any existing overlay screen. - void SetOverlayScreen(Screen *screen); + void SetBackgroundOverlayScreens(Screen *backgroundScreen, Screen *overlayScreen); std::recursive_mutex inputLock_; @@ -179,6 +176,7 @@ class ScreenManager { const Screen *dialogFinished_ = nullptr; DialogResult dialogResult_{}; + Screen *backgroundScreen_ = nullptr; Screen *overlayScreen_ = nullptr; struct Layer { diff --git a/Common/UI/UIScreen.cpp b/Common/UI/UIScreen.cpp index 2aa634f7b391..99bb251c31df 100644 --- a/Common/UI/UIScreen.cpp +++ b/Common/UI/UIScreen.cpp @@ -193,41 +193,45 @@ void UIScreen::deviceRestored() { root_->DeviceRestored(screenManager()->getDrawContext()); } +void UIScreen::SetupViewport() { + using namespace Draw; + Draw::DrawContext *draw = screenManager()->getDrawContext(); + _dbg_assert_(draw != nullptr); + // Bind and clear the back buffer + draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); + screenManager()->getUIContext()->BeginFrame(); + + Draw::Viewport viewport; + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.Width = g_display.pixel_xres; + viewport.Height = g_display.pixel_yres; + viewport.MaxDepth = 1.0; + viewport.MinDepth = 0.0; + draw->SetViewport(viewport); + draw->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres); +} + void UIScreen::render(ScreenRenderMode mode) { if (mode & ScreenRenderMode::FIRST) { - using namespace Draw; - Draw::DrawContext *draw = screenManager()->getDrawContext(); - _dbg_assert_(draw != nullptr); - // Bind and clear the back buffer - draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI"); - screenManager()->getUIContext()->BeginFrame(); - - Draw::Viewport viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = g_display.pixel_xres; - viewport.Height = g_display.pixel_yres; - viewport.MaxDepth = 1.0; - viewport.MinDepth = 0.0; - draw->SetViewport(viewport); - draw->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres); + SetupViewport(); } DoRecreateViews(); if (root_) { - UIContext *uiContext = screenManager()->getUIContext(); + UIContext &uiContext = *screenManager()->getUIContext(); - UI::LayoutViewHierarchy(*uiContext, root_, ignoreInsets_); + UI::LayoutViewHierarchy(uiContext, root_, ignoreInsets_); - uiContext->PushTransform({translation_, scale_, alpha_}); + uiContext.PushTransform({translation_, scale_, alpha_}); - uiContext->Begin(); - DrawBackground(*uiContext); - root_->Draw(*uiContext); - uiContext->Flush(); + uiContext.Begin(); + DrawBackground(uiContext); + root_->Draw(uiContext); + uiContext.Flush(); - uiContext->PopTransform(); + uiContext.PopTransform(); } } diff --git a/Common/UI/UIScreen.h b/Common/UI/UIScreen.h index 1f359c8ea8e9..003b0a75881f 100644 --- a/Common/UI/UIScreen.h +++ b/Common/UI/UIScreen.h @@ -59,7 +59,6 @@ class UIScreen : public Screen { protected: virtual void CreateViews() = 0; - virtual void DrawBackground(UIContext &dc) {} void RecreateViews() override { recreateViews_ = true; } bool UseVerticalLayout() const; @@ -72,6 +71,8 @@ class UIScreen : public Screen { bool ignoreInput_ = false; protected: + virtual void DrawBackground(UIContext &ui) {} + void SetupViewport(); void DoRecreateViews(); bool recreateViews_ = true; @@ -109,6 +110,9 @@ class PopupScreen : public UIDialogScreen { void SetHasDropShadow(bool has) { hasDropShadow_ = has; } + // For the postproc param sliders on DisplayLayoutScreen + bool wantBrightBackground() const { return !hasDropShadow_; } + protected: virtual bool FillVertical() const { return false; } virtual UI::Size PopupWidth() const { return 550; } diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 5d845ebb3d49..d82d3a9da87c 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -117,19 +117,15 @@ class DisplayLayoutBackground : public UI::View { float startDisplayOffsetY_ = -1.0f; }; -DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) { - // Show background at full brightness - darkenGameBackground_ = false; - forceTransparent_ = true; -} +DisplayLayoutScreen::DisplayLayoutScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename) {} void DisplayLayoutScreen::DrawBackground(UIContext &dc) { if (PSP_IsInited() && !g_Config.bSkipBufferEffects) { - // We normally rely on the PSP screen. - UIDialogScreenWithGameBackground::DrawBackground(dc); + // We normally rely on the PSP screen showing through. } else { // But if it's not present (we're not in game, or skip buffer effects is used), // we have to draw a substitute ourselves. + UIContext &dc = *screenManager()->getUIContext(); // TODO: Clean this up a bit, this GetScreenFrame/CenterDisplay combo is too common. FRect screenFrame = GetScreenFrame(g_display.pixel_xres, g_display.pixel_yres); @@ -138,6 +134,7 @@ void DisplayLayoutScreen::DrawBackground(UIContext &dc) { dc.Flush(); ImageID bg = ImageID("I_PSP_DISPLAY"); + dc.Draw()->DrawImageStretch(bg, dc.GetBounds(), 0x7F000000); dc.Draw()->DrawImageStretch(bg, FRectToBounds(rc), 0x7FFFFFFF); } } diff --git a/UI/DisplayLayoutScreen.h b/UI/DisplayLayoutScreen.h index 0af2648bc663..f4a80b0c8330 100644 --- a/UI/DisplayLayoutScreen.h +++ b/UI/DisplayLayoutScreen.h @@ -32,18 +32,19 @@ class DisplayLayoutScreen : public UIDialogScreenWithGameBackground { void dialogFinished(const Screen *dialog, DialogResult result) override; void onFinish(DialogResult reason) override; - void DrawBackground(UIContext &dc) override; - void resized() override { RecreateViews(); } + bool wantBrightBackground() const override { return true; } + const char *tag() const override { return "DisplayLayout"; } protected: UI::EventReturn OnPostProcShaderChange(UI::EventParams &e); void sendMessage(UIMessage message, const char *value) override; + void DrawBackground(UIContext &dc) override; private: UI::ChoiceStrip *mode_ = nullptr; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index eeb8016b44fb..ec7542c22d93 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -361,6 +361,10 @@ void EmuScreen::bootGame(const Path &filename) { loadingViewVisible_->Divert(UI::V_VISIBLE, 0.75f); screenManager()->getDrawContext()->ResetStats(); + + if (bootPending_) { + System_PostUIMessage(UIMessage::GAME_SELECTED, filename.c_str()); + } } void EmuScreen::bootComplete() { @@ -424,6 +428,8 @@ EmuScreen::~EmuScreen() { PSP_Shutdown(); } + System_PostUIMessage(UIMessage::GAME_SELECTED, ""); + g_OSD.ClearAchievementStuff(); SetExtraAssertInfo(nullptr); @@ -1409,9 +1415,32 @@ static void DrawFPS(UIContext *ctx, const Bounds &bounds) { ctx->RebindTexture(); } +bool EmuScreen::canBeBackground() const { + if (g_Config.bSkipBufferEffects) + return false; + + bool forceTransparent = false; // this needs to be true somehow on the display layout screen. + + if (!g_Config.bTransparentBackground && !forceTransparent) + return false; + + return true; +} + +void EmuScreen::darken() { + if (!screenManager()->topScreen()->wantBrightBackground()) { + UIContext &dc = *screenManager()->getUIContext(); + uint32_t color = GetBackgroundColorWithAlpha(dc); + dc.Begin(); + dc.RebindTexture(); + dc.FillRect(UI::Drawable(color), dc.GetBounds()); + dc.Flush(); + } +} + void EmuScreen::render(ScreenRenderMode mode) { - if (mode == ScreenRenderMode::FIRST) { - // Actually, always gonna be first (?) + if (mode & ScreenRenderMode::FIRST) { + // Actually, always gonna be first when it exists (?) using namespace Draw; DrawContext *draw = screenManager()->getDrawContext(); @@ -1450,8 +1479,19 @@ void EmuScreen::render(ScreenRenderMode mode) { g_OSD.NudgeSidebar(); - if (screenManager()->topScreen() == this) { + if (mode & ScreenRenderMode::TOP) { System_Notify(SystemNotification::KEEP_SCREEN_AWAKE); + } else { + // Not on top. Let's not execute, only draw the image. + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE }, "EmuScreen_Stepping"); + // Just to make sure. + if (PSP_IsInited() && !g_Config.bSkipBufferEffects) { + PSP_BeginHostFrame(); + gpu->CopyDisplayToOutput(true); + PSP_EndHostFrame(); + darken(); + } + return; } if (invalid_) { @@ -1548,8 +1588,11 @@ void EmuScreen::render(ScreenRenderMode mode) { } if (mode & ScreenRenderMode::TOP) { + // TODO: Replace this with something else. if (stopRender_) thin3d->WipeQueue(); + } else if (!screenManager()->topScreen()->wantBrightBackground()) { + darken(); } } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 0720d6ced34f..a050fd92660c 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -46,6 +46,7 @@ class EmuScreen : public UIScreen { void dialogFinished(const Screen *dialog, DialogResult result) override; void sendMessage(UIMessage message, const char *value) override; void resized() override; + bool canBeBackground() const override; // Note: Unlike your average boring UIScreen, here we override the Unsync* functions // to get minimal latency and full control. We forward to UIScreen when needed. @@ -57,7 +58,7 @@ class EmuScreen : public UIScreen { bool key(const KeyInput &key) override; protected: - + void darken(); void focusChanged(ScreenFocusChange focusChange) override; private: diff --git a/UI/GameScreen.cpp b/UI/GameScreen.cpp index d38cd53ccb43..aae67e8be313 100644 --- a/UI/GameScreen.cpp +++ b/UI/GameScreen.cpp @@ -51,12 +51,14 @@ GameScreen::GameScreen(const Path &gamePath) : UIDialogScreenWithGameBackground(gamePath) { g_BackgroundAudio.SetGame(gamePath); + System_PostUIMessage(UIMessage::GAME_SELECTED, gamePath.ToString()); } GameScreen::~GameScreen() { if (CRC32string == "...") { Reporting::CancelCRC(); } + System_PostUIMessage(UIMessage::GAME_SELECTED, ""); } template std::string int2hexstr(I w, size_t hex_len = sizeof(I) << 1) { diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index f52d00698080..43dab5c02559 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -1389,7 +1389,6 @@ UI::EventReturn MainScreen::OnFullScreenToggle(UI::EventParams &e) { } void MainScreen::DrawBackground(UIContext &dc) { - UIScreenWithBackground::DrawBackground(dc); if (highlightedGamePath_.empty() && prevHighlightedGamePath_.empty()) { return; } diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index b375e27f781c..76218bf27a07 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -368,36 +368,10 @@ uint32_t GetBackgroundColorWithAlpha(const UIContext &dc) { return colorAlpha(colorBlend(dc.GetTheme().backgroundColor, 0, 0.5f), 0.65f); // 0.65 = 166 = A6 } -void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z, bool transparent, bool darkenBackground) { +void DrawGameBackground(UIContext &dc, const Path &gamePath, float x, float y, float z) { using namespace Draw; using namespace UI; - if (transparent && PSP_IsInited() && !g_Config.bSkipBufferEffects) { - gpu->CheckDisplayResized(); - gpu->CheckConfigChanged(); - gpu->CopyDisplayToOutput(true); - - DrawContext *draw = dc.GetDrawContext(); - Viewport viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = g_display.pixel_xres; - viewport.Height = g_display.pixel_yres; - viewport.MaxDepth = 1.0; - viewport.MinDepth = 0.0; - draw->SetViewport(viewport); - dc.BeginFrame(); - dc.RebindTexture(); - dc.Begin(); - - if (darkenBackground) { - uint32_t color = GetBackgroundColorWithAlpha(dc); - dc.FillRect(UI::Drawable(color), dc.GetBounds()); - dc.Flush(); - } - return; - } - std::shared_ptr ginfo; if (!gamePath.empty()) ginfo = g_gameInfoCache->GetInfo(dc.GetDrawContext(), gamePath, GAMEINFO_WANTBG); @@ -455,21 +429,43 @@ void HandleCommonMessages(UIMessage message, const char *value, ScreenManager *m } } -void UIScreenWithBackground::DrawBackground(UIContext &dc) { - float x, y, z; - screenManager()->getFocusPosition(x, y, z); - ::DrawBackground(dc, 1.0f, x, y, z); - dc.Flush(); -} +void BackgroundScreen::render(ScreenRenderMode mode) { + if (mode & ScreenRenderMode::FIRST) { + SetupViewport(); + } else { + _dbg_assert_(false); + } + + UIContext *uiContext = screenManager()->getUIContext(); + + uiContext->PushTransform({ translation_, scale_, alpha_ }); -void UIScreenWithGameBackground::DrawBackground(UIContext &dc) { + uiContext->Begin(); float x, y, z; screenManager()->getFocusPosition(x, y, z); + if (!gamePath_.empty()) { - DrawGameBackground(dc, gamePath_, x, y, z, (g_Config.bTransparentBackground || forceTransparent_), darkenGameBackground_); + ::DrawGameBackground(*uiContext, gamePath_, x, y, z); } else { - ::DrawBackground(dc, 1.0f, x, y, z); - dc.Flush(); + ::DrawBackground(*uiContext, 1.0f, x, y, z); + } + + uiContext->Flush(); + + uiContext->PopTransform(); +} + +void BackgroundScreen::sendMessage(UIMessage message, const char *value) { + switch (message) { + case UIMessage::GAME_SELECTED: + if (value && strlen(value)) { + gamePath_ = Path(value); + } else { + gamePath_.clear(); + } + break; + default: + break; } } @@ -481,19 +477,6 @@ void UIScreenWithGameBackground::sendMessage(UIMessage message, const char *valu } } -void UIDialogScreenWithGameBackground::DrawBackground(UIContext &dc) { - using namespace UI; - using namespace Draw; - float x, y, z; - screenManager()->getFocusPosition(x, y, z); - if (!gamePath_.empty()) { - DrawGameBackground(dc, gamePath_, x, y, z, (g_Config.bTransparentBackground || forceTransparent_), darkenGameBackground_); - } else { - ::DrawBackground(dc, 1.0f, x, y, z); - dc.Flush(); - } -} - void UIDialogScreenWithGameBackground::sendMessage(UIMessage message, const char *value) { if (message == UIMessage::SHOW_SETTINGS && screenManager()->topScreen() == this) { screenManager()->push(new GameSettingsScreen(gamePath_)); @@ -506,13 +489,6 @@ void UIScreenWithBackground::sendMessage(UIMessage message, const char *value) { HandleCommonMessages(message, value, screenManager(), this); } -void UIDialogScreenWithBackground::DrawBackground(UIContext &dc) { - float x, y, z; - screenManager()->getFocusPosition(x, y, z); - ::DrawBackground(dc, 1.0f, x, y, z); - dc.Flush(); -} - void UIDialogScreenWithBackground::AddStandardBack(UI::ViewGroup *parent) { using namespace UI; auto di = GetI18NCategory(I18NCat::DIALOG); diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 24415de636d4..cc4a6b595f77 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -36,19 +36,31 @@ void UIBackgroundShutdown(); inline void NoOpVoidBool(bool) {} +class BackgroundScreen : public UIScreen { +public: + void render(ScreenRenderMode mode) override; + void sendMessage(UIMessage message, const char *value) override; + + +private: + void CreateViews() override {} + const char *tag() const override { return "bg"; } + + Path gamePath_; +}; + +// This doesn't have anything to do with the background anymore. It's just a PPSSPP UIScreen +// that knows how handle sendMessage properly. Same for all the below. class UIScreenWithBackground : public UIScreen { public: UIScreenWithBackground() : UIScreen() {} protected: - void DrawBackground(UIContext &dc) override; void sendMessage(UIMessage message, const char *value) override; }; class UIScreenWithGameBackground : public UIScreenWithBackground { public: - UIScreenWithGameBackground(const std::string &gamePath) - : UIScreenWithBackground(), gamePath_(gamePath) {} - void DrawBackground(UIContext &dc) override; + UIScreenWithGameBackground(const Path &gamePath) : UIScreenWithBackground(), gamePath_(gamePath) {} void sendMessage(UIMessage message, const char *value) override; protected: Path gamePath_; @@ -61,9 +73,7 @@ class UIDialogScreenWithBackground : public UIDialogScreen { public: UIDialogScreenWithBackground() : UIDialogScreen() {} protected: - void DrawBackground(UIContext &dc) override; void sendMessage(UIMessage message, const char *value) override; - void AddStandardBack(UI::ViewGroup *parent); }; @@ -71,13 +81,9 @@ class UIDialogScreenWithGameBackground : public UIDialogScreenWithBackground { public: UIDialogScreenWithGameBackground(const Path &gamePath) : UIDialogScreenWithBackground(), gamePath_(gamePath) {} - void DrawBackground(UIContext &dc) override; void sendMessage(UIMessage message, const char *value) override; protected: Path gamePath_; - - bool forceTransparent_ = false; - bool darkenGameBackground_ = true; }; class PromptScreen : public UIDialogScreenWithGameBackground { diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 9b3dbda7ec22..05e7ec97d82c 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -798,7 +798,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch g_screenManager->switchScreen(new LogoScreen(AfterLogoScreen::DEFAULT)); } - g_screenManager->SetOverlayScreen(new OSDOverlayScreen()); + g_screenManager->SetBackgroundOverlayScreens(new BackgroundScreen(), new OSDOverlayScreen()); // Easy testing // screenManager->push(new GPUDriverTestScreen());