Prevent marking state dirty if not needed.
Reduce the impact of Vulkan's overly static state and avoid reencoding
unchanged state repeatedly. Reduces encoding time.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index f5ba75a..1a36927 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -37,8 +37,8 @@
#pragma mark MVKPipelineCommandEncoderState
void MVKPipelineCommandEncoderState::bindPipeline(MVKPipeline* pipeline) {
+ if (pipeline != _pipeline) markDirty();
_pipeline = pipeline;
- markDirty();
}
MVKPipeline* MVKPipelineCommandEncoderState::getPipeline() { return _pipeline; }
@@ -71,14 +71,17 @@
usingViewports.resize(firstViewport + vpCnt);
}
+ bool dirty;
bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
if (isSettingDynamically || (!mustSetDynamically && vpCnt > 0)) {
+ dirty = memcmp(&usingViewports[firstViewport], &viewports[0], vpCnt * sizeof(VkViewport)) != 0;
std::copy(viewports.begin(), viewports.end(), usingViewports.begin() + firstViewport);
} else {
+ dirty = !usingViewports.empty();
usingViewports.clear();
}
- markDirty();
+ if (dirty) markDirty();
}
void MVKViewportCommandEncoderState::encodeImpl(uint32_t stage) {
@@ -121,14 +124,17 @@
usingScissors.resize(firstScissor + sCnt);
}
+ bool dirty;
bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR);
if (isSettingDynamically || (!mustSetDynamically && sCnt > 0)) {
+ dirty = memcmp(&usingScissors[firstScissor], &scissors[0], sCnt * sizeof(VkRect2D)) != 0;
std::copy(scissors.begin(), scissors.end(), usingScissors.begin() + firstScissor);
} else {
+ dirty = !usingScissors.empty();
usingScissors.clear();
}
- markDirty();
+ if (dirty) markDirty();
}
void MVKScissorCommandEncoderState::encodeImpl(uint32_t stage) {
@@ -248,6 +254,7 @@
#pragma mark MVKDepthStencilCommandEncoderState
void MVKDepthStencilCommandEncoderState:: setDepthStencilState(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) {
+ auto oldData = _depthStencilData;
if (vkDepthStencilInfo.depthTestEnable) {
_depthStencilData.depthCompareFunction = mvkMTLCompareFunctionFromVkCompareOp(vkDepthStencilInfo.depthCompareOp);
@@ -260,7 +267,7 @@
setStencilState(_depthStencilData.frontFaceStencilData, vkDepthStencilInfo.front, vkDepthStencilInfo.stencilTestEnable);
setStencilState(_depthStencilData.backFaceStencilData, vkDepthStencilInfo.back, vkDepthStencilInfo.stencilTestEnable);
- markDirty();
+ if (!(oldData == _depthStencilData)) markDirty();
}
void MVKDepthStencilCommandEncoderState::setStencilState(MVKMTLStencilDescriptorData& stencilInfo,
@@ -289,6 +296,8 @@
// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway.
void MVKDepthStencilCommandEncoderState::setStencilCompareMask(VkStencilFaceFlags faceMask,
uint32_t stencilCompareMask) {
+ auto oldData = _depthStencilData;
+
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) {
_depthStencilData.frontFaceStencilData.readMask = stencilCompareMask;
}
@@ -296,13 +305,15 @@
_depthStencilData.backFaceStencilData.readMask = stencilCompareMask;
}
- markDirty();
+ if (!(oldData == _depthStencilData)) markDirty();
}
// We don't check for dynamic state here, because if this is called before pipeline is set,
// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway.
void MVKDepthStencilCommandEncoderState::setStencilWriteMask(VkStencilFaceFlags faceMask,
uint32_t stencilWriteMask) {
+ auto oldData = _depthStencilData;
+
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) {
_depthStencilData.frontFaceStencilData.writeMask = stencilWriteMask;
}
@@ -310,7 +321,7 @@
_depthStencilData.backFaceStencilData.writeMask = stencilWriteMask;
}
- markDirty();
+ if (!(oldData == _depthStencilData)) markDirty();
}
void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() {
@@ -353,22 +364,27 @@
// If ref values are to be set dynamically, don't set them here.
if (_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE)) { return; }
+ if (_frontFaceValue != vkDepthStencilInfo.front.reference || _backFaceValue != vkDepthStencilInfo.back.reference)
+ markDirty();
+
_frontFaceValue = vkDepthStencilInfo.front.reference;
_backFaceValue = vkDepthStencilInfo.back.reference;
- markDirty();
}
// We don't check for dynamic state here, because if this is called before pipeline is set,
// it may not be accurate, and if not dynamic, pipeline will override when it is encoded anyway.
void MVKStencilReferenceValueCommandEncoderState::setReferenceValues(VkStencilFaceFlags faceMask,
uint32_t stencilReference) {
+ bool dirty = false;
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_FRONT_BIT)) {
+ dirty |= (_frontFaceValue != stencilReference);
_frontFaceValue = stencilReference;
}
if (mvkAreAllFlagsEnabled(faceMask, VK_STENCIL_FACE_BACK_BIT)) {
+ dirty |= (_backFaceValue != stencilReference);
_backFaceValue = stencilReference;
}
- markDirty();
+ if (dirty) markDirty();
}
void MVKStencilReferenceValueCommandEncoderState::encodeImpl(uint32_t stage) {
@@ -383,16 +399,20 @@
void MVKDepthBiasCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) {
+ auto wasEnabled = _isEnabled;
_isEnabled = vkRasterInfo.depthBiasEnable;
// If ref values are to be set dynamically, don't set them here.
if (_cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS)) { return; }
- _depthBiasConstantFactor = vkRasterInfo.depthBiasConstantFactor;
- _depthBiasSlopeFactor = vkRasterInfo.depthBiasSlopeFactor;
- _depthBiasClamp = vkRasterInfo.depthBiasClamp;
+ if (_isEnabled != wasEnabled || _depthBiasConstantFactor != vkRasterInfo.depthBiasConstantFactor
+ || _depthBiasSlopeFactor != vkRasterInfo.depthBiasSlopeFactor || _depthBiasClamp != vkRasterInfo.depthBiasClamp) {
- markDirty();
+ markDirty();
+ _depthBiasConstantFactor = vkRasterInfo.depthBiasConstantFactor;
+ _depthBiasSlopeFactor = vkRasterInfo.depthBiasSlopeFactor;
+ _depthBiasClamp = vkRasterInfo.depthBiasClamp;
+ }
}
// We don't check for dynamic state here, because if this is called before pipeline is set,
@@ -400,11 +420,15 @@
void MVKDepthBiasCommandEncoderState::setDepthBias(float depthBiasConstantFactor,
float depthBiasSlopeFactor,
float depthBiasClamp) {
- _depthBiasConstantFactor = depthBiasConstantFactor;
- _depthBiasSlopeFactor = depthBiasSlopeFactor;
- _depthBiasClamp = depthBiasClamp;
- markDirty();
+ if (_depthBiasConstantFactor != depthBiasConstantFactor || _depthBiasSlopeFactor != depthBiasSlopeFactor
+ || _depthBiasClamp != depthBiasClamp) {
+
+ markDirty();
+ _depthBiasConstantFactor = depthBiasConstantFactor;
+ _depthBiasSlopeFactor = depthBiasSlopeFactor;
+ _depthBiasClamp = depthBiasClamp;
+ }
}
void MVKDepthBiasCommandEncoderState::encodeImpl(uint32_t stage) {
@@ -428,12 +452,13 @@
// Abort if we are using dynamic, but call is not dynamic.
if ( !isDynamic && _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS) ) { return; }
- _red = red;
- _green = green;
- _blue = blue;
- _alpha = alpha;
-
- markDirty();
+ if (_red != red || _green != green || _blue != blue || _alpha != alpha) {
+ markDirty();
+ _red = red;
+ _green = green;
+ _blue = blue;
+ _alpha = alpha;
+ }
}
void MVKBlendColorCommandEncoderState::encodeImpl(uint32_t stage) {