XNA Creators Club Online
Page 1 of 1 (3 items)
Sort Posts: Previous Next

IDXGIKeyedMutex is broken

Last post 14/11/2009 12:48 by tictac. 2 replies.
  • 02/11/2009 16:25

    IDXGIKeyedMutex is broken

    I am using Direct3D11 / DXGI 1.1 (in feature level 10_0).

    I have to create a keyed mutex texture2D to use DirectWrite.

    I can do this, and OpenSharedResource and see the texture dimensions in Direct2D.  I can get the IDXGIKeyedMutex on both devices.

    However, to illustrate this problem I totally remove the D2D/DirectWrite code, and....

    AcquireSync() ReleaseSync() is ok until I do something with the immediate context in d3d11. 

    For example, Acquire, ClearRenderTarget, Release will result in this error upon Release...

    First-chance exception at 0x75029617 in TestBed.exe: Microsoft C++ exception: _com_error at memory location 0x0a17eeb4..

    Subsequent attempts to Acquire will result in -2005270527 .. which translates to nothing on Earth.

    Another example, OMSetOutputTargets (to totally different textures) before AcquireSync will trigger AcquireSync to return -2147024809.

    This is not per frame.  Once it breaks, it breaks.  There are no real signs of the texture working or clearing to any color, ever, while in this keyedMutex mode.  Otherwise its fine??

    I dont know what to think???
    Dependency problem???

    Why is it being so difficult??
  • 10/11/2009 19:32 In reply to

    Re: IDXGIKeyedMutex is broken

    First of all, do you run it on Win7 or Vista with 7IP?

    Second, let me make sure my assumptions are correct.

    You have D3D10 device (shared with D2D) and D3D11 device with feature level 10_0.
    You create a shared resource on D3D11 device and then open it on D3D10 device and it works fine.
    Then you call AcquireSync on D3D11 device, call ClearRenderTarget and then call ReleaseSync which has unexpected behavior.

    How exactly does it fail, does it return a particular HRESULT value and prints this string in output log or does it actually throw an _com_error expection out of API call?

    If yes, any chance you got a minimal repro case?

    Thanks!
  • 14/11/2009 12:48 In reply to

    Re: IDXGIKeyedMutex is broken

    Windows 7 32 bit, and Visual Studio 2010 beta 2.
    I'm also using modified SlimDX, with DXGI 1.1 changes.

    The problem above has magically fixed itself, through recompiling or something.

    Now I have more issues with this API, but at least now I get some visual results and the AcquireSync return codes are consistent with the documentation, even if they are unexpected/illogical.
    1) My KeyedMutex is working. Commenting out all AcquireSync/ReleaseSync and I see nothing.
    2) ClearRenderTargetView on my text surface only works the first time - text starts to layer. Clearing possible via D2D maybe, but why is it failing via D3D when AcquireSync is successful?
    3) To force the mutex to work as above, I need to call my RenderText function once, immediately after creating my Devices/Swapchain. That must be before I create my render targets, shader resources,depth buffers,cubemaps, etc. Without this strange fix-up, 4 and 5 below apply.
    4) When RenderText exists purely in middle of my render loop, I get the following result on first frame - E_INVALIDARG when AcquireSync(0, INFINITE) is called. I will see a _com_error in the debug output.
    5) If RenderText is moved to the start of the render loop, specifically before I do OutputMerger/SetTargets, then WAIT_ABANDONED is returned for the D2D mutex (device 1), again first frame. I will see a _com_error on the ReleaseSync(1) just prior.
    6) This solution of creating 2 devices seems to cause PIX to just crash.

    I do have debug info on, in every case, and see nothing.

    Here are some of my functions....

            private void RenderText(string text) 
            { 
                try 
                { 
                    if (_textSurface.Mutex.Acquire(0)) 
                    { 
                        _device.ImmediateContext.ClearRenderTargetView(_textSurface.RenderView, new Color4(1, 1, 0, 0)); 
                        _textSurface.Mutex.Release(1); 
                    } 
                    else 
                        throw new Exception(); 
     
                    if (_textSurfaceKeyD2D.Acquire(1)) 
                    { 
                        SolidColorBrush scb = new SolidColorBrush(_dwRenderTarget, new Color4(1, 0, 1, 0)); 
     
                        _dwRenderTarget.BeginDraw(); 
                     //   _dwRenderTarget.FillRectangle(new SolidColorBrush(_dwRenderTarget, new Color4(1, 0, 0, 1)), new Rectangle(0,0, 500, 500)); 
                        _dwRenderTarget.DrawText(text, _tf, new Rectangle(0, 0, 500, 500), scb); 
                        _dwRenderTarget.EndDraw(); 
     
                        _textSurfaceKeyD2D.Release(2); 
                    } 
                    else 
                        throw new Exception(); 
                } 
                catch (Exception e) 
                { 
                    MessageBox.Show(e.Message); 
                } 
            } 

    now after that I will lock it to D3D as a shader variable and render a full screen quad, hence the Release(2).

    private void InitializeDirect2D(Adapter adapter) 
            { 
                // texture 
                _textSurface = new GPUTextureW(_device, Format.R8G8B8A8_UNorm, _frameSize, BindFlags.ShaderResource | BindFlags.RenderTarget, new SampleDescription(1, 0), resourceFlags: ResourceOptionFlags.KeyedMutex); 
                 
                // device 10 
                _device10_1 = new Device10_1(adapter, SlimDX.Direct3D10.DriverType.Hardware, SlimDX.Direct3D10.DeviceCreationFlags.Debug | SlimDX.Direct3D10.DeviceCreationFlags.BgraSupport, SlimDX.Direct3D10_1.FeatureLevel.Level_10_0); 
                 
                Surface surf = SlimDXHelper.OpenSharedResource(_textSurface.Texture, _device10_1); 
     
                // d2d factory 
                SlimDX.Direct2D.Factory d2Factory = new SlimDX.Direct2D.Factory(SlimDX.Direct2D.FactoryType.MultiThreaded, DebugLevel.Information); 
                 
                // dw factory 
                SlimDX.DirectWrite.Factory dwFactory = new SlimDX.DirectWrite.Factory(SlimDX.DirectWrite.FactoryType.Isolated); 
     
                _tf = new TextFormat(dwFactory, "Arial", FontWeight.Normal, SlimDX.DirectWrite.FontStyle.Normal, FontStretch.Normal, 20, "en-US"); 
     
                // query interface... for IDXGISurface 
                RenderTargetProperties rtp = new RenderTargetProperties(); 
                rtp.MinimumFeatureLevel = SlimDX.Direct2D.FeatureLevel.Direct3D10; 
                rtp.Type = RenderTargetType.Hardware; 
                rtp.Usage = RenderTargetUsage.None;             
                rtp.PixelFormat = new PixelFormat(Format.Unknown, AlphaMode.Ignore);                                    
     
                _dwRenderTarget = RenderTarget.FromDXGI(d2Factory, surf, rtp); 
                 
                _textSurfaceKeyD2D = new KeyedMutex(surf);                         
            } 

            SlimDX::DXGI::Surface^ SlimDXHelper::OpenSharedResource(Texture2D ^source, SlimDX::Direct3D10::Device ^device10) 
            { 
                // get shared handle 
                ID3D11Texture2D *p = reinterpret_cast<ID3D11Texture2D*>(source->ComPointer.ToPointer()); 
     
                IDXGIResource *pDXGI; 
                p->QueryInterface(__uuidof(IDXGIResource), (void**)&pDXGI); 
     
                HANDLE sharedHandle; 
                pDXGI->GetSharedHandle(&sharedHandle); 
                pDXGI->Release(); 
     
                // open shared resource 
                ID3D10Device *dev10 = reinterpret_cast<ID3D10Device*>(device10->ComPointer.ToPointer()); 
     
                IDXGIResource *dest; 
                HRESULT hr = dev10->OpenSharedResource(sharedHandle, __uuidof(IDXGIResource), (void**)&dest); 
     
                // get surface 
                IDXGISurface1 *pSurf; 
                dest->QueryInterface(__uuidof(IDXGISurface1), (void**)&pSurf); 
                dest->Release(); 
     
                return SlimDX::DXGI::Surface::FromPointer(IntPtr(pSurf)); 
            } 

            public ref class KeyedMutex 
            { 
                public
                    KeyedMutex(SlimDX::Direct3D11::Texture2D ^texture) 
                    { 
                        // ok to get mutex from texture, as done in the MS sample 
                        ID3D11Texture2D *r = reinterpret_cast<ID3D11Texture2D*>(texture->ComPointer.ToPointer()); 
     
                        IDXGIKeyedMutex *mut; 
     
                        if (r->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&mut) != S_OK) 
                            throw gcnew Exception("QueryInterface"); 
     
                        mutex = mut; 
                    } 
     
                    KeyedMutex(SlimDX::DXGI::Surface ^surface) 
                    { 
                        IDXGISurface *s = reinterpret_cast<IDXGISurface*>(surface->ComPointer.ToPointer()); 
     
                        IDXGIKeyedMutex *mut; 
     
                        if (s->QueryInterface(__uuidof(IDXGIKeyedMutex), (void**)&mut) != S_OK) 
                            throw gcnew Exception("QueryInterface"); 
     
                        mutex = mut; 
                    } 
     
                    bool Acquire(int device) 
                    { 
                        HRESULT hr = mutex->AcquireSync(device, INFINITE); 
     
                        if (hr == S_OK) 
                            return true
                        else if (hr == WAIT_ABANDONED) 
                            throw gcnew Exception("AcquireSync (" + device + ") WAIT_ABANDONED"); 
                        else if (hr == E_FAIL) 
                            throw gcnew Exception("AcquireSync (" + device + ") E_FAIL"); 
                        else if (hr == WAIT_TIMEOUT) 
                            throw gcnew Exception("AcquireSync (" + device + ") WAIT_TIMEOUT"); 
                        else if (hr == E_INVALIDARG) 
                            throw gcnew Exception("AcquireSync (" + device + ") E_INVALIDARG"); 
     
                        return false
                    } 
     
                    void Release(int device) 
                    { 
                        mutex->ReleaseSync(device); 
                    } 
     
                private
                    IDXGIKeyedMutex *mutex; 
            }; 

    My opinion is the DXGIKeyedMutex definitely needs more debug info as to whats goin on with these _com_errors, and Microsoft should have an example of how to use this with DirectX11.  I have seen the example on codeplex.  I have no clue about COM, but apparently _com_errors have descriptions or something so I will look into that.

    thanks.
Page 1 of 1 (3 items) Previous Next