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

Strange problem with Microsoft.Graphics.Canvas.Geometry.CanvasPathBuilder #948

Open
ibelchamber opened this issue Jan 11, 2024 · 13 comments

Comments

@ibelchamber
Copy link

Hi,
We have a very large and complex solution which does quite a lot of bitmap handling and graphics display etc. One of the things we do is to display on a win2d canvas a number of shapes including polygons. We are suffering occasionally and completely randomly, pauses in our application of about 8 seconds, then things start running again. It I hit break when this pause happens, we are always at the same line:

Using pb As New Microsoft.Graphics.Canvas.Geometry.CanvasPathBuilder(args.DrawingSession.Device)

Often while everything is stuck, we usually see an error showing in the output window every 2 seconds:

EventSource Error: ERROR: Exception during EventCounter cpu-usage metricProvider callback: Attempted to divide by zero

The dispatcher also gets stuck during the pause.

There seems to be little information about this error.

Generally, if we try to reduce how much drawing is going on, we see a reduction in the frequency of the problem, but I cannot find any particular trigger.

Are there any possible explanations for this or does anyone know a bit more about this error and where it might be coming from?

Thanks.

@getrou
Copy link
Member

getrou commented Jan 11, 2024

Win2D does use EventSource objects, but the "cpu-usage metricProvider" bit puzzles me. What version of Win2D are you using?

@ibelchamber
Copy link
Author

ibelchamber commented Jan 11, 2024

Hi, thanks for your answer, I was running 1.27.0, I have upgraded to the latest 1.27.1 , it is still the same. I have spent some time looking for that error and can't really find anything. It is copied exactly from the output window

@getrou
Copy link
Member

getrou commented Jan 11, 2024

Perfect, symbols for 1.27.1 will work great. It looks like you're using managed code. If you turn on mixed (native and managed) debugging, you will get a deeper stack, and we'll get a better look at what's happening inside Win2D.

@ibelchamber
Copy link
Author

Thanks, actually I tried that, and made sure break on all errors is on, but the debugger does not stop on the error, so I can't see the stack. The error only pops up in the output window and the application continues

@getrou
Copy link
Member

getrou commented Jan 12, 2024

Ah, that makes sense. When you break in during the multiple second pause, you said it always stops at the line:
using pb As New Microsoft.Graphics.Canvas.Geometry.CanvasPathBuilder(args.DrawingSession.Device)
With mixed native and managed debugging, is there any more info about where within that constructor the application is hanging?

@ibelchamber
Copy link
Author

ok above that in the stack is:

System.Private.CoreLib.dll!System.Threading.SynchronizationContext.WaitHelper(System.IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) Unknown
[Native to Managed Transition]
[Managed to Native Transition]

I was able to go to the code and I see:

[CLSCompliant(false)] protected static int WaitHelper(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) { if (waitHandles == null) { throw new ArgumentNullException("waitHandles"); } **return WaitHandle.WaitMultipleIgnoringSyncContext(waitHandles, waitAll, millisecondsTimeout);** }

@getrou
Copy link
Member

getrou commented Jan 12, 2024

Hm, that's a system API, not a Win2D API. Are there any stack frames inside Microsoft.Graphics.Canvas.dll?

@ibelchamber
Copy link
Author

Not that I can see, this is parallel stacks, cSpOverlay.DrawShape is our function calling CanvasPathBuilder which is where the delay is

Capture

@getrou
Copy link
Member

getrou commented Jan 16, 2024

I'm surprised that CanvasPathBuilder is not on that stack anywhere, I think this stack might be missing the native frames. Shouldn't there probably be frames in between those transitions to/from native/managed code?

Could you double check and make sure that native debugging is enabled and that your symbols for Microsoft.Graphics.Canvas.dll are loading correctly?

@ibelchamber
Copy link
Author

Thanks again for your time on this. Mixed debugging is on, I have loaded symbols but nothing else seems to show up.

I would really like to explain and solve this but for now it is slightly less urgent as due to urgency I have been forced to find a workaround. We have a large number of fixed shapes including polys and a small number of animated / moving shapes. Redraw is frequent to make the movement ok, but of course this is doing a lot of repeat rendering for the fixed shapes.

So I floated another CanvasControl over the original one, and send all the fixed shapes to the rear one, and just invalidate and draw the front one to do the animation. This is probably more efficient anyway but it seems to greatly reduce the load and prevent the delays.

I still see the error very occasionally so this is not ideal and needs more work but at least from the user side it seems to run correctly. Any other thoughts please let me know.

We are working the graphics system quite hard and drawing multiple canvascontrols. I was concerned about thread safety, we did have some drawing done in a background task but making everything draw on the dispatcher did not seem to prevent the problem

@ibelchamber
Copy link
Author

A bit more info: Although the debugger was not stopping on my system, it was on someone else's system. I've attached some pics from Visual Studio. Any further help on explaining this would be very welcome,

Thanks, Ian

Screenshot 2024-01-18 094756
3
divide by zero exception
Screenshot 2024-01-17 100919
Screenshot 2024-01-17 111624

@getrou
Copy link
Member

getrou commented Feb 1, 2024

That divide by zero error has really thrown me for a loop, that's very strange. The error about multiple calls to CreateDrawingSession is maybe more diagnosable. You mentioned you were doing drawing on multiple threads? If so, you'd have to make sure that only one drawing session per render target is active at a time.

@ibelchamber
Copy link
Author

Ok I tried, but I am not sure it is easy. I can use async and I can use a semaphore to do a canvas.invalidate / render session one at a time. But I can be doing a render (off screen or on screen), and something else might trigger a canvas invalidate / render. Obviously I can't use async in the render as by the time the render happens the drawing session has passed.

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