Defer status taskbar asset rendering

This commit is contained in:
Chris Titus
2026-07-01 22:28:07 -05:00
parent 59714f81e6
commit 44bb99b684
8 changed files with 100 additions and 11 deletions
@@ -0,0 +1,21 @@
function Initialize-WinUtilTaskbarOverlayAssets {
param(
[bool]$IncludeLogo = $true,
[bool]$IncludeStatusAssets = $true
)
if ($IncludeLogo -and -not $sync["logorender"]) {
$sync["logorender"] = (Invoke-WinUtilAssets -Type "Logo" -Size 90 -Render)
Write-WinUtilPerformanceCheckpoint -Name "Taskbar logo asset rendered"
}
if ($IncludeStatusAssets -and -not $sync["checkmarkrender"]) {
$sync["checkmarkrender"] = (Invoke-WinUtilAssets -Type "checkmark" -Size 512 -Render)
Write-WinUtilPerformanceCheckpoint -Name "Taskbar checkmark asset rendered"
}
if ($IncludeStatusAssets -and -not $sync["warningrender"]) {
$sync["warningrender"] = (Invoke-WinUtilAssets -Type "warning" -Size 512 -Render)
Write-WinUtilPerformanceCheckpoint -Name "Taskbar warning asset rendered"
}
}
@@ -5,6 +5,17 @@ function Invoke-WinUtilAssets {
[switch]$render
)
if ($render -and $null -ne $sync) {
if ($null -eq $sync.RenderedAssetCache) {
$sync.RenderedAssetCache = @{}
}
$cacheKey = "$(([string]$type).ToLowerInvariant())|$Size"
if ($sync.RenderedAssetCache.ContainsKey($cacheKey)) {
return $sync.RenderedAssetCache[$cacheKey]
}
}
# Create the Viewbox and set its size
$LogoViewbox = New-Object Windows.Controls.Viewbox
$LogoViewbox.Width = $Size
@@ -191,6 +202,13 @@ C 21.36,47.14 28.67,50.71 30.01,52.63
$bitmapImage.StreamSource = $imageStream
$bitmapImage.CacheOption = [Windows.Media.Imaging.BitmapCacheOption]::OnLoad
$bitmapImage.EndInit()
if ($bitmapImage.CanFreeze) {
$bitmapImage.Freeze()
}
if ($null -ne $sync -and $sync.ContainsKey("RenderedAssetCache")) {
$sync.RenderedAssetCache[$cacheKey] = $bitmapImage
}
return $bitmapImage
} else {
@@ -61,12 +61,21 @@ function Set-WinUtilTaskbaritem {
if ($overlay) {
switch ($overlay) {
'logo' {
if (-not $sync["logorender"]) {
Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo $true -IncludeStatusAssets $false
}
$sync["Form"].taskbarItemInfo.Overlay = $sync["logorender"]
}
'checkmark' {
if (-not $sync["checkmarkrender"]) {
Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo $false -IncludeStatusAssets $true
}
$sync["Form"].taskbarItemInfo.Overlay = $sync["checkmarkrender"]
}
'warning' {
if (-not $sync["warningrender"]) {
Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo $false -IncludeStatusAssets $true
}
$sync["Form"].taskbarItemInfo.Overlay = $sync["warningrender"]
}
'None' {
+42
View File
@@ -0,0 +1,42 @@
#===========================================================================
# Tests - Asset rendering
#===========================================================================
BeforeAll {
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
}
Describe "Rendered asset caching" {
It "caches rendered bitmap assets by type and size" {
$assetScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Invoke-WinUtilAssets.ps1") -Raw
$assetScript | Should -Match 'RenderedAssetCache'
$assetScript | Should -Match '\$cacheKey = "\$\(\(\[string\]\$type\)\.ToLowerInvariant\(\)\)\|\$Size"'
$assetScript | Should -Match 'return \$sync\.RenderedAssetCache\[\$cacheKey\]'
$assetScript | Should -Match '\$sync\.RenderedAssetCache\[\$cacheKey\] = \$bitmapImage'
}
It "renders only the logo overlay before first paint and defers status overlays" {
$mainScript = Get-Content -Path (Join-Path $script:repoRoot "scripts\main.ps1") -Raw
$mainScript | Should -Match 'Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo \$true -IncludeStatusAssets \$false'
$mainScript | Should -Match 'Dispatcher\.BeginInvoke\(\[System\.Windows\.Threading\.DispatcherPriority\]::Background, \[action\]\{ Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo \$false -IncludeStatusAssets \$true \}'
$mainScript | Should -Not -Match '\$sync\["checkmarkrender"\] = \(Invoke-WinUtilAssets -Type "checkmark"'
$mainScript | Should -Not -Match '\$sync\["warningrender"\] = \(Invoke-WinUtilAssets -Type "warning"'
}
It "lazily creates taskbar overlays before assigning them" {
$taskbarScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Set-WinUtilTaskbarItem.ps1") -Raw
$taskbarScript | Should -Match 'Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo \$true -IncludeStatusAssets \$false'
$taskbarScript | Should -Match 'Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo \$false -IncludeStatusAssets \$true'
}
It "records individual taskbar overlay render checkpoints" {
$overlayScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Initialize-WinUtilTaskbarOverlayAssets.ps1") -Raw
$overlayScript | Should -Match 'Taskbar logo asset rendered'
$overlayScript | Should -Match 'Taskbar checkmark asset rendered'
$overlayScript | Should -Match 'Taskbar warning asset rendered'
}
}
+3 -2
View File
@@ -71,7 +71,8 @@ Describe "Startup performance checkpoints" {
$mainScript = Get-Content -Path (Join-Path $script:repoRoot "scripts\main.ps1") -Raw
$lazyTabScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Initialize-WinUtilTabContent.ps1") -Raw
$runspaceScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Initialize-WinUtilRunspacePool.ps1") -Raw
$startupText = "$mainScript`n$lazyTabScript`n$runspaceScript"
$overlayScript = Get-Content -Path (Join-Path $script:repoRoot "functions\private\Initialize-WinUtilTaskbarOverlayAssets.ps1") -Raw
$startupText = "$mainScript`n$lazyTabScript`n$runspaceScript`n$overlayScript"
foreach ($checkpoint in @(
"Runspace pool initialized",
@@ -81,7 +82,7 @@ Describe "Startup performance checkpoints" {
"Tweaks UI created",
"Features UI created",
"AppX UI created",
"Assets rendered",
"Taskbar logo asset rendered",
"First content rendered"
)) {
$startupText | Should -Match ([regex]::Escape($checkpoint))
+1
View File
@@ -302,6 +302,7 @@ Describe "XAML and sync wiring" {
"InitializedTabs",
"PerformanceTrace",
"PerformanceTraceEnabled",
"RenderedAssetCache",
"ToggleStatusCache",
"InstallAppAreaBorder",
"InstallAppAreaScrollViewer",
+2 -5
View File
@@ -340,6 +340,7 @@ $sync["Form"].Add_ContentRendered({
$sync["Form"].Focus()
$sync["Form"].Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ Initialize-WinUtilRunspacePool | Out-Null }) | Out-Null
$sync["Form"].Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo $false -IncludeStatusAssets $true }) | Out-Null
})
# The SearchBarTimer is used to delay the search operation until the user has stopped typing for a short period
@@ -384,11 +385,7 @@ $sync["Form"].Add_Loaded({
$NavLogoPanel = $sync["Form"].FindName("NavLogoPanel")
$NavLogoPanel.Children.Add((Invoke-WinUtilAssets -Type "logo" -Size 25)) | Out-Null
$sync["logorender"] = (Invoke-WinUtilAssets -Type "Logo" -Size 90 -Render)
$sync["checkmarkrender"] = (Invoke-WinUtilAssets -Type "checkmark" -Size 512 -Render)
$sync["warningrender"] = (Invoke-WinUtilAssets -Type "warning" -Size 512 -Render)
Write-WinUtilPerformanceCheckpoint -Name "Assets rendered"
Initialize-WinUtilTaskbarOverlayAssets -IncludeLogo $true -IncludeStatusAssets $false
Set-WinUtilTaskbaritem -overlay "logo"
+4 -4
View File
@@ -52,10 +52,10 @@ WinUtil currently does too much work before the first GUI paint. Work from the t
## P6 - Asset And Theme Cost
- [ ] Measure `Invoke-WinUtilAssets -Render` calls during startup.
- [ ] Cache rendered logo, checkmark, and warning images once per process.
- [ ] Defer non-critical taskbar overlay assets until after first render if measurable.
- [ ] Verify taskbar overlay success/error states still display correctly.
- [x] Measure `Invoke-WinUtilAssets -Render` calls during startup.
- [x] Cache rendered logo, checkmark, and warning images once per process.
- [x] Defer non-critical taskbar overlay assets until after first render if measurable.
- [x] Verify taskbar overlay success/error states still display correctly.
## P7 - Verification