From a494f9ff6a3e8be6db7bbf4f4fe4002f1f87c524 Mon Sep 17 00:00:00 2001 From: Ben Doherty Date: Fri, 18 Oct 2024 11:07:11 -0400 Subject: [PATCH] Metal: avoid redundant scissor rect state changes (#8207) --- filament/backend/src/metal/MetalContext.h | 1 + filament/backend/src/metal/MetalDriver.mm | 7 ++++++- filament/backend/src/metal/MetalState.h | 16 ++++++++++++---- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/filament/backend/src/metal/MetalContext.h b/filament/backend/src/metal/MetalContext.h index ef1175fa688..e8acf71fbc6 100644 --- a/filament/backend/src/metal/MetalContext.h +++ b/filament/backend/src/metal/MetalContext.h @@ -161,6 +161,7 @@ struct MetalContext { CullModeStateTracker cullModeState; WindingStateTracker windingState; DepthClampStateTracker depthClampState; + ScissorRectStateTracker scissorRectState; Handle currentRenderPrimitive; // State caches. diff --git a/filament/backend/src/metal/MetalDriver.mm b/filament/backend/src/metal/MetalDriver.mm index fb17e99c76b..8528bb77d0c 100644 --- a/filament/backend/src/metal/MetalDriver.mm +++ b/filament/backend/src/metal/MetalDriver.mm @@ -1227,6 +1227,7 @@ mContext->depthStencilState.invalidate(); mContext->cullModeState.invalidate(); mContext->windingState.invalidate(); + mContext->scissorRectState.invalidate(); mContext->currentPolygonOffset = {0.0f, 0.0f}; mContext->finalizedDescriptorSets.clear(); @@ -1953,7 +1954,11 @@ .height = static_cast(bottom - top) }; - [mContext->currentRenderPassEncoder setScissorRect:scissorRect]; + auto& srs = mContext->scissorRectState; + srs.updateState(scissorRect); + if (srs.stateChanged()) { + [mContext->currentRenderPassEncoder setScissorRect:scissorRect]; + } } void MetalDriver::beginTimerQuery(Handle tqh) { diff --git a/filament/backend/src/metal/MetalState.h b/filament/backend/src/metal/MetalState.h index 1e14cddc258..c861cd8cfc9 100644 --- a/filament/backend/src/metal/MetalState.h +++ b/filament/backend/src/metal/MetalState.h @@ -204,9 +204,8 @@ class StateCache { // Different kinds of state, like pipeline state, uniform buffer state, etc., are passed to the // current Metal command encoder and persist throughout the lifetime of the encoder (a frame). // StateTracker is used to prevent calling redundant state change methods. -template +template > class StateTracker { - public: // Call to force the state to dirty at the beginning of each frame, as all state must be @@ -214,7 +213,7 @@ class StateTracker { void invalidate() noexcept { mStateDirty = true; } void updateState(const StateType& newState) noexcept { - if (mCurrentState != newState) { + if (!StateEqual()(mCurrentState, newState)) { mCurrentState = newState; mStateDirty = true; } @@ -235,7 +234,6 @@ class StateTracker { bool mStateDirty = true; StateType mCurrentState = {}; - }; // Pipeline state @@ -343,6 +341,16 @@ using DepthStencilStateTracker = StateTracker; using DepthStencilStateCache = StateCache, DepthStateCreator>; +struct MtlScissorRectEqual { + bool operator()(const MTLScissorRect& lhs, const MTLScissorRect& rhs) const { + return lhs.height == rhs.height && + lhs.width == rhs.width && + lhs.x == rhs.x && + lhs.y == rhs.y; + } +}; +using ScissorRectStateTracker = StateTracker; + // Uniform buffers class MetalBufferObject;