Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Screen manager refactoring, preparation for running the game behind the pause screen #18511

Merged
merged 7 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
3 changes: 1 addition & 2 deletions Common/UI/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,8 +164,7 @@ void UIContext::ActivateTopScissor() {
int w = std::max(0.0f, ceilf(scale_x * bounds.w));
int h = std::max(0.0f, ceilf(scale_y * bounds.h));
if (x < 0 || y < 0 || x + w > g_display.pixel_xres || y + h > g_display.pixel_yres) {
// This won't actually report outside a game, but we can try.
DEBUG_LOG(G3D, "UI scissor out of bounds in %sScreen: %d,%d-%d,%d / %d,%d", screenTag_ ? screenTag_ : "N/A", x, y, w, h, g_display.pixel_xres, g_display.pixel_yres);
DEBUG_LOG(G3D, "UI scissor out of bounds: %d,%d-%d,%d / %d,%d", x, y, w, h, g_display.pixel_xres, g_display.pixel_yres);
if (x < 0) { w += x; x = 0; }
if (y < 0) { h += y; y = 0; }
if (x >= g_display.pixel_xres) { x = g_display.pixel_xres - 1; }
Expand Down
6 changes: 0 additions & 6 deletions Common/UI/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,6 @@ class UIContext {

void setUIAtlas(const std::string &name);

void SetScreenTag(const char *tag) {
screenTag_ = tag;
}

// TODO: Move to private.
const UI::Theme *theme;

Expand All @@ -142,6 +138,4 @@ class UIContext {

std::string lastUIAtlas_;
std::string UIAtlas_ = "ui_atlas.zim";

const char *screenTag_ = nullptr;
};
124 changes: 74 additions & 50 deletions Common/UI/Screen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "Common/UI/UI.h"
#include "Common/UI/View.h"
#include "Common/UI/ViewGroup.h"
#include "Common/UI/IconCache.h"

#include "Common/Log.h"
#include "Common/TimeUtil.h"
Expand Down Expand Up @@ -61,11 +60,10 @@ 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();
}

g_iconCache.FrameUpdate();
}

void ScreenManager::switchToNext() {
Expand Down Expand Up @@ -139,7 +137,6 @@ void ScreenManager::axis(const AxisInput *axes, size_t count) {
void ScreenManager::deviceLost() {
for (auto &iter : stack_)
iter.screen->deviceLost();
g_iconCache.ClearTextures();
}

void ScreenManager::deviceRestored() {
Expand All @@ -159,52 +156,68 @@ void ScreenManager::resized() {

void ScreenManager::render() {
if (!stack_.empty()) {
switch (stack_.back().flags) {
case LAYER_TRANSPARENT:
if (stack_.size() == 1) {
ERROR_LOG(SYSTEM, "Can't have sidemenu over nothing");
break;
} else {
auto last = stack_.end();
auto iter = last;
iter--;
while (iter->flags == LAYER_TRANSPARENT) {
iter--;
}
auto first = iter;
_assert_(iter->screen);

// TODO: Make really sure that this "mismatched" pre/post only happens
// when screens are "compatible" (both are UIScreens, for example).
first->screen->preRender();
while (iter < last) {
iter->screen->render();
iter++;
}
stack_.back().screen->render();
if (overlayScreen_) {
overlayScreen_->render();
}
if (postRenderCb_) {
// Really can't render anything after this! Will crash the screenshot mechanism if we do.
postRenderCb_(getUIContext(), postRenderUserdata_);
}
first->screen->postRender();
break;
// Collect the screens to render
TinySet<Screen *, 6> layers;

// 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;
do {
--iter;
if (!coveringScreen) {
layers.push_back(iter->screen);
} else if (!backgroundScreen && iter->screen->canBeBackground()) {
// There still might be a screen that wants to be background - generally the EmuScreen if present.
layers.push_back(iter->screen);
backgroundScreen = iter->screen;
}
default:
_assert_(stack_.back().screen);
stack_.back().screen->preRender();
stack_.back().screen->render();
if (overlayScreen_) {
overlayScreen_->render();
if (iter->flags != LAYER_TRANSPARENT) {
coveringScreen = iter->screen;
}
if (postRenderCb_) {
// Really can't render anything after this! Will crash the screenshot mechanism if we do.
postRenderCb_(getUIContext(), postRenderUserdata_);
} while (iter != stack_.begin());

// 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;
if (i == (int)layers.size() - 1) {
// Bottom.
mode = ScreenRenderMode::FIRST;
if (layers[i] == backgroundScreen && coveringScreen != layers[i]) {
mode |= ScreenRenderMode::BACKGROUND;
}
if (i == 0) {
mode |= ScreenRenderMode::TOP;
}
} else if (i == 0) {
mode = ScreenRenderMode::TOP;
} else {
mode = ScreenRenderMode::BEHIND;
}
stack_.back().screen->postRender();
break;
layers[i]->render(mode);
}

if (overlayScreen_) {
// It doesn't care about mode.
overlayScreen_->render(ScreenRenderMode::TOP);
}

getUIContext()->Flush();

if (postRenderCb_) {
// Really can't render anything after this! Will crash the screenshot mechanism if we do.
postRenderCb_(getUIContext(), postRenderUserdata_);
}
} else {
ERROR_LOG(SYSTEM, "No current screen!");
Expand Down Expand Up @@ -235,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 @@ -370,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);
}
22 changes: 14 additions & 8 deletions Common/UI/Screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ enum class ScreenFocusChange {
FOCUS_BECAME_TOP, // Became the top screen again
};

enum class ScreenRenderMode {
DEFAULT = 0,
FIRST = 1,
BACKGROUND = 2,
BEHIND = 4,
TOP = 8,
};
ENUM_CLASS_BITOPS(ScreenRenderMode);

class Screen {
public:
Screen() : screenManager_(nullptr) { }
Expand All @@ -56,14 +65,14 @@ class Screen {

virtual void onFinish(DialogResult reason) {}
virtual void update() {}
virtual void preRender() {}
virtual void render() {}
virtual void postRender() {}
virtual void render(ScreenRenderMode mode) {}
virtual void resized() {}
virtual void dialogFinished(const Screen *dialog, DialogResult result) {}
virtual void sendMessage(UIMessage message, const char *value) {}
virtual void deviceLost() {}
virtual void deviceRestored() {}
virtual bool canBeBackground() const { return false; }
virtual bool wantBrightBackground() const { return false; } // special hack for DisplayLayoutScreen.

virtual void focusChanged(ScreenFocusChange focusChange);

Expand All @@ -78,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 @@ -153,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 @@ -171,6 +176,7 @@ class ScreenManager {
const Screen *dialogFinished_ = nullptr;
DialogResult dialogResult_{};

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

struct Layer {
Expand Down
28 changes: 13 additions & 15 deletions Common/UI/UIScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ void UIScreen::deviceRestored() {
root_->DeviceRestored(screenManager()->getDrawContext());
}

void UIScreen::preRender() {
void UIScreen::SetupViewport() {
using namespace Draw;
Draw::DrawContext *draw = screenManager()->getDrawContext();
_dbg_assert_(draw != nullptr);
Expand All @@ -212,28 +212,26 @@ void UIScreen::preRender() {
draw->SetTargetSize(g_display.pixel_xres, g_display.pixel_yres);
}

void UIScreen::postRender() {
screenManager()->getUIContext()->Flush();
}
void UIScreen::render(ScreenRenderMode mode) {
if (mode & ScreenRenderMode::FIRST) {
SetupViewport();
}

void UIScreen::render() {
DoRecreateViews();

if (root_) {
UIContext *uiContext = screenManager()->getUIContext();

uiContext->SetScreenTag(tag());
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
10 changes: 6 additions & 4 deletions Common/UI/UIScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ class UIScreen : public Screen {
~UIScreen();

void update() override;
void preRender() override;
void render() override;
void postRender() override;
void render(ScreenRenderMode mode) override;
void deviceLost() override;
void deviceRestored() override;

Expand All @@ -61,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 @@ -74,6 +71,8 @@ class UIScreen : public Screen {
bool ignoreInput_ = false;

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

bool recreateViews_ = true;
Expand Down Expand Up @@ -111,6 +110,9 @@ class PopupScreen : public UIDialogScreen {

void SetHasDropShadow(bool has) { hasDropShadow_ = has; }

// For the postproc param sliders on DisplayLayoutScreen
bool wantBrightBackground() const override { return !hasDropShadow_; }

protected:
virtual bool FillVertical() const { return false; }
virtual UI::Size PopupWidth() const { return 550; }
Expand Down
4 changes: 2 additions & 2 deletions UI/ControlMappingScreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -713,8 +713,8 @@ void TouchTestScreen::axis(const AxisInput &axis) {
UpdateLogView();
}

void TouchTestScreen::render() {
UIDialogScreenWithGameBackground::render();
void TouchTestScreen::render(ScreenRenderMode mode) {
UIDialogScreenWithGameBackground::render(mode);
UIContext *ui_context = screenManager()->getUIContext();
Bounds bounds = ui_context->GetLayoutBounds();

Expand Down
2 changes: 1 addition & 1 deletion UI/ControlMappingScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ class TouchTestScreen : public UIDialogScreenWithGameBackground {
}

void touch(const TouchInput &touch) override;
void render() override;
void render(ScreenRenderMode mode) override;

bool key(const KeyInput &key) override;
void axis(const AxisInput &axis) override;
Expand Down
Loading