简体   繁体   中英

DirectX12 commandList execution error

I've started to learn DirectX12 and i try to make some kind of simple engine. I follow the Frank D. Luna "Introduction to 3D programming with DirectX12" and i have got some problems. First during creating swapChain, filling description like this:

DXGI_SWAP_CHAIN_DESC swapChainDesc;
swapChainDesc.BufferDesc.Width = Core::displayWidth;
swapChainDesc.BufferDesc.Height = Core::displayHeight;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
swapChainDesc.BufferDesc.Format = Core::pixelDefinitionFormat;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
swapChainDesc.SampleDesc.Count = Core::multiSamplingLevel ? 4 : 1;
swapChainDesc.SampleDesc.Quality = Core::multiSamplingEnabled ? (Core::multiSamplingLevel - 1) : 0;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = (INT) Core::buffering;
swapChainDesc.OutputWindow = Core::mainWindow;
swapChainDesc.Windowed = true;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

// Note: Swap chain uses queue to perform flush.
ThrowIfFailed(Core::factory->CreateSwapChain(
    Core::commandQueue.Get(),
    &swapChainDesc,
    Core::swapChain.GetAddressOf()
));

I recive "bad parameter" error. I've already found solution on MSDN but i want to know what i'am doing wrong.

Second question is why have i:

D3D12 ERROR: ID3D12GraphicsCommandList::*: A single command list cannot write to multiple buffers within a particular swapchain. [ STATE_SETTING ERROR #904: COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES]

Durning execution of this clearing screen code fragment:

void Renderer::drawSomething() {

// Reuse the memory associated with command recording.
// We can only reset when the associated command lists have finished
// execution on the GPU.
ThrowIfFailed(Core::commandAllocator->Reset());

// A command list can be reset after it has been added to the 
// command queue via ExecuteCommandList. Reusing the command list reuses memory.
ThrowIfFailed(Core::commandList->Reset(Core::commandAllocator.Get(), NULL));

// Set the viewport and scissor rect. This needs to be reset 
// whenever the command list is reset.
Core::commandList->RSSetViewports(1, &Core::viewport);
Core::commandList->RSSetScissorRects(1, &Core::scissorsRectangle);

// Indicate a state transition on the resource usage.
Core::commandList->ResourceBarrier(
    1,
    &CD3DX12_RESOURCE_BARRIER::Transition(
        Core::getCurrentBackBuffer().Get(),
        D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_PRESENT,
        D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_RENDER_TARGET
    )
);



// Specify the buffers we are going to render to.
Core::commandList->OMSetRenderTargets(
    1,
    &Core::getCurrentBackBufferView(),
    true,
    &Core::getDSVHeapStartDescriptorHandle()
);

// Clear the back buffer and depth buffer.
Core::commandList->ClearRenderTargetView(
    Core::getCurrentBackBufferView(),
    DirectX::Colors::LightSteelBlue,
    0,
    NULL
);

Core::commandList->ClearDepthStencilView(
    Core::getDSVHeapStartDescriptorHandle(),
    D3D12_CLEAR_FLAGS::D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAGS::D3D12_CLEAR_FLAG_STENCIL,
    1.0f,
    0,
    0,
    NULL
);


//// Indicate a state transition on the resource usage.
Core::commandList->ResourceBarrier(
    1,
    &CD3DX12_RESOURCE_BARRIER::Transition(
        Core::getCurrentBackBuffer().Get(),
        D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_RENDER_TARGET,
        D3D12_RESOURCE_STATES::D3D12_RESOURCE_STATE_PRESENT
    )
);

// Done recording commands.
ThrowIfFailed(Core::commandList->Close());

// Add the command list to the queue for execution.
ID3D12CommandList* cmdsLists[] = {Core::commandList.Get()};
Core::commandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);

// swap the back and front buffers
ThrowIfFailed(Core::swapChain->Present(0, 0));
UINT buffering = Core::buffering;
Core::currentBackBuffer = (Core::currentBackBuffer + 1) % buffering;
Core::flushCommandQueue();
}

To not making big mess in this post, i won't place all code here, but if you would like to look how does it look like, or it would be important in this case, my whole repository is here: repository

It's very small and simlple, almost all code is placed in Core class.

Thank you in advance!

Edit: I found solution to second question. Problem was in this loop:

void Core::createSwapChainBuffersIntoRTVHeap() {
for (UINT i = 0; i < Core::buffering; i++) {
    CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHeapHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
    ErrorUtils::messageAndExitIfFailed(
        swapChain->GetBuffer(i, IID_PPV_ARGS(&swapChainBackBuffers[i])),
        L"B³¹d pobierania backBuffera!",
        GET_SWAPCHAIN_BACK_BUFFER_ERROR
    );

    device->CreateRenderTargetView(swapChainBackBuffers[i].Get(), NULL, rtvHeapHandle);
    //Zapamiêtuje offset, to jest sterta po prostu zwyk³a
    rtvHeapHandle.Offset(1, rtvDescriptorSize);
}

}

I did only one move to made this code look like this:

void Core::createSwapChainBuffersIntoRTVHeap() {
CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHeapHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
for (UINT i = 0; i < Core::buffering; i++) {
    ErrorUtils::messageAndExitIfFailed(
        swapChain->GetBuffer(i, IID_PPV_ARGS(&swapChainBackBuffers[i])),
        L"B³¹d pobierania backBuffera!",
        GET_SWAPCHAIN_BACK_BUFFER_ERROR
    );

    device->CreateRenderTargetView(swapChainBackBuffers[i].Get(), NULL, rtvHeapHandle);
    //Zapamiêtuje offset, to jest sterta po prostu zwyk³a
    rtvHeapHandle.Offset(1, rtvDescriptorSize);
}

}

After that. When the commandList closing gone right, i've got AccessViolationException in D3D12.dll on:

ThrowIfFailed(Core::swapChain->Present(0, 0));

Which after few hours of internet research i fixed by forcing WARP on this application using "dxcpl.exe". I assume that was because i work on laptop with HD4000 and Nvidia as second card, but i'm not sure.

This will not help you to fix the problem at once, but will give you much more information. DirectX12 wants you to push all commands into commandlists and it will only report an error when you call Close() on it. Note that you can not "resurrect" the commandlist that failed on Close() by resetting it, the best thing you can do is to delete it and then create a new commandlist. In this case you however may not update referenced resources. Don't really recommend you doing that.

What you indeed can do is to use the ID3D12InfoQueue interface to make your program break on D3D12 errors if the debugger is attached.

Get it from your device :

ID3D12InfoQueue* InfoQueue = nullptr;
Core::device->QueryInterface(IID_PPV_ARGS(&InfoQueue));

Enable "break on severity":

InfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
InfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
InfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, false);

And let it go:

InfoQueue->Release();

You can also set your InfoQueue to whitelist or blacklist sets of D3D12 error ids. Your error ID is D3D12_MESSAGE_ID_COMMAND_LIST_MULTIPLE_SWAPCHAIN_BUFFER_REFERENCES (code 904).

Hope that this will help someone to deal with this graphics API.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM