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:
parent
ac1dfbacb6
commit
a30fdc466b
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
EmitCs([
|
||||||
|
cCounterSlice = DxvkBufferSlice(counterView)
|
||||||
|
] (DxvkContext* ctx) {
|
||||||
const uint32_t zero = 0;
|
const uint32_t zero = 0;
|
||||||
m_context->updateBuffer(
|
ctx->updateBuffer(
|
||||||
counterSlice.buffer(),
|
cCounterSlice.buffer(),
|
||||||
counterSlice.offset(),
|
cCounterSlice.offset(),
|
||||||
sizeof(zero), &zero);
|
sizeof(zero), &zero);
|
||||||
|
});
|
||||||
ExecuteFlush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user