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.