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

[d3d11] Remove initializer context

This moves all initialization commands to the CS thread and the regular
context in such a way that resource initialization is processed before
any context commands can use the resource.
This commit is contained in:
Philip Rebohle 2024-10-08 11:40:05 +02:00 committed by Philip Rebohle
parent ac1dfbacb6
commit a30fdc466b
5 changed files with 142 additions and 63 deletions

View File

@ -881,6 +881,10 @@ namespace dxvk {
void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) { void D3D11ImmediateContext::EmitCsChunk(DxvkCsChunkRef&& chunk) {
// Flush init commands so that the CS thread
// can processe them before the first use.
m_parent->FlushInitCommands();
m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk)); m_csSeqNum = m_csThread.dispatchChunk(std::move(chunk));
} }
@ -936,11 +940,6 @@ namespace dxvk {
if (synchronizeSubmission) if (synchronizeSubmission)
m_submitStatus.result = VK_NOT_READY; m_submitStatus.result = VK_NOT_READY;
// Flush init context so that new resources are fully initialized
// before the app can access them in any way. This has to happen
// unconditionally since we may otherwise deadlock on Map.
m_parent->FlushInitContext();
// Exit early if there's nothing to do // Exit early if there's nothing to do
if (!GetPendingCsChunks() && !hEvent) if (!GetPendingCsChunks() && !hEvent)
return; return;
@ -980,6 +979,10 @@ namespace dxvk {
// Free local staging buffer so that we don't // Free local staging buffer so that we don't
// end up with a persistent allocation // end up with a persistent allocation
ResetStagingBuffer(); ResetStagingBuffer();
// Notify the device that the context has been flushed,
// this resets some resource initialization heuristics.
m_parent->NotifyContextFlush();
} }

View File

@ -1839,11 +1839,6 @@ namespace dxvk {
} }
void D3D11Device::FlushInitContext() {
m_initializer->Flush();
}
D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel( D3D_FEATURE_LEVEL D3D11Device::GetMaxFeatureLevel(
const Rc<DxvkInstance>& Instance, const Rc<DxvkInstance>& Instance,
const Rc<DxvkAdapter>& Adapter) { const Rc<DxvkAdapter>& Adapter) {

View File

@ -391,7 +391,13 @@ namespace dxvk {
return m_dxvkDevice; return m_dxvkDevice;
} }
void FlushInitContext(); void FlushInitCommands() {
m_initializer->FlushCsChunk();
}
void NotifyContextFlush() {
m_initializer->NotifyContextFlush();
}
VkPipelineStageFlags GetEnabledShaderStages() const { VkPipelineStageFlags GetEnabledShaderStages() const {
return m_dxvkDevice->getShaderPipelineStages(); return m_dxvkDevice->getShaderPipelineStages();

View File

@ -1,5 +1,6 @@
#include <cstring> #include <cstring>
#include "d3d11_context_imm.h"
#include "d3d11_device.h" #include "d3d11_device.h"
#include "d3d11_initializer.h" #include "d3d11_initializer.h"
@ -9,11 +10,10 @@ namespace dxvk {
D3D11Device* pParent) D3D11Device* pParent)
: m_parent(pParent), : m_parent(pParent),
m_device(pParent->GetDXVKDevice()), m_device(pParent->GetDXVKDevice()),
m_context(m_device->createContext(DxvkContextType::Supplementary)),
m_stagingBuffer(m_device, StagingBufferSize), m_stagingBuffer(m_device, StagingBufferSize),
m_stagingSignal(new sync::Fence(0)) { m_stagingSignal(new sync::Fence(0)),
m_context->beginRecording( m_csChunk(m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse)) {
m_device->createCommandList());
} }
@ -22,13 +22,12 @@ namespace dxvk {
} }
void D3D11Initializer::Flush() { void D3D11Initializer::NotifyContextFlush() {
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
NotifyContextFlushLocked();
if (m_transferCommands != 0)
ExecuteFlush();
} }
void D3D11Initializer::InitBuffer( void D3D11Initializer::InitBuffer(
D3D11Buffer* pBuffer, D3D11Buffer* pBuffer,
const D3D11_SUBRESOURCE_DATA* pInitialData) { const D3D11_SUBRESOURCE_DATA* pInitialData) {
@ -63,18 +62,18 @@ namespace dxvk {
if (counterView == nullptr) if (counterView == nullptr)
return; return;
DxvkBufferSlice counterSlice(counterView);
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
m_transferCommands += 1; m_transferCommands += 1;
const uint32_t zero = 0; EmitCs([
m_context->updateBuffer( cCounterSlice = DxvkBufferSlice(counterView)
counterSlice.buffer(), ] (DxvkContext* ctx) {
counterSlice.offset(), const uint32_t zero = 0;
sizeof(zero), &zero); ctx->updateBuffer(
cCounterSlice.buffer(),
ExecuteFlush(); cCounterSlice.offset(),
sizeof(zero), &zero);
});
} }
@ -86,23 +85,30 @@ namespace dxvk {
Rc<DxvkBuffer> buffer = pBuffer->GetBuffer(); Rc<DxvkBuffer> buffer = pBuffer->GetBuffer();
if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) {
ThrottleAllocation(buffer->info().size);
auto stagingSlice = m_stagingBuffer.alloc(buffer->info().size); auto stagingSlice = m_stagingBuffer.alloc(buffer->info().size);
std::memcpy(stagingSlice.mapPtr(0), pInitialData->pSysMem, stagingSlice.length()); std::memcpy(stagingSlice.mapPtr(0), pInitialData->pSysMem, stagingSlice.length());
m_transferCommands += 1; m_transferCommands += 1;
m_context->uploadBuffer(buffer, EmitCs([
stagingSlice.buffer(), cBuffer = buffer,
stagingSlice.offset()); cStagingSlice = std::move(stagingSlice)
] (DxvkContext* ctx) {
ctx->uploadBuffer(cBuffer,
cStagingSlice.buffer(),
cStagingSlice.offset());
});
} else { } else {
m_transferCommands += 1; m_transferCommands += 1;
m_context->initBuffer(buffer); EmitCs([
cBuffer = buffer
] (DxvkContext* ctx) {
ctx->initBuffer(cBuffer);
});
} }
ThrottleAllocation(0); ThrottleAllocationLocked();
} }
@ -153,7 +159,6 @@ namespace dxvk {
packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask); packedFormat, image->mipLevelExtent(mip), formatInfo->aspectMask);
} }
ThrottleAllocation(dataSize);
stagingSlice = m_stagingBuffer.alloc(dataSize); stagingSlice = m_stagingBuffer.alloc(dataSize);
} }
@ -188,8 +193,18 @@ namespace dxvk {
} }
// Upload all subresources of the image in one go // Upload all subresources of the image in one go
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
m_context->uploadImage(image, stagingSlice.buffer(), stagingSlice.offset(), packedFormat); EmitCs([
cImage = std::move(image),
cStagingSlice = std::move(stagingSlice),
cFormat = packedFormat
] (DxvkContext* ctx) {
ctx->uploadImage(cImage,
cStagingSlice.buffer(),
cStagingSlice.offset(),
cFormat);
});
}
} else { } else {
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) { if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_STAGING) {
m_transferCommands += 1; m_transferCommands += 1;
@ -197,14 +212,13 @@ namespace dxvk {
// While the Microsoft docs state that resource contents are // While the Microsoft docs state that resource contents are
// undefined if no initial data is provided, some applications // undefined if no initial data is provided, some applications
// expect a resource to be pre-cleared. // expect a resource to be pre-cleared.
VkImageSubresourceRange subresources; EmitCs([
subresources.aspectMask = formatInfo->aspectMask; cImage = std::move(image)
subresources.baseMipLevel = 0; ] (DxvkContext* ctx) {
subresources.levelCount = desc->MipLevels; ctx->initImage(cImage,
subresources.baseArrayLayer = 0; cImage->getAvailableSubresources(),
subresources.layerCount = desc->ArraySize; VK_IMAGE_LAYOUT_UNDEFINED);
});
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_UNDEFINED);
} }
if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) { if (mapMode != D3D11_COMMON_TEXTURE_MAP_MODE_NONE) {
@ -215,7 +229,7 @@ namespace dxvk {
} }
} }
ThrottleAllocation(0); ThrottleAllocationLocked();
} }
@ -262,25 +276,35 @@ namespace dxvk {
// Initialize the image on the GPU // Initialize the image on the GPU
std::lock_guard<dxvk::mutex> lock(m_mutex); std::lock_guard<dxvk::mutex> lock(m_mutex);
VkImageSubresourceRange subresources = image->getAvailableSubresources(); EmitCs([
cImage = std::move(image)
m_context->initImage(image, subresources, VK_IMAGE_LAYOUT_PREINITIALIZED); ] (DxvkContext* ctx) {
ctx->initImage(cImage,
cImage->getAvailableSubresources(),
VK_IMAGE_LAYOUT_PREINITIALIZED);
});
m_transferCommands += 1; m_transferCommands += 1;
ThrottleAllocation(0); ThrottleAllocationLocked();
} }
void D3D11Initializer::InitTiledTexture( void D3D11Initializer::InitTiledTexture(
D3D11CommonTexture* pTexture) { D3D11CommonTexture* pTexture) {
m_context->initSparseImage(pTexture->GetImage()); std::lock_guard<dxvk::mutex> lock(m_mutex);
EmitCs([
cImage = pTexture->GetImage()
] (DxvkContext* ctx) {
ctx->initSparseImage(cImage);
});
m_transferCommands += 1; m_transferCommands += 1;
ThrottleAllocation(0); ThrottleAllocationLocked();
} }
void D3D11Initializer::ThrottleAllocation(VkDeviceSize allocationSize) { void D3D11Initializer::ThrottleAllocationLocked() {
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics(); DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
// If the amount of memory in flight exceeds the limit, stall the // If the amount of memory in flight exceeds the limit, stall the
@ -288,25 +312,38 @@ namespace dxvk {
VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingSignal->value(); VkDeviceSize stagingMemoryInFlight = stats.allocatedTotal - m_stagingSignal->value();
if (stagingMemoryInFlight > MaxMemoryInFlight) { if (stagingMemoryInFlight > MaxMemoryInFlight) {
ExecuteFlush(); ExecuteFlushLocked();
m_stagingSignal->wait(stats.allocatedTotal - MaxMemoryInFlight); m_stagingSignal->wait(stats.allocatedTotal - MaxMemoryInFlight);
} else if (m_transferCommands >= MaxCommandsPerSubmission || stats.allocatedSinceLastReset >= MaxMemoryPerSubmission) { } else if (m_transferCommands >= MaxCommandsPerSubmission || stats.allocatedSinceLastReset >= MaxMemoryPerSubmission) {
// Flush pending commands if there are a lot of updates in flight // Flush pending commands if there are a lot of updates in flight
// to keep both execution time and staging memory in check. // to keep both execution time and staging memory in check.
ExecuteFlush(); ExecuteFlushLocked();
} }
} }
void D3D11Initializer::ExecuteFlush() { void D3D11Initializer::ExecuteFlush() {
std::lock_guard lock(m_mutex);
ExecuteFlushLocked();
}
void D3D11Initializer::ExecuteFlushLocked() {
DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics(); DxvkStagingBufferStats stats = m_stagingBuffer.getStatistics();
m_context->signal(m_stagingSignal, stats.allocatedTotal); EmitCs([
m_context->flushCommandList(nullptr); cSignal = m_stagingSignal,
cSignalValue = stats.allocatedTotal
] (DxvkContext* ctx) {
ctx->signal(cSignal, cSignalValue);
ctx->flushCommandList(nullptr);
});
m_stagingBuffer.reset(); FlushCsChunk();
m_transferCommands = 0;
NotifyContextFlushLocked();
} }
@ -336,4 +373,16 @@ namespace dxvk {
} }
} }
void D3D11Initializer::FlushCsChunkLocked() {
m_parent->GetContext()->InjectCsChunk(std::move(m_csChunk), false);
m_csChunk = m_parent->AllocCsChunk(DxvkCsChunkFlag::SingleUse);
}
void D3D11Initializer::NotifyContextFlushLocked() {
m_stagingBuffer.reset();
m_transferCommands = 0;
}
} }

View File

@ -37,7 +37,14 @@ namespace dxvk {
~D3D11Initializer(); ~D3D11Initializer();
void Flush(); void FlushCsChunk() {
std::lock_guard<dxvk::mutex> lock(m_csMutex);
if (!m_csChunk->empty())
FlushCsChunkLocked();
}
void NotifyContextFlush();
void InitBuffer( void InitBuffer(
D3D11Buffer* pBuffer, D3D11Buffer* pBuffer,
@ -56,13 +63,15 @@ namespace dxvk {
D3D11Device* m_parent; D3D11Device* m_parent;
Rc<DxvkDevice> m_device; Rc<DxvkDevice> m_device;
Rc<DxvkContext> m_context;
DxvkStagingBuffer m_stagingBuffer; DxvkStagingBuffer m_stagingBuffer;
Rc<sync::Fence> m_stagingSignal; Rc<sync::Fence> m_stagingSignal;
size_t m_transferCommands = 0; size_t m_transferCommands = 0;
dxvk::mutex m_csMutex;
DxvkCsChunkRef m_csChunk;
void InitDeviceLocalBuffer( void InitDeviceLocalBuffer(
D3D11Buffer* pBuffer, D3D11Buffer* pBuffer,
const D3D11_SUBRESOURCE_DATA* pInitialData); const D3D11_SUBRESOURCE_DATA* pInitialData);
@ -82,13 +91,30 @@ namespace dxvk {
void InitTiledTexture( void InitTiledTexture(
D3D11CommonTexture* pTexture); D3D11CommonTexture* pTexture);
void ThrottleAllocation(VkDeviceSize allocationSize); void ThrottleAllocationLocked();
void ExecuteFlush(); void ExecuteFlush();
void ExecuteFlushLocked();
void SyncSharedTexture( void SyncSharedTexture(
D3D11CommonTexture* pResource); D3D11CommonTexture* pResource);
void FlushCsChunkLocked();
void NotifyContextFlushLocked();
template<typename Cmd>
void EmitCs(Cmd&& command) {
std::lock_guard<dxvk::mutex> lock(m_csMutex);
if (unlikely(!m_csChunk->push(command))) {
FlushCsChunkLocked();
m_csChunk->push(command);
}
}
}; };
} }