Keep the confetti canvas usable after it is unloaded and reloaded - #3467
Open
FrayxRulez wants to merge 1 commit into
Open
FrayxRulez wants to merge 1 commit into
FrayxRulez wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported by crash telemetry on 12.10.7.
Exception
NativeException: ACCESS_VIOLATION Reading address 0x0000000000000088, on the UI thread:Cause
Line 855 of Win2D 1.28.3's
CanvasAnimatedControl.cppism_gameLoop->StopDispatcher();. Disassembled from the shippedMicrosoft.Graphics.Canvas.dll(PDB matched):mov rax,[rbx+348h]loadsm_gameLoop, thenmov rcx,[rax+88h]readsCanvasGameLoop::m_gameLoopThread(the member after the 0x50-byterecursive_mutexand six pointers/bools). Som_gameLoopis null whileIsLoaded()- checked a few instructions earlier - is true.ConfettiView.OnUnloadedcallsCanvas.RemoveFromVisualTree(). The canvas is the root ofConfettiView's template, and Win2D'sRemoveFromVisualTreeImplonly knows how to detach an element from aPanel,UserControlorContentControlparent, so the control stays in the tree. What does happen is thatCanvasAnimatedControl::RemoveFromVisualTreeresetsm_canvasSwapChainPanel. When the canvas is later loaded again,CanvasAnimatedControl::Loaded()sees no swap chain panel, takes its designer path (theassertis compiled out) and returns without creating the game loop, butBaseControl::OnLoadedstill setsm_isLoaded = true. The next change that needs a draw - a resize, a DPI change - runsChangedImpl, which checksIsLoaded()and dereferences the null game loop.MainPagerealizesConfettion the first confetti and never unloads it (theCompletedhookup is commented out), so every later unload/reload of the page arms this: the passcode lock does exactly that (WindowContext.Lockswaps the window content,Unlockrestores it). The log tails end either onHiding passcode lockor on a window resize or restore, i.e. the first draw request after an earlier reload. The same path also left confetti silently broken after a reload, sinceCanvaswas nulled.Change
RemoveFromVisualTreeand stop nullingCanvas; Win2D already destroys the game loop onUnloadedand recreates it onLoaded, as long as it still has its swap chain panel.RemoveFromVisualTreewas there to break the cycle Win2D creates by holdingDrawhandlers strongly.Drawis now subscribed only while the canvas is loaded, with a load count mirroring Win2D's ownm_loadedCount, sinceLoadedfor a new parent can arrive beforeUnloadedfor the old one.Loaded/Unloadedstay subscribed, which is what lets the view recover.Unbuilt: syntax-checked with Roslyn only, not compiled or run.