Dedup bindings per encoder. (#3772)

This commit is contained in:
Branimir Karadžić
2026-06-20 05:22:12 +00:00
committed by GitHub
parent 4f101d98be
commit 73629ada72
8 changed files with 153 additions and 42 deletions
+4 -4
View File
@@ -1555,11 +1555,11 @@ namespace bgfx
m_draw.m_occlusionQuery = _occlusionQuery;
}
m_draw.m_bindIdx = bindStateIndexCached();
m_frame->m_renderItem[renderItemIdx].draw = m_draw;
m_frame->m_renderItemBind[renderItemIdx] = m_bind;
m_draw.clear(_flags);
m_bind.clear(_flags);
clearBind(_flags);
if (_flags & BGFX_DISCARD_STATE)
{
m_uniformBegin = m_uniformEnd;
@@ -1610,11 +1610,11 @@ namespace bgfx
m_compute.m_uniformIdx = m_uniformIdx;
m_compute.m_uniformBegin = m_uniformBegin;
m_compute.m_uniformEnd = m_uniformEnd;
m_compute.m_bindIdx = bindStateIndexCached();
m_frame->m_renderItem[renderItemIdx].compute = m_compute;
m_frame->m_renderItemBind[renderItemIdx] = m_bind;
m_compute.clear(_flags);
m_bind.clear(_flags);
clearBind(_flags);
m_uniformBegin = m_uniformEnd;
}
+85 -3
View File
@@ -1998,6 +1998,7 @@ namespace bgfx
m_indirectBuffer = BGFX_INVALID_HANDLE;
m_numIndirectBuffer = BGFX_INVALID_HANDLE;
m_occlusionQuery = BGFX_INVALID_HANDLE;
m_bindIdx = 0;
}
bool setStreamBit(uint8_t _stream, VertexBufferHandle _handle)
@@ -2030,6 +2031,7 @@ namespace bgfx
uint32_t m_numIndirect;
uint32_t m_numIndirectIndex;
uint32_t m_streamMask;
uint32_t m_bindIdx;
uint16_t m_instanceDataStride;
uint16_t m_numMatrices;
uint16_t m_scissor;
@@ -2043,6 +2045,8 @@ namespace bgfx
OcclusionQueryHandle m_occlusionQuery;
};
static_assert(sizeof(RenderDraw) == 128, "RenderDraw size changed.");
BX_ALIGN_DECL_CACHE_LINE(struct) RenderCompute
{
void clear(uint8_t _flags)
@@ -2067,6 +2071,7 @@ namespace bgfx
m_indirectBuffer = BGFX_INVALID_HANDLE;
m_startIndirect = 0;
m_numIndirect = UINT32_MAX;
m_bindIdx = 0;
}
uint32_t m_uniformBegin;
@@ -2079,6 +2084,7 @@ namespace bgfx
uint32_t m_numZ;
uint32_t m_startIndirect;
uint32_t m_numIndirect;
uint32_t m_bindIdx;
uint16_t m_numMatrices;
uint8_t m_submitFlags;
uint8_t m_uniformIdx;
@@ -2573,7 +2579,7 @@ namespace bgfx
m_perfStats.viewStats = m_viewStats;
bx::memSet(&m_renderItemBind[0], 0, sizeof(m_renderItemBind) );
bx::memSet(&m_renderBind[0], 0, sizeof(m_renderBind) );
}
~Frame()
@@ -2626,6 +2632,7 @@ namespace bgfx
m_frameCache.reset();
m_numRenderItems = 0;
m_numRenderBinds = 0;
m_numBlitItems = 0;
m_iboffset = 0;
m_vboffset = 0;
@@ -2745,7 +2752,7 @@ namespace bgfx
uint64_t m_sortKeys[BGFX_CONFIG_MAX_DRAW_CALLS+1];
RenderItemCount m_sortValues[BGFX_CONFIG_MAX_DRAW_CALLS+1];
RenderItem m_renderItem[BGFX_CONFIG_MAX_DRAW_CALLS+1];
RenderBind m_renderItemBind[BGFX_CONFIG_MAX_DRAW_CALLS + 1];
RenderBind m_renderBind[BGFX_CONFIG_MAX_DRAW_CALLS + 1];
uint32_t m_blitKeys[BGFX_CONFIG_MAX_BLIT_ITEMS+1];
BlitItem m_blitItem[BGFX_CONFIG_MAX_BLIT_ITEMS+1];
@@ -2756,6 +2763,7 @@ namespace bgfx
UniformBuffer** m_uniformBuffer;
uint32_t m_numRenderItems;
uint32_t m_numRenderBinds;
uint32_t m_numBlitItems;
uint32_t m_iboffset;
@@ -2884,6 +2892,11 @@ namespace bgfx
m_numSubmitted = 0;
m_numDropped = 0;
m_bindHashMap.clear();
m_bindLlastIdx = 0;
m_bindEmptyIdx = UINT32_MAX;
m_bindDirty = true;
}
void end(bool _finalize)
@@ -2907,6 +2920,64 @@ namespace bgfx
}
}
uint32_t bindStateIndex()
{
const uint32_t hash = bx::hash<bx::HashMurmur3>(m_bind.m_bind, sizeof(m_bind.m_bind) );
BindHashMap::const_iterator it = m_bindHashMap.find(hash);
if (it != m_bindHashMap.end() )
{
const uint32_t idx = it->second;
BX_ASSERT(0 == bx::memCmp(&m_frame->m_renderBind[idx], &m_bind, sizeof(m_bind) )
, "RenderBind hash collision (hash 0x%08x)."
, hash
);
return idx;
}
const uint32_t idx = bx::atomicFetchAndAddsat<uint32_t>(&m_frame->m_numRenderBinds, 1, BGFX_CONFIG_MAX_DRAW_CALLS);
m_frame->m_renderBind[idx] = m_bind;
m_bindHashMap.insert(stl::make_pair(hash, idx) );
return idx;
}
uint32_t bindStateIndexCached()
{
if (m_bindDirty)
{
m_bindLlastIdx = bindStateIndex();
m_bindDirty = false;
}
else
{
BX_ASSERT(0 == bx::memCmp(&m_frame->m_renderBind[m_bindLlastIdx], &m_bind, sizeof(m_bind) )
, "Stale bind dirty flag: cached index %d does not match current bind."
, m_bindLlastIdx
);
}
return m_bindLlastIdx;
}
void clearBind(uint8_t _flags)
{
m_bind.clear(_flags);
if (0 != (_flags & BGFX_DISCARD_BINDINGS) )
{
if (UINT32_MAX == m_bindEmptyIdx)
{
m_bindEmptyIdx = bindStateIndex();
}
m_bindLlastIdx = m_bindEmptyIdx;
m_bindDirty = false;
}
}
void setMarker(const bx::StringView& _name)
{
UniformBuffer::update(&m_frame->m_uniformBuffer[m_uniformIdx]);
@@ -3144,6 +3215,7 @@ namespace bgfx
void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint32_t _flags)
{
m_bindDirty = true;
Binding& bind = m_bind.m_bind[_stage];
bind.setTexture(
_handle
@@ -3161,6 +3233,7 @@ namespace bgfx
void setTexture(uint8_t _stage, UniformHandle _sampler, TextureHandle _handle, uint16_t _firstLayer, uint16_t _numLayers, uint8_t _firstMip, uint8_t _numMips, uint32_t _flags)
{
m_bindDirty = true;
Binding& bind = m_bind.m_bind[_stage];
bind.setTexture(
_handle
@@ -3182,18 +3255,21 @@ namespace bgfx
void setBuffer(uint8_t _stage, IndexBufferHandle _handle, Access::Enum _access)
{
m_bindDirty = true;
Binding& bind = m_bind.m_bind[_stage];
bind.setIndexBuffer(_handle, _access);
}
void setBuffer(uint8_t _stage, VertexBufferHandle _handle, Access::Enum _access)
{
m_bindDirty = true;
Binding& bind = m_bind.m_bind[_stage];
bind.setBuffer(_handle, _access);
}
void setImage(uint8_t _stage, TextureHandle _handle, uint8_t _mip, Access::Enum _access, TextureFormat::Enum _format)
{
m_bindDirty = true;
Binding& bind = m_bind.m_bind[_stage];
bind.setImage(_handle, _mip, _access, _format);
}
@@ -3208,7 +3284,7 @@ namespace bgfx
m_discard = false;
m_draw.clear(_flags);
m_compute.clear(_flags);
m_bind.clear(_flags);
clearBind(_flags);
if (_flags & BGFX_DISCARD_STATE)
{
@@ -3269,6 +3345,12 @@ namespace bgfx
HandleSet m_uniformSet;
HandleSet m_occlusionQuerySet;
typedef stl::unordered_map<uint32_t, uint32_t> BindHashMap;
BindHashMap m_bindHashMap;
uint32_t m_bindLlastIdx;
uint32_t m_bindEmptyIdx;
bool m_bindDirty;
int64_t m_cpuTimeBegin;
int64_t m_cpuTimeEnd;
};
+3 -2
View File
@@ -5848,7 +5848,7 @@ namespace bgfx { namespace d3d11
const uint32_t itemIdx = _render->m_sortValues[item];
const RenderItem& renderItem = _render->m_renderItem[itemIdx];
const RenderBind& renderBind = _render->m_renderItemBind[itemIdx];
const RenderBind& renderBind = _render->m_renderBind[isCompute ? renderItem.compute.m_bindIdx : renderItem.draw.m_bindIdx];
++item;
if (viewChanged)
@@ -6759,10 +6759,11 @@ namespace bgfx { namespace d3d11
);
double elapsedCpuMs = double(frameTime)*toMs;
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / Binds: %4d / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
, _render->m_numRenderItems
, statsKeyType[0]
, statsKeyType[1]
, _render->m_numRenderBinds
, elapsedCpuMs
, elapsedCpuMs > maxGpuElapsed ? '>' : '<'
, maxGpuElapsed
+46 -23
View File
@@ -7011,6 +7011,10 @@ namespace bgfx { namespace d3d12
uint16_t m_samplerStateIdx;
};
static constexpr uint8_t kBindStateNotBuilt = 0;
static constexpr uint8_t kBindStateValid = 1;
static constexpr uint8_t kBindStateEmpty = 2;
void RendererContextD3D12::submitBlit(BlitState& _bs, uint16_t _view)
{
TextureHandle currentSrc = { kInvalidHandle };
@@ -7191,7 +7195,7 @@ namespace bgfx { namespace d3d12
uint16_t currentSamplerStateIdx = kInvalidHandle;
ProgramHandle currentProgram = BGFX_INVALID_HANDLE;
uint32_t currentBindHash = 0;
uint32_t currentBindIdx = UINT32_MAX;
bool hasPredefined = false;
bool commandListChanged = false;
ID3D12PipelineState* currentPso = NULL;
@@ -7255,7 +7259,11 @@ namespace bgfx { namespace d3d12
D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = UINT64_C(0);
StateCacheLru<Bind, 64> bindLru;
const uint32_t numRenderBinds = _render->m_numRenderBinds;
Bind* bindCache = (Bind* )BX_STACK_ALLOC(bx::max<uint32_t>(numRenderBinds, 1)*sizeof(Bind) );
uint8_t* bindState = (uint8_t*)BX_STACK_ALLOC(bx::max<uint32_t>(numRenderBinds, 1) );
bx::memSet(bindState, kBindStateNotBuilt, numRenderBinds);
uint32_t bindCacheCount = 0;
if (NULL != m_msaaRt)
{
@@ -7302,7 +7310,8 @@ namespace bgfx { namespace d3d12
const uint32_t itemIdx = _render->m_sortValues[item];
const RenderItem& renderItem = _render->m_renderItem[itemIdx];
const RenderBind& renderBind = _render->m_renderItemBind[itemIdx];
const uint32_t bindIdx = isCompute ? renderItem.compute.m_bindIdx : renderItem.draw.m_bindIdx;
const RenderBind& renderBind = _render->m_renderBind[bindIdx];
++item;
if (viewChanged)
@@ -7408,16 +7417,19 @@ namespace bgfx { namespace d3d12
{
currentPso = pso;
m_commandList->SetPipelineState(pso);
currentBindHash = 0;
currentBindIdx = UINT32_MAX;
}
uint32_t bindHash = bx::hash<bx::HashMurmur2A>(renderBind.m_bind, sizeof(renderBind.m_bind) );
if (currentBindHash != bindHash)
if (currentBindIdx != bindIdx)
{
currentBindHash = bindHash;
currentBindIdx = bindIdx;
Bind* bindCached = bindLru.find(bindHash);
if (NULL == bindCached)
Bind* bindCached = kBindStateValid == bindState[bindIdx]
? &bindCache[bindIdx]
: NULL
;
if (kBindStateNotBuilt == bindState[bindIdx])
{
uint32_t numSet = 0;
D3D12_GPU_DESCRIPTOR_HANDLE srvHandle[BGFX_MAX_COMPUTE_BINDINGS] = {};
@@ -7498,10 +7510,16 @@ namespace bgfx { namespace d3d12
if (0 != numSet)
{
Bind bind;
Bind& bind = bindCache[bindIdx];
bind.m_srvHandle = srvHandle[0];
bind.m_samplerStateIdx = getSamplerState(samplerFlags, maxComputeBindings, _render->m_colorPalette);
bindCached = bindLru.add(bindHash, bind, 0);
bindState[bindIdx] = kBindStateValid;
++bindCacheCount;
bindCached = &bind;
}
else
{
bindState[bindIdx] = kBindStateEmpty;
}
}
}
@@ -7640,7 +7658,7 @@ namespace bgfx { namespace d3d12
m_commandList->SetDescriptorHeaps(BX_COUNTOF(heaps), heaps);
currentPso = NULL;
currentBindHash = 0;
currentBindIdx = UINT32_MAX;
currentSamplerStateIdx = kInvalidHandle;
currentProgram = BGFX_INVALID_HANDLE;
currentState.clear();
@@ -7709,9 +7727,7 @@ namespace bgfx { namespace d3d12
, uint8_t(draw.m_instanceDataStride/16)
);
const uint32_t bindHash = bx::hash<bx::HashMurmur2A>(renderBind.m_bind, sizeof(renderBind.m_bind) );
if (currentBindHash != bindHash
if (currentBindIdx != bindIdx
|| 0 != changedStencil
|| (hasFactor && blendFactor != draw.m_rgba)
|| (0 != (BGFX_STATE_PT_MASK & changedFlags)
@@ -7723,12 +7739,12 @@ namespace bgfx { namespace d3d12
m_batch.flush(m_commandList);
}
if (currentBindHash != bindHash)
if (currentBindIdx != bindIdx)
{
currentBindHash = bindHash;
currentBindIdx = bindIdx;
Bind* bindCached = bindLru.find(bindHash);
if (NULL == bindCached)
Bind* bindCached = kBindStateValid == bindState[bindIdx] ? &bindCache[bindIdx] : NULL;
if (kBindStateNotBuilt == bindState[bindIdx])
{
uint32_t numSet = 0;
D3D12_GPU_DESCRIPTOR_HANDLE srvHandle[BGFX_CONFIG_MAX_TEXTURE_SAMPLERS] = {};
@@ -7812,10 +7828,16 @@ namespace bgfx { namespace d3d12
if (0 != numSet)
{
Bind bind;
Bind& bind = bindCache[bindIdx];
bind.m_srvHandle = srvHandle[0];
bind.m_samplerStateIdx = getSamplerState(samplerFlags, BGFX_CONFIG_MAX_TEXTURE_SAMPLERS, _render->m_colorPalette);
bindCached = bindLru.add(bindHash, bind, 0);
bindState[bindIdx] = kBindStateValid;
++bindCacheCount;
bindCached = &bind;
}
else
{
bindState[bindIdx] = kBindStateEmpty;
}
}
@@ -8156,10 +8178,11 @@ namespace bgfx { namespace d3d12
);
double elapsedCpuMs = double(frameTime)*toMs;
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / Binds: %4d / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
, _render->m_numRenderItems
, statsKeyType[0]
, statsKeyType[1]
, _render->m_numRenderBinds
, elapsedCpuMs
, elapsedCpuMs > maxGpuElapsed ? '>' : '<'
, maxGpuElapsed
@@ -8205,7 +8228,7 @@ namespace bgfx { namespace d3d12
tvm.printf(10, pos++, 0x8b, " %6d | %6d | %6d | %6d "
, m_pipelineStateCache.getCount()
, m_samplerAllocator.getCount()
, bindLru.getCount()
, bindCacheCount
, m_cmd.m_control.getNumUsed()
);
pos++;
+3 -2
View File
@@ -7809,7 +7809,7 @@ namespace bgfx { namespace gl
const uint32_t itemIdx = _render->m_sortValues[item];
const RenderItem& renderItem = _render->m_renderItem[itemIdx];
const RenderBind& renderBind = _render->m_renderItemBind[itemIdx];
const RenderBind& renderBind = _render->m_renderBind[isCompute ? renderItem.compute.m_bindIdx : renderItem.draw.m_bindIdx];
++item;
if (viewChanged)
@@ -8888,10 +8888,11 @@ namespace bgfx { namespace gl
);
double elapsedCpuMs = double(frameTime)*toMs;
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / Binds: %4d / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
, _render->m_numRenderItems
, statsKeyType[0]
, statsKeyType[1]
, _render->m_numRenderBinds
, elapsedCpuMs
, elapsedCpuMs > elapsedGpuMs ? '>' : '<'
, maxGpuElapsed
+3 -2
View File
@@ -4994,7 +4994,7 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
const uint32_t itemIdx = _render->m_sortValues[item];
const RenderItem& renderItem = _render->m_renderItem[itemIdx];
const RenderBind& renderBind = _render->m_renderItemBind[itemIdx];
const RenderBind& renderBind = _render->m_renderBind[isCompute ? renderItem.compute.m_bindIdx : renderItem.draw.m_bindIdx];
++item;
if (viewChanged
@@ -6013,10 +6013,11 @@ static_assert(BX_COUNTOF(s_accessNames) == Access::Count, "Invalid s_accessNames
);
double elapsedCpuMs = double(frameTime)*toMs;
tvm.printf(10, pos++, 0x8b, " Submitted: %4d (draw %4d, compute %4d) / CPU %3.4f [ms] %c GPU %3.4f [ms] (latency %d)"
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / Binds: %4d / CPU %3.4f [ms] %c GPU %3.4f [ms] (latency %d)"
, _render->m_numRenderItems
, statsKeyType[0]
, statsKeyType[1]
, _render->m_numRenderBinds
, elapsedCpuMs
, elapsedCpuMs > maxGpuElapsed ? '>' : '<'
, maxGpuElapsed
+6 -4
View File
@@ -9358,7 +9358,8 @@ VK_DESTROY
const uint32_t itemIdx = _render->m_sortValues[item];
const RenderItem& renderItem = _render->m_renderItem[itemIdx];
const RenderBind& renderBind = _render->m_renderItemBind[itemIdx];
const uint32_t bindIdx = isCompute ? renderItem.compute.m_bindIdx : renderItem.draw.m_bindIdx;
const RenderBind& renderBind = _render->m_renderBind[bindIdx];
++item;
if (viewChanged)
@@ -9682,7 +9683,7 @@ VK_DESTROY
bx::HashMurmur2A hash;
hash.begin();
hash.add(program.m_descriptorSetLayout);
hash.add(renderBind.m_bind, sizeof(renderBind.m_bind) );
hash.add(bindIdx);
hash.add(sbo.buffer);
hash.add(vsSize);
hash.add(0);
@@ -9977,7 +9978,7 @@ VK_DESTROY
bx::HashMurmur2A hash;
hash.begin();
hash.add(program.m_descriptorSetLayout);
hash.add(renderBind.m_bind, sizeof(renderBind.m_bind) );
hash.add(bindIdx);
hash.add(sbo.buffer);
hash.add(vsSize);
hash.add(fsSize);
@@ -10351,10 +10352,11 @@ VK_DESTROY
);
double elapsedCpuMs = double(frameTime)*toMs;
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / Binds %d / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
, _render->m_numRenderItems
, statsKeyType[0]
, statsKeyType[1]
, _render->m_numRenderBinds
, elapsedCpuMs
, elapsedCpuMs > maxGpuElapsed ? '>' : '<'
, maxGpuElapsed
+3 -2
View File
@@ -5609,7 +5609,7 @@ m_resolution.formatColor = TextureFormat::BGRA8;
const uint32_t itemIdx = _render->m_sortValues[item];
const RenderItem& renderItem = _render->m_renderItem[itemIdx];
const RenderBind& renderBind = _render->m_renderItemBind[itemIdx];
const RenderBind& renderBind = _render->m_renderBind[isCompute ? renderItem.compute.m_bindIdx : renderItem.draw.m_bindIdx];
++item;
if (viewChanged)
@@ -6469,10 +6469,11 @@ m_resolution.formatColor = TextureFormat::BGRA8;
);
double elapsedCpuMs = double(frameTime)*toMs;
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
tvm.printf(10, pos++, 0x8b, " Submitted: %5d (draw %5d, compute %4d) / Binds: %4d / CPU %7.4f [ms] %c GPU %7.4f [ms] (latency %d) "
, _render->m_numRenderItems
, statsKeyType[0]
, statsKeyType[1]
, _render->m_numRenderBinds
, elapsedCpuMs
, elapsedCpuMs > maxGpuElapsed ? '>' : '<'
, maxGpuElapsed