diff --git a/src/d3d11/d3d11_buffer.cpp b/src/d3d11/d3d11_buffer.cpp index 4cefa1ea..b1fd409f 100644 --- a/src/d3d11/d3d11_buffer.cpp +++ b/src/d3d11/d3d11_buffer.cpp @@ -1,6 +1,9 @@ #include "d3d11_buffer.h" +#include "d3d11_context.h" #include "d3d11_device.h" +#include "../dxvk/dxvk_data.h" + namespace dxvk { D3D11Buffer::D3D11Buffer( @@ -61,6 +64,74 @@ namespace dxvk { } + HRESULT D3D11Buffer::Map( + D3D11DeviceContext* pContext, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedSubresource) { + const Rc buffer = GetDXVKBuffer(); + + if (buffer->mapPtr(0) == nullptr) { + Logger::err("D3D11: Cannot map a device-local buffer"); + return E_FAIL; + } + + if (pMappedSubresource == nullptr) + return S_OK; + + if (!buffer->isInUse()) { + // Simple case: The buffer is currently not being + // used by the device, we can return the pointer. + pMappedSubresource->pData = buffer->mapPtr(0); + pMappedSubresource->RowPitch = buffer->info().size; + pMappedSubresource->DepthPitch = buffer->info().size; + return S_OK; + } else { + // Don't wait if the application tells us not to + if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) + return DXGI_ERROR_WAS_STILL_DRAWING; + + if (MapType == D3D11_MAP_WRITE_DISCARD) { + // Instead of synchronizing with the device, which is + // highly inefficient, return a host-local buffer to + // the application and upload its contents on unmap() + // TODO evaluate whether this improves performance + m_mapData = new DxvkDataBuffer(buffer->info().size); + + pMappedSubresource->pData = m_mapData->data(); + pMappedSubresource->RowPitch = buffer->info().size; + pMappedSubresource->DepthPitch = buffer->info().size; + return S_OK; + } else { + // We have to wait for the device to complete + pContext->Flush(); + pContext->Synchronize(); + + pMappedSubresource->pData = buffer->mapPtr(0); + pMappedSubresource->RowPitch = buffer->info().size; + pMappedSubresource->DepthPitch = buffer->info().size; + return S_OK; + } + } + } + + + void D3D11Buffer::Unmap( + D3D11DeviceContext* pContext) { + if (m_mapData != nullptr) { + const Rc context + = pContext->GetDXVKContext(); + + context->updateBuffer( + m_resource->GetDXVKBuffer(), + 0, m_mapData->size(), + m_mapData->data()); + + m_mapData = nullptr; + } + } + + Rc D3D11Buffer::GetDXVKBuffer() { return m_resource->GetDXVKBuffer(); } diff --git a/src/d3d11/d3d11_buffer.h b/src/d3d11/d3d11_buffer.h index 36d9e6fe..0f59284e 100644 --- a/src/d3d11/d3d11_buffer.h +++ b/src/d3d11/d3d11_buffer.h @@ -8,6 +8,7 @@ namespace dxvk { class D3D11Device; + class D3D11DeviceContext; class D3D11Buffer : public D3D11DeviceChild { @@ -37,6 +38,15 @@ namespace dxvk { void STDMETHODCALLTYPE GetDesc( D3D11_BUFFER_DESC *pDesc) final; + HRESULT Map( + D3D11DeviceContext* pContext, + D3D11_MAP MapType, + UINT MapFlags, + D3D11_MAPPED_SUBRESOURCE* pMappedSubresource); + + void Unmap( + D3D11DeviceContext* pContext); + Rc GetDXVKBuffer(); private: @@ -45,6 +55,8 @@ namespace dxvk { Com m_resource; D3D11_BUFFER_DESC m_desc; + Rc m_mapData; + }; } diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 707e008e..e5f156c0 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -179,30 +179,7 @@ namespace dxvk { if (resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) { D3D11Buffer* resource = static_cast(pResource); - - const Rc buffer = resource->GetDXVKBuffer(); - - if (buffer->mapPtr(0) == nullptr) { - Logger::err("D3D11: Cannot map a device-local buffer"); - return E_FAIL; - } - - if (pMappedResource == nullptr) - return S_OK; - - if (buffer->isInUse()) { - if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) - return DXGI_ERROR_WAS_STILL_DRAWING; - - this->Flush(); - m_device->waitForIdle(); - // TODO properly synchronize - } - - pMappedResource->pData = buffer->mapPtr(0); - pMappedResource->RowPitch = buffer->info().size; - pMappedResource->DepthPitch = buffer->info().size; - return S_OK; + return resource->Map(this, MapType, MapFlags, pMappedResource); } else { Logger::err("D3D11: Mapping of image resources currently not supported"); return E_NOTIMPL; @@ -213,7 +190,15 @@ namespace dxvk { void STDMETHODCALLTYPE D3D11DeviceContext::Unmap( ID3D11Resource* pResource, UINT Subresource) { - // There's literally nothing we have to do here at the moment + D3D11_RESOURCE_DIMENSION resourceDim = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pResource->GetType(&resourceDim); + + if (resourceDim == D3D11_RESOURCE_DIMENSION_BUFFER) { + D3D11Buffer* resource = static_cast(pResource); + return resource->Unmap(this); + } else { + // We already displayed an error on Map() + } } @@ -1456,6 +1441,11 @@ namespace dxvk { } + void D3D11DeviceContext::Synchronize() { + m_device->waitForIdle(); + } + + void D3D11DeviceContext::BindConstantBuffers( DxbcProgramType ShaderStage, D3D11ConstantBufferBindings* pBindings, diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 6722a18b..d31121fd 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -541,6 +541,12 @@ namespace dxvk { UINT NumBuffers, ID3D11Buffer** ppSOTargets) final; + void Synchronize(); + + Rc GetDXVKContext() const { + return m_context; + } + private: ID3D11Device* const m_parent;