diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index c2f54985b..9b00360e3 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -375,6 +375,8 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - *Requires Metal 3.1 for `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`.* - `VK_EXT_extended_dynamic_state2` - *Primitive restart is always enabled, as Metal does not support disabling it (`VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT`).* +- `VK_EXT_extended_dynamic_state3` + - *Metal does not support `VK_POLYGON_MODE_POINT`* - `VK_EXT_external_memory_host` - `VK_EXT_fragment_shader_interlock` - *Requires Metal 2.0 and Raster Order Groups.* diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 4b091229e..e7b23f2ce 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -18,6 +18,10 @@ MoltenVK 1.2.7 Released TBD +- Add support for extensions: + - `VK_EXT_extended_dynamic_state3` *(Metal does not support `VK_POLYGON_MODE_POINT`)* +- Fix regression that broke `VK_POLYGON_MODE_LINE`. +- Fix regression in marking rendering state dirty after `vkCmdClearAttachments()`. - Reduce disk space consumed after running `fetchDependencies` script by removing intermediate file caches. - Fix rare deadlock during launch via `dlopen()`. - Update to latest SPIRV-Cross: diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm index a7930a474..87515ba12 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm @@ -144,10 +144,9 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { - if (_vertexCount == 0 || _instanceCount == 0) { - // Nothing to do. - return; - } + if (_vertexCount == 0 || _instanceCount == 0) { return; } // Nothing to do. + + cmdEncoder->restartMetalRenderPassIfNeeded(); auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); @@ -172,7 +171,7 @@ } tessParams; uint32_t outControlPointCount = 0; if (pipeline->isTessellationPipeline()) { - tessParams.inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); + tessParams.inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); tessParams.patchCount = mvkCeilingDivide(_vertexCount, tessParams.inControlPointCount) * _instanceCount; } @@ -369,10 +368,9 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { - if (_indexCount == 0 || _instanceCount == 0) { - // Nothing to do. - return; - } + if (_indexCount == 0 || _instanceCount == 0) { return; } // Nothing to do. + + cmdEncoder->restartMetalRenderPassIfNeeded(); auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); @@ -401,7 +399,7 @@ } tessParams; uint32_t outControlPointCount = 0; if (pipeline->isTessellationPipeline()) { - tessParams.inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); + tessParams.inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); tessParams.patchCount = mvkCeilingDivide(_indexCount, tessParams.inControlPointCount) * _instanceCount; } @@ -649,6 +647,8 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->restartMetalRenderPassIfNeeded(); + auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline(); // Metal doesn't support triangle fans, so encode it as indexed indirect triangles instead. @@ -686,7 +686,7 @@ // encoding and execution. So we don't know how big to make the buffers. // We must assume an arbitrarily large number of vertices may be submitted. // But not too many, or we'll exhaust available VRAM. - inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); + inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); vertexCount = kMVKMaxDrawIndirectVertexCount; patchCount = mvkCeilingDivide(vertexCount, inControlPointCount); @@ -990,6 +990,7 @@ } void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->restartMetalRenderPassIfNeeded(); encode(cmdEncoder, cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding); } @@ -1034,7 +1035,7 @@ // encoding and execution. So we don't know how big to make the buffers. // We must assume an arbitrarily large number of vertices may be submitted. // But not too many, or we'll exhaust available VRAM. - inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints(); + inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints(); outControlPointCount = pipeline->getOutputControlPointCount(); vertexCount = kMVKMaxDrawIndirectVertexCount; patchCount = mvkCeilingDivide(vertexCount, inControlPointCount); diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h index 7f1df4b43..16e4863bf 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.h @@ -46,7 +46,6 @@ class MVKCmdBeginRenderPassBase : public MVKCommand { protected: - MVKSmallVector> _subpassSamplePositions; MVKRenderPass* _renderPass; MVKFramebuffer* _framebuffer; VkRect2D _renderArea; @@ -203,7 +202,26 @@ class MVKCmdSetSampleLocations : public MVKCommand { protected: MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; - MVKSmallVector _samplePositions; + MVKSmallVector _sampleLocations; +}; + + +#pragma mark - +#pragma mark MVKCmdSetSampleLocationsEnable + +/** Vulkan command to dynamically enable custom sample locations. */ +class MVKCmdSetSampleLocationsEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 sampleLocationsEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkBool32 _sampleLocationsEnable; }; @@ -366,6 +384,25 @@ class MVKCmdSetDepthWriteEnable : public MVKCommand { }; +#pragma mark - +#pragma mark MVKCmdSetDepthClipEnable + +/** Vulkan command to dynamically enable depth clip. */ +class MVKCmdSetDepthClipEnable : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthClipEnable); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkBool32 _depthClipEnable; +}; + + #pragma mark - #pragma mark MVKCmdSetDepthCompareOp @@ -551,6 +588,25 @@ class MVKCmdSetPatchControlPoints : public MVKCommand { }; +#pragma mark - +#pragma mark MVKCmdSetPolygonMode + +/** Vulkan command to dynamically set the polygon mode. */ +class MVKCmdSetPolygonMode : public MVKCommand { + +public: + VkResult setContent(MVKCommandBuffer* cmdBuff, + VkPolygonMode polygonMode); + + void encode(MVKCommandEncoder* cmdEncoder) override; + +protected: + MVKCommandTypePool* getTypePool(MVKCommandPool* cmdPool) override; + + VkPolygonMode _polygonMode; +}; + + #pragma mark - #pragma mark MVKCmdSetPrimitiveTopology diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm index c4bb75484..a2492acec 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm @@ -36,30 +36,6 @@ _renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass; _framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer; _renderArea = pRenderPassBegin->renderArea; - _subpassSamplePositions.clear(); - - for (const auto* next = (VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) { - switch (next->sType) { - case VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT: { - // Build an array of arrays, one array of sample positions for each subpass index. - // For subpasses not included in VkRenderPassSampleLocationsBeginInfoEXT, the resulting array of samples will be empty. - _subpassSamplePositions.resize(_renderPass->getSubpassCount()); - auto* pRPSampLocnsInfo = (VkRenderPassSampleLocationsBeginInfoEXT*)next; - for (uint32_t spSLIdx = 0; spSLIdx < pRPSampLocnsInfo->postSubpassSampleLocationsCount; spSLIdx++) { - auto& spsl = pRPSampLocnsInfo->pPostSubpassSampleLocations[spSLIdx]; - uint32_t spIdx = spsl.subpassIndex; - auto& spSampPosns = _subpassSamplePositions[spIdx]; - for (uint32_t slIdx = 0; slIdx < spsl.sampleLocationsInfo.sampleLocationsCount; slIdx++) { - auto& sl = spsl.sampleLocationsInfo.pSampleLocations[slIdx]; - spSampPosns.push_back(MTLSamplePositionMake(sl.x, sl.y)); - } - } - break; - } - default: - break; - } - } cmdBuff->_currentSubpassInfo.beginRenderpass(_renderPass); @@ -86,15 +62,6 @@ template void MVKCmdBeginRenderPass::encode(MVKCommandEncoder* cmdEncoder) { - - // Convert the sample position array of arrays to an array of array-references, - // so that it can be passed to the command encoder. - size_t spSPCnt = _subpassSamplePositions.size(); - MVKArrayRef spSPRefs[spSPCnt]; - for (uint32_t spSPIdx = 0; spSPIdx < spSPCnt; spSPIdx++) { - spSPRefs[spSPIdx] = _subpassSamplePositions[spSPIdx].contents(); - } - cmdEncoder->beginRenderpass(this, _contents, _renderPass, @@ -102,7 +69,7 @@ _renderArea, _clearValues.contents(), _attachments.contents(), - MVKArrayRef(spSPRefs, spSPCnt)); + kMVKCommandUseBeginRenderPass); } template class MVKCmdBeginRenderPass<1, 0>; @@ -217,17 +184,29 @@ VkResult MVKCmdSetSampleLocations::setContent(MVKCommandBuffer* cmdBuff, const VkSampleLocationsInfoEXT* pSampleLocationsInfo) { - + _sampleLocations.clear(); for (uint32_t slIdx = 0; slIdx < pSampleLocationsInfo->sampleLocationsCount; slIdx++) { - auto& sl = pSampleLocationsInfo->pSampleLocations[slIdx]; - _samplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y)); + _sampleLocations.push_back(pSampleLocationsInfo->pSampleLocations[slIdx]); } - return VK_SUCCESS; } void MVKCmdSetSampleLocations::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->setDynamicSamplePositions(_samplePositions.contents()); + cmdEncoder->_renderingState.setSampleLocations(_sampleLocations.contents(), true); +} + + +#pragma mark - +#pragma mark MVKCmdSetSampleLocationsEnable + +VkResult MVKCmdSetSampleLocationsEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 sampleLocationsEnable) { + _sampleLocationsEnable = sampleLocationsEnable; + return VK_SUCCESS; +} + +void MVKCmdSetSampleLocationsEnable::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_renderingState.setSampleLocationsEnable(_sampleLocationsEnable, true); } @@ -240,7 +219,7 @@ uint32_t viewportCount, const VkViewport* pViewports) { _firstViewport = firstViewport; - _viewports.clear(); // Clear for reuse + _viewports.clear(); _viewports.reserve(viewportCount); for (uint32_t vpIdx = 0; vpIdx < viewportCount; vpIdx++) { _viewports.push_back(pViewports[vpIdx]); @@ -267,7 +246,7 @@ uint32_t scissorCount, const VkRect2D* pScissors) { _firstScissor = firstScissor; - _scissors.clear(); // Clear for reuse + _scissors.clear(); _scissors.reserve(scissorCount); for (uint32_t sIdx = 0; sIdx < scissorCount; sIdx++) { _scissors.push_back(pScissors[sIdx]); @@ -362,6 +341,20 @@ } +#pragma mark - +#pragma mark MVKCmdSetDepthClipEnable + +VkResult MVKCmdSetDepthClipEnable::setContent(MVKCommandBuffer* cmdBuff, + VkBool32 depthClipEnable) { + _depthClipEnable = depthClipEnable; + return VK_SUCCESS; +} + +void MVKCmdSetDepthClipEnable::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_renderingState.setDepthClipEnable(_depthClipEnable, true); +} + + #pragma mark - #pragma mark MVKCmdSetDepthCompareOp @@ -501,7 +494,21 @@ } void MVKCmdSetPatchControlPoints::encode(MVKCommandEncoder* cmdEncoder) { - cmdEncoder->_graphicsPipelineState.setPatchControlPoints(_patchControlPoints); + cmdEncoder->_renderingState.setPatchControlPoints(_patchControlPoints, true); +} + + +#pragma mark - +#pragma mark MVKCmdSetPolygonMode + +VkResult MVKCmdSetPolygonMode::setContent(MVKCommandBuffer* cmdBuff, + VkPolygonMode polygonMode) { + _polygonMode = polygonMode; + return VK_SUCCESS; +} + +void MVKCmdSetPolygonMode::encode(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_renderingState.setPolygonMode(_polygonMode, true); } diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 124859bdc..52dcb78f0 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -1506,8 +1506,10 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma // Return to the previous rendering state on the next render activity cmdEncoder->_graphicsPipelineState.markDirty(); + cmdEncoder->_graphicsResourcesState.markDirty(); cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->_renderingState.markDirty(); + cmdEncoder->_occlusionQueryState.markDirty(); } template diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 39580131a..92d02e772 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -250,21 +250,23 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { const VkRect2D& renderArea, MVKArrayRef clearValues, MVKArrayRef attachments, - MVKArrayRef> subpassSamplePositions, - MVKCommandUse cmdUse = kMVKCommandUseBeginRenderPass); + MVKCommandUse cmdUse); /** Begins the next render subpass. */ void beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents renderpassContents); - /** Sets the dynamic custom sample positions to use when rendering. */ - void setDynamicSamplePositions(MVKArrayRef dynamicSamplePositions); - /** Begins dynamic rendering. */ void beginRendering(MVKCommand* rendCmd, const VkRenderingInfo* pRenderingInfo); /** Begins a Metal render pass for the current render subpass. */ void beginMetalRenderPass(MVKCommandUse cmdUse); + /** + * If a Metal render pass has started, and it needs to be restarted, + * then end the existing Metal render pass, and start a new one. + */ + void restartMetalRenderPassIfNeeded(); + /** If a render encoder is active, encodes store actions for all attachments to it. */ void encodeStoreActions(bool storeOverride = false); @@ -435,13 +437,13 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { id _mtlRenderEncoder; /** Tracks the current graphics pipeline bound to the encoder. */ - MVKGraphicsPipelineCommandEncoderState _graphicsPipelineState; + MVKPipelineCommandEncoderState _graphicsPipelineState; /** Tracks the current graphics resources state of the encoder. */ MVKGraphicsResourcesCommandEncoderState _graphicsResourcesState; /** Tracks the current compute pipeline bound to the encoder. */ - MVKComputePipelineCommandEncoderState _computePipelineState; + MVKPipelineCommandEncoderState _computePipelineState; /** Tracks the current compute resources state of the encoder. */ MVKComputeResourcesCommandEncoderState _computeResourcesState; @@ -452,6 +454,9 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { /** Tracks the current rendering states of the encoder. */ MVKRenderingCommandEncoderState _renderingState; + /** Tracks the occlusion query state of the encoder. */ + MVKOcclusionQueryCommandEncoderState _occlusionQueryState; + /** The size of the threadgroup for the compute shader. */ MTLSize _mtlThreadgroupSize; @@ -479,7 +484,6 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { void encodeGPUCounterSample(MVKGPUCounterQueryPool* mvkQryPool, uint32_t sampleIndex, MVKCounterSamplingFlags samplingPoints); void encodeTimestampStageCounterSamples(); id getStageCountersMTLFence(); - MVKArrayRef getCustomSamplePositions(); NSString* getMTLRenderCommandEncoderName(MVKCommandUse cmdUse); template void retainIfImmediatelyEncoding(T& mtlEnc); template void endMetalEncoding(T& mtlEnc); @@ -495,8 +499,6 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { MVKSmallVector _timestampStageCounterQueries; MVKSmallVector _clearValues; MVKSmallVector _attachments; - MVKSmallVector _dynamicSamplePositions; - MVKSmallVector> _subpassSamplePositions; id _mtlComputeEncoder; id _mtlBlitEncoder; id _stageCountersMTLFence; @@ -505,7 +507,6 @@ class MVKCommandEncoder : public MVKBaseDeviceObject { MVKPushConstantsCommandEncoderState _tessEvalPushConstants; MVKPushConstantsCommandEncoderState _fragmentPushConstants; MVKPushConstantsCommandEncoderState _computePushConstants; - MVKOcclusionQueryCommandEncoderState _occlusionQueryState; MVKPrefillMetalCommandBuffersStyle _prefillStyle; VkSubpassContents _subpassContents; uint32_t _renderSubpassIndex; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 9575bb760..44f0204e1 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -442,7 +442,6 @@ pRenderingInfo->renderArea, MVKArrayRef(clearValues, attCnt), MVKArrayRef(imageViews, attCnt), - MVKArrayRef>(), kMVKCommandUseBeginRendering); // If we've just created new transient objects, once retained by this encoder, @@ -462,7 +461,6 @@ const VkRect2D& renderArea, MVKArrayRef clearValues, MVKArrayRef attachments, - MVKArrayRef> subpassSamplePositions, MVKCommandUse cmdUse) { _pEncodingContext->setRenderingContext(renderPass, framebuffer); _renderArea = renderArea; @@ -471,13 +469,6 @@ _clearValues.assign(clearValues.begin(), clearValues.end()); _attachments.assign(attachments.begin(), attachments.end()); - // Copy the sample positions array of arrays, one array of sample positions for each subpass index. - _subpassSamplePositions.resize(subpassSamplePositions.size()); - for (uint32_t spSPIdx = 0; spSPIdx < subpassSamplePositions.size(); spSPIdx++) { - _subpassSamplePositions[spSPIdx].assign(subpassSamplePositions[spSPIdx].begin(), - subpassSamplePositions[spSPIdx].end()); - } - setSubpass(passCmd, subpassContents, 0, cmdUse); } @@ -518,10 +509,6 @@ beginMetalRenderPass(kMVKCommandUseNextSubpass); } -void MVKCommandEncoder::setDynamicSamplePositions(MVKArrayRef dynamicSamplePositions) { - _dynamicSamplePositions.assign(dynamicSamplePositions.begin(), dynamicSamplePositions.end()); -} - // Retain encoders when prefilling, because prefilling may span multiple autorelease pools. template void MVKCommandEncoder::retainIfImmediatelyEncoding(T& mtlEnc) { @@ -536,7 +523,6 @@ mtlEnc = nil; } - // Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder. void MVKCommandEncoder::beginMetalRenderPass(MVKCommandUse cmdUse) { @@ -592,8 +578,8 @@ // If no custom sample positions are established, size will be zero, // and Metal will default to using default sample postions. if (_pDeviceMetalFeatures->programmableSamplePositions) { - auto cstmSampPosns = getCustomSamplePositions(); - [mtlRPDesc setSamplePositions: cstmSampPosns.data() count: cstmSampPosns.size()]; + auto sampPosns = _renderingState.getSamplePositions(); + [mtlRPDesc setSamplePositions: sampPosns.data() count: sampPosns.size()]; } _mtlRenderEncoder = [_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPDesc]; @@ -616,16 +602,13 @@ _occlusionQueryState.beginMetalRenderPass(); } -// If custom sample positions have been set, return them, otherwise return an empty array. -// For Metal, VkPhysicalDeviceSampleLocationsPropertiesEXT::variableSampleLocations is false. -// As such, Vulkan requires that sample positions must be established at the beginning of -// a renderpass, and that both pipeline and dynamic sample locations must be the same as those -// set for each subpass. Therefore, the only sample positions of use are those set for each -// subpass when the renderpass begins. The pipeline and dynamic sample positions are ignored. -MVKArrayRef MVKCommandEncoder::getCustomSamplePositions() { - return (_renderSubpassIndex < _subpassSamplePositions.size() - ? _subpassSamplePositions[_renderSubpassIndex].contents() - : MVKArrayRef()); +void MVKCommandEncoder::restartMetalRenderPassIfNeeded() { + if ( !_mtlRenderEncoder ) { return; } + + if (_renderingState.needsMetalRenderPassRestart()) { + encodeStoreActions(true); + beginMetalRenderPass(kMVKCommandUseRestartSubpass); + } } void MVKCommandEncoder::encodeStoreActions(bool storeOverride) { @@ -1161,12 +1144,12 @@ _computeResourcesState(this), _depthStencilState(this), _renderingState(this), + _occlusionQueryState(this), _vertexPushConstants(this, VK_SHADER_STAGE_VERTEX_BIT), _tessCtlPushConstants(this, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT), _tessEvalPushConstants(this, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT), _fragmentPushConstants(this, VK_SHADER_STAGE_FRAGMENT_BIT), _computePushConstants(this, VK_SHADER_STAGE_COMPUTE_BIT), - _occlusionQueryState(this), _prefillStyle(prefillStyle){ _pDeviceFeatures = &_device->_enabledFeatures; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 82ea4eabb..4ac895d43 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -106,8 +106,11 @@ class MVKCommandEncoderState : public MVKBaseObject { virtual void encodeImpl(uint32_t stage) = 0; MVKDevice* getDevice(); bool isDynamicState(MVKRenderStateType state); + template T& getContent(T* iVarAry, bool isDynamic) { + return iVarAry[isDynamic ? StateScope::Dynamic : StateScope::Static]; + } template T& getContent(T* iVarAry, MVKRenderStateType state) { - return iVarAry[isDynamicState(state) ? StateScope::Dynamic : StateScope::Static]; + return getContent(iVarAry, isDynamicState(state)); } MVKCommandEncoder* _cmdEncoder; @@ -123,9 +126,11 @@ class MVKCommandEncoderState : public MVKBaseObject { class MVKPipelineCommandEncoderState : public MVKCommandEncoderState { public: - virtual void bindPipeline(MVKPipeline* pipeline); + void bindPipeline(MVKPipeline* pipeline); MVKPipeline* getPipeline(); + MVKGraphicsPipeline* getGraphicsPipeline() { return (MVKGraphicsPipeline*)getPipeline(); } + MVKComputePipeline* getComputePipeline() { return (MVKComputePipeline*)getPipeline(); } MVKPipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {} @@ -136,42 +141,6 @@ class MVKPipelineCommandEncoderState : public MVKCommandEncoderState { }; -#pragma mark - -#pragma mark MVKGraphicsPipelineCommandEncoderState - -/** Holds encoder state established by graphics pipeline commands. */ -class MVKGraphicsPipelineCommandEncoderState : public MVKPipelineCommandEncoderState { - -public: - void bindPipeline(MVKPipeline* pipeline) override; - - MVKGraphicsPipeline* getGraphicsPipeline() { return (MVKGraphicsPipeline*)getPipeline(); } - - void setPatchControlPoints(uint32_t patchControlPoints); - uint32_t getPatchControlPoints(); - - MVKGraphicsPipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKPipelineCommandEncoderState(cmdEncoder) {} - -protected: - uint32_t _patchControlPoints[StateScope::Count] = {}; -}; - - -#pragma mark - -#pragma mark MVKComputePipelineCommandEncoderState - -/** Holds encoder state established by compute pipeline commands. */ -class MVKComputePipelineCommandEncoderState : public MVKPipelineCommandEncoderState { - -public: - MVKComputePipeline* getComputePipeline() { return (MVKComputePipeline*)getPipeline(); } - - MVKComputePipelineCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKPipelineCommandEncoderState(cmdEncoder) {} - -protected: -}; - - #pragma mark - #pragma mark MVKPushConstantsCommandEncoderState @@ -257,7 +226,7 @@ class MVKDepthStencilCommandEncoderState : public MVKCommandEncoderState { VkStencilOp passOp, VkStencilOp depthFailOp, VkCompareOp compareOp); MVKMTLDepthStencilDescriptorData _depthStencilData[StateScope::Count]; - bool _depthTestEnabled[StateScope::Count]; + bool _depthTestEnabled[StateScope::Count] = {}; bool _hasDepthAttachment = false; bool _hasStencilAttachment = false; }; @@ -294,9 +263,6 @@ class MVKRenderingCommandEncoderState : public MVKCommandEncoderState { void setFrontFace(VkFrontFace frontFace, bool isDynamic); - void setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic); - MTLPrimitiveType getPrimitiveType(); - void setPolygonMode(VkPolygonMode polygonMode, bool isDynamic); void setBlendConstants(float blendConstants[4], bool isDynamic); @@ -316,13 +282,26 @@ class MVKRenderingCommandEncoderState : public MVKCommandEncoderState { void setRasterizerDiscardEnable(VkBool32 rasterizerDiscardEnable, bool isDynamic); + void setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic); + MTLPrimitiveType getPrimitiveType(); + + void setPatchControlPoints(uint32_t patchControlPoints, bool isDynamic); + uint32_t getPatchControlPoints(); + + void setSampleLocationsEnable(VkBool32 sampleLocationsEnable, bool isDynamic); + void setSampleLocations(const MVKArrayRef sampleLocations, bool isDynamic); + MVKArrayRef getSamplePositions(); + void beginMetalRenderPass() override; + bool needsMetalRenderPassRestart(); + + bool isDirty(MVKRenderStateType state); + void markDirty() override; MVKRenderingCommandEncoderState(MVKCommandEncoder* cmdEncoder) : MVKCommandEncoderState(cmdEncoder) {} protected: void encodeImpl(uint32_t stage) override; - bool isDirty(MVKRenderStateType state); bool isDrawingTriangles(); template void setContent(T* iVarAry, T* pVal, MVKRenderStateType state, bool isDynamic) { auto* pIVar = &iVarAry[isDynamic ? StateScope::Dynamic : StateScope::Static]; @@ -330,10 +309,11 @@ class MVKRenderingCommandEncoderState : public MVKCommandEncoderState { *pIVar = *pVal; _dirtyStates.enable(state); _modifiedStates.enable(state); - markDirty(); + MVKCommandEncoderState::markDirty(); // Avoid local markDirty() as it marks all states dirty. } } + MVKSmallVector _mtlSampleLocations[StateScope::Count] = {}; MVKMTLViewports _mtlViewports[StateScope::Count] = {}; MVKMTLScissors _mtlScissors[StateScope::Count] = {}; MVKColor32 _mtlBlendConstants[StateScope::Count] = {}; @@ -344,8 +324,10 @@ class MVKRenderingCommandEncoderState : public MVKCommandEncoderState { MTLPrimitiveType _mtlPrimitiveTopology[StateScope::Count] = { MTLPrimitiveTypePoint, MTLPrimitiveTypePoint }; MTLDepthClipMode _mtlDepthClipEnable[StateScope::Count] = { MTLDepthClipModeClip, MTLDepthClipModeClip }; MTLTriangleFillMode _mtlPolygonMode[StateScope::Count] = { MTLTriangleFillModeFill, MTLTriangleFillModeFill }; + uint32_t _mtlPatchControlPoints[StateScope::Count] = {}; MVKRenderStateFlags _dirtyStates; MVKRenderStateFlags _modifiedStates; + bool _mtlSampleLocationsEnable[StateScope::Count] = {}; bool _mtlDepthBiasEnable[StateScope::Count] = {}; bool _mtlPrimitiveRestartEnable[StateScope::Count] = {}; bool _mtlRasterizerDiscardEnable[StateScope::Count] = {}; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index 9e17aa99a..c7246a516 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -45,8 +45,11 @@ #pragma mark MVKPipelineCommandEncoderState void MVKPipelineCommandEncoderState::bindPipeline(MVKPipeline* pipeline) { - if (pipeline != _pipeline) markDirty(); - _pipeline = pipeline; + if (pipeline == _pipeline) { return; } + + _pipeline = pipeline; + _pipeline->wasBound(_cmdEncoder); + markDirty(); } MVKPipeline* MVKPipelineCommandEncoderState::getPipeline() { return _pipeline; } @@ -59,23 +62,6 @@ } -#pragma mark - -#pragma mark MVKGraphicsPipelineCommandEncoderState - -void MVKGraphicsPipelineCommandEncoderState::bindPipeline(MVKPipeline* pipeline) { - MVKPipelineCommandEncoderState::bindPipeline(pipeline); - _patchControlPoints[StateScope::Static] = getGraphicsPipeline()->_tessInfo.patchControlPoints; -} - -void MVKGraphicsPipelineCommandEncoderState::setPatchControlPoints(uint32_t patchControlPoints) { - _patchControlPoints[StateScope::Dynamic] = patchControlPoints; -} - -uint32_t MVKGraphicsPipelineCommandEncoderState::getPatchControlPoints() { - return getContent(_patchControlPoints, PatchControlPoints); -} - - #pragma mark - #pragma mark MVKPushConstantsCommandEncoderState @@ -310,60 +296,43 @@ #pragma mark - #pragma mark MVKRenderingCommandEncoderState -#define getContent(state) getContent(_mtl##state, state) -#define setContent(state) setContent(_mtl##state, &mtl##state, state, isDynamic) +#define getMTLContent(state) getContent(_mtl##state, state) +#define setMTLContent(state) setContent(_mtl##state, &mtl##state, state, isDynamic) void MVKRenderingCommandEncoderState::setCullMode(VkCullModeFlags cullMode, bool isDynamic) { auto mtlCullMode = mvkMTLCullModeFromVkCullModeFlags(cullMode); - setContent(CullMode); + setMTLContent(CullMode); _cullBothFaces[isDynamic ? StateScope::Dynamic : StateScope::Static] = (cullMode == VK_CULL_MODE_FRONT_AND_BACK); } void MVKRenderingCommandEncoderState::setFrontFace(VkFrontFace frontFace, bool isDynamic) { auto mtlFrontFace = mvkMTLWindingFromVkFrontFace(frontFace); - setContent(FrontFace); -} - -void MVKRenderingCommandEncoderState::setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic) { - auto mtlPrimitiveTopology = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(topology); - setContent(PrimitiveTopology); -} - -MTLPrimitiveType MVKRenderingCommandEncoderState::getPrimitiveType() { - return getContent(PrimitiveTopology); -} - -bool MVKRenderingCommandEncoderState::isDrawingTriangles() { - switch (getPrimitiveType()) { - case MTLPrimitiveTypeTriangle: return true; - case MTLPrimitiveTypeTriangleStrip: return true; - default: return false; - } + setMTLContent(FrontFace); } void MVKRenderingCommandEncoderState::setPolygonMode(VkPolygonMode polygonMode, bool isDynamic) { auto mtlPolygonMode = mvkMTLTriangleFillModeFromVkPolygonMode(polygonMode); - setContent(PolygonMode); + setMTLContent(PolygonMode); } void MVKRenderingCommandEncoderState::setBlendConstants(float blendConstants[4], bool isDynamic) { MVKColor32 mtlBlendConstants; mvkCopy(mtlBlendConstants.float32, blendConstants, 4); - setContent(BlendConstants); + setMTLContent(BlendConstants); } void MVKRenderingCommandEncoderState::setDepthBias(const VkPipelineRasterizationStateCreateInfo& vkRasterInfo) { bool isDynamic = false; bool mtlDepthBiasEnable = static_cast(vkRasterInfo.depthBiasEnable); - setContent(DepthBiasEnable); + setMTLContent(DepthBiasEnable); MVKDepthBias mtlDepthBias = { .depthBiasConstantFactor = vkRasterInfo.depthBiasConstantFactor, .depthBiasSlopeFactor = vkRasterInfo.depthBiasSlopeFactor, .depthBiasClamp = vkRasterInfo.depthBiasClamp }; - setContent(DepthBias); + setMTLContent(DepthBias); } void MVKRenderingCommandEncoderState::setDepthBias(float depthBiasConstantFactor, @@ -375,18 +344,18 @@ .depthBiasSlopeFactor = depthBiasSlopeFactor, .depthBiasClamp = depthBiasClamp }; - setContent(DepthBias); + setMTLContent(DepthBias); } void MVKRenderingCommandEncoderState::setDepthBiasEnable(VkBool32 depthBiasEnable) { bool isDynamic = true; bool mtlDepthBiasEnable = static_cast(depthBiasEnable); - setContent(DepthBiasEnable); + setMTLContent(DepthBiasEnable); } void MVKRenderingCommandEncoderState::setDepthClipEnable(bool depthClip, bool isDynamic) { auto mtlDepthClipEnable = depthClip ? MTLDepthClipModeClip : MTLDepthClipModeClamp; - setContent(DepthClipEnable); + setMTLContent(DepthClipEnable); } void MVKRenderingCommandEncoderState::setStencilReferenceValues(const VkPipelineDepthStencilStateCreateInfo& vkDepthStencilInfo) { @@ -395,7 +364,7 @@ .frontFaceValue = vkDepthStencilInfo.front.reference, .backFaceValue = vkDepthStencilInfo.back.reference }; - setContent(StencilReference); + setMTLContent(StencilReference); } void MVKRenderingCommandEncoderState::setStencilReferenceValues(VkStencilFaceFlags faceMask, uint32_t stencilReference) { @@ -403,7 +372,7 @@ MVKStencilReference mtlStencilReference = _mtlStencilReference[StateScope::Dynamic]; if (shouldUpdateFace(FRONT)) { mtlStencilReference.frontFaceValue = stencilReference; } if (shouldUpdateFace(BACK)) { mtlStencilReference.backFaceValue = stencilReference; } - setContent(StencilReference); + setMTLContent(StencilReference); } void MVKRenderingCommandEncoderState::setViewports(const MVKArrayRef viewports, @@ -418,7 +387,7 @@ mtlViewports.viewports[firstViewport + vpIdx] = mvkMTLViewportFromVkViewport(viewports[vpIdx]); mtlViewports.viewportCount = max(mtlViewports.viewportCount, vpIdx + 1); } - setContent(Viewports); + setMTLContent(Viewports); } void MVKRenderingCommandEncoderState::setScissors(const MVKArrayRef scissors, @@ -433,17 +402,118 @@ mtlScissors.scissors[firstScissor + sIdx] = mvkMTLScissorRectFromVkRect2D(scissors[sIdx]); mtlScissors.scissorCount = max(mtlScissors.scissorCount, sIdx + 1); } - setContent(Scissors); + setMTLContent(Scissors); } void MVKRenderingCommandEncoderState::setPrimitiveRestartEnable(VkBool32 primitiveRestartEnable, bool isDynamic) { bool mtlPrimitiveRestartEnable = static_cast(primitiveRestartEnable); - setContent(PrimitiveRestartEnable); + setMTLContent(PrimitiveRestartEnable); } void MVKRenderingCommandEncoderState::setRasterizerDiscardEnable(VkBool32 rasterizerDiscardEnable, bool isDynamic) { bool mtlRasterizerDiscardEnable = static_cast(rasterizerDiscardEnable); - setContent(RasterizerDiscardEnable); + setMTLContent(RasterizerDiscardEnable); +} + +// This value is retrieved, not encoded, so don't mark this encoder as dirty. +void MVKRenderingCommandEncoderState::setPrimitiveTopology(VkPrimitiveTopology topology, bool isDynamic) { + getContent(_mtlPrimitiveTopology, isDynamic) = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(topology); +} + +MTLPrimitiveType MVKRenderingCommandEncoderState::getPrimitiveType() { + return getMTLContent(PrimitiveTopology); +} + +bool MVKRenderingCommandEncoderState::isDrawingTriangles() { + switch (getPrimitiveType()) { + case MTLPrimitiveTypeTriangle: return true; + case MTLPrimitiveTypeTriangleStrip: return true; + default: return false; + } +} + +// This value is retrieved, not encoded, so don't mark this encoder as dirty. +void MVKRenderingCommandEncoderState::setPatchControlPoints(uint32_t patchControlPoints, bool isDynamic) { + getContent(_mtlPatchControlPoints, isDynamic) = patchControlPoints; +} + +uint32_t MVKRenderingCommandEncoderState::getPatchControlPoints() { + return getMTLContent(PatchControlPoints); +} + +void MVKRenderingCommandEncoderState::setSampleLocationsEnable(VkBool32 sampleLocationsEnable, bool isDynamic) { + bool slEnbl = static_cast(sampleLocationsEnable); + auto& mtlSampLocEnbl = getContent(_mtlSampleLocationsEnable, isDynamic); + + if (slEnbl == mtlSampLocEnbl) { return; } + + mtlSampLocEnbl = slEnbl; + + // This value is retrieved, not encoded, so don't mark this encoder as dirty. + _dirtyStates.enable(SampleLocationsEnable); +} + +void MVKRenderingCommandEncoderState::setSampleLocations(MVKArrayRef sampleLocations, bool isDynamic) { + auto& mtlSampPosns = getContent(_mtlSampleLocations, isDynamic); + size_t slCnt = sampleLocations.size(); + + // When comparing new vs current, make use of fact that MTLSamplePosition & VkSampleLocationEXT have same memory footprint. + if (slCnt == mtlSampPosns.size() && + mvkAreEqual((MTLSamplePosition*)sampleLocations.data(), + mtlSampPosns.data(), slCnt)) { + return; + } + + mtlSampPosns.clear(); + for (uint32_t slIdx = 0; slIdx < slCnt; slIdx++) { + auto& sl = sampleLocations[slIdx]; + mtlSampPosns.push_back(MTLSamplePositionMake(mvkClamp(sl.x, kMVKMinSampleLocationCoordinate, kMVKMaxSampleLocationCoordinate), + mvkClamp(sl.y, kMVKMinSampleLocationCoordinate, kMVKMaxSampleLocationCoordinate))); + } + + // This value is retrieved, not encoded, so don't mark this encoder as dirty. + _dirtyStates.enable(SampleLocations); +} + +MVKArrayRef MVKRenderingCommandEncoderState::getSamplePositions() { + return getMTLContent(SampleLocationsEnable) ? getMTLContent(SampleLocations).contents() : MVKArrayRef(); +} + +// Return whether state is dirty, and mark it not dirty +bool MVKRenderingCommandEncoderState::isDirty(MVKRenderStateType state) { + bool rslt = _dirtyStates.isEnabled(state); + _dirtyStates.disable(state); + return rslt; +} + +// Don't force sample location & sample location enable to become dirty if they weren't already, because +// this may cause needsMetalRenderPassRestart() to trigger an unnecessary Metal renderpass restart. +void MVKRenderingCommandEncoderState::markDirty() { + MVKCommandEncoderState::markDirty(); + + bool wasSLDirty = _dirtyStates.isEnabled(SampleLocations); + bool wasSLEnblDirty = _dirtyStates.isEnabled(SampleLocationsEnable); + + _dirtyStates.enableAll(); + + _dirtyStates.set(SampleLocations, wasSLDirty); + _dirtyStates.set(SampleLocationsEnable, wasSLEnblDirty); +} + +// Don't call parent beginMetalRenderPass() because it +// will call local markDirty() which is too aggressive. +void MVKRenderingCommandEncoderState::beginMetalRenderPass() { + if (_isModified) { + _dirtyStates = _modifiedStates; + MVKCommandEncoderState::markDirty(); + } +} + +// Don't use || on isDirty calls, to ensure they both get called, so that the dirty flag of each will be cleared. +bool MVKRenderingCommandEncoderState::needsMetalRenderPassRestart() { + bool isSLDirty = isDirty(SampleLocations); + bool isSLEnblDirty = isDirty(SampleLocationsEnable); + return isSLDirty || isSLEnblDirty; } #pragma mark Encoding @@ -453,15 +523,16 @@ auto& rendEnc = _cmdEncoder->_mtlRenderEncoder; - if (isDirty(CullMode)) { [rendEnc setCullMode: getContent(CullMode)]; } - if (isDirty(FrontFace)) { [rendEnc setFrontFacingWinding: getContent(FrontFace)]; } + if (isDirty(PolygonMode)) { [rendEnc setTriangleFillMode: getMTLContent(PolygonMode)]; } + if (isDirty(CullMode)) { [rendEnc setCullMode: getMTLContent(CullMode)]; } + if (isDirty(FrontFace)) { [rendEnc setFrontFacingWinding: getMTLContent(FrontFace)]; } if (isDirty(BlendConstants)) { - auto& bcFlt = getContent(BlendConstants).float32; + auto& bcFlt = getMTLContent(BlendConstants).float32; [rendEnc setBlendColorRed: bcFlt[0] green: bcFlt[1] blue: bcFlt[2] alpha: bcFlt[3]]; } if (isDirty(DepthBiasEnable) || isDirty(DepthBias)) { - if (getContent(DepthBiasEnable)) { - auto& db = getContent(DepthBias); + if (getMTLContent(DepthBiasEnable)) { + auto& db = getMTLContent(DepthBias); [rendEnc setDepthBias: db.depthBiasConstantFactor slopeScale: db.depthBiasSlopeFactor clamp: db.depthBiasClamp]; @@ -470,11 +541,11 @@ } } if (isDirty(DepthClipEnable) && _cmdEncoder->_pDeviceFeatures->depthClamp) { - [rendEnc setDepthClipMode: getContent(DepthClipEnable)]; + [rendEnc setDepthClipMode: getMTLContent(DepthClipEnable)]; } if (isDirty(StencilReference)) { - auto& sr = getContent(StencilReference); + auto& sr = getMTLContent(StencilReference); [rendEnc setStencilFrontReferenceValue: sr.frontFaceValue backReferenceValue: sr.backFaceValue]; } @@ -484,13 +555,13 @@ // to use primitive restart at all, and is just setting this as a "just-in-case", // and forcing an error here would be unexpected to the app (including CTS). auto mtlPrimType = getPrimitiveType(); - if (isDirty(PrimitiveRestartEnable) && !getContent(PrimitiveRestartEnable) && + if (isDirty(PrimitiveRestartEnable) && !getMTLContent(PrimitiveRestartEnable) && (mtlPrimType == MTLPrimitiveTypeTriangleStrip || mtlPrimType == MTLPrimitiveTypeLineStrip)) { reportWarning(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support disabling primitive restart."); } if (isDirty(Viewports)) { - auto& mtlViewports = getContent(Viewports); + auto& mtlViewports = getMTLContent(Viewports); if (_cmdEncoder->_pDeviceFeatures->multiViewport) { #if MVK_MACOS_OR_IOS [rendEnc setViewports: mtlViewports.viewports count: mtlViewports.viewportCount]; @@ -504,7 +575,7 @@ // set to front-and-back, emulate this by using zeroed scissor rectangles. if (isDirty(Scissors)) { static MTLScissorRect zeroRect = {}; - auto mtlScissors = getContent(Scissors); + auto mtlScissors = getMTLContent(Scissors); bool shouldDiscard = ((_mtlRasterizerDiscardEnable[StateScope::Dynamic] && isDynamicState(RasterizerDiscardEnable)) || (isDrawingTriangles() && _cullBothFaces[StateScope::Dynamic] && isDynamicState(CullMode))); for (uint32_t sIdx = 0; sIdx < mtlScissors.scissorCount; sIdx++) { @@ -521,17 +592,8 @@ } } -// Return whether state is dirty, and mark it not dirty -bool MVKRenderingCommandEncoderState::isDirty(MVKRenderStateType state) { - bool rslt = _dirtyStates.isEnabled(state); - _dirtyStates.disable(state); - return rslt; -} - -void MVKRenderingCommandEncoderState::beginMetalRenderPass() { - MVKCommandEncoderState::beginMetalRenderPass(); - _dirtyStates = _modifiedStates; -} +#undef getMTLContent +#undef setMTLContent #pragma mark - diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def index 65683f847..6703a0bad 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def +++ b/MoltenVK/MoltenVK/Commands/MVKCommandTypePools.def @@ -81,6 +81,7 @@ MVK_CMD_TYPE_POOL(EndRenderPass) MVK_CMD_TYPE_POOLS_FROM_3_THRESHOLDS(BeginRendering, 1, 2, 4) MVK_CMD_TYPE_POOL(EndRendering) MVK_CMD_TYPE_POOL(SetSampleLocations) +MVK_CMD_TYPE_POOL(SetSampleLocationsEnable) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(ExecuteCommands, 1) MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindDescriptorSetsStatic, 1, 4) MVK_CMD_TYPE_POOLS_FROM_THRESHOLD(BindDescriptorSetsDynamic, 4) @@ -91,6 +92,7 @@ MVK_CMD_TYPE_POOL(SetDepthBias) MVK_CMD_TYPE_POOL(SetDepthBiasEnable) MVK_CMD_TYPE_POOL(SetDepthTestEnable) MVK_CMD_TYPE_POOL(SetDepthWriteEnable) +MVK_CMD_TYPE_POOL(SetDepthClipEnable) MVK_CMD_TYPE_POOL(SetDepthCompareOp) MVK_CMD_TYPE_POOL(SetStencilTestEnable) MVK_CMD_TYPE_POOL(SetStencilOp) @@ -100,8 +102,9 @@ MVK_CMD_TYPE_POOL(SetStencilReference) MVK_CMD_TYPE_POOL(SetCullMode) MVK_CMD_TYPE_POOL(SetFrontFace) MVK_CMD_TYPE_POOL(SetPrimitiveTopology) -MVK_CMD_TYPE_POOL(SetPatchControlPoints) MVK_CMD_TYPE_POOL(SetPrimitiveRestartEnable) +MVK_CMD_TYPE_POOL(SetPolygonMode) +MVK_CMD_TYPE_POOL(SetPatchControlPoints) MVK_CMD_TYPE_POOL(SetRasterizerDiscardEnable) MVK_CMD_TYPE_POOLS_FROM_2_THRESHOLDS(BindVertexBuffers, 1, 2) MVK_CMD_TYPE_POOL(BindIndexBuffer) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 125bf9aa9..be9c08fb4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -73,16 +73,22 @@ class MVKPrivateDataSlot; /** The buffer index to use for vertex content. */ -const static uint32_t kMVKVertexContentBufferIndex = 0; +static constexpr uint32_t kMVKVertexContentBufferIndex = 0; // Parameters to define the sizing of inline collections -const static uint32_t kMVKQueueFamilyCount = 4; -const static uint32_t kMVKQueueCountPerQueueFamily = 1; // Must be 1. See comments in MVKPhysicalDevice::getQueueFamilies() -const static uint32_t kMVKMinSwapchainImageCount = 2; -const static uint32_t kMVKMaxSwapchainImageCount = 3; -const static uint32_t kMVKMaxColorAttachmentCount = 8; -const static uint32_t kMVKMaxViewportScissorCount = 16; -const static uint32_t kMVKMaxDescriptorSetCount = SPIRV_CROSS_NAMESPACE::kMaxArgumentBuffers; +static constexpr uint32_t kMVKQueueFamilyCount = 4; +static constexpr uint32_t kMVKQueueCountPerQueueFamily = 1; // Must be 1. See comments in MVKPhysicalDevice::getQueueFamilies() +static constexpr uint32_t kMVKMinSwapchainImageCount = 2; +static constexpr uint32_t kMVKMaxSwapchainImageCount = 3; +static constexpr uint32_t kMVKMaxColorAttachmentCount = 8; +static constexpr uint32_t kMVKMaxViewportScissorCount = 16; +static constexpr uint32_t kMVKMaxDescriptorSetCount = SPIRV_CROSS_NAMESPACE::kMaxArgumentBuffers; +static constexpr uint32_t kMVKMaxSampleCount = 8; +static constexpr uint32_t kMVKSampleLocationCoordinateGridSize = 16; +static constexpr float kMVKMinSampleLocationCoordinate = 0.0; +static constexpr float kMVKMaxSampleLocationCoordinate = (float)(kMVKSampleLocationCoordinateGridSize - 1) / (float)kMVKSampleLocationCoordinateGridSize; +static constexpr VkExtent2D kMVKSampleLocationPixelGridSize = { 1, 1 }; +static constexpr VkExtent2D kMVKSampleLocationPixelGridSizeNotSupported = { 0, 0 }; #if !MVK_XCODE_12 typedef NSUInteger MTLTimestamp; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 99ac0ef35..0dd865f23 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -75,9 +75,6 @@ static const uint32_t kAMDRadeonRX6800DeviceId = 0x73bf; static const uint32_t kAMDRadeonRX6700DeviceId = 0x73df; -static const VkExtent2D kMetalSamplePositionGridSize = { 1, 1 }; -static const VkExtent2D kMetalSamplePositionGridSizeNotSupported = { 0, 0 }; - static const uint32_t kMaxTimeDomains = 2; #pragma clang diagnostic pop @@ -399,6 +396,41 @@ extDynState2->extendedDynamicState2PatchControlPoints = true; break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_FEATURES_EXT: { + auto* extDynState3 = (VkPhysicalDeviceExtendedDynamicState3FeaturesEXT*)next; + extDynState3->extendedDynamicState3TessellationDomainOrigin = false; + extDynState3->extendedDynamicState3DepthClampEnable = true; + extDynState3->extendedDynamicState3PolygonMode = true; + extDynState3->extendedDynamicState3RasterizationSamples = false; + extDynState3->extendedDynamicState3SampleMask = false; + extDynState3->extendedDynamicState3AlphaToCoverageEnable = false; + extDynState3->extendedDynamicState3AlphaToOneEnable = false; + extDynState3->extendedDynamicState3LogicOpEnable = false; + extDynState3->extendedDynamicState3ColorBlendEnable = false; + extDynState3->extendedDynamicState3ColorBlendEquation = false; + extDynState3->extendedDynamicState3ColorWriteMask = false; + extDynState3->extendedDynamicState3RasterizationStream = false; + extDynState3->extendedDynamicState3ConservativeRasterizationMode = false; + extDynState3->extendedDynamicState3ExtraPrimitiveOverestimationSize = false; + extDynState3->extendedDynamicState3DepthClipEnable = true; + extDynState3->extendedDynamicState3SampleLocationsEnable = true; + extDynState3->extendedDynamicState3ColorBlendAdvanced = false; + extDynState3->extendedDynamicState3ProvokingVertexMode = false; + extDynState3->extendedDynamicState3LineRasterizationMode = false; + extDynState3->extendedDynamicState3LineStippleEnable = false; + extDynState3->extendedDynamicState3DepthClipNegativeOneToOne = false; + extDynState3->extendedDynamicState3ViewportWScalingEnable = false; + extDynState3->extendedDynamicState3ViewportSwizzle = false; + extDynState3->extendedDynamicState3CoverageToColorEnable = false; + extDynState3->extendedDynamicState3CoverageToColorLocation = false; + extDynState3->extendedDynamicState3CoverageModulationMode = false; + extDynState3->extendedDynamicState3CoverageModulationTableEnable = false; + extDynState3->extendedDynamicState3CoverageModulationTable = false; + extDynState3->extendedDynamicState3CoverageReductionMode = false; + extDynState3->extendedDynamicState3RepresentativeFragmentTestEnable = false; + extDynState3->extendedDynamicState3ShadingRateImageEnable = false; + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT: { auto* interlockFeatures = (VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT*)next; interlockFeatures->fragmentShaderSampleInterlock = _metalFeatures.rasterOrderGroups; @@ -747,11 +779,11 @@ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT: { auto* sampLocnProps = (VkPhysicalDeviceSampleLocationsPropertiesEXT*)next; sampLocnProps->sampleLocationSampleCounts = _metalFeatures.supportedSampleCounts; - sampLocnProps->maxSampleLocationGridSize = kMetalSamplePositionGridSize; - sampLocnProps->sampleLocationCoordinateRange[0] = 0.0; - sampLocnProps->sampleLocationCoordinateRange[1] = (15.0 / 16.0); - sampLocnProps->sampleLocationSubPixelBits = 4; - sampLocnProps->variableSampleLocations = VK_FALSE; + sampLocnProps->maxSampleLocationGridSize = kMVKSampleLocationPixelGridSize; + sampLocnProps->sampleLocationCoordinateRange[0] = kMVKMinSampleLocationCoordinate; + sampLocnProps->sampleLocationCoordinateRange[1] = kMVKMaxSampleLocationCoordinate; + sampLocnProps->sampleLocationSubPixelBits = mvkPowerOfTwoExponent(kMVKSampleLocationCoordinateGridSize); + sampLocnProps->variableSampleLocations = true; break; } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: { @@ -860,8 +892,8 @@ VkMultisamplePropertiesEXT* pMultisampleProperties) { if (pMultisampleProperties) { pMultisampleProperties->maxSampleLocationGridSize = (mvkIsOnlyAnyFlagEnabled(samples, _metalFeatures.supportedSampleCounts) - ? kMetalSamplePositionGridSize - : kMetalSamplePositionGridSizeNotSupported); + ? kMVKSampleLocationPixelGridSize + : kMVKSampleLocationPixelGridSizeNotSupported); } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def index b97928333..d3856e8c3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceFeatureStructs.def @@ -66,6 +66,7 @@ MVK_DEVICE_FEATURE_EXTN(PortabilitySubset, PORTABILITY_SUBSET, MVK_DEVICE_FEATURE_EXTN(4444Formats, 4444_FORMATS, EXT, 2) MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState, EXTENDED_DYNAMIC_STATE, EXT, 1) MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState2, EXTENDED_DYNAMIC_STATE_2, EXT, 3) +MVK_DEVICE_FEATURE_EXTN(ExtendedDynamicState3, EXTENDED_DYNAMIC_STATE_3, EXT, 31) MVK_DEVICE_FEATURE_EXTN(FragmentShaderInterlock, FRAGMENT_SHADER_INTERLOCK, EXT, 3) MVK_DEVICE_FEATURE_EXTN(PipelineCreationCacheControl, PIPELINE_CREATION_CACHE_CONTROL, EXT, 1) MVK_DEVICE_FEATURE_EXTN(Robustness2, ROBUSTNESS_2, EXT, 3) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 45068c19a..ea8152019 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -700,7 +700,27 @@ ADD_DVC_EXT_ENTRY_POINT(vkGetPastPresentationTimingGOOGLE, GOOGLE_DISPLAY_TIMING); ADD_DVC_EXT_ENTRY_POINT(vkCmdSetLogicOpEXT, EXT_EXTENDED_DYNAMIC_STATE_2); ADD_DVC_EXT_ENTRY_POINT(vkCmdSetPatchControlPointsEXT, EXT_EXTENDED_DYNAMIC_STATE_2); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetAlphaToCoverageEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetAlphaToOneEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetColorBlendAdvancedEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetColorBlendEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetColorBlendEquationEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetColorWriteMaskEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetConservativeRasterizationModeEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetDepthClampEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetDepthClipEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetDepthClipNegativeOneToOneEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetExtraPrimitiveOverestimationSizeEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetLineRasterizationModeEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetLineStippleEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); ADD_DVC_EXT_ENTRY_POINT(vkCmdSetLogicOpEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetPolygonModeEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetProvokingVertexModeEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetRasterizationSamplesEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetRasterizationStreamEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetSampleLocationsEnableEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetSampleMaskEXT, EXT_EXTENDED_DYNAMIC_STATE_3); + ADD_DVC_EXT_ENTRY_POINT(vkCmdSetTessellationDomainOriginEXT, EXT_EXTENDED_DYNAMIC_STATE_3); } void MVKInstance::logVersions() { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h index 062b646b5..6827b5b9b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h @@ -132,7 +132,10 @@ class MVKPipeline : public MVKVulkanAPIDeviceObject { /** Returns the debug report object type of this object. */ VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT; } - /** Binds this pipeline to the specified command encoder. */ + /** Called when the pipeline has been bound to the command encoder. */ + virtual void wasBound(MVKCommandEncoder* cmdEncoder) {} + + /** Encodes this pipeline to the command encoder. */ virtual void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) = 0; /** Binds the push constants to a command encoder. */ @@ -241,6 +244,7 @@ enum MVKRenderStateType { PrimitiveTopology, RasterizerDiscardEnable, SampleLocations, + SampleLocationsEnable, Scissors, StencilCompareMask, StencilOp, @@ -249,17 +253,22 @@ enum MVKRenderStateType { StencilWriteMask, VertexStride, Viewports, + MVKRenderStateTypeCount }; /** Boolean tracking of rendering state. */ struct MVKRenderStateFlags { void enable(MVKRenderStateType rs) { if (rs) { mvkEnableFlags(_stateFlags, getFlagMask(rs)); } } void disable(MVKRenderStateType rs) { if (rs) { mvkDisableFlags(_stateFlags, getFlagMask(rs)); } } + void set(MVKRenderStateType rs, bool val) { val? enable(rs) : disable(rs); } + void enableAll() { mvkEnableAllFlags(_stateFlags); } + void disableAll() { mvkDisableAllFlags(_stateFlags); } bool isEnabled(MVKRenderStateType rs) { return mvkIsAnyFlagEnabled(_stateFlags, getFlagMask(rs)); } protected: uint32_t getFlagMask(MVKRenderStateType rs) { return rs ? (1u << (rs - 1u)) : 0; } // Ignore Unknown type uint32_t _stateFlags = 0; + static_assert(sizeof(_stateFlags) * 8 >= MVKRenderStateTypeCount - 1, "_stateFlags is too small to support the number of flags in MVKRenderStateType."); // Ignore Unknown type }; /** Represents an Vulkan graphics pipeline. */ @@ -270,7 +279,8 @@ class MVKGraphicsPipeline : public MVKPipeline { /** Returns the number and order of stages in this pipeline. Draws commands must encode this pipeline once per stage. */ void getStages(MVKPiplineStages& stages); - /** Binds this pipeline to the specified command encoder. */ + virtual void wasBound(MVKCommandEncoder* cmdEncoder) override; + void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) override; /** Returns whether this pipeline permits dynamic setting of the state. */ @@ -312,9 +322,6 @@ class MVKGraphicsPipeline : public MVKPipeline { /** Returns true if the tessellation control shader needs a buffer to store its per-patch output. */ bool needsTessCtlPatchOutputBuffer() { return _needsTessCtlPatchOutputBuffer; } - /** Returns whether this pipeline has custom sample positions enabled. */ - bool isUsingCustomSamplePositions() { return _isUsingCustomSamplePositions; } - /** Returns the Vulkan primitive topology. */ VkPrimitiveTopology getVkPrimitiveTopology() { return _vkPrimitiveTopology; } @@ -327,9 +334,6 @@ class MVKGraphicsPipeline : public MVKPipeline { */ bool isValidVertexBufferIndex(MVKShaderStage stage, uint32_t mtlBufferIndex); - /** Returns the custom samples used by this pipeline. */ - MVKArrayRef getCustomSamplePositions() { return _customSamplePositions.contents(); } - /** Returns the Metal vertex buffer index to use for the specified vertex attribute binding number. */ uint32_t getMetalBufferIndexForVertexAttributeBinding(uint32_t binding) { return _device->getMetalBufferIndexForVertexAttributeBinding(binding); } @@ -354,8 +358,6 @@ class MVKGraphicsPipeline : public MVKPipeline { ~MVKGraphicsPipeline() override; protected: - friend class MVKGraphicsPipelineCommandEncoderState; - typedef MVKSmallVector SPIRVShaderOutputs; typedef MVKSmallVector SPIRVShaderInputs; @@ -364,7 +366,7 @@ class MVKGraphicsPipeline : public MVKPipeline { bool compileTessVertexStageState(MTLComputePipelineDescriptor* vtxPLDesc, MVKMTLFunction* pVtxFunctions, VkPipelineCreationFeedback* pVertexFB); bool compileTessControlStageState(MTLComputePipelineDescriptor* tcPLDesc, VkPipelineCreationFeedback* pTessCtlFB); void initDynamicState(const VkGraphicsPipelineCreateInfo* pCreateInfo); - void initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo); + void initSampleLocations(const VkGraphicsPipelineCreateInfo* pCreateInfo); void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, VkPipelineCreationFeedback* pPipelineFB, const VkPipelineShaderStageCreateInfo* pVertexSS, VkPipelineCreationFeedback* pVertexFB, const VkPipelineShaderStageCreateInfo* pTessCtlSS, VkPipelineCreationFeedback* pTessCtlFB, const VkPipelineShaderStageCreateInfo* pTessEvalSS, VkPipelineCreationFeedback* pTessEvalFB, const VkPipelineShaderStageCreateInfo* pFragmentSS, VkPipelineCreationFeedback* pFragmentFB); void initShaderConversionConfig(SPIRVToMSLConversionConfiguration& shaderConfig, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData); void initReservedVertexAttributeBufferCount(const VkGraphicsPipelineCreateInfo* pCreateInfo); @@ -404,7 +406,7 @@ class MVKGraphicsPipeline : public MVKPipeline { MVKSmallVector _viewports; MVKSmallVector _scissors; - MVKSmallVector _customSamplePositions; + MVKSmallVector _sampleLocations; MVKSmallVector _translatedVertexBindings; MVKSmallVector _zeroDivisorVertexBindings; MVKSmallVector _mtlArgumentEncoders; @@ -449,7 +451,7 @@ class MVKGraphicsPipeline : public MVKPipeline { bool _needsFragmentViewRangeBuffer = false; bool _isRasterizing = false; bool _isRasterizingColor = false; - bool _isUsingCustomSamplePositions = false; + bool _sampleLocationsEnable = false; }; @@ -461,7 +463,6 @@ class MVKComputePipeline : public MVKPipeline { public: - /** Binds this pipeline to the specified command encoder. */ void encode(MVKCommandEncoder* cmdEncoder, uint32_t = 0) override; /** Returns if this pipeline allows non-zero dispatch bases in vkCmdDispatchBase(). */ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 7cb4a3cea..0b2663400 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -229,6 +229,13 @@ #pragma mark - #pragma mark MVKGraphicsPipeline +// Set retrieve-only rendering state when pipeline is bound, as it's too late at draw command. +void MVKGraphicsPipeline::wasBound(MVKCommandEncoder* cmdEncoder) { + cmdEncoder->_renderingState.setPatchControlPoints(_tessInfo.patchControlPoints, false); + cmdEncoder->_renderingState.setSampleLocations(_sampleLocations.contents(), false); + cmdEncoder->_renderingState.setSampleLocationsEnable(_sampleLocationsEnable, false); +} + void MVKGraphicsPipeline::getStages(MVKPiplineStages& stages) { if (isTessellationPipeline()) { stages.push_back(kMVKGraphicsStageVertex); @@ -514,7 +521,7 @@ _hasRasterInfo = mvkSetOrClear(&_rasterInfo, pCreateInfo->pRasterizationState); // Must run after _isRasterizing and _dynamicState are populated - initCustomSamplePositions(pCreateInfo); + initSampleLocations(pCreateInfo); // Depth stencil content - clearing will disable depth and stencil testing // Must ignore allowed bad pDepthStencilState pointer if rasterization disabled or no depth or stencil attachment format @@ -563,6 +570,8 @@ static MVKRenderStateType getRenderStateType(VkDynamicState vkDynamicState) { case VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE: return PrimitiveRestartEnable; case VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY: return PrimitiveTopology; case VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE: return RasterizerDiscardEnable; + case VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT: return SampleLocations; + case VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT: return SampleLocationsEnable; case VK_DYNAMIC_STATE_SCISSOR: return Scissors; case VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT: return Scissors; case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK: return StencilCompareMask; @@ -626,7 +635,7 @@ static MVKRenderStateType getRenderStateType(VkDynamicState vkDynamicState) { } // Must run after _isRasterizing and _dynamicState are populated -void MVKGraphicsPipeline::initCustomSamplePositions(const VkGraphicsPipelineCreateInfo* pCreateInfo) { +void MVKGraphicsPipeline::initSampleLocations(const VkGraphicsPipelineCreateInfo* pCreateInfo) { // Must ignore allowed bad pMultisampleState pointer if rasterization disabled if ( !(_isRasterizing && pCreateInfo->pMultisampleState) ) { return; } @@ -635,12 +644,9 @@ static MVKRenderStateType getRenderStateType(VkDynamicState vkDynamicState) { switch (next->sType) { case VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT: { auto* pSampLocnsCreateInfo = (VkPipelineSampleLocationsStateCreateInfoEXT*)next; - _isUsingCustomSamplePositions = pSampLocnsCreateInfo->sampleLocationsEnable; - if (_isUsingCustomSamplePositions && !isDynamicState(SampleLocations)) { - for (uint32_t slIdx = 0; slIdx < pSampLocnsCreateInfo->sampleLocationsInfo.sampleLocationsCount; slIdx++) { - auto& sl = pSampLocnsCreateInfo->sampleLocationsInfo.pSampleLocations[slIdx]; - _customSamplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y)); - } + _sampleLocationsEnable = pSampLocnsCreateInfo->sampleLocationsEnable; + for (uint32_t slIdx = 0; slIdx < pSampLocnsCreateInfo->sampleLocationsInfo.sampleLocationsCount; slIdx++) { + _sampleLocations.push_back(pSampLocnsCreateInfo->sampleLocationsInfo.pSampleLocations[slIdx]); } break; } @@ -1635,7 +1641,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 // Multisampling - must ignore allowed bad pMultisampleState pointer if rasterization disabled if (_isRasterizing && pCreateInfo->pMultisampleState) { - plDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(pCreateInfo->pMultisampleState->rasterizationSamples); + plDesc.rasterSampleCount = mvkSampleCountFromVkSampleCountFlagBits(pCreateInfo->pMultisampleState->rasterizationSamples); plDesc.alphaToCoverageEnabled = pCreateInfo->pMultisampleState->alphaToCoverageEnable; plDesc.alphaToOneEnabled = pCreateInfo->pMultisampleState->alphaToOneEnable; @@ -1926,10 +1932,14 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 } } -// We render points if either the topology or polygon fill mode dictate it +// We render points if either the static topology or static polygon fill mode dictate it bool MVKGraphicsPipeline::isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo) { - return ((pCreateInfo->pInputAssemblyState && (pCreateInfo->pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)) || - (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->polygonMode == VK_POLYGON_MODE_POINT))); + return ((pCreateInfo->pInputAssemblyState && + (pCreateInfo->pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST) && + !isDynamicState(PrimitiveTopology)) || + (pCreateInfo->pRasterizationState && + (pCreateInfo->pRasterizationState->polygonMode == VK_POLYGON_MODE_POINT) && + !isDynamicState(PolygonMode))); } // We disable rasterization if either static rasterizerDiscard is enabled or the static cull mode dictates it. diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index f63ecf983..d8c222bdd 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -105,6 +105,7 @@ MVK_EXTENSION(EXT_debug_utils, EXT_DEBUG_UTILS, MVK_EXTENSION(EXT_descriptor_indexing, EXT_DESCRIPTOR_INDEXING, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_extended_dynamic_state, EXT_EXTENDED_DYNAMIC_STATE, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_extended_dynamic_state2, EXT_EXTENDED_DYNAMIC_STATE_2, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_extended_dynamic_state3, EXT_EXTENDED_DYNAMIC_STATE_3, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0, 1.0) MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA, MVK_NA) diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.cpp b/MoltenVK/MoltenVK/Utility/MVKFoundation.cpp index 85ad7d5b5..d00fb3971 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.cpp +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.cpp @@ -33,7 +33,7 @@ const char* mvkVkCommandName(MVKCommandUse cmdUse) { case kMVKCommandUseBeginRendering: return "vkCmdBeginRendering"; case kMVKCommandUseBeginRenderPass: return "vkCmdBeginRenderPass"; case kMVKCommandUseNextSubpass: return "vkCmdNextSubpass"; - case kMVKCommandUseRestartSubpass: return "Metal renderpass restart on barrier"; + case kMVKCommandUseRestartSubpass: return "Metal renderpass restart"; case kMVKCommandUsePipelineBarrier: return "vkCmdPipelineBarrier"; case kMVKCommandUseBlitImage: return "vkCmdBlitImage"; case kMVKCommandUseCopyImage: return "vkCmdCopyImage"; diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index f5820721a..d3aa660a0 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -76,7 +76,7 @@ typedef enum : uint8_t { kMVKCommandUseBeginRendering, /**< vkCmdBeginRendering. */ kMVKCommandUseBeginRenderPass, /**< vkCmdBeginRenderPass. */ kMVKCommandUseNextSubpass, /**< vkCmdNextSubpass. */ - kMVKCommandUseRestartSubpass, /**< Restart a subpass because of explicit or implicit barrier. */ + kMVKCommandUseRestartSubpass, /**< Create a new Metal renderpass due to Metal requirements. */ kMVKCommandUsePipelineBarrier, /**< vkCmdPipelineBarrier. */ kMVKCommandUseBlitImage, /**< vkCmdBlitImage. */ kMVKCommandUseCopyImage, /**< vkCmdCopyImage. */ @@ -102,8 +102,8 @@ typedef enum : uint8_t { /** Represents a given stage of a graphics pipeline. */ enum MVKGraphicsStage { - kMVKGraphicsStageVertex = 0, /**< The vertex shader stage. */ - kMVKGraphicsStageTessControl, /**< The tessellation control shader stage. */ + kMVKGraphicsStageVertex = 0, /**< The tessellation vertex compute shader stage. */ + kMVKGraphicsStageTessControl, /**< The tessellation control compute shader stage. */ kMVKGraphicsStageRasterization /**< The rest of the pipeline. */ }; diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index d1c6fbbee..c08c5b3a5 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -3652,6 +3652,120 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPatchControlPointsEXT( #pragma mark - #pragma mark VK_EXT_extended_dynamic_state3 +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetAlphaToCoverageEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 alphaToCoverageEnable) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetAlphaToOneEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 alphaToOneEnable) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetColorBlendAdvancedEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorBlendAdvancedEXT* pColorBlendAdvanced) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetColorBlendEnableEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkBool32* pColorBlendEnables) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetColorBlendEquationEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorBlendEquationEXT* pColorBlendEquations) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetColorWriteMaskEXT( + VkCommandBuffer commandBuffer, + uint32_t firstAttachment, + uint32_t attachmentCount, + const VkColorComponentFlags* pColorWriteMasks) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetConservativeRasterizationModeEXT( + VkCommandBuffer commandBuffer, + VkConservativeRasterizationModeEXT conservativeRasterizationMode) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthClampEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthClampEnable) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetDepthClipEnable, commandBuffer, !depthClampEnable); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthClipEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 depthClipEnable) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetDepthClipEnable, commandBuffer, depthClipEnable); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetDepthClipNegativeOneToOneEXT( + VkCommandBuffer commandBuffer, + VkBool32 negativeOneToOne) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetExtraPrimitiveOverestimationSizeEXT( + VkCommandBuffer commandBuffer, + float extraPrimitiveOverestimationSize) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLineRasterizationModeEXT( + VkCommandBuffer commandBuffer, + VkLineRasterizationModeEXT lineRasterizationMode) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLineStippleEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 stippledLineEnable) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLogicOpEnableEXT( VkCommandBuffer commandBuffer, VkBool32 logicOpEnable) { @@ -3660,6 +3774,65 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetLogicOpEnableEXT( MVKTraceVulkanCallEnd(); } +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetPolygonModeEXT( + VkCommandBuffer commandBuffer, + VkPolygonMode polygonMode) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetPolygonMode, commandBuffer, polygonMode); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetProvokingVertexModeEXT( + VkCommandBuffer commandBuffer, + VkProvokingVertexModeEXT provokingVertexMode) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetRasterizationSamplesEXT( + VkCommandBuffer commandBuffer, + VkSampleCountFlagBits rasterizationSamples) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetRasterizationStreamEXT( + VkCommandBuffer commandBuffer, + uint32_t rasterizationStream) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetSampleLocationsEnableEXT( + VkCommandBuffer commandBuffer, + VkBool32 sampleLocationsEnable) { + + MVKTraceVulkanCallStart(); + MVKAddCmd(SetSampleLocationsEnable, commandBuffer, sampleLocationsEnable); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetSampleMaskEXT( + VkCommandBuffer commandBuffer, + VkSampleCountFlagBits samples, + const VkSampleMask* pSampleMask) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + +MVK_PUBLIC_VULKAN_SYMBOL void vkCmdSetTessellationDomainOriginEXT( + VkCommandBuffer commandBuffer, + VkTessellationDomainOrigin domainOrigin) { + + MVKTraceVulkanCallStart(); + MVKTraceVulkanCallEnd(); +} + #pragma mark - #pragma mark VK_EXT_external_memory_host extension