1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-04 16:24:29 +01:00

[d3d11] Implement more accurate resource tracking on deferred contexts

Allows us to track chunks that access any given tracked resource more
accurately and flush as needed, e.g. if a staging buffer is written at
the start of a long command list.
This commit is contained in:
Philip Rebohle 2023-01-17 12:33:19 +01:00 committed by Philip Rebohle
parent cf5adb8b12
commit d7a4ddb5d0
5 changed files with 93 additions and 57 deletions

View File

@ -41,44 +41,64 @@ namespace dxvk {
}
void D3D11CommandList::AddChunk(DxvkCsChunkRef&& Chunk) {
m_chunks.push_back(std::move(Chunk));
}
void D3D11CommandList::AddQuery(D3D11Query* pQuery) {
m_queries.emplace_back(pQuery);
}
void D3D11CommandList::EmitToCommandList(ID3D11CommandList* pCommandList) {
auto cmdList = static_cast<D3D11CommandList*>(pCommandList);
for (const auto& chunk : m_chunks)
cmdList->m_chunks.push_back(chunk);
for (const auto& query : m_queries)
cmdList->m_queries.push_back(query);
for (const auto& resource : m_resources)
cmdList->m_resources.push_back(resource);
MarkSubmitted();
uint64_t D3D11CommandList::AddChunk(DxvkCsChunkRef&& Chunk) {
m_chunks.push_back(std::move(Chunk));
return m_chunks.size() - 1;
}
uint64_t D3D11CommandList::AddCommandList(
D3D11CommandList* pCommandList) {
// This will be the chunk ID of the first chunk
// added, for the purpose of resource tracking.
uint64_t baseChunkId = m_chunks.size();
for (const auto& chunk : pCommandList->m_chunks)
m_chunks.push_back(chunk);
for (const auto& query : pCommandList->m_queries)
m_queries.push_back(query);
for (const auto& resource : pCommandList->m_resources) {
TrackedResource entry = resource;
entry.chunkId += baseChunkId;
m_resources.push_back(std::move(entry));
}
pCommandList->MarkSubmitted();
// Return ID of the last chunk added. The command list
// added can never be empty, so do not handle zero.
return m_chunks.size() - 1;
}
void D3D11CommandList::EmitToCsThread(
const D3D11ChunkDispatchProc& DispatchProc) {
uint64_t seq = 0;
for (const auto& query : m_queries)
query->DoDeferredEnd();
for (const auto& chunk : m_chunks)
seq = DispatchProc(DxvkCsChunkRef(chunk));
for (const auto& resource : m_resources)
TrackResourceSequenceNumber(resource, seq);
for (size_t i = 0, j = 0; i < m_chunks.size(); i++) {
// If there are resources to track for the current chunk,
// use a strong flush hint to dispatch GPU work quickly.
GpuFlushType flushType = GpuFlushType::ImplicitWeakHint;
if (j < m_resources.size() && m_resources[j].chunkId == i)
flushType = GpuFlushType::ImplicitStrongHint;
// Dispatch the chunk and capture its sequence number
uint64_t seq = DispatchProc(DxvkCsChunkRef(m_chunks[i]), flushType);
// Track resource sequence numbers for the added chunk
while (j < m_resources.size() && m_resources[j].chunkId == i)
TrackResourceSequenceNumber(m_resources[j++].ref, seq);
}
MarkSubmitted();
}
@ -87,8 +107,13 @@ namespace dxvk {
void D3D11CommandList::TrackResourceUsage(
ID3D11Resource* pResource,
D3D11_RESOURCE_DIMENSION ResourceType,
UINT Subresource) {
m_resources.emplace_back(pResource, Subresource, ResourceType);
UINT Subresource,
uint64_t ChunkId) {
TrackedResource entry;
entry.ref = D3D11ResourceRef(pResource, Subresource, ResourceType);
entry.chunkId = ChunkId;
m_resources.push_back(std::move(entry));
}
@ -96,7 +121,6 @@ namespace dxvk {
const D3D11ResourceRef& Resource,
uint64_t Seq) {
ID3D11Resource* iface = Resource.Get();
UINT subresource = Resource.GetSubresource();
switch (Resource.GetType()) {
case D3D11_RESOURCE_DIMENSION_UNKNOWN:
@ -109,17 +133,17 @@ namespace dxvk {
case D3D11_RESOURCE_DIMENSION_TEXTURE1D: {
auto impl = static_cast<D3D11Texture1D*>(iface)->GetCommonTexture();
impl->TrackSequenceNumber(subresource, Seq);
impl->TrackSequenceNumber(Resource.GetSubresource(), Seq);
} break;
case D3D11_RESOURCE_DIMENSION_TEXTURE2D: {
auto impl = static_cast<D3D11Texture2D*>(iface)->GetCommonTexture();
impl->TrackSequenceNumber(subresource, Seq);
impl->TrackSequenceNumber(Resource.GetSubresource(), Seq);
} break;
case D3D11_RESOURCE_DIMENSION_TEXTURE3D: {
auto impl = static_cast<D3D11Texture3D*>(iface)->GetCommonTexture();
impl->TrackSequenceNumber(subresource, Seq);
impl->TrackSequenceNumber(Resource.GetSubresource(), Seq);
} break;
}
}

View File

@ -6,7 +6,7 @@
namespace dxvk {
using D3D11ChunkDispatchProc = std::function<uint64_t (DxvkCsChunkRef&&)>;
using D3D11ChunkDispatchProc = std::function<uint64_t (DxvkCsChunkRef&&, GpuFlushType)>;
class D3D11CommandList : public D3D11DeviceChild<ID3D11CommandList> {
@ -24,34 +24,36 @@ namespace dxvk {
UINT STDMETHODCALLTYPE GetContextFlags() final;
void AddChunk(
DxvkCsChunkRef&& Chunk);
void AddQuery(
D3D11Query* pQuery);
void EmitToCommandList(
ID3D11CommandList* pCommandList);
uint64_t AddChunk(
DxvkCsChunkRef&& Chunk);
uint64_t AddCommandList(
D3D11CommandList* pCommandList);
void EmitToCsThread(
const D3D11ChunkDispatchProc& DispatchProc);
void TrackResourceUsage(
ID3D11Resource* pResource,
D3D11_RESOURCE_DIMENSION ResourceType,
UINT Subresource);
bool HasTrackedResources() const {
return !m_resources.empty();
}
UINT Subresource,
uint64_t ChunkId);
private:
UINT const m_contextFlags;
struct TrackedResource {
D3D11ResourceRef ref;
uint64_t chunkId;
};
UINT m_contextFlags;
std::vector<DxvkCsChunkRef> m_chunks;
std::vector<Com<D3D11Query, false>> m_queries;
std::vector<D3D11ResourceRef> m_resources;
std::vector<TrackedResource> m_resources;
std::atomic<bool> m_submitted = { false };
std::atomic<bool> m_warned = { false };

View File

@ -148,8 +148,9 @@ namespace dxvk {
// Record any chunks from the given command list into the
// current command list and deal with context state
auto commandList = static_cast<D3D11CommandList*>(pCommandList);
commandList->EmitToCommandList(m_commandList.ptr());
m_chunkId = m_commandList->AddCommandList(commandList);
// Restore deferred context state
if (RestoreContextState)
RestoreCommandListState();
else
@ -166,7 +167,8 @@ namespace dxvk {
FinalizeQueries();
// Clean up command list state so that the any state changed
// by this command list does not affect the calling context
// by this command list does not affect the calling context.
// This also ensures that the command list is never empty.
ResetCommandListState();
// Make sure all commands are visible to the command list
@ -180,6 +182,7 @@ namespace dxvk {
// Any use of ExecuteCommandList will reset command list state
// before the command list is actually executed.
m_commandList = CreateCommandList();
m_chunkId = 0;
if (RestoreDeferredContextState)
RestoreCommandListState();
@ -388,7 +391,12 @@ namespace dxvk {
void D3D11DeferredContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
m_commandList->AddChunk(std::move(chunk));
m_chunkId = m_commandList->AddChunk(std::move(chunk));
}
uint64_t D3D11DeferredContext::GetCurrentChunkId() const {
return m_csChunk->empty() ? m_chunkId : m_chunkId + 1;
}
@ -398,14 +406,15 @@ namespace dxvk {
m_commandList->TrackResourceUsage(
pResource->GetInterface(),
pResource->GetDimension(),
Subresource);
Subresource, GetCurrentChunkId());
}
void D3D11DeferredContext::TrackBufferSequenceNumber(
D3D11Buffer* pResource) {
m_commandList->TrackResourceUsage(
pResource, D3D11_RESOURCE_DIMENSION_BUFFER, 0);
m_commandList->TrackResourceUsage(pResource,
D3D11_RESOURCE_DIMENSION_BUFFER, 0,
GetCurrentChunkId());
}

View File

@ -96,6 +96,9 @@ namespace dxvk {
// Begun and ended queries, will also be stored in command list
std::vector<Com<D3D11Query, false>> m_queriesBegun;
// Chunk ID within the current command list
uint64_t m_chunkId = 0ull;
HRESULT MapBuffer(
ID3D11Resource* pResource,
D3D11_MAPPED_SUBRESOURCE* pMappedResource);
@ -118,6 +121,8 @@ namespace dxvk {
void EmitCsChunk(DxvkCsChunkRef&& chunk);
uint64_t GetCurrentChunkId() const;
void TrackTextureSequenceNumber(
D3D11CommonTexture* pResource,
UINT Subresource);

View File

@ -238,7 +238,7 @@ namespace dxvk {
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
// Dispatch command list to the CS thread
commandList->EmitToCsThread([this] (DxvkCsChunkRef&& chunk) {
commandList->EmitToCsThread([this] (DxvkCsChunkRef&& chunk, GpuFlushType flushType) {
EmitCsChunk(std::move(chunk));
// Return the sequence number from before the flush since
@ -247,14 +247,10 @@ namespace dxvk {
// Consider a flush after every chunk in case the app
// submits a very large command list or the GPU is idle
ConsiderFlush(GpuFlushType::ImplicitWeakHint);
ConsiderFlush(flushType);
return csSeqNum;
});
// If any resource tracking took place, flush with a strong hint
if (commandList->HasTrackedResources())
ConsiderFlush(GpuFlushType::ImplicitStrongHint);
// Restore the immediate context's state
if (RestoreContextState)
RestoreCommandListState();