What I am trying to capture screen with DirectX and display with WPF's Image (then maybe do some 2D control to 3D stuff). I already implemented capture with Win32 API which doesn't look pretty. As for DWM, there's no way to go 3D with it.
Well, so much for the background. Basically I am referencing to this post, using managed DirectX to capture screen.
I created a DirectX device:
PresentParameters presentParameters = new PresentParameters { Windowed = true, SwapEffect = SwapEffect.Discard }; WindowInteropHelper windowInteropHelper = new WindowInteropHelper(this); _device = new Device(0, DeviceType.Hardware, windowInteropHelper.Handle, CreateFlags.SoftwareVertexProcessing, presentParameters);
Then I created a surface and get the front buffer data:
_surface = _device.CreateOffscreenPlainSurface(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, Format.A8R8G8B8, Pool.Scracth); _device.GetFrontBufferData(0, _surface);
But when I tried to assign it to a D3DImage:
_image = new D3DImage(); _image.IsFrontBufferAvailableChanged += ImageOnIsFrontBufferAvailableChanged; _image.Lock(); _image.SetBackBuffer(D3DResourceType.IDirect3DSurface9, (IntPtr) _surface.UnmanagedComPointer); //ArgumentException Here _image.Unlock();
I got an exception at SetBackBuffer
ArgumentException: Back buffer's usage does not meet the requirements for the resource type.
So I did some digging, found a MSDN document specifies the required back buffer settings:
The following list shows the required back buffer settings for the IDirect3DSurface9 type.
D3DFMT_A8R8G8B8 or D3DFMT_X8R8G8B8
D3DUSAGE_RENDERTARGET
D3DPOOL_DEFAULT
So my surface's format is A8R8G8B8, but it cannot be Pool.Default. Otherwise I will get anInvalidCallException
at _device.GetFrontBufferData(0,
_surface);
Well, after some more digging, I set it to Pool.SystemMemory. And make a copy to a surface in Pool.Default:
_defaultSurface = _device.CreateOffscreenPlainSurface(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, Format.A8R8G8B8, Pool.Default); _device.UpdateSurface(_surface, _defaultSurface );
But I am still getting that ArgumentException when SetBackBuffer.
I couldn't figure it out since then.
Any ideas? Thanks.