Skip to content

Add Skia InkCanvas integration and refine rendering backends - #30

Merged
qian-o merged 50 commits into
masterfrom
fix/views
Aug 5, 2026
Merged

qian-o merged 50 commits into
masterfrom
fix/views

Conversation

@qian-o

@qian-o qian-o commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • add the SkiaSharp GPU integration layer and the cross-platform InkCanvas experiment, including MSAA controls and native backend texture wrapping
  • refine texture layout, native-object access, synchronization, and view-surface behavior across DirectX 12, Metal, Vulkan, Avalonia, MAUI, WPF, WinForms, and WinUI
  • preserve opaque scene and fluid-tank frame visibility during low-resolution fluid reconstruction, including distant-camera cases
  • align initializer, flag, and compact single-line formatting with the repository conventions

Validation

  • dotnet build Zenith.NET.slnx -c Release
  • focused Release builds for InkCanvas and FluidTank
  • dotnet format --verify-no-changes and declaration-order/flags audits
  • runtime validation of InkCanvas and FluidTank on macOS/Metal
  • Metal and Vulkan compilation for all affected FluidTank shader entry points
  • HLSL SM 6.6 generation for the affected DirectX 12 shader paths (final DXIL generation is unavailable on macOS without DXC)

qian-o added 30 commits July 30, 2026 17:15
Previously, DenyShaderResource was set if TextureUsages lacked Sampled. Now, it is set only when TextureUsages includes DepthStencilAttachment but not Sampled, restricting denial to unsampled depth-stencil attachments.
Updated Avalonia to 12.1.1, Slangc.NET to 2026.14.1, and Uno.WinUI to 6.6.184 to keep dependencies current.
Introduce CanTransition to DXTexture to indicate if a texture supports transitions. Update constructors and related classes to set this property. DXCommandBuffer.TransitionImpl now checks CanTransition before transitioning. Adjust DXGraphicsContext and DXHeap to pass CanTransition when creating textures.
The textures array now initializes each Texture with an additional boolean argument (true), reflecting a change in the Texture class constructor. This likely enables a new behavior or flag during texture initialization.
Added a ComPtr<ID3D11Query> to Surface and created the query in the constructor. Wrapped resource copy with Begin/End on the query and replaced DeviceContext.Flush() with a polling loop using GetData to ensure copy completion before proceeding.
Introduce ComPtr<ID3D11Query> to Surface for GPU synchronization.
Replace DeviceContext.Flush with Begin/End query and GetData polling.
Ensure proper disposal of Query in Surface.Dispose.
Align WinUI implementation with GetData polling logic.
Replaced synchronous Dispatcher.Invoke/Invoke with asynchronous Dispatcher.InvokeAsync/InvokeAsync using DispatcherPriority.Render to enhance UI responsiveness. Added System.Windows.Threading import for DispatcherPriority support.
Updated IZenithView.UI to invoke actions with the default dispatcher priority by removing the DispatcherPriority.Render argument from Dispatcher.InvokeAsync. This simplifies priority management for UI actions.
Upgraded the SkiaSharp NuGet package from 4.150.1 to 4.151.0 in Directory.Packages.props. No other package versions were changed; only minor formatting adjustments were made.
Introduced Zenith.NET.Extensions.Skia namespace with SkiaSharp integration. Added Extensions.cs for GraphicsContext extension to create SKTexture with GRContext management. Implemented SKTexture and SKTextureDesc types for texture handling; methods are not yet implemented.
Implement GetNativeObject in graphics API wrappers to return native handles or pointers based on NativeObjectType. Expand NativeObjectType enum to cover all supported native objects for DirectX 12, Metal, and Vulkan, enabling type-safe access to underlying resources.
The GetNativeObject method in MTLTextureView now returns 0 for all NativeObjectType values, instead of returning Texture.NativePtr for MTLTexture and default for others.
Refactors Skia integration in Zenith.NET for improved thread safety and extensibility:
- Replaces GRContext dictionary with thread-safe SKRenderer management using reference counting.
- Adds SKFormats.cs for mapping Zenith.NET formats to SkiaSharp, DirectX12, and Vulkan equivalents.
- Implements SKRenderer for backend context creation and resource management across DirectX12, Metal, and Vulkan.
- Refactors SKTexture to use SKRenderer, improving resource cleanup and API abstraction.
- Ensures robust, multi-API rendering with proper resource lifecycle handling.
Added SkiaBoard project to Experiments, including project file and source code. Implemented App.cs for window/input/rendering setup with Silk.NET and Zenith.NET, integrating SkiaSharp for drawing. Board.cs provides drawing board features: brush/eraser, color palette, undo/redo, clear, and brush size adjustment. CocoaHelper.cs enables Metal layer interop on macOS. Updated Program.cs to launch SkiaBoard and Zenith.NET.slnx to include the new project.
The solution file was updated to include a Byte Order Mark (BOM) at the beginning. No other modifications to the solution structure or project references were made.
- Changed Gallery, GalleryResources, and scene classes from sealed to non-sealed for inheritance support.
- Moved scene classes to SkiaGallery.Scenes namespace.
- Made GalleryResources.CreateText static and updated all usages.
- Improved code formatting and consistency.
- Added missing using directives in App.cs and Gallery.cs.
- Added UTF-8 BOM to project and source files.
- Added new static SKColor fields to GalleryPalette: Navigation, Ink, Muted, Line, Accent, Coral, Blue, and Amber.
- Modified SKTexture constructor to set Usages to only ColorAttachment and TransferSrc.
- Removed Usages field from SKTextureDesc struct.
Add an interactive vector whiteboard that demonstrates the minimal Skia GPU interop path: GraphicsContext, swap chain, GPU-backed SKTexture.Render, copy, present.

Finished strokes are baked into an SKPicture so each frame only redraws the in-progress stroke. The eraser sweeps a segment between frames and splits strokes into surviving fragments instead of deleting them outright.
Added required using directives to multiple files. Simplified point addition in Board.cs with the null-conditional operator. Refactored EnsureLayout by defining 'top' and 'bottom' as constants at the method's start.
Refactored App.cs to move event subscriptions into the Run method using inline lambdas. Inlined CreateTexture and DrawBoard logic. Simplified DPI scaling and logical size calculations. Handled texture recreation and swap chain resizing in window.Resize event. Removed nullable assertion in Board.cs and improved null checks in Stroke.cs for eraser operations.
Added TextureUsages.Sampled and TextureUsages.TransferDst to the texture initialization, allowing the texture to be used as a sampled texture and as a transfer destination, in addition to its previous usages as a color attachment and transfer source.
Added UTF-8 BOM to Canvas.cs, CanvasController.cs, and Toolbar.cs. Replaced private field 'context' with public read-only property 'Context' in CanvasController.cs and updated all references accordingly.
- Introduce Particles value to FluidViewMode enum
- Refactor BeginRenderPass with single-line color attachments
- Simplify reflection texture assignment with ternary operator
Changed GRContext.Flush to use surface argument and added GRContext.Submit(true) call, replacing previous boolean arguments. This aligns with updated API usage and may improve resource management.
Replaces SampleCount enum with IsMultisamplingEnabled boolean in SKTextureDesc. CanvasController now sets IsMultisamplingEnabled when creating textures. SKSurface uses sample count 4 if multisampling is enabled, otherwise 1. Removes SampleCount from SKTextureDesc.
qian-o added 18 commits August 4, 2026 16:00
- Import System.Numerics for Vector4 usage.
- Move Layout initialization into constructor and set conditionally.
- Use Vector4.Zero instead of default in BeginRenderPass.
- Assign Layout inline within the if condition for clarity.
- Moved SKFormats.DirectX12 method within SKFormats class; implementation unchanged
- Removed Skia SampleCount to uint mapping method from SKFormats
- No changes to PixelFormat mapping methods for Skia or Vulkan
- Updated SKRenderer.cs to reference relocated SKFormats.DirectX12
Replaced all usages of Layout with RequiredLayout in CanvasController and SKTexture. Removed the Layout property and updated all logic and references to ensure correct layout handling during texture transitions and rendering.
Updated validation message handling to ignore messages containing
"ID3D12CommandList::ClearRenderTargetView", as these are known
non-errors from Skia with the old D3D12 API. All other messages
continue to be printed to the console.
Adjusted code formatting by separating CanClear and IsMultisamplingEnabled properties. Removed IsMultisamplingEnabled from the code. No functional changes; only property order and spacing were modified.
Renamed the IsMultisamplingEnabled property and variable to MSAA in all relevant files. Updated all references, declarations, and usages in Canvas, CanvasController, and Toolbar classes for improved clarity and consistency. No changes to logic or behavior.
Renamed all references from "multisampling" to "msaa" and "MultisamplingWidth" to "MSAAWidth" for improved naming consistency. Updated variables, constants, and SKRect fields in the MSAA toolbar control, including related logic and UI drawing code.
Removed IsAntialias property from SKPaint in Canvas and Toolbar to use default antialiasing. Introduced GRContextOptions in SKRenderer with custom settings (e.g., AvoidStencilBuffers, AllowPathMaskCaching, cache sizes). Updated Direct3D, Metal, and Vulkan GRContext creation to accept options. Set GRContext resource cache limit to 256 MB.
The AllowPathMaskCaching option was removed from GRContextOptions initialization in the SKRenderer class. This option was previously set to true but is no longer present in the updated code.
Refactored object initializations and method calls in FluidSimulation.cs and FluidTankRenderer.cs to use single-line statements. This improves code compactness and readability by consolidating multi-line GridDimensions initialization and BeginRenderPass calls.
Copilot AI lite review requested due to automatic review settings August 5, 2026 06:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a SkiaSharp GPU integration layer plus a new cross-platform InkCanvas experiment, while also refining native-object access and synchronization behavior across multiple rendering backends and view implementations. It additionally adjusts FluidTank rendering/shader logic to preserve scene/frame visibility during low-resolution fluid reconstruction and updates a few dependency versions.

Changes:

  • Add Zenith.NET.Extensions.Skia (SkiaSharp GRContext + backend texture wrapping) and a new Experiments/InkCanvas sample using it.
  • Implement/extend GetNativeObject(NativeObjectType) across DirectX 12 / Metal / Vulkan resources and contexts.
  • Refine FluidTank formats/shaders and update several view backends (WPF/WinUI/MAUI/WinForms/Avalonia) synchronization/UI dispatch behavior.

Reviewed changes

Copilot reviewed 53 out of 53 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
Zenith.NET.slnx Adds InkCanvas experiment project to the solution.
sources/Zenith.NET/Enums/NativeObjectType.cs Expands native handle type taxonomy for DX12/Metal/Vulkan interop.
sources/Zenith.NET.Vulkan/VKTopLevelAccelerationStructure.cs Exposes Vulkan acceleration structure native handle.
sources/Zenith.NET.Vulkan/VKBottomLevelAccelerationStructure.cs Exposes Vulkan AS + device address native handles.
sources/Zenith.NET.Vulkan/VKTimeline.cs Exposes Vulkan semaphore native handle.
sources/Zenith.NET.Vulkan/VKTexture.cs Exposes Vulkan image + allocation memory/offset native handles.
sources/Zenith.NET.Vulkan/VKHeap.cs Exposes Vulkan device memory native handle.
sources/Zenith.NET.Vulkan/VKGraphicsContext.cs Exposes Vulkan instance/device/physical device + proc addrs.
sources/Zenith.NET.Vulkan/VKFormats.cs Reorders barrier stage/access flag aggregation (no semantic change intended).
sources/Zenith.NET.Vulkan/VKCommandQueue.cs Exposes Vulkan queue + family index native handles.
sources/Zenith.NET.Vulkan/VKCommandBuffer.cs Exposes Vulkan command buffer native handle.
sources/Zenith.NET.Vulkan/VKBuffer.cs Exposes Vulkan buffer/address/memory/offset native handles.
sources/Zenith.NET.Metal/MTLTimeline.cs Exposes Metal shared event native pointer.
sources/Zenith.NET.Metal/MTLTexture.cs Exposes Metal texture native pointer.
sources/Zenith.NET.Metal/MTLGraphicsContext.cs Exposes Metal device native pointer.
sources/Zenith.NET.DirectX12/DXTopLevelAccelerationStructure.cs Exposes DX12 AS GPU VA + resource handle.
sources/Zenith.NET.DirectX12/DXBottomLevelAccelerationStructure.cs Exposes DX12 BLAS GPU VA + resource handle.
sources/Zenith.NET.DirectX12/DXTimeline.cs Exposes DX12 fence handle.
sources/Zenith.NET.DirectX12/DXTexture.cs Adds CanTransition and exposes DX12 resource native handle; updates constructor signature for wrapped resources.
sources/Zenith.NET.DirectX12/DXSwapChain.cs Updates swapchain texture construction for new DXTexture ctor.
sources/Zenith.NET.DirectX12/DXHeap.cs Updates heap texture construction for new DXTexture ctor.
sources/Zenith.NET.DirectX12/DXGraphicsContext.cs Exposes DX12 adapter/device native handles and updates wrapped texture creation.
sources/Zenith.NET.DirectX12/DXFormats.cs Adjusts DenyShaderResource flag application for depth textures only.
sources/Zenith.NET.DirectX12/DXCommandQueue.cs Exposes DX12 command queue native handle.
sources/Zenith.NET.DirectX12/DXCommandBuffer.cs Exposes DX12 graphics command list native handle; skips transitions when CanTransition is false.
sources/Zenith.NET.DirectX12/DXBuffer.cs Exposes DX12 resource handle + GPU virtual address.
sources/Views/Zenith.NET.Views.WPF/ZenithView.cs Switches UI dispatch to async dispatcher invocation.
sources/Views/Zenith.NET.Views.WPF/Surface.cs Adds D3D11 query-based GPU completion wait before releasing keyed mutex.
sources/Views/Zenith.NET.Views.WinUI/ZenithView.WinUI.cs Adds D3D11 query-based GPU completion wait before releasing keyed mutex.
sources/Views/Zenith.NET.Views.WinForms/ZenithView.cs Switches UI dispatch to async invocation.
sources/Views/Zenith.NET.Views.Maui/Platforms/Windows/Surface.cs Adds D3D11 query-based GPU completion wait before releasing keyed mutex.
sources/Views/Zenith.NET.Views.Avalonia/ZenithView.cs Switches UI dispatch to async dispatcher invocation.
sources/Extensions/Zenith.NET.Extensions.Skia/SKTextureDesc.cs Introduces a Skia texture descriptor used by the new Skia renderer integration.
sources/Extensions/Zenith.NET.Extensions.Skia/SKTexture.cs Adds a disposable wrapper that renders via Skia into a Zenith texture.
sources/Extensions/Zenith.NET.Extensions.Skia/SKRenderer.cs Adds GRContext creation for DX12/Metal/Vulkan and backend texture wrapping.
sources/Extensions/Zenith.NET.Extensions.Skia/SKFormats.cs Adds PixelFormat/usage mappings for Skia backend interop.
sources/Extensions/Zenith.NET.Extensions.Skia/Extensions.cs Adds GraphicsContext extension API for creating SKTextures with renderer caching.
sources/Experiments/InkCanvas/Program.cs Adds InkCanvas entry point.
sources/Experiments/InkCanvas/InkCanvas.csproj Adds experiment project referencing Skia extension + backend implementations.
sources/Experiments/InkCanvas/Helpers/CocoaHelper.cs Adds CAMetalLayer attachment helper for macOS window surfaces.
sources/Experiments/InkCanvas/Drawing/Toolbar.cs Implements drawing UI controls (palette, stroke width, MSAA toggle, clear).
sources/Experiments/InkCanvas/Drawing/Stroke.cs Implements stroke building, smoothing, and erasing via path ops.
sources/Experiments/InkCanvas/Drawing/CanvasController.cs Wires input events to the canvas + manages SKTexture resizing/MSAA toggles.
sources/Experiments/InkCanvas/Drawing/Canvas.cs Implements the main drawing/erasing model with caching and UI integration.
sources/Experiments/InkCanvas/App.cs Sets up windowing/input, selects backend per OS, renders InkCanvas to swapchain.
sources/Experiments/FluidTank/FluidTankRenderer.cs Updates formats and composites; tightens render pass setup formatting; preserves reflection creation logic.
sources/Experiments/FluidTank/FluidSimulation.cs Compacts GridDimensions initialization formatting.
sources/Experiments/FluidTank/Assets/Shaders/Scene.slang Writes alpha for “frame” material to support fluid occlusion logic.
sources/Experiments/FluidTank/Assets/Shaders/FluidSurface.slang Stores linear depth in attributes to support later occlusion checks.
sources/Experiments/FluidTank/Assets/Shaders/FluidComposite.slang Adds frame-occlusion logic so scene/frame stays visible when fluid reconstructs at low res.
sources/Experiments/FluidTank/App.cs Reorders init assignments and window options formatting.
sources/Experiments/CornellBox/App.cs Reorders init assignments and window options formatting.
sources/Directory.Packages.props Updates Avalonia, SkiaSharp, Slangc.NET, Uno.WinUI versions.
Suppressed comments (2)

sources/Views/Zenith.NET.Views.WPF/Surface.cs:113

  • ID3D11DeviceContext::Begin is not valid for an EVENT query (and the current QueryDesc defaults to EVENT). This can trigger debug-layer errors or undefined behavior. Use End(Query) after CopyResource and poll GetData for completion without Begin().
        D3D.D3D11DeviceContext.Begin(Query);
        D3D.D3D11DeviceContext.CopyResource((ID3D11Resource*)D3D9SharedTexture.Handle, (ID3D11Resource*)D3D11RenderTarget.Handle);
        D3D.D3D11DeviceContext.End(Query);

sources/Views/Zenith.NET.Views.Maui/Platforms/Windows/Surface.cs:106

  • ID3D11DeviceContext::Begin is not valid for an EVENT query (and the current QueryDesc defaults to EVENT). This can trigger debug-layer errors or undefined behavior. Use End(Query) after CopyResource and poll GetData for completion without Begin().
        D3D.DeviceContext.Begin(Query);
        D3D.DeviceContext.CopyResource((ID3D11Resource*)backBuffer.Handle, (ID3D11Resource*)Texture.Handle);
        D3D.DeviceContext.End(Query);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread sources/Views/Zenith.NET.Views.WPF/Surface.cs
Comment thread sources/Views/Zenith.NET.Views.WinUI/ZenithView.WinUI.cs
Comment thread sources/Views/Zenith.NET.Views.Maui/Platforms/Windows/Surface.cs
Comment thread sources/Views/Zenith.NET.Views.WinUI/ZenithView.WinUI.cs Outdated
Comment thread sources/Views/Zenith.NET.Views.WPF/ZenithView.cs
Comment thread sources/Views/Zenith.NET.Views.WinForms/ZenithView.cs
Comment thread sources/Views/Zenith.NET.Views.Avalonia/ZenithView.cs
Updated NuGet.Packaging.props to use version 1.0.0, moving from the 1.0.0-rc release candidate to the stable release.

@qian-o qian-o left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1

Removed explicit DeviceContext.Begin/End(Query) calls in Surface.cs and ZenithView.WinUI.cs. Resource copy and query data polling logic remain unchanged.
@qian-o
qian-o merged commit 02d2fc8 into master Aug 5, 2026
2 checks passed
@qian-o
qian-o deleted the fix/views branch August 5, 2026 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants