asynchronous rendering of two threads
I got an error.
D3D12 CORRUPTION: ID3D12CommandList::ClearRenderTargetView: Two threads were found to be executing methods associated with the same CommandList at the same time. This will cause corruption of memory. Appropriate thread synchronization needs to occur external to the Direct3D API. 20076 and 22772 are the implicated thread ids. [ MISCELLANEOUS CORRUPTION #18: CORRUPTED_MULTITHREADING]
The crash line on the first threads is:
ID3D12ResourcePtr createBuffer(FBuffer::State initState, size_t size, const D3D12_HEAP_PROPERTIES& heapProps, FBuffer::BindFlags bindFlags)
{
........
ID3D12ResourcePtr pApiHandle;
d3d_call(pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufDesc, d3dState, nullptr, IID_PPV_ARGS(&pApiHandle)));
another crash line on the second thread is:
void RenderContext::clearRtv(const RenderTargetView* pRtv, const glm::vec4& color)
{
resourceBarrier(pRtv->getResource(), FResource::State::RenderTarget);
mpLowLevelData->getCommandList()->ClearRenderTargetView(pRtv->getApiHandle()->getCpuHandle(0), glm::value_ptr(color), 0, nullptr);
mCommandsPending = true;
}
I try to create the two RenderContexts and swapchain in different command queues, but the problem is not solved. I want the two threads run independently, but it seems it doesn't work
I tried to use two ResourceAllocator for the two render context, but I found the performance deteriorate (no threading).
It has nothing to do with the create. My guess is that thread 1 dispatched an execute which triggered a GPU execution but doesn't block the CPU, that's why you're seeing the crash inside createBuffer.
I think the problem is that some commands always use the main command-list (by calling gpDevice->getRenderContext()). Need to make them thread aware and make sure to use the correct context
yes I think you are right. but I have a question, the two threads both use one ResourceAllocator, right now
the creation of ResourceAllocator is like this:
mpResourceAllocator = ResourceAllocator::create(1024 * 1024 * 2, mpRenderContext->getLowLevelData()->getFence());
it uses the first render context'fence. But in my case the second render context's flush in another thread may be faster or slower than the first render context, so that means the fence value may be not equal to the first one.
in Device::executeDeferredReleases() you use the first fence value to release the buffer,
mpFrameFence->gpuSignal(mpRenderContext->getLowLevelData()->getCommandQueue());
uint64_t gpuVal = mpFrameFence->getGpuValue(); while (mDeferredReleases.size() && mDeferredReleases.front().frameID <= gpuVal) { mDeferredReleases.pop(); }
I think this fence value not good for asynchronous rendering of two threads
Change the code so that the resource-allocator gets the Device::mpFrameFence, that will remove the dependency on the render-context