Skip to content

Commit

Permalink
[d3d9] Ensure that we stay below the maximum sampler count
Browse files Browse the repository at this point in the history
  • Loading branch information
doitsujin committed Sep 27, 2024
1 parent fce9ab7 commit 7dab117
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 1 deletion.
73 changes: 72 additions & 1 deletion src/d3d9/d3d9_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6642,11 +6642,14 @@ namespace dxvk {
samplerInfo.first, DxsoBindingType::Image,
samplerInfo.second);

m_samplerBindCount++;

EmitCs([this,
cSlot = slot,
cState = D3D9SamplerInfo(m_state.samplerStates[Sampler]),
cIsCube = bool(m_cubeTextures & (1u << Sampler)),
cIsDepth = bool(m_depthTextures & (1u << Sampler))
cIsDepth = bool(m_depthTextures & (1u << Sampler)),
cBindId = m_samplerBindCount
] (DxvkContext* ctx) {
DxvkSamplerKey key = { };

Expand Down Expand Up @@ -6697,6 +6700,10 @@ namespace dxvk {

VkShaderStageFlags stage = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
ctx->bindResourceSampler(stage, cSlot, m_dxvkDevice->createSampler(key));

// Let the main thread know about current sampler stats
uint64_t liveCount = m_dxvkDevice->getSamplerStats().liveCount;
m_lastSamplerStats.store(liveCount | (cBindId << SamplerCountBits), std::memory_order_relaxed);
});
}

Expand Down Expand Up @@ -6741,6 +6748,8 @@ namespace dxvk {


void D3D9DeviceEx::UndirtySamplers(uint32_t mask) {
EnsureSamplerLimit();

for (uint32_t i : bit::BitMask(mask))
BindSampler(i);

Expand Down Expand Up @@ -6972,6 +6981,68 @@ namespace dxvk {
}


void D3D9DeviceEx::EnsureSamplerLimit() {
constexpr uint32_t MaxSamplerCount = DxvkSamplerPool::MaxSamplerCount - SamplerCount;

// Maximum possible number of live samplers we can have
// since last reading back from the CS thread.
if (likely(m_lastSamplerLiveCount + m_samplerBindCount - m_lastSamplerBindCount <= MaxSamplerCount))
return;

// Update current stats from CS thread and check again. We
// don't want to do this every time due to potential cache
// thrashing.
uint64_t lastStats = m_lastSamplerStats.load(std::memory_order_relaxed);
m_lastSamplerLiveCount = lastStats & SamplerCountMask;
m_lastSamplerBindCount = lastStats >> SamplerCountBits;

if (likely(m_lastSamplerLiveCount + m_samplerBindCount - m_lastSamplerBindCount <= MaxSamplerCount))
return;

// If we have a large number of sampler updates in flight, wait for
// the CS thread to complete some and re-evaluate. We should not hit
// this path under normal gameplay conditions.
ConsiderFlush(GpuFlushType::ImplicitSynchronization);

uint64_t sequenceNumber = m_csThread.lastSequenceNumber();

while (++sequenceNumber <= GetCurrentSequenceNumber()) {
SynchronizeCsThread(sequenceNumber);

uint64_t lastStats = m_lastSamplerStats.load(std::memory_order_relaxed);
m_lastSamplerLiveCount = lastStats & SamplerCountMask;
m_lastSamplerBindCount = lastStats >> SamplerCountBits;

if (m_lastSamplerLiveCount + m_samplerBindCount - m_lastSamplerBindCount <= MaxSamplerCount)
return;
}

// If we end up here, the game somehow managed to queue up so
// many samplers that we need to wait for the GPU to free some.
// We should absolutely never hit this path in the real world.
Logger::warn("Sampler pool exhausted, synchronizing with GPU.");

Flush();
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);

// Need to reset sampler stats here since we'd
// otherwise hit this path again the next time
m_lastSamplerStats = 0u;

uint64_t submissionId = m_submissionFence->value();

while (++submissionId <= m_submissionId) {
m_submissionFence->wait(submissionId);

if (m_dxvkDevice->getSamplerStats().liveCount <= MaxSamplerCount)
return;
}

// If we end up *here*, good luck.
Logger::warn("Sampler pool exhausted, cannot create any new samplers.");
}


template <DxsoProgramType ShaderStage>
void D3D9DeviceEx::BindShader(
const D3D9CommonShader* pShaderModule) {
Expand Down
15 changes: 15 additions & 0 deletions src/d3d9/d3d9_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,8 @@ namespace dxvk {

void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType, bool UploadVBOs, bool UploadIBOs);

void EnsureSamplerLimit();

template <DxsoProgramType ShaderStage>
void BindShader(
const D3D9CommonShader* pShaderModule);
Expand Down Expand Up @@ -1458,6 +1460,19 @@ namespace dxvk {
D3D9VkInteropDevice m_d3d9Interop;
D3D9On12 m_d3d9On12;
DxvkD3D8Bridge m_d3d8Bridge;

// Sampler statistics
constexpr static uint32_t SamplerCountBits = 12u;
constexpr static uint64_t SamplerCountMask = (1u << SamplerCountBits) - 1u;

uint64_t m_samplerBindCount = 0u;

uint64_t m_lastSamplerLiveCount = 0u;
uint64_t m_lastSamplerBindCount = 0u;

// Written by CS thread
alignas(CACHE_LINE_SIZE)
std::atomic<uint64_t> m_lastSamplerStats = { 0u };
};

}

0 comments on commit 7dab117

Please sign in to comment.