Repository navigation
Optimizing Background Video/Image Renderer - #915
Conversation
Parameters: Quality: 70 Subsample chroma: 4:2:0 Sharp YUV Downsampling: Enabled Sharpness: 7 Noise synthesis: 30 Effort: 7
This reverts commit e54913d.
Previously, the Window will only be decided as "Hidden" if no WS_MINIMIZE is present. This causes an issue where a window with minimized state but hidden into a tray will return the condition as true. Adding barrier to check if no WS_VISIBLE was present, then assume it as hidden as well.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
| .ConfigureAwait(false); | ||
|
|
||
| if (color == default) return; | ||
|
|
||
| string hex = $"{color.R:X2}{color.G:X2}{color.B:X2}"; | ||
| if (!string.IsNullOrEmpty(configKey)) | ||
| { | ||
| string? savedHex = LauncherConfig.GetAppConfigValue($"{configKey}-AccentColor").ToString(); | ||
| if (savedHex == hex) return; | ||
| LauncherConfig.SetAndSaveConfigValue($"{configKey}-AccentColor", hex); | ||
| } | ||
|
|
||
| ColorAccentChanged?.Invoke(color); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Logger.LogWriteLine($"GetMediaAccentColor failed: {ex}", LogType.Error, true); | ||
| Logger.LogWriteLine($"LoadMediaAccentColor failed: {ex}", LogType.Error, true); | ||
| SentryHelper.ExceptionHandler(ex); | ||
| } | ||
| } | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Bug: 10-bit H.264 video backgrounds fail to decode when the FFmpeg toggle is disabled because Media Foundation does not support High 10 profile decoding.
Severity: MEDIUM
Suggested Fix
Restore the check for 10-bit video pixel formats (such as YUV420P10) in video codec detection to force FFmpeg decoding even if the global FFmpeg toggle is disabled, or provide a fallback when Media Foundation fails to decode.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.Loaders.cs#L26-L280
Potential issue: Removing the `RequiresFFmpegDecoder` check for YUV 10-bit formats
(`AV_PIX_FMT_YUV420P10LE`/`BE`) causes 10-bit H.264 background videos to bypass FFmpeg
when the 'use FFmpeg' toggle is disabled. In this configuration,
`CheckCodecOrSpawnDialog` returns `(true, false)`, routing playback through Windows
Media Foundation. Because Windows' H.264 decoder MFT only supports up to 8-bit profiles
(Baseline/Main/High), playback fails without an FFmpeg fallback or `MediaFailed`
handler, leaving the background blank.
Did we get this right? 👍 / 👎 to inform future reviews.
|
|
||
| private static ReadOnlySpan<char> TryGetFileExtensionFromUri(Uri uri) | ||
| { | ||
| ReadOnlySpan<char> pathAndQuery = uri.PathAndQuery; | ||
| int indexOfQuerySign = pathAndQuery.IndexOf('?'); | ||
| if (indexOfQuerySign > 0) | ||
| pathAndQuery = pathAndQuery[..indexOfQuerySign]; | ||
|
|
||
| return Path.GetExtension(pathAndQuery); | ||
| } | ||
| } |
There was a problem hiding this comment.
Bug: ReadBitmapImageFromUriDetached requests unnecessary write access via FileAccess.ReadWrite, causing load failures on read-only or exclusively locked image files.
Severity: LOW
Suggested Fix
Change FileAccess.ReadWrite to FileAccess.Read and adjust FileShare to FileShare.Read in ReadBitmapImageFromUriDetached when opening source image streams.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
CollapseLauncher/XAMLs/Theme/CustomControls/LayeredBackgroundImageExtensions.ImageSourceFactory.cs#L1-L250
Potential issue: `ReadBitmapImageFromUriDetached` opens images using `File.Open(...,
FileAccess.ReadWrite, FileShare.ReadWrite)` even though the operation is read-only. When
referencing a native-format image directly (such as an uncropped custom background below
the minimum crop dimension), opening a read-only file or a file held open without write
sharing throws an `UnauthorizedAccessException` or sharing violation. Because the logger
passed from `PresenterFactory` is null, the exception is swallowed silently and the
background remains blank.
Did we get this right? 👍 / 👎 to inform future reviews.
| if (source is Uri sourceAsUri || | ||
| (source is string sourceUriAsString && | ||
| Uri.TryCreate(sourceUriAsString, UriKind.Absolute, out sourceAsUri!))) | ||
| { | ||
| if (sourceAsUri.IsFile) | ||
| { | ||
| string fullyQualifiedPath = sourceAsUri.LocalPath.GetFullyQualifiedPath(); | ||
| ffmpegMediaSource = await FFmpegMediaSource | ||
| .CreateFromFileAsync(fullyQualifiedPath, | ||
| ffmpegConfig, |
There was a problem hiding this comment.
Bug: Local path string sources construct redundant FFmpegMediaSource instances in GetMediaSourceAsync, leaking the first instance and its open file handle.
Severity: MEDIUM
Suggested Fix
Ensure GetMediaSourceAsync only creates a single FFmpegMediaSource for string/Uri inputs, structuring conditional branches to avoid repeating CreateFromFileAsync or disposing existing instances before reassigning.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
CollapseLauncher/XAMLs/Theme/CustomControls/LayeredBackgroundImageExtensions.MediaSourceFactory.cs#L89-L98
Potential issue: In `GetMediaSourceAsync` when `useFFmpeg` is enabled and the source is
passed as a local-path string, both the initial `Uri` check and the subsequent string
check construct an `FFmpegMediaSource` instance via `CreateFromFileAsync`. The first
created instance is overwritten by the second without being disposed, leaking its
unmanaged resources and underlying file handle until GC/RCW finalization.
| if (sender is not Image asImage) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| asImage.ImageOpened -= ImagePresenterOnLoaded; | ||
| asImage.ImageFailed -= ImagePresenterOnLoaded; | ||
| asImage.Loaded -= ImagePresenterOnLoaded; | ||
| await UnloadLastPresenter(parent, asImage); | ||
| tcs.TrySetResult(); | ||
| } |
There was a problem hiding this comment.
Bug: AddImagePresenterAsync is called without an ImageFailed handler, causing LoadPresenter to hang indefinitely if image decoding fails.
Severity: MEDIUM
Suggested Fix
Pass an ImageFailed event handler to AddImagePresenterAsync that transitions the TaskCompletionSource to an exception or completed state when image loading fails.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
CollapseLauncher/XAMLs/Theme/CustomControls/LayeredBackgroundImage.Loader.cs#L71-L89
Potential issue: When adding an image background presenter in
`LayeredBackgroundImage.Loader.cs`, `AddImagePresenterAsync` is invoked without
providing an `onFailedEventHandler` (passing `null`). If image decoding fails, neither
`ImageOpened` nor any failure handler triggers completion on the underlying
`TaskCompletionSource`, causing `LoadPresenter` to await `tcs.Task` indefinitely and
leaving previous background presenters loaded.
For now, just rely on GC to automatically free them, just call Dispose if an object is an IDisposable
| // -- Get context and invalidate previous CTS | ||
| LayeredImageBackgroundContext? context = CurrentSelectedBackgroundContext; | ||
| if (context == null) | ||
| return; | ||
|
|
||
| private void CancelCurrentBackgroundLoad() | ||
| { | ||
| if (Interlocked.Exchange(ref _imageLoadingTokenSource, null) is { } lastCts) | ||
| { | ||
| lastCts.Cancel(); | ||
| lastCts.Dispose(); | ||
| } | ||
| IsBackgroundLoading = false; | ||
| } | ||
|
|
||
| public void PreloadBackground(PresetConfig? preset, Grid? presenterGrid) | ||
| { | ||
| if (preset == null || presenterGrid == null) return; | ||
|
|
||
| CancelCurrentBackgroundLoad(); | ||
| Interlocked.Increment(ref _loadGeneration); | ||
|
|
||
| PresenterGrid = presenterGrid; | ||
| string autoPlayKey = $"LastIsEnableBackgroundAutoPlay-{preset.GameName}-{preset.ZoneName}"; | ||
| CurrentIsEnableBackgroundAutoPlayKey = autoPlayKey; | ||
|
|
||
| string cachedBgKey = $"CachedBg-{preset.GameName}-{preset.ZoneName}"; | ||
| string? backgroundUrl = LauncherConfig.GetAppConfigValue($"{cachedBgKey}-Background").ToString(); | ||
| string? staticBgUrl = LauncherConfig.GetAppConfigValue($"{cachedBgKey}-StaticBackground").ToString(); | ||
| string? overlayUrl = LauncherConfig.GetAppConfigValue($"{cachedBgKey}-Overlay").ToString(); | ||
|
|
||
| if (string.IsNullOrEmpty(backgroundUrl) && string.IsNullOrEmpty(staticBgUrl)) | ||
| { | ||
| IsBackgroundLoading = true; | ||
| return; | ||
| } | ||
| // -- Invalidate last Cancellation Token (and thus, cancel all asynchronous routines) | ||
| // and then renew the token. Also toggle the background loading indicator. | ||
| DispatcherQueueExtensions.CurrentDispatcherQueue.TryEnqueue(() => IsBackgroundLoading = true ); | ||
| token = InvalidateAndRenewCancelToken(token); | ||
|
|
||
| string? primaryBg = backgroundUrl ?? staticBgUrl; | ||
| stopwatch = Stopwatch.StartNew(); |
There was a problem hiding this comment.
Bug: Cancelled background loading tasks unconditionally set IsBackgroundLoading = false in finally, prematurely hiding the loading indicator while a newer request is still in progress.
Severity: MEDIUM
Suggested Fix
In the finally block of ImageBackgroundManager.Loaders.cs, guard the dispatch that sets IsBackgroundLoading = false with a check ensuring that cancellation has not been requested for the task's token.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.Loaders.cs#L47-L62
Potential issue: In `ImageBackgroundManager.Loaders.cs`, when a background load
operation is cancelled by a newer request (e.g., rapidly changing background indexes),
the cancelled task's `finally` block unconditionally enqueues `IsBackgroundLoading =
false`. Because the check `if (!token.IsCancellationRequested)` was removed, the
cancellation of an earlier task prematurely resets `IsBackgroundLoading` to `false` on
the UI thread while the newer load task is still downloading. This dismisses the loading
indicator and re-enables UI controls prematurely.
| Task<(string, ImageExternalCodecType)> processTask = ImplAsync(); | ||
| if (processTask.IsCompleted) | ||
| { | ||
| return (filePath, codecType); | ||
| return new ValueTask<(string, ImageExternalCodecType)>(processTask.Result); | ||
| } | ||
|
|
||
| // Return null if the codec type is not supported. | ||
| if (codecType == ImageExternalCodecType.NotSupported) | ||
| return new ValueTask<(string, ImageExternalCodecType)>(processTask); |
There was a problem hiding this comment.
Bug: Failed background image loads no longer invoke OnBackgroundLoadFailed, preventing fallback placeholder images from displaying.
Severity: MEDIUM
Suggested Fix
Restore the invocation of OnBackgroundLoadFailed?.Invoke() when the resolved background URI is null or invalid before returning.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
CollapseLauncher/Classes/GameManagement/ImageBackground/ImageBackgroundManager.ImageCropperAndConvert.cs#L576-L582
Potential issue: The invocation of `OnBackgroundLoadFailed` was removed during
refactoring. When background, static, or overlay URLs are missing or fail to resolve,
the method now silently returns after setting `backgroundToUse = null` instead of firing
the failure callback. Consequently, `PlaceholderBackgroundLayer` is never inserted by
`MainPage`, leaving `OnBackgroundLoadFailed` unused and displaying an outdated
background rather than the fallback preset placeholder.
 # Preview 1.84.7 (Codename: Columbina) # What's Changed? - 1.84.7 ## **[New]** [Game Settings Subsystem Support for Supported Plugin-based Games](#900), by @Cryotechnic We have implemented a new Update 6 extension for v1 API Standard. The plugin developer could now add customizations to the game into Collapse Launcher. To see the example of the implementation, see the source code of our Wuthering Waves plugin [here](https://github.com/CollapseLauncher/Hi3Helper.Plugin.Wuwa/tree/main/Hi3Helper.Plugin.Wuwa/Management/Settings). <img width="962" height="541" alt="image" src="https://github.com/user-attachments/assets/1f668111-fbf7-445a-b90c-70c1693ba87b" /> ## **[Imp]** [Optimizing Background Video/Image Renderer](#915), by @neon-nyan Optimizing the Background Video/Image Load routines and provides better memory allocation after dispose/use of each frames. The following PR also provides major improvements on the frame renderer for the background video playback, including direct GPU drawn to the frame's IDirect3DTexture outside of the UI thread, which reduces the VRAM usage and (hopefully) stutters. ### Video Background Playing (Honkai Impact 3rd - Mainland China - Picture 2 1080p) | Mem: Current Release | Mem: This PR | VRAM: Current Release | VRAM: This PR | |----|----|----|----| |  |  |  |  | ### Video Background On-Pause/Window minimized (Custom Video 2160p) | Mem: Current Release | Mem: This PR | VRAM: Current Release | VRAM: This PR | |----|----|----|----| |  |  |  |  | - **[Fix]** Race Conditions in Sophon API Loader causing Available Game Version reverted to Deprecated ZIP API, by @neon-nyan - **[New]** Sync game settings to database by @bagusnl, @neon-nyan - Now users with DB subsystem set-up can backup their game settings to the configured DB endpoint. Uses Collapse' way of saving registry so storage shouldn't be a problem. - Guide on setting Collapse' DB subsystem is here https://collapselauncher.com/feature/database.html - **[Imp]** DiscordRPC fixes and stability improvements by @neon-nyan - **[Imp]** Improved Collapse settings loading time by initializing Waifu2x at startup time by @neon-nyan - **[Imp]** Improved video background playback by reducing animation in carousel by @neon-nyan - Should be smoother and less prone of frame skip now - **[Imp]** Background CPU and Memory utilizations by @neon-nyan - CPU utilization should be next to 0 when Collapse is minimized (and to tray) by hiding WinUI elements. - Memory utilization is improved by running more aggressive garbage-collections - **[Fix]** Region without static images uses last loaded region background resources by @neon-nyan <details> <summary>Changelog Prefixes</summary> ``` **[New]** **[Imp]** **[Fix]** **[Loc]** **[Doc]** ``` </details>
 # Stable 1.84.7 (Codename: Columbina) # What's Changed? - 1.84.7 ## **[New]** [Game Settings Subsystem Support for Plugin-based Games](#900), by @Cryotechnic We have implemented a new Update 6 extension for v1 API Standard. The plugin developer could now add customizations to the game into Collapse Launcher. To see the example of the implementation, see the source code of our Wuthering Waves plugin [here](https://github.com/CollapseLauncher/Hi3Helper.Plugin.Wuwa/tree/main/Hi3Helper.Plugin.Wuwa/Management/Settings). <img width="962" height="541" alt="image" src="https://github.com/user-attachments/assets/1f668111-fbf7-445a-b90c-70c1693ba87b" /> ## **[Imp]** [Optimizing Background Video/Image Renderer](#915), by @neon-nyan Optimizing the Background Video/Image Load routines and provides better memory allocation after dispose/use of each frames. The following PR also provides major improvements on the frame renderer for the background video playback, including direct GPU drawn to the frame's IDirect3DTexture outside of the UI thread, which reduces the VRAM usage and (hopefully) stutters. ### Video Background Playing (Honkai Impact 3rd - Mainland China - Picture 2 1080p) | Mem: Current Release | Mem: This PR | VRAM: Current Release | VRAM: This PR | |----|----|----|----| |  |  |  |  | ### Video Background On-Pause/Window minimized (Custom Video 2160p) | Mem: Current Release | Mem: This PR | VRAM: Current Release | VRAM: This PR | |----|----|----|----| |  |  |  |  | - **[Fix]** Race Conditions in Sophon API Loader causing Available Game Version reverted to Deprecated ZIP API, by @neon-nyan - **[New]** Sync game settings to database by @bagusnl, @neon-nyan - Now users with DB subsystem set-up can backup their game settings to the configured DB endpoint. Uses Collapse' way of saving registry so storage shouldn't be a problem. - Guide on setting Collapse' DB subsystem is here https://collapselauncher.com/feature/database.html - **[Imp]** DiscordRPC fixes and stability improvements by @neon-nyan - **[Imp]** Improved Collapse settings loading time by initializing Waifu2x at startup time by @neon-nyan - **[Imp]** Improved video background playback by reducing animation in carousel by @neon-nyan - Should be smoother and less prone of frame skip now - **[Imp]** Background CPU and Memory utilizations by @neon-nyan - CPU utilization should be next to 0 when Collapse is minimized (and to tray) by hiding WinUI elements. - Memory utilization is improved by running more aggressive garbage-collections - **[Fix]** Region without static images uses last loaded region background resources by @neon-nyan <details> <summary>Changelog Prefixes</summary> ``` **[New]** **[Imp]** **[Fix]** **[Loc]** **[Doc]** ``` </details>
Main Goal
Optimizing the Background Video/Image Load routines and provides better memory allocation after dispose/use of each frames. The following PR also provides major improvements on the frame renderer for the background video playback, including direct GPU drawn to the frame's IDirect3DTexture outside of the UI thread, which reduces the VRAM usage and (hopefully) stutters.
Reduced Memory and VRAM Allocation
Video Background Playing (Honkai Impact 3rd - Mainland China - Picture 2 1080p)
Video Background On-Pause/Window minimized (Custom Video 2160p)
Other Improvements
[Fix] Missing Alpha Channel on HEIF/AVIF Encoded Background Image.
The Alpha channel went missing while decoding HEIF/AVIF Encoded Images which caused by incorrect decoding request via the
PhotoSauce.MagicScalerlibrary. A bug fix has been submitted into a PR here and while waiting for the PR to be merged, we copied our version of the workaround here.[Imp] Reencoding Sprites to AVIF
Previously, all the static sprites within Collapse assets (including Logo and Default Posters) are encoded using lossless PNG format with reduced palettes (256 colors + dithering). However, the size of the sprites are still considerably huge. So now, we decided to re-encode most of the sprites to AVIF with high bit-depth (up to 16-bit) while maintaining a smaller overall file sizes. The size reduction might be not that noticeable.
PR Status :
Templates
Changelog Prefixes