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:
parent
cf5adb8b12
commit
d7a4ddb5d0
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 };
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user