From 88bd5b2534f48a39beb8c62d2e7b597d91b04414 Mon Sep 17 00:00:00 2001 From: Wojciech Figat Date: Wed, 4 Jan 2023 12:06:56 +0100 Subject: [PATCH] Fix threading issues with GPU buffers mapping --- Source/Engine/Graphics/GPUDevice.cpp | 3 ++- .../GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp | 10 ++++++++-- .../Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.h | 1 + .../GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp | 3 ++- .../Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.h | 2 +- Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp | 2 +- 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index 432acc548..16f13d522 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -447,6 +447,8 @@ void GPUDevice::preDispose() SAFE_DELETE_GPU_RESOURCE(_res->PS_Clear); SAFE_DELETE_GPU_RESOURCE(_res->FullscreenTriangleVB); + Locker.Unlock(); + // Release GPU resources memory and unlink from device // Note: after that no GPU resources should be used/created, only deleted _resourcesLock.Lock(); @@ -456,7 +458,6 @@ void GPUDevice::preDispose() } _resources.Clear(); _resourcesLock.Unlock(); - Locker.Unlock(); } void GPUDevice::DrawBegin() diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp index ecf9e7bba..b82375cb4 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.cpp @@ -21,6 +21,7 @@ void* GPUBufferDX11::Map(GPUResourceMapMode mode) { if (!IsInMainThread()) _device->Locker.Lock(); + ASSERT(!_mapped); D3D11_MAPPED_SUBRESOURCE map; map.pData = nullptr; @@ -46,13 +47,18 @@ void* GPUBufferDX11::Map(GPUResourceMapMode mode) const HRESULT result = _device->GetIM()->Map(_resource, 0, mapType, mapFlags, &map); if (result != DXGI_ERROR_WAS_STILL_DRAWING) LOG_DIRECTX_RESULT(result); + _mapped = map.pData != nullptr; return map.pData; } void GPUBufferDX11::Unmap() { - _device->GetIM()->Unmap(_resource, 0); - + if (_mapped) + { + _mapped = false; + _device->GetIM()->Unmap(_resource, 0); + } + if (!IsInMainThread()) _device->Locker.Unlock(); } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.h index cdae2b846..a870c4de9 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUBufferDX11.h @@ -101,6 +101,7 @@ private: ID3D11Buffer* _resource = nullptr; GPUBufferViewDX11 _view; + bool _mapped = false; public: diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp index 946c7f987..e13f30dc8 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.cpp @@ -77,9 +77,10 @@ void GPUBufferDX12::Unmap() writtenRangePtr = nullptr; break; default: - CRASH; + return; } _resource->Unmap(0, writtenRangePtr); + _lastMapMode = (GPUResourceMapMode)255; } GPUResource* GPUBufferDX12::AsGPUResource() const diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.h b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.h index 0f3410b17..9c13dacd9 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUBufferDX12.h @@ -113,7 +113,7 @@ private: GPUBufferViewDX12 _view; GPUBufferDX12* _counter = nullptr; - GPUResourceMapMode _lastMapMode; + GPUResourceMapMode _lastMapMode = (GPUResourceMapMode)255; public: diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index e67ba36b2..c7dc2f990 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -684,13 +684,13 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co if (data) { uint32 counter = data[surfaceAtlasData.CulledObjectsCounterIndex]; - _culledObjectsSizeBuffer->Unmap(); if (counter > 0) { objectsBufferCapacity = counter; notReady = false; } } + _culledObjectsSizeBuffer->Unmap(); // Allow to be ready if the buffer was already used if (notReady && surfaceAtlasData.CulledObjectsBuffer && surfaceAtlasData.CulledObjectsBuffer->IsAllocated())