Skip to content

Commit 17af6b7

Browse files
committed
perf(render): add layout caching and smooth DataTree scroll rendering
- introduce layout caching and buffered frame reuse across the Views render pipeline - fix DataTree scroll artifacts, separator repaint gaps, and invalidation behavior during fast scrolling - prewarm deferred slices and SimpleRootSite layout work during idle time to reduce scroll latency - add optional render interaction tracing, parser tests, and tracing config/build script cleanup - fold in native/build/package cleanup and reviewer follow-up fixes needed to support the new path
1 parent cc63c4a commit 17af6b7

34 files changed

Lines changed: 2132 additions & 325 deletions

.github/instructions/debugging.instructions.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ description: "Runtime debugging and tracing guidance for FieldWorks"
4949

5050
## Dev switch (auto config)
5151
- FieldWorks now supports a swappable diagnostics config via `FieldWorks.Diagnostics.config`.
52-
- Default is quiet. `build.ps1` now enables the dev diagnostics config automatically for Debug builds unless you override `/p:UseDevTraceConfig`. You can also force it via `UseDevTraceConfig=true`, by setting environment variable `FW_TRACE_LOG` before the build, or by passing `-TraceCrashes` to `build.ps1`; the dev diagnostics file is copied as `FieldWorks.Diagnostics.config` in the output.
52+
- Default is quiet. Use `build.ps1 -EnableTracing` to copy the dev diagnostics file into the output as `FieldWorks.Diagnostics.config`. You can also force it via `UseDevTraceConfig=true` or by setting environment variable `FW_TRACE_LOG` before the build.
5353
- Dev log location: `Output/Debug/FieldWorks.trace.log` (relative to the app folder) so it’s easy to collect alongside binaries.
5454
- Dev config logs to `%temp%/FieldWorks.trace.log` and turns on the core switches above. Edit `Src/Common/FieldWorks/FieldWorks.Diagnostics.dev.config` to change log path or switches.
5555

@@ -59,5 +59,5 @@ description: "Runtime debugging and tracing guidance for FieldWorks"
5959

6060
## Proposed Improvements (dev-only)
6161
- Add `Docs/FieldWorks.trace.sample.config` with the snippet above for easy reuse.
62-
- Introduce a dev flag (`UseDevTraceConfig=true` or `FW_TRACE_LOG` env var) that copies the dev diagnostics file next to `FieldWorks.exe` in Debug builds so tracing is on by default for local runs.
62+
- Keep `build.ps1 -EnableTracing` as the single scripted path that copies the dev diagnostics file next to `FieldWorks.exe` for local trace-enabled runs.
6363
- Document standard trace switches in `Docs/logging.md` and keep `EnvVarTraceListener` as the default listener for dev traces.

.vscode/tasks.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,12 @@
8989
"label": "Test: RenderBaselineTests",
9090
"type": "shell",
9191
"command": ".\\test.ps1 -TestProject \"Src/Common/RootSite/RootSiteTests/RootSiteTests.csproj\" -TestFilter \"FullyQualifiedName~RenderBaselineTests\"",
92+
"options": {
93+
"shell": {
94+
"executable": "powershell.exe",
95+
"args": ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command"]
96+
}
97+
},
9298
"problemMatcher": [],
9399
"group": "test",
94100
"presentation": {

Build/Agent/FwBuildHelpers.psm1

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,110 @@ function Test-GitTrackedFile {
306306
}
307307
}
308308

309+
function Get-NewestWriteTimeUtc {
310+
<#!
311+
.SYNOPSIS
312+
Returns the newest LastWriteTimeUtc among matching files under one or more roots.
313+
#>
314+
param(
315+
[Parameter(Mandatory)][string[]]$Paths,
316+
[string[]]$IncludePatterns = @()
317+
)
318+
319+
$latest = [datetime]::MinValue
320+
foreach ($path in $Paths) {
321+
if (-not (Test-Path $path)) {
322+
continue
323+
}
324+
325+
$items = Get-ChildItem -Path $path -Recurse -File -ErrorAction SilentlyContinue
326+
if ($IncludePatterns.Count -gt 0) {
327+
$items = $items | Where-Object {
328+
$fileName = $_.Name
329+
foreach ($pattern in $IncludePatterns) {
330+
if ($fileName -like $pattern) {
331+
return $true
332+
}
333+
}
334+
return $false
335+
}
336+
}
337+
338+
foreach ($item in $items) {
339+
if ($item.LastWriteTimeUtc -gt $latest) {
340+
$latest = $item.LastWriteTimeUtc
341+
}
342+
}
343+
}
344+
345+
return $latest
346+
}
347+
348+
function Get-OldestWriteTimeUtc {
349+
<#!
350+
.SYNOPSIS
351+
Returns the oldest LastWriteTimeUtc across a set of required artifact files.
352+
Returns $null if any required artifact is missing.
353+
#>
354+
param(
355+
[Parameter(Mandatory)][string[]]$Paths
356+
)
357+
358+
$oldest = [datetime]::MaxValue
359+
$foundAny = $false
360+
foreach ($path in $Paths) {
361+
if (-not (Test-Path $path)) {
362+
return $null
363+
}
364+
365+
$item = Get-Item -LiteralPath $path -ErrorAction Stop
366+
$foundAny = $true
367+
if ($item.LastWriteTimeUtc -lt $oldest) {
368+
$oldest = $item.LastWriteTimeUtc
369+
}
370+
}
371+
372+
if (-not $foundAny) {
373+
return $null
374+
}
375+
376+
return $oldest
377+
}
378+
379+
function Test-ViewsNativeArtifactsStale {
380+
<#!
381+
.SYNOPSIS
382+
Returns $true when the Views/FwKernel native artifacts are missing or older than relevant native inputs.
383+
#>
384+
param(
385+
[Parameter(Mandatory)][string]$RepoRoot,
386+
[Parameter(Mandatory)][string]$Configuration
387+
)
388+
389+
$sourceRoots = @(
390+
(Join-Path $RepoRoot 'Src\views'),
391+
(Join-Path $RepoRoot 'Src\Kernel'),
392+
(Join-Path $RepoRoot 'Src\Generic'),
393+
(Join-Path $RepoRoot 'Include')
394+
)
395+
$sourcePatterns = @('*.cpp', '*.c', '*.cc', '*.h', '*.hpp', '*.ixx', '*.idl', '*.rc', '*.mak', '*.def', '*.bat')
396+
$artifactPaths = @(
397+
(Join-Path $RepoRoot "Output\$Configuration\Views.dll"),
398+
(Join-Path $RepoRoot "Output\$Configuration\views.lib"),
399+
(Join-Path $RepoRoot "Output\$Configuration\Common\FwKernelTlb.h"),
400+
(Join-Path $RepoRoot "Obj\$Configuration\Views\autopch\VwRootBox.obj")
401+
)
402+
403+
$latestSource = Get-NewestWriteTimeUtc -Paths $sourceRoots -IncludePatterns $sourcePatterns
404+
$oldestArtifact = Get-OldestWriteTimeUtc -Paths $artifactPaths
405+
406+
if ($oldestArtifact -eq $null) {
407+
return $true
408+
}
409+
410+
return $latestSource -gt $oldestArtifact
411+
}
412+
309413
# =============================================================================
310414
# Module Exports
311415
# =============================================================================
@@ -323,5 +427,8 @@ Export-ModuleMember -Function @(
323427
'Stop-ConflictingProcesses',
324428
'Remove-StaleObjFolders',
325429
'Test-IsFileLockError',
326-
'Invoke-WithFileLockRetry'
430+
'Invoke-WithFileLockRetry',
431+
'Get-NewestWriteTimeUtc',
432+
'Get-OldestWriteTimeUtc',
433+
'Test-ViewsNativeArtifactsStale'
327434
)

Build/Src/Directory.Packages.props

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,29 @@
11
<Project>
2+
<!-- Build infrastructure versions are centralized here rather than in the repo root CPM file. -->
3+
<Import Project="..\SilVersions.props" />
4+
25
<PropertyGroup>
36
<!--
4-
Build infrastructure projects (FwBuildTasks, NativeBuild) manage their own
5-
package versions independently. They do not contribute assemblies to the
6-
shared Output/ directory, so CPM transitive pinning does not apply here.
7-
FwBuildTasks also requires different versions of test infrastructure packages
8-
(NUnit3TestAdapter 5.2.0, SIL.TestUtilities 12.0.0-*) than the main codebase.
7+
Build infrastructure projects keep their package versions scoped to Build/Src.
8+
This avoids polluting the repo-root CPM file while still centralizing versions
9+
for FwBuildTasks and NativeBuild in one place.
910
-->
10-
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
11+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
1112
</PropertyGroup>
13+
14+
<PropertyGroup Label="NativeBuild Package Version Properties">
15+
<!-- NativeBuild.csproj is a legacy MSBuild project that still requires explicit Version attributes. -->
16+
<BuildSrcSilChorusL10nsVersion>3.0.1</BuildSrcSilChorusL10nsVersion>
17+
</PropertyGroup>
18+
19+
<ItemGroup Label="Build Infrastructure Packages">
20+
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="18.3.3" />
21+
<PackageVersion Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
22+
<PackageVersion Include="NUnit" Version="3.14.0" />
23+
<PackageVersion Include="NUnit3TestAdapter" Version="5.2.0" />
24+
<PackageVersion Include="SIL.BuildTasks" Version="3.2.0" />
25+
<PackageVersion Include="SIL.TestUtilities" Version="12.0.1" />
26+
<PackageVersion Include="System.Reflection.Metadata" Version="9.0.13" />
27+
<PackageVersion Include="System.Resources.Extensions" Version="9.0.13" />
28+
</ItemGroup>
1229
</Project>

Build/Src/FwBuildTasks/FwBuildTasks.csproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
<Prefer32Bit>false</Prefer32Bit>
2222
</PropertyGroup>
2323
<ItemGroup>
24-
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="18.3.3" />
25-
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="2.1.0" />
26-
<PackageReference Include="NUnit" Version="3.14.0" PrivateAssets="All" />
27-
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0" PrivateAssets="All" />
28-
<PackageReference Include="SIL.BuildTasks" Version="3.2.0" />
29-
<PackageReference Include="SIL.TestUtilities" Version="12.0.1" PrivateAssets="All" />
30-
<PackageReference Include="System.Reflection.Metadata" Version="9.0.13" />
31-
<PackageReference Include="System.Resources.Extensions" Version="9.0.13" />
24+
<PackageReference Include="Microsoft.Build.Utilities.Core" />
25+
<PackageReference Include="Microsoft.Extensions.DependencyModel" />
26+
<PackageReference Include="NUnit" PrivateAssets="All" />
27+
<PackageReference Include="NUnit3TestAdapter" PrivateAssets="All" />
28+
<PackageReference Include="SIL.BuildTasks" />
29+
<PackageReference Include="SIL.TestUtilities" PrivateAssets="All" />
30+
<PackageReference Include="System.Reflection.Metadata" />
31+
<PackageReference Include="System.Resources.Extensions" />
3232
<Reference Include="netstandard" />
3333
<Reference Include="Microsoft.Build.Framework" />
3434
<Reference Include="System.IO.Compression" />

Build/Src/NativeBuild/NativeBuild.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@
4343
</PropertyGroup>
4444
<!-- Reference to sil.lcmodel.core package for contentFiles. -->
4545
<ItemGroup>
46-
<PackageReference Include="SIL.LCModel.Core" Version="$(SilLcmVersion)" GeneratePathProperty="true">
46+
<PackageReference
47+
Include="SIL.LCModel.Core"
48+
Version="$(SilLcmVersion)"
49+
GeneratePathProperty="true">
4750
<IncludeAssets>none</IncludeAssets>
4851
<PrivateAssets>all</PrivateAssets>
4952
</PackageReference>
@@ -53,7 +56,7 @@
5356
They must be explicitly referenced here because NativeBuild.csproj is a traditional
5457
MSBuild project, not an SDK-style project, so it doesn't inherit from Directory.Build.props.
5558
-->
56-
<PackageReference Include="SIL.Chorus.L10ns" Version="3.0.1">
59+
<PackageReference Include="SIL.Chorus.L10ns" Version="$(BuildSrcSilChorusL10nsVersion)">
5760
<IncludeAssets>none</IncludeAssets>
5861
<PrivateAssets>all</PrivateAssets>
5962
</PackageReference>
@@ -68,10 +71,7 @@
6871
</PackageReference>
6972
</ItemGroup>
7073
<!-- Override the Build target to call native build instead -->
71-
<Target
72-
Name="Build"
73-
DependsOnTargets="allCppNoTest"
74-
>
74+
<Target Name="Build" DependsOnTargets="allCppNoTest">
7575
<Message Text="Native C++ components built successfully" Importance="high" />
7676
</Target>
7777
<!-- Ensure Clean works -->

Build/scripts/Invoke-CppTest.ps1

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -219,11 +219,9 @@ function Ensure-UnitPlusPlusLibrary {
219219

220220
function Ensure-TestViewsPrerequisites {
221221
if ($TestProject -ne 'TestViews') { return }
222-
$fwKernelHeader = Join-Path $WorktreePath "Output\$Configuration\Common\FwKernelTlb.h"
223-
$viewsObj = Join-Path $WorktreePath "Obj\$Configuration\Views\autopch\VwRootBox.obj"
224-
if ((Test-Path $fwKernelHeader) -and (Test-Path $viewsObj)) { return }
222+
if (-not (Test-ViewsNativeArtifactsStale -RepoRoot $WorktreePath -Configuration $Configuration)) { return }
225223

226-
Write-Host "[INFO] Missing native artifacts or generated headers required for TestViews." -ForegroundColor Yellow
224+
Write-Host "[INFO] Refreshing native artifacts and generated headers required for TestViews." -ForegroundColor Yellow
227225
Build-NativeArtifacts
228226
Build-ViewsInterfacesArtifacts
229227
}

FLExInstaller/Directory.Packages.props

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@
22
<PropertyGroup>
33
<!--
44
Installer projects use WiX-specific packages (WixToolset.Dtf.*) that are
5-
not shared with the main FieldWorks codebase. Opt out of CPM to avoid
6-
needing unnecessary entries in the root Directory.Packages.props.
5+
not shared with the main FieldWorks codebase. Keep those versions scoped
6+
to FLExInstaller, but centralize them here.
77
-->
8-
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
8+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
99
</PropertyGroup>
10+
11+
<ItemGroup Label="Installer Packages">
12+
<PackageVersion Include="WixToolset.Dtf.CustomAction" Version="6.0.0" />
13+
<PackageVersion Include="WixToolset.Dtf.WindowsInstaller" Version="6.0.0" />
14+
</ItemGroup>
1015
</Project>

FLExInstaller/wix6/Shared/CustomActions/CustomActions/CustomActions.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
<Content Include="CustomAction.config" CopyToOutputDirectory="PreserveNewest" />
1111
</ItemGroup>
1212
<ItemGroup>
13-
<PackageReference Include="WixToolset.Dtf.CustomAction" Version="6.0.0" />
14-
<PackageReference Include="WixToolset.Dtf.WindowsInstaller" Version="6.0.0" />
13+
<PackageReference Include="WixToolset.Dtf.CustomAction" />
14+
<PackageReference Include="WixToolset.Dtf.WindowsInstaller" />
1515
</ItemGroup>
1616
<ItemGroup>
1717
<Reference Include="System.Windows.Forms" />

SDK_MIGRATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ With CPM ensuring all projects resolve to the same package version, most manual
262262
- Initializes VS Developer environment
263263
- Supports `/m` parallel builds
264264
- **Stale DLL detection**: Runs `Remove-StaleDlls.ps1` pre-build to catch version-mismatched binaries
265-
- **Diagnostics config**: Optionally copies dev trace config for Debug builds (`-TraceCrashes` or `UseDevTraceConfig`)
265+
- **Diagnostics config**: Optionally copies dev trace config for Debug builds (`-EnableTracing` or `UseDevTraceConfig`)
266266
- **Installer support**: `-BuildInstaller` flag triggers full installer build pipeline
267267

268268
**Note**: `build.sh` is not supported in this repo (FieldWorks is Windows-first). Use `.\build.ps1`.

0 commit comments

Comments
 (0)