Skip to content

Commit

Permalink
Refactor UI background rendering. There's now a BackgroundScreen.
Browse files Browse the repository at this point in the history
  • Loading branch information
hrydgard committed Dec 10, 2023
1 parent 48d60d8 commit 6d51fbc
Show file tree
Hide file tree
Showing 15 changed files with 170 additions and 119 deletions.
2 changes: 1 addition & 1 deletion Common/GPU/Vulkan/VulkanFramebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
1 change: 1 addition & 0 deletions Common/System/System.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
29 changes: 24 additions & 5 deletions Common/UI/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand All @@ -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) {

This comment has been minimized.

Copy link
@unknownbrackets

unknownbrackets Dec 28, 2023

Collaborator

I would just name it foundBackgroundScreen...

-[Unknown]

This comment has been minimized.

Copy link
@hrydgard

hrydgard Dec 28, 2023

Author Owner

Yeah, good point hah.

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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
10 changes: 4 additions & 6 deletions Common/UI/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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; }
Expand Down Expand Up @@ -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_;

Expand All @@ -179,6 +176,7 @@ class ScreenManager {
const Screen *dialogFinished_ = nullptr;
DialogResult dialogResult_{};

Screen *backgroundScreen_ = nullptr;
Screen *overlayScreen_ = nullptr;

struct Layer {
Expand Down
52 changes: 28 additions & 24 deletions Common/UI/UIScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}

Expand Down
6 changes: 5 additions & 1 deletion Common/UI/UIScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -72,6 +71,8 @@ class UIScreen : public Screen {
bool ignoreInput_ = false;

protected:

This comment has been minimized.

Copy link
@unknownbrackets

unknownbrackets Dec 28, 2023

Collaborator

I guess this protected: isn't needed and is a duplicate?

-[Unknown]

virtual void DrawBackground(UIContext &ui) {}
void SetupViewport();
void DoRecreateViews();

bool recreateViews_ = true;
Expand Down Expand Up @@ -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; }
Expand Down
11 changes: 4 additions & 7 deletions UI/DisplayLayoutScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}
}
Expand Down
5 changes: 3 additions & 2 deletions UI/DisplayLayoutScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
49 changes: 46 additions & 3 deletions UI/EmuScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -424,6 +428,8 @@ EmuScreen::~EmuScreen() {
PSP_Shutdown();
}

System_PostUIMessage(UIMessage::GAME_SELECTED, "");

g_OSD.ClearAchievementStuff();

SetExtraAssertInfo(nullptr);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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_) {
Expand Down Expand Up @@ -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();
}
}

Expand Down
3 changes: 2 additions & 1 deletion UI/EmuScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -57,7 +58,7 @@ class EmuScreen : public UIScreen {
bool key(const KeyInput &key) override;

protected:

void darken();
void focusChanged(ScreenFocusChange focusChange) override;

private:
Expand Down
2 changes: 2 additions & 0 deletions UI/GameScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename I> std::string int2hexstr(I w, size_t hex_len = sizeof(I) << 1) {
Expand Down
1 change: 0 additions & 1 deletion UI/MainScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading

0 comments on commit 6d51fbc

Please sign in to comment.