forked from unom/punktfunk
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea5afbaa8c | ||
|
|
832a5ffd8d | ||
|
|
76c677a8f8 | ||
|
|
7cb70bf6ea | ||
|
|
b6b3c10cb5 | ||
|
|
d669064dc0 | ||
|
|
d4ad8be6bf | ||
|
|
1b28a7f7f1 |
+21
-10
@@ -676,20 +676,23 @@ jobs:
|
||||
# Skipped on PRs (cost); runs on main pushes + manual dispatch. Needs the build/test job green
|
||||
# first, and is a separate job so a capture hiccup can never red the core signal.
|
||||
#
|
||||
# Scope = the two REQUIRED iOS sizes (iPhone 6.9" + iPad 13"), captured on the Simulator
|
||||
# (`simctl io screenshot`, no Screen Recording grant needed). macOS and tvOS are deliberately
|
||||
# NOT in CI: the self-hosted runner is headless (no window-server session), so the mac window
|
||||
# capture can't run there; tvOS needs the Tier-3 build-std slice. Generate those two locally on
|
||||
# a GUI Mac with `clients/apple/tools/screenshots.sh macos tvos`.
|
||||
# Scope = the two REQUIRED iOS sizes (iPhone 6.9" + iPad 13") + Apple TV (1920×1080), captured
|
||||
# on the Simulator (`simctl io screenshot`, no Screen Recording grant needed). The tvOS slice is
|
||||
# Tier-3 (nightly -Zbuild-std, same as the distribute job — slow cold, cached on the self-hosted
|
||||
# runner). The tvOS scene list is explicit: the gamepad-console scenes are iOS/macOS-only, and an
|
||||
# unknown scene name falls back to a NORMAL app launch — the capture would silently be of the
|
||||
# real empty app. macOS stays deliberately NOT in CI: the runner is headless (no window-server
|
||||
# session), so the mac window capture can't run there — generate it locally on a GUI Mac with
|
||||
# `clients/apple/tools/screenshots.sh macos`.
|
||||
screenshots:
|
||||
needs: swift
|
||||
if: gitea.event_name != 'pull_request'
|
||||
runs-on: macos-arm64
|
||||
timeout-minutes: 75
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Rust toolchain + iOS Simulator targets
|
||||
- name: Rust toolchain + iOS Simulator targets (+ nightly for the tvOS slices)
|
||||
run: |
|
||||
if ! command -v rustup >/dev/null && [ ! -x "$HOME/.cargo/bin/rustup" ]; then
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
|
||||
@@ -699,6 +702,10 @@ jobs:
|
||||
dirname "$RUSTUP" >> "$GITHUB_PATH"
|
||||
"$RUSTUP" target add aarch64-apple-darwin x86_64-apple-darwin \
|
||||
aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
|
||||
# tvOS targets are tier-3 (no prebuilt std) — build-xcframework.sh compiles them with
|
||||
# nightly + -Zbuild-std, so ensure nightly + rust-src are present (see the swift job).
|
||||
"$RUSTUP" toolchain install nightly --profile minimal
|
||||
"$RUSTUP" component add rust-src --toolchain nightly
|
||||
|
||||
# Shared compile cache. The script handles the macOS side (user-prefix install +
|
||||
# GITHUB_PATH, bsdtar globbing) — see scripts/ci/ensure-sccache.sh.
|
||||
@@ -735,10 +742,10 @@ jobs:
|
||||
-mtime +7 -exec rm -rf {} + 2>/dev/null || true
|
||||
fi
|
||||
|
||||
- name: Build PunktfunkCore.xcframework (mac + iOS slices)
|
||||
run: BUILD_IOS=1 bash scripts/build-xcframework.sh
|
||||
- name: Build PunktfunkCore.xcframework (mac + iOS + tvOS slices)
|
||||
run: BUILD_IOS=1 BUILD_TVOS=1 bash scripts/build-xcframework.sh
|
||||
|
||||
- name: Capture screenshots (iPhone 6.9" + iPad 13"; auto-creates the Simulators)
|
||||
- name: Capture screenshots (iPhone 6.9" + iPad 13" + Apple TV; auto-creates the Simulators)
|
||||
working-directory: clients/apple
|
||||
env:
|
||||
SETTLE: "8" # Simulators settle slower than a local run
|
||||
@@ -746,6 +753,10 @@ jobs:
|
||||
# Independent invocations: one platform failing skips it, not the other.
|
||||
bash tools/screenshots.sh ios || echo "::warning::iOS (iPhone 6.9\") screenshots skipped"
|
||||
bash tools/screenshots.sh ipad || echo "::warning::iPad 13\" screenshots skipped"
|
||||
# tvOS shoots only the scenes that exist there — the 06–09 gamepad-console scenes are
|
||||
# compiled out on tvOS (native focus engine), and an unknown name = a normal app launch.
|
||||
SCENES="01-stream 02-hosts 05-settings 03-pair" \
|
||||
bash tools/screenshots.sh tvos || echo "::warning::Apple TV screenshots skipped"
|
||||
echo "Produced:"; ls -la screenshots || true
|
||||
|
||||
- name: Shut the Simulators down (leaked booted sims once piled up 846 deep)
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ with the version table of the release you are moving to, then read **Breaking ch
|
||||
|
||||
## v0.28.1
|
||||
|
||||
50 commits since v0.28.0.
|
||||
60 commits since v0.28.0.
|
||||
|
||||
A patch release in the strict sense: **nothing on the wire, in the C ABI, in the driver protocol or
|
||||
in the plugin contract moves.** Every host, client, driver and plugin built against v0.28.0 keeps
|
||||
|
||||
@@ -51,6 +51,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libxdamage-dev libxcomposite-dev libxrender-dev libxext-dev libxxf86vm-dev \
|
||||
libxtst-dev libx11-dev libxres-dev libxmu-dev libxcursor-dev libxi-dev \
|
||||
libxfixes-dev libxkbcommon-dev libxkbcommon-x11-dev libcap-dev libdrm-dev \
|
||||
# x11-xcb is needed by the VULKAN WSI LAYER (layer/meson.build), not by the compositor — so it
|
||||
# was not missed until v0.28.1 started building the layer beside the binary. Debian is the only
|
||||
# channel that needs it named: Arch's libx11 and Fedora's libX11-devel both carry x11-xcb.pc
|
||||
# themselves, while Debian splits it into its own -dev package.
|
||||
libx11-xcb-dev \
|
||||
libinput-dev libudev-dev libpipewire-0.3-dev libseat-dev libsdl2-dev \
|
||||
libluajit-5.1-dev libavif-dev libdecor-0-dev hwdata libglm-dev libbenchmark-dev \
|
||||
libvulkan-dev libxcb1-dev libxcb-composite0-dev libxcb-xfixes0-dev libxcb-res0-dev \
|
||||
@@ -66,3 +71,13 @@ RUN set -eux; \
|
||||
pkg-config --atleast-version=1.23.1 wayland-server \
|
||||
|| { echo "wayland-server $have < 1.23.1 — the vendored wlroots will not configure" >&2; exit 1; }; \
|
||||
echo "wayland-server $have — OK"
|
||||
|
||||
# The layer's own floor, asserted for the same reason: a missing x11-xcb does not fail the
|
||||
# COMPOSITOR build, it fails `layer/meson.build` — and the layer is the only route to an HDR10
|
||||
# swapchain for a nested game, so losing it silently ships a package that looks healthy and denies
|
||||
# every game HDR. This is exactly how v0.28.1's deb leg broke, one release after the layer was
|
||||
# added; assert it here so the next dep the layer grows fails at image build, not mid-release.
|
||||
RUN set -eux; \
|
||||
pkg-config --exists x11-xcb \
|
||||
|| { echo "x11-xcb absent — the Vulkan WSI layer will not configure (need libx11-xcb-dev)" >&2; exit 1; }; \
|
||||
echo "x11-xcb $(pkg-config --modversion x11-xcb) — OK"
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package io.unom.punktfunk.screenshots
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onRoot
|
||||
import com.github.takahirom.roborazzi.captureRoboImage
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.annotation.GraphicsMode
|
||||
|
||||
/**
|
||||
* The same Roborazzi harness as ScreenshotTest, at Android TV geometry: 960×540dp in the
|
||||
* `television` UI mode at xhdpi (2.0×) = 1920×1080 px — the Play Store's 16:9 TV screenshot size,
|
||||
* captured 1:1 with no resampling. Only the screens that exist on a TV are shot here: the
|
||||
* gamepad-console shell (what LEANBACK_LAUNCHER opens into) and the in-stream view. Files are
|
||||
* prefixed `tv-` so the artifact separates the form factors.
|
||||
*/
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@GraphicsMode(GraphicsMode.Mode.NATIVE)
|
||||
@Config(sdk = [36], qualifiers = "w960dp-h540dp-television-xhdpi")
|
||||
class TvScreenshotTest {
|
||||
@get:Rule
|
||||
val compose = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
private val out = "build/outputs/roborazzi"
|
||||
|
||||
private fun shootRoot(name: String, content: @androidx.compose.runtime.Composable () -> Unit) {
|
||||
compose.mainClock.autoAdvance = false
|
||||
compose.setContent { ShotTheme(content) }
|
||||
compose.mainClock.advanceTimeBy(800)
|
||||
compose.onRoot().captureRoboImage("$out/tv-$name.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun stream() = shootRoot("stream") { StreamScene(io.unom.punktfunk.StatsVerbosity.COMPACT) }
|
||||
|
||||
@Test
|
||||
fun streamDetailed() =
|
||||
shootRoot("stream-detailed") { StreamScene(io.unom.punktfunk.StatsVerbosity.DETAILED) }
|
||||
|
||||
@Test
|
||||
fun consoleHome() = shootRoot("console-home") { ConsoleHomeScene() }
|
||||
|
||||
@Test
|
||||
fun consoleSettings() = shootRoot("console-settings") { ConsoleSettingsScene() }
|
||||
|
||||
@Test
|
||||
fun consoleControllers() = shootRoot("console-controllers") { ConsoleControllersScene() }
|
||||
|
||||
@Test
|
||||
fun connectingConsole() = shootRoot("connecting-console") { ConnectConsoleScene() }
|
||||
}
|
||||
+10
-11
@@ -1,20 +1,18 @@
|
||||
Wire-compatible with 0.28.0 — everything you have already paired keeps working, and you can update one side at a time. Nothing here changes how a host and a client agree on what to send each other, so an old client on a new host, or the other way round, streams exactly as it does today.
|
||||
|
||||
This is a fix release, and most of it is about things that were wrong in ways nothing announced. On Windows, your Steam library could stay completely empty after the last update, and a Punktfunk host sitting idle — nothing connected, nothing streaming — could wreck the frame rate of a game you were playing on that same machine. An Android TV box could be silent for a whole session; a Steam Deck's Punktfunk home would not open; games could not reach high dynamic range (HDR) at all on Linux machines running our own compositor, while the Steam interface in front of them glared; and an Apple TV was being pushed into HDR mode by streams that were not HDR at all, lifting blacks to grey.
|
||||
This is a fix release, and most of it is about things that were wrong in ways nothing announced. On Windows, your Steam library could stay completely empty after the last update, and a Punktfunk host sitting idle — nothing connected, nothing streaming — could wreck the frame rate of a game you were playing on that same machine. Streaming from a Mac with the microphone on cut the sound and froze the controls every couple of seconds. An Android TV box could be silent for a whole session; a Steam Deck's Punktfunk home would not open; games could not reach high dynamic range (HDR) at all on Linux machines running our own compositor, while the Steam interface in front of them glared; and an Apple TV was being pushed into HDR mode by streams that were not HDR at all, lifting blacks to grey.
|
||||
|
||||
Several of these came from people who reported them carefully enough to be found. One of them, the crash that lost your game on reconnect, was tracked down, fixed and proven on his own hardware by **luxus** — that fix is in this release as he wrote it.
|
||||
|
||||
## TL;DR
|
||||
|
||||
- **On Windows, your Steam games went missing after updating to 0.28.0.** The Steam add-on could publish nothing, because Steam keeps its artwork in Program Files and the host was not allowed to read it. Fixed — and one unreadable cover no longer throws away the whole library with it.
|
||||
- **An idle Punktfunk host could ruin a game you were playing on that same machine**, down to 2–5 frames per second at worst, with nothing connected and no stream running. Two separate causes, both fixed, both reported from Helldivers 2.
|
||||
- **No sound at all on some Android TV boxes** — an NVIDIA Shield in particular — is fixed, and the app now recovers when your TV or receiver changes mode mid-stream instead of staying silent for the rest of the session.
|
||||
- **The Punktfunk home would not open on a Steam Deck after updating to 0.28.0.** That is fixed, along with the missing statistics overlay in streams that came from the same fault.
|
||||
- **Games can finally use high dynamic range on Linux hosts running Punktfunk's compositor.** They could not before, on essentially any machine, and nothing said so.
|
||||
- **HDR streams looked washed out while the Steam interface looked glaring** — one brightness mistake causing both, now corrected.
|
||||
- **On an Apple TV, ordinary streams were switching the television into HDR** and lifting blacks to grey — and those same streams were being drawn with no colour information at all.
|
||||
- **If your Apple device's statistics overlay ever showed impossibly good numbers, that is why** — three separate faults made those figures unreliable. Old measurements are worth re-taking.
|
||||
- **Streaming your desktop with the mouse pointer forwarded failed outright on Hyprland and Sway**, giving you a black picture. It affected every current install, not only old ones.
|
||||
- **On Windows, your Steam games went missing after 0.28.0** — the add-on could publish nothing, because Steam keeps its artwork somewhere the host was not allowed to read.
|
||||
- **An idle host could ruin a game running on that same Windows machine**, down to 2–5 frames per second, with nothing connected and no stream running.
|
||||
- **Streaming from a Mac with your microphone on cut the sound and froze your controls every couple of seconds** — and turning the mic off was the only way round it.
|
||||
- **No sound at all on some Android TV boxes**, an NVIDIA Shield in particular — and sound now returns by itself when your TV changes mode mid-stream.
|
||||
- **The Punktfunk home would not open on a Steam Deck after 0.28.0**, and streams elsewhere lost their statistics overlay to the same fault.
|
||||
- **Streaming your desktop with the pointer forwarded gave a black picture on Hyprland and Sway** — every current install, not just old ones.
|
||||
- **High dynamic range was broken in both directions on Linux hosts:** games could not reach it at all, and everything else was mapped a stop too bright. Both fixed.
|
||||
|
||||
## Before you update
|
||||
|
||||
@@ -38,6 +36,7 @@ Several of these came from people who reported them carefully enough to be found
|
||||
- **On Windows, the Steam add-on synced nothing and your grid stayed empty.** Steam installs to Program Files and keeps its artwork there, and the host's list of places it is allowed to read art from covered the launchers that install per-user — but not Steam. Every cover the add-on offered was rejected, and because one bad cover failed the whole submission, that meant every Steam game rather than one thumbnail. Both halves are fixed: Steam's own install locations are now allowed (including on a second drive), and a cover that cannot be served is dropped so the rest of your library still arrives. This only affected Windows — every Steam layout on Linux was already covered — and it arrived with 0.28.0, when the built-in Steam scanner was replaced by the add-on.
|
||||
- **A Punktfunk host that was doing nothing at all could wreck a game running on the same Windows machine** — 2–5 frames per second at worst, with no client connected and no stream ever started. Two independent causes, both from the same set of reports: the host presents a controller speaker that looks exactly like a real DualSense's, and a game that finds it engages its DualSense audio path against a device nothing is feeding; and the host was claiming your default microphone permanently, so any game holding an open voice input stalled on a virtual mic that only runs during a stream. The controller speaker is now hidden except while a controller is actually attached, and your microphone is only borrowed for the length of a stream. Machines already stuck repair themselves on the next start.
|
||||
- **Streaming your desktop with the pointer forwarded gave a black picture on Hyprland and Sway.** Punktfunk asked the desktop's screen-sharing service for the pointer in a form neither compositor offers, and the request was refused before it ever reached them — so the whole capture failed rather than losing just the pointer. It now asks what is actually available and takes the best on offer. Measured against fully up-to-date Hyprland and portal versions: this was every current install, and updating them would not have helped. You will now see a single pointer drawn by the host instead of your client drawing its own.
|
||||
- **Streaming from a Mac with the microphone on cut the audio and froze the controls on a two-and-a-half second beat**, while the picture carried on untouched. Some microphones — a multi-channel audio interface set as your Mac's input, for instance — cannot run the echo-cancelling mode Punktfunk asks for. Each failed attempt knocked out the working audio path, and the knock-out was itself the signal that triggered the next attempt, so it went round forever. Your controls froze on the same beat because that rebuild happened on the part of the app that also sends your keyboard and mouse. All three links in that loop are broken now, and audio setup no longer happens where your input lives — so even a genuine change of sound device no longer costs you control of the stream. Until now the only workaround was turning the client's microphone off.
|
||||
- **An Android TV box could have no audio for an entire session.** Reported on an NVIDIA Shield with a host and settings that played fine everywhere else, and video unaffected. The app asked Android for an audio device and then trusted the answer: a device that accepted the request but played nothing was never noticed, a device that refused to start disabled sound for the rest of the session, and — most common on a television — a device that went away during an HDMI mode change was never reopened. It now proves that sound is actually being taken before it accepts a device, and reopens automatically when your TV or receiver changes mode. TV boxes now use the ordinary shared audio path rather than the exclusive low-latency one, which was never buying them the latency it cost.
|
||||
- **The Punktfunk home would not open on a Steam Deck after updating to 0.28.0.** Both the Decky button and the library shortcut failed. The same fault silently removed the statistics and capture overlays inside streams on other machines. It came from a graphics library sizing itself to what the machine's graphics driver supported rather than to what Punktfunk had asked for, which only became a problem once drivers moved ahead of us.
|
||||
- **Games could not use high dynamic range on Linux hosts running Punktfunk's compositor** — on essentially every machine, not a rare configuration. Reaching HDR requires a small graphics component that has to match the compositor exactly, and we shipped the compositor without it, leaving the host guessing whether the one your distribution provided was compatible. Because we build our own compositor, that guess was almost always wrong in the direction of switching HDR off. We now ship the matching component ourselves, on every Linux packaging channel.
|
||||
@@ -61,4 +60,4 @@ Most of the rest of this release exists because people took the trouble to repor
|
||||
|
||||
Protocol, ABI, driver and embedder detail — including the version table and the (empty) breaking-changes list — is in [CHANGELOG.md](https://git.unom.io/unom/punktfunk/src/tag/v0.28.1/CHANGELOG.md).
|
||||
|
||||
Nothing breaks: the wire protocol, the C ABI, the virtual-display driver protocol and the plugin contract are all unchanged from v0.28.0. Two things are worth reading if they apply to you: every Linux packaging channel now ships a second gamescope artifact and a package without it fails to build rather than degrading quietly, and Android's `nativeStartAudio` takes one more argument.
|
||||
Nothing breaks: the wire protocol, the C ABI, the virtual-display driver protocol and the plugin contract are all unchanged from v0.28.0. Three things are worth reading if they apply to you: every Linux packaging channel now ships a second gamescope artifact and a package without it fails to build rather than degrading quietly, Android's `nativeStartAudio` takes one more argument, and `SessionAudio.start()` is now asynchronous on macOS as it already was on iOS and tvOS — playback is live shortly after the call rather than on return.
|
||||
|
||||
Reference in New Issue
Block a user