diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index cb4d1cb0..eb72f483 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -147,7 +147,7 @@ protected: void encodeImpl(uint32_t stage) override; void resetImpl() override; - MVKVectorInline _mtlViewports; + MVKVectorInline _mtlViewports, _mtlDynamicViewports; }; @@ -176,7 +176,7 @@ protected: void encodeImpl(uint32_t stage) override; void resetImpl() override; - MVKVectorInline _mtlScissors; + MVKVectorInline _mtlScissors, _mtlDynamicScissors; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index b671f790..9fa6c906 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -54,34 +54,51 @@ void MVKViewportCommandEncoderState::setViewports(const MVKVector & uint32_t firstViewport, bool isSettingDynamically) { - bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT); - uint32_t maxViewports = _cmdEncoder->getDevice()->_pProperties->limits.maxViewports; - if ((mustSetDynamically == isSettingDynamically) && mtlViewports.size() > 0 && + if (isSettingDynamically && mtlViewports.size() > 0 && (firstViewport + mtlViewports.size() <= maxViewports) && (firstViewport < maxViewports)) { + if (firstViewport + mtlViewports.size() > _mtlDynamicViewports.size()) { + _mtlDynamicViewports.resize(firstViewport + mtlViewports.size()); + } + + std::copy(mtlViewports.begin(), mtlViewports.end(), _mtlDynamicViewports.begin() + firstViewport); + + markDirty(); + } else if (!isSettingDynamically && + (firstViewport + mtlViewports.size() <= maxViewports) && + (firstViewport < maxViewports)) { + + bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_VIEWPORT); + if (firstViewport + mtlViewports.size() > _mtlViewports.size()) { _mtlViewports.resize(firstViewport + mtlViewports.size()); } - std::copy(mtlViewports.begin(), mtlViewports.end(), _mtlViewports.begin() + firstViewport); + if (mtlViewports.size() > 0 && !mustSetDynamically) + std::copy(mtlViewports.begin(), mtlViewports.end(), _mtlViewports.begin() + firstViewport); + else + _mtlViewports.clear(); + markDirty(); } } void MVKViewportCommandEncoderState::encodeImpl(uint32_t stage) { if (stage != kMVKGraphicsStageRasterization) { return; } - MVKAssert(!_mtlViewports.empty(), "Must specify at least one viewport"); + auto& mtlViewports = _mtlViewports.size() > 0 ? _mtlViewports : _mtlDynamicViewports; + MVKAssert(!mtlViewports.empty(), "Must specify at least one viewport"); if (_cmdEncoder->_pDeviceFeatures->multiViewport) { - [_cmdEncoder->_mtlRenderEncoder setViewports: &_mtlViewports[0] count: _mtlViewports.size()]; + [_cmdEncoder->_mtlRenderEncoder setViewports: &mtlViewports[0] count: mtlViewports.size()]; } else { - [_cmdEncoder->_mtlRenderEncoder setViewport: _mtlViewports[0]]; + [_cmdEncoder->_mtlRenderEncoder setViewport: mtlViewports[0]]; } } void MVKViewportCommandEncoderState::resetImpl() { _mtlViewports.clear(); + _mtlDynamicViewports.clear(); } @@ -92,26 +109,42 @@ void MVKScissorCommandEncoderState::setScissors(const MVKVector uint32_t firstScissor, bool isSettingDynamically) { - bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR); - uint32_t maxScissors = _cmdEncoder->getDevice()->_pProperties->limits.maxViewports; - if ((mustSetDynamically == isSettingDynamically) && mtlScissors.size() > 0 && + if (isSettingDynamically && mtlScissors.size() > 0 && (firstScissor + mtlScissors.size() <= maxScissors) && (firstScissor < maxScissors)) { + if (firstScissor + mtlScissors.size() > _mtlDynamicScissors.size()) { + _mtlDynamicScissors.resize(firstScissor + mtlScissors.size()); + } + + std::copy(mtlScissors.begin(), mtlScissors.end(), _mtlDynamicScissors.begin() + firstScissor); + + markDirty(); + } else if (!isSettingDynamically && + (firstScissor + mtlScissors.size() <= maxScissors) && + (firstScissor < maxScissors)) { + + bool mustSetDynamically = _cmdEncoder->supportsDynamicState(VK_DYNAMIC_STATE_SCISSOR); + if (firstScissor + mtlScissors.size() > _mtlScissors.size()) { _mtlScissors.resize(firstScissor + mtlScissors.size()); } - std::copy(mtlScissors.begin(), mtlScissors.end(), _mtlScissors.begin() + firstScissor); + if (mtlScissors.size() > 0 && !mustSetDynamically) + std::copy(mtlScissors.begin(), mtlScissors.end(), _mtlScissors.begin() + firstScissor); + else + _mtlScissors.clear(); + markDirty(); } } void MVKScissorCommandEncoderState::encodeImpl(uint32_t stage) { if (stage != kMVKGraphicsStageRasterization) { return; } - MVKAssert(!_mtlScissors.empty(), "Must specify at least one scissor rect"); - auto clippedScissors(_mtlScissors); + auto& mtlScissors = _mtlScissors.size() > 0 ? _mtlScissors : _mtlDynamicScissors; + MVKAssert(!mtlScissors.empty(), "Must specify at least one scissor rect"); + auto clippedScissors(mtlScissors); std::for_each(clippedScissors.begin(), clippedScissors.end(), [this](MTLScissorRect& scissor) { scissor = _cmdEncoder->clipToRenderArea(scissor); }); @@ -124,6 +157,7 @@ void MVKScissorCommandEncoderState::encodeImpl(uint32_t stage) { void MVKScissorCommandEncoderState::resetImpl() { _mtlScissors.clear(); + _mtlDynamicScissors.clear(); }