Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CanvasControl and ScrollViewer causes flickering. #125

Closed
SebastianStehle opened this issue Aug 5, 2015 · 16 comments
Closed

CanvasControl and ScrollViewer causes flickering. #125

SebastianStehle opened this issue Aug 5, 2015 · 16 comments

Comments

@SebastianStehle
Copy link

Hello together,

I render a canvas behind a ScrollViewer to support scrolling and zooming (I know that this is a strange solution, but all important interfaces are internal or sealed).

private void CanvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
    float zoom = scrollViewer.ZoomFactor;

    float inverseZoom = 1f / scrollViewer.ZoomFactor;

    float scaledContentW = Document.Size.X * scrollViewer.ZoomFactor;
    float scaledContentH = Document.Size.Y * scrollViewer.ZoomFactor;

    float translateX;
    float translateY;

    if (scaledContentW < scrollViewer.ViewportWidth)
    {
        translateX = ((float)scrollViewer.ViewportWidth * inverseZoom - Document.Size.X) * 0.5f;
    }
    else
    {
        translateX = -inverseZoom * (float)scrollViewer.HorizontalOffset;
    }

    if (scaledContentH < scrollViewer.ViewportHeight)
    {
        translateY = ((float)scrollViewer.ViewportHeight * inverseZoom - Document.Size.Y) * 0.5f;
    }
    else
    {
        translateY = -inverseZoom * (float)scrollViewer.VerticalOffset;
    }

    float visibleX = inverseZoom * (float)scrollViewer.HorizontalOffset;
    float visibleY = inverseZoom * (float)scrollViewer.VerticalOffset; ;

    float visibleW = Math.Min(Document.Size.X, inverseZoom * (float)scrollViewer.ViewportWidth);
    float visibleH = Math.Min(Document.Size.Y, inverseZoom * (float)scrollViewer.ViewportHeight);

    Rect2 visibleRect = new Rect2(visibleX, visibleY, visibleW, visibleH);

    transform =
        Matrix3x2.CreateTranslation(
            translateX,
            translateY) *
        Matrix3x2.CreateScale(zoom);

    // Render with Transform
}

This works fine but the text is jumping around by 1 or 2 pixels. I thought this might happen because of clear type, but even when I change the textaliasing to grayscale it doesnt help.

I render the text in the vertical and horizontal center of a rect. I also tried to position it manually to ensure that I dont get any subpixels but it doesnt help.

Any ideas?

EDIT: I just noticed that sometimes the whole canvas content jumps around 10 pixels or so when zooming, very strange.

@shawnhar
Copy link
Member

shawnhar commented Aug 5, 2015

I think the source of this instability must be coming from one of your inputs to this function.

What is Document.Size? Are you sure that isn't changing?

Is it possible the ScrollViewer itself could be unstable? Try making its contents visible so you can see whether that matches what the CanvasControl is doing.

@SebastianStehle
Copy link
Author

Hi, the document size is always constant. I added some some blue rectangles to the scroll viewer and recognized that there is difference of some pixels when scroling.

Especially when zooming very fast, I get this problems. I guess it are general synchronization issues, but I dont know. I use a normal canvas control and registers itself the CompositionTarget.Rendering event. Therefore I thought that the rendering of xaml controls and Win2D should be synchronized.

Using an AnimatedCanvasControl makes the things worse (btw: you should think about some inheritance here, very hard to swap the controls).

@SebastianStehle
Copy link
Author

I created a sample application. I recognized that XAML has the same problem with texts, but when zooming very fast you will see the synchronization problems.

@SebastianStehle
Copy link
Author

I updated the sample with an xaml control that is transformed in the same way. It has the same problem.

So there are 2 scenarios:
#1 My transformation is wrong (I dont think so)
#2 ScrollViewer has a bug (I dont hope so, it is not easy to implement it by yourself).

@SebastianStehle SebastianStehle changed the title Text Transformation causes "unsmooth" rendering. CanvasControl and ScrollViewer causes flickering. Aug 6, 2015
@shawnhar
Copy link
Member

shawnhar commented Aug 6, 2015

Any chance you could share this sample?

There may not be anything we can do if pure XAML shows the same issue without Win2D even involved, but I'd like to take a look.

@SebastianStehle
Copy link
Author

Sorry, I have forgotten to add the link: https://github.com/SebastianStehle/Win2DZoomTest

@shawnhar
Copy link
Member

shawnhar commented Aug 6, 2015

Thanks for the excellent repro! I see the same jerking issues. Unfortunately though I think this isn't something we can do anything about in Win2D.

I believe there are three separate things going on here:

  • Extra latency between the content directly in the ScrollViewer vs. content that is separately updated in response to ScrollViewer zoom/pan is expected. This is because XAML rendering and some forms of simple animation happen on a dedicated rendering thread, but all your event handlers run on the UI thread. So there is inevitably some latency in these other controls getting updated to match the ScrollViewer. The only solution for that is to put your Win2D content inside the ScrollViewer (or just live with the latency).
  • I see some pan discontinuities due to the viewport size changing when the scrollbars appear/hide due to changing zoom level. Setting the scroll view to always or never show scrollbars avoids that.
  • I also see some general jitter when using pinch zoom on my touch monitor, which applies equally to all the content. Not sure how much of this is specific my hardware, but it's definitely not entirely smooth.

@SebastianStehle
Copy link
Author

Thanks for your response, I think you are right, that the problem (flickering) occurs when the scrollbars become visible. I have the impression that at this point of time the scene is jumping some pixels to the right and then back to the right position, when the horizontal scrollbar becomes visible.

But I dont understand why, even when I always show the scrollbars it doesnt change and I have written down the numbers of the translation value and the zoom factor and couldnt find the issue.

@shawnhar
Copy link
Member

shawnhar commented Aug 6, 2015

I suspect what is happening is that the arrival of the scrollbar changes the viewport size, which you use in the transform computation, but your reading of the value of that size is not synchronized with the viewport pan/zoom values changing.

I don't see this kind of flicker if I force the scrollbars to always on or always off.

@SebastianStehle
Copy link
Author

Even when I use ActualHeight and ActualWidth I see the problem, I recorded my screen and watched the video with 25% speed to be sure.

@shawnhar
Copy link
Member

shawnhar commented Aug 6, 2015

Strange, I don't see that at all.

Regardless, I don't think there's going to be much you can do to improve this given how hard the ScrollViewer tries to be asynchronous on the XAML rendering thread.

Recommend either moving your scrolling content to be true children of the ScrollViewer (perhaps using virtual surfaces once we add those to Win2D), or doing your own scrolling logic some other way.

@SebastianStehle
Copy link
Author

I think you are right. I see the same problem with xaml controls and transformations, so either my eyes or the scrollviewer is broken in some way. The issue can be closed.

Do you know when you are going to release the virtual surface?

@shawnhar
Copy link
Member

shawnhar commented Aug 6, 2015

We are working on virtual surfaces this sprint.

@shawnhar shawnhar closed this as completed Aug 6, 2015
@SebastianStehle
Copy link
Author

I found the issue. I was zooming in and out for some iterations and recognized that the offset and zoom numbers look good.

But using this values to transform an x value of 500 you see the problem: https://www.dropbox.com/s/9ak6ohg4zb1mnxa/Test.png?dl=0

I dont know the reason, perhaps some floating point problem but this explains where the flickering comes from. Do you have any idea how to solve it?

@shawnhar
Copy link
Member

shawnhar commented Aug 6, 2015

What am I looking at here? Can you explain what the columns in this table are?

@SebastianStehle
Copy link
Author

Sorry:

Column 1: The computed zoom value of the transformation matrix (M11) = ScrollViewer.ZoomFactor
Column 2: The computed x offset of the matrix (See above)
Column 3: The x value of the result of matrix * vector (500, 500), here: Colum1 * 500 + Column2

The charts show each three columns.

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

No branches or pull requests

2 participants