From c3801699ebdd8a11a96f09599fa58c14877875b3 Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:22:51 +0000 Subject: [PATCH 01/10] fix(ci): adapt builds to Blacksmith runners --- .github/workflows/auto-build.yml | 19 ++++++++++++++++- .github/workflows/qt-ci.yml | 17 ++++++++++++++- .github/workflows/qt-release-candidate.yml | 21 +++++++++++++++---- .../src/macos/presentation.rs | 4 +++- .../src/macos/video.rs | 4 ++-- .../src/embedded_input.rs | 4 +++- .../src/macos_backend.rs | 2 +- opennow-qt/tests/tst_singleinstance.cpp | 3 ++- .../scripts/build-native-streamer.mjs | 11 +++++++--- 9 files changed, 70 insertions(+), 15 deletions(-) diff --git a/.github/workflows/auto-build.yml b/.github/workflows/auto-build.yml index 9db870f6f..8d7a1b4ed 100644 --- a/.github/workflows/auto-build.yml +++ b/.github/workflows/auto-build.yml @@ -148,6 +148,7 @@ jobs: sudo apt-get install -y \ cmake \ libasound2-dev \ + libdbus-1-dev \ libdrm-dev \ libpulse-dev \ libva-dev \ @@ -165,7 +166,9 @@ jobs: - name: Install Linux ARM64 cross compiler if: matrix.label == 'linux-arm64' - run: sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + run: | + sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-g++" >> "$GITHUB_ENV" - name: Install Windows ARM64 compiler if: matrix.native_target == 'aarch64-pc-windows-msvc' @@ -197,6 +200,20 @@ jobs: with: arch: amd64_arm64 + - name: Install Windows LLVM + if: runner.os == 'Windows' + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + choco install llvm -y --no-progress + $llvmBin = Join-Path $env:ProgramFiles "LLVM\bin" + if (-not (Test-Path (Join-Path $llvmBin "clang.exe")) -or + -not (Test-Path (Join-Path $llvmBin "libclang.dll"))) { + throw "LLVM installation is missing libclang.dll" + } + $llvmBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + "LIBCLANG_PATH=$llvmBin" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - name: Pin CMake for bundled SDL2 if: runner.os == 'macOS' shell: bash diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index 1d1998c1a..ebb24afc0 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -129,6 +129,20 @@ jobs: with: arch: amd64_arm64 + - name: Install Windows LLVM + if: runner.os == 'Windows' + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + choco install llvm -y --no-progress + $llvmBin = Join-Path $env:ProgramFiles "LLVM\bin" + if (-not (Test-Path (Join-Path $llvmBin "clang.exe")) -or + -not (Test-Path (Join-Path $llvmBin "libclang.dll"))) { + throw "LLVM installation is missing libclang.dll" + } + $llvmBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + "LIBCLANG_PATH=$llvmBin" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - name: Install Windows host Qt tools if: matrix.label == 'windows-arm64' uses: jurplel/install-qt-action@v4 @@ -164,6 +178,7 @@ jobs: sudo apt-get update sudo apt-get install -y \ libasound2-dev \ + libdbus-1-dev \ libdrm-dev \ libpulse-dev \ libsecret-1-dev \ @@ -246,7 +261,7 @@ jobs: fi cmake -S opennow-qt -B build/opennow-qt-release \ -DCMAKE_BUILD_TYPE=Release \ - -DSDL3_DIR="$RUNNER_TEMP/SDL-install/lib/cmake/SDL3" \ + -DCMAKE_PREFIX_PATH="$RUNNER_TEMP/SDL-install" \ "${OPENNOW_CMAKE_ARGS[@]}" - name: Build Qt release diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index c157bc706..b6d888708 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -109,7 +109,7 @@ jobs: shell: bash run: | sudo apt-get update - sudo apt-get install -y libasound2-dev libdrm-dev libpulse-dev libsecret-1-dev \ + sudo apt-get install -y libasound2-dev libdbus-1-dev libdrm-dev libpulse-dev libsecret-1-dev \ libva-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxi-dev \ libxrandr-dev libxrender-dev libxss-dev make nasm pkg-config @@ -129,7 +129,7 @@ jobs: UPDATE_PUBLIC_KEY: ${{ inputs.update_public_key }} run: | cmake -S opennow-qt -B build/qt-release -DCMAKE_BUILD_TYPE=Release \ - -DSDL3_DIR="$RUNNER_TEMP/SDL-install/lib/cmake/SDL3" \ + -DCMAKE_PREFIX_PATH="$RUNNER_TEMP/SDL-install" \ -DOPENNOW_BUILD_VERSION="$RELEASE_VERSION" \ -DOPENNOW_UPDATE_ED25519_PUBLIC_KEY="$UPDATE_PUBLIC_KEY" cmake --build build/qt-release --config Release --parallel @@ -232,6 +232,19 @@ jobs: with: arch: ${{ matrix.arch == 'arm64' && 'amd64_arm64' || 'x64' }} + - name: Install LLVM + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + choco install llvm -y --no-progress + $llvmBin = Join-Path $env:ProgramFiles "LLVM\bin" + if (-not (Test-Path (Join-Path $llvmBin "clang.exe")) -or + -not (Test-Path (Join-Path $llvmBin "libclang.dll"))) { + throw "LLVM installation is missing libclang.dll" + } + $llvmBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + "LIBCLANG_PATH=$llvmBin" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + - name: Install WiX Toolset shell: pwsh run: | @@ -290,7 +303,7 @@ jobs: if [[ -n "${{ matrix.rust_target }}" ]]; then args+=("-DOPENNOW_RUST_TARGET=${{ matrix.rust_target }}"); fi if [[ -n "${OPENNOW_QT_HOST_PATH:-}" ]]; then args+=("-DQT_HOST_PATH=${OPENNOW_QT_HOST_PATH}"); fi cmake -S opennow-qt -B build/qt-release -DCMAKE_BUILD_TYPE=Release \ - -DSDL3_DIR="$RUNNER_TEMP/SDL-install/lib/cmake/SDL3" \ + -DCMAKE_PREFIX_PATH="$RUNNER_TEMP/SDL-install" \ -DOPENNOW_BUILD_VERSION="$RELEASE_VERSION" \ -DOPENNOW_UPDATE_ED25519_PUBLIC_KEY="$UPDATE_PUBLIC_KEY" "${args[@]}" cmake --build build/qt-release --config Release --parallel @@ -418,7 +431,7 @@ jobs: cmake -S opennow-qt -B build/qt-release -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_OSX_ARCHITECTURES=${{ matrix.cmake_arch }} \ -DOPENNOW_RUST_TARGET=${{ matrix.rust_target }} \ - -DSDL3_DIR="$RUNNER_TEMP/SDL-install/lib/cmake/SDL3" \ + -DCMAKE_PREFIX_PATH="$RUNNER_TEMP/SDL-install" \ -DOPENNOW_BUILD_VERSION="$RELEASE_VERSION" \ -DOPENNOW_UPDATE_ED25519_PUBLIC_KEY="$UPDATE_PUBLIC_KEY" cmake --build build/qt-release --config Release --parallel diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs index 90d896ea1..f184903c0 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs @@ -374,6 +374,8 @@ struct PendingFrame { _chroma_texture: Retained>, } +unsafe impl Send for PendingFrame {} + struct MetalPresenter { layer: Retained, device: Retained>, @@ -656,7 +658,7 @@ impl MetalPresenter { // SAFETY: `presented_handler` is a valid Objective-C block. Metal copies the escaping // handler and invokes it after the drawable reaches scanout. unsafe { - drawable_as_base.addPresentedHandler(RcBlock::as_ptr(&presented_handler)); + drawable_as_base.addPresentedHandler(&presented_handler); } command_buffer.presentDrawable(drawable_as_base); command_buffer.commit(); diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs index 1fc44f0d5..e6dd3402b 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs @@ -162,7 +162,7 @@ impl VideoDecoder { let hardware_decoder_key = unsafe { kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder }; let mut destination_entries = vec![ - (cf_ptr(metal_compatibility_key), cf_ptr(true_value)), + (cf_ptr(metal_compatibility_key), cf_ptr(&*true_value)), ( cf_ptr(io_surface_properties_key), cf_ptr(&*empty_properties), @@ -171,7 +171,7 @@ impl VideoDecoder { destination_entries.insert(0, (cf_ptr(pixel_format_key), cf_ptr(&*pixel_format_number))); let destination_attributes = make_dictionary(&destination_entries)?; let decoder_specification = - make_dictionary(&[(cf_ptr(hardware_decoder_key), cf_ptr(true_value))])?; + make_dictionary(&[(cf_ptr(hardware_decoder_key), cf_ptr(&*true_value))])?; let mut session_ptr = ptr::null_mut(); let status = unsafe { diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs index d89a3f9c1..20b5aad76 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs @@ -1,5 +1,7 @@ +use std::sync::Arc; +#[cfg(any(target_os = "linux", target_os = "windows"))] +use std::sync::Mutex; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex}; use crate::{CapturedInput, CapturedInputQueue}; diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs index 1302d2b17..c77e62b57 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs @@ -331,7 +331,7 @@ impl MacExternalSurface { eprintln!( "External macOS stream window ready (native keyboard/mouse capture: {capture_input})" ); - let mut input_capture = SdlInputCapture::new(capture_input, false, stream.shortcuts); + let mut input_capture = SdlInputCapture::new(capture_input, false, false, stream.shortcuts); input_capture.enable_gamepads(&sdl); Ok(Self { input_capture, diff --git a/opennow-qt/tests/tst_singleinstance.cpp b/opennow-qt/tests/tst_singleinstance.cpp index 37f0c3159..91acadfd5 100644 --- a/opennow-qt/tests/tst_singleinstance.cpp +++ b/opennow-qt/tests/tst_singleinstance.cpp @@ -19,7 +19,7 @@ private slots: std::atomic_bool secondaryCompleted = false; std::atomic_bool secondaryBecamePrimary = true; - std::jthread secondary([&] { + std::thread secondary([&] { SingleInstance instance; secondaryBecamePrimary = instance.acquire( {QStringLiteral("opennow"), QStringLiteral("opennow://launch/99")}); @@ -27,6 +27,7 @@ private slots: }); QTRY_COMPARE_WITH_TIMEOUT(activation.size(), 1, 2'000); QTRY_VERIFY_WITH_TIMEOUT(secondaryCompleted.load(), 2'000); + secondary.join(); QVERIFY(!secondaryBecamePrimary.load()); const auto arguments = activation.first().first().toStringList(); QCOMPARE(arguments.value(1), QStringLiteral("opennow://launch/99")); diff --git a/opennow-stable/scripts/build-native-streamer.mjs b/opennow-stable/scripts/build-native-streamer.mjs index 7564391f3..37a2b637e 100644 --- a/opennow-stable/scripts/build-native-streamer.mjs +++ b/opennow-stable/scripts/build-native-streamer.mjs @@ -204,13 +204,18 @@ if (!nativeTarget || platformKey === hostPlatformKey) { .map((line) => JSON.parse(line)); const ready = messages.find((message) => message.id === "verify" && message.type === "ready"); const stopped = messages.find((message) => message.id === "stop" && message.type === "ok"); - const started = messages.find((message) => message.id === "verify-start" && message.type === "ok"); - const capabilitiesComplete = ready?.capabilities?.supportsOfferAnswer === true + const startRejected = messages.find((message) => + message.id === "verify-start" + && message.type === "error" + && message.code === "nvst-handoff-required"); + const capabilitiesComplete = ready?.capabilities?.protocolVersion === nativeProtocolVersion + && ready.capabilities.supportsOwnedNvstNegotiation === true + && ready.capabilities.supportsInput === true && ready.capabilities.supportsVideoDecode === true && ready.capabilities.supportsVideoPresent === true && ready.capabilities.supportsAudioDecode === true && ready.capabilities.supportsAudioOutput === true; - if (!capabilitiesComplete || !started || !stopped) { + if (!capabilitiesComplete || !startRejected || !stopped) { throw new Error(`Native streamer verification returned an incomplete handshake: ${verify.stdout}`); } } From 0b4c980b9adec7f3ceae1183d63986cd435d109f Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:41:15 +0000 Subject: [PATCH 02/10] fix(ci): resolve cross-platform runner failures --- .../ensure-windows-media-foundation.ps1 | 23 +++++++++++++++++ .github/workflows/auto-build.yml | 7 ++++++ .github/workflows/qt-ci.yml | 25 +++++++++++++++++-- .github/workflows/qt-release-candidate.yml | 8 ++++-- .../src/macos/presentation.rs | 2 +- .../src/windows/embedded.rs | 1 + .../src/windows/mod.rs | 12 +++++++++ .../crates/opennow-streamer/build.rs | 11 ++++++-- opennow-qt/CMakeLists.txt | 2 ++ 9 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 .github/scripts/ensure-windows-media-foundation.ps1 diff --git a/.github/scripts/ensure-windows-media-foundation.ps1 b/.github/scripts/ensure-windows-media-foundation.ps1 new file mode 100644 index 000000000..4174e3f81 --- /dev/null +++ b/.github/scripts/ensure-windows-media-foundation.ps1 @@ -0,0 +1,23 @@ +$ErrorActionPreference = "Stop" + +$feature = Get-WindowsFeature -Name Server-Media-Foundation +if (-not $feature) { + throw "The Server-Media-Foundation feature is unavailable on this runner." +} + +if (-not $feature.Installed) { + $result = Install-WindowsFeature -Name Server-Media-Foundation + $result | Format-List Success, RestartNeeded, ExitCode, FeatureResult + if (-not $result.Success) { + throw "Installing Server-Media-Foundation failed with exit code $($result.ExitCode)." + } + if ($result.RestartNeeded.ToString() -ne "No") { + throw "Installing Server-Media-Foundation requires a runner restart." + } +} + +$feature = Get-WindowsFeature -Name Server-Media-Foundation +$dll = Join-Path $env:SystemRoot "System32\mfplat.dll" +if (-not $feature.Installed -or -not (Test-Path $dll)) { + throw "Windows Media Foundation is unavailable (feature=$($feature.InstallState), mfplat=$((Test-Path $dll)))." +} diff --git a/.github/workflows/auto-build.yml b/.github/workflows/auto-build.yml index 8d7a1b4ed..9748b9823 100644 --- a/.github/workflows/auto-build.yml +++ b/.github/workflows/auto-build.yml @@ -129,6 +129,12 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Enable Windows Media Foundation + if: runner.os == 'Windows' + shell: pwsh + working-directory: . + run: .github/scripts/ensure-windows-media-foundation.ps1 + - name: Setup Node.js uses: actions/setup-node@v4 with: @@ -242,6 +248,7 @@ jobs: run: npm run build - name: Test and build native streamer v2 + shell: bash env: OPENNOW_NATIVE_STREAMER_TARGET: ${{ matrix.native_target }} OPENNOW_NATIVE_STREAMER_PLATFORM_KEY: ${{ matrix.native_platform_key }} diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index ebb24afc0..13d1eeb03 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -10,6 +10,7 @@ on: - ".github/workflows/qt-ci.yml" - ".github/workflows/qt-release-candidate.yml" - ".github/actionlint.yaml" + - ".github/scripts/ensure-windows-media-foundation.ps1" - "opennow-qt/**" - "native/opennow-core/**" - "native/opennow-streamer/**" @@ -18,6 +19,7 @@ on: - ".github/workflows/qt-ci.yml" - ".github/workflows/qt-release-candidate.yml" - ".github/actionlint.yaml" + - ".github/scripts/ensure-windows-media-foundation.ps1" - "opennow-qt/**" - "native/opennow-core/**" - "native/opennow-streamer/**" @@ -94,6 +96,11 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Enable Windows Media Foundation + if: runner.os == 'Windows' + shell: pwsh + run: .github/scripts/ensure-windows-media-foundation.ps1 + - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: @@ -228,10 +235,24 @@ jobs: if: runner.os == 'Linux' shell: bash run: | + case "$(uname -m)" in + x86_64) + actionlint_arch=amd64 + actionlint_sha256=8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 + ;; + aarch64) + actionlint_arch=arm64 + actionlint_sha256=325e971b6ba9bfa504672e29be93c24981eeb1c07576d730e9f7c8805afff0c6 + ;; + *) + echo "Unsupported actionlint architecture: $(uname -m)" >&2 + exit 1 + ;; + esac curl --fail --location --retry 3 \ - https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_amd64.tar.gz \ + "https://github.com/rhysd/actionlint/releases/download/v1.7.12/actionlint_1.7.12_linux_${actionlint_arch}.tar.gz" \ --output "$RUNNER_TEMP/actionlint.tar.gz" - echo "8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 $RUNNER_TEMP/actionlint.tar.gz" \ + echo "$actionlint_sha256 $RUNNER_TEMP/actionlint.tar.gz" \ | sha256sum --check --strict tar -xzf "$RUNNER_TEMP/actionlint.tar.gz" -C "$RUNNER_TEMP" actionlint "$RUNNER_TEMP/actionlint" -color=false \ diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index b6d888708..578b1c356 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -181,7 +181,7 @@ jobs: set -euo pipefail appimage=$(find build/release-artifacts -maxdepth 1 -type f -name '*.AppImage' -print -quit) "$appimage" --smoke-test --allow-multiple-instances --route home --reduced-motion - (cd build/release-artifacts && sha256sum *.AppImage *.deb > SHA256SUMS) + (cd build/release-artifacts && sha256sum -- *.AppImage *.deb > SHA256SUMS) - uses: actions/upload-artifact@v4 with: @@ -211,6 +211,10 @@ jobs: with: ref: ${{ needs.preflight.outputs.source_sha }} + - name: Enable Windows Media Foundation + shell: pwsh + run: .github/scripts/ensure-windows-media-foundation.ps1 + - uses: dtolnay/rust-toolchain@stable - name: Install ARM64 compiler and Rust target @@ -512,7 +516,7 @@ jobs: shell: bash run: | set -euo pipefail - (cd build/release-artifacts && shasum -a 256 *.dmg *.zip > SHA256SUMS) + (cd build/release-artifacts && shasum -a 256 -- *.dmg *.zip > SHA256SUMS) - name: Remove temporary signing material if: always() diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs index f184903c0..32564c889 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs @@ -658,7 +658,7 @@ impl MetalPresenter { // SAFETY: `presented_handler` is a valid Objective-C block. Metal copies the escaping // handler and invokes it after the drawable reaches scanout. unsafe { - drawable_as_base.addPresentedHandler(&presented_handler); + drawable_as_base.addPresentedHandler(RcBlock::as_ptr(&presented_handler)); } command_buffer.presentDrawable(drawable_as_base); command_buffer.commit(); diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/embedded.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/embedded.rs index 2b9ef2177..d7caffd39 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/embedded.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/embedded.rs @@ -96,6 +96,7 @@ struct EmbeddedMediaRuntime { impl EmbeddedMediaRuntime { fn initialize() -> Result { + super::ensure_media_foundation_available()?; unsafe { let mta_cookie = CoIncrementMTAUsage().map_err(|error| format!("CoIncrementMTAUsage: {error}"))?; diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/mod.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/mod.rs index b1ff52928..3fce3a36c 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/mod.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/mod.rs @@ -12,12 +12,15 @@ use std::sync::{Arc, mpsc}; use std::thread::{self, JoinHandle}; use std::time::{Duration, Instant}; +use ::windows::Win32::Foundation::FreeLibrary; use ::windows::Win32::Media::MediaFoundation::{MF_VERSION, MFSTARTUP_LITE, MFShutdown, MFStartup}; use ::windows::Win32::Media::{TIMERR_NOERROR, timeBeginPeriod, timeEndPeriod}; use ::windows::Win32::System::Com::{COINIT_MULTITHREADED, CoInitializeEx, CoUninitialize}; +use ::windows::Win32::System::LibraryLoader::{LOAD_LIBRARY_SEARCH_SYSTEM32, LoadLibraryExW}; use ::windows::Win32::System::Threading::{ GetCurrentThread, SetThreadPriority, THREAD_PRIORITY_ABOVE_NORMAL, }; +use ::windows::core::w; use crate::{ ADAPTIVE_VIDEO_QUEUE_CAPACITY, BackendConfig, BackendError, BackendEvent, CapabilityProbe, @@ -251,8 +254,17 @@ impl Drop for LowLatencyThreadGuard { struct MediaRuntime; +fn ensure_media_foundation_available() -> Result<(), String> { + unsafe { + let module = LoadLibraryExW(w!("mfplat.dll"), None, LOAD_LIBRARY_SEARCH_SYSTEM32) + .map_err(|error| format!("Media Foundation is unavailable: {error}"))?; + FreeLibrary(module).map_err(|error| format!("FreeLibrary(mfplat.dll): {error}")) + } +} + impl MediaRuntime { fn initialize() -> Result { + ensure_media_foundation_available().map_err(BackendError::Startup)?; unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) .ok() diff --git a/native/opennow-streamer/crates/opennow-streamer/build.rs b/native/opennow-streamer/crates/opennow-streamer/build.rs index bca8c323f..898065cd5 100644 --- a/native/opennow-streamer/crates/opennow-streamer/build.rs +++ b/native/opennow-streamer/crates/opennow-streamer/build.rs @@ -8,10 +8,17 @@ fn main() { && std::env::var_os("CARGO_FEATURE_LINUX_FFMPEG_BUNDLED").is_some() { // OpenH264 is compiled from C++ sources. The production Linux binary - // carries that runtime and GCC's unwinder just like its other native - // media libraries. + // carries that runtime and GCC's unwinder after the native media + // archives that reference them. println!("cargo:rustc-link-lib=static=stdc++"); println!("cargo:rustc-link-lib=static=gcc"); println!("cargo:rustc-link-lib=static=gcc_eh"); + println!("cargo:rustc-link-arg=-Wl,-Bstatic"); + println!("cargo:rustc-link-arg=-lstdc++"); + println!("cargo:rustc-link-arg=-lgcc"); + println!("cargo:rustc-link-arg=-lgcc_eh"); + println!("cargo:rustc-link-arg=-Wl,-Bdynamic"); + println!("cargo:rustc-link-arg=-lm"); + println!("cargo:rustc-link-arg=-lc"); } } diff --git a/opennow-qt/CMakeLists.txt b/opennow-qt/CMakeLists.txt index a74df5cc9..ab0403801 100644 --- a/opennow-qt/CMakeLists.txt +++ b/opennow-qt/CMakeLists.txt @@ -603,6 +603,8 @@ if(BUILD_TESTING) # directory, so deploy the test runtime explicitly and make the runners # depend on it. This keeps a clean build directly runnable by CTest. add_custom_target(opennow-qt-test-runtime ALL + COMMAND ${CMAKE_COMMAND} -E make_directory + "$" COMMAND ${CMAKE_COMMAND} -E copy_if_different "$" "$/" From fc279b61f8f06ac3b9ecd2319a07c1ea0d2f5a47 Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Mon, 31 Aug 2026 17:25:05 +0000 Subject: [PATCH 03/10] fix(ci): clear remaining platform runner failures --- .github/workflows/qt-ci.yml | 1 + .github/workflows/qt-release-candidate.yml | 2 +- .../src/macos/embedded.rs | 38 +++++---- .../src/macos/presentation.rs | 8 +- .../src/macos/video.rs | 60 +++++++-------- .../opennow-streamer-platform/src/output.rs | 22 ++---- opennow-qt/CMakeLists.txt | 77 +++++++++++++++---- 7 files changed, 124 insertions(+), 84 deletions(-) diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index 13d1eeb03..9c9166fbf 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -190,6 +190,7 @@ jobs: libpulse-dev \ libsecret-1-dev \ libva-dev \ + libvulkan-dev \ libx11-dev \ libxcursor-dev \ libxext-dev \ diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index 578b1c356..47a38130b 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -110,7 +110,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y libasound2-dev libdbus-1-dev libdrm-dev libpulse-dev libsecret-1-dev \ - libva-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxi-dev \ + libva-dev libvulkan-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxi-dev \ libxrandr-dev libxrender-dev libxss-dev make nasm pkg-config - name: Build SDL3 diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/embedded.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/embedded.rs index f6bd567cc..2b637047e 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/embedded.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/embedded.rs @@ -105,22 +105,22 @@ fragment float4 embedded_video_fragment( #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum BiPlanarFormat { - Nv12VideoRange, - Nv12FullRange, - P010VideoRange, - P010FullRange, + Nv12Video, + Nv12Full, + P010Video, + P010Full, } impl BiPlanarFormat { fn from_pixel_format(pixel_format: u32) -> Option { if pixel_format == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange { - Some(Self::Nv12VideoRange) + Some(Self::Nv12Video) } else if pixel_format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange { - Some(Self::Nv12FullRange) + Some(Self::Nv12Full) } else if pixel_format == kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange { - Some(Self::P010VideoRange) + Some(Self::P010Video) } else if pixel_format == kCVPixelFormatType_420YpCbCr10BiPlanarFullRange { - Some(Self::P010FullRange) + Some(Self::P010Full) } else { None } @@ -128,10 +128,8 @@ impl BiPlanarFormat { const fn plane_formats(self) -> (MTLPixelFormat, MTLPixelFormat) { match self { - Self::Nv12VideoRange | Self::Nv12FullRange => { - (MTLPixelFormat::R8Unorm, MTLPixelFormat::RG8Unorm) - } - Self::P010VideoRange | Self::P010FullRange => { + Self::Nv12Video | Self::Nv12Full => (MTLPixelFormat::R8Unorm, MTLPixelFormat::RG8Unorm), + Self::P010Video | Self::P010Full => { (MTLPixelFormat::R16Unorm, MTLPixelFormat::RG16Unorm) } } @@ -144,12 +142,12 @@ impl BiPlanarFormat { VideoColorSpace::Bt709 => 1, }, sample_format: match self { - Self::Nv12VideoRange | Self::Nv12FullRange => 0, - Self::P010VideoRange | Self::P010FullRange => 1, + Self::Nv12Video | Self::Nv12Full => 0, + Self::P010Video | Self::P010Full => 1, }, full_range: match self { - Self::Nv12VideoRange | Self::P010VideoRange => 0, - Self::Nv12FullRange | Self::P010FullRange => 1, + Self::Nv12Video | Self::P010Video => 0, + Self::Nv12Full | Self::P010Full => 1, }, } } @@ -558,19 +556,19 @@ mod tests { fn accepts_nv12_and_p010_ranges_only() { assert_eq!( BiPlanarFormat::from_pixel_format(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), - Some(BiPlanarFormat::Nv12VideoRange) + Some(BiPlanarFormat::Nv12Video) ); assert_eq!( BiPlanarFormat::from_pixel_format(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange), - Some(BiPlanarFormat::Nv12FullRange) + Some(BiPlanarFormat::Nv12Full) ); assert_eq!( BiPlanarFormat::from_pixel_format(kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange), - Some(BiPlanarFormat::P010VideoRange) + Some(BiPlanarFormat::P010Video) ); assert_eq!( BiPlanarFormat::from_pixel_format(kCVPixelFormatType_420YpCbCr10BiPlanarFullRange), - Some(BiPlanarFormat::P010FullRange) + Some(BiPlanarFormat::P010Full) ); assert_eq!(BiPlanarFormat::from_pixel_format(0), None); } diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs index 32564c889..8749d58c5 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/presentation.rs @@ -74,6 +74,8 @@ fragment float4 video_fragment( } "#; +type PresentedHandler = RcBlock>)>; + pub(super) struct PresenterHandle { queue: Arc>, worker: Option>, @@ -378,7 +380,7 @@ unsafe impl Send for PendingFrame {} struct MetalPresenter { layer: Retained, - device: Retained>, + _device: Retained>, command_queue: Retained>, pipeline: Retained>, texture_cache: CFRetained, @@ -530,7 +532,7 @@ impl MetalPresenter { let texture_cache = unsafe { CFRetained::from_raw(cache_ptr) }; Ok(Self { layer, - device, + _device: device, command_queue, pipeline, texture_cache, @@ -649,7 +651,7 @@ impl MetalPresenter { } let telemetry = Arc::clone(&self.telemetry); let expected_period = frame.minimum_frame_duration_seconds; - let presented_handler: RcBlock>)> = + let presented_handler: PresentedHandler = RcBlock::new(move |drawable: NonNull>| { // SAFETY: Metal supplies a valid drawable pointer for the duration of this block. let presented_time = unsafe { drawable.as_ref() }.presentedTime(); diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs index e6dd3402b..a550cc894 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-macos/src/macos/video.rs @@ -162,7 +162,7 @@ impl VideoDecoder { let hardware_decoder_key = unsafe { kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder }; let mut destination_entries = vec![ - (cf_ptr(metal_compatibility_key), cf_ptr(&*true_value)), + (cf_ptr(metal_compatibility_key), cf_ptr(true_value)), ( cf_ptr(io_surface_properties_key), cf_ptr(&*empty_properties), @@ -171,7 +171,7 @@ impl VideoDecoder { destination_entries.insert(0, (cf_ptr(pixel_format_key), cf_ptr(&*pixel_format_number))); let destination_attributes = make_dictionary(&destination_entries)?; let decoder_specification = - make_dictionary(&[(cf_ptr(hardware_decoder_key), cf_ptr(&*true_value))])?; + make_dictionary(&[(cf_ptr(hardware_decoder_key), cf_ptr(true_value))])?; let mut session_ptr = ptr::null_mut(); let status = unsafe { @@ -386,34 +386,6 @@ fn time_to_100ns(time: CMTime) -> i64 { }) } -#[cfg(test)] -mod tests { - use super::{frame_duration_seconds, time_to_100ns}; - use objc2_core_media::{CMTime, CMTimeFlags}; - - #[test] - fn converts_120_hz_core_media_duration_to_seconds() { - let duration = CMTime { - value: 750, - timescale: 90_000, - flags: CMTimeFlags(1), - epoch: 0, - }; - assert!((frame_duration_seconds(duration) - 1.0 / 120.0).abs() < f64::EPSILON); - } - - #[test] - fn converts_core_media_time_to_cross_platform_100ns_units() { - let time = CMTime { - value: 90_000, - timescale: 90_000, - flags: CMTimeFlags(1), - epoch: 0, - }; - assert_eq!(time_to_100ns(time), 10_000_000); - } -} - fn create_format_description( format: &VideoFormat, ) -> Result, BackendError> { @@ -559,3 +531,31 @@ fn check_status(api: &'static str, status: i32) -> Result<(), BackendError> { Err(BackendError::AppleApi { api, status }) } } + +#[cfg(test)] +mod tests { + use super::{frame_duration_seconds, time_to_100ns}; + use objc2_core_media::{CMTime, CMTimeFlags}; + + #[test] + fn converts_120_hz_core_media_duration_to_seconds() { + let duration = CMTime { + value: 750, + timescale: 90_000, + flags: CMTimeFlags(1), + epoch: 0, + }; + assert!((frame_duration_seconds(duration) - 1.0 / 120.0).abs() < f64::EPSILON); + } + + #[test] + fn converts_core_media_time_to_cross_platform_100ns_units() { + let time = CMTime { + value: 90_000, + timescale: 90_000, + flags: CMTimeFlags(1), + epoch: 0, + }; + assert_eq!(time_to_100ns(time), 10_000_000); + } +} diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs index 07bd8d9fe..5dc13de26 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs @@ -2588,30 +2588,22 @@ impl WindowsExternalSdlSurface { if let Err(error) = self.release() { eprintln!("{error}"); } - } else if matches!( + continue; + } + let focus_lost = matches!( event, sdl2::event::Event::Window { window_id, win_event: sdl2::event::WindowEvent::FocusLost, .. } if window_id == stream_window_id - ) { - self.input_capture.handle_event( - &self.sdl, - &mut self.window, - self.stream_size, - event, - ); + ); + self.input_capture + .handle_event(&self.sdl, &mut self.window, self.stream_size, event); + if focus_lost { if let Some(raw_input) = self.raw_input.as_ref() { raw_input.release_buttons(); } - } else { - self.input_capture.handle_event( - &self.sdl, - &mut self.window, - self.stream_size, - event, - ); } } self.sync_raw_input(); diff --git a/opennow-qt/CMakeLists.txt b/opennow-qt/CMakeLists.txt index ab0403801..51eab2698 100644 --- a/opennow-qt/CMakeLists.txt +++ b/opennow-qt/CMakeLists.txt @@ -271,16 +271,36 @@ if(WIN32) "$" "$" COMMENT "Copying SDL3 next to the OpenNOW executable") - find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${Qt6_DIR}/../../../bin") - if(WINDEPLOYQT_EXECUTABLE) - add_custom_command(TARGET opennow-qt POST_BUILD - COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-translations --qmldir "${CMAKE_CURRENT_SOURCE_DIR}/qml" - "$" - COMMAND "${CMAKE_COMMAND}" -E rm -f - "$/tls/qopensslbackend.dll" - "$/plugins/tls/qopensslbackend.dll" - COMMENT "Deploying Qt runtime plugins and preferring Windows Schannel TLS") + get_filename_component(OPENNOW_QT_TARGET_BIN "${Qt6_DIR}/../../../bin" ABSOLUTE) + set(OPENNOW_WINDEPLOYQT_ARGS + --no-translations + --qmldir "${CMAKE_CURRENT_SOURCE_DIR}/qml") + if(QT_HOST_PATH) + find_program(WINDEPLOYQT_EXECUTABLE NAMES windeployqt + HINTS "${QT_HOST_PATH}/bin" + NO_DEFAULT_PATH + REQUIRED) + find_file(OPENNOW_TARGET_QTPATHS_EXECUTABLE + NAMES qtpaths6.bat qtpaths.bat + HINTS "${OPENNOW_QT_TARGET_BIN}" + NO_DEFAULT_PATH + REQUIRED) + list(PREPEND OPENNOW_WINDEPLOYQT_ARGS + --qtpaths "${OPENNOW_TARGET_QTPATHS_EXECUTABLE}") + else() + find_program(WINDEPLOYQT_EXECUTABLE NAMES windeployqt + HINTS "${OPENNOW_QT_TARGET_BIN}" + NO_DEFAULT_PATH + REQUIRED) endif() + add_custom_command(TARGET opennow-qt POST_BUILD + COMMAND "${WINDEPLOYQT_EXECUTABLE}" ${OPENNOW_WINDEPLOYQT_ARGS} + "$" + COMMAND "${CMAKE_COMMAND}" -E rm -f + "$/tls/qopensslbackend.dll" + "$/plugins/tls/qopensslbackend.dll" + COMMENT "Deploying Qt runtime plugins and preferring Windows Schannel TLS" + COMMAND_EXPAND_LISTS) # windeployqt intentionally deploys only the production `windows` QPA # plugin. CTest runs the GUI/QML smoke suite with `QT_QPA_PLATFORM=offscreen`, # so keep that test-only plugin beside the deployed application as well. @@ -461,6 +481,11 @@ endif() include(CTest) if(BUILD_TESTING) + set(OPENNOW_QT_SMOKE_TIMEOUT 5) + if(APPLE AND "x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES) + set(OPENNOW_QT_SMOKE_TIMEOUT 15) + endif() + add_executable(opennow-fake-core tests/fake_core.cpp) qt_add_executable(opennow-localization-tests @@ -537,6 +562,28 @@ if(BUILD_TESTING) COMMAND opennow-nativestreamruntime-tests -o -,txt) set_tests_properties(opennow-nativestreamruntime-tests PROPERTIES TIMEOUT 8) + if(APPLE) + add_custom_target(opennow-streamer-ffi-test-runtime ALL + COMMAND ${CMAKE_COMMAND} -E make_directory + "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${OPENNOW_STREAMER_FFI_RUNTIME}" + "$/" + COMMAND ${CMAKE_COMMAND} -E make_directory + "$" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${OPENNOW_STREAMER_FFI_RUNTIME}" + "$/" + DEPENDS opennow-streamer-ffi-build + COMMENT "Deploying the embedded streamer runtime for CTest") + foreach(test_target IN ITEMS + opennow-streamvideo-tests + opennow-nativestreamruntime-tests) + add_dependencies(${test_target} opennow-streamer-ffi-test-runtime) + set_property(TARGET ${test_target} APPEND PROPERTY BUILD_RPATH "@loader_path") + endforeach() + endif() + qt_add_executable(opennow-embedded-orchestration-tests tests/tst_embeddedorchestration.cpp ) @@ -629,7 +676,7 @@ if(BUILD_TESTING) --console --route "${route}" --reduced-motion) set_tests_properties("qml-route-${route}" PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" - TIMEOUT 5 + TIMEOUT ${OPENNOW_QT_SMOKE_TIMEOUT} ) endforeach() foreach(route home library store friends settings stream) @@ -637,7 +684,7 @@ if(BUILD_TESTING) COMMAND opennow-qt --smoke-test --allow-multiple-instances --desktop --route "${route}" --reduced-motion) set_tests_properties("qml-desktop-route-${route}" PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" - TIMEOUT 5 + TIMEOUT ${OPENNOW_QT_SMOKE_TIMEOUT} ) endforeach() foreach(overlay desktop-stream-menu desktop-stream-stats desktop-stream-stats-expanded desktop-stream-exit-confirm) @@ -646,7 +693,7 @@ if(BUILD_TESTING) --desktop --route stream --overlay "${overlay}" --reduced-motion) set_tests_properties("qml-${overlay}" PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" - TIMEOUT 5 + TIMEOUT ${OPENNOW_QT_SMOKE_TIMEOUT} ) endforeach() add_test(NAME qml-fullscreen-stream-stats-shortcut @@ -665,7 +712,7 @@ if(BUILD_TESTING) --reduced-motion) set_tests_properties(qml-console-mode-persistence-rollback PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" - TIMEOUT 5 + TIMEOUT ${OPENNOW_QT_SMOKE_TIMEOUT} ) add_test(NAME qml-streamer-event-contract COMMAND opennow-qt @@ -676,14 +723,14 @@ if(BUILD_TESTING) --reduced-motion) set_tests_properties(qml-streamer-event-contract PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" - TIMEOUT 5 + TIMEOUT ${OPENNOW_QT_SMOKE_TIMEOUT} ) foreach(overlay friends friend-actions quick-settings session-conflict session-report queue-ad guide-session guide-controls guide-media guide-shortcuts) add_test(NAME "qml-overlay-${overlay}" COMMAND opennow-qt --smoke-test --allow-multiple-instances --route home --overlay "${overlay}" --reduced-motion) set_tests_properties("qml-overlay-${overlay}" PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=offscreen" - TIMEOUT 5 + TIMEOUT ${OPENNOW_QT_SMOKE_TIMEOUT} ) endforeach() add_test(NAME opennow-performance-report-harness From b2cf5550e2dfea8217617a8aa6183811b2cceba8 Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Mon, 31 Aug 2026 19:15:43 +0000 Subject: [PATCH 04/10] fix(ci): stabilize hardware-constrained runner checks --- .github/actionlint.yaml | 2 ++ .github/workflows/qt-ci.yml | 15 ++++++--- .github/workflows/qt-release-candidate.yml | 8 ++--- .../src/windows/graphics.rs | 33 +++++++++++++------ .../src/macos_backend.rs | 18 ++++------ .../opennow-streamer-platform/src/output.rs | 1 + opennow-qt/CMakeLists.txt | 4 +++ 7 files changed, 51 insertions(+), 30 deletions(-) diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml index 10aa5cf19..a7639bee8 100644 --- a/.github/actionlint.yaml +++ b/.github/actionlint.yaml @@ -8,6 +8,8 @@ self-hosted-runner: - blacksmith-4vcpu-windows-2025 - blacksmith-6vcpu-macos-15 - blacksmith-6vcpu-macos-latest + - blacksmith-8vcpu-ubuntu-2404 + - blacksmith-8vcpu-ubuntu-2404-arm - opennow-release-signer config-variables: null diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index 9c9166fbf..cbe64f99c 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -40,7 +40,8 @@ jobs: matrix: include: - label: linux-x64 - os: blacksmith-4vcpu-ubuntu-2404 + os: blacksmith-8vcpu-ubuntu-2404 + build-parallel: 6 qt-host: linux qt-arch: linux_gcc_64 package-generator: DEB @@ -50,7 +51,8 @@ jobs: linuxdeploy-sha256: c20cd71e3a4e3b80c3483cef793cda3f4e990aca14014d23c544ca3ce1270b4d qt-plugin-sha256: 15106be885c1c48a021198e7e1e9a48ce9d02a86dd0a1848f00bdbf3c1c92724 - label: linux-arm64 - os: blacksmith-4vcpu-ubuntu-2404-arm + os: blacksmith-8vcpu-ubuntu-2404-arm + build-parallel: 6 qt-host: linux_arm64 qt-arch: linux_gcc_arm64 package-generator: DEB @@ -61,6 +63,7 @@ jobs: qt-plugin-sha256: bf1c24aff6d749b5cf423afad6f15abd4440f81dec1aab95706b25f6667cdcf1 - label: windows-x64 os: blacksmith-4vcpu-windows-2025 + build-parallel: 4 qt-host: windows qt-arch: win64_msvc2022_64 package-generator: ZIP @@ -68,6 +71,7 @@ jobs: cmake-arch: "" - label: windows-arm64 os: blacksmith-4vcpu-windows-2025 + build-parallel: 4 qt-host: windows qt-arch: win64_msvc2022_arm64_cross_compiled package-generator: ZIP @@ -75,6 +79,7 @@ jobs: cmake-arch: ARM64 - label: macos-arm64 os: blacksmith-6vcpu-macos-15 + build-parallel: 6 qt-host: mac qt-arch: clang_64 package-generator: "DragNDrop;ZIP" @@ -82,6 +87,7 @@ jobs: cmake-arch: arm64 - label: macos-x64 os: blacksmith-6vcpu-macos-15 + build-parallel: 6 qt-host: mac qt-arch: clang_64 package-generator: "DragNDrop;ZIP" @@ -220,7 +226,7 @@ jobs: -DSDL_TEST_LIBRARY=OFF \ -DSDL_TESTS=OFF \ "${SDL_CMAKE_ARGS[@]}" - cmake --build "$RUNNER_TEMP/SDL-build" --config Release --parallel + cmake --build "$RUNNER_TEMP/SDL-build" --config Release --parallel "${{ matrix.build-parallel }}" cmake --install "$RUNNER_TEMP/SDL-build" --config Release --prefix "$RUNNER_TEMP/SDL-install" - name: Rust format and lint @@ -288,7 +294,7 @@ jobs: - name: Build Qt release shell: bash - run: cmake --build build/opennow-qt-release --config Release --parallel + run: cmake --build build/opennow-qt-release --config Release --parallel "${{ matrix.build-parallel }}" - name: Test Qt shell if: matrix.label != 'windows-arm64' @@ -354,3 +360,4 @@ jobs: path: build/qt-packages/* if-no-files-found: error retention-days: 14 + compression-level: 0 diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index 47a38130b..349fab8a6 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -73,14 +73,14 @@ jobs: matrix: include: - arch: x64 - runner: blacksmith-4vcpu-ubuntu-2404 + runner: blacksmith-8vcpu-ubuntu-2404 qt_host: linux qt_arch: linux_gcc_64 linuxdeploy_arch: x86_64 linuxdeploy_sha256: c20cd71e3a4e3b80c3483cef793cda3f4e990aca14014d23c544ca3ce1270b4d qt_plugin_sha256: 15106be885c1c48a021198e7e1e9a48ce9d02a86dd0a1848f00bdbf3c1c92724 - arch: arm64 - runner: blacksmith-4vcpu-ubuntu-2404-arm + runner: blacksmith-8vcpu-ubuntu-2404-arm qt_host: linux_arm64 qt_arch: linux_gcc_arm64 linuxdeploy_arch: aarch64 @@ -119,7 +119,7 @@ jobs: git clone --depth 1 --branch "$SDL_VERSION" https://github.com/libsdl-org/SDL.git "$RUNNER_TEMP/SDL" cmake -S "$RUNNER_TEMP/SDL" -B "$RUNNER_TEMP/SDL-build" -DCMAKE_BUILD_TYPE=Release \ -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TEST_LIBRARY=OFF -DSDL_TESTS=OFF - cmake --build "$RUNNER_TEMP/SDL-build" --config Release --parallel + cmake --build "$RUNNER_TEMP/SDL-build" --config Release --parallel 6 cmake --install "$RUNNER_TEMP/SDL-build" --config Release --prefix "$RUNNER_TEMP/SDL-install" - name: Configure, build, and test release @@ -132,7 +132,7 @@ jobs: -DCMAKE_PREFIX_PATH="$RUNNER_TEMP/SDL-install" \ -DOPENNOW_BUILD_VERSION="$RELEASE_VERSION" \ -DOPENNOW_UPDATE_ED25519_PUBLIC_KEY="$UPDATE_PUBLIC_KEY" - cmake --build build/qt-release --config Release --parallel + cmake --build build/qt-release --config Release --parallel 6 ctest --test-dir build/qt-release -C Release --output-on-failure --parallel 4 - name: Build DEB and AppImage diff --git a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/graphics.rs b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/graphics.rs index a2c65ca81..4e86c96e1 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/graphics.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform-windows/src/windows/graphics.rs @@ -1123,6 +1123,10 @@ mod tests { } } + fn is_missing_hardware_video_support(error: &str) -> bool { + error.contains("0x80004002") || error.contains("0x887A0004") + } + #[test] fn swap_chain_formats_match_official_windows_client() { assert_eq!( @@ -1202,14 +1206,18 @@ mod tests { } #[test] - fn d3d11_on_12_exposes_video_processing_interfaces() { - Graphics::probe(WindowsGraphicsApi::D3d12) - .expect("D3D11-on-12 must support the complete graphics presentation path"); + fn d3d11_on_12_exposes_video_processing_or_reports_unsupported_hardware() { + if let Err(error) = Graphics::probe(WindowsGraphicsApi::D3d12) { + assert!( + is_missing_hardware_video_support(&error), + "D3D11-on-12 probe failed unexpectedly: {error}" + ); + } } #[test] - fn p010_presentation_selects_a_driver_supported_scanout() { - let graphics = Graphics::new( + fn p010_presentation_selects_a_scanout_or_reports_unsupported_hardware() { + let result = Graphics::new( WindowsGraphicsApi::D3d11, SurfaceTarget::Owned(OwnedWindow { parent: None, @@ -1222,11 +1230,16 @@ mod tests { visible: false, }), video_format(VideoPixelFormat::P010), - ) - .expect("P010 must use either native 10-bit scan-out or the SDR fallback"); - assert!( - graphics.swap_format == DXGI_FORMAT_R10G10B10A2_UNORM - || graphics.swap_format == DXGI_FORMAT_R8G8B8A8_UNORM ); + match result { + Ok(graphics) => assert!( + graphics.swap_format == DXGI_FORMAT_R10G10B10A2_UNORM + || graphics.swap_format == DXGI_FORMAT_R8G8B8A8_UNORM + ), + Err(error) => assert!( + is_missing_hardware_video_support(&error), + "P010 presenter failed unexpectedly: {error}" + ), + } } } diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs index c77e62b57..3e7ed83b6 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/macos_backend.rs @@ -17,6 +17,8 @@ use crate::output::{ const HIDDEN_SURFACE: ScreenRect = ScreenRect::new(0.0, 0.0, 2.0, 2.0); const ORDERING_POLL_INTERVAL: Duration = Duration::from_millis(100); +type H264ParameterSetBytes = (Option>, Option>); +type H265ParameterSetBytes = (Option>, Option>, Option>); pub(crate) fn available() -> bool { h264_available() || h265_available() || av1_available() @@ -508,9 +510,7 @@ impl H264ParameterSetTracker { self.candidate = None; } - fn parameter_sets_from_annex_b( - access_unit: &[u8], - ) -> Result<(Option>, Option>), String> { + fn parameter_sets_from_annex_b(access_unit: &[u8]) -> Result { let Some((mut start, prefix)) = find_start_code(access_unit, 0) else { return Err("H.264 access unit has no Annex B start code".to_owned()); }; @@ -531,9 +531,7 @@ impl H264ParameterSetTracker { } } - fn parameter_sets_from_avcc( - access_unit: &[u8], - ) -> Result<(Option>, Option>), String> { + fn parameter_sets_from_avcc(access_unit: &[u8]) -> Result { let mut offset = 0usize; let mut sequence = None; let mut picture = None; @@ -640,9 +638,7 @@ impl H265ParameterSetTracker { self.candidate = None; } - fn parameter_sets_from_annex_b( - access_unit: &[u8], - ) -> Result<(Option>, Option>, Option>), String> { + fn parameter_sets_from_annex_b(access_unit: &[u8]) -> Result { let Some((mut start, prefix)) = find_start_code(access_unit, 0) else { return Err("H.265 access unit has no Annex B start code".to_owned()); }; @@ -669,9 +665,7 @@ impl H265ParameterSetTracker { } } - fn parameter_sets_from_avcc( - access_unit: &[u8], - ) -> Result<(Option>, Option>, Option>), String> { + fn parameter_sets_from_avcc(access_unit: &[u8]) -> Result { let mut offset = 0usize; let mut video = None; let mut sequence = None; diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs index 5dc13de26..074fa4b88 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/output.rs @@ -1369,6 +1369,7 @@ impl SdlInputCapture { std::mem::take(&mut self.captured) } + #[cfg(any(target_os = "linux", target_os = "windows"))] pub(crate) const fn relative_mouse_enabled(&self) -> bool { self.relative_mouse } diff --git a/opennow-qt/CMakeLists.txt b/opennow-qt/CMakeLists.txt index 51eab2698..67fc462ec 100644 --- a/opennow-qt/CMakeLists.txt +++ b/opennow-qt/CMakeLists.txt @@ -287,6 +287,9 @@ if(WIN32) REQUIRED) list(PREPEND OPENNOW_WINDEPLOYQT_ARGS --qtpaths "${OPENNOW_TARGET_QTPATHS_EXECUTABLE}") + set(OPENNOW_QT_DEPLOY_TOOL_ARGS + DEPLOY_TOOL_OPTIONS + --qtpaths "${OPENNOW_TARGET_QTPATHS_EXECUTABLE}") else() find_program(WINDEPLOYQT_EXECUTABLE NAMES windeployqt HINTS "${OPENNOW_QT_TARGET_BIN}" @@ -824,6 +827,7 @@ if(WIN32 OR APPLE) TARGET opennow-qt OUTPUT_SCRIPT opennow_deploy_script NO_UNSUPPORTED_PLATFORM_ERROR + ${OPENNOW_QT_DEPLOY_TOOL_ARGS} ) install(SCRIPT "${opennow_deploy_script}") endif() From 82cafc09dc9ea49bc14f187d6536d68e1042b7c8 Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Tue, 1 Sep 2026 07:35:09 +0000 Subject: [PATCH 05/10] fix(ci): resolve remaining platform failures --- .github/workflows/auto-build.yml | 6 ++++++ .github/workflows/qt-ci.yml | 11 +++++++++++ .github/workflows/qt-release-candidate.yml | 5 +++++ .github/workflows/release.yml | 6 ++++++ .../opennow-streamer-platform/src/embedded_input.rs | 1 + opennow-qt/CMakeLists.txt | 2 +- 6 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto-build.yml b/.github/workflows/auto-build.yml index 9748b9823..320c5f0da 100644 --- a/.github/workflows/auto-build.yml +++ b/.github/workflows/auto-build.yml @@ -198,7 +198,13 @@ jobs: if (-not $compiler) { throw "Visual Studio ARM64 compiler is unavailable after installation." } + $linker = Join-Path $compiler.Directory.FullName "link.exe" + if (-not (Test-Path $linker)) { + throw "Visual Studio ARM64 linker is unavailable after installation." + } + "CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER=$linker" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append Write-Host "Using Windows ARM64 compiler: $($compiler.FullName)" + Write-Host "Using Windows ARM64 linker: $linker" - name: Setup Windows ARM64 build tools if: matrix.native_target == 'aarch64-pc-windows-msvc' diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index cbe64f99c..30fec646f 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -134,7 +134,18 @@ jobs: if ($install.ExitCode -notin 0, 3010) { throw "Visual Studio ARM64 compiler installation failed with exit code $($install.ExitCode)." } + $compiler = Get-ChildItem "$installPath\VC\Tools\MSVC\*\bin\Hostx64\arm64\cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 } + if (-not $compiler) { + throw "Visual Studio ARM64 compiler is unavailable after installation." + } + $linker = Join-Path $compiler.Directory.FullName "link.exe" + if (-not (Test-Path $linker)) { + throw "Visual Studio ARM64 linker is unavailable after installation." + } + "CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER=$linker" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + Write-Host "Using Windows ARM64 compiler: $($compiler.FullName)" + Write-Host "Using Windows ARM64 linker: $linker" - name: Setup Windows ARM64 build tools if: matrix.label == 'windows-arm64' diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index 349fab8a6..c41c17a67 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -230,7 +230,12 @@ jobs: $arguments = "modify --installPath `"$installPath`" --quiet --norestart --add Microsoft.VisualStudio.Component.VC.Tools.ARM64" $install = Start-Process "$installerRoot\vs_installer.exe" -Wait -PassThru -ArgumentList $arguments if ($install.ExitCode -notin 0, 3010) { throw "ARM64 compiler installation failed" } + $compiler = Get-ChildItem "$installPath\VC\Tools\MSVC\*\bin\Hostx64\arm64\cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 } + if (-not $compiler) { throw "ARM64 compiler is unavailable after installation" } + $linker = Join-Path $compiler.Directory.FullName "link.exe" + if (-not (Test-Path $linker)) { throw "ARM64 linker is unavailable after installation" } + "CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER=$linker" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - uses: ilammy/msvc-dev-cmd@v1 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 25b9c229b..dc2021b0d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -391,7 +391,13 @@ jobs: if (-not $compiler) { throw "Visual Studio ARM64 compiler is unavailable after installation." } + $linker = Join-Path $compiler.Directory.FullName "link.exe" + if (-not (Test-Path $linker)) { + throw "Visual Studio ARM64 linker is unavailable after installation." + } + "CARGO_TARGET_AARCH64_PC_WINDOWS_MSVC_LINKER=$linker" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append Write-Host "Using Windows ARM64 compiler: $($compiler.FullName)" + Write-Host "Using Windows ARM64 linker: $linker" - name: Setup Windows ARM64 build tools if: matrix.native_target == 'aarch64-pc-windows-msvc' diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs index 20b5aad76..a7b3d9103 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/embedded_input.rs @@ -117,6 +117,7 @@ impl EmbeddedInputCapture { } } +#[cfg(any(target_os = "linux", target_os = "windows", test))] const fn raw_capture_enabled(active: bool, relative_mouse: bool) -> bool { active && relative_mouse } diff --git a/opennow-qt/CMakeLists.txt b/opennow-qt/CMakeLists.txt index 67fc462ec..2a3321045 100644 --- a/opennow-qt/CMakeLists.txt +++ b/opennow-qt/CMakeLists.txt @@ -17,7 +17,7 @@ set(CMAKE_AUTOMOC ON) # propagated by the targets below, so avoid the redundant compiler subprocess. set(CMAKE_AUTOMOC_COMPILER_PREDEFINES OFF) -find_package(Qt6 6.8 REQUIRED COMPONENTS Quick QuickControls2 GuiPrivate Network Multimedia Test) +find_package(Qt6 6.8 REQUIRED COMPONENTS Quick QuickControls2 Gui Network Multimedia Test) find_package(SDL3 REQUIRED CONFIG) find_package(Threads REQUIRED) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") From cc6685026eb510039d0a1eff18310e692540197b Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Tue, 1 Sep 2026 07:46:26 +0000 Subject: [PATCH 06/10] fix(ci): align platform tests and package scanning --- .../opennow-streamer-platform/src/lib.rs | 27 ++++++++++++------- opennow-qt/CMakeLists.txt | 12 +++++++++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/native/opennow-streamer/crates/opennow-streamer-platform/src/lib.rs b/native/opennow-streamer/crates/opennow-streamer-platform/src/lib.rs index 586a0717f..aeda57f3c 100644 --- a/native/opennow-streamer/crates/opennow-streamer-platform/src/lib.rs +++ b/native/opennow-streamer/crates/opennow-streamer-platform/src/lib.rs @@ -451,21 +451,28 @@ mod tests { .iter() .find(|backend| backend.backend == "videotoolbox") .expect("VideoToolbox backend"); - assert!( - hardware - .codecs - .iter() - .filter(|codec| codec.codec != "h264") - .all(|codec| !codec.available) - ); + for (codec, expected) in [ + ("h264", macos_backend::h264_available()), + ("h265", macos_backend::h265_available()), + ("av1", macos_backend::av1_available()), + ] { + assert_eq!( + hardware + .codecs + .iter() + .find(|capability| capability.codec == codec) + .expect(codec) + .available, + expected, + ); + } + assert_eq!(hardware.available, macos_backend::available()); assert_eq!( hardware.available, hardware .codecs .iter() - .find(|codec| codec.codec == "h264") - .expect("h264") - .available + .any(|capability| capability.available) ); } } diff --git a/opennow-qt/CMakeLists.txt b/opennow-qt/CMakeLists.txt index 2a3321045..a53119a19 100644 --- a/opennow-qt/CMakeLists.txt +++ b/opennow-qt/CMakeLists.txt @@ -857,6 +857,18 @@ else() set(CPACK_DEBIAN_PACKAGE_SECTION "games") set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS TRUE) + get_target_property(OPENNOW_SDL3_RUNTIME_LOCATION + ${OPENNOW_SDL3_RUNTIME_TARGET} IMPORTED_LOCATION_RELEASE) + if(NOT OPENNOW_SDL3_RUNTIME_LOCATION) + get_target_property(OPENNOW_SDL3_RUNTIME_LOCATION + ${OPENNOW_SDL3_RUNTIME_TARGET} IMPORTED_LOCATION) + endif() + if(OPENNOW_SDL3_RUNTIME_LOCATION) + get_filename_component(OPENNOW_SDL3_RUNTIME_DIRECTORY + "${OPENNOW_SDL3_RUNTIME_LOCATION}" DIRECTORY) + set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS + "${OPENNOW_SDL3_RUNTIME_DIRECTORY}") + endif() set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6core6 (>= 6.8) | libqt6core6t64 (>= 6.8), libqt6gui6 (>= 6.8), libqt6network6 (>= 6.8), libqt6qml6 (>= 6.8), libqt6quick6 (>= 6.8), libqt6quickcontrols2-6 (>= 6.8), libqt6multimedia6 (>= 6.8), qml6-module-qtquick, qml6-module-qtquick-controls, qml6-module-qtquick-dialogs, qml6-module-qtquick-effects, qml6-module-qtmultimedia, libsdl3-0 | libsdl3-0.0") if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$") From 8521d4735796cdd8f0f11fb2f8da581fd90f484e Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Tue, 1 Sep 2026 08:07:06 +0000 Subject: [PATCH 07/10] fix(qt): expose SDL to AppImage packaging --- .github/workflows/qt-ci.yml | 1 + .github/workflows/qt-release-candidate.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index 30fec646f..77b16b8a1 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -332,6 +332,7 @@ jobs: LINUXDEPLOY_SHA256: ${{ matrix.linuxdeploy-sha256 }} QT_PLUGIN_SHA256: ${{ matrix.qt-plugin-sha256 }} run: | + export LD_LIBRARY_PATH="$RUNNER_TEMP/SDL-install/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" cmake --install build/opennow-qt-release --config Release \ --prefix "$PWD/build/AppDir/usr" curl --fail --location --retry 3 \ diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index c41c17a67..01d72c767 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -143,6 +143,7 @@ jobs: LINUXDEPLOY_SHA256: ${{ matrix.linuxdeploy_sha256 }} QT_PLUGIN_SHA256: ${{ matrix.qt_plugin_sha256 }} run: | + export LD_LIBRARY_PATH="$RUNNER_TEMP/SDL-install/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" mkdir -p build/release-artifacts cpack --config build/qt-release/CPackConfig.cmake -C Release -G DEB -B build/release-artifacts cmake --install build/qt-release --config Release --prefix "$PWD/build/AppDir/usr" From d731b75c564acfe6230db08ddf03184ad41f71af Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Tue, 1 Sep 2026 08:33:49 +0000 Subject: [PATCH 08/10] fix(qt): complete platform packaging dependencies --- .github/workflows/qt-ci.yml | 3 +++ .github/workflows/qt-release-candidate.yml | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index 77b16b8a1..e9fb7a961 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -204,6 +204,7 @@ jobs: libasound2-dev \ libdbus-1-dev \ libdrm-dev \ + libgstreamer-plugins-bad1.0-0 \ libpulse-dev \ libsecret-1-dev \ libva-dev \ @@ -367,6 +368,8 @@ jobs: - name: Upload unsigned validation package uses: actions/upload-artifact@v4 + env: + NODE_OPTIONS: --max-old-space-size=8192 with: name: opennow-qt-${{ matrix.label }}-unsigned path: build/qt-packages/* diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index 01d72c767..72fdd9fba 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -110,7 +110,7 @@ jobs: run: | sudo apt-get update sudo apt-get install -y libasound2-dev libdbus-1-dev libdrm-dev libpulse-dev libsecret-1-dev \ - libva-dev libvulkan-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxi-dev \ + libgstreamer-plugins-bad1.0-0 libva-dev libvulkan-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxi-dev \ libxrandr-dev libxrender-dev libxss-dev make nasm pkg-config - name: Build SDL3 @@ -532,6 +532,8 @@ jobs: rm -f "$RUNNER_TEMP/opennow-signing.p12" "$RUNNER_TEMP/AuthKey.p8" - uses: actions/upload-artifact@v4 + env: + NODE_OPTIONS: --max-old-space-size=8192 with: name: opennow-qt-${{ inputs.version }}-macos-${{ matrix.arch }}-signed-notarized path: build/release-artifacts/* From 19487682208ba5cf59cbd1f08b8d3b8b0339afa7 Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Tue, 1 Sep 2026 08:51:27 +0000 Subject: [PATCH 09/10] fix(qt): supply complete GStreamer runtime --- .github/workflows/qt-ci.yml | 1 + .github/workflows/qt-release-candidate.yml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index e9fb7a961..9354b6aed 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -205,6 +205,7 @@ jobs: libdbus-1-dev \ libdrm-dev \ libgstreamer-plugins-bad1.0-0 \ + libgstreamer-plugins-good1.0-0 \ libpulse-dev \ libsecret-1-dev \ libva-dev \ diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index 72fdd9fba..d232329fe 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -110,7 +110,8 @@ jobs: run: | sudo apt-get update sudo apt-get install -y libasound2-dev libdbus-1-dev libdrm-dev libpulse-dev libsecret-1-dev \ - libgstreamer-plugins-bad1.0-0 libva-dev libvulkan-dev libx11-dev libxcursor-dev libxext-dev libxfixes-dev libxi-dev \ + libgstreamer-plugins-bad1.0-0 libgstreamer-plugins-good1.0-0 libva-dev libvulkan-dev libx11-dev \ + libxcursor-dev libxext-dev libxfixes-dev libxi-dev \ libxrandr-dev libxrender-dev libxss-dev make nasm pkg-config - name: Build SDL3 From 0fcb4e5944d718f9a170558a3a62f813bcc0c259 Mon Sep 17 00:00:00 2001 From: zortos293 <65777760+zortos293@users.noreply.github.com> Date: Tue, 1 Sep 2026 09:20:26 +0000 Subject: [PATCH 10/10] fix(qt): upload only finished packages --- .github/workflows/qt-ci.yml | 8 +++++--- .github/workflows/qt-release-candidate.yml | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/.github/workflows/qt-ci.yml b/.github/workflows/qt-ci.yml index 9354b6aed..1df432a68 100644 --- a/.github/workflows/qt-ci.yml +++ b/.github/workflows/qt-ci.yml @@ -369,11 +369,13 @@ jobs: - name: Upload unsigned validation package uses: actions/upload-artifact@v4 - env: - NODE_OPTIONS: --max-old-space-size=8192 with: name: opennow-qt-${{ matrix.label }}-unsigned - path: build/qt-packages/* + path: | + build/qt-packages/*.AppImage + build/qt-packages/*.deb + build/qt-packages/*.dmg + build/qt-packages/*.zip if-no-files-found: error retention-days: 14 compression-level: 0 diff --git a/.github/workflows/qt-release-candidate.yml b/.github/workflows/qt-release-candidate.yml index d232329fe..70a12d995 100644 --- a/.github/workflows/qt-release-candidate.yml +++ b/.github/workflows/qt-release-candidate.yml @@ -188,7 +188,10 @@ jobs: - uses: actions/upload-artifact@v4 with: name: opennow-qt-${{ inputs.version }}-linux-${{ matrix.arch }}-signed - path: build/release-artifacts/* + path: | + build/release-artifacts/*.AppImage + build/release-artifacts/*.deb + build/release-artifacts/SHA256SUMS if-no-files-found: error windows: @@ -386,7 +389,10 @@ jobs: - uses: actions/upload-artifact@v4 with: name: opennow-qt-${{ inputs.version }}-windows-${{ matrix.arch }}-signed - path: build/release-artifacts/* + path: | + build/release-artifacts/*.msi + build/release-artifacts/*.zip + build/release-artifacts/SHA256SUMS if-no-files-found: error macos: @@ -533,11 +539,12 @@ jobs: rm -f "$RUNNER_TEMP/opennow-signing.p12" "$RUNNER_TEMP/AuthKey.p8" - uses: actions/upload-artifact@v4 - env: - NODE_OPTIONS: --max-old-space-size=8192 with: name: opennow-qt-${{ inputs.version }}-macos-${{ matrix.arch }}-signed-notarized - path: build/release-artifacts/* + path: | + build/release-artifacts/*.dmg + build/release-artifacts/*.zip + build/release-artifacts/SHA256SUMS if-no-files-found: error inventory: