locked
How do I dispose my SwapChainPanel -derived class and free memory without crashing?

    Question

  • Ok, I will try to explain as best as I can.   My app is mostly based on a Win8.1 XAML/DirectX sample (C#/C++). This one:
    http://code.msdn.microsoft.com/windowsapps/XAML-SwapChainPanel-00cb688b

    It creates a C++ class based ultimately on SwapChainPanel that can be used in a C# app.  The downside to using this is there seems to be no concern for freeing memory when done with the SwapChainPanel. (Other than using ComPtr for many of the interfaces.)  Indeed, many other developers complain that memory just increases when navigating back and forth to a page containing this panel, so it's not just me.

    I've tried to modify it so that I can explicitly call Dispose() from C# on the SwapChainPanel.  I've added virtual public destructors to both the DirectXPanelBase class that is directly based on SwapChainPanel and my actual class "MoleculePanel" which is based on DirectXPanelBase.

    I have verified that when I call Dispose() on the panel from the C# portion of the app, that all of the destructors are being called. I assume the destructor for the SwapChainPanel is then being called.  However, it immediately crashes the entire app.  I get an Access Violation reading location 0x000000c error followed by many thread exiting errors (0x80131506).  Finally, it says this:

    D3D11 WARNING: Process is terminating. Using simple reporting. Please call ReportLiveObjects() at runtime for standard reporting. [ STATE_CREATION WARNING #0: UNKNOWN] D3D11 WARNING: Live Producer at 0x09350E14, Refcount: 2. [ STATE_CREATION WARNING #0: UNKNOWN] D3D11 WARNING: Live Object at 0x09351C38, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN] D3D11 WARNING: Live Object at 0x09371C98, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]

    ...

    D3D11 WARNING:  Live Object at 0x091B9604, Refcount: 0. [ STATE_CREATION WARNING #0: UNKNOWN]
    D3D11 WARNING: Live                         Object :     40 [ STATE_CREATION WARNING #0: UNKNOWN]
    DXGI WARNING: Live Producer at 0x0932CD40, Refcount: 4. [ STATE_CREATION WARNING #0: ]
    DXGI WARNING:  Live Object at 0x06F03F18, Refcount: 3. [ STATE_CREATION WARNING #0: ]
    DXGI WARNING:  Live Object at 0x0939AC48, Refcount: 1. [ STATE_CREATION WARNING #0: ]
    DXGI WARNING: Live                         Object :      2 [ STATE_CREATION WARNING #0: ]
    First-chance exception at 0x6CBAA7BB (WINDOWS.UI.XAML.DLL) in MoleculeStudioUniversal.WindowsPhone.exe: 0xC0000420: Assertion Failure.


    Before I call Dispose(), I do stop the rendering asynchronous task (and the mouse/touch input asynchronous task). 

    What am I doing wrong?  Should I be manually releasing all of the ComPtr for the DirectX interfaces?  After reading about these, I thought they disposed themselves.  I just really need to know how to dispose of the SwapChainPanel and free all that memory...

    Thanks. 


    Lee McPherson


    • Edited by Lee McPherson Thursday, July 10, 2014 12:10 AM more spacing for reading
    Thursday, July 10, 2014 12:09 AM

Answers

  • Ok, solved my own problem.  It has nothing to do with disposing the SwapChainPanel using destructors.  I removed most of that stuff.  The problem lay with the low-latency touch input code that is suggested to use.  I had the following in my RenderLoopStart() function.  (It probably is overkill, but I just copied the RenderLoop code)

    auto workItemHandler2 = ref new WorkItemHandler([this](IAsyncAction^)
    	{
    		// The CoreIndependentInputSource will raise pointer events for the specified device types on whichever thread it's created on.
    		m_coreInput = CreateCoreIndependentInputSource(
    			Windows::UI::Core::CoreInputDeviceTypes::Mouse |
    			Windows::UI::Core::CoreInputDeviceTypes::Touch |
    			Windows::UI::Core::CoreInputDeviceTypes::Pen
    			);
    
    		// Register for pointer events, which will be raised on the background thread.
    		m_PointerWheelChangedToken = m_coreInput->PointerWheelChanged += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &MoleculePanel::OnPointerWheelChanged);
    		m_coreInput->PointerPressed += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &MoleculePanel::OnPointerPressed);
    		m_coreInput->PointerMoved += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &MoleculePanel::OnPointerMoved);
    		m_coreInput->PointerReleased += ref new TypedEventHandler<Object^, PointerEventArgs^>(this, &MoleculePanel::OnPointerReleased);
    
    		// Begin processing input messages as they're delivered.
    		m_coreInput->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit);
    	});
    	m_inputWorker = ThreadPool::RunAsync(workItemHandler2, WorkItemPriority::High, WorkItemOptions::TimeSliced);

    The function that is important is the ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit)!  According to the docs, this function with this option will run until the window is closed (not the page, the window).  So, I decided to try to forcefully stop it when I also called StopRenderLoop().   You just have to call StopProcessEvents on the Dispatcher.  It works like a charm!  The memory drops back to its original level before loading the page!  I can finally publish for 512MB devices :)

    oid MoleculePanel::StopRenderLoop()
    {
    	// Cancel the asynchronous task and let the render thread exit.
    	m_renderLoopWorker->Cancel();
    	m_inputWorker->Cancel();
    	m_coreInput->Dispatcher->StopProcessEvents();
    }


    Lee McPherson

    • Marked as answer by Lee McPherson Thursday, July 10, 2014 12:11 PM
    Thursday, July 10, 2014 12:10 PM