mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-02 12:32:03 +01:00
iOS: Show the game on an AirPlay TV, with the controls on the phone
An external display (like an Apple TV over AirPlay) becomes a Game output, when the backend is Metal. The game is shown there full screen, and the phone shows the touch controls with "Playing on TV" in place of the game. The menus stay on the phone. With other backends, iOS keeps mirroring. Up to iOS 26 the external display scene comes from the Info.plist role. iOS 27 ignores that, and only offers the scene to apps that register a scene accessory for it, so we do that too. The registration is withdrawn when the view controller shuts down, so it follows a backend change, and a restart now goes to the app's scene rather than the first one. An Apple TV 4K only offers 3840x2160 over AirPlay, so the stream stays 4K, but we render at 1920x1080 and let the layer scale it up. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
d491fc90cf
commit
7bd4b13baa
11 files changed
+261
-10
No files matched your search
+16
-2
@@ -1577,6 +1577,16 @@ ScreenRenderRole EmuScreen::renderRole(bool isTop) const {
|
||||
return role;
|
||||
}
|
||||
|
||||
// In place of the game, while it's on another output.
|
||||
void EmuScreen::drawGameOnOutputMessage() {
|
||||
UIContext &dc = *screenManager()->getUIContext();
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
const Bounds &bounds = dc.GetBounds();
|
||||
dc.Begin();
|
||||
dc.DrawText(di->T("Playing on TV"), bounds.centerX(), bounds.centerY(), 0xFF505050, ALIGN_CENTER);
|
||||
dc.Flush();
|
||||
}
|
||||
|
||||
void EmuScreen::darken() {
|
||||
if (screenManager()->topScreen()->wantBrightBackground()) {
|
||||
return;
|
||||
@@ -1714,7 +1724,9 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
|
||||
Viewport viewport{0.0f, 0.0f, (float)g_display.pixel_xres, (float)g_display.pixel_yres, 0.0f, 1.0f};
|
||||
|
||||
if (!skipBufferEffects_ && !ShouldRunEmulation(mode)) {
|
||||
if (gpu && !gameOnOutput_) {
|
||||
if (gameOnOutput_) {
|
||||
drawGameOnOutputMessage();
|
||||
} else if (gpu) {
|
||||
gpu->CopyDisplayToOutput(displayLayoutConfig);
|
||||
}
|
||||
draw->SetViewport(viewport);
|
||||
@@ -1747,7 +1759,9 @@ ScreenRenderFlags EmuScreen::render(ScreenRenderMode mode) {
|
||||
const bool skipBufferEffects = skipBufferEffects_;
|
||||
|
||||
// Gotta copy the output at some point. Also this is where we take the screenshot if needed.
|
||||
if (gpu && !gameOnOutput_) {
|
||||
if (gameOnOutput_) {
|
||||
drawGameOnOutputMessage();
|
||||
} else if (gpu) {
|
||||
gpu->CopyDisplayToOutput(displayLayoutConfig);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user