Thursday, February 25, 2010

D3D 10 Full Screen Shenanigans

So I've been compiling release builds of my emulator lately, and been hosting them here ), and decided to add some full screen support. (sidebar; if anyone knows of some decent free hosting with Frontpage extensions, suitable for hosting ClickOnce packages let me know. It's shocking that not even MSFT's codeplex does

So, since I'm already happily rendering in a HwndHost, inside a WPF form, I figured it'd be a simple call to swapChain.SetFullScreenState(true, null). No such luck! It blowed up and I had to fire up DebugView to see what's going on in there. (sidebar the 2nd; VS 2010 RC doesn't seem to capture the native debug output, perhaps a bug?).

So, what's the story in there?

[5576] IDXGISwapChain::SetFullscreenState: Fullscreen is not allowed for swapchains targetting a child window. Applications are advised to create a second swapchain targetting a non-child window.

Oh yeah? Well scroo yoo too DXGI. I guess that makes sense.

Since I'd been advised to create a second swapchain, I decided that I would do just that. But, it needs to target a non-child window. Which is easy enough, it's a matter of creating a new (WinForms) Form and using it's window handle in the mode description.

So, to create the new swapchain, it's as easy as setting up a DXGI factory and doing the such:


fullSwapChainDescription = new DXGI.SwapChainDescription();
fullSwapChainDescription.ModeDescription = fullDesc;
fullSwapChainDescription.SampleDescription = sampleDescription;
fullSwapChainDescription.BufferCount = 2;
fullSwapChainDescription.Flags = DXGI.SwapChainFlags.None;
fullSwapChainDescription.IsWindowed = false;
fullSwapChainDescription.OutputHandle = myForm.Handle;
fullSwapChainDescription.SwapEffect = DXGI.SwapEffect.Discard;
fullSwapChainDescription.Usage = DXGI.Usage.RenderTargetOutput;

FullSwapChain = new DXGI.SwapChain(dxgiFactory, _device, fullSwapChainDescription);


_device is my D3D device, created earlier.

So, I have 3 SwapChain objects, one Windowed, one FullScreen, and one which holds a reference to the Active one, and this is toggled.

But it's not that easy! Firstly, if I create the new swapchain during app startup, the screen will blank out for a moment. So, I defer it until the first time it is needed. Secondly, switching the swap chain isn't enough. My code is set to render to a resource (texture) which is created from the orignal swap chain. So, the resource and RenderTargetView need to be rebuilt:

if (resouce != null) resource.Dispose();
resource = Texture2D.FromSwapChain(ActiveSwapChain, 0);
RenderTarget = new D3D10.RenderTargetView(_device, resource
);
tileFilters[tileFilters.Count - 1].RenderToTexture(resource);
tileFilters[tileFilters.Count - 1].RenderTarget = RenderTarget;


The last two lines are specific to my app, they set the RenderTarget on the last stage in my rendering chain, thus making it render to the swapchains buffer.

There's more that must be done, the ViewPort should be resized to match the new swapchain.

So, the strangest thing is in switching back to windowed mode. After setting the ActiveSwapChain, it was bombing out of the Toggle method I had wrote, leaving the app in a weird hybrid state. I could only correct it by including a Thread.Sleep(500) in there. I don't like this, obviously. My gut tells me that the emulator is requesting frames to be drawn in the interim, but it really should not be so, as the update calls should be blocked by a lock(this) during the swap.

Well, I'm not a DXGI guru yet, so I guess I'll just keep to the googling and hacking until I figure it out. This does seem to work cleanly, however, despite the icky Sleep call.

Anyone wanting to try my emulator may do so at the link above. If you want to play nintendo games for free, you're probably better off elsewhere. It's still chock full of bugs, the new UI was composed over the last few days from the detritus of fishbulb's past. But, there it is. 10NES.

In other news, if you happen to be looking for a talented coder to join your team in the Baltimore/Washington/Annapolis area(s), feel free to get in touch with me.

No comments: