The goal: Write "minimum viable", no frills or extras code that sets up SharpDX 12 (a C# wrapper around DirectX 12), creates a window, and executes a present loop that clears the screen to RGBA (0, 0, 1, 1).
The expectation: Having followed a DirectX 12 setup tutorial as best as I can, I would then get a window with a blue background.
The outcome: On the second run through the loop, on the line "swapChain.Present(1, SharpDX.DXGI.PresentFlags.None);" The error message "SharpDX.SharpDXException: HRESULT: [0x887A0005], Module: [SharpDX.DXGI], ApiCode: [DXGI_ERROR_DEVICE_REMOVED/DeviceRemoved], Message: The GPU device instance has been suspended. Use GetDeviceRemovedReason to determine the appropriate action.
at SharpDX.Result.CheckError() at SharpDX.DXGI.SwapChain.Present(Int32 syncInterval, PresentFlags flags) at DirectX12BlueScreen.Program.Main(String[] args) in *\DirectX12BlueScreen\DirectX12BlueScreen\Program.cs:line 114" printed to the console window (which I am using for debug output)
What I am looking for: Why the error is happening (the device has certainly not been removed); what part of my code is causing the error; and a solution to the problem, if the preceding two pieces of information do not supply that information.
As the full code is 165 lines, I have posted the loop here, and the full code in a pastebin: https://pastebin.com/vctaYkNC
while(form.Visible)
{
commandAllocator[0].Reset();
commandList.Reset(commandAllocator[0], null);
commandList.SetViewport(viewport: viewport);
commandList.SetScissorRectangles(rectangle: scissorsRectangle);
commandList.ResourceBarrierTransition(
resource: renderTargets[0],
stateBefore: ResourceStates.Present,
stateAfter: ResourceStates.RenderTarget);
commandList.ClearRenderTargetView(
renderTargetView:
rtvDescriptorHeap.CPUDescriptorHandleForHeapStart,
colorRGBA: new RawColor4(0f, 0f, 1f, 1f));
commandList.ResourceBarrierTransition(
resource: renderTargets[0],
stateBefore: ResourceStates.RenderTarget,
stateAfter: ResourceStates.Present);
commandList.Close();
commandQueue.ExecuteCommandList(commandList);
swapChain.Present(1, SharpDX.DXGI.PresentFlags.None);
Application.DoEvents();
}
Edit: Using information supplied by PhillipH, I now have a more accurate error readout: "System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception. at SharpDX.Direct3D12.GraphicsCommandList.ClearRenderTargetView(CpuDescriptorHandle renderTargetView, RawColor4 colorRGBA, Int32 numRects, RawRectangle[] rectsRef) at SharpDX.Direct3D12.GraphicsCommandList.ClearRenderTargetView(CpuDescriptorHandle renderTargetView, RawColor4 colorRGBA) at DirectX12BlueScreen.Program.Main(String[] args) in *\DirectX12BlueScreen\DirectX12BlueScreen\Program.cs:line 138"
I was not setting up the render targets correctly, and I wasn't using fences at all. I was using SwapChain rather than SwapChain3, and so couldn't get the current buffer index. The correct code has been put into a pastebin for future reference.
It successfully rendered as intended for three minutes, so I think I can call this one resolved.
Thanks to PhillipH, without whose help I'd still be wondering how to get good error messages.
The working render loop:
while (form.Visible)
{
commandAllocator[0].Reset();
commandList.Reset(commandAllocator[0], null);
commandList.ResourceBarrierTransition(
resource: renderTargets[currentBufferIndex],
stateBefore: ResourceStates.Present,
stateAfter: ResourceStates.RenderTarget);
renderTargetView =
rtvDescriptorHeap.CPUDescriptorHandleForHeapStart +
currentBufferIndex *
renderTargetViewHeapSize;
commandList.ClearRenderTargetView(
renderTargetView: renderTargetView,
colorRGBA: new RawColor4(0f, 0f, 1f, 1f));
commandList.ResourceBarrierTransition(
resource: renderTargets[currentBufferIndex],
stateBefore: ResourceStates.RenderTarget,
stateAfter: ResourceStates.Present);
commandList.Close();
commandQueue.ExecuteCommandList(commandList);
swapChain.Present(1, SharpDX.DXGI.PresentFlags.None);
long fenceToWaitFor = fenceValue;
commandQueue.Signal(fence[0], fenceValue);
++fenceValue;
if (fence[0].CompletedValue < fenceValue)
{
fence[0].SetEventOnCompletion(fenceToWaitFor,
fenceEvent.SafeWaitHandle.DangerousGetHandle());
fenceEvent.WaitOne();
fenceEvent.Reset();
}
currentBufferIndex = swapChain.CurrentBackBufferIndex;
Application.DoEvents();
}
User contributions licensed under CC BY-SA 3.0