mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-11 10:24:10 +01:00
[d3d9] Ensure that we stay below the maximum sampler count
This commit is contained in:
parent
07dfeeb319
commit
e6f89062f5
@ -6642,11 +6642,14 @@ namespace dxvk {
|
|||||||
samplerInfo.first, DxsoBindingType::Image,
|
samplerInfo.first, DxsoBindingType::Image,
|
||||||
samplerInfo.second);
|
samplerInfo.second);
|
||||||
|
|
||||||
|
m_samplerBindCount++;
|
||||||
|
|
||||||
EmitCs([this,
|
EmitCs([this,
|
||||||
cSlot = slot,
|
cSlot = slot,
|
||||||
cState = D3D9SamplerInfo(m_state.samplerStates[Sampler]),
|
cState = D3D9SamplerInfo(m_state.samplerStates[Sampler]),
|
||||||
cIsCube = bool(m_cubeTextures & (1u << Sampler)),
|
cIsCube = bool(m_cubeTextures & (1u << Sampler)),
|
||||||
cIsDepth = bool(m_depthTextures & (1u << Sampler))
|
cIsDepth = bool(m_depthTextures & (1u << Sampler)),
|
||||||
|
cBindId = m_samplerBindCount
|
||||||
] (DxvkContext* ctx) {
|
] (DxvkContext* ctx) {
|
||||||
DxvkSamplerKey key = { };
|
DxvkSamplerKey key = { };
|
||||||
|
|
||||||
@ -6697,6 +6700,10 @@ namespace dxvk {
|
|||||||
|
|
||||||
VkShaderStageFlags stage = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
VkShaderStageFlags stage = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
ctx->bindResourceSampler(stage, cSlot, m_dxvkDevice->createSampler(key));
|
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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6741,6 +6748,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
void D3D9DeviceEx::UndirtySamplers(uint32_t mask) {
|
void D3D9DeviceEx::UndirtySamplers(uint32_t mask) {
|
||||||
|
EnsureSamplerLimit();
|
||||||
|
|
||||||
for (uint32_t i : bit::BitMask(mask))
|
for (uint32_t i : bit::BitMask(mask))
|
||||||
BindSampler(i);
|
BindSampler(i);
|
||||||
|
|
||||||
@ -6972,6 +6981,69 @@ 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);
|
||||||
|
|
||||||
|
uint64_t submissionId = m_submissionFence->value();
|
||||||
|
|
||||||
|
while (++submissionId <= m_submissionId) {
|
||||||
|
m_submissionFence->wait(submissionId);
|
||||||
|
|
||||||
|
// Need to manually update sampler stats here since we
|
||||||
|
// might otherwise hit this path again the next time
|
||||||
|
auto samplerStats = m_dxvkDevice->getSamplerStats();
|
||||||
|
m_lastSamplerStats = samplerStats.liveCount | (m_samplerBindCount << SamplerCountBits);
|
||||||
|
|
||||||
|
if (samplerStats.liveCount <= MaxSamplerCount)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we end up *here*, good luck.
|
||||||
|
Logger::warn("Sampler pool exhausted, cannot create any new samplers.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <DxsoProgramType ShaderStage>
|
template <DxsoProgramType ShaderStage>
|
||||||
void D3D9DeviceEx::BindShader(
|
void D3D9DeviceEx::BindShader(
|
||||||
const D3D9CommonShader* pShaderModule) {
|
const D3D9CommonShader* pShaderModule) {
|
||||||
|
@ -917,6 +917,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType, bool UploadVBOs, bool UploadIBOs);
|
void PrepareDraw(D3DPRIMITIVETYPE PrimitiveType, bool UploadVBOs, bool UploadIBOs);
|
||||||
|
|
||||||
|
void EnsureSamplerLimit();
|
||||||
|
|
||||||
template <DxsoProgramType ShaderStage>
|
template <DxsoProgramType ShaderStage>
|
||||||
void BindShader(
|
void BindShader(
|
||||||
const D3D9CommonShader* pShaderModule);
|
const D3D9CommonShader* pShaderModule);
|
||||||
@ -1458,6 +1460,19 @@ namespace dxvk {
|
|||||||
D3D9VkInteropDevice m_d3d9Interop;
|
D3D9VkInteropDevice m_d3d9Interop;
|
||||||
D3D9On12 m_d3d9On12;
|
D3D9On12 m_d3d9On12;
|
||||||
DxvkD3D8Bridge m_d3d8Bridge;
|
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 };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user