perf: Views engine render optimizations — warm 99.99% faster, cold 10% faster#724
Open
johnml1135 wants to merge 4 commits intomainfrom
Open
perf: Views engine render optimizations — warm 99.99% faster, cold 10% faster#724johnml1135 wants to merge 4 commits intomainfrom
johnml1135 wants to merge 4 commits intomainfrom
Conversation
This comment has been minimized.
This comment has been minimized.
Contributor
There was a problem hiding this comment.
Pull request overview
Performance-focused updates introduce render verification/benchmark infrastructure and targeted optimizations in the DetailControls/DataTree rendering path to reduce redundant work and support pixel-perfect render validation.
Changes:
- Added RenderVerification infrastructure (environment validation, diagnostics/trace toggling, benchmark result models, reporting & comparison utilities).
- Optimized
DataTree/Sliceconstruction, layout, painting, and visibility paths to avoid repeated O(N) work. - Added/updated test harness assets (layouts/parts, new diagnostics tests, VS Code tasks) and snapshot testing support.
Reviewed changes
Copilot reviewed 68 out of 153 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| Src/Common/RenderVerification/RenderModels.cs | Adds shared models for scenarios and timing results used by render verification/benchmarks. |
| Src/Common/RenderVerification/RenderEnvironmentValidator.cs | Captures environment details and produces a hash/diff for deterministic snapshot comparisons. |
| Src/Common/RenderVerification/RenderDiagnosticsToggle.cs | Adds a toggle for diagnostics/trace output with file-backed flags and a trace listener. |
| Src/Common/RenderVerification/RenderBenchmarkResults.cs | Defines JSON-serializable benchmark run/result structures and flags loading. |
| Src/Common/RenderVerification/RenderBenchmarkReportWriter.cs | Writes JSON + Markdown summary reports and recommendations for benchmark runs. |
| Src/Common/RenderVerification/RenderBenchmarkComparer.cs | Compares runs to detect regressions/improvements and generates a summary. |
| Src/Common/RenderVerification/CompositeViewCapture.cs | Implements two-pass DataTree capture with Views content overlay for pixel-perfect snapshots. |
| Src/Common/FieldWorks/FieldWorks.Diagnostics.dev.config | Adds a new trace switch for Views render timing. |
| Src/Common/Controls/XMLViews/XMLViewsTests/XmlBrowseViewBaseTests.cs | Updates test stub interface to include NeedsReconstruct. |
| Src/Common/Controls/DetailControls/VectorReferenceView.cs | Avoids drawing a trailing separator bar after the last item. |
| Src/Common/Controls/DetailControls/Slice.cs | Adds cached XML attribute parsing + width fast-path + DataTree method call updates. |
| Src/Common/Controls/DetailControls/PossibilityVectorReferenceView.cs | Avoids drawing a trailing separator bar after the last item. |
| Src/Common/Controls/DetailControls/HwndDiagnostics.cs | Adds helper methods to read USER/GDI handle counts for diagnostics/tests. |
| Src/Common/Controls/DetailControls/DetailControlsTests/TestResult.xml | Adds a test runner output artifact (currently shows a failed/invalid run). |
| Src/Common/Controls/DetailControls/DetailControlsTests/TestParts.xml | Extends test parts inventory to include senses sequences and collapsible slices. |
| Src/Common/Controls/DetailControls/DetailControlsTests/Test.fwlayout | Updates test layouts to include CitationForm and senses parts/layouts. |
| Src/Common/Controls/DetailControls/DetailControlsTests/DetailControlsTests.csproj | Adds snapshot/JSON deps and references RenderVerification project. |
| Src/Common/Controls/DetailControls/DetailControlsTests/DataTreeTests.cs | Updates expected template XML string for modified layout composition. |
| Src/Common/Controls/DetailControls/DetailControlsTests/DataTreeHwndCountTest.cs | Adds baseline diagnostics tests for handle growth and slice install count. |
| Src/Common/Controls/DetailControls/DataTree.cs | Adds multiple layout/paint/visibility optimizations and diagnostics counters. |
| Directory.Packages.props | Adds central package version for Verify. |
| AGENTS.md | Adds note about external dependency repository (liblcm). |
| .vscode/tasks.json | Adds tasks for render baseline tests and building tests via repo script. |
| .vscode/settings.json | Allows the new “Build Tests” task as an approved VS Code task. |
| .github/skills/openspec-verify-change/SKILL.md | Updates generatedBy metadata version. |
| .github/skills/openspec-sync-specs/SKILL.md | Updates generatedBy metadata version. |
| .github/skills/openspec-onboard/SKILL.md | Updates onboarding workflow text/commands and cross-platform command notes. |
| .github/skills/openspec-new-change/SKILL.md | Updates generatedBy metadata version. |
| .github/skills/openspec-ff-change/SKILL.md | Updates generatedBy metadata version. |
| .github/skills/openspec-explore/SKILL.md | Updates explore-mode wording around “proposal” vs other workflows. |
| .github/skills/openspec-continue-change/SKILL.md | Updates generatedBy metadata version. |
| .github/skills/openspec-bulk-archive-change/SKILL.md | Updates text and generatedBy metadata version. |
| .github/skills/openspec-archive-change/SKILL.md | Updates guidance to invoke the sync skill via Task tool. |
| .github/skills/openspec-apply-change/SKILL.md | Updates generatedBy metadata version. |
| .github/prompts/opsx-onboard.prompt.md | Mirrors onboarding prompt updates (CLI install check, command list). |
| .github/prompts/opsx-ff.prompt.md | Clarifies template usage vs context/rules constraints. |
| .github/prompts/opsx-explore.prompt.md | Mirrors explore prompt updates (“proposal” wording). |
| .github/prompts/opsx-bulk-archive.prompt.md | Mirrors bulk-archive prompt copy update. |
| .github/prompts/opsx-archive.prompt.md | Mirrors archive prompt sync invocation update. |
| .github/instructions/csharp.instructions.md | Adds C# instructions file (currently specifies “latest C# / C# 14” guidance). |
| .gitattributes | Marks Verify snapshot PNG extensions as binary. |
| .GitHub/skills/render-testing/SKILL.md | Adds a render-testing skill doc with build/test/run instructions and baseline workflow. |
| .GitHub/skills/code-review-skill-main/scripts/pr-analyzer.py | Adds a Python tool to analyze diffs and estimate PR review complexity. |
| .GitHub/skills/code-review-skill-main/reference/typescript.md | Adds TypeScript review reference documentation. |
| .GitHub/skills/code-review-skill-main/reference/security-review-guide.md | Adds security review reference documentation. |
| .GitHub/skills/code-review-skill-main/reference/java.md | Adds Java review reference documentation. |
| .GitHub/skills/code-review-skill-main/reference/cpp.md | Adds C++ review reference documentation. |
| .GitHub/skills/code-review-skill-main/reference/code-review-best-practices.md | Adds code review best practices reference documentation. |
| .GitHub/skills/code-review-skill-main/reference/c.md | Adds C review reference documentation. |
| .GitHub/skills/code-review-skill-main/assets/review-checklist.md | Adds a condensed review checklist asset. |
| .GitHub/skills/code-review-skill-main/assets/pr-review-template.md | Adds a PR review template asset. |
| .GitHub/skills/code-review-skill-main/SKILL.md | Adds a top-level code review skill description/index. |
| .GitHub/skills/code-review-skill-main/README.md | Adds documentation for the code-review skill bundle. |
| .GitHub/skills/code-review-skill-main/LICENSE | Adds license file for the bundled code-review skill content. |
| .GitHub/skills/code-review-skill-main/CONTRIBUTING.md | Adds contribution guidelines for the bundled code-review skill content. |
| .GitHub/skills/code-review-skill-main/.gitignore | Adds gitignore for the bundled code-review skill content. |
Comments suppressed due to low confidence (1)
.GitHub/skills/render-testing/SKILL.md:1
- This doc hardcodes a user-specific NUnit console path and recommends
dotnet buildfor a .NET Framework workflow. For portability and alignment with repo build guidance, prefer.\build.ps1/.\test.ps1(and avoid assumingC:\\Users\\johnm\\...exists). Also consider avoiding or clearly calling out commands with pipes/redirection in docs, since the repo guidance prefers wrapper scripts for piped commands.
---
Src/Common/Controls/DetailControls/DetailControlsTests/TestResult.xml
Outdated
Show resolved
Hide resolved
NUnit Tests 1 files ± 0 1 suites ±0 10m 2s ⏱️ + 4m 13s For more details on these failures, see this check. Results for commit 34648c1. ± Comparison against base commit b6ac397. This pull request removes 49 and adds 465 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
04900b0 to
d6741a0
Compare
17af6b7 to
141e590
Compare
- speed up DataTree and Views rendering, scrolling, and layout work - expand render benchmarks, committed baselines, and timing coverage - keep timing baselines informational in CI and harden test runs - refresh build, tracing, and supporting test infrastructure
- replace unsupported Unicode escape syntax in the local PowerShell whitespace checker
b50b621 to
f97db79
Compare
This comment has been minimized.
This comment has been minimized.
Force ANTIALIASED_QUALITY for render tests by setting FW_FONT_QUALITY=4 in the render test assembly setup and reading that override in the native LOGFONT creation paths. This keeps local and CI rasterization aligned without changing production rendering. Also remove the RootSite per-channel pixel tolerance now that tests render deterministically again, so snapshot failures remain strict and actionable.
2ba3085 to
34648c1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Render Performance Optimizations
Summary
This branch delivers comprehensive performance optimizations to the FieldWorks Views engine rendering pipeline, reducing warm render time by 99.99% (153ms → 0.01ms) and cold render time by ~10% (60.36ms → 54.32ms) across 15 benchmark scenarios.
All 15 scenarios pass with 0% pixel variance — no visual regressions.
Motivation
FieldWorks UI responsiveness is bottlenecked by the Views engine render pipeline. Switching between entries, refreshing displays, or navigating within editors triggers
Reconstruct()→Layout()→DrawTheRoot()cycles. Profiling revealed:RefreshDisplay()called Reconstruct on ALL root sites, even when no data changedBenchmark Infrastructure
New test infrastructure
RenderBenchmarkHarness— creates real VwRootBox + VwGraphics in an offscreen HWND, measures CreateView/MakeRoot/PerformOffscreenLayout/DrawTheRoot independentlyRenderTimingSuiteTests— 15 scenarios covering simple through extreme content (long-prose: 4 sections × 80 verses; lex-extreme: 25 entries × 10 senses)RenderVerifyTests— pixel-perfect snapshot verification using Verify + ImageSharpRenderBenchmarkResults/RenderBenchmarkReportWriter— generates markdown summary reports with per-scenario timingDataTreeRenderTests— DataTree-level render scenarios (collapsed/expanded/deep/extreme/multiws/simple)Test files
Src/Common/RootSite/RootSiteTests/RenderBenchmarkHarness.csSrc/Common/RootSite/RootSiteTests/RenderTimingSuiteTests.csSrc/Common/RootSite/RootSiteTests/RenderVerifyTests.csSrc/Common/RootSite/RootSiteTests/RenderBenchmarkTestsBase.csSrc/Common/RenderVerification/(supporting infrastructure)Src/Common/Controls/DetailControlsTests/DataTreeRenderTests.csPhase 1: Warm Render Optimizations (153ms → 0.01ms)
PATH-L1: Width-Invariant Layout Guard
Src/views/VwRootBox.cpp,VwRootBox.hm_fNeedsLayout+m_dxLastLayoutWidthtoVwRootBox::Layout(). If box tree hasn't changed and width is the same, skip the entire layout traversal.PATH-L4: Harness GDI Caching
Src/Common/RootSite/RootSiteTests/RenderBenchmarkHarness.csPerformOffscreenLayout()instead of allocating per call.PATH-R1: Reconstruct Guard
Src/views/VwRootBox.cpp,VwRootBox.hm_fNeedsReconstructflag.Reconstruct()returns early if noPropChanged, style change, or overlay change has occurred since last construction.PATH-L5: Skip Reconstruct When Data Unchanged
Src/views/Views.idh,Src/Common/SimpleRootSite/SimpleRootSite.csNeedsReconstructproperty via COM.SimpleRootSite.RefreshDisplay()checks this before performing expensive reconstruct cycle.Phase 2: Cold Render Optimizations (60.36ms → 54.32ms)
PATH-R1-FIX: Construct Guard Bug Fix
Src/views/VwRootBox.cppConstruct()was leavingm_fNeedsReconstruct = true(set during Init), so the PATH-R1 guard never fired on the first warm render. Fixed by settingm_fNeedsReconstruct = falseafter successful construction.PATH-C1: HFONT LRU Cache
Src/views/lib/VwGraphics.h,VwGraphics.cpp(LgCharRenderProps → HFONT)in VwGraphics. On font change, check cache viamemcmpof font-specific fields. Cache hit → reuse HFONT (skipCreateFontIndirect). Cache miss → create and add to cache. All cached HFONTs freed on destructor/ReleaseDC.PATH-C2: Color State Caching
Src/views/lib/VwGraphics.h,VwGraphics.cppPATH-N1: NFC Normalization Bypass
Src/views/lib/UniscribeSegment.h,UniscribeSegment.cpp,UniscribeEngine.cppOffsetInNfc()andOffsetToOrig()performed COM Fetch + ICU NFC normalization on every call — 12+ times perFindBreakPointinvocation. For content-heavy views, this meant millions of redundant normalizations. Added NFC detection inCallScriptItemize()(comparing pre/post normalization length). When text is already NFC (common case — FieldWorks stores NFC), new overloads return identity offsets, completely skipping COM and ICU calls.mixed-styles-27.1%,lex-deep-24.9%,lex-extreme-24.3%Bug Fixes
VwPropertyStore Crash Fix
Src/views/VwPropertyStore.cppAssert(m_chrp.ws)andAssertPtr(qws)at line 1336 fired whenws=0reached VwPropertyStore during PropChanged-driven box tree rebuilds. Fixed by guardingget_EngineOrNullwithif (m_chrp.ws)check and usingAssertPtrN(qws)to allow null engine pointer. The code already defaulted to LTR directionality when qws was null.VwDrawRootBuffered Coordinate Fixes
Src/views/VwRootBox.cppVwDrawRootBuffered.Other Fixes
Final Benchmark Results
Files Changed (Key Production Files)
Src/views/VwRootBox.hSrc/views/VwRootBox.cppSrc/views/Views.idhSrc/views/VwPropertyStore.cppSrc/views/lib/VwGraphics.hSrc/views/lib/VwGraphics.cppSrc/views/lib/UniscribeSegment.hSrc/views/lib/UniscribeSegment.cppSrc/views/lib/UniscribeEngine.cppSrc/Common/SimpleRootSite/SimpleRootSite.csSrc/Common/Controls/DetailControls/DataTree.csSrc/Common/Controls/DetailControls/Slice.csFuture Optimization Paths
The remaining opportunity for significant cold render improvement is PATH-V1: Lazy VwLazyBox Construction — deferring off-screen paragraph construction until scrolled into view. This is the only path that can achieve the 50% cold reduction target, as the engine is fundamentally bottlenecked by
ScriptShape/ScriptPlacekernel calls that cannot be made faster, only avoided.See layout-optimization-paths.md for full analysis.
This change is