Skip to content

fix: derive DPI scale from surface size for correct RDP and per-monitor rendering - #2156

Open
beto-rodriguez wants to merge 1 commit into
masterfrom
claude/issue-2137-20260421-1551
Open

fix: derive DPI scale from surface size for correct RDP and per-monitor rendering#2156
beto-rodriguez wants to merge 1 commit into
masterfrom
claude/issue-2137-20260421-1551

Conversation

@beto-rodriguez

Copy link
Copy Markdown
Collaborator

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

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>
Copilot AI review requested due to automatic review settings April 21, 2026 15:59
@github-actions

github-actions Bot commented Apr 21, 2026

Copy link
Copy Markdown

Thanks for your contribution!

The build and test process is starting. This may take a while.
You can find more details below as the process continues or at the actions tab.

Packing complete!

You can download the NuGet packages for this build here (dev-312).
The packages will be available for 30 days, you can either use them directly, or wait for this PR to be merged to have them published to NuGet.org.

Section 1: Core & Snapshot Tests ✅

Core ✅ | Snapshot ✅

Code Coverage 📉

Line Coverage
Before 80.5%
After 80.4%
Delta -.1%

Section 2: UI Tests ✅

Windows ✅ | Linux ✅ | Mac ✅ | Browser ✅ | Android ✅ | iOS ✅

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 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/SKImageInfo size divided by ActualWidth/ActualHeight, removing reliance on DisplayInformation / XamlRoot.RasterizationScale.
  • MAUI: Replace DeviceDisplay.MainDisplayInfo.Density tracking with per-frame scale derived from surface pixel size vs. Width/Height.
  • WPF: Replace PresentationSource/TransformToDevice DPI 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)
Comment thread src/skiasharp/LiveChartsCore.SkiaSharp.WPF/Rendering/CPURenderMode.cs Dismissed
{
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)
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.

Problem with correct scaling on high dpi

2 participants