1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-19 05:52:11 +01:00

[d3d11] Synchronize only to given sequence number in WaitForResources

Avoids costly thread synchronization when mapping staging resources
for reading, as well as some other scenarios.
This commit is contained in:
Philip Rebohle 2022-02-09 02:58:21 +01:00
parent afe1840c74
commit 5a6711ed1d
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 36 additions and 23 deletions

View File

@ -39,7 +39,7 @@ namespace dxvk {
D3D11ImmediateContext::~D3D11ImmediateContext() { D3D11ImmediateContext::~D3D11ImmediateContext() {
Flush(); Flush();
SynchronizeCsThread(); SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
SynchronizeDevice(); SynchronizeDevice();
} }
@ -368,7 +368,8 @@ namespace dxvk {
} else { } else {
// Wait until the resource is no longer in use // Wait until the resource is no longer in use
if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) { if (MapType != D3D11_MAP_WRITE_NO_OVERWRITE) {
if (!WaitForResource(pResource->GetBuffer(), MapType, MapFlags)) if (!WaitForResource(pResource->GetBuffer(),
pResource->GetSequenceNumber(), MapType, MapFlags))
return DXGI_ERROR_WAS_STILL_DRAWING; return DXGI_ERROR_WAS_STILL_DRAWING;
} }
@ -422,7 +423,8 @@ namespace dxvk {
if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) { if (mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_DIRECT) {
// Wait for the resource to become available // Wait for the resource to become available
if (!WaitForResource(mappedImage, MapType, MapFlags)) if (!WaitForResource(mappedImage,
pResource->GetSequenceNumber(Subresource), MapType, MapFlags))
return DXGI_ERROR_WAS_STILL_DRAWING; return DXGI_ERROR_WAS_STILL_DRAWING;
// Query the subresource's memory layout and hope that // Query the subresource's memory layout and hope that
@ -447,7 +449,8 @@ namespace dxvk {
|| mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER; || mapMode == D3D11_COMMON_TEXTURE_MAP_MODE_BUFFER;
// Wait for mapped buffer to become available // Wait for mapped buffer to become available
if (wait && !WaitForResource(mappedBuffer, MapType, MapFlags)) if (wait && !WaitForResource(mappedBuffer,
pResource->GetSequenceNumber(Subresource), MapType, MapFlags))
return DXGI_ERROR_WAS_STILL_DRAWING; return DXGI_ERROR_WAS_STILL_DRAWING;
mapPtr = pResource->GetMappedSlice(Subresource).mapPtr; mapPtr = pResource->GetMappedSlice(Subresource).mapPtr;
@ -542,14 +545,15 @@ namespace dxvk {
} }
void D3D11ImmediateContext::SynchronizeCsThread() { void D3D11ImmediateContext::SynchronizeCsThread(uint64_t SequenceNumber) {
D3D10DeviceLock lock = LockContext(); D3D10DeviceLock lock = LockContext();
// Dispatch current chunk so that all commands // Dispatch current chunk so that all commands
// recorded prior to this function will be run // recorded prior to this function will be run
FlushCsChunk(); if (SequenceNumber > m_csSeqNum)
FlushCsChunk();
m_csThread.synchronize(DxvkCsThread::SynchronizeAll); m_csThread.synchronize(SequenceNumber);
} }
@ -560,6 +564,7 @@ namespace dxvk {
bool D3D11ImmediateContext::WaitForResource( bool D3D11ImmediateContext::WaitForResource(
const Rc<DxvkResource>& Resource, const Rc<DxvkResource>& Resource,
uint64_t SequenceNumber,
D3D11_MAP MapType, D3D11_MAP MapType,
UINT MapFlags) { UINT MapFlags) {
// Determine access type to wait for based on map mode // Determine access type to wait for based on map mode
@ -567,29 +572,35 @@ namespace dxvk {
? DxvkAccess::Write ? DxvkAccess::Write
: DxvkAccess::Read; : DxvkAccess::Read;
// Wait for the any pending D3D11 command to be executed // Wait for any CS chunk using the resource to execute, since
// on the CS thread so that we can determine whether the // otherwise we cannot accurately determine if the resource is
// resource is currently in use or not. // actually being used by the GPU right now.
if (!Resource->isInUse(access)) bool isInUse = Resource->isInUse(access);
SynchronizeCsThread();
if (!isInUse) {
if (Resource->isInUse(access)) { SynchronizeCsThread(SequenceNumber);
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) { isInUse = Resource->isInUse(access);
}
if (MapFlags & D3D11_MAP_FLAG_DO_NOT_WAIT) {
if (isInUse) {
// We don't have to wait, but misbehaving games may // We don't have to wait, but misbehaving games may
// still try to spin on `Map` until the resource is // still try to spin on `Map` until the resource is
// idle, so we should flush pending commands // idle, so we should flush pending commands
FlushImplicit(FALSE); FlushImplicit(FALSE);
return false; return false;
} else { }
} else {
if (isInUse) {
// Make sure pending commands using the resource get // Make sure pending commands using the resource get
// executed on the the GPU if we have to wait for it // executed on the the GPU if we have to wait for it
Flush(); Flush();
SynchronizeCsThread(); SynchronizeCsThread(SequenceNumber);
Resource->waitIdle(access); Resource->waitIdle(access);
} }
} }
return true; return true;
} }

View File

@ -109,10 +109,11 @@ namespace dxvk {
const UINT* pUAVInitialCounts); const UINT* pUAVInitialCounts);
void STDMETHODCALLTYPE SwapDeviceContextState( void STDMETHODCALLTYPE SwapDeviceContextState(
ID3DDeviceContextState* pState, ID3DDeviceContextState* pState,
ID3DDeviceContextState** ppPreviousState); ID3DDeviceContextState** ppPreviousState);
void SynchronizeCsThread(); void SynchronizeCsThread(
uint64_t SequenceNumber);
private: private:
@ -158,6 +159,7 @@ namespace dxvk {
bool WaitForResource( bool WaitForResource(
const Rc<DxvkResource>& Resource, const Rc<DxvkResource>& Resource,
uint64_t SequenceNumber,
D3D11_MAP MapType, D3D11_MAP MapType,
UINT MapFlags); UINT MapFlags);

View File

@ -91,7 +91,7 @@ namespace dxvk {
auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr()); auto immediateContext = static_cast<D3D11ImmediateContext*>(deviceContext.ptr());
immediateContext->Flush(); immediateContext->Flush();
immediateContext->SynchronizeCsThread(); immediateContext->SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
} }