fix: derive DPI scale from surface size for correct RDP and per-monitor rendering - #2156
fix: derive DPI scale from surface size for correct RDP and per-monitor rendering#2156beto-rodriguez wants to merge 1 commit into
Conversation
Fixes incorrect chart rendering when using Remote Desktop (RDP) or when moving between monitors with different DPI settings. Previously, DPI was read from system metadata APIs (PresentationSource.CompositionTarget in WPF, DeviceDisplay.MainDisplayInfo in MAUI, XamlRoot.RasterizationScale / DisplayInformation in WinUI) which can return stale or incorrect values in RDP sessions (reporting the client machine's DPI instead of the session DPI). The fix computes the scale factor directly from the ratio of the rendering surface's physical pixel dimensions to the control's logical size on every frame. This is always accurate regardless of how DPI is reported by the OS, handles per-monitor DPI changes automatically, and removes the need for the MainDisplayInfoChanged event subscription in MAUI. Affected frameworks: WPF (CPU+GPU), MAUI (CPU+GPU), WinUI/UNO (CPU+GPU). Avalonia, WinForms, Eto, and Blazor are not affected as they handle DPI through their own framework pipelines. Fixes #2137 Co-authored-by: Beto Rodríguez <beto-rodriguez@users.noreply.github.com>
Thanks for your contribution!The build and test process is starting. This may take a while. Packing complete!You can download the NuGet packages for this build here (dev-312). Section 1: Core & Snapshot Tests ✅Core ✅ | Snapshot ✅ Code Coverage 📉
Section 2: UI Tests ✅Windows ✅ | Linux ✅ | Mac ✅ | Browser ✅ | Android ✅ | iOS ✅ |
There was a problem hiding this comment.
Pull request overview
This PR fixes DPI scaling issues that cause incorrect chart rendering in RDP sessions and when moving windows across monitors with different DPI settings by deriving the scale factor from the render surface pixel size vs. the control’s logical size on each frame.
Changes:
- WinUI/UNO: Compute per-frame X/Y scale from
BackendRenderTarget/SKImageInfosize divided byActualWidth/ActualHeight, removing reliance onDisplayInformation/XamlRoot.RasterizationScale. - MAUI: Replace
DeviceDisplay.MainDisplayInfo.Densitytracking with per-frame scale derived from surface pixel size vs.Width/Height. - WPF: Replace
PresentationSource/TransformToDeviceDPI lookup with per-frame scale derived from surface pixel size vs.ActualWidth/ActualHeight.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/skiasharp/_Shared.WinUI/Rendering/GPURenderMode.cs | GPU path now scales canvas using surface/logical size ratio to reflect RDP/per-monitor DPI changes accurately. |
| src/skiasharp/_Shared.WinUI/Rendering/CPURenderMode.cs | CPU path now scales canvas using surface/logical size ratio to reflect RDP/per-monitor DPI changes accurately. |
| src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/Rendering/GPURenderMode.cs | GPU path now derives scale per frame from backend surface vs. view size; removes display-density event subscription. |
| src/skiasharp/LiveChartsCore.SkiaSharpView.Maui/Rendering/CPURenderMode.cs | CPU path now derives scale per frame from surface vs. view size; removes display-density event subscription. |
| src/skiasharp/LiveChartsCore.SkiaSharp.WPF/Rendering/GPURenderMode.cs | GPU path now derives DPI scaling from surface/logical size ratio instead of PresentationSource DPI APIs. |
| src/skiasharp/LiveChartsCore.SkiaSharp.WPF/Rendering/CPURenderMode.cs | CPU path now derives DPI scaling from surface/logical size ratio instead of PresentationSource DPI APIs. |
| { | ||
| var scaleX = args.Info.Width / (float)ActualWidth; | ||
| var scaleY = args.Info.Height / (float)ActualHeight; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = args.BackendRenderTarget.Width / (float)ActualWidth; | ||
| var scaleY = args.BackendRenderTarget.Height / (float)ActualHeight; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = args.BackendRenderTarget.Width / (float)ActualWidth; | ||
| var scaleY = args.BackendRenderTarget.Height / (float)ActualHeight; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = args.Info.Width / (float)Width; | ||
| var scaleY = args.Info.Height / (float)Height; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = args.Info.Width / (float)Width; | ||
| var scaleY = args.Info.Height / (float)Height; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = e.BackendRenderTarget.Width / (float)Width; | ||
| var scaleY = e.BackendRenderTarget.Height / (float)Height; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = e.BackendRenderTarget.Width / (float)Width; | ||
| var scaleY = e.BackendRenderTarget.Height / (float)Height; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = e.BackendRenderTarget.Width / (float)ActualWidth; | ||
| var scaleY = e.BackendRenderTarget.Height / (float)ActualHeight; | ||
| if (scaleX != 1f || scaleY != 1f) |
| { | ||
| var scaleX = e.BackendRenderTarget.Width / (float)ActualWidth; | ||
| var scaleY = e.BackendRenderTarget.Height / (float)ActualHeight; | ||
| if (scaleX != 1f || scaleY != 1f) |
Fixes incorrect chart rendering when using Remote Desktop (RDP) or when moving between monitors with different DPI settings.
Previously, DPI was read from system metadata APIs that can return stale or incorrect values in RDP sessions. The fix computes the scale factor directly from the ratio of the rendering surface's physical pixel dimensions to the control's logical size on every frame.
Fixed frameworks: WPF (CPU+GPU), MAUI (CPU+GPU), WinUI/UNO (CPU+GPU).
Closes #2137
Generated with Claude Code