diff --git a/anda/apps/envision/envision.spec b/anda/apps/envision/envision.spec index eb154194a4..352f0ba8f1 100644 --- a/anda/apps/envision/envision.spec +++ b/anda/apps/envision/envision.spec @@ -1,5 +1,5 @@ -%global commit 0a46a7d3329d86629d7562d9f5747da70973a338 -%global commit_date 20250723 +%global commit 5470662f25a0fc9cdb024d2e3dce4108f5cc529a +%global commit_date 20250917 %global shortcommit %(c=%{commit}; echo ${c:0:7}) Name: envision-nightly diff --git a/anda/apps/flameshot/flameshot-nightly.spec b/anda/apps/flameshot/flameshot-nightly.spec index 81d2e7286b..a5e138c305 100644 --- a/anda/apps/flameshot/flameshot-nightly.spec +++ b/anda/apps/flameshot/flameshot-nightly.spec @@ -1,9 +1,9 @@ #? https://github.com/flameshot-org/flameshot/blob/master/packaging/rpm/fedora/flameshot.spec %global ver 13.1.0 -%global commit 06f41a86cc91d53d68871fcdc67053239ff1e87b +%global commit 1e18288738d77beb6acdb2df65ae0cf5f984d58c %global shortcommit %{sub %{commit} 1 7} -%global commit_date 20250830 +%global commit_date 20250911 %global devel_name QtColorWidgets %global _distro_extra_cflags -fuse-ld=mold %global _distro_extra_cxxflags -fuse-ld=mold diff --git a/anda/apps/fontviewer/fontviewer.spec b/anda/apps/fontviewer/fontviewer.spec index e54b93a5c1..0911c2b911 100644 --- a/anda/apps/fontviewer/fontviewer.spec +++ b/anda/apps/fontviewer/fontviewer.spec @@ -1,6 +1,6 @@ Name: fontviewer Epoch: 1 -Version: 1.1.0 +Version: 1.2.0 Release: 1%?dist Summary: View and install fonts diff --git a/anda/apps/legcord/nightly/legcord-nightly.spec b/anda/apps/legcord/nightly/legcord-nightly.spec index 71c43dee37..400fd26f50 100644 --- a/anda/apps/legcord/nightly/legcord-nightly.spec +++ b/anda/apps/legcord/nightly/legcord-nightly.spec @@ -1,5 +1,5 @@ -%global commit 774311e9473dbf7741f0daced1bad98ddac17de8 -%global commit_date 20250614 +%global commit b55a0f58bae0c633498948ddab054f96da6da2d0 +%global commit_date 20250911 %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global debug_package %nil %global __strip /bin/true diff --git a/anda/apps/mpv/mpv-nightly.spec b/anda/apps/mpv/mpv-nightly.spec index de9355336d..66c2d1dc01 100644 --- a/anda/apps/mpv/mpv-nightly.spec +++ b/anda/apps/mpv/mpv-nightly.spec @@ -1,9 +1,9 @@ # Disable X11 for RHEL 10+ %bcond x11 %[%{undefined rhel} || 0%{?rhel} < 10] -%global commit 2b74582fcb9c57c981acc11c3e3d57d97c47a8ac +%global commit 764da9919c9dcdd951d9441dac2b56b8a03770ad %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250808 +%global commit_date 20250916 %global ver 0.40.0 Name: mpv-nightly diff --git a/anda/apps/ruffle/ruffle-nightly.spec b/anda/apps/ruffle/ruffle-nightly.spec index 08e7dc104f..f4f860ce64 100644 --- a/anda/apps/ruffle/ruffle-nightly.spec +++ b/anda/apps/ruffle/ruffle-nightly.spec @@ -1,4 +1,4 @@ -%global ver 2025-09-13 +%global ver 2025-09-17 %global goodver %(echo %ver | sed 's/-//g') %global __brp_mangle_shebangs %{nil} %bcond_without mold @@ -9,7 +9,7 @@ language. Ruffle targets both the desktop and the web using WebAssembly.} Name: ruffle-nightly Version: %goodver -Release: 2%?dist +Release: 1%?dist Summary: A Flash Player emulator written in Rust License: Apache-2.0 OR MIT URL: https://ruffle.rs/ diff --git a/anda/apps/throne/Sagernet.SingBox.Version.txt b/anda/apps/throne/Sagernet.SingBox.Version.txt index 40faed9aa4..6741c5e834 100644 --- a/anda/apps/throne/Sagernet.SingBox.Version.txt +++ b/anda/apps/throne/Sagernet.SingBox.Version.txt @@ -1 +1 @@ -1.11.8 +v1.11.15 \ No newline at end of file diff --git a/anda/apps/winetricks/git/winetricks-git.spec b/anda/apps/winetricks/git/winetricks-git.spec index 0dcd4b7090..9a597a5e88 100644 --- a/anda/apps/winetricks/git/winetricks-git.spec +++ b/anda/apps/winetricks/git/winetricks-git.spec @@ -1,9 +1,9 @@ # Fedora sometimes sources the snapshots under stable versions and just bumps release # For user clarity I have separated these into different packages -%global commit 2c76995ed67b5bf3e957e73afb4fbb4734593149 +%global commit 13bf50cbf84e00a7d5a0f13e1beefad306d58622 %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global ver 20250102 -%global commit_date 20250807 +%global commit_date 20250916 Name: winetricks-git Version: %{ver}^%{commit_date}git.%{shortcommit} diff --git a/anda/devs/ghostty/nightly/ghostty-nightly.spec b/anda/devs/ghostty/nightly/ghostty-nightly.spec index bdb24ac79b..8923ccc0a4 100644 --- a/anda/devs/ghostty/nightly/ghostty-nightly.spec +++ b/anda/devs/ghostty/nightly/ghostty-nightly.spec @@ -1,9 +1,9 @@ -%global commit d3cadf24952a6088affee9f752f75c3db8287801 +%global commit 0f0a61c38dbebbd70979afbd3df81bf143efca9d %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global fulldate 2025-08-27 +%global fulldate 2025-09-17 %global commit_date %(echo %{fulldate} | sed 's/-//g') %global public_key RWQlAjJC23149WL2sEpT/l0QKy7hMIFhYdQOFy0Z7z7PbneUgvlsnYcV -%global ver 1.1.4 +%global ver 1.2.1 %global base_name ghostty %global appid com.mitchellh.%{base_name} diff --git a/anda/devs/micro/micro-nightly.spec b/anda/devs/micro/micro-nightly.spec index 039f144da9..aba7acf113 100644 --- a/anda/devs/micro/micro-nightly.spec +++ b/anda/devs/micro/micro-nightly.spec @@ -12,8 +12,8 @@ # Naming variable as something other than "commit" is necessary # to stop %%gometa from putting commit hash in release -%global commit_hash b8057f28c6e5adef9744250643ad8cf8b5fafa18 -%global commit_date 20250826 +%global commit_hash ad24089e4e638209af66a27526f050a41de96b7f +%global commit_date 20250910 %global shortcommit %{sub %{commit_hash} 1 7} %global ver 2.0.14 diff --git a/anda/devs/zed/nightly/zed-nightly.spec b/anda/devs/zed/nightly/zed-nightly.spec index 8da62ff61d..151f78b8a1 100644 --- a/anda/devs/zed/nightly/zed-nightly.spec +++ b/anda/devs/zed/nightly/zed-nightly.spec @@ -1,7 +1,7 @@ -%global commit 0a9f40787216f18ee2f4dc79211877d1af496284 +%global commit f6c5c68751f686a4cf90ea1a1d32a361cb7c888e %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250828 -%global ver 0.203.0 +%global commit_date 20250917 +%global ver 0.205.0 %bcond_with check %bcond nightly 1 diff --git a/anda/games/gamescope-session-steam/gamescope-session-steam.spec b/anda/games/gamescope-session-steam/gamescope-session-steam.spec index ee7eb65a25..ffa56da88a 100644 --- a/anda/games/gamescope-session-steam/gamescope-session-steam.spec +++ b/anda/games/gamescope-session-steam/gamescope-session-steam.spec @@ -2,7 +2,7 @@ %global commit ba967fd8c5de7dc6c623b614296b3872255996b0 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20241206 +%global commit_date 20250904 Name: gamescope-session-steam Version: %commit_date.%shortcommit diff --git a/anda/games/gamescope-session/gamescope-session.spec b/anda/games/gamescope-session/gamescope-session.spec index 9693af941a..38318fce39 100644 --- a/anda/games/gamescope-session/gamescope-session.spec +++ b/anda/games/gamescope-session/gamescope-session.spec @@ -2,7 +2,7 @@ %global commit c65fbffa7306167989e4dd6fe76d6bab3c9d8c30 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250802 +%global commit_date 20250904 Name: gamescope-session Version: %commit_date.%shortcommit diff --git a/anda/games/prismlauncher-nightly/prismlauncher-nightly.spec b/anda/games/prismlauncher-nightly/prismlauncher-nightly.spec index a3a2438d28..8bf68472a8 100644 --- a/anda/games/prismlauncher-nightly/prismlauncher-nightly.spec +++ b/anda/games/prismlauncher-nightly/prismlauncher-nightly.spec @@ -1,10 +1,10 @@ %global real_name prismlauncher %global nice_name PrismLauncher -%global commit 8275529afb29f0e959de45ee20ec495bd5e6b351 +%global commit b7b06c0e487601a2849cbf3063087bd8124e1c02 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250806 +%global commit_date 20250917 %global snapshot_info %{commit_date}.%{shortcommit} %bcond_without qt6 diff --git a/anda/games/rpcs3/rpcs3.spec b/anda/games/rpcs3/rpcs3.spec index d45123f54c..ecd6b65954 100644 --- a/anda/games/rpcs3/rpcs3.spec +++ b/anda/games/rpcs3/rpcs3.spec @@ -6,8 +6,8 @@ # Need to get rid of everything Clang can't use and undefine -Wunused-command-line-argument where possible due to the project's build flags %global build_cflags %(echo %{build_cflags} | sed 's:-Werror ::g' | sed 's:-Wunused-command-line-argument ::g' | sed 's:-specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 ::g' | sed 's:-specs=/usr/lib/rpm/redhat/redhat-hardened-ld ::g' | sed 's:-specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors ::g' | sed 's:-specs=/usr/lib/rpm/redhat/redhat-package-notes ::g') -Wno-unused-command-line-argument %global build_cxxflags %(echo %{build_cxxflags} | sed 's:-Werror ::g' | sed 's:-Wunused-command-line-argument ::g' | sed 's:-specs\=/usr/lib/rpm/redhat/redhat-annobin-cc1 ::g' | sed 's:-specs=/usr/lib/rpm/redhat/redhat-hardened-ld ::g' | sed 's:-specs=/usr/lib/rpm/redhat/redhat-hardened-ld-errors ::g' | sed 's:-specs=/usr/lib/rpm/redhat/redhat-package-notes ::g') -Wno-unused-command-line-argument -%global commit 0daa6d6fb085fbcedc97dd9b1b2827c9f4741715 -%global ver 0.0.37-18140 +%global commit 335ed8d91be36902fd47cf45c59ef0cc4caebf15 +%global ver 0.0.37-18143 Name: rpcs3 Version: %(echo %{ver} | sed 's/-/^/g') diff --git a/anda/games/terra-gamescope/handheld.patch b/anda/games/terra-gamescope/handheld.patch index 8db7c5ae35..abac2aba08 100755 --- a/anda/games/terra-gamescope/handheld.patch +++ b/anda/games/terra-gamescope/handheld.patch @@ -1,3 +1,2576 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton +Date: Thu, 21 Nov 2024 07:18:22 +0000 +Subject: Revert "steamcompmgr: Fix crash when using magnifier and game + recording" + +This reverts commit 611a47683f8304ae7a128347a2237df345482fcd. +--- + src/steamcompmgr.cpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index a8f44d1ef2da..0a1f2b263b21 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -1974,7 +1974,7 @@ paint_window_commit( const gamescope::Rc &lastCommit, steamcompmgr_win + drawYOffset += w->GetGeometry().nY * currentScaleRatio_y; + } + +- if ( cursor && zoomScaleRatio != 1.0 ) ++ if ( zoomScaleRatio != 1.0 ) + { + drawXOffset += (((int)sourceWidth / 2) - cursor->x()) * currentScaleRatio_x; + drawYOffset += (((int)sourceHeight / 2) - cursor->y()) * currentScaleRatio_y; +@@ -2200,10 +2200,10 @@ static void paint_pipewire() + s_ulLastOverrideCommitId = ulOverrideCommitId; + + // Paint the windows we have onto the Pipewire stream. +- paint_window( pFocus->focusWindow, pFocus->focusWindow, &frameInfo, global_focus.cursor, 0, 1.0f, pFocus->overrideWindow ); ++ paint_window( pFocus->focusWindow, pFocus->focusWindow, &frameInfo, nullptr, 0, 1.0f, pFocus->overrideWindow ); + + if ( pFocus->overrideWindow && !pFocus->focusWindow->isSteamStreamingClient ) +- paint_window( pFocus->overrideWindow, pFocus->focusWindow, &frameInfo, global_focus.cursor, PaintWindowFlag::NoFilter, 1.0f, pFocus->overrideWindow ); ++ paint_window( pFocus->overrideWindow, pFocus->focusWindow, &frameInfo, nullptr, PaintWindowFlag::NoFilter, 1.0f, pFocus->overrideWindow ); + + gamescope::Rc pRGBTexture = s_pPipewireBuffer->texture->isYcbcr() + ? vulkan_acquire_screenshot_texture( g_nOutputWidth, g_nOutputHeight, false, DRM_FORMAT_XRGB2101010 ) +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton +Date: Thu, 21 Nov 2024 07:19:00 +0000 +Subject: backend: Hack + +--- + src/backend.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/backend.cpp b/src/backend.cpp +index 8a6bbe8ed944..2411d4ebdc48 100644 +--- a/src/backend.cpp ++++ b/src/backend.cpp +@@ -56,7 +56,7 @@ namespace gamescope + CBaseBackendFb::~CBaseBackendFb() + { + // I do not own the client buffer, but I released that in DecRef. +- assert( !HasLiveReferences() ); ++ //assert( !HasLiveReferences() ); + } + + uint32_t CBaseBackendFb::IncRef() +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Fri, 31 Jan 2025 17:21:47 -0800 +Subject: layer: Fix 32-bit layer crash +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some fprintf pointers added in "layer: Fix oldSwapchain when going in/out +of XWayland bypassing" will crash when executed in the 32-bit WSI layer. + +GCC also warns about the pointer usage when compiling the 32-bit layer: +"warning: format ‘%p’ expects argument of type ‘void*’, but argument 3 +has type ‘VkSwapchainKHR’ {aka ‘long long unsigned int’} [-Wformat=]" + +To keep it simple, let's just reinterpret_cast the problematic pointers +to void*. + +Closes: #1718 +Closes: #1736 +--- + layer/VkLayer_FROG_gamescope_wsi.cpp | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp +index 718a2604f318..5bd1408bf780 100644 +--- a/layer/VkLayer_FROG_gamescope_wsi.cpp ++++ b/layer/VkLayer_FROG_gamescope_wsi.cpp +@@ -1076,9 +1076,9 @@ namespace GamescopeWSILayer { + gamescope_swapchain_destroy(state->object); + } + GamescopeSwapchain::remove(swapchain); +- fprintf(stderr, "[Gamescope WSI] Destroying swapchain: %p\n", swapchain); ++ fprintf(stderr, "[Gamescope WSI] Destroying swapchain: %p\n", reinterpret_cast(swapchain)); + pDispatch->DestroySwapchainKHR(device, swapchain, pAllocator); +- fprintf(stderr, "[Gamescope WSI] Destroyed swapchain: %p\n", swapchain); ++ fprintf(stderr, "[Gamescope WSI] Destroyed swapchain: %p\n", reinterpret_cast(swapchain)); + } + + static VkResult CreateSwapchainKHR( +@@ -1160,7 +1160,7 @@ namespace GamescopeWSILayer { + + fprintf(stderr, "[Gamescope WSI] Creating swapchain for xid: 0x%0x - oldSwapchain: %p - provided minImageCount: %u - minImageCount: %u - format: %s - colorspace: %s - flip: %s\n", + gamescopeSurface->window, +- pCreateInfo->oldSwapchain, ++ reinterpret_cast(pCreateInfo->oldSwapchain), + pCreateInfo->minImageCount, + minImageCount, + vkroots::helpers::enumString(pCreateInfo->imageFormat), +@@ -1241,7 +1241,7 @@ namespace GamescopeWSILayer { + + fprintf(stderr, "[Gamescope WSI] Created swapchain for xid: 0x%0x swapchain: %p - imageCount: %u\n", + gamescopeSurface->window, +- *pSwapchain, ++ reinterpret_cast(*pSwapchain), + imageCount); + + gamescope_swapchain_swapchain_feedback( +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Sun, 5 Jan 2025 11:05:42 +0900 +Subject: main: cleanup args + +--- + src/main.cpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/main.cpp b/src/main.cpp +index 9dff5c4d8560..cd251af559e1 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -70,6 +70,7 @@ const struct option *gamescope_options = (struct option[]){ + { "expose-wayland", no_argument, 0 }, + { "mouse-sensitivity", required_argument, nullptr, 's' }, + { "mangoapp", no_argument, nullptr, 0 }, ++ { "adaptive-sync", no_argument, nullptr, 0 }, + + { "backend", required_argument, nullptr, 0 }, + +@@ -88,7 +89,6 @@ const struct option *gamescope_options = (struct option[]){ + { "default-touch-mode", required_argument, nullptr, 0 }, + { "generate-drm-mode", required_argument, nullptr, 0 }, + { "immediate-flips", no_argument, nullptr, 0 }, +- { "adaptive-sync", no_argument, nullptr, 0 }, + { "framerate-limit", required_argument, nullptr, 0 }, + + // openvr options +@@ -203,6 +203,7 @@ const char usage[] = + " Default: 1000 nits, Max: 10000 nits\n" + " --framerate-limit Set a simple framerate limit. Used as a divisor of the refresh rate, rounds down eg 60 / 59 -> 60fps, 60 / 25 -> 30fps. Default: 0, disabled.\n" + " --mangoapp Launch with the mangoapp (mangohud) performance overlay enabled. You should use this instead of using mangohud on the game or gamescope.\n" ++ " --adaptive-sync Enable adaptive sync if available (variable rate refresh)\n" + "\n" + "Nested mode options:\n" + " -o, --nested-unfocused-refresh game refresh rate when unfocused\n" +@@ -213,11 +214,10 @@ const char usage[] = + " --display-index forces gamescope to use a specific display in nested mode." + "\n" + "Embedded mode options:\n" +- " -O, --prefer-output list of connectors in order of preference\n" ++ " -O, --prefer-output list of connectors in order of preference (ex: DP-1,DP-2,DP-3,HDMI-A-1)\n" + " --default-touch-mode 0: hover, 1: left, 2: right, 3: middle, 4: passthrough\n" + " --generate-drm-mode DRM mode generation algorithm (cvt, fixed)\n" + " --immediate-flips Enable immediate flips, may result in tearing\n" +- " --adaptive-sync Enable adaptive sync if available (variable rate refresh)\n" + "\n" + #if HAVE_OPENVR + "VR mode options:\n" +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Wed, 29 Jan 2025 11:16:47 +0100 +Subject: steamcompmgr: Set WM_STATE property on map and unmap notify events. + +This is mandated by the ICCCM specification and Wine now depends on it. +--- + src/steamcompmgr.cpp | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 0a1f2b263b21..2544acfb0501 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -3378,6 +3378,14 @@ found:; + return vecPossibleFocusWindows; + } + ++static void set_wm_state( xwayland_ctx_t *ctx, Window win, uint32_t state ) ++{ ++ uint32_t wmState[] = { state, None }; ++ XChangeProperty(ctx->dpy, win, ctx->atoms.WMStateAtom, ctx->atoms.WMStateAtom, 32, ++ PropModeReplace, (unsigned char *)wmState, ++ sizeof(wmState) / sizeof(wmState[0])); ++} ++ + void xwayland_ctx_t::DetermineAndApplyFocus( const std::vector< steamcompmgr_win_t* > &vecPossibleFocusWindows ) + { + xwayland_ctx_t *ctx = this; +@@ -3438,10 +3446,7 @@ void xwayland_ctx_t::DetermineAndApplyFocus( const std::vector< steamcompmgr_win + { + /* Some games (e.g. DOOM Eternal) don't react well to being put back as + * iconic, so never do that. Only take them out of iconic. */ +- uint32_t wmState[] = { ICCCM_NORMAL_STATE, None }; +- XChangeProperty(ctx->dpy, ctx->focus.focusWindow->xwayland().id, ctx->atoms.WMStateAtom, ctx->atoms.WMStateAtom, 32, +- PropModeReplace, (unsigned char *)wmState, +- sizeof(wmState) / sizeof(wmState[0])); ++ set_wm_state( ctx, ctx->focus.focusWindow->xwayland().id, ICCCM_NORMAL_STATE ); + + gpuvis_trace_printf( "determine_and_apply_focus focus %lu", ctx->focus.focusWindow->xwayland().id ); + +@@ -4227,6 +4232,8 @@ map_win(xwayland_ctx_t* ctx, Window id, unsigned long sequence) + } + + MakeFocusDirty(); ++ ++ set_wm_state( ctx, w->xwayland().id, ICCCM_NORMAL_STATE ); + } + + static void +@@ -4251,6 +4258,7 @@ unmap_win(xwayland_ctx_t *ctx, Window id, bool fade) + MakeFocusDirty(); + + finish_unmap_win(ctx, w); ++ set_wm_state( ctx, w->xwayland().id, ICCCM_WITHDRAWN_STATE ); + } + + uint32_t +@@ -4817,10 +4825,7 @@ handle_wm_change_state(xwayland_ctx_t *ctx, steamcompmgr_win_t *w, XClientMessag + * agreed on it; immediately revert to normal state to avoid being + * stuck in a paused state. */ + xwm_log.debugf("Rejecting WM_CHANGE_STATE to ICONIC for window 0x%lx", w->xwayland().id); +- uint32_t wmState[] = { ICCCM_NORMAL_STATE, None }; +- XChangeProperty(ctx->dpy, w->xwayland().id, ctx->atoms.WMStateAtom, ctx->atoms.WMStateAtom, 32, +- PropModeReplace, (unsigned char *)wmState, +- sizeof(wmState) / sizeof(wmState[0])); ++ set_wm_state( ctx, w->xwayland().id, ICCCM_NORMAL_STATE ); + } else { + xwm_log.debugf("Unhandled WM_CHANGE_STATE to %ld for window 0x%lx", state, w->xwayland().id); + } +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Tue, 1 Apr 2025 23:37:29 +0100 +Subject: rendervulkan: Fix scaled YUV coming out weird + +Our linear emulation doesn't fully support unnormalized right now. +--- + src/rendervulkan.hpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp +index d8a24e93795a..a3a11a7ba96f 100644 +--- a/src/rendervulkan.hpp ++++ b/src/rendervulkan.hpp +@@ -325,6 +325,9 @@ struct FrameInfo_t + } + + bool viewConvertsToLinearAutomatically() const { ++ if (isYcbcr()) ++ return true; ++ + return colorspace == GAMESCOPE_APP_TEXTURE_COLORSPACE_LINEAR || + colorspace == GAMESCOPE_APP_TEXTURE_COLORSPACE_SCRGB || + colorspace == GAMESCOPE_APP_TEXTURE_COLORSPACE_PASSTHRU; +@@ -362,7 +365,7 @@ struct FrameInfo_t + uint32_t result = 0; + for (int i = 0; i < layerCount; i++) + { +- result |= layers[ i ].colorspace << (i * GamescopeAppTextureColorspace_Bits); ++result |= layers[ i ].colorspace << (i * GamescopeAppTextureColorspace_Bits); + } + return result; + } +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Wed, 2 Apr 2025 01:09:56 +0100 +Subject: steamcompmgr: Fix pipewire stream being incorrect size on external + displays when scaled up + +--- + src/steamcompmgr.cpp | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 2544acfb0501..7371a3905b56 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -2199,6 +2199,17 @@ static void paint_pipewire() + s_ulLastFocusCommitId = ulFocusCommitId; + s_ulLastOverrideCommitId = ulOverrideCommitId; + ++ uint32_t uWidth = s_pPipewireBuffer->texture->width(); ++ uint32_t uHeight = s_pPipewireBuffer->texture->height(); ++ ++ const uint32_t uCompositeDebugBackup = g_uCompositeDebug; ++ const uint32_t uBackupWidth = currentOutputWidth; ++ const uint32_t uBackupHeight = currentOutputHeight; ++ ++ g_uCompositeDebug = 0; ++ currentOutputWidth = uWidth; ++ currentOutputHeight = uHeight; ++ + // Paint the windows we have onto the Pipewire stream. + paint_window( pFocus->focusWindow, pFocus->focusWindow, &frameInfo, nullptr, 0, 1.0f, pFocus->overrideWindow ); + +@@ -2206,13 +2217,11 @@ static void paint_pipewire() + paint_window( pFocus->overrideWindow, pFocus->focusWindow, &frameInfo, nullptr, PaintWindowFlag::NoFilter, 1.0f, pFocus->overrideWindow ); + + gamescope::Rc pRGBTexture = s_pPipewireBuffer->texture->isYcbcr() +- ? vulkan_acquire_screenshot_texture( g_nOutputWidth, g_nOutputHeight, false, DRM_FORMAT_XRGB2101010 ) ++ ? vulkan_acquire_screenshot_texture( uWidth, uHeight, false, DRM_FORMAT_XRGB2101010 ) + : gamescope::Rc{ s_pPipewireBuffer->texture }; + + gamescope::Rc pYUVTexture = s_pPipewireBuffer->texture->isYcbcr() ? s_pPipewireBuffer->texture : nullptr; + +- uint32_t uCompositeDebugBackup = g_uCompositeDebug; +- g_uCompositeDebug = 0; + + std::optional oPipewireSequence = vulkan_screenshot( &frameInfo, pRGBTexture, pYUVTexture ); + // If we ever want the fat compositing path, use this. +@@ -2220,6 +2229,9 @@ static void paint_pipewire() + + g_uCompositeDebug = uCompositeDebugBackup; + ++ currentOutputWidth = uBackupWidth; ++ currentOutputHeight = uBackupHeight; ++ + if ( oPipewireSequence ) + { + vulkan_wait( *oPipewireSequence, true ); +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Wed, 2 Apr 2025 01:55:47 +0100 +Subject: steamcompmgr: VRR frame limiting + +--- + src/steamcompmgr.cpp | 116 +++++++++++++++++++++++++++--------- + src/steamcompmgr_shared.hpp | 2 + + 2 files changed, 91 insertions(+), 27 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 7371a3905b56..d91cc45b5be5 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -898,10 +898,6 @@ bool g_bChangeDynamicRefreshBasedOnGameOpenRatherThanActive = false; + + bool steamcompmgr_window_should_limit_fps( steamcompmgr_win_t *w ) + { +- // VRR + FPS Limit needs another approach. +- if ( GetBackend()->IsVRRActive() ) +- return false; +- + return w && !window_is_steam( w ) && !w->isOverlay && !w->isExternalOverlay; + } + +@@ -5076,6 +5072,8 @@ steamcompmgr_flush_frame_done( steamcompmgr_win_t *w ) + w->unlockedForFrameCallback = false; + w->receivedDoneCommit = false; + ++ w->last_commit_first_latch_time = timespec_to_nanos(now); ++ + // Acknowledge commit once. + wlserver_lock(); + +@@ -5093,35 +5091,58 @@ steamcompmgr_flush_frame_done( steamcompmgr_win_t *w ) + } + } + +-static bool steamcompmgr_should_vblank_window( bool bShouldLimitFPS, uint64_t vblank_idx ) +-{ +- if ( GetBackend()->IsVRRActive() ) +- return true; ++static std::optional s_oLowestFPSLimitScheduleVRR; + ++static bool steamcompmgr_should_vblank_window( bool bShouldLimitFPS, uint64_t vblank_idx, steamcompmgr_win_t *w = nullptr, uint64_t now = 0 ) ++{ + bool bSendCallback = true; + + int nRefreshHz = gamescope::ConvertmHzToHz( g_nNestedRefresh ? g_nNestedRefresh : g_nOutputRefresh ); + int nTargetFPS = g_nSteamCompMgrTargetFPS; +- if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && nRefreshHz > nTargetFPS ) ++ ++ if ( GetBackend()->IsVRRActive() ) + { +- int nVblankDivisor = nRefreshHz / nTargetFPS; ++ bool bCloseEnough = std::abs( g_nSteamCompMgrTargetFPS - nRefreshHz ) < 2; ++ ++ if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && w && !bCloseEnough ) ++ { ++ uint64_t schedule = w->last_commit_first_latch_time + g_SteamCompMgrLimitedAppRefreshCycle; ++ ++ static constexpr uint64_t k_ulVRRScheduleFudge = 200'000; // 0.2ms ++ if ( now + k_ulVRRScheduleFudge < schedule ) ++ { ++ bSendCallback = false; + +- if ( vblank_idx % nVblankDivisor != 0 ) +- bSendCallback = false; ++ if ( !s_oLowestFPSLimitScheduleVRR ) ++ s_oLowestFPSLimitScheduleVRR = schedule; ++ else ++ s_oLowestFPSLimitScheduleVRR = std::min( *s_oLowestFPSLimitScheduleVRR, schedule ); ++ } ++ } ++ } ++ else ++ { ++ if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && nRefreshHz > nTargetFPS ) ++ { ++ int nVblankDivisor = nRefreshHz / nTargetFPS; ++ ++ if ( vblank_idx % nVblankDivisor != 0 ) ++ bSendCallback = false; ++ } + } + + return bSendCallback; + } + +-static bool steamcompmgr_should_vblank_window( steamcompmgr_win_t *w, uint64_t vblank_idx ) ++static bool steamcompmgr_should_vblank_window( steamcompmgr_win_t *w, uint64_t vblank_idx, uint64_t now ) + { +- return steamcompmgr_should_vblank_window( steamcompmgr_window_should_limit_fps( w ), vblank_idx ); ++ return steamcompmgr_should_vblank_window( steamcompmgr_window_should_limit_fps( w ), vblank_idx, w, now ); + } + + static void +-steamcompmgr_latch_frame_done( steamcompmgr_win_t *w, uint64_t vblank_idx ) ++steamcompmgr_latch_frame_done( steamcompmgr_win_t *w, uint64_t vblank_idx, uint64_t now ) + { +- if ( steamcompmgr_should_vblank_window( w, vblank_idx ) ) ++ if ( steamcompmgr_should_vblank_window( w, vblank_idx, now ) ) + { + w->unlockedForFrameCallback = true; + } +@@ -6145,12 +6166,27 @@ void handle_done_commits_xwayland( xwayland_ctx_t *ctx, bool vblank, uint64_t vb + + uint64_t now = get_time_in_nanos(); + +- vblank = vblank && steamcompmgr_should_vblank_window( true, vblank_idx ); +- + // very fast loop yes + for ( auto& entry : ctx->doneCommits.listCommitsDone ) + { +- if (entry.fifo && (!vblank || fifo_win_seqs.count(entry.winSeq) > 0)) ++ bool entry_vblank = vblank; ++ ++ if ( GetBackend()->IsVRRActive() ) ++ { ++ for ( steamcompmgr_win_t *w = ctx->list; w; w = w->xwayland().next ) ++ { ++ if (w->seq != entry.winSeq) ++ continue; ++ ++ entry_vblank = entry_vblank && steamcompmgr_should_vblank_window( true, vblank_idx, w, now ); ++ } ++ } ++ else ++ { ++ entry_vblank = entry_vblank && steamcompmgr_should_vblank_window( true, vblank_idx ); ++ } ++ ++ if (entry.fifo && (!entry_vblank || fifo_win_seqs.count(entry.winSeq) > 0)) + { + commits_before_their_time.push_back( entry ); + continue; +@@ -7414,6 +7450,11 @@ void LaunchNestedChildren( char **ppPrimaryChildArgv ) + } + } + ++static gamescope::CTimerFunction g_FPSLimitVRRTimer{ [] ++{ ++ // do nothing. ++}}; ++ + void + steamcompmgr_main(int argc, char **argv) + { +@@ -7547,6 +7588,7 @@ steamcompmgr_main(int argc, char **argv) + } + + g_SteamCompMgrWaiter.AddWaitable( &GetVBlankTimer() ); ++ g_SteamCompMgrWaiter.AddWaitable( &g_FPSLimitVRRTimer ); + GetVBlankTimer().ArmNextVBlank( true ); + + { +@@ -7722,18 +7764,20 @@ steamcompmgr_main(int argc, char **argv) + if ( vblank ) + { + { ++ uint64_t now = get_time_in_nanos(); ++ + gamescope_xwayland_server_t *server = NULL; + for (size_t i = 0; (server = wlserver_get_xwayland_server(i)); i++) + { + for (steamcompmgr_win_t *w = server->ctx->list; w; w = w->xwayland().next) + { +- steamcompmgr_latch_frame_done( w, vblank_idx ); ++ steamcompmgr_latch_frame_done( w, vblank_idx, now ); + } + } + + for ( const auto& xdg_win : g_steamcompmgr_xdg_wins ) + { +- steamcompmgr_latch_frame_done( xdg_win.get(), vblank_idx ); ++ steamcompmgr_latch_frame_done( xdg_win.get(), vblank_idx, now ); + } + } + } +@@ -7757,18 +7801,36 @@ steamcompmgr_main(int argc, char **argv) + + steamcompmgr_check_xdg(vblank, vblank_idx); + ++ if ( s_oLowestFPSLimitScheduleVRR ) ++ { ++ g_FPSLimitVRRTimer.ArmTimer( *s_oLowestFPSLimitScheduleVRR ); ++ s_oLowestFPSLimitScheduleVRR = std::nullopt; ++ } ++ + if ( vblank ) + { + vblank_idx++; + + int nRealRefreshmHz = g_nNestedRefresh ? g_nNestedRefresh : g_nOutputRefresh; +- int nRealRefreshHz = gamescope::ConvertmHzToHz( nRealRefreshmHz ); +- int nTargetFPS = g_nSteamCompMgrTargetFPS ? g_nSteamCompMgrTargetFPS : nRealRefreshHz; +- nTargetFPS = std::min( nTargetFPS, nRealRefreshHz ); +- int nVblankDivisor = nRealRefreshHz / nTargetFPS; +- + g_SteamCompMgrAppRefreshCycle = gamescope::mHzToRefreshCycle( nRealRefreshmHz ); +- g_SteamCompMgrLimitedAppRefreshCycle = g_SteamCompMgrAppRefreshCycle * nVblankDivisor; ++ g_SteamCompMgrLimitedAppRefreshCycle = g_SteamCompMgrAppRefreshCycle; ++ if ( g_nSteamCompMgrTargetFPS ) ++ { ++ int nRealRefreshHz = gamescope::ConvertmHzToHz( nRealRefreshmHz ); ++ int nTargetFPS = g_nSteamCompMgrTargetFPS; ++ nTargetFPS = std::min( nTargetFPS, nRealRefreshHz ); ++ ++ if ( GetBackend()->IsVRRActive() ) ++ { ++ g_SteamCompMgrLimitedAppRefreshCycle = gamescope::mHzToRefreshCycle( gamescope::ConvertHztomHz( nTargetFPS ) ); ++ } ++ else ++ { ++ int nVblankDivisor = nRealRefreshHz / nTargetFPS; ++ ++ g_SteamCompMgrLimitedAppRefreshCycle = g_SteamCompMgrAppRefreshCycle * nVblankDivisor; ++ } ++ } + } + + // Handle presentation-time stuff +diff --git a/src/steamcompmgr_shared.hpp b/src/steamcompmgr_shared.hpp +index 095694e4937a..f300eb94d954 100644 +--- a/src/steamcompmgr_shared.hpp ++++ b/src/steamcompmgr_shared.hpp +@@ -127,6 +127,8 @@ struct steamcompmgr_win_t { + bool maybe_a_dropdown = false; + bool outdatedInteractiveFocus = false; + ++ uint64_t last_commit_first_latch_time = 0; ++ + bool hasHwndStyle = false; + uint32_t hwndStyle = 0; + bool hasHwndStyleEx = false; +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Colin Kinloch +Date: Sat, 21 Dec 2024 17:08:12 +0000 +Subject: scripts: Derive script path from meson prefix + +--- + meson.build | 1 + + src/Script/Script.cpp | 2 +- + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index c4924c7afb44..00a1cb42bde4 100644 +--- a/meson.build ++++ b/meson.build +@@ -68,6 +68,7 @@ endif + add_project_arguments( + '-DHAVE_PIPEWIRE=@0@'.format(pipewire_dep.found().to_int()), + '-DHAVE_OPENVR=@0@'.format(openvr_dep.found().to_int()), ++ '-DSCRIPT_DIR="@0@"'.format(prefix / data_dir / 'gamescope/scripts'), + language: 'cpp', + ) + +diff --git a/src/Script/Script.cpp b/src/Script/Script.cpp +index a104ee993bc9..142371b33e0f 100644 +--- a/src/Script/Script.cpp ++++ b/src/Script/Script.cpp +@@ -130,7 +130,7 @@ namespace gamescope + } + else + { +- RunFolder( "/usr/share/gamescope/scripts", true ); ++ RunFolder( SCRIPT_DIR, true ); + RunFolder( "/etc/gamescope/scripts", true ); + } + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Wed, 30 Oct 2024 14:56:18 -0700 +Subject: script: Lenovo Legion Go LCD display configuration + +Add support for the Lenovo Legion Go handheld, which features a rotated +1600x2560 panel that reports 60Hz and 144Hz modes in the EDID. VRR and +HDR are not supported, and only one panel model is known to be in use. + +Modes other than 60Hz and 144Hz have a small chance of causing a locked +touchscreen until another modeset is performed or have artifacts during +modesetting, so extra modes are not included. The dynamic_modegen section +is filled out in case users decide to add their own refresh rates in a +local table. + +This configuration has been tested with: +* SteamOS Main 20241025.1000 with kernel 6.8.12-valve3 +* Arch Linux with kernel 6.12-rc5 + +Signed-off-by: Matthew Schwartz +--- + .../displays/lenovo.legiongo.lcd.lua | 45 +++++++++++++++++++ + 1 file changed, 45 insertions(+) + create mode 100644 scripts/00-gamescope/displays/lenovo.legiongo.lcd.lua + +diff --git a/scripts/00-gamescope/displays/lenovo.legiongo.lcd.lua b/scripts/00-gamescope/displays/lenovo.legiongo.lcd.lua +new file mode 100644 +index 000000000000..2360cfe35cb2 +--- /dev/null ++++ b/scripts/00-gamescope/displays/lenovo.legiongo.lcd.lua +@@ -0,0 +1,45 @@ ++gamescope.config.known_displays.lenovo_legiongo_lcd = { ++ pretty_name = "Lenovo Legion Go LCD", ++ dynamic_refresh_rates = { ++ 60, 144 ++ }, ++ hdr = { ++ -- Setup some fallbacks for undocking with HDR, meant ++ -- for the internal panel. It does not support HDR. ++ supported = false, ++ force_enabled = false, ++ eotf = gamescope.eotf.gamma22, ++ max_content_light_level = 500, ++ max_frame_average_luminance = 500, ++ min_content_light_level = 0.5 ++ }, ++ -- Use the EDID colorimetry for now, but someone should check ++ -- if the EDID colorimetry truly matches what the display is capable of. ++ dynamic_modegen = function(base_mode, refresh) ++ debug("Generating mode "..refresh.."Hz for Lenovo Legion Go LCD") ++ local mode = base_mode ++ ++ -- These are only tuned for 1600x2560 ++ gamescope.modegen.set_resolution(mode, 1600, 2560) ++ ++ -- Horizontal timings: Hfront, Hsync, Hback ++ gamescope.modegen.set_h_timings(mode, 60, 30, 130) ++ -- Vertical timings: Vfront, Vsync, Vback ++ gamescope.modegen.set_v_timings(mode, 30, 4, 96) ++ ++ mode.clock = gamescope.modegen.calc_max_clock(mode, refresh) ++ mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) ++ ++ return mode ++ end, ++ matches = function(display) ++ -- There is only a single panel in use on the Lenovo Legion Go. ++ if display.vendor == "LEN" and display.model == "Go Display" and display.product == 0x0001 then ++ debug("[lenovo_legiongo_lcd] Matched vendor: "..display.vendor.." model: "..display.model.." product: "..display.product) ++ return 5000 ++ end ++ return -1 ++ end ++} ++debug("Registered Lenovo Legion Go LCD as a known display") ++--debug(inspect(gamescope.config.known_displays.lenovo_legiongo_lcd)) +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aarron Lee +Date: Wed, 9 Oct 2024 23:19:15 -0400 +Subject: script: GPD Win 4 display configuration + +This introduces a display configuration for the GPD Win 4 handheld. + +Most of this display configuration was derived from the edid as-is, +excluding the dynamic_refresh_rates. + +All refresh rates were all manually tested with the Steam slider, +and the device functioned as expected through multiple games. + +This was tested on two separate GPD Win 4 devices. + +Tested on: + +Model DMI + - G1618-04 +Distro + - Bazzite 40 +Kernels + - 6.9.12-210.fsync.fc40.x86_64 + - 6.11.2-201.fsync.fc40.x86_64 + +All refresh rates were tested with the following games: + +- Ghost of Tsushima +- Nier Automata +- Metaphor: ReFantazio (Demo) +- Boomerang Fu + +These games were tested with 35hz, 40hz, 50hz, +and had no observed issues: + +- Crosscode +- Cult of Lamb +- Dave the Diver +- MDA Rain Code Plus +- Shantae and the Seven Sirens +--- + .../00-gamescope/displays/gpd.win4.lcd.lua | 60 +++++++++++++++++++ + 1 file changed, 60 insertions(+) + create mode 100644 scripts/00-gamescope/displays/gpd.win4.lcd.lua + +diff --git a/scripts/00-gamescope/displays/gpd.win4.lcd.lua b/scripts/00-gamescope/displays/gpd.win4.lcd.lua +new file mode 100644 +index 000000000000..5f5eec898c3b +--- /dev/null ++++ b/scripts/00-gamescope/displays/gpd.win4.lcd.lua +@@ -0,0 +1,60 @@ ++-- colorimetry from edid ++local gpd_win4_lcd_colorimetry = { ++ r = { x = 0.6250, y = 0.3398 }, ++ g = { x = 0.2802, y = 0.5947 }, ++ b = { x = 0.1552, y = 0.0703 }, ++ w = { x = 0.2832, y = 0.2978 } ++} ++ ++gamescope.config.known_displays.gpd_win4_lcd = { ++ pretty_name = "GPD Win 4", ++ dynamic_refresh_rates = { ++ 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, ++ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, ++ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60 ++ }, ++ hdr = { ++ supported = false, ++ force_enabled = false, ++ eotf = gamescope.eotf.gamma22, ++ max_content_light_level = 400, ++ max_frame_average_luminance = 400, ++ min_content_light_level = 0.5 ++ }, ++ colorimetry = gpd_win4_lcd_colorimetry, ++ dynamic_modegen = function(base_mode, refresh) ++ debug("Generating mode "..refresh.."Hz for GPD Win 4") ++ local mode = base_mode ++ ++ gamescope.modegen.set_resolution(mode, 1920, 1080) ++ ++ -- Horizontal timings: Hfront, Hsync, Hback ++ gamescope.modegen.set_h_timings(mode, 72, 8, 16) ++ -- Vertical timings: Vfront, Vsync, Vback ++ gamescope.modegen.set_v_timings(mode, 14, 3, 13) ++ ++ mode.clock = gamescope.modegen.calc_max_clock(mode, refresh) ++ mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) ++ ++ return mode ++ end, ++ matches = function(display) ++ -- There are multiple revisions of the GPD Win 4 ++ -- They all should have the same panel ++ -- lcd_types is just in case there are different panels ++ local lcd_types = { ++ { vendor = "GPD", model = "G1618-04" }, ++ } ++ ++ for index, value in ipairs(lcd_types) do ++ if value.vendor == display.vendor and value.model == display.model then ++ debug("[gpd_win4_lcd] Matched vendor: "..value.vendor.." model: "..value.model) ++ return 5000 ++ end ++ end ++ ++ return -1 ++ end ++} ++debug("Registered GPD Win 4 as a known display") ++--debug(inspect(gamescope.config.known_displays.gpd_win4_lcd)) +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Wed, 2 Apr 2025 03:15:44 +0100 +Subject: DRMBackend: Read the EDID's modes for dynamic refresh rate modes by + default + +Should supercede https://github.com/ValveSoftware/gamescope/pull/1627 and allow this feature on some handhelds that just expose modes in the EDID. +--- + src/Backends/DRMBackend.cpp | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp +index 0b121e84167a..37185856b7ec 100644 +--- a/src/Backends/DRMBackend.cpp ++++ b/src/Backends/DRMBackend.cpp +@@ -2142,6 +2142,8 @@ namespace gamescope + bool bHasKnownColorimetry = false; + bool bHasKnownHDRInfo = false; + ++ m_Mutable.ValidDynamicRefreshRates.clear(); ++ m_Mutable.fnDynamicModeGenerator = nullptr; + { + CScriptScopedLock script; + +@@ -2155,8 +2157,6 @@ namespace gamescope + (int)oKnownDisplay->first.size(), oKnownDisplay->first.data(), + (int)psvPrettyName.size(), psvPrettyName.data() ); + +- m_Mutable.fnDynamicModeGenerator = nullptr; +- m_Mutable.ValidDynamicRefreshRates.clear(); + + sol::optional otDynamicRefreshRates = tTable["dynamic_refresh_rates"]; + sol::optional ofnDynamicModegen = tTable["dynamic_modegen"]; +@@ -2243,6 +2243,34 @@ namespace gamescope + bHasKnownHDRInfo = true; + } + } ++ else ++ { ++ // Unknown display, see if there are any other refresh rates in the EDID we can get. ++ if ( GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL ) ++ { ++ const drmModeModeInfo *pPreferredMode = find_mode( m_pConnector.get(), 0, 0, 0 ); ++ ++ if ( pPreferredMode ) ++ { ++ // See if the EDID has any modes for us. ++ for (int i = 0; i < m_pConnector->count_modes; i++) ++ { ++ const drmModeModeInfo *pMode = &m_pConnector->modes[i]; ++ ++ if ( pMode->hdisplay != pPreferredMode->hdisplay || pMode->vdisplay != pPreferredMode->vdisplay ) ++ continue; ++ ++ ++ if ( !Algorithm::Contains( m_Mutable.ValidDynamicRefreshRates, pMode->vrefresh ) ) ++ { ++ m_Mutable.ValidDynamicRefreshRates.push_back( pMode->vrefresh ); ++ } ++ } ++ ++ std::sort( m_Mutable.ValidDynamicRefreshRates.begin(), m_Mutable.ValidDynamicRefreshRates.end() ); ++ } ++ } ++ } + } + + if ( !bHasKnownColorimetry ) +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: sharkautarch <128002472+sharkautarch@users.noreply.github.com> +Date: Tue, 3 Dec 2024 13:31:37 -0500 +Subject: wlserver: wlserver_run(): ensure waylock is released when + wl_event_loop_dispatch returns ret<0 + +--- + src/wlserver.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/wlserver.cpp b/src/wlserver.cpp +index 78a86ee0e2e2..4ce9511352d0 100644 +--- a/src/wlserver.cpp ++++ b/src/wlserver.cpp +@@ -1956,6 +1956,7 @@ void wlserver_run(void) + wl_display_flush_clients(wlserver.display); + int ret = wl_event_loop_dispatch(wlserver.event_loop, 0); + if (ret < 0) { ++ wlserver_unlock(); + break; + } + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Wed, 2 Apr 2025 04:29:16 +0100 +Subject: DRMBackend: Expose data string from EDID to matches function + +--- + src/Backends/DRMBackend.cpp | 12 ++++++++++-- + src/Script/Script.cpp | 3 ++- + src/Script/Script.h | 2 +- + 3 files changed, 13 insertions(+), 4 deletions(-) + +diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp +index 37185856b7ec..06ebbe7255d4 100644 +--- a/src/Backends/DRMBackend.cpp ++++ b/src/Backends/DRMBackend.cpp +@@ -287,6 +287,7 @@ namespace gamescope + const char *GetName() const override { return m_Mutable.szName; } + const char *GetMake() const override { return m_Mutable.pszMake; } + const char *GetModel() const override { return m_Mutable.szModel; } ++ const char *GetDataString() const { return m_Mutable.szDataString; } + uint32_t GetPossibleCRTCMask() const { return m_Mutable.uPossibleCRTCMask; } + std::span GetValidDynamicRefreshRates() const override { return m_Mutable.ValidDynamicRefreshRates; } + const displaycolorimetry_t& GetDisplayColorimetry() const { return m_Mutable.DisplayColorimetry; } +@@ -392,6 +393,7 @@ namespace gamescope + char szName[32]{}; + char szMakePNP[4]{}; + char szModel[16]{}; ++ char szDataString[16]{}; + const char *pszMake = ""; // Not owned, no free. This is a pointer to pnp db or szMakePNP. + std::vector ValidDynamicRefreshRates{}; + DRMModeGenerator fnDynamicModeGenerator; +@@ -2128,13 +2130,19 @@ namespace gamescope + for ( size_t i = 0; pDescriptors[i] != nullptr; i++ ) + { + const di_edid_display_descriptor *pDesc = pDescriptors[i]; +- if ( di_edid_display_descriptor_get_tag( pDesc ) == DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_NAME ) ++ const di_edid_display_descriptor_tag eTag = di_edid_display_descriptor_get_tag( pDesc ); ++ if ( eTag == DI_EDID_DISPLAY_DESCRIPTOR_PRODUCT_NAME ) + { + // Max length of di_edid_display_descriptor_get_string is 14 + // m_szModel is 16 bytes. + const char *pszModel = di_edid_display_descriptor_get_string( pDesc ); + strncpy( m_Mutable.szModel, pszModel, sizeof( m_Mutable.szModel ) ); + } ++ else if ( eTag == DI_EDID_DISPLAY_DESCRIPTOR_DATA_STRING ) ++ { ++ const char *pszDataString = di_edid_display_descriptor_get_string( pDesc ); ++ strncpy( m_Mutable.szDataString, pszDataString, sizeof( m_Mutable.szDataString ) ); ++ } + } + + drm_log.infof("Connector %s -> %s - %s", m_Mutable.szName, m_Mutable.szMakePNP, m_Mutable.szModel ); +@@ -2147,7 +2155,7 @@ namespace gamescope + { + CScriptScopedLock script; + +- auto oKnownDisplay = script.Manager().Gamescope().Config.LookupDisplay( script, m_Mutable.szMakePNP, pProduct->product, m_Mutable.szModel ); ++ auto oKnownDisplay = script.Manager().Gamescope().Config.LookupDisplay( script, m_Mutable.szMakePNP, pProduct->product, m_Mutable.szModel, m_Mutable.szDataString ); + if ( oKnownDisplay ) + { + sol::table tTable = oKnownDisplay->second; +diff --git a/src/Script/Script.cpp b/src/Script/Script.cpp +index 142371b33e0f..ceb1f80e3a77 100644 +--- a/src/Script/Script.cpp ++++ b/src/Script/Script.cpp +@@ -247,7 +247,7 @@ namespace gamescope + // GamescopeScript_t + // + +- std::optional> GamescopeScript_t::Config_t::LookupDisplay( CScriptScopedLock &script, std::string_view psvVendor, uint16_t uProduct, std::string_view psvModel ) ++ std::optional> GamescopeScript_t::Config_t::LookupDisplay( CScriptScopedLock &script, std::string_view psvVendor, uint16_t uProduct, std::string_view psvModel, std::string_view psvDataString ) + { + int nMaxPrority = -1; + std::optional> oOutDisplay; +@@ -256,6 +256,7 @@ namespace gamescope + tDisplay["vendor"] = psvVendor; + tDisplay["product"] = uProduct; + tDisplay["model"] = psvModel; ++ tDisplay["data_string"] = psvDataString; + + for ( auto iter : KnownDisplays ) + { +diff --git a/src/Script/Script.h b/src/Script/Script.h +index 6eebb66a9f36..7c856a75e512 100644 +--- a/src/Script/Script.h ++++ b/src/Script/Script.h +@@ -30,7 +30,7 @@ namespace gamescope + + sol::table KnownDisplays; + +- std::optional> LookupDisplay( CScriptScopedLock &script, std::string_view psvVendor, uint16_t uProduct, std::string_view psvModel ); ++ std::optional> LookupDisplay( CScriptScopedLock &script, std::string_view psvVendor, uint16_t uProduct, std::string_view psvModel, std::string_view psvDataString ); + } Config; + }; + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "Pierre-Loup A. Griffais" +Date: Tue, 15 Apr 2025 15:56:02 -0700 +Subject: steamcompmgr: avoid a crash with pipewire+magnification + +It won't render the correct offset for now, but that's better than crashing. + +Probably magnification should be ignore when painting for pipewire? +--- + src/steamcompmgr.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index d91cc45b5be5..d0a069e69c60 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -1972,8 +1972,8 @@ paint_window_commit( const gamescope::Rc &lastCommit, steamcompmgr_win + + if ( zoomScaleRatio != 1.0 ) + { +- drawXOffset += (((int)sourceWidth / 2) - cursor->x()) * currentScaleRatio_x; +- drawYOffset += (((int)sourceHeight / 2) - cursor->y()) * currentScaleRatio_y; ++ drawXOffset += (((int)sourceWidth / 2) - (cursor ? cursor->x() : 0)) * currentScaleRatio_x; ++ drawYOffset += (((int)sourceHeight / 2) - (cursor ? cursor->y() : 0)) * currentScaleRatio_y; + } + } + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Sun, 6 Apr 2025 20:35:54 -0700 +Subject: build: add workaround to build with CMake 4.0 + +OpenVR's CMakelist does not support CMake 4.0 yet, causing build failures +in gamescope. Until a new OpenVR SDK is released, let's make sure gamescope +stays buildable in the meantime with a workaround which can be removed in +the future. + +Closes: #1785 +--- + meson.build | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/meson.build b/meson.build +index 00a1cb42bde4..cc07a59ca99a 100644 +--- a/meson.build ++++ b/meson.build +@@ -55,7 +55,10 @@ if get_option('enable_openvr_support') + if not openvr_dep.found() + cmake = import('cmake') + openvr_var = cmake.subproject_options() +- openvr_var.add_cmake_defines({'USE_LIBCXX': false}) ++ openvr_var.add_cmake_defines({'USE_LIBCXX': false, ++ #HACK: remove me when openvr supports CMake 4.0 ++ 'CMAKE_POLICY_VERSION_MINIMUM': '3.5'}) ++ #ENDHACK + openvr_var.set_override_option('warning_level', '0') + openvr_proj = cmake.subproject('openvr', options : openvr_var) + openvr_dep = openvr_proj.dependency('openvr_api') +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Fri, 25 Apr 2025 16:17:00 +0100 +Subject: WaylandBackend: Fix initial scale for Wayland surfaces + +--- + src/Backends/WaylandBackend.cpp | 26 ++++++++++++++++++++++---- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp +index 08af8bca1b99..da43d03987a8 100644 +--- a/src/Backends/WaylandBackend.cpp ++++ b/src/Backends/WaylandBackend.cpp +@@ -272,6 +272,7 @@ namespace gamescope + std::vector m_pOutputs; + bool m_bNeedsDecorCommit = false; + uint32_t m_uFractionalScale = 120; ++ bool m_bHasRecievedScale = false; + + std::mutex m_PlaneStateLock; + std::optional m_oCurrentPlaneState; +@@ -1358,14 +1359,31 @@ namespace gamescope + + void CWaylandPlane::Wayland_FractionalScale_PreferredScale( wp_fractional_scale_v1 *pFractionalScale, uint32_t uScale ) + { +- if ( m_uFractionalScale != uScale ) ++ bool bDirty = false; ++ ++ static uint32_t s_uGlobalFractionalScale = 120; ++ if ( s_uGlobalFractionalScale != uScale ) + { +- g_nOutputWidth = ( g_nOutputWidth * uScale ) / m_uFractionalScale; +- g_nOutputHeight = ( g_nOutputHeight * uScale ) / m_uFractionalScale; ++ if ( m_bHasRecievedScale ) ++ { ++ g_nOutputWidth = ( g_nOutputWidth * uScale ) / m_uFractionalScale; ++ g_nOutputHeight = ( g_nOutputHeight * uScale ) / m_uFractionalScale; ++ } ++ ++ s_uGlobalFractionalScale = uScale; ++ bDirty = true; ++ } + ++ if ( m_uFractionalScale != uScale ) ++ { + m_uFractionalScale = uScale; +- force_repaint(); ++ bDirty = true; + } ++ ++ m_bHasRecievedScale = true; ++ ++ if ( bDirty ) ++ force_repaint(); + } + + //////////////// +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= +Date: Wed, 9 Apr 2025 14:01:13 -0700 +Subject: rendervulkan: Append VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA + when creating scanout VkImages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It already appends VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA when +creating scanout images to make other Vulkan drivers works, so lets +also append VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA to make +ANV+Xe KMD work. + +Signed-off-by: José Roberto de Souza +--- + src/rendervulkan.cpp | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp +index 7efcc0dbd8a9..b8412b8fdf2f 100644 +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -163,6 +163,7 @@ Target *pNextFind(const Base *base, VkStructureType sType) + } + + #define VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA (VkStructureType)1000001002 ++#define VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA (VkStructureType)1000001003 + + struct wsi_image_create_info { + VkStructureType sType; +@@ -173,6 +174,11 @@ struct wsi_image_create_info { + const uint64_t *modifiers; + }; + ++struct wsi_memory_allocate_info { ++ VkStructureType sType; ++ const void *pNext; ++ bool implicit_sync; ++}; + + // DRM doesn't have 32bit floating point formats, so add our own + #define DRM_FORMAT_ABGR32323232F fourcc_code('A', 'B', '8', 'F') +@@ -2215,6 +2221,15 @@ bool CVulkanTexture::BInit( uint32_t width, uint32_t height, uint32_t depth, uin + VkImportMemoryFdInfoKHR importMemoryInfo = {}; + VkExportMemoryAllocateInfo memory_export_info = {}; + VkMemoryDedicatedAllocateInfo memory_dedicated_info = {}; ++ struct wsi_memory_allocate_info memory_wsi_info = {}; ++ ++ if ( flags.bFlippable == true ) ++ { ++ memory_wsi_info = { ++ .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, ++ .pNext = std::exchange(allocInfo.pNext, &memory_wsi_info), ++ }; ++ } + + if ( flags.bExportable == true || pDMA != nullptr ) + { +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MithicSpirit +Date: Thu, 30 Jan 2025 15:54:26 -0500 +Subject: WaylandBackend: prevent crash after closing window + +Whenever a window was closed, gamescope would segfault due to calling +IsSurfacePlane with null (from Wayland_Pointer_Leave, and maybe a few +other places). This is addressed by having IsSurfacePlane short-circuit +if it's passed null. + +HACK: I feel like IsSurfacePlane shouldn't ever be called with a null +pointer, but this is the easiest way to solve this for now, and the code +needs refactoring anyway. +--- + src/Backends/WaylandBackend.cpp | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp +index da43d03987a8..22f8ee5c8fac 100644 +--- a/src/Backends/WaylandBackend.cpp ++++ b/src/Backends/WaylandBackend.cpp +@@ -75,7 +75,9 @@ static inline uint32_t WaylandScaleToLogical( uint32_t pValue, uint32_t pFactor + } + + static bool IsSurfacePlane( wl_surface *pSurface ) { +- return wl_proxy_get_tag( (wl_proxy *)pSurface ) == &GAMESCOPE_plane_tag; ++ // HACK: this probably should never be called with a null pointer, but it ++ // was happening after a window was closed. ++ return pSurface && (wl_proxy_get_tag( (wl_proxy *)pSurface ) == &GAMESCOPE_plane_tag); + } + + #define WAYLAND_NULL() [] ( void *pData, Args... args ) { } +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Tue, 1 Apr 2025 23:03:56 -0700 +Subject: script: fixup Ally config to support BOE panels + +Also made some style fixups. Verified working on both BOE +and TMX panel models. +--- + .../displays/asus.rogally.lcd.lua | 35 ++++++++++++------- + 1 file changed, 23 insertions(+), 12 deletions(-) + +diff --git a/scripts/00-gamescope/displays/asus.rogally.lcd.lua b/scripts/00-gamescope/displays/asus.rogally.lcd.lua +index 11ba7cc30f9b..40b5188b5c73 100644 +--- a/scripts/00-gamescope/displays/asus.rogally.lcd.lua ++++ b/scripts/00-gamescope/displays/asus.rogally.lcd.lua +@@ -10,7 +10,7 @@ local rogally_lcd_refresh_rates = { + } + + gamescope.config.known_displays.rogally_lcd = { +- pretty_name = "ASUS ROG Ally/Ally X LCD", ++ pretty_name = "ASUS ROG Ally / ROG Ally X LCD", + hdr = { + -- Setup some fallbacks for undocking with HDR, meant + -- for the internal panel. It does not support HDR. +@@ -21,16 +21,14 @@ gamescope.config.known_displays.rogally_lcd = { + max_frame_average_luminance = 500, + min_content_light_level = 0.5 + }, +- -- Use the EDID colorimetry for now, but someone should check +- -- if the EDID colorimetry truly matches what the display is capable of. + dynamic_refresh_rates = rogally_lcd_refresh_rates, +- -- Follow the Steam Deck OLED style for modegen by variang the VFP (Vertical Front Porch) ++ -- Follow the Steam Deck OLED style for modegen by varying the VFP (Vertical Front Porch) + -- + -- Given that this display is VRR and likely has an FB/Partial FB in the DDIC: + -- it should be able to handle this method, and it is more optimal for latency + -- than elongating the clock. + dynamic_modegen = function(base_mode, refresh) +- debug("Generating mode "..refresh.."Hz for ROG Ally with fixed pixel clock") ++ debug("Generating mode "..refresh.."Hz for ASUS ROG Ally / ROG Ally X LCD with fixed pixel clock") + local vfps = { + 1771, 1720, 1655, 1600, 1549, + 1499, 1455, 1405, 1361, 1320, +@@ -50,7 +48,7 @@ gamescope.config.known_displays.rogally_lcd = { + } + local vfp = vfps[zero_index(refresh - 48)] + if vfp == nil then +- warn("Couldn't do refresh "..refresh.." on ROG Ally") ++ warn("Couldn't do refresh "..refresh.." on ASUS ROG Ally / ROG Ally X LCD") + return base_mode + end + +@@ -62,15 +60,28 @@ gamescope.config.known_displays.rogally_lcd = { + --debug(inspect(mode)) + return mode + end, +- -- There is only a single panel model in use across both +- -- ROG Ally + ROG Ally X. + matches = function(display) +- if display.vendor == "TMX" and display.model == "TL070FVXS01-0" and display.product == 0x0002 then +- debug("[rogally_lcd] Matched vendor: "..display.vendor.." model: "..display.model.." product:"..display.product) +- return 5000 ++ -- There are two panels used across the ROG Ally and ROG Ally X ++ -- with the same timings, but the model names are in different ++ -- parts of the EDID. ++ local lcd_types = { ++ { vendor = "TMX", model = "TL070FVXS01-0", product = 0x0002 }, ++ { vendor = "BOE", data_string = "TS070FHM-LU0", product = 0x0C33 }, ++ } ++ ++ for index, value in ipairs(lcd_types) do ++ -- We only match if the vendor and product match exactly, plus either model or data_string ++ if value.vendor == display.vendor and value.product == display.product then ++ if (value.model and value.model == display.model) ++ or (value.data_string and value.data_string == display.data_string) then ++ debug("[rogally_lcd] Matched vendor: "..value.vendor.." model: "..(value.model or value.data_string).." product: "..value.product) ++ return 5000 ++ end ++ end + end ++ + return -1 + end + } +-debug("Registered ASUS ROG Ally/Ally X LCD as a known display") ++debug("Registered ASUS ROG Ally / ROG Ally X LCD as a known display") + --debug(inspect(gamescope.config.known_displays.rogally_lcd)) +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Colin Kinloch +Date: Sat, 21 Dec 2024 17:24:31 +0000 +Subject: scripts: Search GAMESCOPE_SCRIPT_PATH for scripts + +Adds GAMESCOPE_SCRIPT_PATH as a colon separated list of paths to search for scripts in. + +It's also added to the meson devenv which allows developers to test changes by running: +`meson devenv -C _build` +--- + meson.build | 4 ++++ + src/Script/Script.cpp | 10 ++++++++++ + 2 files changed, 14 insertions(+) + +diff --git a/meson.build b/meson.build +index cc07a59ca99a..562ee1585a6b 100644 +--- a/meson.build ++++ b/meson.build +@@ -102,3 +102,7 @@ endif + + # Handle default script/config stuff + meson.add_install_script('default_scripts_install.sh') ++ ++devenv = environment() ++devenv.set('GAMESCOPE_SCRIPT_PATH', join_paths(meson.current_source_dir(), 'scripts')) ++meson.add_devenv(devenv) +diff --git a/src/Script/Script.cpp b/src/Script/Script.cpp +index ceb1f80e3a77..2d3cd47bb8ec 100644 +--- a/src/Script/Script.cpp ++++ b/src/Script/Script.cpp +@@ -124,10 +124,20 @@ namespace gamescope + + void CScriptManager::RunDefaultScripts() + { ++ const char *sScriptPathEnv = getenv("GAMESCOPE_SCRIPT_PATH"); ++ + if ( cv_script_use_local_scripts ) + { + RunFolder( "../scripts", true ); + } ++ else if ( sScriptPathEnv ) ++ { ++ std::vector sScriptPaths = gamescope::Split( sScriptPathEnv, ":" ); ++ for ( const auto &sScriptPath : sScriptPaths ) ++ { ++ RunFolder( sScriptPath, true ); ++ } ++ } + else + { + RunFolder( SCRIPT_DIR, true ); +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Apr 2025 17:42:30 -0600 +Subject: steamcompmgr: Set receivedDoneCommit even if the commit is not for + current surface in update_wayland_res(). + +--- + src/steamcompmgr.cpp | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index d0a069e69c60..e40f95715746 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -6469,8 +6469,7 @@ void update_wayland_res(CommitDoneList_t *doneCommits, steamcompmgr_win_t *w, Re + wlserver_lock(); + wlr_buffer_unlock( buf ); + wlserver_unlock(); +- +- // Don't mark as recieve done commit, it was for the wrong surface. ++ w->receivedDoneCommit = true; + return; + } + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: "kingstom.chen" +Date: Tue, 18 Feb 2025 08:59:06 +0800 +Subject: Force wrap file usage for stb and glm dependencies + +the `dependency()` for stb and glm first searched for system-installed versions, +which could an incompatible version (e.g. `stb_image_resize2.h`), it may break the build. + +By forcing the use of the subproject wrap files, it will prevent breaking changes +due to unpredictable system dependency versions. +--- + src/meson.build | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/meson.build b/src/meson.build +index 74fc0334d47e..f35f7ef0cb94 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -19,11 +19,14 @@ xkbcommon = dependency('xkbcommon') + thread_dep = dependency('threads') + cap_dep = dependency('libcap', required: get_option('rt_cap')) + epoll_dep = dependency('epoll-shim', required: false) +-glm_dep = dependency('glm') + sdl2_dep = dependency('SDL2', required: get_option('sdl2_backend')) +-stb_dep = dependency('stb') + avif_dep = dependency('libavif', version: '>=1.0.0', required: get_option('avif_screenshots')) + ++glm_proj = subproject('glm') ++glm_dep = glm_proj.get_variable('glm_dep') ++stb_proj = subproject('stb') ++stb_dep = stb_proj.get_variable('stb_dep') ++ + wlroots_dep = dependency( + 'wlroots', + version: ['>= 0.18.0', '< 0.19.0'], +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Thu, 3 Apr 2025 14:08:50 -0700 +Subject: script: Lenovo Legion Go S LCD display configuration + +This configuration covers the non-VRR limiter of the Lenovo Legion Go S. +In the EDID, only 60Hz and 120Hz are listed as valid modes with different +pixel clocks. Because of this, an LCD Deck style for dynamic modegen works best. + +The refresh rates within this configuration were tested with hundreds of modesets +on my Z2 Go model with a CSW panel. +--- + .../displays/lenovo.legiongos.lcd.lua | 59 +++++++++++++++++++ + 1 file changed, 59 insertions(+) + create mode 100644 scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua + +diff --git a/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua +new file mode 100644 +index 000000000000..6263478c0517 +--- /dev/null ++++ b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua +@@ -0,0 +1,59 @@ ++local legiongos_lcd_refresh_rates = { ++ 52, 53, 54, 56, 57, 58, 59, ++ 60, 61, 62, 63, 64, 65, 67, 68, 69, ++ 70, ++ 102, 103, 104, 105, 106, 107, 108, 109, ++ 111, 112, 113, 114, 115, 116, 117, 118, 119, ++ 120 ++} ++ ++gamescope.config.known_displays.legiongos_lcd = { ++ pretty_name = "Lenovo Legion Go S LCD", ++ hdr = { ++ -- The Legion Go S panel does not support HDR. ++ supported = false, ++ force_enabled = false, ++ eotf = gamescope.eotf.gamma22, ++ max_content_light_level = 500, ++ max_frame_average_luminance = 500, ++ min_content_light_level = 0.5 ++ }, ++ -- 60Hz has a different pixel clock than 120Hz in the EDID with VRR disabled, ++ -- and the panel is not responsive to tuning VFPs. To cover the non-VRR ++ -- limiter, an LCD Deck-style dynamic modegen method works best. ++ dynamic_refresh_rates = legiongos_lcd_refresh_rates, ++ dynamic_modegen = function(base_mode, refresh) ++ debug("Generating mode "..refresh.."Hz for Lenovo Legion Go S LCD") ++ local mode = base_mode ++ ++ -- These are only tuned for 1920x1200. ++ gamescope.modegen.set_resolution(mode, 1920, 1200) ++ ++ -- hfp, hsync, hbp ++ gamescope.modegen.set_h_timings(mode, 48, 36, 80) ++ -- vfp, vsync, vbp ++ gamescope.modegen.set_v_timings(mode, 54, 6, 4) ++ mode.clock = gamescope.modegen.calc_max_clock(mode, refresh) ++ mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) ++ ++ --debug(inspect(mode)) ++ return mode ++ end, ++ matches = function(display) ++ local lcd_types = { ++ { vendor = "CSW", model = "PN8007QB1-1", product = 0x0800 }, ++ { vendor = "BOE", model = "NS080WUM-LX1", product = 0x0C00 }, ++ } ++ ++ for index,value in ipairs(lcd_types) do ++ if value.vendor == display.vendor and value.model == display.model and value.product == display.product then ++ debug("[legiongos_lcd] Matched vendor: "..display.vendor.." model: "..display.model.." product: "..display.product) ++ return 5000 ++ end ++ end ++ ++ return -1 ++ end ++} ++debug("Registered Lenovo Legion Go S LCD as a known display") ++--debug(inspect(gamescope.config.known_displays.legiongos_lcd)) +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Wed, 9 Apr 2025 14:22:16 -0700 +Subject: script: add additional BOE panel + +Some BOE units have panels with different product codes but +identical model names. +--- + scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua +index 6263478c0517..32f776c17f3d 100644 +--- a/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua ++++ b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua +@@ -43,6 +43,7 @@ gamescope.config.known_displays.legiongos_lcd = { + local lcd_types = { + { vendor = "CSW", model = "PN8007QB1-1", product = 0x0800 }, + { vendor = "BOE", model = "NS080WUM-LX1", product = 0x0C00 }, ++ { vendor = "BOE", model = "NS080WUM-LX1", product = 0x0CFF }, + } + + for index,value in ipairs(lcd_types) do +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Attila Fidan +Date: Wed, 29 Jan 2025 07:51:13 +0000 +Subject: WaylandBackend: Don't assert on non-xkb-v1 keymaps + +Long story short, there are some edge cases where sway may send +no_keymap to clients when a virtual keyboard is created on the seat, +in specific circumstances. It will later send the xkb keymap before any +key events are sent. Other clients simply ignore non-xkb-v1 keymaps (or +the lack of a keymap), they don't assert. So gamescope should do the +same. +--- + src/Backends/WaylandBackend.cpp | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp +index 22f8ee5c8fac..3207a6b9f7d4 100644 +--- a/src/Backends/WaylandBackend.cpp ++++ b/src/Backends/WaylandBackend.cpp +@@ -2748,7 +2748,8 @@ namespace gamescope + // Ideally we'd use this to influence our keymap to clients, eg. x server. + + defer( close( nFd ) ); +- assert( uFormat == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 ); ++ if ( uFormat != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 ) ++ return; + + char *pMap = (char *)mmap( nullptr, uSize, PROT_READ, MAP_PRIVATE, nFd, 0 ); + if ( !pMap || pMap == MAP_FAILED ) +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: M Stoeckl +Date: Tue, 21 Jan 2025 16:08:47 -0500 +Subject: main: Give error message on invalid integer or float argument + +--- + src/main.cpp | 54 +++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 41 insertions(+), 13 deletions(-) + +diff --git a/src/main.cpp b/src/main.cpp +index cd251af559e1..58bede8582fd 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -425,6 +425,34 @@ static enum gamescope::GamescopeBackend parse_backend_name(const char *str) + } + } + ++static int parse_integer(const char *str, const char *optionName) ++{ ++ auto result = gamescope::Parse(str); ++ if ( result.has_value() ) ++ { ++ return result.value(); ++ } ++ else ++ { ++ fprintf( stderr, "gamescope: invalid value for --%s, \"%s\" is either not an integer or is far too large\n", optionName, str ); ++ exit(1); ++ } ++} ++ ++static float parse_float(const char *str, const char *optionName) ++{ ++ auto result = gamescope::Parse(str); ++ if ( result.has_value() ) ++ { ++ return result.value(); ++ } ++ else ++ { ++ fprintf( stderr, "gamescope: invalid value for --%s, \"%s\" could not be interpreted as a real number\n", optionName, str ); ++ exit(1); ++ } ++} ++ + struct sigaction handle_signal_action = {}; + + void ShutdownGamescope() +@@ -677,25 +705,25 @@ int main(int argc, char **argv) + const char *opt_name; + switch (o) { + case 'w': +- g_nNestedWidth = atoi( optarg ); ++ g_nNestedWidth = parse_integer( optarg, "nested-width" ); + break; + case 'h': +- g_nNestedHeight = atoi( optarg ); ++ g_nNestedHeight = parse_integer( optarg, "nested-height" ); + break; + case 'r': +- g_nNestedRefresh = gamescope::ConvertHztomHz( atoi( optarg ) ); ++ g_nNestedRefresh = gamescope::ConvertHztomHz( parse_integer( optarg, "nested-refresh" ) ); + break; + case 'W': +- g_nPreferredOutputWidth = atoi( optarg ); ++ g_nPreferredOutputWidth = parse_integer( optarg, "output-width" ); + break; + case 'H': +- g_nPreferredOutputHeight = atoi( optarg ); ++ g_nPreferredOutputHeight = parse_integer( optarg, "output-height" ); + break; + case 'o': +- g_nNestedUnfocusedRefresh = gamescope::ConvertHztomHz( atoi( optarg ) ); ++ g_nNestedUnfocusedRefresh = gamescope::ConvertHztomHz( parse_integer( optarg, "nested-unfocused-refresh" ) ); + break; + case 'm': +- g_flMaxWindowScale = atof( optarg ); ++ g_flMaxWindowScale = parse_float( optarg, "max-scale" ); + break; + case 'S': + g_wantedUpscaleScaler = parse_upscaler_scaler(optarg); +@@ -716,7 +744,7 @@ int main(int argc, char **argv) + g_bGrabbed = true; + break; + case 's': +- g_mouseSensitivity = atof( optarg ); ++ g_mouseSensitivity = parse_float( optarg, "mouse-sensitivity" ); + break; + case 'e': + steamMode = true; +@@ -734,21 +762,21 @@ int main(int argc, char **argv) + } else if (strcmp(opt_name, "disable-color-management") == 0) { + g_bForceDisableColorMgmt = true; + } else if (strcmp(opt_name, "xwayland-count") == 0) { +- g_nXWaylandCount = atoi( optarg ); ++ g_nXWaylandCount = parse_integer( optarg, opt_name ); + } else if (strcmp(opt_name, "composite-debug") == 0) { + cv_composite_debug |= CompositeDebugFlag::Markers; + cv_composite_debug |= CompositeDebugFlag::PlaneBorders; + } else if (strcmp(opt_name, "hdr-debug-heatmap") == 0) { + cv_composite_debug |= CompositeDebugFlag::Heatmap; + } else if (strcmp(opt_name, "default-touch-mode") == 0) { +- gamescope::cv_touch_click_mode = (gamescope::TouchClickMode) atoi( optarg ); ++ gamescope::cv_touch_click_mode = (gamescope::TouchClickMode) parse_integer( optarg, opt_name ); + } else if (strcmp(opt_name, "generate-drm-mode") == 0) { + g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); + } else if (strcmp(opt_name, "force-orientation") == 0) { + g_DesiredInternalOrientation = force_orientation( optarg ); + } else if (strcmp(opt_name, "sharpness") == 0 || + strcmp(opt_name, "fsr-sharpness") == 0) { +- g_upscaleFilterSharpness = atoi( optarg ); ++ g_upscaleFilterSharpness = parse_integer( optarg, opt_name ); + } else if (strcmp(opt_name, "rt") == 0) { + g_bRt = true; + } else if (strcmp(opt_name, "prefer-vk-device") == 0) { +@@ -762,7 +790,7 @@ int main(int argc, char **argv) + } else if (strcmp(opt_name, "force-grab-cursor") == 0) { + g_bForceRelativeMouse = true; + } else if (strcmp(opt_name, "display-index") == 0) { +- g_nNestedDisplayIndex = atoi( optarg ); ++ g_nNestedDisplayIndex = parse_integer( optarg, opt_name ); + } else if (strcmp(opt_name, "adaptive-sync") == 0) { + cv_adaptive_sync = true; + } else if (strcmp(opt_name, "expose-wayland") == 0) { +@@ -770,7 +798,7 @@ int main(int argc, char **argv) + } else if (strcmp(opt_name, "backend") == 0) { + eCurrentBackend = parse_backend_name( optarg ); + } else if (strcmp(opt_name, "cursor-scale-height") == 0) { +- g_nCursorScaleHeight = atoi(optarg); ++ g_nCursorScaleHeight = parse_integer(optarg, opt_name); + } else if (strcmp(opt_name, "mangoapp") == 0) { + g_bLaunchMangoapp = true; + } +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Joshua Ashton +Date: Sat, 7 Sep 2024 22:22:22 +0100 +Subject: protocol: Add gamescope-action-binding protocol + +--- + protocol/gamescope-action-binding.xml | 85 ++++++++++ + protocol/meson.build | 1 + + src/Apps/gamescope_hotkey_example.cpp | 179 +++++++++++++++++++++ + src/WaylandServer/GamescopeActionBinding.h | 163 +++++++++++++++++++ + src/WaylandServer/WaylandDecls.h | 3 + + src/meson.build | 2 + + src/wlserver.cpp | 58 ++++++- + 7 files changed, 489 insertions(+), 2 deletions(-) + create mode 100644 protocol/gamescope-action-binding.xml + create mode 100644 src/Apps/gamescope_hotkey_example.cpp + create mode 100644 src/WaylandServer/GamescopeActionBinding.h + +diff --git a/protocol/gamescope-action-binding.xml b/protocol/gamescope-action-binding.xml +new file mode 100644 +index 000000000000..2164cb87ad84 +--- /dev/null ++++ b/protocol/gamescope-action-binding.xml +@@ -0,0 +1,85 @@ ++ ++ ++ ++ ++ Copyright © 2024 Valve Corporation ++ ++ Permission is hereby granted, free of charge, to any person obtaining a ++ copy of this software and associated documentation files (the "Software"), ++ to deal in the Software without restriction, including without limitation ++ the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ and/or sell copies of the Software, and to permit persons to whom the ++ Software is furnished to do so, subject to the following conditions: ++ ++ The above copyright notice and this permission notice (including the next ++ paragraph) shall be included in all copies or substantial portions of the ++ Software. ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ++ DEALINGS IN THE SOFTWARE. ++ ++ ++ ++ This is a private Gamescope protocol. Regular Wayland clients must not use ++ it. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Flags that control how the action is armed. ++ ++ ++ ++ ++ ++ ++ ++ Flags that say how the action was triggered. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/protocol/meson.build b/protocol/meson.build +index dbce92edce52..9f75f188af52 100644 +--- a/protocol/meson.build ++++ b/protocol/meson.build +@@ -36,6 +36,7 @@ protocols = [ + 'gamescope-reshade.xml', + 'gamescope-swapchain.xml', + 'gamescope-private.xml', ++ 'gamescope-action-binding.xml', + + # wlroots protocols + 'wlr-layer-shell-unstable-v1.xml', +diff --git a/src/Apps/gamescope_hotkey_example.cpp b/src/Apps/gamescope_hotkey_example.cpp +new file mode 100644 +index 000000000000..ffd88bdfa2c8 +--- /dev/null ++++ b/src/Apps/gamescope_hotkey_example.cpp +@@ -0,0 +1,179 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "convar.h" ++#include "Utils/Version.h" ++ ++#include ++ ++#include ++#include ++ ++// TODO: Consolidate ++#define WAYLAND_NULL() [] ( void *pData, Args... args ) { } ++#define WAYLAND_USERDATA_TO_THIS(type, name) [] ( void *pData, Args... args ) { type *pThing = (type *)pData; pThing->name( std::forward(args)... ); } ++ ++namespace gamescope ++{ ++ class CActionBinding ++ { ++ public: ++ bool Init( gamescope_action_binding_manager *pManager, std::span pKeySyms ) ++ { ++ Shutdown(); ++ ++ m_pBinding = gamescope_action_binding_manager_create_action_binding( pManager ); ++ if ( !m_pBinding ) ++ return false; ++ ++ wl_array array; ++ wl_array_init(&array); ++ for ( uint32_t uKeySym : pKeySyms ) ++ { ++ uint32_t *pKeySymPtr = (uint32_t *)wl_array_add(&array, sizeof(uint32_t) ); ++ *pKeySymPtr = uKeySym; ++ } ++ ++ gamescope_action_binding_add_listener( m_pBinding, &s_BindingListener, (void *)this ); ++ gamescope_action_binding_add_keyboard_trigger( m_pBinding, &array ); ++ gamescope_action_binding_set_description( m_pBinding, "My Example Hotkey :)" ); ++ gamescope_action_binding_arm( m_pBinding, 0 ); ++ ++ return true; ++ } ++ ++ void Shutdown() ++ { ++ if ( m_pBinding ) ++ { ++ gamescope_action_binding_destroy( m_pBinding ); ++ m_pBinding = nullptr; ++ } ++ } ++ ++ void Wayland_Triggered( gamescope_action_binding *pBinding, uint32_t uSequence, uint32_t uTriggerFlags, uint32_t uTimeLo, uint32_t uTimeHi ) ++ { ++ fprintf( stderr, "Hotkey pressed!" ); ++ } ++ ++ private: ++ gamescope_action_binding *m_pBinding = nullptr; ++ ++ static const gamescope_action_binding_listener s_BindingListener; ++ }; ++ ++ const gamescope_action_binding_listener CActionBinding::s_BindingListener = ++ { ++ .triggered = WAYLAND_USERDATA_TO_THIS( CActionBinding, Wayland_Triggered ), ++ }; ++ ++ class GamescopeHotkeyExample ++ { ++ public: ++ GamescopeHotkeyExample(); ++ ~GamescopeHotkeyExample(); ++ ++ bool Init(); ++ void Run(); ++ private: ++ wl_display *m_pDisplay = nullptr; ++ gamescope_action_binding_manager *m_pActionBindingManager = nullptr; ++ ++ void Wayland_Registry_Global( wl_registry *pRegistry, uint32_t uName, const char *pInterface, uint32_t uVersion ); ++ static const wl_registry_listener s_RegistryListener; ++ }; ++ ++ GamescopeHotkeyExample::GamescopeHotkeyExample() ++ { ++ } ++ ++ GamescopeHotkeyExample::~GamescopeHotkeyExample() ++ { ++ } ++ ++ bool GamescopeHotkeyExample::Init() ++ { ++ const char *pDisplayName = getenv( "GAMESCOPE_WAYLAND_DISPLAY" ); ++ if ( !pDisplayName || !*pDisplayName ) ++ pDisplayName = "gamescope-0"; ++ ++ if ( !( m_pDisplay = wl_display_connect( pDisplayName ) ) ) ++ { ++ fprintf( stderr, "Failed to open GAMESCOPE_WAYLAND_DISPLAY.\n" ); ++ return false; ++ } ++ ++ { ++ wl_registry *pRegistry; ++ if ( !( pRegistry = wl_display_get_registry( m_pDisplay ) ) ) ++ { ++ fprintf( stderr, "Failed to get wl_registry.\n" ); ++ return false; ++ } ++ ++ wl_registry_add_listener( pRegistry, &s_RegistryListener, (void *)this ); ++ wl_display_roundtrip( m_pDisplay ); ++ wl_display_roundtrip( m_pDisplay ); ++ ++ if ( !m_pActionBindingManager ) ++ { ++ fprintf( stderr, "Failed to get Gamescope binding manager\n" ); ++ return false; ++ } ++ ++ wl_registry_destroy( pRegistry ); ++ } ++ ++ return true; ++ } ++ ++ void GamescopeHotkeyExample::Run() ++ { ++ // Add a test hotkey of Shift + P. ++ std::vector uKeySyms = { 0xffe1, 0x0070 }; // XKB_KEY_Shift_L + XKB_KEY_p ++ ++ CActionBinding binding; ++ if ( !binding.Init( m_pActionBindingManager, uKeySyms ) ) ++ return; ++ ++ wl_display_flush( m_pDisplay ); ++ ++ for ( ;; ) ++ { ++ wl_display_dispatch( m_pDisplay ); ++ } ++ } ++ ++ void GamescopeHotkeyExample::Wayland_Registry_Global( wl_registry *pRegistry, uint32_t uName, const char *pInterface, uint32_t uVersion ) ++ { ++ if ( !strcmp( pInterface, gamescope_action_binding_manager_interface.name ) ) ++ { ++ m_pActionBindingManager = (decltype(m_pActionBindingManager)) wl_registry_bind( pRegistry, uName, &gamescope_action_binding_manager_interface, uVersion ); ++ } ++ } ++ ++ const wl_registry_listener GamescopeHotkeyExample::s_RegistryListener = ++ { ++ .global = WAYLAND_USERDATA_TO_THIS( GamescopeHotkeyExample, Wayland_Registry_Global ), ++ .global_remove = WAYLAND_NULL(), ++ }; ++ ++ static int RunHotkeyExample( int argc, char *argv[] ) ++ { ++ gamescope::GamescopeHotkeyExample hotkeyExample; ++ if ( !hotkeyExample.Init() ) ++ return 1; ++ ++ hotkeyExample.Run(); ++ ++ return 0; ++ } ++} ++ ++int main( int argc, char *argv[] ) ++{ ++ return gamescope::RunHotkeyExample( argc, argv ); ++} +diff --git a/src/WaylandServer/GamescopeActionBinding.h b/src/WaylandServer/GamescopeActionBinding.h +new file mode 100644 +index 000000000000..81aab05dcd22 +--- /dev/null ++++ b/src/WaylandServer/GamescopeActionBinding.h +@@ -0,0 +1,163 @@ ++#pragma once ++ ++#include "WaylandProtocol.h" ++ ++#include "gamescope-action-binding-protocol.h" ++ ++#include ++#include ++#include ++ ++#include "convar.h" ++#include "Utils/Algorithm.h" ++ ++#include "wlr_begin.hpp" ++#include ++#include ++#include "wlr_end.hpp" ++ ++using namespace std::literals; ++ ++uint64_t get_time_in_nanos(); ++ ++namespace gamescope::WaylandServer ++{ ++ struct Keybind_t ++ { ++ std::unordered_set setKeySyms; ++ }; ++ ++ /////////////////////////// ++ // CGamescopeActionBinding ++ /////////////////////////// ++ class CGamescopeActionBinding : public CWaylandResource ++ { ++ public: ++ WL_PROTO_DEFINE( gamescope_action_binding, 1 ); ++ ++ CGamescopeActionBinding( WaylandResourceDesc_t desc ) ++ : CWaylandResource( desc ) ++ { ++ s_Bindings.push_back( this ); ++ } ++ ++ ~CGamescopeActionBinding() ++ { ++ std::erase_if( s_Bindings, [this]( CGamescopeActionBinding *pBinding ){ return pBinding == this; } ); ++ } ++ ++ // gamescope_action_binding ++ ++ void SetDescription( const char *pszDescription ) ++ { ++ m_sDescription = pszDescription; ++ } ++ ++ void AddKeyboardTrigger( wl_array *pKeysymsArray ) ++ { ++ size_t zKeysymCount = pKeysymsArray->size / sizeof( xkb_keysym_t ); ++ ++ std::span pKeysyms = std::span { ++ reinterpret_cast( pKeysymsArray->data ), ++ zKeysymCount }; ++ ++ std::unordered_set setKeySyms; ++ for ( xkb_keysym_t uKeySym : pKeysyms ) ++ { ++ setKeySyms.emplace( uKeySym ); ++ } ++ ++ m_KeyboardTriggers.emplace_back( std::move( setKeySyms ) ); ++ } ++ ++ void ClearTriggers() ++ { ++ m_KeyboardTriggers.clear(); ++ } ++ ++ void Arm( uint32_t uArmFlags ) ++ { ++ m_ouArmFlags = uArmFlags; ++ } ++ ++ void Disarm() ++ { ++ m_ouArmFlags = std::nullopt; ++ } ++ ++ // ++ ++ bool IsArmed() { return m_ouArmFlags != std::nullopt; } ++ std::span GetKeyboardTriggers() { return m_KeyboardTriggers; } ++ ++ bool Execute() ++ { ++ if ( !IsArmed() ) ++ return false; ++ ++ uint32_t uArmFlags = *m_ouArmFlags; ++ bool bBlockInput = !!( uArmFlags & GAMESCOPE_ACTION_BINDING_ARM_FLAG_NO_BLOCK ); ++ ++ uint32_t uTriggerFlags = GAMESCOPE_ACTION_BINDING_TRIGGER_FLAG_KEYBOARD; ++ ++ uint64_t ulNow = get_time_in_nanos(); ++ ++ static uint32_t s_uSequence = 0; ++ uint32_t uTimeLo = static_cast( ulNow & 0xffffffff ); ++ uint32_t uTimeHi = static_cast( ulNow >> 32 ); ++ gamescope_action_binding_send_triggered( GetResource(), s_uSequence++, uTriggerFlags, uTimeLo, uTimeHi ); ++ ++ if ( uArmFlags & GAMESCOPE_ACTION_BINDING_ARM_FLAG_ONE_SHOT ) ++ Disarm(); ++ ++ return bBlockInput; ++ } ++ ++ static std::span GetBindings() ++ { ++ return s_Bindings; ++ } ++ ++ private: ++ std::string m_sDescription; ++ std::vector m_KeyboardTriggers; ++ ++ std::optional m_ouArmFlags; ++ ++ static std::vector s_Bindings; ++ }; ++ ++ const struct gamescope_action_binding_interface CGamescopeActionBinding::Implementation = ++ { ++ .destroy = WL_PROTO_DESTROY(), ++ .set_description = WL_PROTO( CGamescopeActionBinding, SetDescription ), ++ .add_keyboard_trigger = WL_PROTO( CGamescopeActionBinding, AddKeyboardTrigger ), ++ .clear_triggers = WL_PROTO( CGamescopeActionBinding, ClearTriggers ), ++ .arm = WL_PROTO( CGamescopeActionBinding, Arm ), ++ .disarm = WL_PROTO( CGamescopeActionBinding, Disarm ), ++ }; ++ ++ std::vector CGamescopeActionBinding::s_Bindings; ++ ++ ////////////////////////////////// ++ // CGamescopeActionBindingManager ++ ////////////////////////////////// ++ class CGamescopeActionBindingManager : public CWaylandResource ++ { ++ public: ++ WL_PROTO_DEFINE( gamescope_action_binding_manager, 1 ); ++ WL_PROTO_DEFAULT_CONSTRUCTOR(); ++ ++ void CreateActionBinding( uint32_t uId ) ++ { ++ CWaylandResource::Create( m_pClient, m_uVersion, uId ); ++ } ++ }; ++ ++ const struct gamescope_action_binding_manager_interface CGamescopeActionBindingManager::Implementation = ++ { ++ .destroy = WL_PROTO_DESTROY(), ++ .create_action_binding = WL_PROTO( CGamescopeActionBindingManager, CreateActionBinding ), ++ }; ++ ++} +diff --git a/src/WaylandServer/WaylandDecls.h b/src/WaylandServer/WaylandDecls.h +index e8fd9343192b..e43623aa6a74 100644 +--- a/src/WaylandServer/WaylandDecls.h ++++ b/src/WaylandServer/WaylandDecls.h +@@ -15,4 +15,7 @@ namespace gamescope::WaylandServer + class CReshadeManager; + using CReshade = CWaylandProtocol; + ++ class CGamescopeActionBindingManager; ++ using CGamescopeActionBindingProtocol = CWaylandProtocol; ++ + } +diff --git a/src/meson.build b/src/meson.build +index f35f7ef0cb94..842768ce7ce4 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -222,3 +222,5 @@ executable('gamescope_color_microbench', ['color_bench.cpp', 'color_helpers.cpp' + executable('gamescope_color_tests', ['color_tests.cpp', 'color_helpers.cpp'], gamescope_core_src, gamescope_version, dependencies:[glm_dep]) + + executable('gamescopectl', ['Apps/gamescopectl.cpp'], gamescope_core_src, gamescope_version, protocols_client_src, dependencies: [dep_wayland], install:true ) ++ ++executable('gamescope_hotkey_example', ['Apps/gamescope_hotkey_example.cpp'], gamescope_core_src, gamescope_version, protocols_client_src, dependencies: [dep_wayland, xkbcommon], install: false ) +diff --git a/src/wlserver.cpp b/src/wlserver.cpp +index 4ce9511352d0..ffaf7aff7343 100644 +--- a/src/wlserver.cpp ++++ b/src/wlserver.cpp +@@ -20,6 +20,7 @@ + #include "WaylandServer/WaylandProtocol.h" + #include "WaylandServer/LinuxDrmSyncobj.h" + #include "WaylandServer/Reshade.h" ++#include "WaylandServer/GamescopeActionBinding.h" + + #include "wlr_begin.hpp" + #include +@@ -108,6 +109,7 @@ static void wlserver_update_cursor_constraint(); + static void handle_pointer_constraint(struct wl_listener *listener, void *data); + static void wlserver_constrain_cursor( struct wlr_pointer_constraint_v1 *pNewConstraint ); + struct wlr_surface *wlserver_surface_to_main_surface( struct wlr_surface *pSurface ); ++void wlserver_process_hotkeys( wlr_keyboard *keyboard, uint32_t key, bool press ); + + std::vector& gamescope_xwayland_server_t::retrieve_commits() + { +@@ -306,6 +308,9 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) + } + #endif + ++ // TODO: Remove the below hack when Steam is shipping ++ // `gamescope_action_binding_manager` in Steam Stable ++ // as it can just use a keybind to grab these always. + bool forbidden_key = + keysym == XKB_KEY_XF86AudioLowerVolume || + keysym == XKB_KEY_XF86AudioRaiseVolume || +@@ -324,6 +329,8 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) + return; + } + } ++ ++ wlserver_process_hotkeys( keyboard->wlr, event->state == WL_KEYBOARD_KEY_STATE_PRESSED, event->time_msec ); + + wlr_seat_set_keyboard( wlserver.wlr.seat, keyboard->wlr ); + wlr_seat_keyboard_notify_key( wlserver.wlr.seat, event->time_msec, event->keycode, event->state ); +@@ -1748,6 +1755,8 @@ bool wlserver_init( void ) { + + create_reshade(); + ++ new gamescope::WaylandServer::CGamescopeActionBindingProtocol( wlserver.display ); ++ + create_gamescope_xwayland(); + + create_gamescope_swapchain_factory_v2(); +@@ -2038,12 +2047,57 @@ void wlserver_keyboardfocus( struct wlr_surface *surface, bool bConstrain ) + } + } + ++void wlserver_process_hotkeys( wlr_keyboard *keyboard, uint32_t key, bool press ) ++{ ++ xkb_keycode_t keycode = key + 8; ++ xkb_keysym_t keysym = xkb_state_key_get_one_sym( keyboard->xkb_state, keycode ); ++ ++ static std::unordered_set s_setPressedKeySyms; ++ if ( press ) ++ { ++ s_setPressedKeySyms.emplace( keysym ); ++ } ++ else ++ { ++ s_setPressedKeySyms.erase( keysym ); ++ } ++ ++ { ++ using namespace gamescope::WaylandServer; ++ ++ std::span ppBindings = CGamescopeActionBinding::GetBindings(); ++ ++ for ( CGamescopeActionBinding *pBinding : ppBindings ) ++ { ++ if ( !pBinding->IsArmed() ) ++ continue; ++ ++ std::span pKeybinds = pBinding->GetKeyboardTriggers(); ++ for ( const Keybind_t &keybind : pKeybinds ) ++ { ++ if ( !pBinding->IsArmed() ) ++ break; ++ ++ if ( s_setPressedKeySyms != keybind.setKeySyms ) ++ continue; ++ ++ if ( pBinding->Execute() ) ++ return; ++ } ++ } ++ } ++} ++ + void wlserver_key( uint32_t key, bool press, uint32_t time ) + { + assert( wlserver_is_lock_held() ); + +- assert( wlserver.wlr.virtual_keyboard_device != nullptr ); +- wlr_seat_set_keyboard( wlserver.wlr.seat, wlserver.wlr.virtual_keyboard_device ); ++ wlr_keyboard *keyboard = wlserver.wlr.virtual_keyboard_device; ++ ++ wlserver_process_hotkeys( keyboard, key, press ); ++ ++ assert( keyboard != nullptr ); ++ wlr_seat_set_keyboard( wlserver.wlr.seat, keyboard ); + wlr_seat_keyboard_notify_key( wlserver.wlr.seat, time, key, press ); + + bump_input_counter(); +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Samuel Dionne-Riel +Date: Mon, 14 Oct 2024 20:50:45 -0400 +Subject: wlserver: Re-hook pausing on session pause + +During the refactor in 88eb1b477d8b1efbe6d7087dcde74052dad84049, the +handle_session_active function lost the ultimate role of *causing a +pause* when the session became inactive. + +The duty of pausing the session was given the `DirtyState` function on +the backend, which now uses the same "moral" condition to set the paused +state (`g_DRM.paused = !wlsession_active();`)... + +... except that now `DirtyState` state is only called when the session +is resumed. In turn, this means that on session suspend, nothing ends-up +pausing the DRM backend anymore! + +This change unconditionally calls `DirtyState`, which in turn does the +accounting for pausing the backend. Actually, it conditionally passes +`false` to the argument to force nothing. + +This fixes what ends-up causing `drmModeAtomicCommit: Permission denied` +when moving to another VT from gamescope's. +--- + src/wlserver.cpp | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/wlserver.cpp b/src/wlserver.cpp +index ffaf7aff7343..bb87703162be 100644 +--- a/src/wlserver.cpp ++++ b/src/wlserver.cpp +@@ -1347,8 +1347,7 @@ bool wlsession_active() + + static void handle_session_active( struct wl_listener *listener, void *data ) + { +- if (wlserver.wlr.session->active) +- GetBackend()->DirtyState( true, true ); ++ GetBackend()->DirtyState( wlserver.wlr.session->active, wlserver.wlr.session->active ); + wl_log.infof( "Session %s", wlserver.wlr.session->active ? "resumed" : "paused" ); + } + #endif +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Sat, 1 Mar 2025 22:35:56 +0000 +Subject: steamcompmgr: Fix icon/title being spam set + +Overlays should not get an appid, that's just for focus id logic. +--- + src/steamcompmgr.cpp | 23 ++++++++++++++++++++--- + src/steamcompmgr_shared.hpp | 6 ++++++ + 2 files changed, 26 insertions(+), 3 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index e40f95715746..f718832ea5c2 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -3961,8 +3961,10 @@ determine_and_apply_focus() + if ( global_focus.focusWindow ) + { + GetBackend()->GetNestedHints()->SetVisible( true ); +- GetBackend()->GetNestedHints()->SetTitle( global_focus.focusWindow->title ); +- GetBackend()->GetNestedHints()->SetIcon( global_focus.focusWindow->icon ); ++ if ( global_focus.focusWindow != previous_focus.focusWindow ) { ++ GetBackend()->GetNestedHints()->SetTitle( global_focus.focusWindow->title ); ++ GetBackend()->GetNestedHints()->SetIcon( global_focus.focusWindow->icon ); ++ } + } + else + { +@@ -4200,9 +4202,15 @@ map_win(xwayland_ctx_t* ctx, Window id, unsigned long sequence) + { + w->appID = w->xwayland().id; + } ++ + w->isOverlay = get_prop(ctx, w->xwayland().id, ctx->atoms.overlayAtom, 0); + w->isExternalOverlay = get_prop(ctx, w->xwayland().id, ctx->atoms.externalOverlayAtom, 0); + ++ // misyl: Disable appID for overlay types, as parts of the code don't expect that focus-wise. ++ // Fixes mangoapp usage when nested, and not in SteamOS. ++ if ( w->IsAnyOverlay() ) ++ w->appID = 0; ++ + get_size_hints(ctx, w); + + get_net_wm_state(ctx, w); +@@ -4462,6 +4470,9 @@ add_win(xwayland_ctx_t *ctx, Window id, Window prev, unsigned long sequence) + new_win->appID = id; + } + ++ if ( new_win->IsAnyOverlay() ) ++ new_win->appID = 0; ++ + Window transientFor = None; + if ( XGetTransientForHint( ctx->dpy, id, &transientFor ) ) + { +@@ -4693,7 +4704,7 @@ damage_win(xwayland_ctx_t *ctx, XDamageNotifyEvent *de) + if (!w) + return; + +- if ((w->isOverlay || w->isExternalOverlay) && !w->opacity) ++ if (w->IsAnyOverlay() && !w->opacity) + return; + + // First damage event we get, compute focus; we only want to focus damaged +@@ -5295,6 +5306,8 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + xwm_log.errorf( "appid clash was %u now %u", w->appID, appID ); + } + w->appID = appID; ++ if ( w->IsAnyOverlay() ) ++ w->appID = 0; + + MakeFocusDirty(); + } +@@ -5305,6 +5318,8 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + if (w) + { + w->isOverlay = get_prop(ctx, w->xwayland().id, ctx->atoms.overlayAtom, 0); ++ if ( w->IsAnyOverlay() ) ++ w->appID = 0; + MakeFocusDirty(); + } + } +@@ -5314,6 +5329,8 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + if (w) + { + w->isExternalOverlay = get_prop(ctx, w->xwayland().id, ctx->atoms.externalOverlayAtom, 0); ++ if ( w->IsAnyOverlay() ) ++ w->appID = 0; + MakeFocusDirty(); + } + } +diff --git a/src/steamcompmgr_shared.hpp b/src/steamcompmgr_shared.hpp +index f300eb94d954..989d09d50c4a 100644 +--- a/src/steamcompmgr_shared.hpp ++++ b/src/steamcompmgr_shared.hpp +@@ -116,6 +116,12 @@ struct steamcompmgr_win_t { + uint32_t appID = 0; + bool isOverlay = false; + bool isExternalOverlay = false; ++ ++ bool IsAnyOverlay() const ++ { ++ return isOverlay || isExternalOverlay; ++ } ++ + bool isFullscreen = false; + bool isSysTrayIcon = false; + bool sizeHintsSpecified = false; +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Autumn Ashton +Date: Sun, 2 Mar 2025 00:36:38 +0000 +Subject: steamcompmgr: Fix Steam sidebars with recent icon fix + +--- + src/steamcompmgr.cpp | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index f718832ea5c2..e46c34bbfbc0 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -4208,7 +4208,7 @@ map_win(xwayland_ctx_t* ctx, Window id, unsigned long sequence) + + // misyl: Disable appID for overlay types, as parts of the code don't expect that focus-wise. + // Fixes mangoapp usage when nested, and not in SteamOS. +- if ( w->IsAnyOverlay() ) ++ if ( w->isExternalOverlay ) + w->appID = 0; + + get_size_hints(ctx, w); +@@ -4470,7 +4470,7 @@ add_win(xwayland_ctx_t *ctx, Window id, Window prev, unsigned long sequence) + new_win->appID = id; + } + +- if ( new_win->IsAnyOverlay() ) ++ if ( new_win->isExternalOverlay ) + new_win->appID = 0; + + Window transientFor = None; +@@ -5306,7 +5306,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + xwm_log.errorf( "appid clash was %u now %u", w->appID, appID ); + } + w->appID = appID; +- if ( w->IsAnyOverlay() ) ++ if ( w->isExternalOverlay ) + w->appID = 0; + + MakeFocusDirty(); +@@ -5318,7 +5318,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + if (w) + { + w->isOverlay = get_prop(ctx, w->xwayland().id, ctx->atoms.overlayAtom, 0); +- if ( w->IsAnyOverlay() ) ++ if ( w->isExternalOverlay ) + w->appID = 0; + MakeFocusDirty(); + } +@@ -5329,7 +5329,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) + if (w) + { + w->isExternalOverlay = get_prop(ctx, w->xwayland().id, ctx->atoms.externalOverlayAtom, 0); +- if ( w->IsAnyOverlay() ) ++ if ( w->isExternalOverlay ) + w->appID = 0; + MakeFocusDirty(); + } +-- +2.50.1 + + From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Fri, 22 Nov 2024 01:37:48 +0100 @@ -10,7 +2583,7 @@ Subject: [NA] add dev script diff --git a/sync.sh b/sync.sh new file mode 100755 -index 0000000..878bf6c +index 000000000000..8dd5815d4aeb --- /dev/null +++ b/sync.sh @@ -0,0 +1,21 @@ @@ -25,7 +2598,7 @@ index 0000000..878bf6c + +set -e + -+meson build/ -Dforce_fallback_for=stb,libdisplay-info,libliftoff,wlroots,vkroots ++meson build/ -Dforce_fallback_for=stb,libdisplay-info,libliftoff,wlroots,vkroots -Denable_openvr_support=false +ninja -C build/ +scp build/src/gamescope ${HOST}:gamescope + @@ -36,7 +2609,7 @@ index 0000000..878bf6c + # sudo reboot +EOF -- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 @@ -50,29 +2623,29 @@ move by Antheas. Co-authored-by: Kyle Gospodnetich Co-authored-by: Antheas Kapenekakis --- - src/Backends/DRMBackend.cpp | 5 +++++ + src/Backends/DRMBackend.cpp | 4 +++- src/main.cpp | 31 +++++++++++++++++++++++++++++++ src/main.hpp | 2 ++ - 3 files changed, 38 insertions(+) + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 0b121e8..75c3258 100644 +index 06ebbe7255d4..ffce5d7d8448 100644 --- a/src/Backends/DRMBackend.cpp +++ b/src/Backends/DRMBackend.cpp -@@ -2243,6 +2243,11 @@ namespace gamescope - bHasKnownHDRInfo = true; - } +@@ -2253,8 +2253,10 @@ namespace gamescope } -+ else if ( g_customRefreshRates.size() > 0 && GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL ) { -+ // Only apply custom refresh rates as a fallback, allowing a graceful transition to the new system. -+ m_Mutable.ValidDynamicRefreshRates = g_customRefreshRates; -+ return; -+ } - } + else + { ++ if ( g_customRefreshRates.size() > 0 && GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL ) ++ m_Mutable.ValidDynamicRefreshRates = g_customRefreshRates; + // Unknown display, see if there are any other refresh rates in the EDID we can get. +- if ( GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL ) ++ else if ( GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL ) + { + const drmModeModeInfo *pPreferredMode = find_mode( m_pConnector.get(), 0, 0, 0 ); - if ( !bHasKnownColorimetry ) diff --git a/src/main.cpp b/src/main.cpp -index 9dff5c4..8381889 100644 +index 58bede8582fd..1443f49b51e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -129,6 +129,7 @@ const struct option *gamescope_options = (struct option[]){ @@ -89,9 +2662,9 @@ index 9dff5c4..8381889 100644 " --framerate-limit Set a simple framerate limit. Used as a divisor of the refresh rate, rounds down eg 60 / 59 -> 60fps, 60 / 25 -> 30fps. Default: 0, disabled.\n" + " --custom-refresh-rates Set custom refresh rates for the output. eg: 60,90,110-120\n" " --mangoapp Launch with the mangoapp (mangohud) performance overlay enabled. You should use this instead of using mangohud on the game or gamescope.\n" + " --adaptive-sync Enable adaptive sync if available (variable rate refresh)\n" "\n" - "Nested mode options:\n" -@@ -425,6 +427,33 @@ static enum gamescope::GamescopeBackend parse_backend_name(const char *str) +@@ -453,6 +455,33 @@ static float parse_float(const char *str, const char *optionName) } } @@ -125,7 +2698,7 @@ index 9dff5c4..8381889 100644 struct sigaction handle_signal_action = {}; void ShutdownGamescope() -@@ -746,6 +775,8 @@ int main(int argc, char **argv) +@@ -774,6 +803,8 @@ int main(int argc, char **argv) g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); } else if (strcmp(opt_name, "force-orientation") == 0) { g_DesiredInternalOrientation = force_orientation( optarg ); @@ -133,9 +2706,9 @@ index 9dff5c4..8381889 100644 + g_customRefreshRates = parse_custom_refresh_rates( optarg ); } else if (strcmp(opt_name, "sharpness") == 0 || strcmp(opt_name, "fsr-sharpness") == 0) { - g_upscaleFilterSharpness = atoi( optarg ); + g_upscaleFilterSharpness = parse_integer( optarg, opt_name ); diff --git a/src/main.hpp b/src/main.hpp -index 2e6fb83..390c04a 100644 +index 2e6fb833af12..390c04a63ecd 100644 --- a/src/main.hpp +++ b/src/main.hpp @@ -3,6 +3,7 @@ @@ -155,100 +2728,7 @@ index 2e6fb83..390c04a 100644 enum class GamescopeUpscaleFilter : uint32_t { -- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Alesh Slovak -Date: Thu, 26 Sep 2024 07:13:24 -0400 -Subject: fix(vrr): Revert "steamcompmgr: Move outdatedInteractiveFocus to - window" - -This reverts commit 299bc3410dcfd46da5e3c988354b60ed3a356900. ---- - src/steamcompmgr.cpp | 39 +++++++++++++++++++++++-------------- - src/steamcompmgr_shared.hpp | 1 - - 2 files changed, 24 insertions(+), 16 deletions(-) - -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 11a7cad..df7616d 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -3299,7 +3299,7 @@ found:; - if ( window_has_commits( focus ) ) - out->focusWindow = focus; - else -- focus->outdatedInteractiveFocus = true; -+ out->outdatedInteractiveFocus = true; - - // Always update X's idea of focus, but still dirty - // the it being outdated so we can resolve that globally later. -@@ -6044,28 +6044,37 @@ bool handle_done_commit( steamcompmgr_win_t *w, xwayland_ctx_t *ctx, uint64_t co - // Window just got a new available commit, determine if that's worth a repaint - - // If this is an overlay that we're presenting, repaint -- if ( w == global_focus.overlayWindow && w->opacity != TRANSLUCENT ) -+ if ( gameFocused ) - { -- hasRepaintNonBasePlane = true; -- } -+ if ( w == global_focus.overlayWindow && w->opacity != TRANSLUCENT ) -+ { -+ hasRepaintNonBasePlane = true; -+ } - -- if ( w == global_focus.notificationWindow && w->opacity != TRANSLUCENT ) -- { -- hasRepaintNonBasePlane = true; -+ if ( w == global_focus.notificationWindow && w->opacity != TRANSLUCENT ) -+ { -+ hasRepaintNonBasePlane = true; -+ } - } -- -- // If this is an external overlay, repaint -- if ( w == global_focus.externalOverlayWindow && w->opacity != TRANSLUCENT ) -+ if ( ctx ) - { -- hasRepaintNonBasePlane = true; -+ if ( ctx->focus.outdatedInteractiveFocus ) -+ { -+ MakeFocusDirty(); -+ ctx->focus.outdatedInteractiveFocus = false; -+ } - } -- -- if ( w->outdatedInteractiveFocus ) -+ if ( global_focus.outdatedInteractiveFocus ) - { - MakeFocusDirty(); -- w->outdatedInteractiveFocus = false; -- } -+ global_focus.outdatedInteractiveFocus = false; - -+ // If this is an external overlay, repaint -+ if ( w == global_focus.externalOverlayWindow && w->opacity != TRANSLUCENT ) -+ { -+ hasRepaintNonBasePlane = true; -+ } -+ } - // If this is the main plane, repaint - if ( w == global_focus.focusWindow && !w->isSteamStreamingClient ) - { -diff --git a/src/steamcompmgr_shared.hpp b/src/steamcompmgr_shared.hpp -index 095694e..e41fad9 100644 ---- a/src/steamcompmgr_shared.hpp -+++ b/src/steamcompmgr_shared.hpp -@@ -125,7 +125,6 @@ struct steamcompmgr_win_t { - unsigned int requestedHeight = 0; - bool is_dialog = false; - bool maybe_a_dropdown = false; -- bool outdatedInteractiveFocus = false; - - bool hasHwndStyle = false; - uint32_t hwndStyle = 0; --- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 @@ -261,14 +2741,14 @@ allows for CTRL for a smooth transition. Suggested-by: Antheas Kapenekakis --- - src/wlserver.cpp | 19 ++++++++++++++++++- - 1 file changed, 18 insertions(+), 1 deletion(-) + src/wlserver.cpp | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index 78a86ee..99df8aa 100644 +index bb87703162be..8b58050fd6d7 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp -@@ -290,6 +290,9 @@ static void wlserver_handle_modifiers(struct wl_listener *listener, void *data) +@@ -292,6 +292,9 @@ static void wlserver_handle_modifiers(struct wl_listener *listener, void *data) bump_input_counter(); } @@ -278,7 +2758,7 @@ index 78a86ee..99df8aa 100644 static void wlserver_handle_key(struct wl_listener *listener, void *data) { struct wlserver_keyboard *keyboard = wl_container_of( listener, keyboard, key ); -@@ -310,7 +313,14 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) +@@ -315,7 +318,14 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) keysym == XKB_KEY_XF86AudioLowerVolume || keysym == XKB_KEY_XF86AudioRaiseVolume || keysym == XKB_KEY_XF86PowerOff; @@ -294,192 +2774,32 @@ index 78a86ee..99df8aa 100644 { // Always send volume+/- to root server only, to avoid it reaching the game. struct wlr_surface *old_kb_surf = wlserver.kb_focus_surface; -@@ -319,6 +329,13 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) +@@ -323,9 +333,22 @@ static void wlserver_handle_key(struct wl_listener *listener, void *data) + if ( new_kb_surf ) { wlserver_keyboardfocus( new_kb_surf, false ); - wlr_seat_set_keyboard( wlserver.wlr.seat, keyboard->wlr ); +- wlr_seat_set_keyboard( wlserver.wlr.seat, keyboard->wlr ); ++ wlr_seat_set_keyboard( wlserver.wlr.seat, wlserver.wlr.virtual_keyboard_device ); ++ + if (is_steamshortcut) + { + // send ctrl down modifier to trigger the overlay + wlr_keyboard_modifiers ctrl_down_modifier; + ctrl_down_modifier.depressed = WLR_MODIFIER_CTRL; ++ ctrl_down_modifier.latched = WLR_MODIFIER_CTRL; ++ ctrl_down_modifier.locked = WLR_MODIFIER_CTRL; + wlr_seat_keyboard_notify_modifiers(wlserver.wlr.seat, &ctrl_down_modifier); + } ++ wlr_seat_keyboard_notify_key( wlserver.wlr.seat, event->time_msec, event->keycode, event->state ); wlserver_keyboardfocus( old_kb_surf, false ); ++ wlr_seat_set_keyboard( wlserver.wlr.seat, keyboard->wlr ); ++ return; --- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 11 Oct 2024 17:52:48 +0200 -Subject: fix: allow for disabling touch atom click - -Causes issues in certain devices (or not anymore?). - -Parameter option by Kyle. - -Co-authored-by: Kyle Gospodnetich ---- - src/main.cpp | 2 ++ - src/steamcompmgr.cpp | 5 ++++- - 2 files changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/main.cpp b/src/main.cpp -index 8381889..a76b51b 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -128,6 +128,7 @@ const struct option *gamescope_options = (struct option[]){ - { "disable-xres", no_argument, nullptr, 'x' }, - { "fade-out-duration", required_argument, nullptr, 0 }, - { "force-orientation", required_argument, nullptr, 0 }, -+ { "disable-touch-click", no_argument, nullptr, 0 }, - { "force-windows-fullscreen", no_argument, nullptr, 0 }, - { "custom-refresh-rates", required_argument, nullptr, 0 }, - -@@ -188,6 +189,7 @@ const char usage[] = - " -T, --stats-path write statistics to path\n" - " -C, --hide-cursor-delay hide cursor image after delay\n" - " -e, --steam enable Steam integration\n" -+ " --disable-touch-click disable touchscreen tap acting as a click\n" - " --xwayland-count create N xwayland servers\n" - " --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n" - " --force-orientation rotate the internal display (left, right, normal, upsidedown)\n" -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index df7616d..4a17499 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -197,6 +197,7 @@ update_runtime_info(); - gamescope::ConVar cv_adaptive_sync( "adaptive_sync", false, "Whether or not adaptive sync is enabled if available." ); - gamescope::ConVar cv_adaptive_sync_ignore_overlay( "adaptive_sync_ignore_overlay", false, "Whether or not to ignore overlay planes for pushing commits with adaptive sync." ); - gamescope::ConVar cv_adaptive_sync_overlay_cycles( "adaptive_sync_overlay_cycles", 1, "Number of vblank cycles to ignore overlay repaints before forcing a commit with adaptive sync." ); -+gamescope::ConVar cv_disable_touch_click{ "disable_touch_click", false, "Prevents touchscreen taps acting as clicks" }; - - uint64_t g_SteamCompMgrLimitedAppRefreshCycle = 16'666'666; - uint64_t g_SteamCompMgrAppRefreshCycle = 16'666'666; -@@ -5185,7 +5186,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) - MakeFocusDirty(); } } -- if (ev->atom == ctx->atoms.steamTouchClickModeAtom ) -+ if (ev->atom == ctx->atoms.steamTouchClickModeAtom && !cv_disable_touch_click ) - { - gamescope::cv_touch_click_mode = (gamescope::TouchClickMode) get_prop(ctx, ctx->root, ctx->atoms.steamTouchClickModeAtom, 0u ); - } -@@ -7476,6 +7477,8 @@ steamcompmgr_main(int argc, char **argv) - g_reshade_technique_idx = atoi(optarg); - } else if (strcmp(opt_name, "mura-map") == 0) { - set_mura_overlay(optarg); -+ } else if (strcmp(opt_name, "disable-touch-click") == 0) { -+ cv_disable_touch_click = true; - } - break; - case '?': -- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 11 Oct 2024 21:56:54 +0200 -Subject: fix(intel-gpu): allow for (enabling) hacky texture - -Disabling hacky texture will use more hardware planes, causing some devices to composite yielding lower fps. Required for intel to work ---- - src/main.cpp | 2 ++ - src/steamcompmgr.cpp | 5 ++++- - 2 files changed, 6 insertions(+), 1 deletion(-) - -diff --git a/src/main.cpp b/src/main.cpp -index a76b51b..84e05a9 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -128,6 +128,7 @@ const struct option *gamescope_options = (struct option[]){ - { "disable-xres", no_argument, nullptr, 'x' }, - { "fade-out-duration", required_argument, nullptr, 0 }, - { "force-orientation", required_argument, nullptr, 0 }, -+ { "enable-hacky-texture", no_argument, nullptr, 0 }, - { "disable-touch-click", no_argument, nullptr, 0 }, - { "force-windows-fullscreen", no_argument, nullptr, 0 }, - { "custom-refresh-rates", required_argument, nullptr, 0 }, -@@ -189,6 +190,7 @@ const char usage[] = - " -T, --stats-path write statistics to path\n" - " -C, --hide-cursor-delay hide cursor image after delay\n" - " -e, --steam enable Steam integration\n" -+ " --enable-hacky-texture enable hacky texture on hw that support it\n" - " --disable-touch-click disable touchscreen tap acting as a click\n" - " --xwayland-count create N xwayland servers\n" - " --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n" -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 4a17499..da3115f 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -147,6 +147,7 @@ static lut3d_t g_tmpLut3d; - extern int g_nDynamicRefreshHz; - - bool g_bForceHDRSupportDebug = false; -+bool g_bHackyEnabled = false; - extern float g_flInternalDisplayBrightnessNits; - extern float g_flHDRItmSdrNits; - extern float g_flHDRItmTargetNits; -@@ -2412,7 +2413,7 @@ paint_all(bool async) - if ( overlay == global_focus.inputFocusWindow ) - update_touch_scaling( &frameInfo ); - } -- else if ( !GetBackend()->UsesVulkanSwapchain() && GetBackend()->IsSessionBased() ) -+ else if ( g_bHackyEnabled && !GetBackend()->UsesVulkanSwapchain() && GetBackend()->IsSessionBased() ) - { - auto tex = vulkan_get_hacky_blank_texture(); - if ( tex != nullptr ) -@@ -7479,6 +7480,8 @@ steamcompmgr_main(int argc, char **argv) - set_mura_overlay(optarg); - } else if (strcmp(opt_name, "disable-touch-click") == 0) { - cv_disable_touch_click = true; -+ } else if (strcmp(opt_name, "enable-hacky-texture") == 0) { -+ g_bHackyEnabled = true; - } - break; - case '?': --- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 11 Oct 2024 23:01:13 +0200 -Subject: fix: re-add external orientation options to not break current - sessions (incl. applying ext. orientation) - ---- - src/main.cpp | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/main.cpp b/src/main.cpp -index 84e05a9..2398535 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -129,6 +129,8 @@ const struct option *gamescope_options = (struct option[]){ - { "fade-out-duration", required_argument, nullptr, 0 }, - { "force-orientation", required_argument, nullptr, 0 }, - { "enable-hacky-texture", no_argument, nullptr, 0 }, -+ { "force-panel-type", required_argument, nullptr, 0 }, -+ { "force-external-orientation", required_argument, nullptr, 0 }, - { "disable-touch-click", no_argument, nullptr, 0 }, - { "force-windows-fullscreen", no_argument, nullptr, 0 }, - { "custom-refresh-rates", required_argument, nullptr, 0 }, -@@ -777,7 +779,7 @@ int main(int argc, char **argv) - gamescope::cv_touch_click_mode = (gamescope::TouchClickMode) atoi( optarg ); - } else if (strcmp(opt_name, "generate-drm-mode") == 0) { - g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); -- } else if (strcmp(opt_name, "force-orientation") == 0) { -+ } else if (strcmp(opt_name, "force-orientation") == 0 || strcmp(opt_name, "force-external-orientation") == 0) { - g_DesiredInternalOrientation = force_orientation( optarg ); - } else if (strcmp(opt_name, "custom-refresh-rates") == 0) { - g_customRefreshRates = parse_custom_refresh_rates( optarg ); --- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 @@ -492,10 +2812,10 @@ Subject: fix(external): fix crash when using external touchscreens 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index 99df8aa..5e8f516 100644 +index 8b58050fd6d7..0b99c498e55d 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp -@@ -2492,8 +2492,12 @@ static void apply_touchscreen_orientation(double *x, double *y ) +@@ -2552,8 +2552,12 @@ static void apply_touchscreen_orientation(double *x, double *y ) double tx = 0; double ty = 0; @@ -511,196 +2831,7 @@ index 99df8aa..5e8f516 100644 default: case GAMESCOPE_PANEL_ORIENTATION_AUTO: -- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 11 Oct 2024 23:47:59 +0200 -Subject: feat(vrr): allow for setting refresh rate if the internal display - allows - -For the Ally, we have a set of VFP that work to set the refresh rate. -They can also be used for VRR but gamescope does not currently allow for -it. Therefore, bypass some checks to allow it to work just for this usecase. ---- - src/main.cpp | 2 ++ - src/steamcompmgr.cpp | 7 +++++-- - 2 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/src/main.cpp b/src/main.cpp -index 2398535..0621c65 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -132,6 +132,7 @@ const struct option *gamescope_options = (struct option[]){ - { "force-panel-type", required_argument, nullptr, 0 }, - { "force-external-orientation", required_argument, nullptr, 0 }, - { "disable-touch-click", no_argument, nullptr, 0 }, -+ { "enable-vrr-modesetting", no_argument, nullptr, 0 }, - { "force-windows-fullscreen", no_argument, nullptr, 0 }, - { "custom-refresh-rates", required_argument, nullptr, 0 }, - -@@ -194,6 +195,7 @@ const char usage[] = - " -e, --steam enable Steam integration\n" - " --enable-hacky-texture enable hacky texture on hw that support it\n" - " --disable-touch-click disable touchscreen tap acting as a click\n" -+ " --enable-vrr-modesetting enable setting framerate while VRR is on in the internal display\n" - " --xwayland-count create N xwayland servers\n" - " --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n" - " --force-orientation rotate the internal display (left, right, normal, upsidedown)\n" -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index da3115f..69fd348 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -148,6 +148,7 @@ extern int g_nDynamicRefreshHz; - - bool g_bForceHDRSupportDebug = false; - bool g_bHackyEnabled = false; -+bool g_bVRRModesetting = false; - extern float g_flInternalDisplayBrightnessNits; - extern float g_flHDRItmSdrNits; - extern float g_flHDRItmTargetNits; -@@ -899,7 +900,7 @@ bool g_bChangeDynamicRefreshBasedOnGameOpenRatherThanActive = false; - bool steamcompmgr_window_should_limit_fps( steamcompmgr_win_t *w ) - { - // VRR + FPS Limit needs another approach. -- if ( GetBackend()->IsVRRActive() ) -+ if ( GetBackend()->IsVRRActive() && !(g_bVRRModesetting && GetBackend()->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL) ) - return false; - - return w && !window_is_steam( w ) && !w->isOverlay && !w->isExternalOverlay; -@@ -923,7 +924,7 @@ steamcompmgr_user_has_any_game_open() - - bool steamcompmgr_window_should_refresh_switch( steamcompmgr_win_t *w ) - { -- if ( GetBackend()->IsVRRActive() ) -+ if ( GetBackend()->IsVRRActive() && !(g_bVRRModesetting && GetBackend()->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL)) - return false; - - if ( g_bChangeDynamicRefreshBasedOnGameOpenRatherThanActive ) -@@ -7480,6 +7481,8 @@ steamcompmgr_main(int argc, char **argv) - set_mura_overlay(optarg); - } else if (strcmp(opt_name, "disable-touch-click") == 0) { - cv_disable_touch_click = true; -+ } else if (strcmp(opt_name, "enable-vrr-modesetting") == 0) { -+ g_bVRRModesetting = true; - } else if (strcmp(opt_name, "enable-hacky-texture") == 0) { - g_bHackyEnabled = true; - } --- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 11 Oct 2024 19:09:05 +0200 -Subject: feat: add external option that now only lies to steam - -Previously, there was a force-panel option that allowed for VRR. -However, this is no longer the case and VRR works fine. -This option still allows for scaling the display though. So, create a -variant of the patch that only does that. ---- - src/main.cpp | 16 ++++++++++++++++ - src/steamcompmgr.cpp | 2 +- - src/steamcompmgr.hpp | 1 + - src/wlserver.cpp | 2 +- - src/wlserver.hpp | 1 + - 5 files changed, 20 insertions(+), 2 deletions(-) - -diff --git a/src/main.cpp b/src/main.cpp -index 0621c65..056e1c1 100644 ---- a/src/main.cpp -+++ b/src/main.cpp -@@ -199,6 +199,7 @@ const char usage[] = - " --xwayland-count create N xwayland servers\n" - " --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n" - " --force-orientation rotate the internal display (left, right, normal, upsidedown)\n" -+ " --force-panel-type lie to steam that the screen is external\n" - " --force-windows-fullscreen force windows inside of gamescope to be the size of the nested display (fullscreen)\n" - " --cursor-scale-height if specified, sets a base output height to linearly scale the cursor against.\n" - " --hdr-enabled enable HDR output (needs Gamescope WSI layer enabled for support from clients)\n" -@@ -373,6 +374,19 @@ static GamescopePanelOrientation force_orientation(const char *str) - } - } - -+bool g_FakeExternal = false; -+static bool force_panel_type_external(const char *str) -+{ -+ if (strcmp(str, "internal") == 0) { -+ return false; -+ } else if (strcmp(str, "external") == 0) { -+ return true; -+ } else { -+ fprintf( stderr, "gamescope: invalid value for --force-panel-type\n" ); -+ exit(1); -+ } -+} -+ - static enum GamescopeUpscaleScaler parse_upscaler_scaler(const char *str) - { - if (strcmp(str, "auto") == 0) { -@@ -783,6 +797,8 @@ int main(int argc, char **argv) - g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); - } else if (strcmp(opt_name, "force-orientation") == 0 || strcmp(opt_name, "force-external-orientation") == 0) { - g_DesiredInternalOrientation = force_orientation( optarg ); -+ } else if (strcmp(opt_name, "force-panel-type") == 0) { -+ g_FakeExternal = force_panel_type_external( optarg ); - } else if (strcmp(opt_name, "custom-refresh-rates") == 0) { - g_customRefreshRates = parse_custom_refresh_rates( optarg ); - } else if (strcmp(opt_name, "sharpness") == 0 || -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 69fd348..3dd64f8 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -7192,7 +7192,7 @@ void update_mode_atoms(xwayland_ctx_t *root_ctx, bool* needs_flush = nullptr) - if (needs_flush) - *needs_flush = true; - -- if ( GetBackend()->GetCurrentConnector() && GetBackend()->GetCurrentConnector()->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL ) -+ if ( !g_FakeExternal && GetBackend()->GetCurrentConnector() && GetBackend()->GetCurrentConnector()->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL ) - { - XDeleteProperty(root_ctx->dpy, root_ctx->root, root_ctx->atoms.gamescopeDisplayModeListExternal); - -diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp -index 9f384c4..30e48e8 100644 ---- a/src/steamcompmgr.hpp -+++ b/src/steamcompmgr.hpp -@@ -127,6 +127,7 @@ extern float focusedWindowScaleY; - extern float focusedWindowOffsetX; - extern float focusedWindowOffsetY; - -+extern bool g_FakeExternal; - extern bool g_bFSRActive; - - extern uint32_t inputCounter; -diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index 5e8f516..1eeaa25 100644 ---- a/src/wlserver.cpp -+++ b/src/wlserver.cpp -@@ -1078,7 +1078,7 @@ static uint32_t get_conn_display_info_flags() - return 0; - - uint32_t flags = 0; -- if ( pConn->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL ) -+ if ( pConn->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL && !g_FakeExternal ) - flags |= GAMESCOPE_CONTROL_DISPLAY_FLAG_INTERNAL_DISPLAY; - if ( pConn->SupportsVRR() ) - flags |= GAMESCOPE_CONTROL_DISPLAY_FLAG_SUPPORTS_VRR; -diff --git a/src/wlserver.hpp b/src/wlserver.hpp -index 0569472..104f7a2 100644 ---- a/src/wlserver.hpp -+++ b/src/wlserver.hpp -@@ -190,6 +190,7 @@ struct wlserver_t { - }; - - extern struct wlserver_t wlserver; -+extern bool g_FakeExternal; - - std::vector wlserver_xdg_commit_queue(); - --- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 @@ -716,10 +2847,10 @@ custom modeline generation has been provided. 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 75c3258..f014be9 100644 +index ffce5d7d8448..c4f358fbc933 100644 --- a/src/Backends/DRMBackend.cpp +++ b/src/Backends/DRMBackend.cpp -@@ -2161,7 +2161,9 @@ namespace gamescope +@@ -2169,7 +2169,9 @@ namespace gamescope sol::optional otDynamicRefreshRates = tTable["dynamic_refresh_rates"]; sol::optional ofnDynamicModegen = tTable["dynamic_modegen"]; @@ -731,104 +2862,33 @@ index 75c3258..f014be9 100644 m_Mutable.ValidDynamicRefreshRates = TableToVector( *otDynamicRefreshRates ); -- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 25 Oct 2024 21:22:10 +0200 -Subject: fix(vrr): allow frame limiter to work with VRR enabled - -Down to 48hz, modeset the correct framerate. Below 48hz, -disable VRR and use the classic frame limiter. ---- - src/steamcompmgr.cpp | 30 ++++++++++++++++++++++++++++-- - 1 file changed, 28 insertions(+), 2 deletions(-) - -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 3dd64f8..7dacfe7 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -165,6 +165,7 @@ uint32_t g_reshade_technique_idx = 0; - - bool g_bSteamIsActiveWindow = false; - bool g_bForceInternal = false; -+bool g_bVRRRequested = false; - - static std::vector< steamcompmgr_win_t* > GetGlobalPossibleFocusWindows(); - static bool -@@ -827,6 +828,28 @@ static void _update_app_target_refresh_cycle() - { - auto rates = GetBackend()->GetCurrentConnector()->GetValidDynamicRefreshRates(); - -+ if (g_bVRRModesetting) { -+ if (g_bVRRRequested) { -+ // If modeset VRR, go upwards to match the refresh rate 1-1. Refresh -+ // doubling would hurt us here by breaking the frame limiter. -+ for ( auto rate = rates.begin(); rate != rates.end(); rate++ ) -+ { -+ if ((int)*rate == target_fps) -+ { -+ g_nDynamicRefreshRate[ type ] = *rate; -+ // Enable VRR as we have the correct refresh rate -+ cv_adaptive_sync = true; -+ return; -+ } -+ } -+ // Otherwise, disable VRR as we can't match the refresh rate 1-1 -+ // (e.g., below 48hz). -+ cv_adaptive_sync = false; -+ } else { -+ cv_adaptive_sync = false; -+ } -+ } -+ - // Find highest mode to do refresh doubling with. - for ( auto rate = rates.rbegin(); rate != rates.rend(); rate++ ) - { -@@ -5522,8 +5545,11 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) - } - if ( ev->atom == ctx->atoms.gamescopeVRREnabled ) - { -- bool enabled = !!get_prop( ctx, ctx->root, ctx->atoms.gamescopeVRREnabled, 0 ); -- cv_adaptive_sync = enabled; -+ g_bVRRRequested = !!get_prop( ctx, ctx->root, ctx->atoms.gamescopeVRREnabled, 0 ); -+ // Try to match refresh rate and have that set the cv_adaptive_sync only if it can -+ if (g_bVRRModesetting) update_app_target_refresh_cycle(); -+ // otherwise, fall back to original behavior -+ else cv_adaptive_sync = g_bVRRRequested; - } - if ( ev->atom == ctx->atoms.gamescopeDisplayForceInternal ) - { --- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Antheas Kapenekakis Date: Wed, 30 Oct 2024 00:39:03 +0100 -Subject: fix(battery): run at half hz while at steamUI and disable VRR V2 + - param +Subject: fix(battery): run at half hz while at steamUI with atom --- - src/steamcompmgr.cpp | 43 ++++++++++++++++++++++++++++++++----------- - 1 file changed, 32 insertions(+), 11 deletions(-) + src/steamcompmgr.cpp | 44 ++++++++++++++++++++++++++++++++++---------- + src/xwayland_ctx.hpp | 2 ++ + 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 7dacfe7..4098c44 100644 +index e46c34bbfbc0..3b3a106b13e9 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp -@@ -166,6 +166,9 @@ uint32_t g_reshade_technique_idx = 0; +@@ -165,6 +165,8 @@ uint32_t g_reshade_technique_idx = 0; + bool g_bSteamIsActiveWindow = false; bool g_bForceInternal = false; - bool g_bVRRRequested = false; -+bool g_bVRRCanEnable = false; +bool b_bForceFrameLimit = false; +bool g_bRefreshHalveEnable = false; static std::vector< steamcompmgr_win_t* > GetGlobalPossibleFocusWindows(); static bool -@@ -793,6 +796,7 @@ uint64_t g_uCurrentBasePlaneCommitID = 0; +@@ -791,6 +793,7 @@ uint64_t g_uCurrentBasePlaneCommitID = 0; bool g_bCurrentBasePlaneIsFifo = false; static int g_nSteamCompMgrTargetFPS = 0; @@ -836,7 +2896,7 @@ index 7dacfe7..4098c44 100644 static uint64_t g_uDynamicRefreshEqualityTime = 0; static int g_nDynamicRefreshRate[gamescope::GAMESCOPE_SCREEN_TYPE_COUNT] = { 0, 0 }; // Delay to stop modes flickering back and forth. -@@ -812,7 +816,7 @@ static void _update_app_target_refresh_cycle() +@@ -810,7 +813,7 @@ static void _update_app_target_refresh_cycle() int target_fps = g_nCombinedAppRefreshCycleOverride[type]; g_nDynamicRefreshRate[ type ] = 0; @@ -845,7 +2905,7 @@ index 7dacfe7..4098c44 100644 if ( !target_fps ) { -@@ -821,7 +825,7 @@ static void _update_app_target_refresh_cycle() +@@ -819,7 +822,7 @@ static void _update_app_target_refresh_cycle() if ( g_nCombinedAppRefreshCycleChangeFPS[ type ] ) { @@ -854,26 +2914,7 @@ index 7dacfe7..4098c44 100644 } if ( g_nCombinedAppRefreshCycleChangeRefresh[ type ] ) -@@ -838,15 +842,15 @@ static void _update_app_target_refresh_cycle() - { - g_nDynamicRefreshRate[ type ] = *rate; - // Enable VRR as we have the correct refresh rate -- cv_adaptive_sync = true; -+ g_bVRRCanEnable = true; - return; - } - } - // Otherwise, disable VRR as we can't match the refresh rate 1-1 - // (e.g., below 48hz). -- cv_adaptive_sync = false; -+ g_bVRRCanEnable = false; - } else { -- cv_adaptive_sync = false; -+ g_bVRRCanEnable = false; - } - } - -@@ -864,9 +868,9 @@ static void _update_app_target_refresh_cycle() +@@ -840,9 +843,9 @@ static void _update_app_target_refresh_cycle() static void update_app_target_refresh_cycle() { @@ -885,7 +2926,7 @@ index 7dacfe7..4098c44 100644 update_runtime_info(); } -@@ -5052,7 +5056,7 @@ update_runtime_info() +@@ -5052,7 +5055,7 @@ update_runtime_info() if ( g_nRuntimeInfoFd < 0 ) return; @@ -894,16 +2935,25 @@ index 7dacfe7..4098c44 100644 pwrite( g_nRuntimeInfoFd, &limiter_enabled, sizeof( limiter_enabled ), 0 ); } -@@ -5109,7 +5113,7 @@ static bool steamcompmgr_should_vblank_window( bool bShouldLimitFPS, uint64_t vb - - int nRefreshHz = gamescope::ConvertmHzToHz( g_nNestedRefresh ? g_nNestedRefresh : g_nOutputRefresh ); - int nTargetFPS = g_nSteamCompMgrTargetFPS; -- if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && nRefreshHz > nTargetFPS ) -+ if ( g_nSteamCompMgrTargetFPS && (bShouldLimitFPS || b_bForceFrameLimit) && nRefreshHz > nTargetFPS ) +@@ -5115,7 +5118,7 @@ static bool steamcompmgr_should_vblank_window( bool bShouldLimitFPS, uint64_t vb { - int nVblankDivisor = nRefreshHz / nTargetFPS; + bool bCloseEnough = std::abs( g_nSteamCompMgrTargetFPS - nRefreshHz ) < 2; -@@ -5485,7 +5489,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) +- if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && w && !bCloseEnough ) ++ if ( g_nSteamCompMgrTargetFPS && (bShouldLimitFPS || b_bForceFrameLimit) && w && !bCloseEnough ) + { + uint64_t schedule = w->last_commit_first_latch_time + g_SteamCompMgrLimitedAppRefreshCycle; + +@@ -5133,7 +5136,7 @@ static bool steamcompmgr_should_vblank_window( bool bShouldLimitFPS, uint64_t vb + } + else + { +- if ( g_nSteamCompMgrTargetFPS && bShouldLimitFPS && nRefreshHz > nTargetFPS ) ++ if ( g_nSteamCompMgrTargetFPS && (bShouldLimitFPS || b_bForceFrameLimit) && nRefreshHz > nTargetFPS ) + { + int nVblankDivisor = nRefreshHz / nTargetFPS; + +@@ -5516,7 +5519,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) } if ( ev->atom == ctx->atoms.gamescopeFPSLimit ) { @@ -912,58 +2962,7 @@ index 7dacfe7..4098c44 100644 update_runtime_info(); } for (int i = 0; i < gamescope::GAMESCOPE_SCREEN_TYPE_COUNT; i++) -@@ -5549,7 +5553,7 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) - // Try to match refresh rate and have that set the cv_adaptive_sync only if it can - if (g_bVRRModesetting) update_app_target_refresh_cycle(); - // otherwise, fall back to original behavior -- else cv_adaptive_sync = g_bVRRRequested; -+ else g_bVRRCanEnable = g_bVRRRequested; - } - if ( ev->atom == ctx->atoms.gamescopeDisplayForceInternal ) - { -@@ -7628,6 +7632,23 @@ steamcompmgr_main(int argc, char **argv) - // as a question. - const bool bIsVBlankFromTimer = vblank; - -+ if ( g_bRefreshHalveEnable && window_is_steam( global_focus.focusWindow ) ) { -+ // Halve refresh rate and disable vrr on SteamUI -+ cv_adaptive_sync = false; -+ int nRealRefreshHz = gamescope::ConvertmHzToHz( g_nNestedRefresh ? g_nNestedRefresh : g_nOutputRefresh ); -+ if (nRealRefreshHz > 100 && g_nSteamCompMgrTargetFPSreq > 34) { -+ g_nSteamCompMgrTargetFPS = nRealRefreshHz / 2; -+ b_bForceFrameLimit = true; -+ } else { -+ g_nSteamCompMgrTargetFPS = g_nSteamCompMgrTargetFPSreq; -+ b_bForceFrameLimit = false; -+ } -+ } else { -+ cv_adaptive_sync = g_bVRRCanEnable; -+ g_nSteamCompMgrTargetFPS = g_nSteamCompMgrTargetFPSreq; -+ b_bForceFrameLimit = false; -+ } -+ - // We can always vblank if VRR. - const bool bVRR = GetBackend()->IsVRRActive(); - if ( bVRR ) --- -2.47.1 - - -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Antheas Kapenekakis -Date: Fri, 1 Nov 2024 17:27:54 +0100 -Subject: feat(battery): add atom for controlling frame halving - ---- - src/steamcompmgr.cpp | 6 ++++++ - src/xwayland_ctx.hpp | 2 ++ - 2 files changed, 8 insertions(+) - -diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 4098c44..6c8ce74 100644 ---- a/src/steamcompmgr.cpp -+++ b/src/steamcompmgr.cpp -@@ -5919,6 +5919,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) +@@ -5943,6 +5946,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) MakeFocusDirty(); } } @@ -974,7 +2973,16 @@ index 4098c44..6c8ce74 100644 } static int -@@ -7089,6 +7093,8 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ +@@ -6300,7 +6307,7 @@ void handle_presented_for_window( steamcompmgr_win_t* w ) + + uint64_t next_refresh_time = g_SteamCompMgrVBlankTime.schedule.ulTargetVBlank; + +- uint64_t refresh_cycle = g_nSteamCompMgrTargetFPS && steamcompmgr_window_should_limit_fps( w ) ++ uint64_t refresh_cycle = g_nSteamCompMgrTargetFPS && (steamcompmgr_window_should_limit_fps( w ) || b_bForceFrameLimit) + ? g_SteamCompMgrLimitedAppRefreshCycle + : g_SteamCompMgrAppRefreshCycle; + +@@ -7124,6 +7131,8 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ ctx->atoms.primarySelection = XInternAtom(ctx->dpy, "PRIMARY", false); ctx->atoms.targets = XInternAtom(ctx->dpy, "TARGETS", false); @@ -983,8 +2991,39 @@ index 4098c44..6c8ce74 100644 ctx->root_width = DisplayWidth(ctx->dpy, ctx->scr); ctx->root_height = DisplayHeight(ctx->dpy, ctx->scr); +@@ -7542,7 +7551,7 @@ steamcompmgr_main(int argc, char **argv) + } else if (strcmp(opt_name, "hdr-itm-target-nits") == 0) { + g_flHDRItmTargetNits = atof(optarg); + } else if (strcmp(opt_name, "framerate-limit") == 0) { +- g_nSteamCompMgrTargetFPS = atoi(optarg); ++ g_nSteamCompMgrTargetFPSreq = atoi(optarg); + } else if (strcmp(opt_name, "reshade-effect") == 0) { + g_reshade_effect = optarg; + } else if (strcmp(opt_name, "reshade-technique-idx") == 0) { +@@ -7667,6 +7676,21 @@ steamcompmgr_main(int argc, char **argv) + // as a question. + const bool bIsVBlankFromTimer = vblank; + ++ if ( g_bRefreshHalveEnable && window_is_steam( global_focus.focusWindow ) ) { ++ // Halve refresh rate on SteamUI ++ int nRealRefreshHz = gamescope::ConvertmHzToHz( g_nNestedRefresh ? g_nNestedRefresh : g_nOutputRefresh ); ++ if (nRealRefreshHz > 100 && (g_nSteamCompMgrTargetFPSreq > 50 || !g_nSteamCompMgrTargetFPSreq)) { ++ g_nSteamCompMgrTargetFPS = nRealRefreshHz / 2; ++ b_bForceFrameLimit = true; ++ } else { ++ g_nSteamCompMgrTargetFPS = g_nSteamCompMgrTargetFPSreq; ++ b_bForceFrameLimit = false; ++ } ++ } else { ++ g_nSteamCompMgrTargetFPS = g_nSteamCompMgrTargetFPSreq; ++ b_bForceFrameLimit = false; ++ } ++ + // We can always vblank if VRR. + const bool bVRR = GetBackend()->IsVRRActive(); + if ( bVRR ) diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp -index df2af70..e4eec9f 100644 +index df2af70d19ae..e4eec9fa0c48 100644 --- a/src/xwayland_ctx.hpp +++ b/src/xwayland_ctx.hpp @@ -246,6 +246,8 @@ struct xwayland_ctx_t final : public gamescope::IWaitable @@ -997,7 +3036,7 @@ index df2af70..e4eec9f 100644 bool HasQueuedEvents(); -- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 @@ -1013,10 +3052,10 @@ Subject: feat: add DPMS support through an Atom 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index f014be9..6bb0b88 100644 +index c4f358fbc933..856b03fc3747 100644 --- a/src/Backends/DRMBackend.cpp +++ b/src/Backends/DRMBackend.cpp -@@ -2669,6 +2669,9 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI +@@ -2702,6 +2702,9 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI drm->needs_modeset = true; } @@ -1026,7 +3065,7 @@ index f014be9..6bb0b88 100644 drm_colorspace uColorimetry = DRM_MODE_COLORIMETRY_DEFAULT; const bool bWantsHDR10 = g_bOutputHDREnabled && frameInfo->outputEncodingEOTF == EOTF_PQ; -@@ -2724,7 +2727,7 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI +@@ -2757,7 +2760,7 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK; // We do internal refcounting with these events @@ -1035,7 +3074,7 @@ index f014be9..6bb0b88 100644 flags |= DRM_MODE_PAGE_FLIP_EVENT; if ( async || g_bForceAsyncFlips ) -@@ -2797,7 +2800,13 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI +@@ -2830,7 +2833,13 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI if ( drm->pCRTC ) { @@ -1050,7 +3089,7 @@ index f014be9..6bb0b88 100644 drm->pCRTC->GetProperties().MODE_ID->SetPendingValue( drm->req, drm->pending.mode_id ? drm->pending.mode_id->GetBlobValue() : 0lu, true ); if ( drm->pCRTC->GetProperties().VRR_ENABLED ) -@@ -2828,7 +2837,7 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI +@@ -2861,7 +2870,7 @@ int drm_prepare( struct drm_t *drm, bool async, const struct FrameInfo_t *frameI drm->flags = flags; int ret; @@ -1059,7 +3098,7 @@ index f014be9..6bb0b88 100644 ret = 0; } else if ( drm->bUseLiftoff ) { ret = drm_prepare_liftoff( drm, frameInfo, needs_modeset ); -@@ -3391,6 +3400,7 @@ namespace gamescope +@@ -3424,6 +3433,7 @@ namespace gamescope FrameInfo_t presentCompFrameInfo = {}; presentCompFrameInfo.allowVRR = pFrameInfo->allowVRR; @@ -1068,7 +3107,7 @@ index f014be9..6bb0b88 100644 if ( bNeedsFullComposite ) diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp -index b537170..ccabd88 100644 +index a3a11a7ba96f..0f8cba8516c0 100644 --- a/src/rendervulkan.hpp +++ b/src/rendervulkan.hpp @@ -281,6 +281,8 @@ struct FrameInfo_t @@ -1081,11 +3120,11 @@ index b537170..ccabd88 100644 struct Layer_t { diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index 6c8ce74..dfee904 100644 +index 3b3a106b13e9..fcdc9ac1559f 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp -@@ -169,6 +169,8 @@ bool g_bVRRRequested = false; - bool g_bVRRCanEnable = false; +@@ -167,6 +167,8 @@ bool g_bSteamIsActiveWindow = false; + bool g_bForceInternal = false; bool b_bForceFrameLimit = false; bool g_bRefreshHalveEnable = false; +bool g_bDPMS = false; @@ -1093,16 +3132,16 @@ index 6c8ce74..dfee904 100644 static std::vector< steamcompmgr_win_t* > GetGlobalPossibleFocusWindows(); static bool -@@ -2271,7 +2273,7 @@ bool ShouldDrawCursor() +@@ -2254,7 +2256,7 @@ bool ShouldDrawCursor() } static void -paint_all(bool async) -+paint_all(bool async, bool dpms) ++paint_all( bool async, bool dpms ) { gamescope_xwayland_server_t *root_server = wlserver_get_xwayland_server(0); xwayland_ctx_t *root_ctx = root_server->ctx.get(); -@@ -2322,6 +2324,7 @@ paint_all(bool async) +@@ -2305,6 +2307,7 @@ paint_all(bool async) frameInfo.outputEncodingEOTF = g_ColorMgmt.pending.outputEncodingEOTF; frameInfo.allowVRR = cv_adaptive_sync; frameInfo.bFadingOut = fadingOut; @@ -1110,7 +3149,7 @@ index 6c8ce74..dfee904 100644 // If the window we'd paint as the base layer is the streaming client, // find the video underlay and put it up first in the scenegraph -@@ -5923,6 +5926,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) +@@ -5950,6 +5953,10 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) { g_bRefreshHalveEnable = !!get_prop( ctx, ctx->root, ctx->atoms.gamescopeFrameHalveAtom, 0 ); } @@ -1121,7 +3160,7 @@ index 6c8ce74..dfee904 100644 } static int -@@ -7094,6 +7101,7 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ +@@ -7132,6 +7139,7 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ ctx->atoms.targets = XInternAtom(ctx->dpy, "TARGETS", false); ctx->atoms.gamescopeFrameHalveAtom = XInternAtom( ctx->dpy, "GAMESCOPE_STEAMUI_HALFHZ", false );; @@ -1129,21 +3168,21 @@ index 6c8ce74..dfee904 100644 ctx->root_width = DisplayWidth(ctx->dpy, ctx->scr); ctx->root_height = DisplayHeight(ctx->dpy, ctx->scr); -@@ -8061,9 +8069,10 @@ steamcompmgr_main(int argc, char **argv) - bShouldPaint = false; +@@ -8127,9 +8135,10 @@ steamcompmgr_main(int argc, char **argv) + bShouldPaint = true; } - if ( bShouldPaint ) -+ if (bShouldPaint || (g_bDPMS != g_bDPMS_set && vblank)) ++ if ( bShouldPaint || (g_bDPMS != g_bDPMS_set && vblank) ) { - paint_all( eFlipType == FlipType::Async ); + g_bDPMS_set = g_bDPMS; -+ paint_all( eFlipType == FlipType::Async, g_bDPMS ); ++ paint_all( eFlipType == FlipType::Async, g_bDPMS ); hasRepaint = false; hasRepaintNonBasePlane = false; diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp -index e4eec9f..2347cbb 100644 +index e4eec9fa0c48..2347cbb3340c 100644 --- a/src/xwayland_ctx.hpp +++ b/src/xwayland_ctx.hpp @@ -248,6 +248,7 @@ struct xwayland_ctx_t final : public gamescope::IWaitable @@ -1155,45 +3194,67 @@ index e4eec9f..2347cbb 100644 bool HasQueuedEvents(); -- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Joshua Tam <297250+joshuatam@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:51:02 +0800 -Subject: feat: add rotation shader for rotating output +Subject: feat(intel): add rotation shader for rotating output --- - src/Backends/DRMBackend.cpp | 29 +++++++- - src/main.cpp | 6 ++ - src/main.hpp | 1 + + src/Backends/DRMBackend.cpp | 35 +++++++++- + src/main.cpp | 7 ++ + src/main.hpp | 2 + src/meson.build | 1 + src/rendervulkan.cpp | 126 ++++++++++++++++++++++++++++++----- src/rendervulkan.hpp | 6 +- src/shaders/cs_rotation.comp | 53 +++++++++++++++ src/wlserver.cpp | 5 ++ - 8 files changed, 208 insertions(+), 19 deletions(-) + 8 files changed, 216 insertions(+), 19 deletions(-) create mode 100644 src/shaders/cs_rotation.comp diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 6bb0b88..506963d 100644 +index 856b03fc3747..e1547f4a1a9b 100644 --- a/src/Backends/DRMBackend.cpp +++ b/src/Backends/DRMBackend.cpp -@@ -1752,7 +1752,7 @@ LiftoffStateCacheEntry FrameInfoToLiftoffStateCacheEntry( struct drm_t *drm, con +@@ -1530,6 +1530,10 @@ static void update_drm_effective_orientations( struct drm_t *drm, const drmModeM + if ( pDRMInternalConnector != drm->pConnector ) + pInternalMode = find_mode( pDRMInternalConnector->GetModeConnector(), 0, 0, 0 ); + ++ if ( g_bUseRotationShader ) { ++ g_bEnableDRMRotationShader = true; ++ } ++ + pDRMInternalConnector->UpdateEffectiveOrientation( pInternalMode ); + } + +@@ -1541,6 +1545,10 @@ static void update_drm_effective_orientations( struct drm_t *drm, const drmModeM + if ( pDRMExternalConnector != drm->pConnector ) + pExternalMode = find_mode( pDRMExternalConnector->GetModeConnector(), 0, 0, 0 ); + ++ if ( g_bUseRotationShader ) { ++ g_bEnableDRMRotationShader = false; ++ } ++ + pDRMExternalConnector->UpdateEffectiveOrientation( pExternalMode ); + } + } +@@ -1754,7 +1762,7 @@ LiftoffStateCacheEntry FrameInfoToLiftoffStateCacheEntry( struct drm_t *drm, con uint64_t crtcW = srcWidth / frameInfo->layers[ i ].scale.x; uint64_t crtcH = srcHeight / frameInfo->layers[ i ].scale.y; - if (g_bRotated) -+ if (g_bRotated && !g_bUseRotationShader) ++ if (g_bRotated && !g_bEnableDRMRotationShader) { int64_t imageH = frameInfo->layers[ i ].tex->contentHeight() / frameInfo->layers[ i ].scale.y; -@@ -2045,6 +2045,17 @@ namespace gamescope +@@ -2047,6 +2055,17 @@ namespace gamescope void CDRMConnector::UpdateEffectiveOrientation( const drmModeModeInfo *pMode ) { -+ if (g_bUseRotationShader) -+ { ++ if (g_bEnableDRMRotationShader) ++ { + drm_log.infof("Using rotation shader"); + if (g_DesiredInternalOrientation == GAMESCOPE_PANEL_ORIENTATION_270) { + m_ChosenOrientation = GAMESCOPE_PANEL_ORIENTATION_180; @@ -1206,27 +3267,25 @@ index 6bb0b88..506963d 100644 if ( this->GetScreenType() == GAMESCOPE_SCREEN_TYPE_INTERNAL && g_DesiredInternalOrientation != GAMESCOPE_PANEL_ORIENTATION_AUTO ) { m_ChosenOrientation = g_DesiredInternalOrientation; -@@ -3035,6 +3046,15 @@ bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ) +@@ -3068,6 +3087,13 @@ bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ) g_bRotated = false; g_nOutputWidth = mode->hdisplay; g_nOutputHeight = mode->vdisplay; + -+ if (g_bUseRotationShader && drm->pConnector->GetScreenType() == gamescope::GAMESCOPE_SCREEN_TYPE_INTERNAL) { ++ if (g_bEnableDRMRotationShader) { + g_bRotated = true; + g_nOutputWidth = mode->vdisplay; + g_nOutputHeight = mode->hdisplay; -+ } else { -+ g_bUseRotationShader = false; + } + break; case GAMESCOPE_PANEL_ORIENTATION_90: case GAMESCOPE_PANEL_ORIENTATION_270: -@@ -3294,6 +3314,11 @@ namespace gamescope +@@ -3327,6 +3353,11 @@ namespace gamescope bNeedsFullComposite |= !!(g_uCompositeDebug & CompositeDebugFlag::Heatmap); -+ if (g_bUseRotationShader) ++ if (g_bEnableDRMRotationShader) + { + bNeedsFullComposite = true; + } @@ -1234,17 +3293,17 @@ index 6bb0b88..506963d 100644 bool bDoComposite = true; if ( !bNeedsFullComposite && !bWantsPartialComposite ) { -@@ -3384,7 +3409,7 @@ namespace gamescope +@@ -3417,7 +3448,7 @@ namespace gamescope if ( bDefer && !!( g_uCompositeDebug & CompositeDebugFlag::Markers ) ) g_uCompositeDebug |= CompositeDebugFlag::Markers_Partial; - std::optional oCompositeResult = vulkan_composite( &compositeFrameInfo, nullptr, !bNeedsFullComposite ); -+ std::optional oCompositeResult = vulkan_composite( &compositeFrameInfo, nullptr, !bNeedsFullComposite, nullptr, true, nullptr, g_bUseRotationShader ); ++ std::optional oCompositeResult = vulkan_composite( &compositeFrameInfo, nullptr, !bNeedsFullComposite, nullptr, true, nullptr, g_bEnableDRMRotationShader ); m_bWasCompositing = true; diff --git a/src/main.cpp b/src/main.cpp -index 056e1c1..f61c88f 100644 +index 1443f49b51e9..c96b8f0ac39e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,6 +127,7 @@ const struct option *gamescope_options = (struct option[]){ @@ -1253,51 +3312,53 @@ index 056e1c1..f61c88f 100644 { "fade-out-duration", required_argument, nullptr, 0 }, + { "use-rotation-shader", required_argument, nullptr, 0 }, { "force-orientation", required_argument, nullptr, 0 }, - { "enable-hacky-texture", no_argument, nullptr, 0 }, - { "force-panel-type", required_argument, nullptr, 0 }, -@@ -198,6 +199,7 @@ const char usage[] = - " --enable-vrr-modesetting enable setting framerate while VRR is on in the internal display\n" + { "force-windows-fullscreen", no_argument, nullptr, 0 }, + { "custom-refresh-rates", required_argument, nullptr, 0 }, +@@ -190,6 +191,7 @@ const char usage[] = + " -e, --steam enable Steam integration\n" " --xwayland-count create N xwayland servers\n" " --prefer-vk-device prefer Vulkan device for compositing (ex: 1002:7300)\n" + " --use-rotation-shader use rotation shader for rotating the screen\n" " --force-orientation rotate the internal display (left, right, normal, upsidedown)\n" - " --force-panel-type lie to steam that the screen is external\n" " --force-windows-fullscreen force windows inside of gamescope to be the size of the nested display (fullscreen)\n" -@@ -357,6 +359,8 @@ static gamescope::GamescopeModeGeneration parse_gamescope_mode_generation( const + " --cursor-scale-height if specified, sets a base output height to linearly scale the cursor against.\n" +@@ -348,6 +350,9 @@ static gamescope::GamescopeModeGeneration parse_gamescope_mode_generation( const } } +bool g_bUseRotationShader = false; ++bool g_bEnableDRMRotationShader = false; + GamescopePanelOrientation g_DesiredInternalOrientation = GAMESCOPE_PANEL_ORIENTATION_AUTO; static GamescopePanelOrientation force_orientation(const char *str) { -@@ -797,6 +801,8 @@ int main(int argc, char **argv) +@@ -803,6 +808,8 @@ int main(int argc, char **argv) g_eGamescopeModeGeneration = parse_gamescope_mode_generation( optarg ); - } else if (strcmp(opt_name, "force-orientation") == 0 || strcmp(opt_name, "force-external-orientation") == 0) { + } else if (strcmp(opt_name, "force-orientation") == 0) { g_DesiredInternalOrientation = force_orientation( optarg ); + } else if (strcmp(opt_name, "use-rotation-shader") == 0) { + g_bUseRotationShader = true; - } else if (strcmp(opt_name, "force-panel-type") == 0) { - g_FakeExternal = force_panel_type_external( optarg ); } else if (strcmp(opt_name, "custom-refresh-rates") == 0) { + g_customRefreshRates = parse_custom_refresh_rates( optarg ); + } else if (strcmp(opt_name, "sharpness") == 0 || diff --git a/src/main.hpp b/src/main.hpp -index 390c04a..2464afa 100644 +index 390c04a63ecd..e7b857d44b0d 100644 --- a/src/main.hpp +++ b/src/main.hpp -@@ -22,6 +22,7 @@ extern bool g_bForceRelativeMouse; +@@ -22,6 +22,8 @@ extern bool g_bForceRelativeMouse; extern int g_nOutputRefresh; // mHz extern bool g_bOutputHDREnabled; extern bool g_bForceInternal; +extern bool g_bUseRotationShader; ++extern bool g_bEnableDRMRotationShader; extern bool g_bFullscreen; diff --git a/src/meson.build b/src/meson.build -index 74fc033..d4ff3ea 100644 +index 842768ce7ce4..0a0e958ba313 100644 --- a/src/meson.build +++ b/src/meson.build -@@ -70,6 +70,7 @@ shader_src = [ +@@ -73,6 +73,7 @@ shader_src = [ 'shaders/cs_nis.comp', 'shaders/cs_nis_fp16.comp', 'shaders/cs_rgb_to_nv12.comp', @@ -1306,7 +3367,7 @@ index 74fc033..d4ff3ea 100644 spirv_shaders = glsl_generator.process(shader_src) diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp -index 54d7608..10d6c78 100644 +index b8412b8fdf2f..d833d0093830 100644 --- a/src/rendervulkan.cpp +++ b/src/rendervulkan.cpp @@ -48,6 +48,7 @@ @@ -1317,7 +3378,7 @@ index 54d7608..10d6c78 100644 #define A_CPU #include "shaders/ffx_a.h" -@@ -898,6 +899,7 @@ bool CVulkanDevice::createShaders() +@@ -904,6 +905,7 @@ bool CVulkanDevice::createShaders() SHADER(NIS, cs_nis); } SHADER(RGB_TO_NV12, cs_rgb_to_nv12); @@ -1325,7 +3386,7 @@ index 54d7608..10d6c78 100644 #undef SHADER for (uint32_t i = 0; i < shaderInfos.size(); i++) -@@ -1128,6 +1130,7 @@ void CVulkanDevice::compileAllPipelines() +@@ -1134,6 +1136,7 @@ void CVulkanDevice::compileAllPipelines() SHADER(EASU, 1, 1, 1); SHADER(NIS, 1, 1, 1); SHADER(RGB_TO_NV12, 1, 1, 1); @@ -1333,14 +3394,14 @@ index 54d7608..10d6c78 100644 #undef SHADER for (auto& info : pipelineInfos) { -@@ -3214,8 +3217,16 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) +@@ -3229,8 +3232,16 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) uint32_t uDRMFormat = pOutput->uOutputFormat; + uint32_t l_nOutputWidth = g_nOutputWidth; + uint32_t l_nOutputHeight = g_nOutputHeight; + -+ if (g_bUseRotationShader) { ++ if (g_bEnableDRMRotationShader) { + l_nOutputWidth = g_nOutputHeight; + l_nOutputHeight = g_nOutputWidth; + } @@ -1351,7 +3412,7 @@ index 54d7608..10d6c78 100644 if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3223,7 +3234,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) +@@ -3238,7 +3249,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) } pOutput->outputImages[1] = new CVulkanTexture(); @@ -1360,7 +3421,7 @@ index 54d7608..10d6c78 100644 if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3231,7 +3242,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) +@@ -3246,7 +3257,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) } pOutput->outputImages[2] = new CVulkanTexture(); @@ -1369,7 +3430,7 @@ index 54d7608..10d6c78 100644 if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3246,7 +3257,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) +@@ -3261,7 +3272,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) uint32_t uPartialDRMFormat = pOutput->uOutputFormatOverlay; pOutput->outputImagesPartialOverlay[0] = new CVulkanTexture(); @@ -1378,7 +3439,7 @@ index 54d7608..10d6c78 100644 if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3254,7 +3265,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) +@@ -3269,7 +3280,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) } pOutput->outputImagesPartialOverlay[1] = new CVulkanTexture(); @@ -1387,7 +3448,7 @@ index 54d7608..10d6c78 100644 if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3262,7 +3273,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) +@@ -3277,7 +3288,7 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput ) } pOutput->outputImagesPartialOverlay[2] = new CVulkanTexture(); @@ -1396,7 +3457,7 @@ index 54d7608..10d6c78 100644 if ( bSuccess != true ) { vk_log.errorf( "failed to allocate buffer for KMS" ); -@@ -3392,6 +3403,28 @@ static void update_tmp_images( uint32_t width, uint32_t height ) +@@ -3407,6 +3418,28 @@ static void update_tmp_images( uint32_t width, uint32_t height ) } } @@ -1425,16 +3486,16 @@ index 54d7608..10d6c78 100644 static bool init_nis_data() { -@@ -3856,7 +3889,7 @@ std::optional vulkan_screenshot( const struct FrameInfo_t *frameInfo, - extern std::string g_reshade_effect; - extern uint32_t g_reshade_technique_idx; +@@ -3873,7 +3906,7 @@ extern uint32_t g_reshade_technique_idx; + + ReshadeEffectPipeline *g_pLastReshadeEffect = nullptr; -std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc pPipewireTexture, bool partial, gamescope::Rc pOutputOverride, bool increment, std::unique_ptr pInCommandBuffer ) +std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamescope::Rc pPipewireTexture, bool partial, gamescope::Rc pOutputOverride, bool increment, std::unique_ptr pInCommandBuffer, bool applyRotation ) { EOTF outputTF = frameInfo->outputEncodingEOTF; if (!frameInfo->applyOutputColorMgmt) -@@ -3928,7 +3961,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco +@@ -3948,7 +3981,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco cmdBuffer->setTextureSrgb(0, true); cmdBuffer->setSamplerUnnormalized(0, false); cmdBuffer->setSamplerNearest(0, false); @@ -1451,7 +3512,7 @@ index 54d7608..10d6c78 100644 cmdBuffer->uploadConstants(frameInfo, g_upscaleFilterSharpness / 10.0f); cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); -@@ -3971,7 +4012,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco +@@ -3991,7 +4032,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, nisFrameInfo.layerCount, nisFrameInfo.ycbcrMask(), 0u, nisFrameInfo.colorspaceMask(), outputTF )); bind_all_layers(cmdBuffer.get(), &nisFrameInfo); @@ -1468,7 +3529,7 @@ index 54d7608..10d6c78 100644 cmdBuffer->uploadConstants(&nisFrameInfo); int pixelsPerGroup = 8; -@@ -4009,7 +4058,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco +@@ -4029,7 +4078,15 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco type = frameInfo->blurLayer0 == BLUR_MODE_COND ? SHADER_TYPE_BLUR_COND : SHADER_TYPE_BLUR; cmdBuffer->bindPipeline(g_device.pipeline(type, frameInfo->layerCount, frameInfo->ycbcrMask(), blur_layer_count, frameInfo->colorspaceMask(), outputTF )); bind_all_layers(cmdBuffer.get(), frameInfo); @@ -1485,7 +3546,7 @@ index 54d7608..10d6c78 100644 cmdBuffer->bindTexture(VKR_BLUR_EXTRA_SLOT, g_output.tmpOutput); cmdBuffer->setTextureSrgb(VKR_BLUR_EXTRA_SLOT, !useSrgbView); // Inverted because it chooses whether to view as linear (sRGB view) or sRGB (raw view). It's horrible. I need to change it. cmdBuffer->setSamplerUnnormalized(VKR_BLUR_EXTRA_SLOT, true); -@@ -4019,14 +4076,51 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco +@@ -4039,14 +4096,51 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco } else { @@ -1544,10 +3605,10 @@ index 54d7608..10d6c78 100644 if ( pPipewireTexture != nullptr ) diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp -index ccabd88..51a62bc 100644 +index 0f8cba8516c0..911ca7ea208c 100644 --- a/src/rendervulkan.hpp +++ b/src/rendervulkan.hpp -@@ -393,7 +393,7 @@ gamescope::OwningRc vulkan_create_texture_from_dmabuf( struct wl +@@ -396,7 +396,7 @@ gamescope::OwningRc vulkan_create_texture_from_dmabuf( struct wl gamescope::OwningRc vulkan_create_texture_from_bits( uint32_t width, uint32_t height, uint32_t contentWidth, uint32_t contentHeight, uint32_t drmFormat, CVulkanTexture::createFlags texCreateFlags, void *bits ); gamescope::OwningRc vulkan_create_texture_from_wlr_buffer( struct wlr_buffer *buf, gamescope::OwningRc pBackendFb ); @@ -1556,7 +3617,7 @@ index ccabd88..51a62bc 100644 void vulkan_wait( uint64_t ulSeqNo, bool bReset ); gamescope::Rc vulkan_get_last_output_image( bool partial, bool defer ); gamescope::Rc vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, bool exportable, uint32_t drmFormat, EStreamColorspace colorspace = k_EStreamColorspace_Unknown); -@@ -522,6 +522,9 @@ struct VulkanOutput_t +@@ -533,6 +533,9 @@ struct VulkanOutput_t // NIS gamescope::OwningRc nisScalerImage; gamescope::OwningRc nisUsmImage; @@ -1566,7 +3627,7 @@ index ccabd88..51a62bc 100644 }; -@@ -534,6 +537,7 @@ enum ShaderType { +@@ -545,6 +548,7 @@ enum ShaderType { SHADER_TYPE_RCAS, SHADER_TYPE_NIS, SHADER_TYPE_RGB_TO_NV12, @@ -1576,7 +3637,7 @@ index ccabd88..51a62bc 100644 }; diff --git a/src/shaders/cs_rotation.comp b/src/shaders/cs_rotation.comp new file mode 100644 -index 0000000..1a47fd5 +index 000000000000..1a47fd505748 --- /dev/null +++ b/src/shaders/cs_rotation.comp @@ -0,0 +1,53 @@ @@ -1634,14 +3695,14 @@ index 0000000..1a47fd5 + imageStore(dst, rotatedCoord, outputValue); +} diff --git a/src/wlserver.cpp b/src/wlserver.cpp -index 1eeaa25..5aa986a 100644 +index 0b99c498e55d..d3ae7beb7b1f 100644 --- a/src/wlserver.cpp +++ b/src/wlserver.cpp -@@ -2519,6 +2519,11 @@ static void apply_touchscreen_orientation(double *x, double *y ) +@@ -2579,6 +2579,11 @@ static void apply_touchscreen_orientation(double *x, double *y ) break; } -+ if (g_bUseRotationShader) { ++ if (g_bEnableDRMRotationShader) { + tx = 1.0 - *y; + ty = *x; + } @@ -1650,750 +3711,121 @@ index 1eeaa25..5aa986a 100644 *y = ty; } -- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: "Ruan E. Formigoni" -Date: Thu, 2 Jan 2025 17:07:36 +0100 -Subject: feat: implement bicubic downscaling +From: Antheas Kapenekakis +Date: Thu, 13 Mar 2025 19:04:51 +0100 +Subject: fix(hdr): remove PQ from internal panels and allow disabling for + externals -From https://github.com/ValveSoftware/gamescope/pull/740 +New steam update forces HDR mode. The cursed patching gamescope does is +not supported for all displays, especially internal ones. So disable by +default on internal panels and allow disabling on externals. --- - README.md | 1 + - src/Backends/DRMBackend.cpp | 1 + - src/Backends/OpenVRBackend.cpp | 1 + - src/Backends/SDLBackend.cpp | 4 + - src/Backends/WaylandBackend.cpp | 1 + - src/main.cpp | 54 +++++++++- - src/main.hpp | 15 +++ - src/meson.build | 1 + - src/rendervulkan.cpp | 61 ++++++++++- - src/rendervulkan.hpp | 2 + - src/shaders/bicubic.h | 44 ++++++++ - src/shaders/cs_bicubic.comp | 177 ++++++++++++++++++++++++++++++++ - src/shaders/descriptor_set.h | 1 + - src/steamcompmgr.cpp | 23 +++++ - src/steamcompmgr.hpp | 1 + - src/xwayland_ctx.hpp | 1 + - 16 files changed, 386 insertions(+), 2 deletions(-) - create mode 100644 src/shaders/bicubic.h - create mode 100644 src/shaders/cs_bicubic.comp + src/Backends/DRMBackend.cpp | 2 +- + src/main.cpp | 1 + + src/steamcompmgr.cpp | 3 +++ + src/steamcompmgr.hpp | 1 + + 4 files changed, 6 insertions(+), 1 deletion(-) -diff --git a/README.md b/README.md -index 97dea45..fefb2a0 100644 ---- a/README.md -+++ b/README.md -@@ -66,6 +66,7 @@ See `gamescope --help` for a full list of options. - * `-o`: set a frame-rate limit for the game when unfocused. Specified in frames per second. Defaults to unlimited. - * `-F fsr`: use AMD FidelityFX™ Super Resolution 1.0 for upscaling - * `-F nis`: use NVIDIA Image Scaling v1.0.3 for upscaling -+* `-F bicubic`: use a bicubic filter for downscaling - * `-S integer`: use integer scaling. - * `-S stretch`: use stretch scaling, the game will fill the window. (e.g. 4:3 to 16:9) - * `-b`: create a border-less window. diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp -index 506963d..98bdb71 100644 +index e1547f4a1a9b..d7107325ad59 100644 --- a/src/Backends/DRMBackend.cpp +++ b/src/Backends/DRMBackend.cpp -@@ -3293,6 +3293,7 @@ namespace gamescope - bNeedsFullComposite |= bWasFirstFrame; - bNeedsFullComposite |= pFrameInfo->useFSRLayer0; - bNeedsFullComposite |= pFrameInfo->useNISLayer0; -+ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; - bNeedsFullComposite |= pFrameInfo->blurLayer0; - bNeedsFullComposite |= bNeedsCompositeFromFilter; - bNeedsFullComposite |= !k_bUseCursorPlane && bDrewCursor; -diff --git a/src/Backends/OpenVRBackend.cpp b/src/Backends/OpenVRBackend.cpp -index c39caa5..96a3d01 100644 ---- a/src/Backends/OpenVRBackend.cpp -+++ b/src/Backends/OpenVRBackend.cpp -@@ -554,6 +554,7 @@ namespace gamescope - bNeedsFullComposite |= cv_composite_force; - bNeedsFullComposite |= pFrameInfo->useFSRLayer0; - bNeedsFullComposite |= pFrameInfo->useNISLayer0; -+ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; - bNeedsFullComposite |= pFrameInfo->blurLayer0; - bNeedsFullComposite |= bNeedsCompositeFromFilter; - bNeedsFullComposite |= g_bColorSliderInUse; -diff --git a/src/Backends/SDLBackend.cpp b/src/Backends/SDLBackend.cpp -index 6d50f8d..c24b864 100644 ---- a/src/Backends/SDLBackend.cpp -+++ b/src/Backends/SDLBackend.cpp -@@ -719,6 +719,10 @@ namespace gamescope - case KEY_B: - g_wantedUpscaleFilter = GamescopeUpscaleFilter::LINEAR; - break; -+ case KEY_K: -+ g_wantedDownscaleFilter = (g_wantedDownscaleFilter == GamescopeDownscaleFilter::BICUBIC) ? -+ GamescopeDownscaleFilter::LINEAR : GamescopeDownscaleFilter::BICUBIC; -+ break; - case KEY_U: - g_wantedUpscaleFilter = (g_wantedUpscaleFilter == GamescopeUpscaleFilter::FSR) ? - GamescopeUpscaleFilter::LINEAR : GamescopeUpscaleFilter::FSR; -diff --git a/src/Backends/WaylandBackend.cpp b/src/Backends/WaylandBackend.cpp -index 3226400..7ae273f 100644 ---- a/src/Backends/WaylandBackend.cpp -+++ b/src/Backends/WaylandBackend.cpp -@@ -1614,6 +1614,7 @@ namespace gamescope - bNeedsFullComposite |= cv_composite_force; - bNeedsFullComposite |= pFrameInfo->useFSRLayer0; - bNeedsFullComposite |= pFrameInfo->useNISLayer0; -+ bNeedsFullComposite |= pFrameInfo->useBICUBICLayer0; - bNeedsFullComposite |= pFrameInfo->blurLayer0; - bNeedsFullComposite |= bNeedsCompositeFromFilter; - bNeedsFullComposite |= g_bColorSliderInUse; +@@ -2367,7 +2367,7 @@ namespace gamescope + } + } + +- if ( pColorimetry && pColorimetry->bt2020_rgb && ++ if ( g_bHDRPqEnable && GetScreenType() != GAMESCOPE_SCREEN_TYPE_INTERNAL && pColorimetry && pColorimetry->bt2020_rgb && + pHDRStaticMetadata && pHDRStaticMetadata->eotfs && pHDRStaticMetadata->eotfs->pq ) + { + m_Mutable.HDR.bExposeHDRSupport = true; diff --git a/src/main.cpp b/src/main.cpp -index f61c88f..06a3bca 100644 +index c96b8f0ac39e..58230054ce53 100644 --- a/src/main.cpp +++ b/src/main.cpp -@@ -7,6 +7,7 @@ - #include - #include - #include -+#include - #include - #if defined(__linux__) - #include -@@ -303,11 +304,14 @@ bool g_bGrabbed = false; - float g_mouseSensitivity = 1.0; - - GamescopeUpscaleFilter g_upscaleFilter = GamescopeUpscaleFilter::LINEAR; -+GamescopeDownscaleFilter g_downscaleFilter = GamescopeDownscaleFilter::LINEAR; - GamescopeUpscaleScaler g_upscaleScaler = GamescopeUpscaleScaler::AUTO; - - GamescopeUpscaleFilter g_wantedUpscaleFilter = GamescopeUpscaleFilter::LINEAR; -+GamescopeDownscaleFilter g_wantedDownscaleFilter = GamescopeDownscaleFilter::LINEAR; - GamescopeUpscaleScaler g_wantedUpscaleScaler = GamescopeUpscaleScaler::AUTO; - int g_upscaleFilterSharpness = 2; -+GamescopeBicubicParams g_bicubicParams; - - gamescope::GamescopeModeGeneration g_eGamescopeModeGeneration = gamescope::GAMESCOPE_MODE_GENERATE_CVT; - -@@ -427,6 +431,54 @@ static enum GamescopeUpscaleFilter parse_upscaler_filter(const char *str) - } - } - -+static enum GamescopeDownscaleFilter parse_downscaler_filter(const char *str) -+{ -+ std::string_view arg{str}; -+ -+ // If the string is just 'bicubic' use default values -+ if ( arg == "bicubic" ) { -+ return GamescopeDownscaleFilter::BICUBIC; -+ } -+ -+ // Arguments start after ':' -+ if ( auto search = arg.find(':'); search == std::string::npos ) { -+ fprintf( stderr, "gamescope: invalid argument for --filter=bicubic:float,float\n" ); -+ exit(1); -+ } else { -+ arg = std::string_view(arg.data() + search + 1); -+ } -+ -+ // Push arguments to stream -+ std::stringstream ss; -+ ss << arg; -+ -+ // Validate arguments from stream -+ double b, c; -+ char comma; -+ if ((ss >> b >> comma >> c) && (comma == ',')) { -+ // clamp values -+ b = std::clamp(b, 0.0, 1.0); -+ c = std::clamp(c, 0.0, 1.0); -+ // Ovewrite default global parameters -+ g_bicubicParams.b = b; -+ g_bicubicParams.c = c; -+ // Set downscaler filters -+ return GamescopeDownscaleFilter::BICUBIC; -+ } -+ -+ fprintf( stderr, "gamescope: invalid value for --filter\n" ); -+ exit(1); -+} -+ -+static void parse_filter(const char *str) -+{ -+ if (std::string_view{str}.starts_with("bicubic")) { -+ g_wantedDownscaleFilter = parse_downscaler_filter(str); -+ } else { -+ g_wantedUpscaleFilter = parse_upscaler_filter(str); -+ } -+} -+ - static enum gamescope::GamescopeBackend parse_backend_name(const char *str) - { - if (strcmp(str, "auto") == 0) { -@@ -756,7 +808,7 @@ int main(int argc, char **argv) - g_wantedUpscaleScaler = parse_upscaler_scaler(optarg); - break; - case 'F': -- g_wantedUpscaleFilter = parse_upscaler_filter(optarg); -+ parse_filter(optarg); - break; - case 'b': - g_bBorderlessOutputWindow = true; -diff --git a/src/main.hpp b/src/main.hpp -index 2464afa..040d04c 100644 ---- a/src/main.hpp -+++ b/src/main.hpp -@@ -43,6 +43,18 @@ enum class GamescopeUpscaleFilter : uint32_t - FROM_VIEW = 0xF, // internal - }; - -+enum class GamescopeDownscaleFilter : uint32_t -+{ -+ LINEAR = 0, -+ BICUBIC, -+}; -+ -+struct GamescopeBicubicParams -+{ -+ float b = 0.3f; -+ float c = 0.3f; -+}; -+ - static constexpr bool DoesHardwareSupportUpscaleFilter( GamescopeUpscaleFilter eFilter ) - { - // Could do nearest someday... AMDGPU DC supports custom tap placement to an extent. -@@ -60,10 +72,13 @@ enum class GamescopeUpscaleScaler : uint32_t - }; - - extern GamescopeUpscaleFilter g_upscaleFilter; -+extern GamescopeDownscaleFilter g_downscaleFilter; - extern GamescopeUpscaleScaler g_upscaleScaler; - extern GamescopeUpscaleFilter g_wantedUpscaleFilter; -+extern GamescopeDownscaleFilter g_wantedDownscaleFilter; - extern GamescopeUpscaleScaler g_wantedUpscaleScaler; - extern int g_upscaleFilterSharpness; -+extern GamescopeBicubicParams g_bicubicParams; - - extern bool g_bBorderlessOutputWindow; - -diff --git a/src/meson.build b/src/meson.build -index d4ff3ea..341bace 100644 ---- a/src/meson.build -+++ b/src/meson.build -@@ -66,6 +66,7 @@ shader_src = [ - 'shaders/cs_composite_rcas.comp', - 'shaders/cs_easu.comp', - 'shaders/cs_easu_fp16.comp', -+ 'shaders/cs_bicubic.comp', - 'shaders/cs_gaussian_blur_horizontal.comp', - 'shaders/cs_nis.comp', - 'shaders/cs_nis_fp16.comp', -diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp -index 10d6c78..8b31c1e 100644 ---- a/src/rendervulkan.cpp -+++ b/src/rendervulkan.cpp -@@ -44,6 +44,7 @@ - #include "cs_composite_rcas.h" - #include "cs_easu.h" - #include "cs_easu_fp16.h" -+#include "cs_bicubic.h" - #include "cs_gaussian_blur_horizontal.h" - #include "cs_nis.h" - #include "cs_nis_fp16.h" -@@ -53,6 +54,7 @@ - #define A_CPU - #include "shaders/ffx_a.h" - #include "shaders/ffx_fsr1.h" -+#include "shaders/bicubic.h" - - #include "reshade_effect_manager.hpp" - -@@ -888,6 +890,7 @@ bool CVulkanDevice::createShaders() - SHADER(BLUR_COND, cs_composite_blur_cond); - SHADER(BLUR_FIRST_PASS, cs_gaussian_blur_horizontal); - SHADER(RCAS, cs_composite_rcas); -+ SHADER(BICUBIC, cs_bicubic); - if (m_bSupportsFp16) - { - SHADER(EASU, cs_easu_fp16); -@@ -1128,6 +1131,7 @@ void CVulkanDevice::compileAllPipelines() - SHADER(BLUR_FIRST_PASS, 1, 2, 1); - SHADER(RCAS, k_nMaxLayers, k_nMaxYcbcrMask_ToPreCompile, 1); - SHADER(EASU, 1, 1, 1); -+ SHADER(BICUBIC, 1, 1, 1); - SHADER(NIS, 1, 1, 1); - SHADER(RGB_TO_NV12, 1, 1, 1); - SHADER(ROTATION, k_nMaxLayers, k_nMaxYcbcrMask_ToPreCompile, k_nMaxBlurLayers); -@@ -3724,6 +3728,17 @@ struct EasuPushData_t - } - }; - -+struct BicubicPushData_t -+{ -+ uvec4_t Const0; -+ uvec4_t Const1; -+ -+ BicubicPushData_t(float B, float C, uint32_t inputX, uint32_t inputY, uint32_t tempX, uint32_t tempY, uint32_t winX, uint32_t winY) -+ { -+ BicubicCon(&Const0.x, &Const1.x, B*10, C*10, inputX, inputY, tempX, tempY, winX, winY); -+ } -+}; -+ - struct RcasPushData_t - { - uvec2_t u_layer0Offset; -@@ -3933,7 +3948,51 @@ std::optional vulkan_composite( struct FrameInfo_t *frameInfo, gamesco - for (uint32_t i = 0; i < EOTF_Count; i++) - cmdBuffer->bindColorMgmtLuts(i, frameInfo->shaperLut[i], frameInfo->lut3D[i]); - -- if ( frameInfo->useFSRLayer0 ) -+ if ( frameInfo->useBICUBICLayer0 ) -+ { -+ uint32_t inputX = frameInfo->layers[0].tex->width(); -+ uint32_t inputY = frameInfo->layers[0].tex->height(); -+ -+ uint32_t tempX = frameInfo->layers[0].integerWidth(); -+ uint32_t tempY = frameInfo->layers[0].integerHeight(); -+ -+ update_tmp_images(tempX, tempY); -+ -+ cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BICUBIC, frameInfo->layerCount, frameInfo->ycbcrMask())); -+ cmdBuffer->bindTarget(g_output.tmpOutput); -+ cmdBuffer->bindTexture(0, frameInfo->layers[0].tex); -+ cmdBuffer->setTextureSrgb(0, true); -+ cmdBuffer->setSamplerUnnormalized(0, false); -+ cmdBuffer->setSamplerNearest(0, false); -+ cmdBuffer->uploadConstants(g_bicubicParams.b -+ , g_bicubicParams.c -+ , inputX -+ , inputY -+ , tempX -+ , tempY -+ , currentOutputWidth -+ , currentOutputHeight -+ ); -+ -+ int pixelsPerGroup = 16; -+ -+ cmdBuffer->dispatch(div_roundup(tempX, pixelsPerGroup), div_roundup(tempY, pixelsPerGroup)); -+ -+ struct FrameInfo_t bicFrameInfo = *frameInfo; -+ bicFrameInfo.layers[0].tex = g_output.tmpOutput; -+ bicFrameInfo.layers[0].scale.x = 1.0f; -+ bicFrameInfo.layers[0].scale.y = 1.0f; -+ -+ cmdBuffer->bindPipeline( g_device.pipeline(SHADER_TYPE_BLIT, bicFrameInfo.layerCount, bicFrameInfo.ycbcrMask())); -+ bind_all_layers(cmdBuffer.get(), &bicFrameInfo); -+ cmdBuffer->bindTarget(compositeImage); -+ cmdBuffer->uploadConstants(&bicFrameInfo); -+ -+ pixelsPerGroup = 8; -+ -+ cmdBuffer->dispatch(div_roundup(currentOutputWidth, pixelsPerGroup), div_roundup(currentOutputHeight, pixelsPerGroup)); -+ } -+ else if ( frameInfo->useFSRLayer0 ) - { - uint32_t inputX = frameInfo->layers[0].tex->width(); - uint32_t inputY = frameInfo->layers[0].tex->height(); -diff --git a/src/rendervulkan.hpp b/src/rendervulkan.hpp -index 51a62bc..eeb304c 100644 ---- a/src/rendervulkan.hpp -+++ b/src/rendervulkan.hpp -@@ -270,6 +270,7 @@ struct FrameInfo_t - { - bool useFSRLayer0; - bool useNISLayer0; -+ bool useBICUBICLayer0; - bool bFadingOut; - BlurMode blurLayer0; - int blurRadius; -@@ -536,6 +537,7 @@ enum ShaderType { - SHADER_TYPE_EASU, - SHADER_TYPE_RCAS, - SHADER_TYPE_NIS, -+ SHADER_TYPE_BICUBIC, - SHADER_TYPE_RGB_TO_NV12, - SHADER_TYPE_ROTATION, - -diff --git a/src/shaders/bicubic.h b/src/shaders/bicubic.h -new file mode 100644 -index 0000000..8117e87 ---- /dev/null -+++ b/src/shaders/bicubic.h -@@ -0,0 +1,44 @@ -+//_____________________________________________________________/\_______________________________________________________________ -+//============================================================================================================================== -+// -+// -+// BICUBIC IMAGE SCALING -+// -+// -+//------------------------------------------------------------------------------------------------------------------------------ -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+//_____________________________________________________________/\_______________________________________________________________ -+//============================================================================================================================== -+// CONSTANT SETUP -+//============================================================================================================================== -+// Call to setup required constant values (works on CPU or GPU). -+A_STATIC void BicubicCon( -+outAU4 con0, -+outAU4 con1, -+// Configurable parameters -+AU1 B, -+AU1 C, -+// This the rendered image resolution -+AF1 inputRenderedSizeX, -+AF1 inputRenderedSizeY, -+// This is the resolution of the resource containing the input image (useful for dynamic resolution) -+AF1 inputCurrentSizeX, -+AF1 inputCurrentSizeY, -+// This is the window width / height -+AF1 outputTargetSizeX, -+AF1 outputTargetSizeY) -+{ -+ // Input/Output size information -+ con0[0]=AU1_AF1(inputRenderedSizeX); -+ con0[1]=AU1_AF1(inputRenderedSizeY); -+ con0[2]=AU1_AF1(inputCurrentSizeX); -+ con0[3]=AU1_AF1(inputCurrentSizeY); -+ -+ // Viewport pixel position to normalized image space. -+ con1[0]=AU1_AF1(outputTargetSizeX); -+ con1[1]=AU1_AF1(outputTargetSizeY); -+ con1[2]=B; -+ con1[3]=C; -+} -diff --git a/src/shaders/cs_bicubic.comp b/src/shaders/cs_bicubic.comp -new file mode 100644 -index 0000000..2b6dfb8 ---- /dev/null -+++ b/src/shaders/cs_bicubic.comp -@@ -0,0 +1,177 @@ -+// References -+// https://www.codeproject.com/Articles/236394/Bi-Cubic-and-Bi-Linear-Interpolation-with-GLSL -+// https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl -+// https://web.archive.org/web/20180927181721/http://www.java-gaming.org/index.php?topic=35123.0 -+// https://gist.github.com/TheRealMJP/c83b8c0f46b63f3a88a5986f4fa982b1 -+ -+#version 460 -+ -+#extension GL_GOOGLE_include_directive : require -+#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require -+#extension GL_EXT_scalar_block_layout : require -+ -+#include "descriptor_set.h" -+ -+layout( -+ local_size_x = 64, -+ local_size_y = 1, -+ local_size_z = 1) in; -+ -+// Push constant is a mechanism in modern OpenGL that allows passing small amounts of frequently -+// updated data to the shader without needing to bind a buffer -+layout(binding = 0, scalar) -+uniform layers_t { -+ uvec4 c0, c1; -+}; -+ -+#define A_GPU 1 -+#define A_GLSL 1 -+#define A_HALF 1 -+#include "ffx_a.h" -+#include "bicubic.h" -+ -+// The Mitchell–Netravali filters or BC-splines -+// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters -+// Conditionals are slow in GPU code, so to represent 0 <= f < 1 and 1 <= f < 2 -+// the P(d) form shown in the wikipedia page is used -+vec4 mitchellNetravaliWeights(float f, float B, float C) -+{ -+ float w0 = ((12.0 - 9.0 * B - 6.0 * C) * pow(f, 3.0)) + -+ ((-18.0 + 12.0 * B + 6.0 * C) * pow(f, 2.0)) + -+ (6.0 - 2.0 * B); -+ -+ float w1 = ((-B - 6.0 * C) * pow(f - 1.0, 3.0)) + -+ ((6.0 * B + 30.0 * C) * pow(f - 1.0, 2.0)) + -+ ((-12.0 * B - 48.0 * C) * (f - 1.0)) + -+ (8.0 * B + 24.0 * C); -+ -+ float w2 = ((12.0 - 9.0 * B - 6.0 * C) * pow(1.0 - f, 3.0)) + -+ ((-18.0 + 12.0 * B + 6.0 * C) * pow(1.0 - f, 2.0)) + -+ (6.0 - 2.0 * B); -+ -+ float w3 = ((-B - 6.0 * C) * pow(2.0 - f, 3.0)) + -+ ((6.0 * B + 30.0 * C) * pow(2.0 - f, 2.0)) + -+ ((-12.0 * B - 48.0 * C) * (2.0 - f)) + -+ (8.0 * B + 24.0 * C); -+ -+ return vec4(w0, w1, w2, w3); -+} -+ -+// https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl -+// https://web.archive.org/web/20180927181721/http://www.java-gaming.org/index.php?topic=35123.0 -+// This is an efficient method to implement bicubic filtering, it takes -+// advantage of the fact that the bilinear approach gives the weighted average -+// of a 2x2 area. -+vec4 textureBicubic(sampler2D splr, vec2 texCoords) -+{ -+ vec2 texSize = textureSize(splr, 0); -+ vec2 invTexSize = 1.0 / texSize; -+ -+ // Converts normalized coordinates into pixel-space coordinate -+ // Example: If texCoords is (0.5, 0.5), and the texture size is (1920, 1080), the result will be -+ // (960, 540)—the center of the texture in pixel space. -+ // Subtracting 0.5 ensures that you're sampling from the center of the texel rather than its corner -+ // Example: Assume we have a 3x3 texture and texCoords = (0.5, 0.5): -+ // [0,0][1,0][2,0] -+ // [0,1][1,1][2,1] -+ // [0,2][1,2][2,2] -+ // texCoords * texSize - 0.5 maps to (1.5, 1.5), which is between (1,1) and (2,2), then -+ // subtracts 0.5 to move it to (1.0, 1.0)—the center of the texel -+ texCoords = texCoords * texSize - 0.5; -+ -+ // Get B and C that were pushed from the user input (or default values) -+ float B = c1[2] / 10.0f; -+ float C = c1[3] / 10.0f; -+ -+ // Get the fractional part of the coordinates -+ // They are used in Mitchell Netravali's strategy to calculate the interpolation weights, -+ // i.e., how much influence the neighboring vertices have on the final pixel value -+ vec2 fxy = fract(texCoords); -+ texCoords -= fxy; -+ -+ // Calculate bicubic weights -+ // These weights represent how much influence each neighboring texel in the 4x4 grid will have -+ // on the final interpolated pixel value -+ vec4 xweights = mitchellNetravaliWeights(fxy.x, B, C); -+ vec4 yweights = mitchellNetravaliWeights(fxy.y, B, C); -+ -+ // Modify the current texture coordinates to have an offset in texels for each coordinate -+ // E.g. texCoords + vec(-1.0, 0.0) is a texel to the left -+ // texCoords + vec(1.0, 0.0) is a texel to the right -+ // texCoords + vec(0.0, 1.0) is a texel downwards -+ // texCoords + vec(0.0, -1.0) is a texel upwards -+ vec4 offsetTexels = texCoords.xxyy; -+ offsetTexels += vec2 (-1.0, +1.0).xyxy; -+ // Normalize weights to range between (0,1) -+ // vec4 sumWeights = vec4(xweights.xz + xweights.yw, yweights.xz + yweights.yw); -+ // vec4 normalizedWeights = vec4 (xweights.yw, yweights.yw) / sumWeights; -+ vec4 sumWeights = vec4(xweights.x + xweights.y, xweights.z + xweights.w, yweights.x + yweights.y, yweights.z + yweights.w); -+ vec4 normalizedWeights = vec4 (xweights.y, xweights.w, yweights.y, yweights.w) / sumWeights; -+ // Use the weights to influence the sampling position inside each texel -+ // Each texel has a size from (0,1) -+ vec4 offsetSampler = offsetTexels + normalizedWeights; -+ // Go back to normalized space -+ offsetSampler *= invTexSize.xxyy; -+ // Perform the sampling -+ vec4 sample0 = texture(splr, offsetSampler.xz); -+ vec4 sample1 = texture(splr, offsetSampler.yz); -+ vec4 sample2 = texture(splr, offsetSampler.xw); -+ vec4 sample3 = texture(splr, offsetSampler.yw); -+ -+ // Now we perform linear interpolation in the selected points -+ // The mix(a, b, t) function in GLSL performs linear interpolation between a and b based on the -+ // parameter t, t is between 0 and 1 -+ // https://registry.khronos.org/OpenGL-Refpages/gl4/html/mix.xhtml -+ -+ // Here we want to normalize sx and sy to between 0 and 1 (t value) -+ float sx = sumWeights.x / (sumWeights.x + sumWeights.y); -+ float sy = sumWeights.z / (sumWeights.z + sumWeights.w); -+ -+ return mix( -+ mix(sample3, sample2, sx), mix(sample1, sample0, sx) -+ , sy); -+} -+ -+void bicPass(uvec2 pos) -+{ -+ // Retrieve pushed values -+ AF2 inputRenderedSize = AF2_AU2(c0.xy); -+ AF2 inputCurrentSize = AF2_AU2(c0.zw); -+ AF2 outputTargetSize = AF2_AU2(c1.xy); -+ -+ // ARcpF1(x) == 1.0 / x -+ // scaleFactor is the division between the rendered image and the size it should have at the end -+ // E.g.: Rendered 1920x1080, window size is 960x540, then scaleFactor is 2x2 -+ AF2 scaleFactor = inputRenderedSize * vec2(ARcpF1(inputCurrentSize.x), ARcpF1(inputCurrentSize.y)); -+ -+ // The parameter pos of this function is used to iterate over the output image (e.g. 960x540) -+ // The position of the processed pixel should be taken from the rendered image (e.g. 1920x1080) -+ // 10x10 in the output, corresponds to 20x20 in the original image -+ AF2 positionPixel=AF2(pos)*scaleFactor; -+ -+ // Normalize the image space to be between [0,1] -+ positionPixel=positionPixel*vec2(ARcpF1(inputRenderedSize.x),ARcpF1(inputRenderedSize.y)); -+ -+ // Apply the bicubic algorithm in the normalized pixel position -+ vec4 bicPass = textureBicubic(s_samplers[0], positionPixel); -+ -+ imageStore(dst, ivec2(pos), bicPass); -+} -+ -+ -+void main() -+{ -+ // AMD recommends to use this swizzle and to process 4 pixel per invocation -+ // for better cache utilisation -+ uvec2 pos = ARmp8x8(gl_LocalInvocationID.x) + uvec2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u); -+ -+ bicPass(pos); -+ pos.x += 8u; -+ bicPass(pos); -+ pos.y += 8u; -+ bicPass(pos); -+ pos.x -= 8u; -+ bicPass(pos); -+} -+ -+/* vim: set expandtab ft=cpp fdm=marker ts=4 sw=4 tw=100 et :*/ -diff --git a/src/shaders/descriptor_set.h b/src/shaders/descriptor_set.h -index f2b8527..64cc1c9 100644 ---- a/src/shaders/descriptor_set.h -+++ b/src/shaders/descriptor_set.h -@@ -21,6 +21,7 @@ const int filter_nearest = 1; - const int filter_fsr = 2; - const int filter_nis = 3; - const int filter_pixel = 4; -+const int filter_bicubic = 5; - const int filter_from_view = 255; - - const int EOTF_Gamma22 = 0; +@@ -199,6 +199,7 @@ const char usage[] = + " If this is not set, and there is a HDR client, it will be tonemapped SDR.\n" + " --sdr-gamut-wideness Set the 'wideness' of the gamut for SDR comment. 0 - 1.\n" + " --hdr-sdr-content-nits set the luminance of SDR content in nits. Default: 400 nits.\n" ++ " --hdr-pq-disable disable HDR metadata detection for PQ EOTFs. IE disable HDR for external panels but not ones added through config. \n" + " --hdr-itm-enabled enable SDR->HDR inverse tone mapping. only works for SDR input.\n" + " --hdr-itm-sdr-nits set the luminance of SDR content in nits used as the input for the inverse tone mapping process.\n" + " Default: 100 nits, Max: 1000 nits\n" diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp -index dfee904..c2111d2 100644 +index fcdc9ac1559f..86df7eaf681f 100644 --- a/src/steamcompmgr.cpp +++ b/src/steamcompmgr.cpp -@@ -906,6 +906,7 @@ gamescope::ConCommand cc_debug_set_fps_limit( "debug_set_fps_limit", "Set refres - static int g_nRuntimeInfoFd = -1; +@@ -363,6 +363,7 @@ bool g_bVRRInUse_CachedValue = false; + bool g_bSupportsHDR_CachedValue = false; + bool g_bForceHDR10OutputDebug = false; + gamescope::ConVar cv_hdr_enabled{ "hdr_enabled", false, "Whether or not HDR is enabled if it is available." }; ++bool g_bHDRPqEnable = true; + bool g_bHDRItmEnable = false; + int g_nCurrentRefreshRate_CachedValue = 0; - bool g_bFSRActive = false; -+bool g_bBicubicActive = false; - - BlurMode g_BlurMode = BLUR_MODE_OFF; - BlurMode g_BlurModeOld = BLUR_MODE_OFF; -@@ -2389,6 +2390,10 @@ paint_all(bool async, bool dpms) - paint_window(w, w, &frameInfo, global_focus.cursor, PaintWindowFlag::BasePlane | PaintWindowFlag::DrawBorders, 1.0f, override); - - bool needsScaling = frameInfo.layers[0].scale.x < 0.999f && frameInfo.layers[0].scale.y < 0.999f; -+ // Temporarily allow upscaling as well -+ // bool needsDownScaling = frameInfo.layers[0].scale.x > 1.001f && frameInfo.layers[0].scale.y > 1.001f; -+ bool needsDownScaling = true; -+ frameInfo.useBICUBICLayer0 = g_downscaleFilter == GamescopeDownscaleFilter::BICUBIC && needsDownScaling; - frameInfo.useFSRLayer0 = g_upscaleFilter == GamescopeUpscaleFilter::FSR && needsScaling; - frameInfo.useNISLayer0 = g_upscaleFilter == GamescopeUpscaleFilter::NIS && needsScaling; - } -@@ -2521,10 +2526,12 @@ paint_all(bool async, bool dpms) - } - - frameInfo.useFSRLayer0 = false; -+ frameInfo.useBICUBICLayer0 = false; - frameInfo.useNISLayer0 = false; - } - - g_bFSRActive = frameInfo.useFSRLayer0; -+ g_bBicubicActive = frameInfo.useBICUBICLayer0; - - g_bFirstFrame = false; - -@@ -5445,6 +5452,9 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev) - g_wantedUpscaleScaler = GamescopeUpscaleScaler::AUTO; - g_wantedUpscaleFilter = GamescopeUpscaleFilter::NIS; - break; -+ case 5: -+ g_wantedDownscaleFilter = GamescopeDownscaleFilter::BICUBIC; -+ break; - } - hasRepaint = true; - } -@@ -7017,6 +7027,7 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_ - ctx->atoms.gamescopeLowLatency = XInternAtom( ctx->dpy, "GAMESCOPE_LOW_LATENCY", false ); - - ctx->atoms.gamescopeFSRFeedback = XInternAtom( ctx->dpy, "GAMESCOPE_FSR_FEEDBACK", false ); -+ ctx->atoms.gamescopeBicubicFeedback = XInternAtom( ctx->dpy, "GAMESCOPE_BICUBIC_FEEDBACK", false ); - - ctx->atoms.gamescopeBlurMode = XInternAtom( ctx->dpy, "GAMESCOPE_BLUR_MODE", false ); - ctx->atoms.gamescopeBlurRadius = XInternAtom( ctx->dpy, "GAMESCOPE_BLUR_RADIUS", false ); -@@ -7275,6 +7286,7 @@ extern int g_nPreferredOutputWidth; - extern int g_nPreferredOutputHeight; - - static bool g_bWasFSRActive = false; -+static bool g_bWasBicubicActive = false; - - bool g_bAppWantsHDRCached = false; - -@@ -7689,6 +7701,16 @@ steamcompmgr_main(int argc, char **argv) - flush_root = true; - } - -+ if ( g_bBicubicActive != g_bWasBicubicActive ) -+ { -+ uint32_t active = g_bBicubicActive ? 1 : 0; -+ XChangeProperty( root_ctx->dpy, root_ctx->root, root_ctx->atoms.gamescopeBicubicFeedback, XA_CARDINAL, 32, PropModeReplace, -+ (unsigned char *)&active, 1 ); -+ -+ g_bWasBicubicActive = g_bBicubicActive; -+ flush_root = true; -+ } -+ - if (global_focus.IsDirty()) - determine_and_apply_focus(); - -@@ -7925,6 +7947,7 @@ steamcompmgr_main(int argc, char **argv) - g_bSteamIsActiveWindow = false; - g_upscaleScaler = g_wantedUpscaleScaler; - g_upscaleFilter = g_wantedUpscaleFilter; -+ g_downscaleFilter = g_wantedDownscaleFilter; - } - - // If we're in the middle of a fade, then keep us +@@ -7548,6 +7549,8 @@ steamcompmgr_main(int argc, char **argv) + g_bForceHDRSupportDebug = true; + } else if (strcmp(opt_name, "hdr-debug-force-output") == 0) { + g_bForceHDR10OutputDebug = true; ++ } else if (strcmp(opt_name, "hdr-pq-disabled") == 0 || strcmp(opt_name, "hdr-pq-disable") == 0) { ++ g_bHDRPqEnable = false; + } else if (strcmp(opt_name, "hdr-itm-enabled") == 0 || strcmp(opt_name, "hdr-itm-enable") == 0) { + g_bHDRItmEnable = true; + } else if (strcmp(opt_name, "sdr-gamut-wideness") == 0) { diff --git a/src/steamcompmgr.hpp b/src/steamcompmgr.hpp -index 30e48e8..5679a0c 100644 +index 9f384c461ca4..0df01c0ed0e3 100644 --- a/src/steamcompmgr.hpp +++ b/src/steamcompmgr.hpp -@@ -129,6 +129,7 @@ extern float focusedWindowOffsetY; +@@ -38,6 +38,7 @@ static const uint32_t g_zposOverlay = 3; + static const uint32_t g_zposCursor = 4; + static const uint32_t g_zposMuraCorrection = 5; - extern bool g_FakeExternal; - extern bool g_bFSRActive; -+extern bool g_bBicubicActive; ++extern bool g_bHDRPqEnable; + extern bool g_bHDRItmEnable; + extern bool g_bForceHDRSupportDebug; - extern uint32_t inputCounter; - extern uint64_t g_lastWinSeq; -diff --git a/src/xwayland_ctx.hpp b/src/xwayland_ctx.hpp -index 2347cbb..bc38c98 100644 ---- a/src/xwayland_ctx.hpp -+++ b/src/xwayland_ctx.hpp -@@ -164,6 +164,7 @@ struct xwayland_ctx_t final : public gamescope::IWaitable - Atom gamescopeLowLatency; - - Atom gamescopeFSRFeedback; -+ Atom gamescopeBicubicFeedback; - - Atom gamescopeBlurMode; - Atom gamescopeBlurRadius; -- -2.47.1 +2.50.1 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: brainantifreeze Date: Thu, 19 Dec 2024 09:16:15 +0000 -Subject: fix(nvidia): allow disabling Vulkan extension for nvidia to work +Subject: feat(nvidia): fix crash with current driver -This adds a workaround for #1592 which removes the -VkPhysicalDevicePresentWaitFeaturesKHR extension in -the layer if the environment variable -GAMESCOPE_WSI_HIDE_PRESENT_WAIT_EXT is set. +add layer env var to hide present wait ext -This resolves the current freezing issue on nVidia -in dx12 (without having to set -VKD3D_DISABLE_EXTENSIONS), dx11 (without having -to patch DXVK not to use the extension) and in -native vulkan games. +see: https://github.com/ValveSoftware/gamescope/pull/1671 --- layer/VkLayer_FROG_gamescope_wsi.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/layer/VkLayer_FROG_gamescope_wsi.cpp b/layer/VkLayer_FROG_gamescope_wsi.cpp -index c817880..407dae8 100644 +index 5bd1408bf780..495bbc070ff8 100644 --- a/layer/VkLayer_FROG_gamescope_wsi.cpp +++ b/layer/VkLayer_FROG_gamescope_wsi.cpp -@@ -496,7 +496,11 @@ namespace GamescopeWSILayer { +@@ -183,6 +183,16 @@ namespace GamescopeWSILayer { + return s_ensureMinImageCount; + } + ++ static bool getHidePresentWait() { ++ static bool s_hidePresentWait = []() -> bool { ++ if (auto hide = parseEnv("GAMESCOPE_WSI_HIDE_PRESENT_WAIT_EXT")) { ++ return *hide; ++ } ++ return false; ++ }(); ++ return s_hidePresentWait; ++ } ++ + // Taken from Mesa, licensed under MIT. + // + // No real reason to rewrite this code, +@@ -588,7 +598,11 @@ namespace GamescopeWSILayer { createInfo.ppEnabledExtensionNames = enabledExts.data(); setenv("vk_xwayland_wait_ready", "false", 0); @@ -2406,7 +3838,7 @@ index c817880..407dae8 100644 VkResult result = pfnCreateInstanceProc(&createInfo, pAllocator, pInstance); if (result != VK_SUCCESS) -@@ -801,6 +805,10 @@ namespace GamescopeWSILayer { +@@ -893,6 +907,10 @@ namespace GamescopeWSILayer { const vkroots::VkInstanceDispatch* pDispatch, VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) { @@ -2417,23 +3849,589 @@ index c817880..407dae8 100644 pDispatch->GetPhysicalDeviceFeatures2(physicalDevice, pFeatures); } -@@ -1015,6 +1023,16 @@ namespace GamescopeWSILayer { - return value; - } - -+ static bool getHidePresentWait() { -+ static bool s_hidePresentWait = []() -> bool { -+ if (auto hide = parseEnv("GAMESCOPE_WSI_HIDE_PRESENT_WAIT_EXT")) { -+ return *hide == 1; -+ } -+ return false; -+ }(); -+ return s_hidePresentWait; -+ } -+ - static uint32_t getMinImageCount() { - static uint32_t s_minImageCount = []() -> uint32_t { - if (auto minCount = parseEnv("GAMESCOPE_WSI_MIN_IMAGE_COUNT")) { -- -2.47.1 +2.50.1 + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Sun, 23 Feb 2025 02:16:55 +0100 +Subject: feat(display): add asus z13 + +--- + .../00-gamescope/displays/asus.z13.lcd.lua | 57 +++++++++++++++++++ + 1 file changed, 57 insertions(+) + create mode 100644 scripts/00-gamescope/displays/asus.z13.lcd.lua + +diff --git a/scripts/00-gamescope/displays/asus.z13.lcd.lua b/scripts/00-gamescope/displays/asus.z13.lcd.lua +new file mode 100644 +index 000000000000..891f1ea9ca6f +--- /dev/null ++++ b/scripts/00-gamescope/displays/asus.z13.lcd.lua +@@ -0,0 +1,57 @@ ++gamescope.config.known_displays.asusz13_lcd = { ++ pretty_name = "Asus Z13 LCD", ++ dynamic_refresh_rates = { ++ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, ++ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, ++ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, ++ 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, ++ 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, ++ 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, ++ 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, ++ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, ++ 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180 ++ }, ++ ++ -- Detailed Timing Descriptors: ++ -- DTD 1: 1920x1200 120.002 Hz 8:5 151.683 kHz 315.500 MHz (172 mm x 107 mm) ++ -- Modeline "1920x1200_120.00" 315.500 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync ++ -- DTD 2: 1920x1200 60.001 Hz 8:5 75.841 kHz 157.750 MHz (172 mm x 107 mm) ++ -- Modeline "1920x1200_60.00" 157.750 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync ++ dynamic_modegen = function(base_mode, refresh) ++ debug("Generating mode "..refresh.."Hz with fixed pixel clock") ++ local vfps = { ++ 4886, 4751, 4620, 4495, 4375, 4259, 4147, 4040, 3936, 3836, 3739, 3646, ++ 3556, 3468, 3384, 3302, 3223, 3146, 3072, 2999, 2929, 2861, 2795, 2731, ++ 2668, 2608, 2548, 2491, 2435, 2380, 2327, 2275, 2225, 2175, 2127, 2080, ++ 2035, 1990, 1946, 1903, 1862, 1821, 1781, 1742, 1704, 1667, 1630, 1594, ++ 1559, 1525, 1491, 1458, 1426, 1395, 1364, 1333, 1303, 1274, 1245, 1217, ++ 1190, 1162, 1136, 1110, 1084, 1059, 1034, 1010, 986, 962, 939, 916, 894, ++ 872, 850, 829, 808, 787, 767, 747, 727, 708, 689, 670, 652, 634, 616, ++ 598, 581, 563, 547, 530, 513, 497, 481, 466, 450, 435, 420, 405, 390, ++ 376, 361, 347, 333, 320, 306, 293, 279, 266, 254, 241, 228, 216, 204, ++ 192, 180, 168, 156, 145, 133, 122, 111, 100, 89, 78, 68, 57, 47, 36, ++ 26, 16, 6 ++ } ++ local vfp = vfps[zero_index(refresh - 48)] ++ if vfp == nil then ++ warn("Couldn't do refresh "..refresh.." on ROG Ally") ++ return base_mode ++ end ++ ++ local mode = base_mode ++ ++ gamescope.modegen.adjust_front_porch(mode, vfp) ++ mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) ++ ++ --debug(inspect(mode)) ++ return mode ++ end, ++ matches = function(display) ++ if display.vendor == "TMA" and display.model == "TL134ADXP03" then ++ debug("[z13] Matched vendor: "..display.vendor.." model: "..display.model.." product:"..display.product) ++ return 5000 ++ end ++ return -1 ++ end ++} ++debug("Registered Lenovo Legion Go S LCD as a known display") +\ No newline at end of file +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Wed, 23 Apr 2025 22:51:54 +0200 +Subject: feat(display): consider vporch to avoid timing issues + +--- + src/Backends/DRMBackend.cpp | 8 ++++++++ + src/main.cpp | 1 + + src/main.hpp | 1 + + src/vblankmanager.cpp | 6 +----- + 4 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/src/Backends/DRMBackend.cpp b/src/Backends/DRMBackend.cpp +index d7107325ad59..bcfc56dcbe20 100644 +--- a/src/Backends/DRMBackend.cpp ++++ b/src/Backends/DRMBackend.cpp +@@ -114,6 +114,11 @@ namespace gamescope + return nRefresh; + } + ++ static int32_t GetVblankNs(const drmModeModeInfo *mode) ++ { ++ return (mode->vsync_start - mode->vdisplay) * 1'000'000'000ll / mode->vrefresh / mode->vtotal; ++ } ++ + template + using CAutoDeletePtr = std::unique_ptr; + +@@ -3077,6 +3082,9 @@ bool drm_set_mode( struct drm_t *drm, const drmModeModeInfo *mode ) + g_nOutputRefresh = gamescope::GetModeRefresh( mode ); + g_nDynamicRefreshHz = 0; + ++ g_nsVsync = gamescope::GetVblankNs( mode ); ++ drm_log.infof("Vblank ns: %lu", g_nsVsync); ++ + update_drm_effective_orientations(drm, mode); + + switch ( drm->pConnector->GetCurrentOrientation() ) +diff --git a/src/main.cpp b/src/main.cpp +index 58230054ce53..b11e67c0c9b7 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -285,6 +285,7 @@ int g_nNestedDisplayIndex = 0; + uint32_t g_nOutputWidth = 0; + uint32_t g_nOutputHeight = 0; + int g_nOutputRefresh = 0; ++long g_nsVsync = 0; + bool g_bOutputHDREnabled = false; + + bool g_bFullscreen = false; +diff --git a/src/main.hpp b/src/main.hpp +index e7b857d44b0d..e6f8ff133689 100644 +--- a/src/main.hpp ++++ b/src/main.hpp +@@ -20,6 +20,7 @@ extern uint32_t g_nOutputWidth; + extern uint32_t g_nOutputHeight; + extern bool g_bForceRelativeMouse; + extern int g_nOutputRefresh; // mHz ++extern long g_nsVsync; // ns + extern bool g_bOutputHDREnabled; + extern bool g_bForceInternal; + extern bool g_bUseRotationShader; +diff --git a/src/vblankmanager.cpp b/src/vblankmanager.cpp +index 2fd0ec45ef81..ceb7829127c3 100644 +--- a/src/vblankmanager.cpp ++++ b/src/vblankmanager.cpp +@@ -95,8 +95,6 @@ namespace gamescope + + VBlankScheduleTime CVBlankTimer::CalcNextWakeupTime( bool bPreemptive ) + { +- const GamescopeScreenType eScreenType = GetBackend()->GetScreenType(); +- + const int nRefreshRate = GetRefresh(); + const uint64_t ulRefreshInterval = mHzToRefreshCycle( nRefreshRate ); + +@@ -113,9 +111,7 @@ namespace gamescope + // to not account for vertical front porch when dealing with the vblank + // drm_commit is going to target? + // Need to re-test that. +- const uint64_t ulRedZone = eScreenType == GAMESCOPE_SCREEN_TYPE_INTERNAL +- ? m_ulVBlankDrawBufferRedZone +- : std::min( m_ulVBlankDrawBufferRedZone, ( m_ulVBlankDrawBufferRedZone * 60'000 * nRefreshRate ) / 60'000 ); ++ const uint64_t ulRedZone = m_ulVBlankDrawBufferRedZone + g_nsVsync; + + const uint64_t ulDecayAlpha = m_ulVBlankRateOfDecayPercentage; // eg. 980 = 98% + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Sun, 4 May 2025 22:45:14 +0200 +Subject: Revert "Force wrap file usage for stb and glm dependencies" + +This reverts commit b01717437797ee97a6a9810ddfc69153b3861df1. +--- + src/meson.build | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/meson.build b/src/meson.build +index 0a0e958ba313..8a3a7237c787 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -19,14 +19,11 @@ xkbcommon = dependency('xkbcommon') + thread_dep = dependency('threads') + cap_dep = dependency('libcap', required: get_option('rt_cap')) + epoll_dep = dependency('epoll-shim', required: false) ++glm_dep = dependency('glm') + sdl2_dep = dependency('SDL2', required: get_option('sdl2_backend')) ++stb_dep = dependency('stb') + avif_dep = dependency('libavif', version: '>=1.0.0', required: get_option('avif_screenshots')) + +-glm_proj = subproject('glm') +-glm_dep = glm_proj.get_variable('glm_dep') +-stb_proj = subproject('stb') +-stb_dep = stb_proj.get_variable('stb_dep') +- + wlroots_dep = dependency( + 'wlroots', + version: ['>= 0.18.0', '< 0.19.0'], +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Sat, 17 May 2025 03:06:20 +0200 +Subject: fix: prevent external overlays from pulling focus + +--- + src/steamcompmgr.cpp | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index 86df7eaf681f..be69ce4b391f 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -6132,8 +6132,8 @@ bool handle_done_commit( steamcompmgr_win_t *w, xwayland_ctx_t *ctx, uint64_t co + hasRepaintNonBasePlane = true; + } + +- // If this is an external overlay, repaint +- if ( w == global_focus.externalOverlayWindow && w->opacity != TRANSLUCENT ) ++ // External overlays, e.g., mangohud, should not be able to repaint when VRR is on ++ if ( !GetBackend()->IsVRRActive() && w == global_focus.externalOverlayWindow && w->opacity != TRANSLUCENT ) + { + hasRepaintNonBasePlane = true; + } +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Sun, 22 Jun 2025 15:18:19 +0200 +Subject: feat: add Legion Go S display with all framerates + +--- + .../displays/lenovo.legiongos.lcd.lua | 71 +++++++++++-------- + 1 file changed, 42 insertions(+), 29 deletions(-) + +diff --git a/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua +index 32f776c17f3d..057850f374f8 100644 +--- a/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua ++++ b/scripts/00-gamescope/displays/lenovo.legiongos.lcd.lua +@@ -1,44 +1,58 @@ +-local legiongos_lcd_refresh_rates = { +- 52, 53, 54, 56, 57, 58, 59, +- 60, 61, 62, 63, 64, 65, 67, 68, 69, +- 70, +- 102, 103, 104, 105, 106, 107, 108, 109, +- 111, 112, 113, 114, 115, 116, 117, 118, 119, +- 120 +-} +- + gamescope.config.known_displays.legiongos_lcd = { + pretty_name = "Lenovo Legion Go S LCD", + hdr = { +- -- The Legion Go S panel does not support HDR. ++ -- Setup some fallbacks for undocking with HDR, meant ++ -- for the internal panel. It does not support HDR. + supported = false, + force_enabled = false, +- eotf = gamescope.eotf.gamma22, +- max_content_light_level = 500, +- max_frame_average_luminance = 500, +- min_content_light_level = 0.5 ++ eotf = gamescope.eotf.gamma22, ++ max_content_light_level = 500, ++ max_frame_average_luminance = 500, ++ min_content_light_level = 0.5 + }, +- -- 60Hz has a different pixel clock than 120Hz in the EDID with VRR disabled, +- -- and the panel is not responsive to tuning VFPs. To cover the non-VRR +- -- limiter, an LCD Deck-style dynamic modegen method works best. +- dynamic_refresh_rates = legiongos_lcd_refresh_rates, ++ ++ dynamic_refresh_rates = { ++ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, ++ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, ++ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, ++ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, ++ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, ++ 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, ++ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, ++ 118, 119, 120 ++ }, ++ ++ -- Detailed Timing Descriptors: ++ -- DTD 1: 1920x1200 120.002 Hz 8:5 151.683 kHz 315.500 MHz (172 mm x 107 mm) ++ -- Modeline "1920x1200_120.00" 315.500 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync ++ -- DTD 2: 1920x1200 60.001 Hz 8:5 75.841 kHz 157.750 MHz (172 mm x 107 mm) ++ -- Modeline "1920x1200_60.00" 157.750 1920 1968 2000 2080 1200 1254 1260 1264 -HSync -VSync + dynamic_modegen = function(base_mode, refresh) +- debug("Generating mode "..refresh.."Hz for Lenovo Legion Go S LCD") +- local mode = base_mode ++ debug("Generating mode "..refresh.."Hz with fixed pixel clock") ++ local vfps = { ++ 1950, 1885, 1824, 1764, 1707, 1652, 1599, 1548, 1499, 1451, 1405, ++ 1361, 1318, 1277, 1237, 1198, 1160, 1124, 1088, 1054, 1021, 988, ++ 957, 927, 897, 868, 840, 813, 786, 760, 735, 710, 686, 663, 640, ++ 618, 596, 575, 554, 534, 514, 495, 476, 457, 439, 421, 404, 387, ++ 370, 354, 338, 322, 307, 292, 277, 263, 249, 235, 221, 208, 195, ++ 182, 169, 157, 145, 133, 121, 109, 98, 87, 76, 65, 54 ++ } ++ local vfp = vfps[zero_index(refresh - 48)] ++ if vfp == nil then ++ warn("Couldn't do refresh "..refresh.." on ROG Ally") ++ return base_mode ++ end + +- -- These are only tuned for 1920x1200. +- gamescope.modegen.set_resolution(mode, 1920, 1200) ++ local mode = base_mode + +- -- hfp, hsync, hbp +- gamescope.modegen.set_h_timings(mode, 48, 36, 80) +- -- vfp, vsync, vbp +- gamescope.modegen.set_v_timings(mode, 54, 6, 4) +- mode.clock = gamescope.modegen.calc_max_clock(mode, refresh) ++ gamescope.modegen.adjust_front_porch(mode, vfp) + mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) + + --debug(inspect(mode)) + return mode + end, ++ ++ + matches = function(display) + local lcd_types = { + { vendor = "CSW", model = "PN8007QB1-1", product = 0x0800 }, +@@ -56,5 +70,4 @@ gamescope.config.known_displays.legiongos_lcd = { + return -1 + end + } +-debug("Registered Lenovo Legion Go S LCD as a known display") +---debug(inspect(gamescope.config.known_displays.legiongos_lcd)) ++debug("Registered Lenovo Legion Go S LCD as a known display") +\ No newline at end of file +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Sun, 29 Jun 2025 13:16:59 +0200 +Subject: update misyltoad urls + +--- + .gitmodules | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/.gitmodules b/.gitmodules +index ec7d4e430ee8..17ba783f809b 100644 +--- a/.gitmodules ++++ b/.gitmodules +@@ -1,12 +1,12 @@ + [submodule "subprojects/wlroots"] + path = subprojects/wlroots +- url = https://github.com/Joshua-Ashton/wlroots.git ++ url = https://github.com/misyltoad/wlroots.git + [submodule "subprojects/libliftoff"] + path = subprojects/libliftoff + url = https://gitlab.freedesktop.org/emersion/libliftoff.git + [submodule "subprojects/vkroots"] + path = subprojects/vkroots +- url = https://github.com/Joshua-Ashton/vkroots ++ url = https://github.com/misyltoad/vkroots + [submodule "subprojects/libdisplay-info"] + path = subprojects/libdisplay-info + url = https://gitlab.freedesktop.org/emersion/libdisplay-info +@@ -15,7 +15,7 @@ + url = https://github.com/ValveSoftware/openvr.git + [submodule "src/reshade"] + path = src/reshade +- url = https://github.com/Joshua-Ashton/reshade ++ url = https://github.com/misyltoad/reshade + [submodule "thirdparty/SPIRV-Headers"] + path = thirdparty/SPIRV-Headers + url = https://github.com/KhronosGroup/SPIRV-Headers/ +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Sun, 29 Jun 2025 13:17:14 +0200 +Subject: switch to bazzite fork for wlroots + +--- + .gitmodules | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/.gitmodules b/.gitmodules +index 17ba783f809b..2ae6cd101faf 100644 +--- a/.gitmodules ++++ b/.gitmodules +@@ -1,6 +1,6 @@ + [submodule "subprojects/wlroots"] + path = subprojects/wlroots +- url = https://github.com/misyltoad/wlroots.git ++ url = https://github.com/bazzite-org/wlroots.git + [submodule "subprojects/libliftoff"] + path = subprojects/libliftoff + url = https://gitlab.freedesktop.org/emersion/libliftoff.git +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Matthew Schwartz +Date: Sun, 22 Jun 2025 10:39:19 -0700 +Subject: steamcompmgr: track FSR state with preemptive upscaling + +g_bFSRActive was only being applied to the first frame of preemptive +upscaling, which meant that the FSR badge would quickly flicker from on +to off when preemptive upscaling was active. + +To account for this, track the state of preemptive upscaling and use +it to activate g_bFSRActive when applicable. +--- + src/steamcompmgr.cpp | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/steamcompmgr.cpp b/src/steamcompmgr.cpp +index be69ce4b391f..f867335557f9 100644 +--- a/src/steamcompmgr.cpp ++++ b/src/steamcompmgr.cpp +@@ -2509,6 +2509,9 @@ paint_all( bool async, bool dpms ) + } + + g_bFSRActive = frameInfo.useFSRLayer0; ++ if ( const auto& heldCommit = g_HeldCommits[HELD_COMMIT_BASE]; heldCommit && heldCommit->upscaledTexture ) { ++ g_bFSRActive = ( heldCommit->upscaledTexture->eFilter == GamescopeUpscaleFilter::FSR ); ++ } + + g_bFirstFrame = false; + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Georg Lehmann +Date: Mon, 7 Aug 2023 18:54:01 +0200 +Subject: rendervulkan: account for ycbcr descriptor count when creating + descriptor pool + +--- + src/rendervulkan.cpp | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/src/rendervulkan.cpp b/src/rendervulkan.cpp +index d833d0093830..ac5c16dab035 100644 +--- a/src/rendervulkan.cpp ++++ b/src/rendervulkan.cpp +@@ -847,6 +847,25 @@ bool CVulkanDevice::createPools() + return false; + } + ++ VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = { ++ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, ++ .format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM, ++ .type = VK_IMAGE_TYPE_2D, ++ .tiling = VK_IMAGE_TILING_OPTIMAL, ++ .usage = VK_IMAGE_USAGE_SAMPLED_BIT, ++ }; ++ ++ VkSamplerYcbcrConversionImageFormatProperties ycbcrProps = { ++ .sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES, ++ }; ++ ++ VkImageFormatProperties2 imageFormatProps = { ++ .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, ++ .pNext = &ycbcrProps, ++ }; ++ ++ res = vk.GetPhysicalDeviceImageFormatProperties2( physDev(), &imageFormatInfo, &imageFormatProps ); ++ + VkDescriptorPoolSize poolSizes[3] { + { + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, +@@ -858,7 +877,7 @@ bool CVulkanDevice::createPools() + }, + { + VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, +- uint32_t(m_descriptorSets.size()) * ((2 * VKR_SAMPLER_SLOTS) + (2 * VKR_LUT3D_COUNT)), ++ uint32_t(m_descriptorSets.size()) * (((ycbcrProps.combinedImageSamplerDescriptorCount + 1) * VKR_SAMPLER_SLOTS) + (2 * VKR_LUT3D_COUNT)), + }, + }; + +-- +2.50.1 + + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Antheas Kapenekakis +Date: Wed, 20 Aug 2025 22:07:52 +0200 +Subject: feat: add Ayaneo 3 display + +--- + .../displays/ayaneo.ayaneo3.oled.lua | 69 +++++++++++++++++++ + 1 file changed, 69 insertions(+) + create mode 100644 scripts/00-gamescope/displays/ayaneo.ayaneo3.oled.lua + +diff --git a/scripts/00-gamescope/displays/ayaneo.ayaneo3.oled.lua b/scripts/00-gamescope/displays/ayaneo.ayaneo3.oled.lua +new file mode 100644 +index 000000000000..9f6f725560b6 +--- /dev/null ++++ b/scripts/00-gamescope/displays/ayaneo.ayaneo3.oled.lua +@@ -0,0 +1,69 @@ ++local panel_id = "aya_fhd_oled" ++local panel_name = "AYA FHD OLED Panel" ++ ++local panel_models = { ++ { vendor = "AYA", model = "AYAOLED_FHD" }, ++} ++ ++local panel_refresh_rates = { 60, 90, 120, 144 } ++ ++local panel_hdr = { ++ supported = true, ++ force_enabled = true, ++ eotf = gamescope.eotf.ST2084, ++ max_content_light_level = 993.486, ++ max_frame_average_luminance = 400, ++ min_content_light_level = 0.007 ++} ++ ++ ++gamescope.config.known_displays[panel_id] = { ++ pretty_name = panel_name, ++ ++ -- These tables are optional ++ colorimetry = (panel_colorimetry ~= nil) and panel_colorimetry, ++ dynamic_refresh_rates = (panel_refresh_rates ~= nil) and panel_refresh_rates, ++ hdr = (panel_hdr ~= nil) and panel_hdr, ++ ++ dynamic_modegen = function(base_mode, refresh) ++ local mode = base_mode ++ debug("["..panel_id.."] Switching mode to "..mode.hdisplay.."x"..mode.vdisplay.."@"..refresh.."Hz") ++ ++ -- Override blanking intervals if defined ++ if panel_resolutions ~= nil then ++ for i, res in ipairs(panel_resolutions) do ++ if res.width == mode.hdisplay and res.height == mode.vdisplay then ++ ++ if res.hfp ~= nil and res.hsync ~= nil and res.hbp ~= nil then ++ gamescope.modegen.set_h_timings(mode, set_res.hfp, set_res.hsync, set_res.hbp) ++ debug("["..panel_id.."] Overriding horizontal blanking interval") ++ end ++ ++ if res.vfp ~= nil and res.vsync ~= nil and res.vbp ~= nil then ++ gamescope.modegen.set_v_timings(mode, set_res.vfp, set_res.vsync, set_res.vbp) ++ debug("["..panel_id.."] Overriding vertical blanking interval") ++ end ++ ++ -- No need to iterate anymore ++ break ++ end ++ end ++ end ++ ++ mode.clock = gamescope.modegen.calc_max_clock(mode, refresh) ++ mode.vrefresh = gamescope.modegen.calc_vrefresh(mode) ++ ++ return mode ++ end, ++ ++ matches = function(display) ++ for i, panel in ipairs(panel_models) do ++ if panel.vendor == display.vendor and panel.model == display.model then ++ debug("["..panel_id.."] Matched vendor: "..display.vendor.." model: "..display.model) ++ return 4000 ++ end ++ end ++ ++ return -1 ++ end ++} +\ No newline at end of file +-- +2.50.1 diff --git a/anda/games/terra-gamescope/terra-gamescope.spec b/anda/games/terra-gamescope/terra-gamescope.spec index 087dd1e74f..c5630e35a4 100755 --- a/anda/games/terra-gamescope/terra-gamescope.spec +++ b/anda/games/terra-gamescope/terra-gamescope.spec @@ -3,13 +3,13 @@ %global _default_patch_fuzz 2 %global build_timestamp %(date +"%Y%m%d") #global gamescope_tag 3.15.11 -%global gamescope_commit d3174928d47f7e353e7daca63cf882d65660cc7c +%global gamescope_commit f873ec7868fe84d2850e91148bcbd6d6b19a7443 %define short_commit %(echo %{gamescope_commit} | cut -c1-8) Name: terra-gamescope #Version: 100.%{gamescope_tag} -Version: 104.%{short_commit} -Release: 2%?dist +Version: 127.%{short_commit} +Release: 1%?dist Summary: Micro-compositor for video games on Wayland License: BSD @@ -27,6 +27,8 @@ Patch0: 0001-cstdint.patch # https://github.com/ChimeraOS/gamescope Patch1: handheld.patch +#Patch2: https://github.com/ValveSoftware/gamescope/pull/1867.patch + BuildRequires: meson >= 0.54.0 BuildRequires: ninja-build BuildRequires: cmake @@ -101,9 +103,9 @@ Summary: libs for %{name} %summary %prep +%setup -Tc # git clone --depth 1 --branch %%{gamescope_tag} %%{url}.git -git clone %{url}.git -cd gamescope +git clone %{url}.git $PWD git checkout %{gamescope_commit} git submodule update --init --recursive mkdir -p pkgconfig @@ -115,7 +117,6 @@ sed -i 's^../thirdparty/SPIRV-Headers/include/spirv/^/usr/include/spirv/^' src/m %autopatch -p1 %build -cd gamescope export PKG_CONFIG_PATH=pkgconfig %meson \ --auto-features=enabled \ @@ -123,12 +124,11 @@ export PKG_CONFIG_PATH=pkgconfig %meson_build %install -cd gamescope %meson_install --skip-subprojects %files -%license gamescope/LICENSE -%doc gamescope/README.md +%license LICENSE +%doc README.md %caps(cap_sys_nice=eip) %{_bindir}/gamescope %{_bindir}/gamescopectl %{_bindir}/gamescopestream diff --git a/anda/langs/nim/nim-nightly/nim-nightly.spec b/anda/langs/nim/nim-nightly/nim-nightly.spec index 55551b6479..4f8f30dce5 100644 --- a/anda/langs/nim/nim-nightly/nim-nightly.spec +++ b/anda/langs/nim/nim-nightly/nim-nightly.spec @@ -1,8 +1,8 @@ %global csrc_commit 561b417c65791cd8356b5f73620914ceff845d10 -%global commit d472022a7701d4c3c807980cf805606f2cb26277 +%global commit 51a9ada0436958ba3c3423802dd0d26dec88e18b %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global ver 2.3.1 -%global commit_date 20250828 +%global commit_date 20250917 %global debug_package %nil Name: nim-nightly diff --git a/anda/langs/python/colorthief/anda.hcl b/anda/langs/python/colorthief/anda.hcl new file mode 100644 index 0000000000..13650eb2df --- /dev/null +++ b/anda/langs/python/colorthief/anda.hcl @@ -0,0 +1,9 @@ +project pkg { + arches = ["x86_64"] + rpm { + spec = "python-colorthief.spec" + } + labels { + updbranch = 1 + } +} diff --git a/anda/langs/python/colorthief/python-colorthief.spec b/anda/langs/python/colorthief/python-colorthief.spec new file mode 100644 index 0000000000..52b1138ad0 --- /dev/null +++ b/anda/langs/python/colorthief/python-colorthief.spec @@ -0,0 +1,77 @@ +## Spec originally from Fedora, only modified for multibranch support and Terra changes + +## ...I don't know why they have this here? +# https://fedoraproject.org/wiki/Changes/EncourageI686LeafRemoval +ExcludeArch: %{ix86} + +%global pypi_name colorthief + +Name: python-%{pypi_name} +Version: 0.2.1 +Release: 1%{?dist} +Summary: Grabs the dominant color or a representative color palette from an image + +# https://gitlab.com/fedora/legal/fedora-license-data/-/issues/382 +# License file provided by Python module, see: +# rpm -q --licensefiles {python3_sitelib}/{name}-{version}.dist-info/LICENSE +License: BSD-3-Clause +URL: https://github.com/fengsp/color-thief-py +Source0: %{pypi_source} +BuildRequires: pyproject-rpm-macros +BuildRequires: python3-devel +BuildRequires: python3dist(pillow) +BuildRequires: python3dist(pip) +BuildRequires: python3dist(setuptools) +BuildArch: noarch +Packager: Gilver E. + +%global _description %{expand: +A Python module for grabbing the color palette from an image.} + +%description %_description + +%package -n python3-%{pypi_name} +Summary: %{summary} + +%description -n python3-%{pypi_name} %_description + +%prep +%autosetup -n %{pypi_name}-%{version} + +%build +%if 0%{?fedora} <= 41 || 0%{?rhel} +%py3_build +%else +%pyproject_wheel +%endif + +%install +%if 0%{?fedora} <= 41 || 0%{?rhel} +%py3_install +%else +%pyproject_install +%pyproject_save_files %{pypi_name} +%endif + +%if 0%{?fedora} > 41 +%check +%pyproject_check_import +%endif + +%if 0%{?fedora} <= 41 || 0%{?rhel} +%files -n python3-%{pypi_name} +%license LICENSE +%doc README.rst +%{python3_sitelib}/__pycache__/* +%{python3_sitelib}/%{pypi_name}.py +%{python3_sitelib}/%{pypi_name}-%{version}-py%{python3_version}.egg-info/ +%else +%files -n python3-%{pypi_name} -f %{pyproject_files} +%license LICENSE +%doc README.rst +%endif + + +%changelog +* Mon May 26 2025 Gilver E. - 0.2.1-1 +- Initial port from Fedora diff --git a/anda/langs/python/colorthief/update.rhai b/anda/langs/python/colorthief/update.rhai new file mode 100644 index 0000000000..e0b7496e5a --- /dev/null +++ b/anda/langs/python/colorthief/update.rhai @@ -0,0 +1 @@ +rpm.version(pypi("colorthief")); diff --git a/anda/langs/rust/television/rust-television.spec b/anda/langs/rust/television/rust-television.spec index 1ee158dfcc..6a3fe71cf4 100644 --- a/anda/langs/rust/television/rust-television.spec +++ b/anda/langs/rust/television/rust-television.spec @@ -5,8 +5,8 @@ %global crate television Name: rust-television -Version: 0.13.2 -Release: %autorelease +Version: 0.13.3 +Release: 1%?dist Summary: Cross-platform, fast and extensible general purpose fuzzy finder TUI License: MIT diff --git a/anda/langs/vala/vala-nightly/vala-nightly.spec b/anda/langs/vala/vala-nightly/vala-nightly.spec index 4ecdd2b05e..ee4f5b948d 100644 --- a/anda/langs/vala/vala-nightly/vala-nightly.spec +++ b/anda/langs/vala/vala-nightly/vala-nightly.spec @@ -3,11 +3,11 @@ %global priority 90 %global real_name vala -%global commit ba1b29121791c2a2235f33cf87a11563ac7da945 +%global commit d680994c54dd34b8bd3bd808f0023be19ea647da %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global repo https://gitlab.gnome.org/GNOME/%{real_name}.git -%global commit_date 20250806 +%global commit_date 20250903 %global snapshot_info %{commit_date}.%{shortcommit} Name: vala-nightly diff --git a/anda/langs/zig/master/zig-master.spec b/anda/langs/zig/master/zig-master.spec index 3238d9e4e2..ebcd055b80 100644 --- a/anda/langs/zig/master/zig-master.spec +++ b/anda/langs/zig/master/zig-master.spec @@ -15,7 +15,7 @@ %global mirror_url %(mirrors=%{zig_mirrors}; index=$(( RANDOM % ${#mirrors[@]} )); echo ${mirrors[$index]}) Name: zig-master -Version: 0.16.0~dev.48+aae556071 +Version: 0.16.0~dev.237+496313a1b Release: 1%?dist Summary: Master builds of the Zig language License: MIT AND NCSA AND LGPL-2.1-or-later AND LGPL-2.1-or-later WITH GCC-exception-2.0 AND GPL-2.0-or-later AND GPL-2.0-or-later WITH GCC-exception-2.0 AND BSD-3-Clause AND Inner-Net-2.0 AND ISC AND LicenseRef-Fedora-Public-Domain AND GFDL-1.1-or-later AND ZPL-2.1 diff --git a/anda/misc/krabby/anda.hcl b/anda/misc/krabby/anda.hcl new file mode 100644 index 0000000000..cf0c2fe0b4 --- /dev/null +++ b/anda/misc/krabby/anda.hcl @@ -0,0 +1,5 @@ +project pkg { + rpm { + spec = "krabby.spec" + } +} diff --git a/anda/misc/krabby/krabby.spec b/anda/misc/krabby/krabby.spec new file mode 100644 index 0000000000..3bb62f0f02 --- /dev/null +++ b/anda/misc/krabby/krabby.spec @@ -0,0 +1,34 @@ +Name: krabby +Version: 0.3.0 +Release: 1%{?dist} +SourceLicense: GPL-3.0-or-later +License: (MIT OR Apache-2.0) AND GPL-3.0-or-later AND MIT AND (Unlicense OR MIT) AND (BSD-2-Clause OR Apache-2.0 OR MIT) AND (Apache-2.0 OR BSL-1.0) AND MPL-2.0 AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) +Summary: Print Pokémon sprites in your terminal +URL: https://github.com/yannjor/krabby +Source0: %{url}/archive/refs/tags/v%{version}.tar.gz +BuildRequires: anda-srpm-macros +BuildRequires: cargo-rpm-macros +BuildRequires: mold +Packager: Gilver E. + +%description +Krabby is mostly a Rust rewrite of phoney badger's pokemon-colorscripts with some extra features. + +%prep +%autosetup -n %{name}-%{version} +%cargo_prep_online + +%build + +%install +%cargo_install +%{cargo_license_online} > LICENSE.dependencies + +%files +%license LICENSE LICENSE.dependencies +%doc README.md +%{_bindir}/%{name} + +%changelog +* Thu Feb 27 2025 Gilver E. +- Initial package diff --git a/anda/misc/krabby/update.rhai b/anda/misc/krabby/update.rhai new file mode 100644 index 0000000000..1d7d6637c8 --- /dev/null +++ b/anda/misc/krabby/update.rhai @@ -0,0 +1 @@ +rpm.version(crates("krabby")); diff --git a/anda/misc/openbangla-keyboard/openbangla-keyboard-nightly.spec b/anda/misc/openbangla-keyboard/openbangla-keyboard-nightly.spec index a41d4139f7..165fb7518e 100644 --- a/anda/misc/openbangla-keyboard/openbangla-keyboard-nightly.spec +++ b/anda/misc/openbangla-keyboard/openbangla-keyboard-nightly.spec @@ -1,6 +1,6 @@ %global ver 2.0.0 -%global commit 8070c29ae80f4ebd539547756f56351d98767b22 -%global commit_date 20250724 +%global commit 723e348ad2cb0607684d907ce8a9457e12993f4f +%global commit_date 20250820 %global shortcommit %(c=%{commit}; echo ${c:0:7}) Name: openbangla-keyboard-nightly diff --git a/anda/misc/pokemon-colorscripts/anda.hcl b/anda/misc/pokemon-colorscripts/anda.hcl new file mode 100644 index 0000000000..15a80e2e12 --- /dev/null +++ b/anda/misc/pokemon-colorscripts/anda.hcl @@ -0,0 +1,6 @@ +project pkg { + arches = ["x86_64"] + rpm { + spec = "pokemon-colorscripts.spec" + } +} diff --git a/anda/misc/pokemon-colorscripts/pokemon-colorscripts.spec b/anda/misc/pokemon-colorscripts/pokemon-colorscripts.spec new file mode 100644 index 0000000000..be742e55d7 --- /dev/null +++ b/anda/misc/pokemon-colorscripts/pokemon-colorscripts.spec @@ -0,0 +1,46 @@ +%global commit 5802ff67520be2ff6117a0abc78a08501f6252ad +%global commit_date 20241018 +%global shortcommit %(c=%{commit}; echo ${c:0:7}) + +Name: pokemon-colorscripts +Version: 0^%{commit_date}git.%{shortcommit} +Release: 1%{?dist} +License: MIT +Summary: CLI utility to print out images of Pokémon to the terminal +URL: https://gitlab.com/phoneybadger/%{name} +Source0: %{url}/-/archive/%{commit}/%{name}-%{shortcommit}.tar.gz +BuildArch: noarch +Requires: python3 +Packager: Gilver E. + +%description +A utility that prints unicode sprites of images of Pokémon to the terminal. + +%prep +%autosetup -n %{name}-%{commit} + +%build + +%install +install -Dm644 colorscripts/small/regular/* -t "%{buildroot}%{_datadir}/%{name}/colorscripts/small/regular" +install -Dm644 colorscripts/small/shiny/* -t "%{buildroot}%{_datadir}/%{name}/colorscripts/small/shiny" +install -Dm644 colorscripts/large/regular/* -t "%{buildroot}%{_datadir}/%{name}/colorscripts/large/regular" +install -Dm644 colorscripts/large/shiny/* -t "%{buildroot}%{_datadir}/%{name}/colorscripts/large/shiny" +install -Dm644 pokemon.json "%{buildroot}%{_datadir}/%{name}/pokemon.json" +install -Dm755 pokemon-colorscripts.py "%{buildroot}%{_datadir}/%{name}/pokemon-colorscripts.py" +install -Dm644 pokemon-colorscripts.1 "%{buildroot}%{_mandir}/man1/pokemon-colorscripts.1" +# Make name executable +mkdir -p %{buildroot}%{_bindir} +ln -sf "%{_datadir}/%{name}/pokemon-colorscripts.py" "%{buildroot}%{_bindir}/pokemon-colorscripts" + +%files +%license LICENSE.txt +%doc README.md +%dir %{_datadir}/%{name} +%{_datadir}/%{name}/* +%{_bindir}/pokemon-colorscripts +%{_mandir}/man1/pokemon-colorscripts.1.gz + +%changelog +* Thu Feb 27 2025 Gilver E. +- Initial package diff --git a/anda/misc/pokemon-colorscripts/update.rhai b/anda/misc/pokemon-colorscripts/update.rhai new file mode 100644 index 0000000000..1b9526ea94 --- /dev/null +++ b/anda/misc/pokemon-colorscripts/update.rhai @@ -0,0 +1,5 @@ +rpm.global("commit", gitlab_commit("gitlab.com", "28721344", "main")); +if rpm.changed() { + rpm.global("commit_date", date()); + rpm.release(); +} diff --git a/anda/misc/pokeshell/HELPER_ALIASES b/anda/misc/pokeshell/HELPER_ALIASES new file mode 100644 index 0000000000..c793b37ae8 --- /dev/null +++ b/anda/misc/pokeshell/HELPER_ALIASES @@ -0,0 +1,11 @@ +For ease of use, packaged helper scripts are aliased in /usr/bin. + +To use them, run: + +uv run create-pokemon-identifier + +OR: + +pokeget-timing + +to run the create_pokemon_identifier or timing scripts, respectively. diff --git a/anda/misc/pokeshell/anda.hcl b/anda/misc/pokeshell/anda.hcl new file mode 100644 index 0000000000..631d456eeb --- /dev/null +++ b/anda/misc/pokeshell/anda.hcl @@ -0,0 +1,9 @@ +project pkg { + arches = ["x86_64"] + rpm { + spec = "pokeshell.spec" + } + labels { + nightly = 1 + } +} diff --git a/anda/misc/pokeshell/pokeshell.spec b/anda/misc/pokeshell/pokeshell.spec new file mode 100644 index 0000000000..05a130405e --- /dev/null +++ b/anda/misc/pokeshell/pokeshell.spec @@ -0,0 +1,105 @@ +%global debug_package %{nil} +%global commit 6c9e2569843b08db14a964951f17a3943fd89fa2 +%global shortcommit %(c=%{commit}; echo ${c:0:7}) +%global date 20241124 +%global ver 1.0.0 + +Name: pokeshell +Version: %{ver}^%{date}git.%{shortcommit} +Release: 3%{?dist} +Summary: A shell program to show Pokémon sprites in the terminal. +License: GPL-3.0-or-later +URL: https://github.com/acxz/pokeshell +Source0: %{url}/archive/%{commit}.tar.gz#/%{name}-%{shortcommit}.tar.gz +Source1: HELPER_ALIASES +BuildRequires: sed +Requires: bash +Requires: jq +Requires: ImageMagick +Requires: python3 +Requires: chafa +Recommends: timg +BuildArch: noarch +Packager: Gilver E. + +%description +A featureful shell program to show Pokémon sprites in the terminal. + +%package helper-scripts +Summary: This package contains helper scripts for Pokéshell +Requires: bash +Requires: %{name} +Requires: uv +Recommends: hyperfine +Recommends: pokeget-rs +Recommends: pokemon-colorscripts + +%description helper-scripts +Generates pokemon identifiers (such as localized names) using PokeAPI that the sprite backends do not support natively. + +See included README for what these scripts can do. + +%package bash-completion +Summary: Bash completion for Pokéshell +Requires: bash +Requires: %{name} +Supplements: (%{name} and bash) + +%description bash-completion +Pokéshell Bash completion. + +%package zsh-completion +Summary: Zsh completion for Pokéshell +Requires: %{name} +Requires: zsh +Supplements: (%{name} and zsh) + +%description zsh-completion +Basic Zsh completion support for Pokéshell. + +%prep +%autosetup -n %{name}-%{commit} +cp %{SOURCE1} . +sed -i 's/MY_DIR=.*/MY_DIR=\/usr\/share\/%{name}/g' bin/pokeshell +sed -i 's/\.\.\/share\///' bin/pokeshell + +%build + +%install +install -Dm755 bin/pokeshell %{buildroot}%{_bindir}/%{name} +install -Dm755 bin/imageshell/imageshell.sh -t %{buildroot}%{_datadir}/%{name}/imageshell +install -Dm644 share/pokemon_identifiers.json -t %{buildroot}%{_datadir}/%{name} +install -Dm644 scripts/*.py -t %{buildroot}%{_datadir}/%{name}/scripts +install -Dm644 scripts/*.sh -t %{buildroot}%{_datadir}/%{name}/scripts +# Bash and Zsh completion share a single file, Zsh completion is pretty rudimentary +install -Dm644 share/bash-completion/completions/pokeshell -t %{buildroot}%{bash_completions_dir} +install -Dm644 share/bash-completion/completions/pokeshell %{buildroot}%{zsh_completions_dir}/_%{name} +# Make helper scripts directly executable +ln -sf %{_datadir}/%{name}/scripts/create_pokemon_identifiers.py %{buildroot}%{_bindir}/create-pokemon-identifiers +ln -sf %{_datadir}/%{name}/scripts/timing.sh %{buildroot}%{_bindir}/pokeget-timing + +%files +%license LICENSE.md +%doc README.md +%{_bindir}/%{name} +%dir %{_datadir}/%{name} +%{_datadir}/%{name}/pokemon_identifiers.json +%dir %{_datadir}/%{name}/imageshell +%{_datadir}/%{name}/imageshell/imageshell.sh + +%files helper-scripts +%doc scripts/README.md HELPER_ALIASES +%dir %{_datadir}/%{name}/scripts +%{_datadir}/%{name}/scripts/* +%{_bindir}/create-pokemon-identifiers +%{_bindir}/pokeget-timing + +%files bash-completion +%{bash_completions_dir}/%{name} + +%files zsh-completion +%{zsh_completions_dir}/_%{name} + +%changelog +* Sat Mar 01 2025 Gilver E. +- Initial package diff --git a/anda/misc/pokeshell/update.rhai b/anda/misc/pokeshell/update.rhai new file mode 100644 index 0000000000..9fca409203 --- /dev/null +++ b/anda/misc/pokeshell/update.rhai @@ -0,0 +1,8 @@ +rpm.global("commit", gh_commit("acxz/pokeshell")); +if rpm.changed() { + rpm.release(); + rpm.global("date", date()); + let v = gh_tag("acxz/pokeshell"); + v.crop(1); + rpm.global("ver", v); +} diff --git a/anda/misc/zapret/zapret.spec b/anda/misc/zapret/zapret.spec index 569b619921..b1b5bc081b 100644 --- a/anda/misc/zapret/zapret.spec +++ b/anda/misc/zapret/zapret.spec @@ -1,5 +1,5 @@ Name: zapret -Version: 71.2 +Version: 71.4 Release: 1%?dist Summary: A multi-platform Deep Packet Inspection (DPI) bypass tool License: MIT diff --git a/anda/multimedia/carla/Carla-nightly.spec b/anda/multimedia/carla/Carla-nightly.spec index 389e273e6e..09d5ead0fd 100644 --- a/anda/multimedia/carla/Carla-nightly.spec +++ b/anda/multimedia/carla/Carla-nightly.spec @@ -1,8 +1,8 @@ %global pname carla %global ver 2.5.10 -%global commit c355f1c5d766070e855be095858b38b127b393ce +%global commit 12bc40fd6c9c5b36481c7df55086b27ba9ae8a80 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250804 +%global commit_date 20250901 Name: Carla-nightly Version: %(echo %ver | tr -d 'v')^%commit_date.git~%shortcommit diff --git a/anda/multimedia/ffmpeg/VERSION_LCEVCdec.txt b/anda/multimedia/ffmpeg/VERSION_LCEVCdec.txt new file mode 100644 index 0000000000..1454f6ed4b --- /dev/null +++ b/anda/multimedia/ffmpeg/VERSION_LCEVCdec.txt @@ -0,0 +1 @@ +4.0.1 diff --git a/anda/multimedia/ffmpeg/VERSION_tesseract.txt b/anda/multimedia/ffmpeg/VERSION_tesseract.txt index c7ba1e87f7..a70b636b69 100644 --- a/anda/multimedia/ffmpeg/VERSION_tesseract.txt +++ b/anda/multimedia/ffmpeg/VERSION_tesseract.txt @@ -1 +1 @@ -5.5.0 \ No newline at end of file +0.3.13 \ No newline at end of file diff --git a/anda/multimedia/ffmpeg/anda.hcl b/anda/multimedia/ffmpeg/anda.hcl index 27d2b0ed25..44b1659420 100644 --- a/anda/multimedia/ffmpeg/anda.hcl +++ b/anda/multimedia/ffmpeg/anda.hcl @@ -2,6 +2,7 @@ project pkg { arches = ["x86_64", "aarch64", "i386"] rpm { spec = "ffmpeg.spec" + extra_repos = ["https://repos.fyralabs.com/terrarawhide-nvidia"] } labels { updbranch = 1 diff --git a/anda/multimedia/ffmpeg/ffmpeg-HandBrake.patch b/anda/multimedia/ffmpeg/ffmpeg-HandBrake.patch new file mode 100644 index 0000000000..0326da27f5 --- /dev/null +++ b/anda/multimedia/ffmpeg/ffmpeg-HandBrake.patch @@ -0,0 +1,1904 @@ +diff -Naur ffmpeg-7.1.1.old/configure ffmpeg-7.1.1/configure +--- ffmpeg-7.1.1.old/configure 2025-03-24 10:54:39.093543820 +0100 ++++ ffmpeg-7.1.1/configure 2025-03-24 10:54:39.281929795 +0100 +@@ -3338,6 +3338,7 @@ + av1_mediacodec_decoder_deps="mediacodec" + av1_mediacodec_encoder_deps="mediacodec" + av1_mediacodec_encoder_select="extract_extradata_bsf" ++av1_mf_encoder_deps="mediafoundation" + av1_nvenc_encoder_deps="nvenc NV_ENC_PIC_PARAMS_AV1" + av1_nvenc_encoder_select="atsc_a53" + av1_qsv_decoder_select="qsvdec" +diff -Naur ffmpeg-7.1.1.old/libavcodec/allcodecs.c ffmpeg-7.1.1/libavcodec/allcodecs.c +--- ffmpeg-7.1.1.old/libavcodec/allcodecs.c 2025-03-24 10:54:39.094862193 +0100 ++++ ffmpeg-7.1.1/libavcodec/allcodecs.c 2025-03-24 10:54:39.282298069 +0100 +@@ -839,6 +839,7 @@ + extern const FFCodec ff_av1_qsv_decoder; + extern const FFCodec ff_av1_qsv_encoder; + extern const FFCodec ff_av1_amf_encoder; ++extern const FFCodec ff_av1_mf_encoder; + extern const FFCodec ff_av1_vaapi_encoder; + extern const FFCodec ff_libopenh264_encoder; + extern const FFCodec ff_libopenh264_decoder; +diff -Naur ffmpeg-7.1.1.old/libavcodec/amfenc_av1.c ffmpeg-7.1.1/libavcodec/amfenc_av1.c +--- ffmpeg-7.1.1.old/libavcodec/amfenc_av1.c 2025-03-24 10:54:38.133756381 +0100 ++++ ffmpeg-7.1.1/libavcodec/amfenc_av1.c 2025-03-24 10:54:39.277830845 +0100 +@@ -116,6 +116,7 @@ + { "none", "no adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_NONE }, 0, 0, VE, .unit = "adaptive_quantisation_mode" }, + { "caq", "context adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_AQ_MODE_CAQ }, 0, 0, VE, .unit = "adaptive_quantisation_mode" }, + ++ { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { "align", "alignment mode", OFFSET(align), AV_OPT_TYPE_INT, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS }, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY, AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_NO_RESTRICTIONS, VE, .unit = "align" }, + { "64x16", "", 0, AV_OPT_TYPE_CONST, {.i64 = AMF_VIDEO_ENCODER_AV1_ALIGNMENT_MODE_64X16_ONLY }, 0, 0, VE, .unit = "align" }, +@@ -186,6 +187,8 @@ + AMFRate framerate; + AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + amf_int64 color_depth; ++ amf_int64 color_primaries; ++ amf_int64 transfer_characteristic; + amf_int64 color_profile; + enum AVPixelFormat pix_fmt; + +@@ -238,7 +241,11 @@ + } + + /// Color profile ++ color_primaries = ff_amf_get_color_primaries(avctx); ++ transfer_characteristic = ff_amf_get_transfer_characteristic(avctx); + color_profile = ff_amf_get_color_profile(avctx); ++ AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, color_primaries); ++ AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, transfer_characteristic); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE, color_profile); + + /// Color Depth +@@ -250,16 +257,6 @@ + } + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_COLOR_BIT_DEPTH, color_depth); +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PROFILE, color_profile); +- if (color_depth == AMF_COLOR_BIT_DEPTH_8) { +- /// Color Transfer Characteristics (AMF matches ISO/IEC) +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709); +- /// Color Primaries (AMF matches ISO/IEC) +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT709); +- } else { +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084); +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_AV1_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT2020); +- } + + profile_level = avctx->level; + if (profile_level == AV_LEVEL_UNKNOWN) { +diff -Naur ffmpeg-7.1.1.old/libavcodec/amfenc.c ffmpeg-7.1.1/libavcodec/amfenc.c +--- ffmpeg-7.1.1.old/libavcodec/amfenc.c 2025-03-24 10:54:38.032755166 +0100 ++++ ffmpeg-7.1.1/libavcodec/amfenc.c 2025-03-24 10:54:39.279550845 +0100 +@@ -415,10 +415,6 @@ + else + pix_fmt = avctx->pix_fmt; + +- if (pix_fmt == AV_PIX_FMT_P010) { +- AMF_RETURN_IF_FALSE(ctx, ctx->version >= AMF_MAKE_FULL_VERSION(1, 4, 32, 0), AVERROR_UNKNOWN, "10-bit encoder is not supported by AMD GPU drivers versions lower than 23.30.\n"); +- } +- + ctx->format = amf_av_to_amf_format(pix_fmt); + AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), + "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt)); +@@ -766,11 +762,50 @@ + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud); ++ switch (frame->pict_type) { ++ case AV_PICTURE_TYPE_I: ++ if (ctx->forced_idr) { ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_SPS, 1); ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_PPS, 1); ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_IDR); ++ } else { ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_I); ++ } ++ break; ++ case AV_PICTURE_TYPE_P: ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_P); ++ break; ++ case AV_PICTURE_TYPE_B: ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_PICTURE_TYPE_B); ++ break; ++ } + break; + case AV_CODEC_ID_HEVC: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud); ++ switch (frame->pict_type) { ++ case AV_PICTURE_TYPE_I: ++ if (ctx->forced_idr) { ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_HEADER, 1); ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_IDR); ++ } else { ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_I); ++ } ++ break; ++ case AV_PICTURE_TYPE_P: ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_FORCE_PICTURE_TYPE, AMF_VIDEO_ENCODER_HEVC_PICTURE_TYPE_P); ++ break; ++ } ++ break; ++ case AV_CODEC_ID_AV1: ++ if (frame->pict_type == AV_PICTURE_TYPE_I) { ++ if (ctx->forced_idr) { ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_INSERT_SEQUENCE_HEADER, 1); ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_KEY); ++ } else { ++ AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE, AMF_VIDEO_ENCODER_AV1_FORCE_FRAME_TYPE_INTRA_ONLY); ++ } ++ } + break; +- //case AV_CODEC_ID_AV1 not supported + default: + break; + } +@@ -878,6 +913,115 @@ + return ret; + } + ++int ff_amf_get_color_primaries(AVCodecContext *avctx) ++{ ++ amf_int64 color_primaries = AMF_COLOR_PRIMARIES_UNDEFINED; ++ switch (avctx->color_primaries) { ++ case AVCOL_PRI_BT709: ++ color_primaries = AMF_COLOR_PRIMARIES_BT709; ++ break; ++ case AVCOL_PRI_UNSPECIFIED: ++ color_primaries = AMF_COLOR_PRIMARIES_UNSPECIFIED; ++ break; ++ case AVCOL_PRI_RESERVED: ++ color_primaries = AMF_COLOR_PRIMARIES_RESERVED; ++ break; ++ case AVCOL_PRI_BT470M: ++ color_primaries = AMF_COLOR_PRIMARIES_BT470M; ++ break; ++ case AVCOL_PRI_BT470BG: ++ color_primaries = AMF_COLOR_PRIMARIES_BT470BG; ++ break; ++ case AVCOL_PRI_SMPTE170M: ++ color_primaries = AMF_COLOR_PRIMARIES_SMPTE170M; ++ break; ++ case AVCOL_PRI_SMPTE240M: ++ color_primaries = AMF_COLOR_PRIMARIES_SMPTE240M; ++ break; ++ case AVCOL_PRI_FILM: ++ color_primaries = AMF_COLOR_PRIMARIES_FILM; ++ break; ++ case AVCOL_PRI_BT2020: ++ color_primaries = AMF_COLOR_PRIMARIES_BT2020; ++ break; ++ case AVCOL_PRI_SMPTE428: ++ color_primaries = AMF_COLOR_PRIMARIES_SMPTE428; ++ break; ++ case AVCOL_PRI_SMPTE431: ++ color_primaries = AMF_COLOR_PRIMARIES_SMPTE431; ++ break; ++ case AVCOL_PRI_SMPTE432: ++ color_primaries = AMF_COLOR_PRIMARIES_SMPTE432; ++ break; ++ case AVCOL_PRI_EBU3213: ++ color_primaries = AMF_COLOR_PRIMARIES_JEDEC_P22; ++ break; ++ } ++ return color_primaries; ++} ++ ++int ff_amf_get_transfer_characteristic(AVCodecContext *avctx) ++{ ++ amf_int64 transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNDEFINED; ++ switch (avctx->color_trc) { ++ case AVCOL_TRC_BT709: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709; ++ break; ++ case AVCOL_TRC_UNSPECIFIED: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_UNSPECIFIED; ++ break; ++ case AVCOL_TRC_RESERVED: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_RESERVED; ++ break; ++ case AVCOL_TRC_GAMMA22: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_GAMMA22; ++ break; ++ case AVCOL_TRC_GAMMA28: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_GAMMA28; ++ break; ++ case AVCOL_TRC_SMPTE170M: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE170M; ++ break; ++ case AVCOL_TRC_SMPTE240M: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE240M; ++ break; ++ case AVCOL_TRC_LINEAR: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_LINEAR; ++ break; ++ case AVCOL_TRC_LOG: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_LOG; ++ break; ++ case AVCOL_TRC_LOG_SQRT: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_LOG_SQRT; ++ break; ++ case AVCOL_TRC_IEC61966_2_4: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_IEC61966_2_4; ++ break; ++ case AVCOL_TRC_BT1361_ECG: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_BT1361_ECG; ++ break; ++ case AVCOL_TRC_IEC61966_2_1: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_IEC61966_2_1; ++ break; ++ case AVCOL_TRC_BT2020_10: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_BT2020_10; ++ break; ++ case AVCOL_TRC_BT2020_12: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_BT2020_12; ++ break; ++ case AVCOL_TRC_SMPTE2084: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084; ++ break; ++ case AVCOL_TRC_SMPTE428: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE428; ++ break; ++ case AVCOL_TRC_ARIB_STD_B67: ++ transfer_characteristic = AMF_COLOR_TRANSFER_CHARACTERISTIC_ARIB_STD_B67; ++ break; ++ } ++ return transfer_characteristic; ++} ++ + int ff_amf_get_color_profile(AVCodecContext *avctx) + { + amf_int64 color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN; +diff -Naur ffmpeg-7.1.1.old/libavcodec/amfenc.h ffmpeg-7.1.1/libavcodec/amfenc.h +--- ffmpeg-7.1.1.old/libavcodec/amfenc.h 2025-03-24 10:54:37.990754660 +0100 ++++ ffmpeg-7.1.1/libavcodec/amfenc.h 2025-03-24 10:54:39.277763348 +0100 +@@ -114,6 +114,7 @@ + int max_b_frames; + int qvbr_quality_level; + int hw_high_motion_quality_boost; ++ int forced_idr; + + // HEVC - specific options + +@@ -173,6 +174,8 @@ + */ + extern const enum AVPixelFormat ff_amf_pix_fmts[]; + ++int ff_amf_get_color_primaries(AVCodecContext *avctx); ++int ff_amf_get_transfer_characteristic(AVCodecContext *avctx); + int ff_amf_get_color_profile(AVCodecContext *avctx); + + /** +diff -Naur ffmpeg-7.1.1.old/libavcodec/amfenc_h264.c ffmpeg-7.1.1/libavcodec/amfenc_h264.c +--- ffmpeg-7.1.1.old/libavcodec/amfenc_h264.c 2025-03-24 10:54:38.175756886 +0100 ++++ ffmpeg-7.1.1/libavcodec/amfenc_h264.c 2025-03-24 10:54:39.277925894 +0100 +@@ -133,6 +133,7 @@ + { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + { "me_quarter_pel", "Enable ME Quarter Pixel", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + ++ { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) , AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VE }, + + +@@ -201,6 +202,8 @@ + AMFRate framerate; + AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; ++ amf_int64 color_primaries; ++ amf_int64 transfer_characteristic; + amf_int64 color_profile; + enum AVPixelFormat pix_fmt; + +@@ -273,7 +276,11 @@ + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_ASPECT_RATIO, ratio); + } + ++ color_primaries = ff_amf_get_color_primaries(avctx); ++ transfer_characteristic = ff_amf_get_transfer_characteristic(avctx); + color_profile = ff_amf_get_color_profile(avctx); ++ AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_COLOR_PRIMARIES, color_primaries); ++ AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_TRANSFER_CHARACTERISTIC, transfer_characteristic); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_COLOR_PROFILE, color_profile); + + /// Color Range (Support for older Drivers) +@@ -287,10 +294,6 @@ + AMF_RETURN_IF_FALSE(ctx, pix_fmt != AV_PIX_FMT_P010, AVERROR_INVALIDDATA, "10-bit input video is not supported by AMF H264 encoder\n"); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_COLOR_BIT_DEPTH, AMF_COLOR_BIT_DEPTH_8); +- /// Color Transfer Characteristics (AMF matches ISO/IEC) +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_TRANSFER_CHARACTERISTIC, (amf_int64)avctx->color_trc); +- /// Color Primaries (AMF matches ISO/IEC) +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_OUTPUT_COLOR_PRIMARIES, (amf_int64)avctx->color_primaries); + + // autodetect rate control method + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN) { +diff -Naur ffmpeg-7.1.1.old/libavcodec/amfenc_hevc.c ffmpeg-7.1.1/libavcodec/amfenc_hevc.c +--- ffmpeg-7.1.1.old/libavcodec/amfenc_hevc.c 2025-03-24 10:54:37.991754672 +0100 ++++ ffmpeg-7.1.1/libavcodec/amfenc_hevc.c 2025-03-24 10:54:39.278019962 +0100 +@@ -100,6 +100,7 @@ + { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, + { "me_quarter_pel", "Enable ME Quarter Pixel ", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, + ++ { "forced_idr", "Force I frames to be IDR frames", OFFSET(forced_idr) ,AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL,{ .i64 = -1 }, -1, 1, VE }, + + +@@ -167,6 +168,8 @@ + AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; + amf_int64 color_depth; ++ amf_int64 color_primaries; ++ amf_int64 transfer_characteristic; + amf_int64 color_profile; + enum AVPixelFormat pix_fmt; + +@@ -241,7 +244,11 @@ + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO, ratio); + } + ++ color_primaries = ff_amf_get_color_primaries(avctx); ++ transfer_characteristic = ff_amf_get_transfer_characteristic(avctx); + color_profile = ff_amf_get_color_profile(avctx); ++ AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, color_primaries); ++ AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, transfer_characteristic); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PROFILE, color_profile); + /// Color Range (Support for older Drivers) + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NOMINAL_RANGE, !!(avctx->color_range == AVCOL_RANGE_JPEG)); +@@ -253,15 +260,6 @@ + color_depth = AMF_COLOR_BIT_DEPTH_10; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_COLOR_BIT_DEPTH, color_depth); +- if (color_depth == AMF_COLOR_BIT_DEPTH_8) { +- /// Color Transfer Characteristics (AMF matches ISO/IEC) +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_BT709); +- /// Color Primaries (AMF matches ISO/IEC) +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT709); +- } else { +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_TRANSFER_CHARACTERISTIC, AMF_COLOR_TRANSFER_CHARACTERISTIC_SMPTE2084); +- AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_OUTPUT_COLOR_PRIMARIES, AMF_COLOR_PRIMARIES_BT2020); +- } + + // Picture control properties + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR, ctx->gops_per_idr); +diff -Naur ffmpeg-7.1.1.old/libavcodec/av1dec.c ffmpeg-7.1.1/libavcodec/av1dec.c +--- ffmpeg-7.1.1.old/libavcodec/av1dec.c 2025-03-24 10:54:38.093755899 +0100 ++++ ffmpeg-7.1.1/libavcodec/av1dec.c 2025-03-24 10:54:39.273932914 +0100 +@@ -1002,6 +1002,8 @@ + break; + } + case ITU_T_T35_PROVIDER_CODE_DOLBY: { ++ AVBufferRef *rpu_buf; ++ AVFrameSideData *rpu; + int provider_oriented_code = bytestream2_get_be32(&gb); + if (itut_t35->itu_t_t35_country_code != ITU_T_T35_COUNTRY_CODE_US || + provider_oriented_code != 0x800) +@@ -1014,6 +1016,18 @@ + break; // ignore + } + ++ rpu_buf = av_buffer_alloc(itut_t35->payload_size); ++ if (rpu_buf) { ++ memcpy(rpu_buf->data, itut_t35->payload, itut_t35->payload_size); ++ rpu = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_RPU_BUFFER_T35, rpu_buf); ++ if (!rpu) { ++ av_buffer_unref(&rpu_buf); ++ return AVERROR(ENOMEM); ++ } ++ } else { ++ return AVERROR(ENOMEM); ++ } ++ + ret = ff_dovi_attach_side_data(&s->dovi, frame); + if (ret < 0) + return ret; +diff -Naur ffmpeg-7.1.1.old/libavcodec/bsf/hevc_mp4toannexb.c ffmpeg-7.1.1/libavcodec/bsf/hevc_mp4toannexb.c +--- ffmpeg-7.1.1.old/libavcodec/bsf/hevc_mp4toannexb.c 2025-03-24 10:54:38.075755683 +0100 ++++ ffmpeg-7.1.1/libavcodec/bsf/hevc_mp4toannexb.c 2025-03-24 10:54:39.273106358 +0100 +@@ -125,6 +125,7 @@ + AVPacket *in; + GetByteContext gb; + ++ int has_sps = 0, has_pps = 0; + int got_irap = 0; + int i, ret = 0; + +@@ -158,11 +159,14 @@ + } + + nalu_type = (bytestream2_peek_byte(&gb) >> 1) & 0x3f; ++ has_sps = (has_sps || nalu_type == HEVC_NAL_SPS); ++ has_pps = (has_pps || nalu_type == HEVC_NAL_PPS); + + /* prepend extradata to IRAP frames */ + is_irap = nalu_type >= HEVC_NAL_BLA_W_LP && + nalu_type <= HEVC_NAL_RSV_IRAP_VCL23; +- add_extradata = is_irap && !got_irap; ++ /* ignore the extradata if IRAP frame has sps and pps */ ++ add_extradata = is_irap && !got_irap && !(has_sps && has_pps); + extra_size = add_extradata * ctx->par_out->extradata_size; + got_irap |= is_irap; + +diff -Naur ffmpeg-7.1.1.old/libavcodec/ccaption_dec.c ffmpeg-7.1.1/libavcodec/ccaption_dec.c +--- ffmpeg-7.1.1.old/libavcodec/ccaption_dec.c 2025-03-24 10:54:38.169756814 +0100 ++++ ffmpeg-7.1.1/libavcodec/ccaption_dec.c 2025-03-24 10:54:39.268544045 +0100 +@@ -889,12 +889,13 @@ + + if (ctx->buffer[bidx].str[0] || ctx->real_time) { + ff_dlog(ctx, "cdp writing data (%s)\n", ctx->buffer[bidx].str); +- start_time = ctx->buffer_time[0]; +- sub->pts = start_time; +- end_time = ctx->buffer_time[1]; +- if (!ctx->real_time) ++ if (!ctx->real_time) { ++ start_time = ctx->buffer_time[0]; ++ sub->pts = start_time; ++ end_time = ctx->buffer_time[1]; + sub->end_display_time = av_rescale_q(end_time - start_time, + AV_TIME_BASE_Q, ms_tb); ++ } + else + sub->end_display_time = -1; + ret = ff_ass_add_rect2(sub, ctx->buffer[bidx].str, ctx->readorder++, 0, NULL, NULL, &nb_rect_allocated); +diff -Naur ffmpeg-7.1.1.old/libavcodec/dvdsubdec.c ffmpeg-7.1.1/libavcodec/dvdsubdec.c +--- ffmpeg-7.1.1.old/libavcodec/dvdsubdec.c 2025-03-24 10:54:37.975754480 +0100 ++++ ffmpeg-7.1.1/libavcodec/dvdsubdec.c 2025-03-24 10:54:39.267391144 +0100 +@@ -45,6 +45,8 @@ + int buf_size; + int forced_subs_only; + uint8_t used_color[256]; ++ int64_t pts; ++ int output_empty_rects; + } DVDSubContext; + + static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *rgba, int num_values) +@@ -230,7 +232,10 @@ + uint32_t size; + int64_t offset1, offset2; + +- if (buf_size < 10) ++ if (buf_size < 2) ++ return AVERROR(EAGAIN); ++ ++ if (buf_size == 2 && AV_RB16(buf) == 0) + return -1; + + if (AV_RB16(buf) == 0) { /* HD subpicture with 4-byte offsets */ +@@ -243,15 +248,22 @@ + cmd_pos = 2; + } + ++ if (big_offsets && buf_size < 6) ++ return AVERROR(EAGAIN); ++ + size = READ_OFFSET(buf + (big_offsets ? 2 : 0)); +- cmd_pos = READ_OFFSET(buf + cmd_pos); + +- if (cmd_pos < 0 || cmd_pos > buf_size - 2 - offset_size) { +- if (cmd_pos > size) { +- av_log(ctx, AV_LOG_ERROR, "Discarding invalid packet\n"); +- return 0; +- } ++ if (size == 0) ++ return -1; ++ ++ if (buf_size < size) + return AVERROR(EAGAIN); ++ ++ cmd_pos = READ_OFFSET(buf + cmd_pos); ++ ++ if (cmd_pos < 0 || cmd_pos > size) { ++ av_log(ctx, AV_LOG_ERROR, "Discarding invalid packet\n"); ++ return AVERROR_INVALIDDATA; + } + + while (cmd_pos > 0 && cmd_pos < buf_size - 2 - offset_size) { +@@ -524,10 +536,13 @@ + int appended = 0; + int is_menu; + ++ if (ctx->pts == AV_NOPTS_VALUE && sub->pts != AV_NOPTS_VALUE) ++ ctx->pts = sub->pts; + if (ctx->buf_size) { + int ret = append_to_cached_buf(avctx, buf, buf_size); + if (ret < 0) { + *data_size = 0; ++ ctx->pts = AV_NOPTS_VALUE; + return ret; + } + buf = ctx->buf; +@@ -538,7 +553,12 @@ + is_menu = decode_dvd_subtitles(ctx, sub, buf, buf_size); + if (is_menu == AVERROR(EAGAIN)) { + *data_size = 0; +- return appended ? 0 : append_to_cached_buf(avctx, buf, buf_size); ++ int ret = appended ? 0 : append_to_cached_buf(avctx, buf, buf_size); ++ if (ret < 0) { ++ ctx->pts = AV_NOPTS_VALUE; ++ return ret; ++ } ++ return buf_size; + } + + if (is_menu < 0) { +@@ -547,9 +567,10 @@ + reset_rects(sub); + *data_size = 0; + ++ ctx->pts = AV_NOPTS_VALUE; + return buf_size; + } +- if (!is_menu && find_smallest_bounding_rectangle(ctx, sub) == 0) ++ if (!is_menu && !ctx->output_empty_rects && find_smallest_bounding_rectangle(ctx, sub) == 0) + goto no_subtitle; + + if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED)) +@@ -557,6 +578,8 @@ + + ctx->buf_size = 0; + *data_size = 1; ++ sub->pts = ctx->pts; ++ ctx->pts = AV_NOPTS_VALUE; + return buf_size; + } + +@@ -682,6 +705,7 @@ + av_log(avctx, AV_LOG_DEBUG, " 0x%06"PRIx32, ctx->palette[i]); + av_log(avctx, AV_LOG_DEBUG, "\n"); + } ++ ctx->pts = AV_NOPTS_VALUE; + + return 1; + } +@@ -698,6 +722,7 @@ + { "palette", "set the global palette", OFFSET(palette_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, + { "ifo_palette", "obtain the global palette from .IFO file", OFFSET(ifo_str), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, + { "forced_subs_only", "Only show forced subtitles", OFFSET(forced_subs_only), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, SD}, ++ { "output_empty_rects", "Output subtitles with empty or fully transparent rects", OFFSET(output_empty_rects), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, SD}, + { NULL } + }; + static const AVClass dvdsub_class = { +diff -Naur ffmpeg-7.1.1.old/libavcodec/libdav1d.c ffmpeg-7.1.1/libavcodec/libdav1d.c +--- ffmpeg-7.1.1.old/libavcodec/libdav1d.c 2025-03-24 10:54:38.090755863 +0100 ++++ ffmpeg-7.1.1/libavcodec/libdav1d.c 2025-03-24 10:54:39.274085311 +0100 +@@ -563,6 +563,8 @@ + break; + } + case ITU_T_T35_PROVIDER_CODE_DOLBY: { ++ AVBufferRef *rpu_buf; ++ AVFrameSideData *rpu; + int provider_oriented_code = bytestream2_get_be32(&gb); + if (itut_t35->country_code != ITU_T_T35_COUNTRY_CODE_US || + provider_oriented_code != 0x800) +@@ -575,6 +577,18 @@ + break; // ignore + } + ++ rpu_buf = av_buffer_alloc(itut_t35->payload_size); ++ if (rpu_buf) { ++ memcpy(rpu_buf->data, itut_t35->payload, itut_t35->payload_size); ++ rpu = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_DOVI_RPU_BUFFER_T35, rpu_buf); ++ if (!rpu) { ++ av_buffer_unref(&rpu_buf); ++ goto fail; ++ } ++ } else { ++ goto fail; ++ } ++ + res = ff_dovi_attach_side_data(&dav1d->dovi, frame); + if (res < 0) + goto fail; +diff -Naur ffmpeg-7.1.1.old/libavcodec/mfenc.c ffmpeg-7.1.1/libavcodec/mfenc.c +--- ffmpeg-7.1.1.old/libavcodec/mfenc.c 2025-03-24 10:54:38.125756284 +0100 ++++ ffmpeg-7.1.1/libavcodec/mfenc.c 2025-03-24 10:54:39.282547759 +0100 +@@ -1315,3 +1315,4 @@ + + MF_ENCODER(VIDEO, h264, H264, venc_opts, VFMTS, VCAPS, defaults); + MF_ENCODER(VIDEO, hevc, HEVC, venc_opts, VFMTS, VCAPS, defaults); ++MF_ENCODER(VIDEO, av1, AV1, venc_opts, VFMTS, VCAPS, defaults); +diff -Naur ffmpeg-7.1.1.old/libavcodec/mf_utils.c ffmpeg-7.1.1/libavcodec/mf_utils.c +--- ffmpeg-7.1.1.old/libavcodec/mf_utils.c 2025-03-24 10:54:38.086755815 +0100 ++++ ffmpeg-7.1.1/libavcodec/mf_utils.c 2025-03-24 10:54:39.282392106 +0100 +@@ -240,6 +240,7 @@ + GUID_ENTRY(MFMediaType_Video), + GUID_ENTRY(MFAudioFormat_PCM), + GUID_ENTRY(MFAudioFormat_Float), ++ GUID_ENTRY(ff_MFVideoFormat_AV1), + GUID_ENTRY(MFVideoFormat_H264), + GUID_ENTRY(MFVideoFormat_H264_ES), + GUID_ENTRY(ff_MFVideoFormat_HEVC), +@@ -507,6 +508,7 @@ + const CLSID *ff_codec_to_mf_subtype(enum AVCodecID codec) + { + switch (codec) { ++ case AV_CODEC_ID_AV1: return &ff_MFVideoFormat_AV1; + case AV_CODEC_ID_H264: return &MFVideoFormat_H264; + case AV_CODEC_ID_HEVC: return &ff_MFVideoFormat_HEVC; + case AV_CODEC_ID_AC3: return &MFAudioFormat_Dolby_AC3; +diff -Naur ffmpeg-7.1.1.old/libavcodec/mf_utils.h ffmpeg-7.1.1/libavcodec/mf_utils.h +--- ffmpeg-7.1.1.old/libavcodec/mf_utils.h 2025-03-24 10:54:38.061755515 +0100 ++++ ffmpeg-7.1.1/libavcodec/mf_utils.h 2025-03-24 10:54:39.282464482 +0100 +@@ -113,6 +113,7 @@ + + DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_HEVC, 0x43564548); // FCC('HEVC') + DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_HEVC_ES, 0x53564548); // FCC('HEVS') ++DEFINE_MEDIATYPE_GUID(ff_MFVideoFormat_AV1, 0x31305641); // FCC('AV01') + + + // This enum is missing from mingw-w64's codecapi.h by v7.0.0. +diff -Naur ffmpeg-7.1.1.old/libavcodec/pgssubdec.c ffmpeg-7.1.1/libavcodec/pgssubdec.c +--- ffmpeg-7.1.1.old/libavcodec/pgssubdec.c 2025-03-24 10:54:37.986754612 +0100 ++++ ffmpeg-7.1.1/libavcodec/pgssubdec.c 2025-03-24 10:54:39.280528236 +0100 +@@ -35,9 +35,11 @@ + #include "libavutil/opt.h" + + #define RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +-#define MAX_EPOCH_PALETTES 8 // Max 8 allowed per PGS epoch +-#define MAX_EPOCH_OBJECTS 64 // Max 64 allowed per PGS epoch +-#define MAX_OBJECT_REFS 2 // Max objects per display set ++#define MAX_EPOCH_PALETTES 8 // Max 8 allowed per PGS epoch ++#define MAX_EPOCH_OBJECTS 64 // Max 64 allowed per PGS epoch ++#define MAX_OBJECT_REFS 2 // Max objects per display set ++#define MAX_OBJECT_WH 4096 // Max object width/height ++ + + enum SegmentType { + PALETTE_SEGMENT = 0x14, +@@ -48,57 +50,80 @@ + }; + + typedef struct PGSSubObjectRef { +- int id; +- int window_id; +- uint8_t composition_flag; +- int x; +- int y; +- int crop_x; +- int crop_y; +- int crop_w; +- int crop_h; ++ uint16_t id; ++ uint8_t window_id; ++ uint8_t composition_flag; ++ uint16_t x; ++ uint16_t y; ++ uint16_t crop_x; ++ uint16_t crop_y; ++ uint16_t crop_w; ++ uint16_t crop_h; + } PGSSubObjectRef; + + typedef struct PGSSubPresentation { +- int id_number; +- int palette_id; +- int object_count; ++ uint8_t palette_flag; ++ uint8_t palette_id; ++ uint8_t object_count; + PGSSubObjectRef objects[MAX_OBJECT_REFS]; +- int64_t pts; ++ int64_t pts; + } PGSSubPresentation; + + typedef struct PGSSubObject { +- int id; +- int w; +- int h; +- uint8_t *rle; +- unsigned int rle_buffer_size, rle_data_len; +- unsigned int rle_remaining_len; ++ uint16_t id; ++ uint16_t w; ++ uint16_t h; ++ uint8_t *rle; ++ uint8_t *bitmap; ++ uint32_t rle_buffer_size; ++ uint32_t rle_data_len; ++ uint32_t rle_remaining_len; ++ uint32_t bitmap_buffer_size; ++ uint32_t bitmap_size; + } PGSSubObject; + + typedef struct PGSSubObjects { +- int count; ++ uint8_t count; + PGSSubObject object[MAX_EPOCH_OBJECTS]; + } PGSSubObjects; + + typedef struct PGSSubPalette { +- int id; +- uint32_t clut[256]; ++ uint8_t id; ++ uint32_t clut[AVPALETTE_COUNT]; + } PGSSubPalette; + + typedef struct PGSSubPalettes { +- int count; ++ uint8_t count; + PGSSubPalette palette[MAX_EPOCH_PALETTES]; + } PGSSubPalettes; + ++typedef struct PGSGraphicPlane { ++ uint8_t count; ++ uint8_t writable; ++ AVSubtitleRect visible_rect[MAX_OBJECT_REFS]; ++} PGSGraphicPlane; ++ + typedef struct PGSSubContext { + AVClass *class; + PGSSubPresentation presentation; + PGSSubPalettes palettes; + PGSSubObjects objects; ++ PGSGraphicPlane plane; + int forced_subs_only; + } PGSSubContext; + ++static void clear_graphic_plane(PGSSubContext *ctx) ++{ ++ int i; ++ ++ for (i = 0; i < ctx->plane.count; i++) { ++ av_freep(&ctx->plane.visible_rect[i].data[0]); ++ memset(&ctx->plane.visible_rect[i], 0, sizeof(ctx->plane.visible_rect[i])); ++ } ++ ctx->plane.writable = 0; ++ ctx->plane.count = 0; ++} ++ + static void flush_cache(AVCodecContext *avctx) + { + PGSSubContext *ctx = avctx->priv_data; +@@ -106,8 +131,11 @@ + + for (i = 0; i < ctx->objects.count; i++) { + av_freep(&ctx->objects.object[i].rle); +- ctx->objects.object[i].rle_buffer_size = 0; ++ ctx->objects.object[i].rle_buffer_size = 0; + ctx->objects.object[i].rle_remaining_len = 0; ++ av_freep(&ctx->objects.object[i].bitmap); ++ ctx->objects.object[i].bitmap_buffer_size = 0; ++ ctx->objects.object[i].bitmap_size = 0; + } + ctx->objects.count = 0; + ctx->palettes.count = 0; +@@ -144,6 +172,7 @@ + + static av_cold int close_decoder(AVCodecContext *avctx) + { ++ clear_graphic_plane((PGSSubContext *)avctx->priv_data); + flush_cache(avctx); + + return 0; +@@ -159,48 +188,51 @@ + * @param buf pointer to the RLE data to process + * @param buf_size size of the RLE data to process + */ +-static int decode_rle(AVCodecContext *avctx, AVSubtitleRect *rect, +- const uint8_t *buf, unsigned int buf_size) ++static int decode_object_rle(AVCodecContext *avctx, PGSSubObject *object) + { +- const uint8_t *rle_bitmap_end; ++ const uint8_t *rle_buf; ++ const uint8_t *rle_end; + int pixel_count, line_count; ++ rle_buf = object->rle; ++ rle_end = object->rle + object->rle_data_len; + +- rle_bitmap_end = buf + buf_size; ++ object->bitmap_size = object->w * object->h; ++ av_fast_padded_malloc(&object->bitmap, &object->bitmap_buffer_size, ++ object->bitmap_size); + +- rect->data[0] = av_malloc_array(rect->w, rect->h); +- +- if (!rect->data[0]) ++ if (!object->bitmap) + return AVERROR(ENOMEM); + + pixel_count = 0; + line_count = 0; + +- while (buf < rle_bitmap_end && line_count < rect->h) { ++ while (rle_buf < rle_end && line_count < object->h) { + uint8_t flags, color; + int run; + +- color = bytestream_get_byte(&buf); ++ color = bytestream_get_byte(&rle_buf); + run = 1; + + if (color == 0x00) { +- flags = bytestream_get_byte(&buf); ++ flags = bytestream_get_byte(&rle_buf); + run = flags & 0x3f; + if (flags & 0x40) +- run = (run << 8) + bytestream_get_byte(&buf); +- color = flags & 0x80 ? bytestream_get_byte(&buf) : 0; ++ run = (run << 8) + bytestream_get_byte(&rle_buf); ++ color = flags & 0x80 ? bytestream_get_byte(&rle_buf) : 0; + } + +- if (run > 0 && pixel_count + run <= rect->w * rect->h) { +- memset(rect->data[0] + pixel_count, color, run); ++ if (run > 0 && pixel_count + run <= object->w * object->h) { ++ memset(object->bitmap + pixel_count, color, run); + pixel_count += run; + } else if (!run) { + /* + * New Line. Check if correct pixels decoded, if not display warning + * and adjust bitmap pointer to correct new line position. + */ +- if (pixel_count % rect->w > 0) { +- av_log(avctx, AV_LOG_ERROR, "Decoded %d pixels, when line should be %d pixels\n", +- pixel_count % rect->w, rect->w); ++ if (pixel_count % object->w > 0) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Decoded %d pixels, when object line should be %d pixels\n", ++ pixel_count % object->w, object->w); + if (avctx->err_recognition & AV_EF_EXPLODE) { + return AVERROR_INVALIDDATA; + } +@@ -209,13 +241,11 @@ + } + } + +- if (pixel_count < rect->w * rect->h) { +- av_log(avctx, AV_LOG_ERROR, "Insufficient RLE data for subtitle\n"); ++ if (pixel_count < object->w * object->h) { ++ av_log(avctx, AV_LOG_ERROR, "Insufficient RLE data for object\n"); + return AVERROR_INVALIDDATA; + } +- +- ff_dlog(avctx, "Pixel Count = %d, Area = %d\n", pixel_count, rect->w * rect->h); +- ++ ff_dlog(avctx, "Pixel Count = %d, Area = %d\n", pixel_count, object->w * object->h); + return 0; + } + +@@ -237,7 +267,7 @@ + + uint8_t sequence_desc; + unsigned int rle_bitmap_len, width, height; +- int id; ++ int id, ret; + + if (buf_size <= 4) + return AVERROR_INVALIDDATA; +@@ -260,57 +290,71 @@ + /* Read the Sequence Description to determine if start of RLE data or appended to previous RLE */ + sequence_desc = bytestream_get_byte(&buf); + +- if (!(sequence_desc & 0x80)) { +- /* Additional RLE data */ +- if (buf_size > object->rle_remaining_len) ++ /* First in sequence object definition segment */ ++ if (sequence_desc & 0x80) { ++ if (buf_size <= 7) + return AVERROR_INVALIDDATA; ++ buf_size -= 7; + +- memcpy(object->rle + object->rle_data_len, buf, buf_size); +- object->rle_data_len += buf_size; +- object->rle_remaining_len -= buf_size; +- +- return 0; +- } +- +- if (buf_size <= 7) +- return AVERROR_INVALIDDATA; +- buf_size -= 7; ++ /* Decode rle bitmap length, stored size includes width/height data */ ++ rle_bitmap_len = bytestream_get_be24(&buf) - 2*2; + +- /* Decode rle bitmap length, stored size includes width/height data */ +- rle_bitmap_len = bytestream_get_be24(&buf) - 2*2; ++ if (buf_size > rle_bitmap_len) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Buffer dimension %d larger than the expected RLE data %d\n", ++ buf_size, rle_bitmap_len); ++ return AVERROR_INVALIDDATA; ++ } + +- if (buf_size > rle_bitmap_len) { +- av_log(avctx, AV_LOG_ERROR, +- "Buffer dimension %d larger than the expected RLE data %d\n", +- buf_size, rle_bitmap_len); +- return AVERROR_INVALIDDATA; +- } ++ /* Get bitmap dimensions from data */ ++ width = bytestream_get_be16(&buf); ++ height = bytestream_get_be16(&buf); ++ ++ /* Make sure the bitmap is not too large */ ++ if (MAX_OBJECT_WH < width || MAX_OBJECT_WH < height || !width || !height) { ++ av_log(avctx, AV_LOG_ERROR, "Bitmap dimensions (%dx%d) invalid.\n", width, height); ++ return AVERROR_INVALIDDATA; ++ } + +- /* Get bitmap dimensions from data */ +- width = bytestream_get_be16(&buf); +- height = bytestream_get_be16(&buf); +- +- /* Make sure the bitmap is not too large */ +- if (avctx->width < width || avctx->height < height || !width || !height) { +- av_log(avctx, AV_LOG_ERROR, "Bitmap dimensions (%dx%d) invalid.\n", width, height); +- return AVERROR_INVALIDDATA; +- } ++ object->rle_data_len = 0; ++ object->w = width; ++ object->h = height; ++ /* Dimensions against video are checked at decode after cropping. */ ++ av_fast_padded_malloc(&object->rle, &object->rle_buffer_size, rle_bitmap_len); + +- object->w = width; +- object->h = height; ++ if (!object->rle) { ++ object->rle_remaining_len = 0; ++ return AVERROR(ENOMEM); ++ } + +- av_fast_padded_malloc(&object->rle, &object->rle_buffer_size, rle_bitmap_len); ++ memcpy(object->rle, buf, buf_size); ++ object->rle_remaining_len = rle_bitmap_len; ++ } else { ++ /* Additional RLE data */ ++ if (buf_size > object->rle_remaining_len) ++ return AVERROR_INVALIDDATA; + +- if (!object->rle) { +- object->rle_data_len = 0; +- object->rle_remaining_len = 0; +- return AVERROR(ENOMEM); ++ memcpy(object->rle + object->rle_data_len, buf, buf_size); + } ++ object->rle_data_len += buf_size; ++ object->rle_remaining_len -= buf_size; + +- memcpy(object->rle, buf, buf_size); +- object->rle_data_len = buf_size; +- object->rle_remaining_len = rle_bitmap_len - buf_size; +- ++ /* Last in sequence object definition (can be both first and last) */ ++ if (sequence_desc & 0x40) { ++ /* Attempt decoding if data is valid */ ++ if (0 == object->rle_remaining_len) { ++ ret = decode_object_rle(avctx, object); ++ if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE || ret == AVERROR(ENOMEM))) { ++ return ret; ++ } ++ } else { ++ av_log(avctx, AV_LOG_ERROR, ++ "RLE data length %u is %u bytes shorter than expected\n", ++ object->rle_data_len, object->rle_remaining_len); ++ if (avctx->err_recognition & AV_EF_EXPLODE) ++ return AVERROR_INVALIDDATA; ++ } ++ } + return 0; + } + +@@ -318,7 +362,7 @@ + * Parse the palette segment packet. + * + * The palette segment contains details of the palette, +- * a maximum of 256 colors can be defined. ++ * a maximum of 256 colors (AVPALETTE_COUNT) can be defined. + * + * @param avctx contains the current codec context + * @param buf pointer to the packet to process +@@ -391,13 +435,17 @@ + int64_t pts) + { + PGSSubContext *ctx = avctx->priv_data; +- int i, state, ret; ++ int ret; ++ uint8_t i, state; + const uint8_t *buf_end = buf + buf_size; + + // Video descriptor + int w = bytestream_get_be16(&buf); + int h = bytestream_get_be16(&buf); + ++ // On a new display set, reset writability of the graphic plane ++ ctx->plane.writable = 0; ++ + ctx->presentation.pts = pts; + + ff_dlog(avctx, "Video Dimensions %dx%d\n", +@@ -406,88 +454,121 @@ + if (ret < 0) + return ret; + +- /* Skip 1 bytes of unknown, frame rate */ +- buf++; ++ /* Skip 3 bytes: framerate (1), presentation id number (2) */ ++ buf+=3; + +- // Composition descriptor +- ctx->presentation.id_number = bytestream_get_be16(&buf); + /* +- * state is a 2 bit field that defines pgs epoch boundaries ++ * State is a 2 bit field that defines pgs epoch boundaries + * 00 - Normal, previously defined objects and palettes are still valid + * 01 - Acquisition point, previous objects and palettes can be released + * 10 - Epoch start, previous objects and palettes can be released + * 11 - Epoch continue, previous objects and palettes can be released + * +- * reserved 6 bits discarded ++ * Reserved 6 bits discarded + */ + state = bytestream_get_byte(&buf) >> 6; + if (state != 0) { ++ /* Epoch start always wipes the graphic plane. Epoch continue does only if ++ * playback is not seamless, which should not happen with a proper stream. ++ */ ++ if (0b10 == state) ++ clear_graphic_plane((PGSSubContext *)avctx->priv_data); + flush_cache(avctx); + } + ++ /* Reserved 7 bits discarded. */ ++ ctx->presentation.palette_flag = bytestream_get_byte(&buf) & 0x80; ++ ctx->presentation.palette_id = bytestream_get_byte(&buf); ++ + /* +- * skip palette_update_flag (0x80), ++ * On palette update, don't parse the compositions references, ++ * just evaluate the existing graphic plane with the new palette. + */ +- buf += 1; +- ctx->presentation.palette_id = bytestream_get_byte(&buf); +- ctx->presentation.object_count = bytestream_get_byte(&buf); +- if (ctx->presentation.object_count > MAX_OBJECT_REFS) { +- av_log(avctx, AV_LOG_ERROR, +- "Invalid number of presentation objects %d\n", +- ctx->presentation.object_count); +- ctx->presentation.object_count = 2; +- if (avctx->err_recognition & AV_EF_EXPLODE) { +- return AVERROR_INVALIDDATA; ++ if (!ctx->presentation.palette_flag) { ++ ctx->presentation.object_count = bytestream_get_byte(&buf); ++ if (ctx->presentation.object_count > MAX_OBJECT_REFS) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Invalid number of presentation objects %d\n", ++ ctx->presentation.object_count); ++ ctx->presentation.object_count = 2; ++ if (avctx->err_recognition & AV_EF_EXPLODE) { ++ return AVERROR_INVALIDDATA; ++ } + } +- } + ++ for (i = 0; i < ctx->presentation.object_count; i++) { ++ PGSSubObjectRef *const object = &ctx->presentation.objects[i]; + +- for (i = 0; i < ctx->presentation.object_count; i++) +- { +- PGSSubObjectRef *const object = &ctx->presentation.objects[i]; +- +- if (buf_end - buf < 8) { +- av_log(avctx, AV_LOG_ERROR, "Insufficent space for object\n"); +- ctx->presentation.object_count = i; +- return AVERROR_INVALIDDATA; +- } +- +- object->id = bytestream_get_be16(&buf); +- object->window_id = bytestream_get_byte(&buf); +- object->composition_flag = bytestream_get_byte(&buf); +- +- object->x = bytestream_get_be16(&buf); +- object->y = bytestream_get_be16(&buf); +- +- // If cropping +- if (object->composition_flag & 0x80) { +- object->crop_x = bytestream_get_be16(&buf); +- object->crop_y = bytestream_get_be16(&buf); +- object->crop_w = bytestream_get_be16(&buf); +- object->crop_h = bytestream_get_be16(&buf); +- } +- +- ff_dlog(avctx, "Subtitle Placement x=%d, y=%d\n", +- object->x, object->y); +- +- if (object->x > avctx->width || object->y > avctx->height) { +- av_log(avctx, AV_LOG_ERROR, "Subtitle out of video bounds. x = %d, y = %d, video width = %d, video height = %d.\n", +- object->x, object->y, +- avctx->width, avctx->height); +- object->y = object->x = 0; +- if (avctx->err_recognition & AV_EF_EXPLODE) { ++ if (buf_end - buf < 8) { ++ av_log(avctx, AV_LOG_ERROR, "Insufficent space for object\n"); ++ ctx->presentation.object_count = i; + return AVERROR_INVALIDDATA; + } ++ ++ object->id = bytestream_get_be16(&buf); ++ object->window_id = bytestream_get_byte(&buf); ++ object->composition_flag = bytestream_get_byte(&buf); ++ ++ object->x = bytestream_get_be16(&buf); ++ object->y = bytestream_get_be16(&buf); ++ ++ // If cropping ++ if (object->composition_flag & 0x80) { ++ object->crop_x = bytestream_get_be16(&buf); ++ object->crop_y = bytestream_get_be16(&buf); ++ object->crop_w = bytestream_get_be16(&buf); ++ object->crop_h = bytestream_get_be16(&buf); ++ } ++ ++ /* Placement is checked at decode after cropping. */ ++ ff_dlog(avctx, "Subtitle Placement x=%d, y=%d\n", ++ object->x, object->y); + } + } ++ return 0; ++} ++ ++/** ++ * Parse the window segment packet. ++ * ++ * The window segment instructs the decoder to redraw the graphic plane ++ * with the composition references provided in the presentation segment ++ * ++ * @param avctx contains the current codec context ++ */ ++static int parse_window_segment(AVCodecContext *avctx, const uint8_t *buf, ++ int buf_size) ++{ ++ PGSSubContext *ctx = (PGSSubContext *)avctx->priv_data; ++ ++ // 1 byte: number of windows defined ++ if (bytestream_get_byte(&buf) > MAX_OBJECT_REFS) { ++ av_log(avctx, AV_LOG_ERROR, "Too many windows defined.\n"); ++ return AVERROR_INVALIDDATA; ++ } + ++ /* TODO: mask objects with windows when transfering to the graphic plane ++ * Window Segment Structure ++ * { ++ * 1 byte : window id, ++ * 2 bytes: X position of window, ++ * 2 bytes: Y position of window, ++ * 2 bytes: Width of window, ++ * 2 bytes: Height of window. ++ * } ++ */ ++ // Flush the graphic plane, it will be redrawn. ++ clear_graphic_plane(ctx); ++ ctx->plane.writable = 1; ++ ctx->plane.count = ctx->presentation.object_count; + return 0; + } + + /** + * Parse the display segment packet. + * +- * The display segment controls the updating of the display. ++ * The display segment closes the display set. The inferred data is used ++ * to decide if the display should be updated. + * + * @param avctx contains the current codec context + * @param data pointer to the data pertaining the subtitle to display +@@ -500,26 +581,33 @@ + PGSSubContext *ctx = avctx->priv_data; + int64_t pts; + PGSSubPalette *palette; +- int i, ret; ++ int i; + + pts = ctx->presentation.pts != AV_NOPTS_VALUE ? ctx->presentation.pts : sub->pts; + memset(sub, 0, sizeof(*sub)); + sub->pts = pts; + ctx->presentation.pts = AV_NOPTS_VALUE; +- sub->start_display_time = 0; + // There is no explicit end time for PGS subtitles. The end time + // is defined by the start of the next sub which may contain no + // objects (i.e. clears the previous sub) + sub->end_display_time = UINT32_MAX; +- sub->format = 0; + +- // Blank if last object_count was 0. +- if (!ctx->presentation.object_count) ++ // Object count is zero only on an epoch start with no WDS ++ // or the last DS with a WDS had no presentation object. ++ if (!ctx->plane.count) { + return 1; +- sub->rects = av_calloc(ctx->presentation.object_count, sizeof(*sub->rects)); +- if (!sub->rects) { +- return AVERROR(ENOMEM); + } ++ ++ if (!ctx->presentation.palette_flag && !ctx->plane.writable) { ++ // This display set does not perform a display update ++ // E.g. it only defines new objects or palettes for future usage. ++ return 0; ++ } ++ ++ sub->rects = av_calloc(ctx->plane.count, sizeof(*sub->rects)); ++ if (!sub->rects) ++ return AVERROR(ENOMEM); ++ + palette = find_palette(ctx->presentation.palette_id, &ctx->palettes); + if (!palette) { + // Missing palette. Should only happen with damaged streams. +@@ -528,57 +616,128 @@ + avsubtitle_free(sub); + return AVERROR_INVALIDDATA; + } +- for (i = 0; i < ctx->presentation.object_count; i++) { +- AVSubtitleRect *const rect = av_mallocz(sizeof(*rect)); +- PGSSubObject *object; + +- if (!rect) +- return AVERROR(ENOMEM); +- sub->rects[sub->num_rects++] = rect; +- rect->type = SUBTITLE_BITMAP; ++ for (i = 0; i < ctx->plane.count; i++) { ++ const PGSSubObjectRef *sub_object = &ctx->presentation.objects[i]; ++ AVSubtitleRect *const gp_rect = &ctx->plane.visible_rect[i]; ++ AVSubtitleRect *rect; ++ gp_rect->type = SUBTITLE_BITMAP; ++ ++ // Compose the graphic plane if a window segment has been provided ++ if (ctx->plane.writable) { ++ PGSSubObject *object; ++ ++ // Process bitmap ++ object = find_object(sub_object->id, &ctx->objects); ++ if (!object) { ++ // Missing object. Should only happen with damaged streams. ++ av_log(avctx, AV_LOG_ERROR, "Invalid object id %d\n", sub_object->id); ++ if (avctx->err_recognition & AV_EF_EXPLODE) ++ return AVERROR_INVALIDDATA; ++ // Leaves rect empty with 0 width and height. ++ continue; ++ } ++ if (sub_object->composition_flag & 0x40) ++ gp_rect->flags |= AV_SUBTITLE_FLAG_FORCED; + +- /* Process bitmap */ +- object = find_object(ctx->presentation.objects[i].id, &ctx->objects); +- if (!object) { +- // Missing object. Should only happen with damaged streams. +- av_log(avctx, AV_LOG_ERROR, "Invalid object id %d\n", +- ctx->presentation.objects[i].id); +- if (avctx->err_recognition & AV_EF_EXPLODE) +- return AVERROR_INVALIDDATA; +- // Leaves rect empty with 0 width and height. +- continue; +- } +- if (ctx->presentation.objects[i].composition_flag & 0x40) +- rect->flags |= AV_SUBTITLE_FLAG_FORCED; ++ gp_rect->x = sub_object->x; ++ gp_rect->y = sub_object->y; + +- rect->x = ctx->presentation.objects[i].x; +- rect->y = ctx->presentation.objects[i].y; ++ if (object->rle) { ++ int out_of_picture = 0; ++ gp_rect->w = object->w; ++ gp_rect->h = object->h; ++ ++ gp_rect->linesize[0] = object->w; ++ ++ // Check for cropping. ++ if (sub_object->composition_flag & 0x80) { ++ int out_of_object = 0; ++ ++ if (object->w < sub_object->crop_x + sub_object->crop_w) ++ out_of_object = 1; ++ if (object->h < sub_object->crop_y + sub_object->crop_h) ++ out_of_object = 1; ++ ++ if (out_of_object) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Subtitle cropping values are out of object. " ++ "obj_w = %d, obj_h = %d, crop_x = %d, crop_y = %d, " ++ "crop_w = %d, crop_h = %d.\n", ++ object->w, ++ object->h, ++ sub_object->crop_x, ++ sub_object->crop_y, ++ sub_object->crop_w, ++ sub_object->crop_h); ++ if (avctx->err_recognition & AV_EF_EXPLODE) ++ return AVERROR_INVALIDDATA; ++ } else { ++ // Replace subtitle dimensions with cropping ones. ++ gp_rect->w = sub_object->crop_w; ++ gp_rect->h = sub_object->crop_h; ++ gp_rect->linesize[0] = sub_object->crop_w; ++ } ++ } + +- if (object->rle) { +- rect->w = object->w; +- rect->h = object->h; ++ /* Make sure the subtitle is not out of picture. */ ++ if (avctx->width < gp_rect->x + gp_rect->w || !gp_rect->w) ++ out_of_picture = 1; ++ if (avctx->height < gp_rect->y + gp_rect->h || !gp_rect->h) ++ out_of_picture = 1; ++ if (out_of_picture) { ++ av_log(avctx, AV_LOG_ERROR, ++ "Subtitle out of video bounds. " ++ "x = %d, y = %d, width = %d, height = %d.\n", ++ gp_rect->x, gp_rect->y, gp_rect->w, gp_rect->h); ++ if (avctx->err_recognition & AV_EF_EXPLODE) ++ return AVERROR_INVALIDDATA; ++ gp_rect->w = 0; ++ gp_rect->h = 0; ++ continue; ++ } + +- rect->linesize[0] = object->w; ++ if (!object->bitmap_size || object->rle_remaining_len) { ++ gp_rect->w = 0; ++ gp_rect->h = 0; ++ continue; ++ } + +- if (object->rle_remaining_len) { +- av_log(avctx, AV_LOG_ERROR, "RLE data length %u is %u bytes shorter than expected\n", +- object->rle_data_len, object->rle_remaining_len); +- if (avctx->err_recognition & AV_EF_EXPLODE) +- return AVERROR_INVALIDDATA; +- } +- ret = decode_rle(avctx, rect, object->rle, object->rle_data_len); +- if (ret < 0) { +- if ((avctx->err_recognition & AV_EF_EXPLODE) || +- ret == AVERROR(ENOMEM)) { +- return ret; ++ gp_rect->data[0] = av_malloc_array(gp_rect->w, gp_rect->h); ++ if (!gp_rect->data[0]) ++ return AVERROR(ENOMEM); ++ ++ if (sub_object->composition_flag & 0x80) { ++ /* Copy cropped bitmap. */ ++ int y; ++ ++ for (y = 0; y < sub_object->crop_h; y++) { ++ memcpy(&gp_rect->data[0][y * sub_object->crop_w], ++ &object->bitmap[(sub_object->crop_y + y) * ++ object->w + sub_object->crop_x], ++ sub_object->crop_w); ++ } ++ } ++ else { ++ /* copy full object */ ++ memcpy(gp_rect->data[0], object->bitmap, object->bitmap_size); + } +- rect->w = 0; +- rect->h = 0; +- continue; + } + } +- /* Allocate memory for colors */ +- rect->nb_colors = 256; ++ // Export graphic plane content with latest palette ++ rect = av_memdup(gp_rect, sizeof(*gp_rect)); ++ if (!rect) ++ return AVERROR(ENOMEM); ++ ++ sub->rects[sub->num_rects++] = rect; ++ if (gp_rect->data[0]) { ++ rect->data[0] = av_memdup(gp_rect->data[0], rect->w*rect->h); ++ if (!rect->data[0]) ++ return AVERROR(ENOMEM); ++ } ++ ++ // Allocate memory for colors ++ rect->nb_colors = AVPALETTE_COUNT; + rect->data[1] = av_mallocz(AVPALETTE_SIZE); + if (!rect->data[1]) + return AVERROR(ENOMEM); +@@ -641,14 +800,7 @@ + ret = parse_presentation_segment(avctx, buf, segment_length, sub->pts); + break; + case WINDOW_SEGMENT: +- /* +- * Window Segment Structure (No new information provided): +- * 2 bytes: Unknown, +- * 2 bytes: X position of subtitle, +- * 2 bytes: Y position of subtitle, +- * 2 bytes: Width of subtitle, +- * 2 bytes: Height of subtitle. +- */ ++ ret = parse_window_segment(avctx, buf, segment_length); + break; + case DISPLAY_SEGMENT: + if (*got_sub_ptr) { +diff -Naur ffmpeg-7.1.1.old/libavcodec/videotoolbox.c ffmpeg-7.1.1/libavcodec/videotoolbox.c +--- ffmpeg-7.1.1.old/libavcodec/videotoolbox.c 2025-03-24 10:54:38.027755105 +0100 ++++ ffmpeg-7.1.1/libavcodec/videotoolbox.c 2025-03-24 10:54:39.271196851 +0100 +@@ -916,6 +916,23 @@ + break; + } + ++#if ARCH_X86_64 ++ if (avctx->codec_id == AV_CODEC_ID_H264 && ++ avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10) ++ { ++ // 10-bit H.264 is not supported on x86_64 ++ return AVERROR(ENOSYS); ++ } ++#endif ++ ++ if (avctx->codec_id == AV_CODEC_ID_H264 && ++ (avctx->level == 61 || avctx->level == 62)) ++ { ++ // H.264 Level 6.1 and 6.2 can't be ++ // decoded properly ++ return AVERROR(ENOSYS); ++ } ++ + #if defined(MAC_OS_X_VERSION_10_9) && !TARGET_OS_IPHONE && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9) && AV_HAS_BUILTIN(__builtin_available) + if (avctx->codec_id == AV_CODEC_ID_PRORES) { + if (__builtin_available(macOS 10.9, *)) { +diff -Naur ffmpeg-7.1.1.old/libavformat/isom.h ffmpeg-7.1.1/libavformat/isom.h +--- ffmpeg-7.1.1.old/libavformat/isom.h 2025-03-24 10:54:38.366759184 +0100 ++++ ffmpeg-7.1.1/libavformat/isom.h 2025-03-24 10:54:39.261252302 +0100 +@@ -272,6 +272,9 @@ + MOVEncryptionIndex *encryption_index; + } cenc; + ++ int has_fallback; // Audio fallback track ++ int fallback; ++ + struct IAMFDemuxContext *iamf; + } MOVStreamContext; + +diff -Naur ffmpeg-7.1.1.old/libavformat/matroskaenc.c ffmpeg-7.1.1/libavformat/matroskaenc.c +--- ffmpeg-7.1.1.old/libavformat/matroskaenc.c 2025-03-24 10:54:38.396759545 +0100 ++++ ffmpeg-7.1.1/libavformat/matroskaenc.c 2025-03-24 10:54:39.269651231 +0100 +@@ -2933,6 +2933,16 @@ + case AV_CODEC_ID_AAC: + if (side_data_size && mkv->track.bc) { + int output_sample_rate = 0; ++ if (par->extradata && par->extradata_size) { ++ if (par->extradata_size != side_data_size || ++ memcmp(par->extradata, side_data, side_data_size)) { ++ av_log(s, AV_LOG_ERROR, "Error, AAC extradata changed mid-stream.\n"); ++ return AVERROR(EINVAL); ++ } else { ++ // Already written ++ break; ++ } ++ } + ret = get_aac_sample_rates(s, mkv, side_data, side_data_size, + &track->sample_rate, &output_sample_rate); + if (ret < 0) +diff -Naur ffmpeg-7.1.1.old/libavformat/mov.c ffmpeg-7.1.1/libavformat/mov.c +--- ffmpeg-7.1.1.old/libavformat/mov.c 2025-03-24 10:54:38.353759028 +0100 ++++ ffmpeg-7.1.1/libavformat/mov.c 2025-03-24 10:54:39.261629363 +0100 +@@ -56,6 +56,7 @@ + #include "libavcodec/mpegaudiodecheader.h" + #include "libavcodec/mlp_parse.h" + #include "avformat.h" ++#include "avlanguage.h" + #include "internal.h" + #include "avio_internal.h" + #include "demux.h" +@@ -342,6 +343,73 @@ + return 0; + } + ++static int mov_read_3gp_udta_tag(MOVContext *c, AVIOContext *pb, MOVAtom atom) ++{ ++ const char *key; ++ AVDictionary *metadata; ++ uint16_t langcode = 0; ++ char key2[32], language[4] = {0}; ++ uint32_t str_size, version; ++ char *str; ++ if (atom.size < 6) ++ return AVERROR_INVALIDDATA; ++ switch (atom.type) { ++ case MKTAG( 'a','l','b','m'): key = "album"; break; ++ case MKTAG( 'a','u','t','h'): key = "author"; break; ++ case MKTAG( 'c','p','r','t'): key = "copyright"; break; ++ case MKTAG( 'd','s','c','p'): key = "comment"; break; ++ case MKTAG( 'g','n','r','e'): key = "genre"; break; ++ case MKTAG( 'p','e','r','f'): key = "artist"; break; ++ case MKTAG( 't','i','t','l'): key = "title"; break; ++ case MKTAG( 'y','r','r','c'): key = "date"; break; ++ default: return 0; ++ } ++ version = avio_rb32(pb); // version + flags ++ if (version != 0) ++ av_log(c->fc, AV_LOG_WARNING, "udta %s unknown version number: %u\n", str, version); ++ if (MKTAG( 'y','r','r','c') == atom.type) { ++ int year; ++ year = avio_rb16(pb); ++ str = av_asprintf("%d", year); ++ if (!str) ++ return AVERROR(ENOMEM); ++ } else { ++ int ret; ++ const char *tmp; ++ langcode = avio_rb16(pb); ++ ff_mov_lang_to_iso639(langcode, language); ++ tmp = ff_convert_lang_to(language, AV_LANG_ISO639_2_BIBL); ++ if (!tmp) ++ av_log(c->fc, AV_LOG_WARNING, "udta %s unknown language code: %u\n", str, langcode); ++ str_size = atom.size - 6; ++ if (str_size <= 0 || str_size >= INT_MAX/2) ++ return AVERROR_INVALIDDATA; ++ str = av_mallocz(str_size + 1); ++ if (!str) ++ return AVERROR(ENOMEM); ++ ret = ffio_read_size(pb, str, str_size); ++ if (ret < 0) { ++ av_free(str); ++ return ret; ++ } ++ str[str_size] = 0; ++ } ++ if (c->trak_index < 0) { ++ metadata = c->fc->metadata; ++ c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; ++ } ++ else { ++ metadata = c->fc->streams[c->trak_index]->metadata; ++ } ++ av_dict_set(&metadata, key, str, 0); ++ if (*language && strcmp(language, "und")) { ++ snprintf(key2, sizeof(key2), "%s-%s", key, language); ++ av_dict_set(&metadata, key2, str, 0); ++ } ++ av_freep(&str); ++ return 0; ++} ++ + static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) + { + char tmp_key[AV_FOURCC_MAX_STRING_SIZE] = {0}; +@@ -354,6 +422,7 @@ + int (*parse)(MOVContext*, AVIOContext*, unsigned, const char*) = NULL; + int raw = 0; + int num = 0; ++ AVDictionary *metadata; + + switch (atom.type) { + case MKTAG( '@','P','R','M'): key = "premiere_version"; raw = 1; break; +@@ -367,15 +436,33 @@ + case MKTAG( 'c','a','t','g'): key = "category"; break; + case MKTAG( 'c','p','i','l'): key = "compilation"; + parse = mov_metadata_int8_no_padding; break; +- case MKTAG( 'c','p','r','t'): key = "copyright"; break; ++ case MKTAG( 'c','p','r','t'): ++ key = "copyright"; ++ if (!c->itunes_metadata) { ++ int64_t pos = avio_tell(pb); ++ int ret = mov_read_3gp_udta_tag(c, pb, atom); ++ if (ret != AVERROR_INVALIDDATA) ++ return ret; ++ avio_seek(pb, pos, SEEK_SET); ++ } ++ break; + case MKTAG( 'd','e','s','c'): key = "description"; break; + case MKTAG( 'd','i','s','k'): key = "disc"; + parse = mov_metadata_track_or_disc_number; break; + case MKTAG( 'e','g','i','d'): key = "episode_uid"; + parse = mov_metadata_int8_no_padding; break; + case MKTAG( 'F','I','R','M'): key = "firmware"; raw = 1; break; +- case MKTAG( 'g','n','r','e'): key = "genre"; +- parse = mov_metadata_gnre; break; ++ case MKTAG( 'g','n','r','e'): ++ key = "genre"; ++ parse = mov_metadata_gnre; ++ if (!c->itunes_metadata) { ++ int64_t pos = avio_tell(pb); ++ int ret = mov_read_3gp_udta_tag(c, pb, atom); ++ if (ret != AVERROR_INVALIDDATA) ++ return ret; ++ avio_seek(pb, pos, SEEK_SET); ++ } ++ break; + case MKTAG( 'h','d','v','d'): key = "hd_video"; + parse = mov_metadata_int8_no_padding; break; + case MKTAG( 'H','M','M','T'): +@@ -386,6 +473,7 @@ + return mov_metadata_loci(c, pb, atom.size); + case MKTAG( 'm','a','n','u'): key = "make"; break; + case MKTAG( 'm','o','d','l'): key = "model"; break; ++ case MKTAG( 'n','a','m','e'): key = "title"; raw = 1; break; + case MKTAG( 'p','c','s','t'): key = "podcast"; + parse = mov_metadata_int8_no_padding; break; + case MKTAG( 'p','g','a','p'): key = "gapless_playback"; +@@ -445,6 +533,15 @@ + case MKTAG(0xa9,'w','r','n'): key = "warning"; break; + case MKTAG(0xa9,'w','r','t'): key = "composer"; break; + case MKTAG(0xa9,'x','y','z'): key = "location"; break; ++ case MKTAG( 'a','l','b','m'): ++ case MKTAG( 'a','u','t','h'): ++ case MKTAG( 'd','s','c','p'): ++ case MKTAG( 'p','e','r','f'): ++ case MKTAG( 't','i','t','l'): ++ case MKTAG( 'y','r','r','c'): ++ if (!c->itunes_metadata) { ++ return mov_read_3gp_udta_tag(c, pb, atom); ++ } + } + retry: + if (c->itunes_metadata && atom.size > 8) { +@@ -571,17 +668,23 @@ + } + str[str_size] = 0; + } +- c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; +- av_dict_set(&c->fc->metadata, key, str, 0); ++ if (c->trak_index < 0) { ++ metadata = c->fc->metadata; ++ c->fc->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; ++ if (!strcmp(key, "encoder")) { ++ int major, minor, micro; ++ if (sscanf(str, "HandBrake %d.%d.%d", &major, &minor, µ) == 3) { ++ c->handbrake_version = 1000000*major + 1000*minor + micro; ++ } ++ } ++ } ++ else { ++ metadata = c->fc->streams[c->trak_index]->metadata; ++ } ++ av_dict_set(&metadata, key, str, 0); + if (*language && strcmp(language, "und")) { + snprintf(key2, sizeof(key2), "%s-%s", key, language); +- av_dict_set(&c->fc->metadata, key2, str, 0); +- } +- if (!strcmp(key, "encoder")) { +- int major, minor, micro; +- if (sscanf(str, "HandBrake %d.%d.%d", &major, &minor, µ) == 3) { +- c->handbrake_version = 1000000*major + 1000*minor + micro; +- } ++ av_dict_set(&metadata, key2, str, 0); + } + } + +@@ -9081,6 +9184,23 @@ + return ret; + } + ++static int mov_read_fall(MOVContext *c, AVIOContext *pb, MOVAtom atom) ++{ ++ AVStream *st; ++ MOVStreamContext *sc; ++ ++ if (c->fc->nb_streams < 1) ++ return 0; ++ st = c->fc->streams[c->fc->nb_streams-1]; ++ sc = st->priv_data; ++ ++ sc->fallback = avio_rb32(pb); ++ sc->has_fallback = 1; ++ ++ return 0; ++} ++ ++ + static const MOVParseTableEntry mov_default_parse_table[] = { + { MKTAG('A','C','L','R'), mov_read_aclr }, + { MKTAG('A','P','R','G'), mov_read_avid }, +@@ -9183,6 +9303,7 @@ + { MKTAG('v','p','c','C'), mov_read_vpcc }, + { MKTAG('m','d','c','v'), mov_read_mdcv }, + { MKTAG('c','l','l','i'), mov_read_clli }, ++{ MKTAG('f','a','l','l'), mov_read_fall }, + { MKTAG('d','v','c','C'), mov_read_dvcc_dvvc }, + { MKTAG('d','v','v','C'), mov_read_dvcc_dvvc }, + { MKTAG('d','v','w','C'), mov_read_dvcc_dvvc }, +@@ -10367,6 +10488,23 @@ + err = ff_replaygain_export(st, s->metadata); + if (err < 0) + return err; ++ if (sc->has_fallback) { ++ for (j = 0; j < s->nb_streams; j++) { ++ if (s->streams[j]->id == sc->fallback) { ++ AVPacketSideData *sd; ++ int *fallback; ++ sd = av_packet_side_data_new(&st->codecpar->coded_side_data, ++ &st->codecpar->nb_coded_side_data, ++ AV_PKT_DATA_FALLBACK_TRACK, ++ sizeof(int), 0); ++ if (!sd) ++ return AVERROR(ENOMEM); ++ fallback = (int*)sd->data; ++ *fallback = j; ++ break; ++ } ++ } ++ } + break; + case AVMEDIA_TYPE_VIDEO: + if (sc->display_matrix) { +diff -Naur ffmpeg-7.1.1.old/libavformat/movenc.c ffmpeg-7.1.1/libavformat/movenc.c +--- ffmpeg-7.1.1.old/libavformat/movenc.c 2025-03-24 10:54:38.381759365 +0100 ++++ ffmpeg-7.1.1/libavformat/movenc.c 2025-03-24 10:54:39.258769917 +0100 +@@ -28,6 +28,7 @@ + + #include "movenc.h" + #include "avformat.h" ++#include "avlanguage.h" + #include "avio_internal.h" + #include "dovi_isom.h" + #include "riff.h" +@@ -4055,6 +4056,41 @@ + return len + 24; + } + ++static uint16_t language_code(const char *str) ++{ ++ return (((str[0] - 0x60) & 0x1F) << 10) + ++ (((str[1] - 0x60) & 0x1F) << 5) + ++ (( str[2] - 0x60) & 0x1F); ++} ++static int mov_write_3gp_udta_tag(AVIOContext *pb, AVDictionary *metadata, ++ const char *tag, const char *str) ++{ ++ int64_t pos = avio_tell(pb); ++ AVDictionaryEntry *t = av_dict_get(metadata, str, NULL, 0); ++ if (!t || !utf8len(t->value)) ++ return 0; ++ avio_wb32(pb, 0); /* size */ ++ ffio_wfourcc(pb, tag); /* type */ ++ avio_wb32(pb, 0); /* version + flags */ ++ if (!strcmp(tag, "yrrc")) ++ avio_wb16(pb, atoi(t->value)); ++ else { ++ int lang = 0, len; ++ len = strlen(t->key); ++ if (t->key[len - 4] == '-') { ++ lang = ff_mov_iso639_to_lang(&t->key[len - 3], 1); ++ } ++ if (!lang) ++ lang = ff_mov_iso639_to_lang("und", 1); ++ avio_wb16(pb, lang); /* language */ ++ avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */ ++ if (!strcmp(tag, "albm") && ++ (t = av_dict_get(metadata, "track", NULL, 0))) ++ avio_w8(pb, atoi(t->value)); ++ } ++ return update_size(pb, pos); ++} ++ + static int mov_write_track_metadata(AVIOContext *pb, AVStream *st, + const char *tag, const char *str) + { +@@ -4129,8 +4165,23 @@ + if (ret < 0) + return ret; + +- if (mov->mode & (MODE_MP4|MODE_MOV)) ++ if (mov->mode & (MODE_MP4|MODE_MOV)) { ++ AVDictionaryEntry *t = NULL; ++ int und = 0; ++ + mov_write_track_metadata(pb_buf, st, "name", "title"); ++ while ((t = av_dict_get(st->metadata, "title-", t, AV_DICT_IGNORE_SUFFIX))) { ++ int len = strlen(t->key); ++ if (len == 10 && ++ ff_convert_lang_to(&t->key[len - 3], AV_LANG_ISO639_2_BIBL)) { ++ mov_write_3gp_udta_tag(pb_buf, st->metadata, "titl", t->key); ++ if (!strcmp("und", &t->key[len - 3])) ++ und = 1; ++ } ++ } ++ if (!und) ++ mov_write_3gp_udta_tag(pb_buf, st->metadata, "titl", "title"); ++ } + + if (mov->mode & MODE_MP4) { + if ((ret = mov_write_track_kinds(pb_buf, st)) < 0) +@@ -4727,35 +4778,6 @@ + return 0; + } + +-static uint16_t language_code(const char *str) +-{ +- return (((str[0] - 0x60) & 0x1F) << 10) + +- (((str[1] - 0x60) & 0x1F) << 5) + +- (( str[2] - 0x60) & 0x1F); +-} +- +-static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s, +- const char *tag, const char *str) +-{ +- int64_t pos = avio_tell(pb); +- AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0); +- if (!t || !utf8len(t->value)) +- return 0; +- avio_wb32(pb, 0); /* size */ +- ffio_wfourcc(pb, tag); /* type */ +- avio_wb32(pb, 0); /* version + flags */ +- if (!strcmp(tag, "yrrc")) +- avio_wb16(pb, atoi(t->value)); +- else { +- avio_wb16(pb, language_code("eng")); /* language */ +- avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */ +- if (!strcmp(tag, "albm") && +- (t = av_dict_get(s->metadata, "track", NULL, 0))) +- avio_w8(pb, atoi(t->value)); +- } +- return update_size(pb, pos); +-} +- + static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s) + { + int64_t pos = avio_tell(pb); +@@ -4794,14 +4816,14 @@ + return ret; + + if (mov->mode & MODE_3GP) { +- mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist"); +- mov_write_3gp_udta_tag(pb_buf, s, "titl", "title"); +- mov_write_3gp_udta_tag(pb_buf, s, "auth", "author"); +- mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre"); +- mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment"); +- mov_write_3gp_udta_tag(pb_buf, s, "albm", "album"); +- mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright"); +- mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "perf", "artist"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "titl", "title"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "auth", "author"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "gnre", "genre"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "dscp", "comment"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "albm", "album"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "cprt", "copyright"); ++ mov_write_3gp_udta_tag(pb_buf, s->metadata, "yrrc", "date"); + mov_write_loci_tag(s, pb_buf); + } else if (mov->mode == MODE_MOV && !(mov->flags & FF_MOV_FLAG_USE_MDTA)) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4 + mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0); +diff -Naur ffmpeg-7.1.1.old/libavutil/frame.c ffmpeg-7.1.1/libavutil/frame.c +--- ffmpeg-7.1.1.old/libavutil/frame.c 2025-03-24 10:54:38.298758366 +0100 ++++ ffmpeg-7.1.1/libavutil/frame.c 2025-03-24 10:54:39.274197994 +0100 +@@ -45,6 +45,7 @@ + [AV_FRAME_DATA_FILM_GRAIN_PARAMS] = { "Film grain parameters" }, + [AV_FRAME_DATA_DETECTION_BBOXES] = { "Bounding boxes for object detection and classification" }, + [AV_FRAME_DATA_DOVI_RPU_BUFFER] = { "Dolby Vision RPU Data" }, ++ [AV_FRAME_DATA_DOVI_RPU_BUFFER_T35] = { "Dolby Vision RPU ITU T35 Data" }, + [AV_FRAME_DATA_DOVI_METADATA] = { "Dolby Vision Metadata" }, + [AV_FRAME_DATA_LCEVC] = { "LCEVC NAL data" }, + [AV_FRAME_DATA_VIEW_ID] = { "View ID" }, +diff -Naur ffmpeg-7.1.1.old/libavutil/frame.h ffmpeg-7.1.1/libavutil/frame.h +--- ffmpeg-7.1.1.old/libavutil/frame.h 2025-03-24 10:54:38.287758234 +0100 ++++ ffmpeg-7.1.1/libavutil/frame.h 2025-03-24 10:54:39.274296419 +0100 +@@ -201,6 +201,12 @@ + AV_FRAME_DATA_DOVI_RPU_BUFFER, + + /** ++ * Dolby Vision RPU ITU T35 raw data, suitable for passing to SVT-AV1 ++ * or other libraries. Array of uint8_t. ++ */ ++ AV_FRAME_DATA_DOVI_RPU_BUFFER_T35, ++ ++ /** + * Parsed Dolby Vision metadata, suitable for passing to a software + * implementation. The payload is the AVDOVIMetadata struct defined in + * libavutil/dovi_meta.h. +diff -Naur ffmpeg-7.1.1.old/libswscale/swscale_unscaled.c ffmpeg-7.1.1/libswscale/swscale_unscaled.c +--- ffmpeg-7.1.1.old/libswscale/swscale_unscaled.c 2025-03-24 10:54:38.201757199 +0100 ++++ ffmpeg-7.1.1/libswscale/swscale_unscaled.c 2025-03-24 10:54:39.272233834 +0100 +@@ -341,7 +341,7 @@ + const uint8_t *tsrc0 = src[0]; + for (x = c->srcW; x > 0; x--) { + t = *tsrc0++; +- output_pixel(tdstY++, t | (t << 8)); ++ output_pixel(tdstY++, (t << 8)); + } + src[0] += srcStride[0]; + dstY += dstStride[0] / 2; +@@ -352,9 +352,9 @@ + const uint8_t *tsrc2 = src[2]; + for (x = c->srcW / 2; x > 0; x--) { + t = *tsrc1++; +- output_pixel(tdstUV++, t | (t << 8)); ++ output_pixel(tdstUV++, (t << 8)); + t = *tsrc2++; +- output_pixel(tdstUV++, t | (t << 8)); ++ output_pixel(tdstUV++, (t << 8)); + } + src[1] += srcStride[1]; + src[2] += srcStride[2]; diff --git a/anda/multimedia/ffmpeg/ffmpeg-LCEVCdec-4.patch b/anda/multimedia/ffmpeg/ffmpeg-LCEVCdec-4.patch new file mode 100644 index 0000000000..ff266b17b2 --- /dev/null +++ b/anda/multimedia/ffmpeg/ffmpeg-LCEVCdec-4.patch @@ -0,0 +1,40 @@ +--- a/libavcodec/lcevcdec.c ++++ b/libavcodec/lcevcdec.c +@@ -139,7 +139,7 @@ static int lcevc_send_frame(void *logctx + if (!sd) + return 1; + +- res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size); ++ res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, (uint64_t) in->pts, sd->data, sd->size); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + +@@ -147,7 +147,7 @@ static int lcevc_send_frame(void *logctx + if (ret < 0) + return ret; + +- res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, NULL); ++ res = LCEVC_SendDecoderBase(lcevc->decoder, (uint64_t) in->pts, picture, -1, NULL); + if (res != LCEVC_Success) + return AVERROR_EXTERNAL; + +--- a/libavfilter/vf_lcevc.c ++++ b/libavfilter/vf_lcevc.c +@@ -139,7 +139,7 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in) + return ret; + + if (sd) { +- res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, in->pts, 0, sd->data, sd->size); ++ res = LCEVC_SendDecoderEnhancementData(lcevc->decoder, (uint64_t) in->pts, sd->data, sd->size); + if (res == LCEVC_Again) + return AVERROR(EAGAIN); + else if (res != LCEVC_Success) { +@@ -148,7 +148,7 @@ static int send_frame(AVFilterLink *inlink, AVFrame *in) + } + } + +- res = LCEVC_SendDecoderBase(lcevc->decoder, in->pts, 0, picture, -1, in); ++ res = LCEVC_SendDecoderBase(lcevc->decoder, (uint64_t) in->pts, picture, -1, in); + if (res != LCEVC_Success) { + av_log(ctx, AV_LOG_ERROR, "LCEVC_SendDecoderBase failed\n"); + LCEVC_FreePicture(lcevc->decoder, picture); diff --git a/anda/multimedia/ffmpeg/ffmpeg-chromium.patch b/anda/multimedia/ffmpeg/ffmpeg-chromium.patch index cf9b9c8d6f..2d9d364c30 100644 --- a/anda/multimedia/ffmpeg/ffmpeg-chromium.patch +++ b/anda/multimedia/ffmpeg/ffmpeg-chromium.patch @@ -28,3 +28,4 @@ diff -Naur ffmpeg-7.1.1.old/libavformat/utils.c ffmpeg-7.1.1/libavformat/utils.c + /* an arbitrarily chosen "sane" max packet size -- 50M */ #define SANE_CHUNK_SIZE (50000000) + diff --git a/anda/multimedia/ffmpeg/ffmpeg-svt-vp9.patch b/anda/multimedia/ffmpeg/ffmpeg-svt-vp9.patch index 2d163a4bf2..351c801512 100644 --- a/anda/multimedia/ffmpeg/ffmpeg-svt-vp9.patch +++ b/anda/multimedia/ffmpeg/ffmpeg-svt-vp9.patch @@ -1,8 +1,7 @@ -diff --git a/configure b/configure -index 727c3daea8..1da8f40bff 100755 ---- a/configure -+++ b/configure -@@ -278,6 +278,7 @@ External library support: +diff -Naur ffmpeg-7.1.1.old/configure ffmpeg-7.1.1/configure +--- ffmpeg-7.1.1.old/configure 2025-03-24 10:54:38.202757211 +0100 ++++ ffmpeg-7.1.1/configure 2025-03-24 10:54:38.618546808 +0100 +@@ -278,6 +278,7 @@ --enable-libsrt enable Haivision SRT protocol via libsrt [no] --enable-libssh enable SFTP protocol via libssh [no] --enable-libsvtav1 enable AV1 encoding via SVT [no] @@ -10,7 +9,7 @@ index 727c3daea8..1da8f40bff 100755 --enable-libtensorflow enable TensorFlow as a DNN module backend for DNN based filters like sr [no] --enable-libtesseract enable Tesseract, needed for ocr filter [no] -@@ -1973,6 +1974,7 @@ EXTERNAL_LIBRARY_LIST=" +@@ -1953,6 +1954,7 @@ libshaderc libshine libsmbclient @@ -18,7 +17,7 @@ index 727c3daea8..1da8f40bff 100755 libsnappy libsoxr libspeex -@@ -3658,6 +3660,7 @@ libvpx_vp8_decoder_deps="libvpx" +@@ -3575,6 +3577,7 @@ libvpx_vp8_encoder_deps="libvpx" libvpx_vp9_decoder_deps="libvpx" libvpx_vp9_encoder_deps="libvpx" @@ -26,31 +25,18 @@ index 727c3daea8..1da8f40bff 100755 libvvenc_encoder_deps="libvvenc" libwebp_encoder_deps="libwebp" libwebp_anim_encoder_deps="libwebp" -@@ -7160,6 +7163,7 @@ enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame - die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } - enabled libuavs3d && require_pkg_config libuavs3d "uavs3d >= 1.1.41" uavs3d.h uavs3d_decode - enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl +@@ -6997,6 +7000,7 @@ + enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init + enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket + enabled libsvtav1 && require_pkg_config libsvtav1 "SvtAv1Enc >= 0.9.0" EbSvtAv1Enc.h svt_av1_enc_init_handle +enabled libsvtvp9 && require_pkg_config libsvtvp9 SvtVp9Enc EbSvtVp9Enc.h eb_vp9_svt_init_handle - enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit - enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 2.0.0" libvmaf.h vmaf_init - enabled libvmaf && check_pkg_config libvmaf_cuda "libvmaf >= 2.0.0" libvmaf_cuda.h vmaf_cuda_state_init -diff --git a/libavcodec/Makefile b/libavcodec/Makefile -index 83ef92963a..d63ec14d84 100644 ---- a/libavcodec/Makefile -+++ b/libavcodec/Makefile -@@ -1191,6 +1191,7 @@ OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER) += libvo-amrwbenc.o - OBJS-$(CONFIG_LIBVORBIS_DECODER) += libvorbisdec.o - OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbisenc.o \ - vorbis_data.o -+OBJS-$(CONFIG_LIBSVT_VP9_ENCODER) += libsvt_vp9.o - OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o - OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o - OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o -diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c -index f5ec2e01e8..11928d7afa 100644 ---- a/libavcodec/allcodecs.c -+++ b/libavcodec/allcodecs.c -@@ -809,6 +809,7 @@ extern const FFCodec ff_libuavs3d_decoder; + enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow + enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate + enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg +diff -Naur ffmpeg-7.1.1.old/libavcodec/allcodecs.c ffmpeg-7.1.1/libavcodec/allcodecs.c +--- ffmpeg-7.1.1.old/libavcodec/allcodecs.c 2025-03-24 10:54:38.119756212 +0100 ++++ ffmpeg-7.1.1/libavcodec/allcodecs.c 2025-03-24 10:54:38.619934060 +0100 +@@ -796,6 +796,7 @@ extern const FFCodec ff_libvo_amrwbenc_encoder; extern const FFCodec ff_libvorbis_encoder; extern const FFCodec ff_libvorbis_decoder; @@ -58,11 +44,9 @@ index f5ec2e01e8..11928d7afa 100644 extern const FFCodec ff_libvpx_vp8_encoder; extern const FFCodec ff_libvpx_vp8_decoder; extern FFCodec ff_libvpx_vp9_encoder; -diff --git a/libavcodec/libsvt_vp9.c b/libavcodec/libsvt_vp9.c -new file mode 100644 -index 0000000000..90ed5cbff2 ---- /dev/null -+++ b/libavcodec/libsvt_vp9.c +diff -Naur ffmpeg-7.1.1.old/libavcodec/libsvt_vp9.c ffmpeg-7.1.1/libavcodec/libsvt_vp9.c +--- ffmpeg-7.1.1.old/libavcodec/libsvt_vp9.c 1970-01-01 01:00:00.000000000 +0100 ++++ ffmpeg-7.1.1/libavcodec/libsvt_vp9.c 2025-03-24 10:54:38.620176868 +0100 @@ -0,0 +1,701 @@ +/* +* Scalable Video Technology for VP9 encoder library plugin @@ -276,11 +260,11 @@ index 0000000000..90ed5cbff2 + param->intra_period = avctx->gop_size - 1; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { -+ param->frame_rate_numerator = avctx->framerate.num; -+ param->frame_rate_denominator = avctx->framerate.den; ++ param->frame_rate_numerator = avctx->framerate.num; ++ param->frame_rate_denominator = avctx->framerate.den * avctx->ticks_per_frame; + } else { -+ param->frame_rate_numerator = avctx->time_base.den; -+ param->frame_rate_denominator = avctx->time_base.num; ++ param->frame_rate_numerator = avctx->time_base.den; ++ param->frame_rate_denominator = avctx->time_base.num * avctx->ticks_per_frame; + } + + if (param->rate_control_mode) { @@ -765,6 +749,14 @@ index 0000000000..90ed5cbff2 + .defaults = eb_enc_defaults, + .p.wrapper_name = "libsvt_vp9", +}; --- -2.50.1 - +diff -Naur ffmpeg-7.1.1.old/libavcodec/Makefile ffmpeg-7.1.1/libavcodec/Makefile +--- ffmpeg-7.1.1.old/libavcodec/Makefile 2025-03-24 10:54:37.935753999 +0100 ++++ ffmpeg-7.1.1/libavcodec/Makefile 2025-03-24 10:54:38.620394147 +0100 +@@ -1157,6 +1157,7 @@ + OBJS-$(CONFIG_LIBVORBIS_DECODER) += libvorbisdec.o + OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbisenc.o \ + vorbis_data.o ++OBJS-$(CONFIG_LIBSVT_VP9_ENCODER) += libsvt_vp9.o + OBJS-$(CONFIG_LIBVPX_VP8_DECODER) += libvpxdec.o + OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o + OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o diff --git a/anda/multimedia/ffmpeg/ffmpeg.spec b/anda/multimedia/ffmpeg/ffmpeg.spec index eadbb13e93..5a0978bd56 100644 --- a/anda/multimedia/ffmpeg/ffmpeg.spec +++ b/anda/multimedia/ffmpeg/ffmpeg.spec @@ -1,18 +1,19 @@ %global _lto_cflags %{nil} -%global avcodec_soversion 62 -%global avdevice_soversion 62 -%global avfilter_soversion 11 -%global avformat_soversion 62 -%global avutil_soversion 60 -%global swresample_soversion 6 -%global swscale_soversion 9 +%global avcodec_soversion 61 +%global avdevice_soversion 61 +%global avfilter_soversion 10 +%global avformat_soversion 61 +%global avutil_soversion 59 +%global postproc_soversion 58 +%global swresample_soversion 5 +%global swscale_soversion 8 Summary: A complete solution to record, convert and stream audio and video Name: ffmpeg Version: 7.1.1 -Release: 3%?dist -License: LGPL-3.0-or-later +Release: 16%?dist +License: LGPLv3+ URL: http://%{name}.org/ Epoch: 1 @@ -20,13 +21,15 @@ Source0: http://%{name}.org/releases/%{name}-%{version}.tar.xz # https://github.com/OpenVisualCloud/SVT-VP9/tree/master/ffmpeg_plugin Patch0: %{name}-svt-vp9.patch +# https://github.com/HandBrake/HandBrake/tree/e117cfe7fca37abeec59ea4201e5d93ed7477746 +Patch2: %{name}-HandBrake.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2240127 # Reference: https://crbug.com/1306560 Patch3: %{name}-chromium.patch -# Fix build with recent NVCC: -Patch4: %{name}-nvcc.patch +# Support LCEVCdec 4.0+: +Patch5: https://aur.archlinux.org/cgit/aur.git/plain/080-ffmpeg-lcevcdec4.0.0-fix.patch?h=ffmpeg-full#/%{name}-LCEVCdec-4.patch -BuildRequires: AMF-devel +BuildRequires: AMF-devel >= 1.4.28 BuildRequires: bzip2-devel BuildRequires: codec2-devel BuildRequires: doxygen @@ -34,9 +37,8 @@ BuildRequires: frei0r-devel BuildRequires: gmp-devel BuildRequires: gsm-devel BuildRequires: ilbc-devel -BuildRequires: lame-devel +BuildRequires: lame-devel >= 3.98.3 BuildRequires: ladspa-devel -BuildRequires: LCEVCdec-devel >= 4.0.0 BuildRequires: libavc1394-devel BuildRequires: libchromaprint-devel BuildRequires: libgcrypt-devel @@ -55,60 +57,62 @@ BuildRequires: snappy-devel BuildRequires: soxr-devel BuildRequires: subversion BuildRequires: texinfo -BuildRequires: twolame-devel +BuildRequires: twolame-devel >= 0.3.10 BuildRequires: vo-amrwbenc-devel BuildRequires: xvidcore-devel BuildRequires: xz-devel BuildRequires: pkgconfig(alsa) -BuildRequires: pkgconfig(aom) -BuildRequires: pkgconfig(aribb24) +BuildRequires: pkgconfig(aom) >= 1.0.0 +BuildRequires: pkgconfig(aribb24) >= 1.0.3 BuildRequires: pkgconfig(caca) -BuildRequires: pkgconfig(dav1d) -BuildRequires: pkgconfig(davs2) -BuildRequires: pkgconfig(dvdnav) +BuildRequires: pkgconfig(dav1d) >= 0.5.0 +BuildRequires: pkgconfig(davs2) >= 1.6.0 +BuildRequires: pkgconfig(dvdnav) >= 6.1.1 BuildRequires: pkgconfig(fdk-aac) +BuildRequires: pkgconfig(ffnvcodec) >= 12.0.16.0 BuildRequires: pkgconfig(fontconfig) BuildRequires: pkgconfig(freetype2) BuildRequires: pkgconfig(fribidi) BuildRequires: pkgconfig(harfbuzz) BuildRequires: pkgconfig(jack) -BuildRequires: pkgconfig(kvazaar) -BuildRequires: pkgconfig(lc3) -BuildRequires: pkgconfig(lcms2) -BuildRequires: pkgconfig(libaribcaption) -BuildRequires: pkgconfig(libass) +BuildRequires: pkgconfig(kvazaar) >= 0.8.1 +BuildRequires: pkgconfig(lc3) >= 1.1.0 +BuildRequires: pkgconfig(lcms2) >= 2.13 +BuildRequires: pkgconfig(lcevc_dec) >= 2.0.0 +BuildRequires: pkgconfig(libaribcaption) >= 1.1.1 +BuildRequires: pkgconfig(libass) >= 0.11.0 BuildRequires: pkgconfig(libbluray) BuildRequires: pkgconfig(libbs2b) BuildRequires: pkgconfig(libcdio_paranoia) BuildRequires: pkgconfig(libdc1394-2) BuildRequires: pkgconfig(libdrm) BuildRequires: pkgconfig(libgme) -BuildRequires: pkgconfig(libjxl) -#BuildRequires: pkgconfig(lensfun) +BuildRequires: pkgconfig(libjxl) >= 0.7.0 +#BuildRequires: pkgconfig(lensfun) > 0.3.95 BuildRequires: pkgconfig(libmodplug) BuildRequires: pkgconfig(libmysofa) -BuildRequires: pkgconfig(libopenjp2) -BuildRequires: pkgconfig(libopenmpt) -#BuildRequires: pkgconfig(libplacebo) >= 7.351.0 +BuildRequires: pkgconfig(libopenjp2) >= 2.1.0 +BuildRequires: pkgconfig(libopenmpt) >= 0.2.6557 +BuildRequires: pkgconfig(libplacebo) >= 4.192.0 BuildRequires: pkgconfig(libpulse) BuildRequires: pkgconfig(libqrencode) #BuildRequires: pkgconfig(libquirc) -BuildRequires: pkgconfig(librabbitmq) -BuildRequires: pkgconfig(librist) +BuildRequires: pkgconfig(librabbitmq) >= 0.7.1 +BuildRequires: pkgconfig(librist) >= 0.2.7 BuildRequires: pkgconfig(librtmp) BuildRequires: pkgconfig(librsvg-2.0) BuildRequires: pkgconfig(libssh) BuildRequires: pkgconfig(libtcmalloc) -BuildRequires: pkgconfig(libva) +BuildRequires: pkgconfig(libva) >= 0.35.0 BuildRequires: pkgconfig(libva-drm) BuildRequires: pkgconfig(libva-x11) BuildRequires: pkgconfig(libv4l2) -BuildRequires: pkgconfig(libvvenc) +BuildRequires: pkgconfig(libvvenc) >= 1.11.0 BuildRequires: pkgconfig(libwebp) -BuildRequires: pkgconfig(libwebpmux) +BuildRequires: pkgconfig(libwebpmux) >= 0.4.0 BuildRequires: pkgconfig(libxml-2.0) -BuildRequires: pkgconfig(libzmq) +BuildRequires: pkgconfig(libzmq) >= 4.2.1 BuildRequires: pkgconfig(lilv-0) BuildRequires: pkgconfig(lv2) #BuildRequires: pkgconfig(OpenCL) @@ -116,24 +120,24 @@ BuildRequires: pkgconfig(lv2) BuildRequires: pkgconfig(openh264) BuildRequires: pkgconfig(openssl) BuildRequires: pkgconfig(opus) -BuildRequires: pkgconfig(rav1e) -BuildRequires: pkgconfig(rubberband) +BuildRequires: pkgconfig(rav1e) >= 0.4.0 +BuildRequires: pkgconfig(rubberband) >= 1.8.1 BuildRequires: pkgconfig(sdl2) -BuildRequires: pkgconfig(shaderc) +BuildRequires: pkgconfig(shaderc) >= 2019.1 #BuildRequires: pkgconfig(shine) BuildRequires: pkgconfig(smbclient) BuildRequires: pkgconfig(speex) -BuildRequires: pkgconfig(srt) +BuildRequires: pkgconfig(srt) >= 1.3.0 BuildRequires: pkgconfig(tesseract) -BuildRequires: pkgconfig(uavs3d) -BuildRequires: pkgconfig(vapoursynth-script) -BuildRequires: pkgconfig(vidstab) +BuildRequires: pkgconfig(uavs3d) >= 1.1.41 +BuildRequires: pkgconfig(vapoursynth-script) >= 42 +BuildRequires: pkgconfig(vidstab) >= 0.98 BuildRequires: pkgconfig(vorbis) BuildRequires: pkgconfig(vorbisenc) -BuildRequires: pkgconfig(vpx) -BuildRequires: pkgconfig(vulkan) -BuildRequires: pkgconfig(xavs2) -BuildRequires: pkgconfig(xcb) +BuildRequires: pkgconfig(vpx) >= 1.4.0 +BuildRequires: pkgconfig(vulkan) >= 1.3.277 +BuildRequires: pkgconfig(xavs2) >= 1.3.0 +BuildRequires: pkgconfig(xcb) >= 1.4 BuildRequires: pkgconfig(xcb-shape) BuildRequires: pkgconfig(xcb-shm) BuildRequires: pkgconfig(xcb-xfixes) @@ -142,29 +146,24 @@ BuildRequires: pkgconfig(x11) BuildRequires: pkgconfig(x264) BuildRequires: pkgconfig(x265) BuildRequires: pkgconfig(xv) -BuildRequires: pkgconfig(zimg) +BuildRequires: pkgconfig(zimg) >= 2.7.0 BuildRequires: pkgconfig(zlib) -BuildRequires: pkgconfig(zvbi-0.2) +BuildRequires: pkgconfig(zvbi-0.2) >= 0.2.28 %ifarch x86_64 aarch64 -# Nvidia CUVID support and Performance Primitives based code -BuildRequires: cuda-cudart-devel -BuildRequires: cuda-nvcc -BuildRequires: libnpp-devel BuildRequires: pkgconfig(ffnvcodec) >= 12.0.16.0 %endif %ifarch x86_64 BuildRequires: pkgconfig(libmfx) -BuildRequires: pkgconfig(libvmaf) -BuildRequires: pkgconfig(SvtAv1Enc) +BuildRequires: pkgconfig(libvmaf) >= 2.0.0 +BuildRequires: pkgconfig(SvtAv1Enc) >= 0.9.0 BuildRequires: pkgconfig(SvtVp9Enc) -BuildRequires: pkgconfig(vpl) -#BuildRequires: pkgconfig(xevd) -#BuildRequires: pkgconfig(xeve) +BuildRequires: pkgconfig(vpl) >= 2.6 +#BuildRequires: pkgconfig(xevd) >= 0.4.1 +#BuildRequires: pkgconfig(xeve) >= 0.4.3 %endif -Obsoletes: %{name} < %{epoch}:%{version}-%{release} Obsoletes: %{name}-free < %{epoch}:%{version}-%{release} Provides: %{name}-free = %{epoch}:%{version}-%{release} @@ -181,11 +180,9 @@ Requires: libavdevice%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavfilter%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavformat%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavutil%{?_isa} = %{epoch}:%{version}-%{release} +Requires: libpostproc%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswresample%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswscale%{?_isa} = %{epoch}:%{version}-%{release} -Obsoletes: libpostproc-free < %{epoch}:%{version}-%{release} -Obsoletes: libpostproc < %{epoch}:%{version}-%{release} -Obsoletes: %{name}-libs < %{epoch}:%{version}-%{release} %description libs FFmpeg is a complete and free Internet live audio and video @@ -198,9 +195,6 @@ This metapackage pulls in all the %{name} libraries. Summary: Metapackage for %{name} development files Requires: %{name}-libs%{?_isa} = %{epoch}:%{version}-%{release} Requires: pkgconfig -Obsoletes: %{name}-devel < %{epoch}:%{version}-%{release} -Obsoletes: %{name}-free-devel < %{epoch}:%{version}-%{release} -Provides: %{name}-free-devel = %{epoch}:%{version}-%{release} %description devel FFmpeg is a complete and free Internet live audio and video broadcasting @@ -209,7 +203,6 @@ time in many formats. This package contains development files for %{name}. %package -n libavcodec Summary: FFmpeg codec library -Obsoletes: libavcodec < %{epoch}:%{version}-%{release} Obsoletes: libavcodec-free < %{epoch}:%{version}-%{release} Provides: libavcodec-free = %{epoch}:%{version}-%{release} @@ -223,7 +216,6 @@ Summary: Development files for FFmpeg's codec library Requires: libavcodec%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavutil-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: pkgconfig -Obsoletes: libavcodec-devel < %{epoch}:%{version}-%{release} Obsoletes: libavcodec-free-devel < %{epoch}:%{version}-%{release} Provides: libavcodec-free-devel = %{epoch}:%{version}-%{release} @@ -236,7 +228,6 @@ This subpackage contains the headers for FFmpeg libavcodec. %package -n libavdevice Summary: FFMpeg devices muxing/demuxing library -Obsoletes: libavdevice < %{epoch}:%{version}-%{release} Obsoletes: libavdevice-free < %{epoch}:%{version}-%{release} Provides: libavdevice-free = %{epoch}:%{version}-%{release} @@ -253,7 +244,6 @@ Requires: libavfilter-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavformat-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavutil-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: pkgconfig -Obsoletes: libavdevice-devel < %{epoch}:%{version}-%{release} Obsoletes: libavdevice-free-devel < %{epoch}:%{version}-%{release} Provides: libavdevice-free-devel = %{epoch}:%{version}-%{release} @@ -265,9 +255,9 @@ Summary: FFmpeg audio and video filtering library Requires: libavcodec%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavformat%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavutil%{?_isa} = %{epoch}:%{version}-%{release} +Requires: libpostproc%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswresample%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswscale%{?_isa} = %{epoch}:%{version}-%{release} -Obsoletes: libavfilter < %{epoch}:%{version}-%{release} Obsoletes: libavfilter-free < %{epoch}:%{version}-%{release} Provides: libavfilter-free = %{epoch}:%{version}-%{release} @@ -281,10 +271,10 @@ Requires: libavcodec-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavfilter%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavformat-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavutil-devel%{?_isa} = %{epoch}:%{version}-%{release} +Requires: libpostproc-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswresample-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswscale-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: pkgconfig -Obsoletes: libavfilter-devel < %{epoch}:%{version}-%{release} Obsoletes: libavfilter-free-devel < %{epoch}:%{version}-%{release} Provides: libavfilter-free-devel = %{epoch}:%{version}-%{release} @@ -293,7 +283,6 @@ This subpackage contains the headers for FFmpeg libavfilter. %package -n libavformat Summary: FFmpeg's stream format library -Obsoletes: libavformat < %{epoch}:%{version}-%{release} Obsoletes: libavformat-free < %{epoch}:%{version}-%{release} Provides: libavformat-free = %{epoch}:%{version}-%{release} @@ -309,7 +298,6 @@ Requires: libavformat%{?_isa} = %{epoch}:%{version}-%{release} Requires: libavutil-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswresample-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: pkgconfig -Obsoletes: libavformat-devel < %{epoch}:%{version}-%{release} Obsoletes: libavformat-free-devel < %{epoch}:%{version}-%{release} Provides: libavformat-free-devel = %{epoch}:%{version}-%{release} @@ -318,7 +306,6 @@ This subpackage contains the headers for FFmpeg libavformat. %package -n libavutil Summary: FFmpeg's utility library -Obsoletes: libavutil < %{epoch}:%{version}-%{release} Obsoletes: libavutil-free < %{epoch}:%{version}-%{release} Provides: libavutil-free = %{epoch}:%{version}-%{release} @@ -333,17 +320,38 @@ for pixel and sample formats). Summary: Development files for FFmpeg's utility library Requires: libavutil%{?_isa} = %{epoch}:%{version}-%{release} Requires: pkgconfig -Obsoletes: libavutil-devel < %{epoch}:%{version}-%{release} Obsoletes: libavutil-free-devel < %{epoch}:%{version}-%{release} Provides: libavutil-free-devel = %{epoch}:%{version}-%{release} %description -n libavutil-devel This subpackage contains the headers for FFmpeg libavutil. +%package -n libpostproc +Summary: FFmpeg post-processing library +Obsoletes: libpostproc-free < %{epoch}:%{version}-%{release} +Provides: libpostproc-free = %{epoch}:%{version}-%{release} + +%description -n libpostproc +A library with video postprocessing filters, such as deblocking and +deringing filters, noise reduction, automatic contrast and brightness +correction, linear/cubic interpolating deinterlacing. + +%package -n libpostproc-devel +Summary: Development files for the FFmpeg post-processing library +Requires: libavutil-devel%{?_isa} = %{epoch}:%{version}-%{release} +Requires: libpostproc%{?_isa} = %{epoch}:%{version}-%{release} +Requires: pkgconfig +Obsoletes: libpostproc-free-devel < %{epoch}:%{version}-%{release} +Provides: libpostproc-free-devel = %{epoch}:%{version}-%{release} + +%description -n libpostproc-devel +This subpackage contains the headers for FFmpeg libpostproc. + %package -n libswresample Summary: FFmpeg software resampling library Requires: libavutil%{?_isa} = %{epoch}:%{version}-%{release} Obsoletes: libavresemple < %{epoch}:%{version}-%{release} +Provides: libavresemple = %{epoch}:%{version}-%{release} Obsoletes: libswresample-free < %{epoch}:%{version}-%{release} Provides: libswresample-free = %{epoch}:%{version}-%{release} @@ -356,6 +364,7 @@ Summary: Development files for the FFmpeg software resampling library Requires: libavutil-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswresample%{?_isa} = %{epoch}:%{version}-%{release} Obsoletes: libavresemple-devel < %{epoch}:%{version}-%{release} +Provides: libavresemple-devel = %{epoch}:%{version}-%{release} Obsoletes: libswresample-free-devel < %{epoch}:%{version}-%{release} Provides: libswresample-free-devel = %{epoch}:%{version}-%{release} @@ -364,7 +373,6 @@ This subpackage contains the headers for FFmpeg libswresample. %package -n libswscale Summary: FFmpeg image scaling and colorspace/pixel conversion library -Obsoletes: libswscale < %{epoch}:%{version}-%{release} Obsoletes: libswscale-free < %{epoch}:%{version}-%{release} Provides: libswscale-free = %{epoch}:%{version}-%{release} @@ -376,7 +384,6 @@ pixel format conversion operations. Summary: Development files for FFmpeg's image scaling and colorspace library Requires: libavutil-devel%{?_isa} = %{epoch}:%{version}-%{release} Requires: libswscale%{?_isa} = %{epoch}:%{version}-%{release} -Obsoletes: libswscale-devel < %{epoch}:%{version}-%{release} Obsoletes: libswscale-free-devel < %{epoch}:%{version}-%{release} Provides: libswscale-free-devel = %{epoch}:%{version}-%{release} @@ -390,12 +397,6 @@ This subpackage contains the headers for FFmpeg libswscale. #sed -i -e 's|#!/bin/sh|#!/bin/sh -x|g' configure %build -# Work around a new GCC15 change until FFmpeg updates for it -%if 0%{?fedora} >= 42 -%if "%{version}" <= "7.1.1" -export CFLAGS="%{optflags} -Wno-incompatible-pointer-types" -%endif -%endif %set_build_flags ./configure \ @@ -412,6 +413,7 @@ export CFLAGS="%{optflags} -Wno-incompatible-pointer-types" --enable-alsa \ --enable-bzlib \ --enable-chromaprint \ + --disable-cuda-nvcc \ --enable-frei0r \ --enable-gcrypt \ --enable-gmp \ @@ -455,6 +457,7 @@ export CFLAGS="%{optflags} -Wno-incompatible-pointer-types" --enable-libmodplug \ --enable-libmp3lame \ --enable-libmysofa \ + --disable-libnpp \ --enable-libopencore-amrnb \ --enable-libopencore-amrwb \ --disable-libopencv \ @@ -462,7 +465,7 @@ export CFLAGS="%{optflags} -Wno-incompatible-pointer-types" --enable-libopenjpeg \ --enable-libopenmpt \ --enable-libopus \ - --disable-libplacebo \ + --enable-libplacebo \ --enable-libpulse \ --enable-libqrencode \ --disable-libquirc \ @@ -514,6 +517,7 @@ export CFLAGS="%{optflags} -Wno-incompatible-pointer-types" --enable-opencl \ --enable-opengl \ --enable-openssl \ + --enable-postproc \ --enable-sdl2 \ --enable-shared \ --enable-swresample \ @@ -534,10 +538,8 @@ export CFLAGS="%{optflags} -Wno-incompatible-pointer-types" --prefix=%{_prefix} \ --shlibdir=%{_libdir} \ %ifarch x86_64 aarch64 - --enable-cuda-nvcc \ --enable-cuvid \ --enable-ffnvcodec \ - --enable-libnpp \ --enable-nvdec \ --enable-nvenc \ --extra-cflags="-I%{_includedir}/cuda" \ @@ -630,6 +632,15 @@ mv doc/*.html doc/html %{_libdir}/libavutil.so %{_mandir}/man3/libavutil.3* +%files -n libpostproc +%license COPYING.GPLv2 LICENSE.md +%{_libdir}/libpostproc.so.%{postproc_soversion}* + +%files -n libpostproc-devel +%{_includedir}/libpostproc +%{_libdir}/pkgconfig/libpostproc.pc +%{_libdir}/libpostproc.so + %files -n libswresample %license COPYING.GPLv2 LICENSE.md %{_libdir}/libswresample.so.%{swresample_soversion}* diff --git a/anda/multimedia/ffmpeg/update.rhai b/anda/multimedia/ffmpeg/update.rhai index c7c838cb2d..abe27e5dfd 100644 --- a/anda/multimedia/ffmpeg/update.rhai +++ b/anda/multimedia/ffmpeg/update.rhai @@ -1,11 +1,14 @@ import "andax/bump_extras.rhai" as bump; import "andax/spec.rhai" as spec; -rpm.version(find(`ffmpeg-([\d.]+?)\.tar\.xz`, get("https://ffmpeg.org/download.html"), 1)); +// rpm.version(find(`ffmpeg-([\d.]+?)\.tar\.xz`, get("https://ffmpeg.org/download.html"), 1)); +rpm.version(bump::bodhi("ffmpeg", bump::as_bodhi_ver(labels.branch))); open_file("anda/multimedia/ffmpeg/VERSION_x265.txt", "w").write(bump::madoguchi("x265", labels.branch)); open_file("anda/multimedia/ffmpeg/VERSION_tesseract.txt", "w").write(bump::bodhi("tesseract", bump::as_bodhi_ver(labels.branch))); open_file("anda/multimedia/ffmpeg/VERSION_vvenc.txt", "w").write(bump::madoguchi("vvenc-libs", labels.branch)); +// open_file("anda/multimedia/ffmpeg/VERSION_libnpp.txt", "w").write(bump::madoguchi("libnpp", labels.branch)); +open_file("anda/multimedia/ffmpeg/VERSION_LCEVCdec.txt", "w").write(bump::madoguchi("LCEVCdec", labels.branch)); let dir = sub(`/[^/]+$`, "", __script_path); if sh("[[ `git status " + dir + " --porcelain` ]] && exit 1 || exit 0", #{}).ctx.rc == 1 { diff --git a/anda/multimedia/gstreamer1/gstreamer1-plugin-libav/gstreamer1-plugin-libav.spec b/anda/multimedia/gstreamer1/gstreamer1-plugin-libav/gstreamer1-plugin-libav.spec index ce6a4e2ae7..eb1beafa03 100644 --- a/anda/multimedia/gstreamer1/gstreamer1-plugin-libav/gstreamer1-plugin-libav.spec +++ b/anda/multimedia/gstreamer1/gstreamer1-plugin-libav/gstreamer1-plugin-libav.spec @@ -1,8 +1,9 @@ Name: gstreamer1-plugin-libav -Version: 1.24.11 +Version: 1.26.5 Release: 1%?dist +Epoch: 1 Summary: GStreamer Libav plugin -License: LGPLv2+ +License: LGPL-2.0-or-later URL: https://gstreamer.freedesktop.org/modules/gst-libav.html Source0: https://gstreamer.freedesktop.org/src/gst-libav/gst-libav-%{version}.tar.xz @@ -34,9 +35,10 @@ GStreamer plugin containing libav library code. %autosetup -p1 -n gst-libav-%{version} %build +#export CFLAGS="%{optflags} -Wno-error=attributes" %meson \ -D package-name="Fedora GStreamer-plugins-ugly package" \ - -D package-origin="https://gstreamer.freedesktop.org" \ + -D package-origin="https://terra.fyralabs.com" \ -D doc=disabled %meson_build diff --git a/anda/multimedia/gstreamer1/gstreamer1-plugins-bad/gstreamer1-plugins-bad.spec b/anda/multimedia/gstreamer1/gstreamer1-plugins-bad/gstreamer1-plugins-bad.spec index 797a7af811..193e71008d 100644 --- a/anda/multimedia/gstreamer1/gstreamer1-plugins-bad/gstreamer1-plugins-bad.spec +++ b/anda/multimedia/gstreamer1/gstreamer1-plugins-bad/gstreamer1-plugins-bad.spec @@ -3,8 +3,8 @@ %global majorminor 1.0 Name: gstreamer1-plugins-bad -Version: 1.26.1 -Release: 5%?dist +Version: 1.26.5 +Release: 1%?dist Epoch: 2 Summary: GStreamer streaming media framework "bad" plugins License: LGPL-2.0-or-later and LGPL-2.0-only @@ -252,7 +252,7 @@ Provides: %{name}-free-devel = %{?epoch}:%{version}-%{release} Provides: %{name}-free-devel%{?_isa} = %{?epoch}:%{version}-%{release} %description devel -%summary. +%summary. %prep %autosetup -p1 -n gst-plugins-bad-%{version} diff --git a/anda/multimedia/gstreamer1/gstreamer1-plugins-ugly/gstreamer1-plugins-ugly.spec b/anda/multimedia/gstreamer1/gstreamer1-plugins-ugly/gstreamer1-plugins-ugly.spec index 7218b83c9a..031b13bb72 100644 --- a/anda/multimedia/gstreamer1/gstreamer1-plugins-ugly/gstreamer1-plugins-ugly.spec +++ b/anda/multimedia/gstreamer1/gstreamer1-plugins-ugly/gstreamer1-plugins-ugly.spec @@ -1,10 +1,11 @@ %global majorminor 1.0 Name: gstreamer1-plugins-ugly -Version: 1.24.11 +Version: 1.26.5 Release: 1%?dist +Epoch: 1 Summary: GStreamer streaming media framework "ugly" plugins -License: LGPLv2+ and LGPLv2 +License: LGPL-2.0-or-later and LGPL-2.0-only URL: http://gstreamer.freedesktop.org/ Source0: http://gstreamer.freedesktop.org/src/gst-plugins-ugly/gst-plugins-ugly-%{version}.tar.xz @@ -39,7 +40,7 @@ This module contains a set of plugins that have good quality and are well tested %build %meson \ -D package-name="Fedora GStreamer-plugins-ugly package" \ - -D package-origin="http://gstreamer.freedesktop.org" \ + -D package-origin="https://terra.fyralabs.com" \ -D a52dec=enabled \ -D asfdemux=enabled \ -D cdio=enabled \ diff --git a/anda/multimedia/gstreamer1/gstreamer1-vaapi/PLUGINS_BAD_release.txt b/anda/multimedia/gstreamer1/gstreamer1-vaapi/PLUGINS_BAD_release.txt index 1204199104..8213d34942 100644 --- a/anda/multimedia/gstreamer1/gstreamer1-vaapi/PLUGINS_BAD_release.txt +++ b/anda/multimedia/gstreamer1/gstreamer1-vaapi/PLUGINS_BAD_release.txt @@ -1 +1 @@ -2.fcrawhide +1.fcrawhide diff --git a/anda/multimedia/gstreamer1/gstreamer1-vaapi/gstreamer1-vaapi.spec b/anda/multimedia/gstreamer1/gstreamer1-vaapi/gstreamer1-vaapi.spec index c42585c109..d36a5078ff 100644 --- a/anda/multimedia/gstreamer1/gstreamer1-vaapi/gstreamer1-vaapi.spec +++ b/anda/multimedia/gstreamer1/gstreamer1-vaapi/gstreamer1-vaapi.spec @@ -1,6 +1,6 @@ Name: gstreamer1-plugin-vaapi -Version: 1.26.0 -Release: 1%{?dist} +Version: 1.26.5 +Release: 1%?dist Epoch: 1 Summary: GStreamer VA-API integration License: LGPLv2+ diff --git a/anda/multimedia/rtaudio/rtaudio-nightly.spec b/anda/multimedia/rtaudio/rtaudio-nightly.spec index a9b3766782..9dbbaa7e90 100644 --- a/anda/multimedia/rtaudio/rtaudio-nightly.spec +++ b/anda/multimedia/rtaudio/rtaudio-nightly.spec @@ -1,8 +1,8 @@ #? https://src.fedoraproject.org/rpms/rtaudio/blob/db1aa72863ccbfd480e22c2f7aefb41ebb8e2360/f/rtaudio.spec -%global commit 40e0d8140f14acd8552d2dc4f42dcc853274a12c +%global commit acec45bb17425b0bfbc9972ead29d2b0c22c0c93 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250430 -%global ver 6.0.1 +%global commit_date 20250909 +%global ver .0.1 Name: rtaudio-nightly Version: %{ver}^%{commit_date}.git.%{shortcommit} diff --git a/anda/system/ipu6-camera-hal/ipu6-camera-hal.spec b/anda/system/ipu6-camera-hal/ipu6-camera-hal.spec index 1e58b347e9..08b3902c55 100644 --- a/anda/system/ipu6-camera-hal/ipu6-camera-hal.spec +++ b/anda/system/ipu6-camera-hal/ipu6-camera-hal.spec @@ -1,5 +1,5 @@ -%global commit c7a6beca177e67983f826bfad2b8875adef000ae -%global commit_date 20250521 +%global commit c933525a6efe8229a7129b7b0b66798f19d2bef7 +%global commit_date 20250627 %global shortcommit %(c=%{commit}; echo ${c:0:7}) %global build_cflags %{__build_flags_lang_c} %{?_distro_extra_cflags} -Wno-alloc-size-larger-than %global build_cxxflags %{__build_flags_lang_cxx} %{?_distro_extra_cxxflags} -Wno-alloc-size-larger-than diff --git a/anda/system/ipu6-drivers/akmod/intel-ipu6-kmod.spec b/anda/system/ipu6-drivers/akmod/intel-ipu6-kmod.spec index 965170668b..4613d0fed3 100644 --- a/anda/system/ipu6-drivers/akmod/intel-ipu6-kmod.spec +++ b/anda/system/ipu6-drivers/akmod/intel-ipu6-kmod.spec @@ -1,8 +1,8 @@ %global buildforkernels akmod %global debug_package %{nil} -%global commit e89983c628d046b2f77af3b6678cc49c2dd58332 +%global commit 69b2fde9edcbc24128b91541fdf2791fbd4bf7a4 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250521 +%global commit_date 20250917 %global modulename intel-ipu6 # Actual "release" version, currently unused as the release versions are back and forth on if on if they use 1.0.0 or 1.0.1 %global ver 1.0.1 @@ -10,7 +10,7 @@ Name: %{modulename}-kmod Summary: Akmods module for %{modulename} Version: 0^%{commit_date}git.%{shortcommit} -Release: 2%?dist +Release: 1%?dist License: GPL-2.0-or-later URL: https://github.com/intel/ipu6-drivers Source0: https://github.com/intel/ipu6-drivers/archive/%{commit}/ipu6-drivers-%{shortcommit}.tar.gz diff --git a/anda/system/ipu6-drivers/dkms/dkms-intel-ipu6.spec b/anda/system/ipu6-drivers/dkms/dkms-intel-ipu6.spec index ca75138662..e32b6e7469 100644 --- a/anda/system/ipu6-drivers/dkms/dkms-intel-ipu6.spec +++ b/anda/system/ipu6-drivers/dkms/dkms-intel-ipu6.spec @@ -1,7 +1,7 @@ %global debug_package %{nil} -%global commit e89983c628d046b2f77af3b6678cc49c2dd58332 +%global commit 69b2fde9edcbc24128b91541fdf2791fbd4bf7a4 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250521 +%global commit_date 20250917 %global modulename intel-ipu6 # Actual "release" version, currently unused as the release versions are back and forth on if on if they use 1.0.0 or 1.0.1 %global ver 1.0.1 @@ -9,7 +9,7 @@ Name: dkms-%{modulename} Summary: DKMS module for %{modulename} Version: 0^%{commit_date}git.%{shortcommit} -Release: 2%?dist +Release: 1%?dist License: GPL-2.0-or-later URL: https://github.com/intel/ipu6-drivers Source0: %{url}/archive/%{commit}.tar.gz#/ipu6-drivers-%{shortcommit}.tar.gz diff --git a/anda/system/ipu6-drivers/kmod-common/intel-ipu6-drivers.spec b/anda/system/ipu6-drivers/kmod-common/intel-ipu6-drivers.spec index 475652db64..22bb1a3c35 100644 --- a/anda/system/ipu6-drivers/kmod-common/intel-ipu6-drivers.spec +++ b/anda/system/ipu6-drivers/kmod-common/intel-ipu6-drivers.spec @@ -1,7 +1,7 @@ %global debug_package %{nil} -%global commit e89983c628d046b2f77af3b6678cc49c2dd58332 +%global commit 69b2fde9edcbc24128b91541fdf2791fbd4bf7a4 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250521 +%global commit_date 20250917 # Actual "release" version, currently unused as the release versions are back and forth on if on if they use 1.0.0 or 1.0.1 # Use this if they ever stop doing that I guess %global ver 1.0.1 @@ -9,7 +9,7 @@ Name: intel-ipu6-drivers Summary: Common files for Intel IPU6 drivers Version: 0^%{commit_date}git.%{shortcommit} -Release: 2%?dist +Release: 1%?dist License: GPL-2.0-or-later URL: https://github.com/intel/ipu6-drivers Source0: https://github.com/intel/ipu6-drivers/archive/%{commit}/ipu6-drivers-%{shortcommit}.tar.gz diff --git a/anda/system/joycond/anda.hcl b/anda/system/joycond/anda.hcl new file mode 100644 index 0000000000..e48a88db84 --- /dev/null +++ b/anda/system/joycond/anda.hcl @@ -0,0 +1,5 @@ +project pkg { + rpm { + spec = "joycond.spec" + } +} diff --git a/anda/system/joycond/joycond.spec b/anda/system/joycond/joycond.spec new file mode 100644 index 0000000000..2bb0f1a80d --- /dev/null +++ b/anda/system/joycond/joycond.spec @@ -0,0 +1,47 @@ +%global commit 39d5728d41b70840342ddc116a59125b337fbde2 +%global shortcommit %(c=%{commit}; echo ${c:0:7}) +%global commit_date %(date '+%Y%m%d') +Name: joycond +Version: %{commit_date}.git~%{shortcommit} +Release: 1%?dist +Summary: Userspace daemon to combine joy-cons from the hid-nintendo kernel driver +License: GPL-3.0-or-later +URL: https://github.com/DanielOgorchock/joycond +Source0: %url/archive/%{commit}/%{commit}.tar.gz#/%{name}-%{commit_date}.git~%{shortcommit}.tar.gz +Patch0: https://github.com/terrapkg/pkg-joycond/raw/refs/heads/main/0001-Revert-virt_ctrlr_passthrough-send-uevent-change-eve.patch +Patch1: https://github.com/terrapkg/pkg-joycond/raw/refs/heads/main/0001-Change-permissions-for-hidraw-access.patch +Packager: Cappy Ishihara +BuildRequires: libevdev-devel libudev-devel +BuildRequires: cmake make systemd-rpm-macros gcc-c++ + +%description +joycond is a linux daemon which uses the evdev devices provided by hid-nintendo +(formerly known as hid-joycon) to implement joycon pairing. + +%prep +%autosetup -n %{name}-%{commit} -p1 + +%build +%cmake . +%cmake_build + +%install +%cmake_install + + +%post +%systemd_post joycond.service + +%preun +%systemd_preun joycond.service + +%postun +%systemd_postun_with_restart joycond.service + +%files +%_bindir/joycond +%_udevrulesdir/72-joycond.rules +%_udevrulesdir/89-joycond.rules +%_unitdir/joycond.service +%_sysconfdir/modules-load.d/joycond.conf +%_datadir/metainfo/com.github.DanielOgorchock.joycond.metainfo.xml \ No newline at end of file diff --git a/anda/system/nvidia-patch/nvidia-patch.spec b/anda/system/nvidia-patch/nvidia-patch.spec index e9f5138257..3542c2f7d4 100644 --- a/anda/system/nvidia-patch/nvidia-patch.spec +++ b/anda/system/nvidia-patch/nvidia-patch.spec @@ -1,7 +1,7 @@ %global debug_package %{nil} -%global commit 119accbcc6d3c56b0fe748dc4990c53bb2359b5e +%global commit e181448e64e2a252962ddf0f8664274cd6c69e6e %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250722 +%global commit_date 20250916 %global patches %{_datadir}/src/nvidia-patch diff --git a/anda/system/nvidia/libva-nvidia-driver/libva-nvidia-driver.spec b/anda/system/nvidia/libva-nvidia-driver/libva-nvidia-driver.spec index 13f8521662..acb43a0803 100644 --- a/anda/system/nvidia/libva-nvidia-driver/libva-nvidia-driver.spec +++ b/anda/system/nvidia/libva-nvidia-driver/libva-nvidia-driver.spec @@ -1,5 +1,5 @@ -%global commit0 ef1e1aa3843f806740c866df4863f2a3ff77a359 -%global date 20250808 +%global commit0 e02b9c5c714f35a7576f0c1e549327e060fc7903 +%global date 20250819 %global shortcommit0 %(c=%{commit0}; echo ${c:0:7}) %global upstream_name nvidia-vaapi-driver diff --git a/anda/system/opentabletdriver-nightly/opentabletdriver-nightly.spec b/anda/system/opentabletdriver-nightly/opentabletdriver-nightly.spec index cf21027be3..da5d808e87 100644 --- a/anda/system/opentabletdriver-nightly/opentabletdriver-nightly.spec +++ b/anda/system/opentabletdriver-nightly/opentabletdriver-nightly.spec @@ -1,7 +1,7 @@ -%global commit d4150dea3c0e1f60177b3bb47faea114ba221663 +%global commit 4cebd851f5a90dbb11c48eba709ac27fe289ebf1 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250125 -%global ver 0.6.5.0 +%global commit_date 20250904 +%global ver 0.6.5.1 # We aren't using Mono but RPM expected Mono %global __requires_exclude_from ^/usr/lib/opentabletdriver/.*$ diff --git a/anda/system/readymade/git/readymade-git.spec b/anda/system/readymade/git/readymade-git.spec index 4818f8bd13..dbc0db75a0 100644 --- a/anda/system/readymade/git/readymade-git.spec +++ b/anda/system/readymade/git/readymade-git.spec @@ -1,5 +1,5 @@ -%global commit eced36223a7683dec87af0f6496a5c01ff757bab -%global commit_date 20250610 +%global commit 9621ae11165ad4de4a3d9edd722bb32d0233ebed +%global commit_date 20250908 %global shortcommit %(c=%{commit}; echo ${c:0:7}) Name: readymade-git @@ -63,3 +63,4 @@ ln -sf %{_datadir}/applications/com.fyralabs.Readymade.desktop %{buildroot}%{_da %_datadir/applications/liveinst.desktop %ghost %_datadir/readymade %_datadir/icons/hicolor/scalable/apps/com.fyralabs.Readymade.svg + diff --git a/anda/system/readymade/stable/readymade.spec b/anda/system/readymade/stable/readymade.spec index 1b9152f13d..91622a69bd 100644 --- a/anda/system/readymade/stable/readymade.spec +++ b/anda/system/readymade/stable/readymade.spec @@ -1,5 +1,5 @@ Name: readymade -Version: 0.12.2 +Version: 0.12.5 Release: 1%?dist Summary: Install ready-made distribution images! License: GPL-3.0-or-later @@ -53,6 +53,6 @@ ln -sf %{_datadir}/applications/com.fyralabs.Readymade.desktop %{buildroot}%{_da %_datadir/polkit-1/actions/com.fyralabs.pkexec.readymade.policy %_datadir/applications/com.fyralabs.Readymade.desktop %_datadir/applications/liveinst.desktop -%_datadir/readymade +%ghost %_datadir/readymade %_datadir/icons/hicolor/scalable/apps/com.fyralabs.Readymade.svg diff --git a/anda/system/rtl8821cu/akmod/rtl8821cu-kmod.spec b/anda/system/rtl8821cu/akmod/rtl8821cu-kmod.spec index 3466e5e331..4bf7c03da8 100644 --- a/anda/system/rtl8821cu/akmod/rtl8821cu-kmod.spec +++ b/anda/system/rtl8821cu/akmod/rtl8821cu-kmod.spec @@ -1,6 +1,6 @@ -%global commit 945c687aa1e62ee0b95b1ddd1dbfdbd513c30152 +%global commit 07fa9cf0fa8b0c08920c359c725dfc250e91422b %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250722 +%global commit_date 20250911 %global ver 5.12.0.4 %global modulename rtl8821cu %global git_name 8821cu-20210916 diff --git a/anda/system/rtl8821cu/dkms/dkms-rtl8821cu.spec b/anda/system/rtl8821cu/dkms/dkms-rtl8821cu.spec index ac4c9fc36b..4abe3d6767 100644 --- a/anda/system/rtl8821cu/dkms/dkms-rtl8821cu.spec +++ b/anda/system/rtl8821cu/dkms/dkms-rtl8821cu.spec @@ -1,6 +1,6 @@ -%global commit 945c687aa1e62ee0b95b1ddd1dbfdbd513c30152 +%global commit 07fa9cf0fa8b0c08920c359c725dfc250e91422b %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250722 +%global commit_date 20250911 %global ver 5.12.0.4 %global modulename rtl8821cu %global git_name 8821cu-20210916 diff --git a/anda/system/rtl8821cu/kmod-common/rtl8821cu-kmod-common.spec b/anda/system/rtl8821cu/kmod-common/rtl8821cu-kmod-common.spec index e4fb7e8c3a..af5d7b966f 100644 --- a/anda/system/rtl8821cu/kmod-common/rtl8821cu-kmod-common.spec +++ b/anda/system/rtl8821cu/kmod-common/rtl8821cu-kmod-common.spec @@ -1,6 +1,6 @@ -%global commit 945c687aa1e62ee0b95b1ddd1dbfdbd513c30152 +%global commit 07fa9cf0fa8b0c08920c359c725dfc250e91422b %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commit_date 20250722 +%global commit_date 20250911 %global ver 5.12.0.4 %global modulename rtl8821cu %global git_name 8821cu-20210916 diff --git a/anda/system/scx-scheds/nightly/scx-scheds-nightly.spec b/anda/system/scx-scheds/nightly/scx-scheds-nightly.spec index ab689de917..24175c0477 100644 --- a/anda/system/scx-scheds/nightly/scx-scheds-nightly.spec +++ b/anda/system/scx-scheds/nightly/scx-scheds-nightly.spec @@ -1,11 +1,11 @@ -%global commit 5ff891e71ce282c802332b398e8a98ccd4207552 +%global commit eb6e035b623d27d8d81bd054917751d060c6d8c5 %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commitdate 20250808 -%global ver 1.0.14 +%global commitdate 20250917 +%global ver 1.0.16 Name: scx-scheds-nightly Version: %{ver}^%{commitdate}.git.%{shortcommit} -Release: 2%?dist +Release: 1%?dist Summary: Nightly builds of sched_ext schedulers and tools SourceLicense: GPL-2.0-only License: ((Apache-2.0 OR MIT) AND BSD-3-Clause) AND ((MIT OR Apache-2.0) AND Unicode-3.0) AND (0BSD OR MIT OR Apache-2.0) AND (Apache-2.0 OR BSL-1.0) AND (Apache-2.0 OR MIT) AND (Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT) AND Apache-2.0 AND (BSD-2-Clause OR Apache-2.0 OR MIT) AND BSD-2-Clause AND BSD-3-Clause AND GPL-2.0-only AND ISC AND (LGPL-2.1-only OR BSD-2-Clause) AND LGPL-2.1 AND (MIT OR Apache-2.0 OR LGPL-2.1-or-later) AND (MIT OR Apache-2.0) AND (MIT OR Zlib OR Apache-2.0) AND MIT AND (MPL-2.0 OR MIT OR Apache-2.0) AND MPL-2.0-only and MPL-2.0-or-later AND (Unlicense OR MIT) AND Zlib diff --git a/anda/system/uutils-coreutils-replace/.gitignore b/anda/system/uutils-coreutils-replace/.gitignore new file mode 100644 index 0000000000..c32b546f7d --- /dev/null +++ b/anda/system/uutils-coreutils-replace/.gitignore @@ -0,0 +1 @@ +*.tar.gz \ No newline at end of file diff --git a/anda/system/uutils-coreutils-replace/anda.hcl b/anda/system/uutils-coreutils-replace/anda.hcl new file mode 100644 index 0000000000..b19312cdcf --- /dev/null +++ b/anda/system/uutils-coreutils-replace/anda.hcl @@ -0,0 +1,8 @@ +project pkg { + rpm { + spec = "uutils-coreutils-replace.spec" + } + labels { + subrepo = "extras" + } +} diff --git a/anda/system/uutils-coreutils-replace/coreutils-fix-metadata.diff b/anda/system/uutils-coreutils-replace/coreutils-fix-metadata.diff new file mode 100644 index 0000000000..793737b640 --- /dev/null +++ b/anda/system/uutils-coreutils-replace/coreutils-fix-metadata.diff @@ -0,0 +1,53 @@ +--- coreutils-*/Cargo.toml ++++ coreutils-*/Cargo.toml +@@ -18,6 +18,7 @@ + categories = ["command-line-utilities"] + rust-version = "1.82.0" + edition = "2021" ++autobins = false + + build = "build.rs" + +@@ -25,7 +26,11 @@ + all-features = true + + [features] +-default = ["feat_common_core"] ++default = [ ++ "feat_acl", ++ "feat_common_core", ++ "feat_selinux", ++] + ## OS feature shortcodes + macos = ["feat_os_macos"] + unix = ["feat_os_unix"] +@@ -325,7 +330,7 @@ + rand_core = "0.9.0" + rayon = "1.10" + regex = "1.10.4" +-rstest = "0.25.0" ++rstest = ">=0.25,<0.28" + rust-ini = "0.21.0" + same-file = "1.0.6" + self_cell = "1.0.4" +@@ -516,7 +521,7 @@ + rstest = { workspace = true } + + [target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies] +-procfs = { version = "0.17", default-features = false } ++procfs = { version = ">=0.17, <0.18", default-features = false } + + [target.'cfg(unix)'.dev-dependencies] + nix = { workspace = true, features = ["process", "signal", "user", "term"] } +@@ -538,11 +543,6 @@ + name = "coreutils" + path = "src/bin/coreutils.rs" + +-[[bin]] +-name = "uudoc" +-path = "src/bin/uudoc.rs" +-required-features = ["uudoc"] +- + # The default release profile. It contains all optimizations, without + # sacrificing debug info. With this profile (like in the standard + # release profile), the debug info and the stack traces will still be available. diff --git a/anda/system/uutils-coreutils-replace/coreutils-fix-seq-neg-num-tests.diff b/anda/system/uutils-coreutils-replace/coreutils-fix-seq-neg-num-tests.diff new file mode 100644 index 0000000000..dbb164e778 --- /dev/null +++ b/anda/system/uutils-coreutils-replace/coreutils-fix-seq-neg-num-tests.diff @@ -0,0 +1,134 @@ +--- a/tests/by-util/test_seq.rs ++++ b/tests/by-util/test_seq.rs +@@ -381,80 +381,80 @@ + #[test] + fn test_width_negative_zero_scientific_notation() { + new_ucmd!() +- .args(&["-w", "-0e0", "1"]) ++ .args(&["-w", "--", "-0e0", "1"]) + .succeeds() + .stdout_only("-0\n01\n"); + new_ucmd!() +- .args(&["-w", "-0e0", "1", "2"]) ++ .args(&["-w", "--", "-0e0", "1", "2"]) + .succeeds() + .stdout_only("-0\n01\n02\n"); + new_ucmd!() +- .args(&["-w", "-0e0", "1", "2.0"]) ++ .args(&["-w", "--", "-0e0", "1", "2.0"]) + .succeeds() + .stdout_only("-0\n01\n02\n"); + + new_ucmd!() +- .args(&["-w", "-0e+1", "1"]) ++ .args(&["-w", "--", "-0e+1", "1"]) + .succeeds() + .stdout_only("-00\n001\n"); + new_ucmd!() +- .args(&["-w", "-0e+1", "1", "2"]) ++ .args(&["-w", "--", "-0e+1", "1", "2"]) + .succeeds() + .stdout_only("-00\n001\n002\n"); + new_ucmd!() +- .args(&["-w", "-0e+1", "1", "2.0"]) ++ .args(&["-w", "--", "-0e+1", "1", "2.0"]) + .succeeds() + .stdout_only("-00\n001\n002\n"); + + new_ucmd!() +- .args(&["-w", "-0.000e0", "1"]) ++ .args(&["-w", "--", "-0.000e0", "1"]) + .succeeds() + .stdout_only("-0.000\n01.000\n"); + new_ucmd!() +- .args(&["-w", "-0.000e0", "1", "2"]) ++ .args(&["-w", "--", "-0.000e0", "1", "2"]) + .succeeds() + .stdout_only("-0.000\n01.000\n02.000\n"); + new_ucmd!() +- .args(&["-w", "-0.000e0", "1", "2.0"]) ++ .args(&["-w", "--", "-0.000e0", "1", "2.0"]) + .succeeds() + .stdout_only("-0.000\n01.000\n02.000\n"); + + new_ucmd!() +- .args(&["-w", "-0.000e-2", "1"]) ++ .args(&["-w", "--", "-0.000e-2", "1"]) + .succeeds() + .stdout_only("-0.00000\n01.00000\n"); + new_ucmd!() +- .args(&["-w", "-0.000e-2", "1", "2"]) ++ .args(&["-w", "--", "-0.000e-2", "1", "2"]) + .succeeds() + .stdout_only("-0.00000\n01.00000\n02.00000\n"); + new_ucmd!() +- .args(&["-w", "-0.000e-2", "1", "2.0"]) ++ .args(&["-w", "--", "-0.000e-2", "1", "2.0"]) + .succeeds() + .stdout_only("-0.00000\n01.00000\n02.00000\n"); + + new_ucmd!() +- .args(&["-w", "-0.000e5", "1"]) ++ .args(&["-w", "--", "-0.000e5", "1"]) + .succeeds() + .stdout_only("-000000\n0000001\n"); + new_ucmd!() +- .args(&["-w", "-0.000e5", "1", "2"]) ++ .args(&["-w", "--", "-0.000e5", "1", "2"]) + .succeeds() + .stdout_only("-000000\n0000001\n0000002\n"); + new_ucmd!() +- .args(&["-w", "-0.000e5", "1", "2.0"]) ++ .args(&["-w", "--", "-0.000e5", "1", "2.0"]) + .succeeds() + .stdout_only("-000000\n0000001\n0000002\n"); + + new_ucmd!() +- .args(&["-w", "-0.000e5", "1"]) ++ .args(&["-w", "--", "-0.000e5", "1"]) + .succeeds() + .stdout_only("-000000\n0000001\n"); + new_ucmd!() +- .args(&["-w", "-0.000e5", "1", "2"]) ++ .args(&["-w", "--", "-0.000e5", "1", "2"]) + .succeeds() + .stdout_only("-000000\n0000001\n0000002\n"); + new_ucmd!() +- .args(&["-w", "-0.000e5", "1", "2.0"]) ++ .args(&["-w", "--", "-0.000e5", "1", "2.0"]) + .succeeds() + .stdout_only("-000000\n0000001\n0000002\n"); + } +@@ -493,7 +493,7 @@ + #[test] + fn test_width_negative_decimal_notation() { + new_ucmd!() +- .args(&["-w", "-.1", ".1", ".11"]) ++ .args(&["-w", "--", "-.1", ".1", ".11"]) + .succeeds() + .stdout_only("-0.1\n00.0\n00.1\n"); + } +@@ -501,19 +501,19 @@ + #[test] + fn test_width_negative_scientific_notation() { + new_ucmd!() +- .args(&["-w", "-1e-3", "1"]) ++ .args(&["-w", "--", "-1e-3", "1"]) + .succeeds() + .stdout_only("-0.001\n00.999\n"); + new_ucmd!() +- .args(&["-w", "-1.e-3", "1"]) ++ .args(&["-w", "--", "-1.e-3", "1"]) + .succeeds() + .stdout_only("-0.001\n00.999\n"); + new_ucmd!() +- .args(&["-w", "-1.0e-4", "1"]) ++ .args(&["-w", "--", "-1.0e-4", "1"]) + .succeeds() + .stdout_only("-0.00010\n00.99990\n"); + new_ucmd!() +- .args(&["-w", "-.1e2", "10", "100"]) ++ .args(&["-w", "--", "-.1e2", "10", "100"]) + .succeeds() + .stdout_only( + "-010 diff --git a/anda/system/uutils-coreutils-replace/update.rhai b/anda/system/uutils-coreutils-replace/update.rhai new file mode 100644 index 0000000000..69aaaf4ad9 --- /dev/null +++ b/anda/system/uutils-coreutils-replace/update.rhai @@ -0,0 +1 @@ +rpm.version(crates("coreutils")); diff --git a/anda/system/uutils-coreutils-replace/uutils-coreutils-replace.spec b/anda/system/uutils-coreutils-replace/uutils-coreutils-replace.spec new file mode 100644 index 0000000000..05b7a01e84 --- /dev/null +++ b/anda/system/uutils-coreutils-replace/uutils-coreutils-replace.spec @@ -0,0 +1,107 @@ +%global coreutils_ver 9.3 +%if 0%{?fedora} >= 42 +### Temporary solution, will be fixed on newer Oniguruma releases. +%global build_cflags %{__build_flags_lang_c} %{?_distro_extra_cflags} -std=c18 -std=gnu18 +%endif + +Name: uutils-coreutils-replace +Version: 0.2.2 +Release: 1%?dist +Summary: Cross-platform Rust rewrite of the GNU coreutils +License: MIT +URL: https://github.com/uutils/coreutils +Source0: %url/archive/refs/tags/%version.tar.gz +Source1: https://src.fedoraproject.org/rpms/coreutils/raw/rawhide/f/coreutils-colorls.sh +Source2: https://src.fedoraproject.org/rpms/coreutils/raw/rawhide/f/coreutils-colorls.csh +Source3: https://raw.githubusercontent.com/coreutils/coreutils/refs/heads/master/src/dircolors.hin +Patch0: coreutils-fix-metadata.diff +Patch1: coreutils-fix-seq-neg-num-tests.diff +Patch3: https://src.fedoraproject.org/rpms/coreutils/raw/rawhide/f/coreutils-8.32-DIR_COLORS.patch +BuildRequires: anda-srpm-macros +BuildRequires: cargo +BuildRequires: clang-devel +BuildRequires: gcc-c++ +BuildRequires: libselinux-devel +BuildRequires: make +BuildRequires: rustfmt +BuildRequires: selinux-policy-devel +Requires: glibc +Provides: coreutils +Provides: coreutils-common +Conflicts: uutils-coreutils + +%description +uutils coreutils is a cross-platform reimplementation of the GNU coreutils in Rust. +While all programs have been implemented, some options might be missing or different +behavior might be experienced. + +This package replaces the GNU coreutils commands. + + +%prep +%setup -q -n coreutils-%version +%cargo_prep_online +/usr/bin/cp %{SOURCE3} . +sed dircolors.hin \ + -e 's| 00;36$| 01;36|' \ + > DIR_COLORS +sed dircolors.hin \ + -e 's| 01;31$| 00;31|' \ + -e 's| 01;35$| 00;35|' \ + > DIR_COLORS.lightbgcolor +%autopatch -p1 + +%build + +%install +install -p -c -Dm644 %{SOURCE1} %{buildroot}%{_sysconfdir}/profile.d/colorls.sh +install -p -c -Dm644 %{SOURCE2} %{buildroot}%{_sysconfdir}/profile.d/colorls.csh +install -p -c -Dm644 DIR_COLORS{,.lightbgcolor} %{buildroot}%{_sysconfdir} +/usr/bin/rm dircolors.hin DIR_COLORS DIR_COLORS.lightbgcolor +%make_install PROFILE_CMD='--profile=rpm' MULTICALL=n DESTDIR=%buildroot BUILDDIR=target/rpm PREFIX=%_prefix SELINUX_ENABLED=1 SKIP_UTILS='hostname kill more uptime' & +wait +/usr/bin/ln -sf hashsum %{buildroot}%{_bindir}/b2sum +/usr/bin/ln -sf hashsum %{buildroot}%{_bindir}/md5sum +/usr/bin/ln -sf hashsum %{buildroot}%{_bindir}/sha1sum +/usr/bin/ln -sf hashsum %{buildroot}%{_bindir}/sha224sum +/usr/bin/ln -sf hashsum %{buildroot}%{_bindir}/sha256sum +/usr/bin/ln -sf hashsum %{buildroot}%{_bindir}/sha384sum +/usr/bin/ln -sf hashsum %{buildroot}%{_bindir}/sha512sum + +%define cmds() $(echo %1{runcon,arch,base{32,64,name,nc},cat,ch{grp,mod,own,root,con},cksum,comm,cp,csplit,cut,date,dd,df,dir{,colors,name},du,echo,env,expand,expr,factor,false,fmt,fold,groups,hashsum,head,host{id},id,install,join,link,ln,logname,ls,mk{dir,fifo,nod,temp},mv,nice,nl,nohup,nproc,numfmt,od,paste,pathchk,pinky,pr,printenv,printf,ptx,pwd,readlink,realpath,rm{,dir},seq,shred,shuf,sleep,sort,split,stat,stdbuf,sum,sync,tac,tail,tee,test,timeout,touch,tr,true,truncate,tsort,tty,uname,un{expand,iq,link},users,vdir,wc,who{,ami},yes}%2) +cat < files.txt +%cmds %_bindir/ "" +%_bindir/[ +%cmds %_datadir/bash-completion/completions/ "" +%cmds %_datadir/fish/vendor_completions.d/ .fish +%cmds %_mandir/man1/ .1.gz +%cmds %_datadir/zsh/site-functions/_ "" +EOF +sed -i 's@ @\n@g' files.txt + +# remove buildroot from paths in files.txt +sed -i "s@%buildroot@/@g" files.txt + + +echo "=== Files ===" +cat files.txt + +%files -f files.txt +%doc README.md +%license LICENSE +%{_bindir}/b2sum +%{_bindir}/md5sum +%{_bindir}/sha1sum +%{_bindir}/sha224sum +%{_bindir}/sha256sum +%{_bindir}/sha384sum +%{_bindir}/sha512sum +%config(noreplace) %{_sysconfdir}/DIR_COLORS +%config(noreplace) %{_sysconfdir}/DIR_COLORS.lightbgcolor +%{_sysconfdir}/profile.d/colorls.sh +%{_sysconfdir}/profile.d/colorls.csh + + + +%changelog +%autochangelog diff --git a/anda/system/wine-dxvk/anda.hcl b/anda/system/wine-dxvk/anda.hcl index cc8e570dc4..7f713b90ec 100644 --- a/anda/system/wine-dxvk/anda.hcl +++ b/anda/system/wine-dxvk/anda.hcl @@ -2,7 +2,7 @@ project pkg { arches = ["x86_64", "i386"] rpm { spec = "wine-dxvk.spec" - extra_repos = ["https://repos.fyralabs.com/terra\\$releasever-mesa"] + extra_repos = ["https://repos.fyralabs.com/terrarawhide-mesa"] } labels { mock = 1 diff --git a/anda/system/wine/dev/anda.hcl b/anda/system/wine/dev/anda.hcl index 5b56f0b34d..ae57da621e 100644 --- a/anda/system/wine/dev/anda.hcl +++ b/anda/system/wine/dev/anda.hcl @@ -2,6 +2,7 @@ project pkg { arches = ["x86_64", "aarch64", "i386"] rpm { spec = "wine-dev.spec" + extra_repos = ["https://repos.fyralabs.com/terrarawhide-mesa"] } labels { mock = 1 diff --git a/anda/system/wine/stable/anda.hcl b/anda/system/wine/stable/anda.hcl index 1bbdbeb74f..49b50d5736 100644 --- a/anda/system/wine/stable/anda.hcl +++ b/anda/system/wine/stable/anda.hcl @@ -2,6 +2,7 @@ project pkg { arches = ["x86_64", "aarch64", "i386"] rpm { spec = "wine-stable.spec" + extra_repos = ["https://repos.fyralabs.com/terrarawhide-mesa"] } labels { mock = 1 diff --git a/anda/system/wine/staging/anda.hcl b/anda/system/wine/staging/anda.hcl index 12c623a5e4..4e0642affd 100644 --- a/anda/system/wine/staging/anda.hcl +++ b/anda/system/wine/staging/anda.hcl @@ -2,6 +2,7 @@ project pkg { arches = ["x86_64", "aarch64", "i386"] rpm { spec = "wine-staging.spec" + extra_repos = ["https://repos.fyralabs.com/terrarawhide-mesa"] } labels { mock = 1 diff --git a/anda/themes/helium-gtk-theme/helium-gtk-theme.spec b/anda/themes/helium-gtk-theme/helium-gtk-theme.spec index 4fe6055407..0981079d91 100644 --- a/anda/themes/helium-gtk-theme/helium-gtk-theme.spec +++ b/anda/themes/helium-gtk-theme/helium-gtk-theme.spec @@ -1,4 +1,4 @@ -%global ver 1.8.42 +%global ver 1.8.61 Summary: tauOS GTK/GNOME Shell Themes Name: helium-gtk-theme diff --git a/anda/themes/lightly-qt6/VER6.txt b/anda/themes/lightly-qt6/VER6.txt index 45a4fb75db..ec635144f6 100644 --- a/anda/themes/lightly-qt6/VER6.txt +++ b/anda/themes/lightly-qt6/VER6.txt @@ -1 +1 @@ -8 +9 diff --git a/anda/tools/copyparty/copyparty.spec b/anda/tools/copyparty/copyparty.spec index 503afa15c7..f797e975f3 100644 --- a/anda/tools/copyparty/copyparty.spec +++ b/anda/tools/copyparty/copyparty.spec @@ -1,7 +1,7 @@ %global pypi_name copyparty Name: %{pypi_name} -Version: 1.19.8 +Version: 1.19.9 Release: 1%?dist Summary: Portable, featureful, and fast file server URL: https://github.com/9001/copyparty diff --git a/anda/tools/neovim-default-editor/neovim-default-editor.spec b/anda/tools/neovim-default-editor/neovim-default-editor.spec index 6cbf026825..6e02c9173c 100644 --- a/anda/tools/neovim-default-editor/neovim-default-editor.spec +++ b/anda/tools/neovim-default-editor/neovim-default-editor.spec @@ -2,7 +2,7 @@ Name: neovim-default-editor # Version, release, and epoch are inherited from the editor package just like other default editors -Version: 0.11.3 +Version: 0.6.0 Release: 1%?dist Epoch: 0 # Inherited from Neovim itself diff --git a/anda/tools/nvidia/cuda-gcc/cuda-gcc.spec b/anda/tools/nvidia/cuda-gcc/cuda-gcc.spec index 8c6b392ec9..3579143f30 100644 --- a/anda/tools/nvidia/cuda-gcc/cuda-gcc.spec +++ b/anda/tools/nvidia/cuda-gcc/cuda-gcc.spec @@ -5,8 +5,8 @@ %endif Name: cuda-gcc -Version: 14.2.1 -Release: 2%?dist +Version: 14.3.1 +Release: 1%?dist Summary: GNU Compiler Collection CUDA compatibility package License: BSD URL: http://gcc.gnu.org diff --git a/anda/tools/spotx-bash/spotx-bash.spec b/anda/tools/spotx-bash/spotx-bash.spec index cf925e1ef8..6b8d5d457d 100644 --- a/anda/tools/spotx-bash/spotx-bash.spec +++ b/anda/tools/spotx-bash/spotx-bash.spec @@ -1,5 +1,5 @@ -%global commit bde730fec64491b5687b3a2eb9108527156e8b02 -%global commit_date 20250824 +%global commit d763ce8858547602c9039c0a54455b54df8d01c4 +%global commit_date 20250907 %global shortcommit %(c=%{commit}; echo ${c:0:7}) Name: spotx-bash