Integrate native fonts and Vulkan GUI backend into PRK.Client
## Root integration task — next-session entry point ### Outcome Make the real PRK.Client render its retained XML/Lua interface through PRK.Gui.Vulkan and measure/draw/interact with text through shared PRK.Fonts layout geometry. Continue through full replacement, not merely development slices. Preserve the existing UI's appearance, layout and behavior within reason; this is a backend migration, not a redesign. Replace CPU Skia UI rasterization/full-surface staging while preserving scripts, saved layouts and native physical-resolution text. User requests prioritizing implementation and ordinary behavior/build/lifetime checks now; defer extensive pixel comparisons to final verification instead of repeatedly comparing intermediate captures. This task is the root for integration slices; the merged foundations must be reused, not rebuilt. ### Start here - PR #2865 is merged: https://git.project-rk.com/prk/engines/pulls/2865. Updated local develop and origin/develop to 86cd49c3498f5687ec5bdb216d1f4d056ef0f7ae. That head also includes #2864 (combat-safe NCU/loot/Skills updates) and #2863 (Lua chat/combat presentation and virtualized scrollback). - /home/mathias/Projects/worktrees/engines-gpu-ui is now on feature/integrate-vulkan-gui, created from fetched origin/develop 86cd49c34. It contains uncommitted native package/CI preparatory changes described below; these are this task's work, not unrelated edits. /home/mathias/Projects/engines remains clean on fix/client-combat-window-updates and must not be switched or have its work carried into integration. - Resume on the existing integration branch, inspecting its diff first; do not recreate/reset it or continue the merged feature/gpu-ui-renderer branch. Repository/client instructions and native Lua/audio/font package conventions were read. No commits or pushes were requested or made. - Keep the Windows VM off. User paused VM testing. Do not start it or retry the old capture export without explicit permission. No feature review was requested; do not run review_feature automatically. ### Merged components to reuse - PRK.Client/PRK.Fonts: owned scalable font faces, immutable runs/coverage, UTF-16 source clusters, metrics, direction selection, missing-glyph reporting and bounded LRU shaping. Shaping/rasterization of misses is CPU work; cached coverage is not scaled to another size. Faces are thread-affine. - PRK.Client/PRK.Fonts.Vulkan: native-size/phase glyph atlases, frame-slot buffers, DrawRange for painter-order interleaving and integer target origins for cropped layers. - PRK.Client/PRK.Gui: physical-pixel paint lists, rounded rectangles/inside borders, immutable RGBA images, nine-slice, rectangular clips and balanced isolated-opacity scopes. - PRK.Client/PRK.Gui.Vulkan: caller-owned Vulkan device/allocator/queue/fences, linear-premultiplied images, ordered batches, cropped per-slot RGBA16F group targets and explicit upload/content commit/discard. RecordUploads then RecordLayers must run outside the root render pass; Draw runs inside a compatible single-color/single-sample/no-depth pass. Commit only after successful queue submission. Retire resources only after all referencing work is complete. Budgets currently refuse oversized frames; production integration needs a usable bounded cache/pressure policy rather than crashing or leaving the GUI blank. - PRK.Client/PRK.TextPlayground remains an independent native font/GUI consumer and regression control, not the production integration target. Preserve it. ### Baseline integration seams and hazards — historical; current implementation below - PRK.GraphicsEngine/UIRenderer.cs still owns GuiSurface, GuiLayoutEngine and GuiInputManager. PrepareFrame performs layout, CPU paint and staging; RecordUpload uploads the Skia surface; RecordFrame draws the UI, screen cover and cursor. Resize recreates CPU and GPU surface/staging resources. Replace the paint/upload mechanism rather than recreating widget state or losing cursor/cover ordering. - PRK.GraphicsEngine/RendererVulkan.cs creates UIRenderer only for windowed output. Its frame preparation calls UIRenderer.PrepareFrame. Command recording uploads UI before RecordCompositePass; that method resolves scene AA, draws display overlays and then the UI inside the composite pass. Layer passes must be recorded outside that pass. Headless renderer construction currently omits UIRenderer, so tests that never instantiate the GUI do not validate integration. - GuiContext already distinguishes logical layout, platform-window input, framebuffer dimensions and UI scale. Commit one consistent metrics/layout/paint/input view during resize; do not independently sample dimensions into mismatched subsystems. Render UI at output resolution after world AA/upscaling, independent of world render scale. - GuiLayoutEngine still measures SKFont; GuiTextLayout, GuiTextSelection and GuiInputManager have separate measurement/index/caret paths. Use one shaped result for measure, wrap, glyph placement, links, selection and caret geometry. Preserve .NET UTF-16 source identity while handling graphemes, ligatures and direction correctly; do not sum isolated character widths as a replacement. - Current develop includes GuiVirtualTextLog and GuiTextIndex. Preserve logical message identities, offscreen selection/copy, scroll anchors, viewport materialization and paced reflow. Width changes must not restore retained-history-wide paint/format work or per-frame Lua formatting. - GuiView, GuiGraphicsArchive and other UI boundaries still expose Skia colors/rectangles/bitmaps. GuiGraphicsArchive masked bitmaps are premultiplied; GuiImage expects straight-alpha sRGB input and converts to linear premultiplication itself. Normalize byte order, alpha association, color-key masks and color space exactly once; avoid double premultiplication. Narrow adapters/asset normalization are appropriate initially. Removing Skia from unrelated image decoding/tools is not a prerequisite. - GuiSkiaRenderer contains the actual widget paint behaviors: chrome, sprites, sliders/bars, tabs, selection/caret, link underlines, map/panned surfaces/markers/fans and overlays. Inventory every reachable behavior before cutover. Add missing backend primitives/effects only for real consumers; do not silently omit widgets or rasterize whole windows as a hidden fallback. - PresentationRefreshSchedule still has a 500 ms resize interval. Trace RefreshPresentation/RecreateSwapChain and world-target/GPU-maintenance costs before replacing the policy. Do not merely delete the interval and claim resize is fixed. Preserve minimize/restore, out-of-date handling and input alignment without stretching an old UI/text surface. - Current APIs have bounded glyph entries/atlas space, image/layer budgets and a 256-physical-pixel font-size limit. Exercise actual allowed UI scale/DPI combinations and long sessions; extend limits/paging/retirement where required rather than choosing a nearby raster size, dropping visible content or reducing existing UI capabilities silently. ### Execution sequence 1. Establish the current-client baseline and a coverage map. Trace ownership and the real frame/render-pass/text/input/asset chain on latest develop. Reuse the existing UI behavior tests, Lua package fixtures, virtual chat and AOT acceptance drivers. Record controlled resize, idle, scroll, append and asset-lifetime workloads before changing defaults. 2. Make native fonts a normal client dependency. Define a licensed deterministic font catalog with explicit regular/italic/family/fallback behavior, reusing suitable existing assets. Package the target-native bridge and required dependencies/notices for development, CI and release/AOT paths rather than depending on system Arial or the playground output directory. Inspect NativeLua/NativeAudio package conventions before adding another packaging scheme. 3. Introduce shared shaped text geometry and the retained paint adapter. Preserve GuiView/XML/Lua contracts and native action authority. Reuse layout invalidation, render order and input routing; avoid a parallel widget or scripting system. Keep mutable paint/font work on the established owner thread unless a measured need justifies immutable cross-thread snapshots. Implement cluster-aware wrap/selection/caret/link mapping while keeping virtual logs bounded. 4. Deliver a representative real-client vertical slice before broad rollout. Use existing retained-window/input/Lua acceptance fixtures covering chrome, label/button, text field, scrolling, clipping, opacity and a link, then run the same route in a client front-end scene and a Lua-owned window. A temporary explicit development selector can preserve the old path as a comparison control. It must be diagnosable and must not silently drop unsupported widgets. Do not switch the shipping default at this point. 5. Complete widget/effect and frame coverage. Translate the remaining reachable widgets, maps/panned content/markers, tooltips, drag visuals, selection and overlays. Implement missing true dimming/color-filter semantics and exceptions on top of isolated layers; preserve screen cover and cursor ordering. Wire actual frame slots, descriptor/image retirement, cancellations, pass compatibility and scene/display changes through the engine's existing lifetime machinery. Audit SDR/HDR encoding and UI luminance rather than assuming the SDR playground proves the client display path. 6. Fix real presentation/resize behavior and cut over. Choose the resize/presentation policy from measurements and the ordering design. Verify framebuffer-native text during continuous resize, UI-scale changes, minimize/restore and display transitions, with stable caches and bounded resource growth. After complete coverage and validation, make the GPU route the normal client path, remove the superseded Skia UI rasterizer/staging/bitmap-cache path and any temporary selector. Keep only genuinely unrelated Skia decode/tool dependencies. ### Acceptance criteria - Normal client builds/publishes can load the required native font assets without manual copying from the playground. CI exercises the native/font and actual GUI integration path, including AOT; build/publish diagnostics identify missing platform assets. - The existing retained/Lua UI renders through the Vulkan painter with the same information, commands, saved geometry, input routing and combat security/lockdown semantics. No protocol/game-rule changes or unrelated UI redesign are included. - Text measurement, wrapping, drawing, caret, links and selection share shaped geometry and stable source identities. Supported text/families/styles have deliberate fallback/refusal behavior. Fractional scale/DPI never stretches cached text or uses an old-size placeholder. - Chat virtualization, scroll anchoring, logging and offscreen copy remain intact. Idle/viewport work stays bounded; moving a panel does not reformat its text or reupload unchanged assets. - Transparent images, painter order, nested clips/groups, dimming exceptions, covers/cursors and all reachable special widgets behave correctly. Resource exhaustion is diagnosable and does not produce a partially visible or permanently unusable interface. - Resize and display transitions preserve native-output UI and input geometry, with no 500 ms UI-stretch workaround, use-after-free, pending-reference destruction or unbounded retained resources. Layer/asset replacement is safe with actual frames in flight. - Controlled baseline/candidate workloads demonstrate the intended CPU/upload/resize behavior. Report frame-time percentiles, layout/shaping/prepare cost, allocations, upload volume and memory with identical scene/assets/history/scale/frame settings; do not infer whole-game FPS improvements from a standalone sample. - Relevant client/graphics/Lua/virtual-chat tests, generator checks, native sanitizers, Native AOT, actual Vulkan synchronization/teardown and installed-asset visual/input checks pass. Linux first; Windows/platform checks require user permission before restarting the VM. HDR/mixed-DPI requirements must be explicitly checked or remain named release gates. No failing check is disabled and incomplete coverage is not turned into approval. ### Validated foundation and limits to carry forward Merged foundations passed Linux Release/Native AOT with 1/3 frame slots on RX9070, native CTest and sanitizers, owned-result/UTF-16/family/cache acceptance, and pixel controls for mixed painting and isolated opacity. Twelve opacity captures match across local modes; non-layered GUI/font controls remain unchanged. These are foundation checks, not proof of real-client integration or a game performance improvement. Windows font and earlier non-layered GUI/input runs passed on GTX1070; final opacity/current-source Windows follow-up and capture export remain deferred. Full client/server solution, HDR, mixed-monitor DPI and production native RID packaging were not established by the foundation PR. ### Current implementation and verified outcome — resume here The retained UI has now cut over to the GPU-only normal path. UIRenderer no longer creates a CPU GUI surface or full-screen pixel staging and the temporary backend selector is removed. Existing GuiView/XML/Lua/input/action contracts are preserved. Old Skia GUI renderer/surface/resources are under TestSupport/LegacyGui and compiled only into reference tests. Actual normal installed front-end and Lua Actions work, not only an isolated fixture. Coverage includes normal/title chrome, ordinary/custom buttons, tabs, combo/field links, scrollbars, item annotations, maps/panned surfaces/markers/sectors, opacity/grayscale dimming exceptions, drag/tooltips and GPU screen-cover source composition. Profiler graphs now emit vector strokes/text rather than CPU bitmaps. Bundled Liberation Sans regular/italic plus DejaVu fallback have notices; existing Arkhip remains a title asset. Native font ABI is now 3 (ICU paragraph/script data and conservative ink bounds); rebuild all old native packages, including paused Windows output. Shared native lines drive layout/paint/wrap/links/selection/editing, with UTF-16 source identities and bounded viewport/background virtual-chat reflow. Internal ligature caret stops remain intentionally whole-cluster. Image LRU observes prepared/submitted references; glyph/layer pressure triggers completed-GPU maintenance and visible-set rebuild rather than whole-window raster fallback. New pressure control was tested red/green. Fixed native-size viewport culling and tested clipped 1000-glyph runs/atlas reclamation. Screen-cover test proves source-sized 2x1 RGBA16F upload and correct linear premultiplication/fade readback, not screen-sized CPU composition. Resize policy was measured on RX9070: forced presentation rebuilds around 9–12 ms at 1080p, 23–25 ms at 4K versus ordinary empty frames around 1–2 ms. Removed the 500 ms stretch interval; commit current drawable metrics/layout before client/input update, with zero/minimized and same-size restore handling. A real resize test exposed stale queued debug names targeting destroyed shader handles; DebugUtils is now device-owned and names live handles synchronously. Real 1/3-slot resize/scale tests pass. Native packaging: prepare-client-fonts.sh for local Linux launchers, executable-owned target validation, and pinned vcpkg BuildPackage.cmake for linux-x64/win-x64/osx-arm64 dependencies/notices. Linux release package built and links only libc/libm/libgcc, not external FreeType/HarfBuzz/ICU shared libraries. Release workflow and macOS setup updated; actual production Linux Native AOT client publish succeeded with package guards. Native audio package was also built in the CI image. Platform recipe/source updates are not Windows/macOS execution evidence. Full-client GUI Native AOT now passes. Added PRK.Client.Gui.AotTests sharing installed acceptance with managed tests; --fixture runs real Engine/UIRenderer/Lua/input without game data for CI, default mode loads installed front-end with isolated temporary preferences. A version-pinned build-only Mono.Cecil compatibility transform annotates Silk.NET 2.23 platform constructor preservation and guards unavailable assembly-file/deps lookup under AOT. No shared NuGet mutation; removed old IL2072/IL3000/IL3002 blanket suppressions. Production Native AOT publish and actual GUI AOT both compile without those warnings; actual installed GUI AOT passes on RX9070, and --fixture passes Xvfb/lavapipe. BuildTools/SilkAotCompatibility/README.md documents the narrowly scoped transformation. License/notice included. Latest verification: - Full PRK.Client.sln Debug build: zero warnings/errors. - Graphics tests 716 passed; client tests 4,179 passed / 44 existing installed/audio skips; non-window Vulkan 28 passed / 1 existing skipped; four windowed retained/resize cases passed on Xvfb/lavapipe (1/3 slots). - Native CTest with ASan/UBSan passed. Core font Native AOT and Lua UI AOT acceptance passed, including zero-allocation warm shaping and full chat/Actions/Hotbar/combat capability regressions. - Actual installed front-end/Lua Actions managed acceptance and latest Native AOT acceptance passed on RX9070 with clean Vulkan error checks and teardown. Driver/loader/libdecor warnings and unused vertex-attribute performance warnings remain environment/existing diagnostic noise, not hidden validation errors. - Final paired visual review of installed front-end/Actions grid and scaled list: .dev-data/gui/installed-final/native-{20,70,140}.png and reference equivalents. Reference is the test-only old painter over the current retained layout on black; native includes the 3D sky. Title/login chrome, fields, controls and text are visibly retained; not a pixel-identical old-layout baseline or whole-game coverage claim. - XML/YAML parsing (17 changed/new files), shell syntax and git diff --check passed. Current Docker/ci tree/tag is 8cf3ba6438dd, referenced by both CI jobs. Local image prk-engines-ci-fonts:local tested; not pushed and hosted CI not run. Nameplate/legacy-removal continuation implemented and verified in tsk_23s9wcf4rf. Native world canvas/overlay now reuses shared font/GUI rendering with physical-size outlined bold labels, brackets, health/organization bands, reverse-depth occlusion and scene-luminance backdrop panels. Deleted TargetIndicatorArt, the old nameplate shader, all LegacyGui test renderer/surface/font/cache code and unused legacy font assets. Migrated rendering tests to actual Vulkan/readback; removed remaining UI SKFont/SKTypeface measurement helpers. Latest: 718 graphics, 4,179 client (44 existing skips), 32 Vulkan (one opt-in skip), real installed RX9070/Lua/nameplate managed and Native AOT, Lua UI AOT, native sanitizers and production Linux Native AOT publish pass. New depth/subpixel controls were verified red/green; inspected final nameplate screenshot .dev-data/gui/native-nameplates-final/native-140.png. This follow-up remains uncommitted; checkpoint 9b635a77b is committed. No shipping/UI text rasterization or old Skia painter remains; Skia stays at image decoding/conversion boundaries. Actual cancellation/submission fault injection, broader installed UI/long-session workloads, controlled baseline/candidate performance data, HDR/mixed-monitor DPI and platform release execution/signing remain gates. Windows VM stays off. User requested committing the validated cutover, then finishing native nameplates and removing the old Skia system, including the test-only legacy renderer. Cutover committed as 9b635a77b (feature: Replace retained UI rasterization with native Vulkan rendering). No push/review occurred; original checkout remains clean. Nameplate and legacy-removal implementation is now complete and locally validated in the uncommitted follow-up. ### Expanded Linux validation — verified outcome User requested maximum practical Linux testing and actual client startup; Windows remains unavailable/off. All tests below ran locally on Linux, using RX9070 where graphics were needed and Xvfb/lavapipe for isolated display/software controls. User requested committing the validated work. Rendering/nameplate/Skia-removal and validation fixes are committed as cacb3967d (feature: Render nameplates natively and remove legacy Skia UI); feedback-audit correction/regression is committed separately as 3a2141c09 (fix: Exclude synthetic client fixtures from feedback audits), after checkpoint 9b635a77b. Integration worktree is clean. No review or push. Final unique MSTest coverage: 4,365 client tests passed across full installed run and explicit asset/profiler/virtual-display reruns; 719 graphics (including installed water), 71 allocator, all 43 hardware Vulkan (including opt-in AA benchmark), 5,946 server unit tests with disposable SQL and proper augmented server RDB, 118 navigation, 14 deployment and 5 web tests passed: 11,281 distinct cases total. Navigation's offline dump-derived tile-corpus check remains unavailable. External login/chat/PFE service integration tests and Windows-only projects were not run. Full ao-emu.sln Debug build succeeded with zero errors and 349 repository warnings, not a warning-free whole-tree claim. Installed coverage includes every shipped playfield surface, animation clip and area-table sweep, original GUI/Lua window rendering, original audio codecs and OpenAL null-driver playback. Initial missing published shader failure was the wrong PRK_DATAROOT; applying the real POSIX release shader preparation (302 artifacts) and using the publish directory passed without weakening the test. Initial optional server RDB failures used raw client data lacking rdb_9000001; all 13 related cases passed with the actual augmented server fixture mounted read-only. SQL-backed trade/portal tests ran on a temporary private Docker network with no host port exposure; database/container/network and ephemeral credential files were removed afterward. Actual normal Native AOT PRK.Client executable started on the KDE Wayland desktop with isolated XDG preferences, remained running, resized to 1440x900 and exited 0 via its native window-close request. Temporary PID-targeted KWin scripts were unloaded. Actual Debug PRK.Client ran offline playfield 655 with 8 crowd actors, rendered a 180-frame profile and exited cleanly; a second 16-actor/1.5x UI-scale run captured .dev-data/gui/linux-validation/offline-scaled/client.png at 1920x1080 and shut down cleanly. No Vulkan validation errors were found; unused shader output/performance warnings remain. No login or production server integration was attempted. Fresh real GUI/nameplate Native AOT fixture passed on RX9070 with installed front-end/Lua input and on Xvfb/lavapipe. Lua UI AOT, direct scripting AOT, font AOT ownership/shaping/cache acceptance and native ASan/UBSan passed. Current standalone GUI JIT/3-slot and AOT/1-slot smokes each passed 156 frames; font JIT/1-slot and AOT/3-slot passed 130 each, with clean lifetime/coverage checks. A software Vulkan integration run passed 32 cases plus the intentionally opt-in AA benchmark skip. Validation found and fixed three relevant issues: (1) startup-rollback fixture's empty data root did not actually remove app-local shaders; it now explicitly requests a missing font and checks the original failure/rollback, restoring real coverage; (2) GuiRenderer.CommitUploadsAfterSubmit boxed a HashSet enumerator through UnionWith, allocating 40 bytes per unchanged frame; existing smoke reproduced 320 bytes over eight frames, explicit additions in the existing loop restore zero-allocation warm frames; (3) whole-tree feedback audit mistakenly treated synthetic PRK.Client.Tests feedback IDs as shipped call sites. A new runtime-vs-test fixture was verified red, then conventional .Tests directories were excluded; all server tests and the real text-database audit passed. Artifacts/TRX/profiles/captures: .dev-data/gui/linux-validation. Logs: /tmp/prk-expanded-full-solution-build.log, /tmp/prk-expanded-host-tests.log, /tmp/prk-expanded-installed-rerun.log, /tmp/prk-expanded-display-tests.log, /tmp/prk-expanded-hardware-vulkan-final.log, /tmp/prk-expanded-final-hardware-regressions.log, /tmp/prk-expanded-native-aot.log, /tmp/prk-expanded-installed-gui-aot.log, /tmp/prk-expanded-software-vulkan.log and playground logs. Broader HDR/mixed-monitor DPI transitions, controlled baseline/candidate performance comparisons and external-service/platform validation remain root-level gates; these broad test runs are not an FPS claim. ### Next-session first action Inspect the existing uncommitted integration diff; do not reset/recreate the worktree. The native overhead-nameplate/legacy-removal slice (tsk_23s9wcf4rf) is implemented and locally verified; inspect its uncommitted diff rather than reimplementing it. Remaining root work is broader display/platform/fault-injection/production-workload validation, not another widget or font renderer. The retained interface is already the normal GPU path; do not reintroduce the selector or port widgets a second time. Keep incomplete platform/performance/HDR/fault-injection gates explicit. ### Historical preparatory implementation — superseded where current status differs: - PRK.Fonts/Package.props selects .dev-data/fonts/<target RID>/package, with an absolute PRKFontsNativeDirectory override. Package.targets copies assets and refuses publishing without the expected bridge/target marker or with a mismatched marker. Fonts.Tests and TextPlayground import it explicitly; the managed font library no longer copies host assets transitively. This executable-owned boundary is intentional: an actual linux-arm64 publish showed the SDK drops RuntimeIdentifier across RID-agnostic managed library references, defeating validation inside PRK.Fonts itself. Moving ownership to executables fixed the reproduced failure. - Native CMake generates prk-fonts-rid.txt from its target OS/architecture and recreates package contents on ordinary builds. Playground helpers use RID-specific build directories. Existing packages need rebuilding. Windows helper source changed but has not been executed; the VM remains off. - Client CI builds/tests native fonts and publishes/executes the core acceptance harness in Release and Native AOT. It now also drives the actual retained client GUI under Xvfb/lavapipe, including UIRenderer, not only the headless renderer that omits it. Docker/ci includes native development dependencies, DejaVu fixtures and Xvfb/X11 support; both CI jobs reference directory-tree tag 9348cb62b3fe. That image built locally as prk-engines-ci-fonts:local. The windowed CI-equivalent commands passed locally. The image has not been pushed; hosted CI and a full client/server solution run remain unperformed. - Verified missing-package control: original source published successfully with an absent native directory; current source refuses with an actionable diagnostic. Current source also refuses an actual linux-arm64 publish pointed at the linux-x64 package. Clean-fixture CTest and Release/Native AOT font acceptance pass, including zero-allocation warm shaping. Host Release playground build has zero compiler warnings/errors. RX9070 GUI regression passes 156 frames, native coverage/opacity/cache/upload/lifetime assertions and clean validation/teardown; artifacts .dev-data/gui/rid-package-regression. Logs are /tmp/prk-font-ci-acceptance.log, /tmp/prk-font-package-candidate.log, /tmp/prk-font-wrong-rid.log and /tmp/prk-font-gui-regression.log. bash syntax and git diff --check pass. - This is not a complete production font package: Linux still dynamically links system FreeType/HarfBuzz; dependency bundling/notices, runtime baselines, application font licensing/catalog/fallback, macOS loader/signing and release/installer wiring remain open. The initial retained integration below does not establish complete interface compatibility, game performance, full solution validation, HDR/DPI behavior or Windows support. All broader incomplete checklists stay unchecked. ## Historical initial retained integration — superseded by current status above - User explicitly prioritized actual integration over more packaging preparation. Work remains uncommitted in /home/mathias/Projects/worktrees/engines-gpu-ui on feature/integrate-vulkan-gui; the original checkout is untouched/clean. No commits, pushes, VM work or feature review occurred. - UIRenderer now has a PRK_DEVCLIENT-only PRK_GUI_BACKEND=vulkan selector requiring an explicit PRK_GUI_FONT; PRK_GUI_ITALIC_FONT optionally supplies an italic face. PRK.Client's development build imports the native package directly. The selector is compiled out of production builds. Repository usage/coverage documentation is PRK.Client/PRK.GraphicsEngine/UI/README.md. - GuiVulkanSurface/GuiVulkanPainter adapt the existing GuiContext/GuiView tree and invalidation to PRK.Gui paint lists. The candidate creates neither GuiSurface nor the full-screen UI image/per-slot pixel staging buffers. It keeps the existing input manager, child/selected-on-top ordering, logical/framebuffer metrics, cursor and screen-cover paths. It prepares only after the actual slot fence, records uploads/layers before the composite pass, draws GUI after scene AA/display overlays, restores state for cover/cursor, commits after successful submission and discards pending uploads on frame failure. Native resources retire through completed-GPU shutdown; ordinary extent changes do not recreate a CPU UI surface. Actual-client cancellation/submission-failure fault injection and display-pipeline replacement remain follow-ups. - The first real-client test exposed VUID-VkGraphicsPipelineCreateInfo-renderPass-09028: the real composite pass has a depth attachment, unlike the playground. Both native primitive and text pipelines now provide explicitly disabled depth/stencil testing and depth writes; the existing composite pass/depth/overlay architecture is preserved. Current hardware and software validation are clean. - ShapedRun now owns TextGeometry with immutable UTF-16 cluster spans, visual advance boxes, width, hit testing and boundary navigation. Native ABI 2 returns HarfBuzz's resolved direction instead of inferring RTL from glyph count/order. A real red/green check proved auto-direction for a single Arabic ligature failed under the old inference. All native bridge packages, including the paused Windows copy, must be rebuilt before using current managed code. - GuiNativeText supplies the same shaped runs to candidate measurement, wrapping, paint, link bounds and selection. Long words break at grapheme boundaries and reshape their actual fragments; field keyboard movement/deletion uses shaped cluster boundaries. Candidate text caches invalidate for text/style/size/wrap and committed framebuffer-scale changes. Common GuiView cache invalidation now clears stale shaped snapshots, including when switching from wrapping to unwrapped text; existing behavior suites remain green. Full internal ligature caret stops, paragraph bidi, fallback and all insertion/truncation boundaries are not finished. - Images normalize premultiplied BGRA/other Skia input to straight-alpha sRGB RGBA once, then reuse PRK.Gui.Vulkan's linear-premultiplied conversion. Nearest sprite versus linear backdrop sampling is retained. A test verifies real premultiplied BGRA input's byte order/alpha association rather than merely testing registration. - The supported slice includes basic retained containers, borderless backing, default/basic border/window artwork, default/flat buttons, text buttons, labels/rich links, plain fields, clipped scrolling, bitmaps/backdrops and isolated opacity. Unsupported content is refused explicitly, with no whole-window CPU fallback. Standard title tabs, ComboBox/custom artwork, drawn scrollbars, special widgets/maps, virtual logs, combat-locked snapshots, field links, dimming/filter effects, named font families/missing glyphs, absent italic faces and wrapped RTL remain gated. Normal full front-end/Lua window compatibility is NOT established. Verified current results: - Normal Debug client build through run-client-dev.sh --build-only: zero compiler warnings/errors. - Graphics tests: 713 passed, zero skipped. Client tests: 4,179 passed, 44 existing installed-asset/audio-device checks skipped. An initial client-suite run failed because cached Lua native assets required GLIBC_2.38 in the older CI image; rebuilding the bridge in that image and explicitly selecting its package resolved the environment mismatch, then the whole selected suite passed without disabling tests. Native Lua CTest also passed. - New windowed RendererLifetimeTests.RetainedVulkanUiDrawsNativeTextAndLayersThroughTheClientFrameLoop passes on RX9070 and the exact local CI image's Xvfb/lavapipe, both with 1/3 frame slots. It uses the actual RendererVulkan/UIRenderer, retained XML/layout/input and client composite pass. Checks cover native label output, a rich link, default button callback routing, real wheel scrolling without glyph reupload, field combining-sequence deletion, scale changes, linear-light isolated opacity readback, stable idle paint/uploads, absence of CPU UI surface/staging owners, and clean Vulkan validation/resource teardown. One fixture iteration lacked capture_input on the scroll view; the correct retained input contract fixed the fixture, not the input router. Hardware 1/3-slot captures are pixel-identical and visually inspected: .dev-data/gui/retained-client-final/retained-1.ppm and retained-3.ppm/png. Current hardware logs include loader/libdecor/RADV environment warnings, but the checks report no Vulkan validation errors. - Native CTest and ASan/UBSan pass with ABI 2. PRK.Fonts.Tests Native AOT acceptance passes, including single-glyph RTL direction, UTF-16/combining/ligature geometry and zero-allocation warm shaping. Existing PRK.Client.UI.AotTests publishes/runs successfully, preserving real Lua/chat/virtual-history/combat-lock/input regressions on the default path. This is NOT Native AOT execution of the new Vulkan GUI route. - Original playground regression remains independent: 156-frame GPU smoke passes with clean validation/teardown, and all 12 captures match the earlier control exactly. Artifacts .dev-data/gui/retained-foundation-control. - Formatting applied to changed C# files, XML/YAML parsing and git diff --check pass. Unrelated pre-existing RendererVulkan formatting was preserved. Logs: /tmp/prk-retained-managed-final.log, /tmp/prk-retained-aot-ci-final.log, /tmp/prk-retained-vulkan-final.log, /tmp/prk-retained-font-aot.log and /tmp/prk-retained-foundation-control.log. The original checkout remains clean. Remaining release/integration gates include full widget/effect/front-end/Lua coverage, virtual chat and complete shaped editing, deterministic licensed font catalog/fallback, bounded cache pressure/eviction/retirement, measured presentation-resize policy, real cancellation/failure/display-transition validation, actual GUI AOT, Windows (VM still off), HDR/mixed DPI, installed assets and controlled game baseline/candidate workloads. Keep the root/checklists open; the initial slice is not a cutover or performance claim. ## Foundation history — historical context, not current branch/setup instructions Plan a replacement for PRK.Client's CPU Skia UI rasterization/upload pipeline with a Vulkan-native renderer. User approved the direction and authorized the first implementation milestone: a minimal standalone application drawing text with the new native libraries. Font extraction is committed and verified. User now authorized starting the new GUI backend. Implement an ordered backend-neutral paint-list core and Vulkan painter for rounded fills/borders, images/nine-slice, nested rectangular clips and interleaved PRK.Fonts text, with caller-owned Vulkan/frame synchronization. Use the existing playground as a real consumer/regression harness; do not silently switch the current game UI renderer before a retained-widget adapter and compositing semantics are implemented. Worktree: /home/mathias/Projects/worktrees/engines-gpu-ui; branch feature/gpu-ui-renderer; based on local develop 7d7995a76. Leave concurrent uncommitted Lua chat work in the original checkout untouched. Requirements: responsive window resize, native physical-resolution text at every supported UI size/display scale with no stretched or shrunk cached bitmap text, modern text shaping and consistent layout/input geometry, existing player-facing UI/Lua contracts preserved. Reuse the existing Vulkan allocator, upload/synchronization/lifetime infrastructure and retained UI behavior where sound. Keep replacement rendering independent of Skia surfaces; removing Skia from unrelated image tooling is not a prerequisite. Respect the client's clean-room restrictions. Planning scope: trace current UI/layout/text/resize/compositing paths; choose a backend-neutral paint and text boundary; evaluate native-size glyph coverage atlases versus analytic GPU outline rendering and specify CPU shaping/rasterization costs explicitly; define coordinate/scale/color/lifetime semantics, phased migration and controlled validation. Source findings on the isolated baseline: GuiSurface allocates SKBitmap/SKCanvas and CPU-paints damage. UIRenderer uses a full-frame RGBA-F16 surface (8 bytes/pixel), a GPU image and one full-size staging buffer per frame slot; Resize recreates those resources. GuiContext already distinguishes logical/window/framebuffer coordinates and UI scale. PresentationRefreshSchedule throttles applied framebuffer refreshes to 500 ms; Engine.OnResize updates live input size without committing layout. GuiLayoutEngine measures through SKFont; GuiDrawResources creates SKTextBlob directly; selection geometry in GuiTextLayout.Place measures UTF-16 characters separately. GuiView exposes Skia color/bitmap/rectangle types, so preserve adapters initially rather than pretending the retained layer is backend-neutral. RendererVulkan records UI after scene composite/spatial AA; preserve native-output UI placement and SDR/HDR linear premultiplied-alpha correctness. Existing graphics behavior tests and Vulkan lifetime tests provide reuse opportunities, but headless renderer construction currently omits UIRenderer, so new real-Vulkan UI acceptance must explicitly instantiate the candidate path. The standalone native text prototype is now implemented and exercised; no controlled comparison against the game renderer has run, so performance improvement remains unmeasured. Proposed direction: GPU primitive/sprite/glyph paint stream under the retained UI, one shared cluster-aware text layout service, independent shaping/line-layout/glyph caches, stable resources across ordinary extent changes, isolated GPU layers only where opacity/dimming semantics require them. Prefer an initial HarfBuzz/FreeType native-size coverage-atlas text spike (CPU shaping and cache-miss rasterization explicitly allowed; one-to-one physical-pixel coverage, no glyph scaling/mip selection or old-size placeholders). Compare analytic GPU outlines before freezing the text backend; do not select SDF/MSDF as the default small-text solution. Native bindings and Native AOT have been validated on Linux and Windows. Production RID packaging and application-font selection/licensing remain separate work. User agreed the direction. The playground and reusable PRK.Fonts/PRK.Fonts.Vulkan extraction passed Linux/Windows validation. Build the new GUI painting backend on these libraries, preserving the existing font harness and reusing its window/device/presentation and capture infrastructure. First GUI acceptance covers painter order across shapes/images/text, rounded geometry and borders, nested/empty clip behavior, linear-premultiplied image filtering, resize/resource reuse, and frame-slot/upload commit/discard safety. Isolated group-opacity implementation is now complete and locally validated: cropped native-resolution RGBA16F targets per frame slot, child-before-parent rendering, one-to-one compositing and explicit layer count/byte budgets. Preserve native glyph phase/size by using integer target origins rather than scaling text. Validate overlapping-child alpha, nested groups, clipped/zero/opaque groups, native text inside groups, warm reuse and resize/retirement on Linux Release/AOT. Retained widget integration and full client renderer replacement remain later slices; do not fake group opacity through child tint multiplication. Address owned raster data, load/operation failures, and explicit frame-slot/lifetime/submission contracts. Preserve native-resolution output, validate multi-font identity and multiple frame slots, and rerun Linux/Windows JIT/AOT checks. Full fallback/bidi paragraph editing, analytic outlines and game UI replacement remain separate milestones. User requested no feature review; that restriction remains. Baseline/candidate measurements must use identical workloads and include controls; no performance claims from source inspection alone. Coordinate shared text/layout changes with the separate Lua chat migration rather than copying its uncommitted changes. First milestone implemented in PRK.Client/PRK.TextPlayground: standalone C# application, direct source-generated GLFW imports, Silk.NET Vulkan bindings with explicit system loader, existing Vulkan memory allocator, and a small C bridge owning HarfBuzz/FreeType state. CPU shapes and rasterizes glyph-cache misses; GPU draws exact-size R8 coverage with texelFetch, no Skia or game assets. Includes resizable window, UI scale controls, Latin/Norwegian/Arabic/combining/ligature samples and a half-pixel-origin GPU coverage probe. Scope is deliberately one font, one frame in flight, fixed bounded caches and synchronous device-idle/pipeline rebuild on resize. Production lifetime design, fallback, general bidi, editing, HDR, analytic outlines and integration remain future work. Verified on Linux x64/RX 9070: Release build with zero compiler warnings/errors; native shaping tests and ASAN/UBSAN; dotnet format; Native AOT publish without warning suppressions; JIT and Native AOT real-window smoke with synchronization validation. Each smoke ran 126 frames across six extent/scale checkpoints at 1x, 1.25x, 1.5x and 2x, including return to 1x. Native H coverage with a half-pixel origin matched GPU sRGB readback within two output code values; no validation errors including teardown or live allocated resources. Extent-only resize and unchanged frames performed no new shaping/glyph uploads; final warm cache was 813 glyphs with 197,493 cumulative glyph-upload bytes, not a throughput benchmark. Visually inspected captures at 1x/1.25x/2x. Mutations disabling ligatures, ignoring fractional phase and stretching GPU rectangles each caused their relevant checks to fail; normal sources/binaries restored and green checks rerun. High-level Silk window/input AOT warnings were fixed by removing those dependencies, not suppressed. Windows validation passed on the user's Windows 11 LTSC VM with passed-through GTX 1070, NVIDIA 560.94, Vulkan 1.3.280 and Khronos synchronization validation. Built native dependencies from vcpkg 817892b0ecbc6af994dd6df999c73faf795adbf2 (FreeType 2.14.3, HarfBuzz 14.6.0, GLFW 3.5.1), native bridge/shaping tests with MSVC 14.44, and .NET 10.0.401 Release plus win-x64 Native AOT without warning suppression. Both graphics checks ran in the logged-on user session, each 126 frames across six size/scale checkpoints. All native coverage, extent-only resize/idle cache reuse, Vulkan validation and resource teardown checks passed. All six Windows JIT/AOT capture pairs are pixel-identical. Compared with Linux/RX9070, common image regions differ by at most one sRGB code value per channel; Windows constrained the requested 1600x1100 client to 1600x1061, so that checkpoint comparison covers the common region. Inspected Windows captures at 1x/1.25x/2x. Linux Release build, native tests, sanitizer tests and actual GPU smoke were rerun after the Windows CMake/import-export changes and passed. Added run.ps1, Windows HarfBuzz CMake package discovery, correct bridge DLL import/export declarations, and verified Windows setup/validation instructions in README.md. The first AOT test-wrapper attempt converted redirected CMake stderr into a terminating PowerShell error before compilation; fixed the temporary wrapper to keep native stdout/stderr separate and the subsequent full AOT build and smoke passed. No compiler/test warnings were suppressed. Existing VM C:\engines and C:\client were inspected only; test source/build artifacts remain in isolated C:\prk-text-playground. Host logs/captures are in .dev-data/text-playground/windows-exchange/artifacts-jit and artifacts-aot. Transfers used the guest agent and temporary libvirt-bridge HTTP, not alternate SSH keys. Temporary build/smoke scheduled tasks and transfer server were removed; VM left running for the user. No playground process remains running. Cross-monitor compositor/DPI behavior, Windows display-scale changes, production distribution packaging and controlled game-performance comparisons remain unverified. User explicitly requested no review yet; no review findings or approval are claimed. Committed as b682bcb4a (feature: Add reusable native font libraries and Vulkan text rendering) on feature/gpu-ui-renderer at the user's request. Session work is committed as b682bcb4a (font libraries), 172191b08 (GUI backend/opacity layers), and db9aa0a94 (platform shader compiler selection). Pushed feature/gpu-ui-renderer with upstream origin/feature/gpu-ui-renderer; worktree is clean. Opening the PR did not complete the broader UI migration. The extraction now adds PRK.Fonts, PRK.Fonts.Vulkan and PRK.Fonts.Tests, migrates the playground to consume them, and registers the projects in the client/root solutions. The existing game UI renderer and concurrent chat checkout remain untouched. Font library extraction implemented: PRK.Fonts has renderer-independent SafeHandle-backed face ownership, owned memory-font input (including Unicode file paths), immutable shaped runs/coverage, UTF-16 source clusters, metrics, direction selection, missing-glyph reporting, structured failures and bounded LRU shape caching. KeepAlive protects borrowed native data until managed copies finish. PRK.Fonts.Vulkan borrows the caller's Vk/device/allocator, supports per-frame-slot staging/instance/descriptor resources, embeds shaders, keys glyphs by face/size/phase, clips in physical pixels, refuses an oversized run atomically, and separates upload recording from submit commit/discard. It never creates/waits on the application device or window. Explicit caller-owned synchronization, single producer/render thread and font-face affinity are documented. GPU atlas growth/eviction, fallback, paragraph layout, analytic outlines and production RID packaging remain future work. Extraction validation: Linux Release and Native AOT core acceptance and real RX9070 Vulkan smoke pass; native CTest also passes ASAN/UBSAN. Warm shaping: 1000 retained cache hits allocate zero bytes. Three-frame-slot graphics checks cover two fonts in one atlas, partial clipping/restoration, discarded/re-recorded first uploads, atomic run refusal/recovery, resize/scale changes and clean validation/resource teardown. A single-slot AOT smoke also passed. The six original Linux prototype captures remain pixel-identical after extraction. Regression mutations corrupting UTF-16 source offsets, omitting font identity, losing discarded uploads and ignoring clipping each caused the appropriate check to fail; mutations were restored. Formatting checks pass for the four projects. Full client/server solution builds were not run. Windows extraction: separate C:\prk-font-library\src uses the existing pinned dependency checkout without altering C:\engines or C:\client. MSVC native tests, Release builds, win-x64 Native AOT builds, and both managed core acceptance executions pass, including Unicode font paths, owned results and cache behavior. Logs are saved on the host under .dev-data/fonts/windows-exchange/build-artifacts. The user logged in and the extracted libraries' Windows interactive GPU regression now passes on the GTX 1070. Ran Release/3-slot, Native AOT/3-slot and Native AOT/1-slot modes, 130 frames each, covering both fonts in one atlas, partial clipping/restoration, discarded/re-recorded uploads, atomic capacity refusal/recovery, extent/scale changes, idle cache reuse and native coverage matching. All modes report zero Vulkan validation errors including teardown and no live allocated resources. All ten captures per Windows mode are pixel-identical across modes. Shared image regions differ from the current Linux/RX9070 control by at most one sRGB code value per channel; Windows still caps the largest requested client height at 1061 rather than 1100. Verified VM source hashes against the clean local checkout (32 source/project/script files). Inspected the 1.25x and clipped-probe images. Host artifacts are under .dev-data/fonts/windows-exchange/graphics-artifacts. Temporary interactive task was removed and no test process remains; VM left running. No transfer server was restarted or new repository changes made. Font extraction milestone is now verified on both platforms in Release and Native AOT. No feature review was performed. Mixed-monitor/display DPI changes, HDR, full solution validation, production RID packaging and performance comparisons with the game renderer remain unverified; the broader GPU UI implementation remains open. First GUI backend slice implemented: PRK.Gui provides thread-owned, revisioned, bounded physical-pixel paint lists with rounded fills/inside borders, immutable straight-alpha sRGB images, nine-slice and nested/intersected integer clips. PRK.Gui.Vulkan borrows the existing font Vulkan device plus physical-device metadata; it draws compatible adjacent batches without reordering shapes/images/text. TextPipeline.DrawRange reuses the validated glyph atlas for interleaved text. Images convert once to linear-premultiplied RGBA16F before filtering; UV sampling clamps to source subregion texel centers. Image staging retires with the submitting frame slot, image caches survive resize, and explicit completed-GPU image release/reload is supported. Texture/batch/instance budgets refuse frames rather than drawing a prefix. Both modules are registered in the client/root solutions. No retained-widget/game renderer was switched. True isolated group opacity/dimming, rounded clip masks, arbitrary transforms/paths and the retained-widget adapter remain subsequent slices. The playground now has --gui / PowerShell -Gui mode with overlapping panels, native text, borders, hover, mouse header dragging and grip resize. Font and GUI modes share PlaygroundApplication's presentation/readback/submit/discard loop rather than duplicating it. Host shader preparation now includes GUI shaders before the SDK-container build (bundled glslc's runtime dependencies are absent in that container). Existing font captures remain pixel-identical across all ten checks after the refactor. GUI validation: Linux Release and Native AOT graphics checks pass on RX9070 with 1/3 frame slots; 129-frame checks cover mixed painter order, native glyph ranges with shape/image covers, extended/empty nested clips, rounded fill/border/corner, fractional edge AA, transparent-red/opaque-blue filtering without halos, nine-slice joins, upload abandonment/re-recording, whole-frame capacity refusal/recovery, panel movement/resize, and image retirement/reload. Warm unchanged frames allocate zero managed bytes and do not reshape/reupload; moving/resizing panels preserves images and shaped data. Regression mutations ignoring text range offsets, skipping premultiplication, wrongly marking discarded image uploads ready and omitting parent clip intersection each caused real GPU checks to fail; mutations restored. Local formatting/build/diff checks pass, zero compiler warnings/errors. Current local Linux Release and AOT checks pass after a final cleanup fix to discard any recorded upload state before pipeline teardown. Original font checks also pass, with all ten original Linux captures pixel-identical. Windows GUI checks ran from isolated C:\prk-gui-backend using the existing pinned native dependencies. Release/3-slot, Native AOT/3-slot and Native AOT/1-slot graphics runs each passed 129 frames on GTX1070, reporting zero validation errors and no live resources. The original font control passed 130 frames. A native user32 mouse-input test captured only the app client: initial panel, header moved by 90x40 and panel resized by 64x24 all matched expected pixels; clean native process exit/validation also passed. An initial test-runner false failure from PowerShell's missing Process.ExitCode value was fixed using a retained process handle and GetExitCodeProcess; all checks were rerun and reported PASS. VM TESTING PAUSED BY USER. The user subsequently requested VM shutdown and continued local implementation; winvm stop confirmed 'shut off (viewer closed, shared memory released)'. Leave the VM off and do not run VM commands, builds, tests, exports or cleanup attempts until explicitly resumed. Windows follow-up is deferred, not a blocker for local GUI implementation, and no additional Windows validation is claimed. During the previous capture/source-hash export, winvm's guest-agent command timed out after its internal 5-second limit. Stopped VM operations and asked the user to check responsiveness; do not rerun the export automatically, as its guest PowerShell process may still be running. Windows capture comparison/visual inspection and source-hash verification are outstanding. Guest test tasks PRKGuiBackend-Build and PRKGuiBackend-Smoke remain registered (previously Ready/PASS) and need cleanup once the guest agent is available. Test output is in the user's LocalAppData\PRKGuiBackend; export requested C:\prk-gui-backend\artifacts.zip. Host transfer server at 192.168.122.1:18475 has been stopped. Source/script/build data is under .dev-data/gui/windows-exchange. Only local work continued after the guest timeout. One cleanup safety line (DiscardUploads before pipeline teardown) and whitespace-only formatting changes were made locally after the Windows runs; update/rebuild the VM copy before claiming current-source Windows validation. No new commit or feature review was performed. Do not claim Windows artifacts were retrieved or all GUI acceptance is finished. Broader client/server solution, HDR, mixed-monitor DPI and game-renderer performance comparisons remain unverified. Local opacity slice verified after VM shutdown: PRK.Gui now records balanced PushOpacity/PopOpacity scopes, intersects them with parent/viewport clips, suppresses zero-opacity children (including image preparation), and allows opacity-one groups to flatten. PRK.Gui.Vulkan plans nested targets, renders children before parents outside the root pass, translates global geometry/text by integer target origins, and composites RGBA16F with texelFetch at native size. Per-slot target images/framebuffers/descriptors have bounded count and aggregate pixel-byte budgets, retire only after their slot's fence, and reuse unchanged dimensions. Targets cache submitted content versions; warm frames neither allocate nor repaint layers. Versions update only after queue submission, so abandoned recordings cannot falsely cache rendered contents. New API flow is RecordUploads -> RecordLayers (outside root pass) -> Draw -> CommitUploadsAfterSubmit, or discard/reset on cancellation. Public text target origins are validated as integer physical pixels. The GUI demo supports whole-panel fade/restore with F, and --gui-base retains the non-layered control. Local smoke covers overlapping opaque children under group alpha, nested groups, glyph-only transparency, half-pixel native text through cropped targets, viewport cropping, zero/opaque groups, layer count/byte refusal and recovery, cached target reuse, resize, fade/hide/restore and clean teardown. The red per-child-alpha control failed as expected before the true implementation. Mutations committing layer content at record time, omitting cropped text translation and rendering parents before children each failed GPU coverage/validation checks and were restored. Final Linux/RX9070 results: Release and Native AOT 1/3-slot runs pass 156 frames each with zero Vulkan errors and no live allocated resources at shutdown. All 12 opacity capture sets are pixel-identical across modes. Nine non-layered GUI controls match historical same-extent captures exactly, and all ten original font controls remain pixel-identical. The control comparison exposed old captures at different actual framebuffer sizes; fixed both smoke paths to wait for an actual framebuffer change rather than assuming twelve fast frames means an async resize completed. An initial new diagnostic fixture overlapped a glyph at the 980px checkpoint; moved that fixture, preserving the actual clipping/order assertions. Current format/build/diff checks pass; visual inspection of the faded panel is clean. Latest artifacts are under .dev-data/gui/opacity-final-jit, opacity-final-aot, opacity-final-one-slot and opacity-font-control. Four baseline opacity targets use 97,024 pixel bytes per slot / 291,072 across three slots, excluding allocator overhead; this is a fixture resource measurement, not a game-renderer performance comparison. VM stayed off; no Windows opacity validation, feature review or commit occurred. The retained-widget adapter, color-filter/dimming effects, rounded clips, full game UI replacement and original broader validation remain open. Pull request: #2865 — feature: Add native fonts and Vulkan GUI rendering foundations https://git.project-rk.com/prk/engines/pulls/2865 Head: feature/gpu-ui-renderer; base: develop. Normal (non-draft) PR is scoped to completed rendering foundations, not the future widget adapter or game renderer cutover. No feature review was run. Before opening, inspected the entire 6,034-line base comparison: only session projects/solution registrations, no unrelated branch commits. Current develop was two commits ahead; merge-tree check passed without conflicts. No existing open PR for this branch was found. PR readiness correction: shader MSBuild defaults now use Linux PATH glslc and Windows VULKAN_SDK when available (explicit compiler overrides preserved). The old bundled Linux executable's shared-library dependencies were missing in the SDK container; CI already installs its own glslc. A clean archived-source build with no generated SPIR-V, system shaderc 2023.8 and warnings as errors passed for the playground and font acceptance executable. Initial validation-fixture attempt omitted the Fonts.Tests directory; corrected the fixture and reran successfully. Copied the already-verified native font bridge into the clean outputs, then the core acceptance executable and a fresh 156-frame RX9070 GUI run passed with clean validation/teardown. Did not run a full solution/CI suite or restart the VM. PR body preserves Windows opacity, HDR/DPI/packaging and integration limits. Full migration acceptance (outside the authorized first milestone): no full-frame CPU UI bitmap rasterization or pixel uploads; no resampling cached text across sizes/DPI; text, links, selection/caret and clipping share shaped geometry; correct transparency/dimming and SDR/HDR UI composition; resize, scale changes, scrolling and glyph/resource eviction are safe with frames in flight; Windows/Linux and existing Lua/player behavior preserved. Relevant builds, behavior tests, actual Vulkan validation, visual text review and controlled performance comparisons must pass. Planning does not complete implementation. Current integration pull request: #2868 — feature: Replace client UI rasterization with native Vulkan rendering https://git.project-rk.com/prk/engines/pulls/2868 Head feature/integrate-vulkan-gui → base develop. Published session commits 9b635a77b, cacb3967d and 3a2141c09 over HTTPS using tea's stored-token Git credential helper; no SSH agent/1Password approval or force-push. Remote default verified as develop, current base seven commits newer than the branch fork; merge-tree reported no conflicts. Worktree clean and upstream origin/feature/integrate-vulkan-gui established. Pull request is non-draft; opening it does not complete the broader platform/HDR/workload gates. Hosted CI setup failure diagnosed: PR jobs reference engines-ci:8cf3ba6438dd (feature Docker/ci tree), which was built locally but never published to the registry. No ci-image workflow run for feature/integrate-vulkan-gui appears in the run history. The successful manually dispatched image workflow at /actions/runs/5607 ran develop/f4b69d6ea and therefore resolves old tag f4d0e85bf897, not the feature tag. PR runs /actions/runs/5605 and /5606 fail before build/test at container pull. Required recovery: dispatch ci-image.yml explicitly on feature/integrate-vulkan-gui, wait for the new tag to be pushed/private, then rerun PR jobs. Rerunning the image workflow on develop cannot create the needed tag. No workflow/repository changes or new remote dispatch performed during this diagnosis. Reported-runtime scrollbar crash reproduced and fixed locally (uncommitted). GuiScrollBar.LayoutOf divided trackHeight * viewportHeight by zero ContentHeight for always-visible empty lists; GPU thumb rectangle construction then rejected Infinity/NaN. Regression reproduces the user's exact GuiRect -> ScrollBar stack before the fix. Shared layout now uses full visible fraction when content fits/is empty and caps the minimum thumb height to available track space, keeping input and paint consistent. Regression covers empty/fitting/populated/cleared content, full-track thumb geometry and working arrow input. Installed managed/AOT acceptance fixture now includes a persistently empty always-visible list so startup/frame-loop coverage retains this case. Verified current client solution Debug build zero warnings/errors; 719 graphics tests passed; 4,180 client tests passed with 43 unavailable/opt-in cases skipped; actual installed RX9070 front-end/Lua/nameplate/empty-scrollbar acceptance passed. Tests ran on host because the user's dev launcher rebuilt default native fonts against host ICU78 (not the CI container's ICU72); initial container test load failure was environmental, then host red/green checks and suites passed. No exception suppression or CPU fallback, commit or push.
Checklist
7 of 12 complete- Replace separate Skia text measurement/character-width paths with shared PRK.Fonts shaped layout for wrap, drawing, caret, links and selection; preserve UTF-16 identities, graphemes/direction, styles/fallback and virtual-chat anchoring/offscreen copy.
- Deliver the isolated HarfBuzz/FreeType/Vulkan text playground; verify Linux Release and Native AOT execution, native shaping/sanitizer checks, real-GPU size/scale coverage and resize/idle cache reuse. Keep full renderer migration and Windows verification separate.
- Establish latest-develop integration ownership/coverage map and real-client baseline workloads, reusing current GuiView/Lua/combat/virtual-chat behavior and identifying renderer/text/asset/presentation gaps before changing the shipping route.
- Implement the GuiView-to-paint-list adapter and a representative real-client/Lua retained-window vertical slice; preserve widget/input/action contracts, saved state and combat locks, then cover every reachable widget without silent omissions or full-window CPU fallback.
- Build and validate the text playground on the Windows VM/GTX 1070 using real interactive Vulkan smoke, native shaping tests, GPU coverage/caching checks and visual captures; exercise Native AOT if the installed toolchain supports it. Preserve existing VM projects and do not run a feature review.
- Make licensed deterministic fonts and the native bridge/dependency/notices package available through normal client development, CI and release/AOT builds; define family/style/fallback and supported scale/DPI limits without relying on the playground or system Arial.
- Integrate GUI prepare/uploads/layer passes/root drawing/commit-discard into RendererVulkan's actual frame slots and retirement lifecycle; preserve scene-AA/output ordering, SDR/HDR behavior, true dimming exceptions, screen cover and cursor ordering.
- Extract PRK.Fonts and PRK.Fonts.Vulkan with explicit ownership, structured errors, immutable shaped/coverage data, bounded caches and caller-owned Vulkan/frame-slot contracts; make the playground consume them and preserve Linux/Windows JIT/AOT visual and synchronization checks.
- Replace the real client's deferred-resize/UI-stretch policy from measured presentation/world-target behavior; verify continuous resize, native text, scale/DPI, minimize/restore and display transitions with consistent input/paint metrics and bounded safe resources.
- Implement ordered GUI paint core and Vulkan backend for rounded fills/borders, immutable images/nine-slice, nested rectangular clips and interleaved native text; validate a real interactive playground with pixel/order/filtering checks, resize/idle reuse and frame-slot/upload lifetime checks. Keep current game UI untouched until its adapter/compositing migration.
- Complete client/graphics/Lua/virtual-chat/native/AOT/actual-GUI Vulkan and installed-asset validation plus controlled baseline/candidate measurements; switch the client default only after coverage passes, then remove the old Skia UI rasterization/staging path and temporary rollout selector.
- Implement real isolated GPU opacity groups with cropped physical-pixel targets per frame slot, nested child-before-parent passes and native-size text compositing; verify alpha overlap, nested/clipped/zero/opaque groups, budgets, upload discard, resize/reuse and teardown locally in Release/AOT. Keep VM testing paused.
- Area
- Project Rubi-Ka
- Project
- engines
- Kind
- Feature
- Task ID
tsk_nxnkyedc6c- Updated