diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision index 206e577d..480b2b8d 100644 --- a/ExternalRevisions/SPIRV-Cross_repo_revision +++ b/ExternalRevisions/SPIRV-Cross_repo_revision @@ -1 +1 @@ -ac5a9570a744eb72725c23c34f36fbc564c0bb51 +942273dc7b107d4f0c2cf3449ae306525e1cbae7 diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h index d9be7761..f31c465d 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h @@ -70,7 +70,7 @@ protected: #pragma mark MVKCmdDraw /** Vulkan command to draw vertices. */ -class MVKCmdDraw : public MVKCommand { +class MVKCmdDraw : public MVKCommand, public MVKLoadStoreOverride { public: void setContent(uint32_t vertexCount, @@ -94,7 +94,7 @@ protected: #pragma mark MVKCmdDrawIndexed /** Vulkan command to draw indexed vertices. */ -class MVKCmdDrawIndexed : public MVKCommand { +class MVKCmdDrawIndexed : public MVKCommand, public MVKLoadStoreOverride { public: void setContent(uint32_t indexCount, @@ -120,7 +120,7 @@ protected: #pragma mark MVKCmdDrawIndirect /** Vulkan command to draw vertices indirectly. */ -class MVKCmdDrawIndirect : public MVKCommand { +class MVKCmdDrawIndirect : public MVKCommand, public MVKLoadStoreOverride { public: void setContent(VkBuffer buffer, @@ -144,7 +144,7 @@ protected: #pragma mark MVKCmdDrawIndexedIndirect /** Vulkan command to draw indexed vertices indirectly. */ -class MVKCmdDrawIndexedIndirect : public MVKCommand { +class MVKCmdDrawIndexedIndirect : public MVKCommand, public MVKLoadStoreOverride { public: void setContent(VkBuffer buffer, diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm index 83e5e004..f1404b1c 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm @@ -84,6 +84,8 @@ void MVKCmdDraw::setContent(uint32_t vertexCount, _instanceCount = instanceCount; _firstVertex = firstVertex; _firstInstance = firstInstance; + _loadOverride = false; + _storeOverride = false; // Validate clearConfigurationResult(); @@ -113,6 +115,8 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { } for (uint32_t s : stages) { auto stage = MVKGraphicsStage(s); + if (stage == kMVKGraphicsStageVertex) + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal id mtlTessCtlEncoder = nil; @@ -148,6 +152,7 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { // so I apply them during the next stage. cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); break; case kMVKGraphicsStageTessControl: @@ -198,7 +203,7 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) { threadsPerThreadgroup: MTLSizeMake(std::max(inControlPointCount, outControlPointCount), 1, 1)]; // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(true); + cmdEncoder->beginMetalRenderPass(_loadOverride, _storeOverride); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) { @@ -267,6 +272,8 @@ void MVKCmdDrawIndexed::setContent(uint32_t indexCount, _firstIndex = firstIndex; _vertexOffset = vertexOffset; _firstInstance = firstInstance; + _loadOverride = false; + _storeOverride = false; // Validate clearConfigurationResult(); @@ -339,6 +346,8 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { atIndex: 4]; [mtlTessCtlEncoder dispatchThreadgroups: MTLSizeMake(1, 1, 1) threadsPerThreadgroup: MTLSizeMake(1, 1, 1)]; } + if (stage == kMVKGraphicsStageVertex) + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal switch (stage) { @@ -376,6 +385,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { // so I apply them during the next stage. cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); break; case kMVKGraphicsStageTessControl: @@ -419,7 +429,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) { threadsPerThreadgroup: MTLSizeMake(std::max(inControlPointCount, outControlPointCount), 1, 1)]; // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(true); + cmdEncoder->beginMetalRenderPass(_loadOverride, _storeOverride); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) { @@ -493,6 +503,8 @@ void MVKCmdDrawIndirect::setContent(VkBuffer buffer, _mtlIndirectBufferOffset = mvkBuffer->getMTLBufferOffset() + offset; _mtlIndirectBufferStride = stride; _drawCount = drawCount; + _loadOverride = false; + _storeOverride = false; // Validate clearConfigurationResult(); @@ -604,6 +616,8 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)]; } + if (stage == kMVKGraphicsStageVertex) + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal switch (stage) { @@ -624,6 +638,7 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { // so I apply them during the next stage. cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); break; case kMVKGraphicsStageTessControl: @@ -650,8 +665,10 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { offset: vtxOutBuff->_offset atIndex: kMVKTessCtlInputBufferIndex]; if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) { - [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer - indirectBufferOffset: mtlTCIndBuffOfst]; + // setStageInRegionWithIndirectBuffer appears to be broken. We have a 1D linear region anyway, so size is irrelevant + //[mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer + // indirectBufferOffset: mtlTCIndBuffOfst]; + [mtlTessCtlEncoder setStageInRegion: MTLRegionMake1D(0, std::max(inControlPointCount, outControlPointCount) * patchCount)]; mtlTCIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments); } else { // We must assume we can read up to the maximum number of vertices. @@ -669,7 +686,7 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments); // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(true); + cmdEncoder->beginMetalRenderPass(_loadOverride, _storeOverride); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) { @@ -728,6 +745,8 @@ void MVKCmdDrawIndexedIndirect::setContent(VkBuffer buffer, _mtlIndirectBufferOffset = mvkBuffer->getMTLBufferOffset() + offset; _mtlIndirectBufferStride = stride; _drawCount = drawCount; + _loadOverride = false; + _storeOverride = false; // Validate clearConfigurationResult(); @@ -849,6 +868,8 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) { [mtlTessCtlEncoder dispatchThreadgroups: MTLSizeMake(1, 1, 1) threadsPerThreadgroup: MTLSizeMake(1, 1, 1)]; } + if (stage == kMVKGraphicsStageVertex) + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal switch (stage) { @@ -872,6 +893,7 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) { // so I apply them during the next stage. cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); + cmdEncoder->_depthStencilState.markDirty(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); break; case kMVKGraphicsStageTessControl: @@ -898,8 +920,10 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) { offset: vtxOutBuff->_offset atIndex: kMVKTessCtlInputBufferIndex]; if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) { - [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer - indirectBufferOffset: mtlTCIndBuffOfst]; + // setStageInRegionWithIndirectBuffer appears to be broken. We have a 1D linear region anyway, so size is irrelevant + //[mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer + // indirectBufferOffset: mtlTCIndBuffOfst]; + [mtlTessCtlEncoder setStageInRegion: MTLRegionMake1D(0, std::max(inControlPointCount, outControlPointCount) * patchCount)]; mtlTCIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments); } else { // We must assume we can read up to the maximum number of vertices. @@ -915,7 +939,7 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) { mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments); // Running this stage prematurely ended the render pass, so we have to start it up again. // TODO: On iOS, maybe we could use a tile shader to avoid this. - cmdEncoder->beginMetalRenderPass(true); + cmdEncoder->beginMetalRenderPass(_loadOverride, _storeOverride); break; case kMVKGraphicsStageRasterization: if (pipeline->isTessellationPipeline()) { @@ -985,6 +1009,7 @@ void mvkCmdDraw(MVKCommandBuffer* cmdBuff, uint32_t firstInstance) { MVKCmdDraw* cmd = cmdBuff->_commandPool->_cmdDrawPool.acquireObject(); cmd->setContent(vertexCount, instanceCount, firstVertex, firstInstance); + cmdBuff->recordDraw(cmd); cmdBuff->addCommand(cmd); } @@ -996,6 +1021,7 @@ void mvkCmdDrawIndexed(MVKCommandBuffer* cmdBuff, uint32_t firstInstance) { MVKCmdDrawIndexed* cmd = cmdBuff->_commandPool->_cmdDrawIndexedPool.acquireObject(); cmd->setContent(indexCount, instanceCount, firstIndex, vertexOffset, firstInstance); + cmdBuff->recordDraw(cmd); cmdBuff->addCommand(cmd); } @@ -1015,6 +1041,7 @@ void mvkCmdDrawIndirect(MVKCommandBuffer* cmdBuff, uint32_t stride) { MVKCmdDrawIndirect* cmd = cmdBuff->_commandPool->_cmdDrawIndirectPool.acquireObject(); cmd->setContent(buffer, offset, drawCount, stride); + cmdBuff->recordDraw(cmd); cmdBuff->addCommand(cmd); } @@ -1025,6 +1052,7 @@ void mvkCmdDrawIndexedIndirect(MVKCommandBuffer* cmdBuff, uint32_t stride) { MVKCmdDrawIndexedIndirect* cmd = cmdBuff->_commandPool->_cmdDrawIndexedIndirectPool.acquireObject(); cmd->setContent(buffer, offset, drawCount, stride); + cmdBuff->recordDraw(cmd); cmdBuff->addCommand(cmd); } diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h index 2044f66c..d5bf3dd7 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h @@ -73,6 +73,8 @@ public: MVKCmdBindPipeline(MVKCommandTypePool* pool); + bool isTessellationPipeline(); + private: VkPipelineBindPoint _bindPoint; MVKPipeline* _pipeline; diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm index bdd47ef5..afe05efc 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm @@ -109,6 +109,13 @@ void MVKCmdBindPipeline::encode(MVKCommandEncoder* cmdEncoder) { MVKCmdBindPipeline::MVKCmdBindPipeline(MVKCommandTypePool* pool) : MVKCommand::MVKCommand((MVKCommandTypePool*)pool) {} +bool MVKCmdBindPipeline::isTessellationPipeline() { + if (_bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS) + return ((MVKGraphicsPipeline*)_pipeline)->isTessellationPipeline(); + else + return false; +} + #pragma mark - #pragma mark MVKCmdBindDescriptorSets @@ -327,6 +334,7 @@ void mvkCmdBindPipeline(MVKCommandBuffer* cmdBuff, VkPipeline pipeline) { MVKCmdBindPipeline* cmd = cmdBuff->_commandPool->_cmdBindPipelinePool.acquireObject(); cmd->setContent(pipelineBindPoint, pipeline); + cmdBuff->recordBindPipeline(cmd); cmdBuff->addCommand(cmd); } diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h index 8a28da3b..4f9b3c9e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h @@ -33,7 +33,7 @@ class MVKFramebuffer; #pragma mark MVKCmdBeginRenderPass /** Vulkan command to begin a render pass. */ -class MVKCmdBeginRenderPass : public MVKCommand { +class MVKCmdBeginRenderPass : public MVKCommand, public MVKLoadStoreOverride { public: void setContent(const VkRenderPassBeginInfo* pRenderPassBegin, diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm index 2b798977..6911aa2e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm @@ -34,6 +34,8 @@ void MVKCmdBeginRenderPass::setContent(const VkRenderPassBeginInfo* pRenderPassB _contents = contents; _renderPass = (MVKRenderPass*)_info.renderPass; _framebuffer = (MVKFramebuffer*)_info.framebuffer; + _loadOverride = false; + _storeOverride = false; // Add clear values _clearValues.clear(); // Clear for reuse @@ -45,7 +47,7 @@ void MVKCmdBeginRenderPass::setContent(const VkRenderPassBeginInfo* pRenderPassB void MVKCmdBeginRenderPass::encode(MVKCommandEncoder* cmdEncoder) { // MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds()); - cmdEncoder->beginRenderpass(_contents, _renderPass, _framebuffer, _info.renderArea, &_clearValues); + cmdEncoder->beginRenderpass(_contents, _renderPass, _framebuffer, _info.renderArea, &_clearValues, _loadOverride, _storeOverride); } MVKCmdBeginRenderPass::MVKCmdBeginRenderPass(MVKCommandTypePool* pool) @@ -277,6 +279,7 @@ void mvkCmdBeginRenderPass(MVKCommandBuffer* cmdBuff, VkSubpassContents contents) { MVKCmdBeginRenderPass* cmd = cmdBuff->_commandPool->_cmdBeginRenderPassPool.acquireObject(); cmd->setContent(pRenderPassBegin, contents); + cmdBuff->recordBeginRenderPass(cmd); cmdBuff->addCommand(cmd); } @@ -288,6 +291,7 @@ void mvkCmdNextSubpass(MVKCommandBuffer* cmdBuff, VkSubpassContents contents) { void mvkCmdEndRenderPass(MVKCommandBuffer* cmdBuff) { MVKCmdEndRenderPass* cmd = cmdBuff->_commandPool->_cmdEndRenderPassPool.acquireObject(); + cmdBuff->recordEndRenderPass(cmd); cmdBuff->addCommand(cmd); } diff --git a/MoltenVK/MoltenVK/Commands/MVKCommand.h b/MoltenVK/MoltenVK/Commands/MVKCommand.h index 3f3c4983..0bb2ff0f 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommand.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommand.h @@ -112,3 +112,19 @@ protected: MVKCommandPool* _commandPool; }; + +#pragma mark - +#pragma mark MVKLoadStoreOverride + +/** Shared state with all draw commands */ +class MVKLoadStoreOverride { +public: + void setLoadOverride(bool loadOverride); + void setStoreOverride(bool storeOverride); + +protected: + bool _loadOverride; + bool _storeOverride; +}; + + diff --git a/MoltenVK/MoltenVK/Commands/MVKCommand.mm b/MoltenVK/MoltenVK/Commands/MVKCommand.mm index e9c564cc..ee433718 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommand.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommand.mm @@ -37,3 +37,16 @@ MVKDevice* MVKCommand::getDevice() { return getCommandPool()->getDevice(); } id MVKCommand::getMTLDevice() { return getCommandPool()->getMTLDevice(); } + +#pragma mark - +#pragma mark MVKLoadStoreOverride + +void MVKLoadStoreOverride::setLoadOverride(bool loadOverride) { + _loadOverride = loadOverride; +} + +void MVKLoadStoreOverride::setStoreOverride(bool storeOverride) { + _storeOverride = storeOverride; +} + + diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h index 09e28544..61a4aad6 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h @@ -39,6 +39,9 @@ class MVKQueryPool; class MVKPipeline; class MVKGraphicsPipeline; class MVKComputePipeline; +class MVKCmdBeginRenderPass; +class MVKCmdEndRenderPass; +class MVKLoadStoreOverride; typedef uint64_t MVKMTLCommandBufferID; @@ -98,6 +101,29 @@ public: MVKCommandBuffer* _next; +#pragma mark Constituent render pass management + /** Preps metadata for recording render pass */ + void recordBeginRenderPass(MVKCmdBeginRenderPass* mvkBeginRenderPass); + + /** Finishes metadata for recording render pass */ + void recordEndRenderPass(MVKCmdEndRenderPass* mvkEndRenderPass); + + /** Update the last recorded pipeline if it will end and start a new Metal render pass (ie, in tessellation) */ + void recordBindPipeline(MVKCmdBindPipeline* mvkBindPipeline); + + /** Update the last recorded drawcall to determine load/store actions */ + void recordDraw(MVKLoadStoreOverride* mvkDraw); + + /** The most recent recorded begin renderpass */ + MVKCmdBeginRenderPass* _lastBeginRenderPass; + + /** The most recent recorded multi-pass (ie, tessellation) pipeline */ + MVKCmdBindPipeline* _lastTessellationPipeline; + + /** The most recent recorded multi-pass (ie, tessellation) draw */ + MVKLoadStoreOverride* _lastTessellationDraw; + + #pragma mark Construction MVKCommandBuffer(MVKDevice* device) : MVKDispatchableDeviceObject(device) {} @@ -240,13 +266,15 @@ public: MVKRenderPass* renderPass, MVKFramebuffer* framebuffer, VkRect2D& renderArea, - MVKVector* clearValues); + MVKVector* clearValues, + bool loadOverride = false, + bool storeOverride = false); /** Begins the next render subpass. */ void beginNextSubpass(VkSubpassContents renderpassContents); /** Begins a Metal render pass for the current render subpass. */ - void beginMetalRenderPass(bool loadOverride = false); + void beginMetalRenderPass(bool loadOverride = false, bool storeOverride = false); /** Returns the render subpass that is currently active. */ MVKRenderSubpass* getSubpass(); @@ -327,7 +355,6 @@ public: /** Marks a timestamp for the specified query. */ void markTimestamp(MVKQueryPool* pQueryPool, uint32_t query); - #pragma mark Dynamic encoding state accessed directly /** A reference to the Metal features supported by the device. */ @@ -398,7 +425,7 @@ public: protected: void addActivatedQuery(MVKQueryPool* pQueryPool, uint32_t query); void finishQueries(); - void setSubpass(VkSubpassContents subpassContents, uint32_t subpassIndex); + void setSubpass(VkSubpassContents subpassContents, uint32_t subpassIndex, bool loadOverride = false, bool storeOverride = false); void clearRenderArea(); const MVKMTLBufferAllocation* copyToTempMTLBufferAllocation(const void* bytes, NSUInteger length); NSString* getMTLRenderCommandEncoderName(); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 4aabdd2f..3e6da6b2 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -25,6 +25,7 @@ #include "MVKQueryPool.h" #include "MVKFoundation.h" #include "MTLRenderPassDescriptor+MoltenVK.h" +#include "MVKCmdDraw.h" using namespace std; @@ -188,6 +189,44 @@ MVKCommandBuffer::~MVKCommandBuffer() { } +#pragma mark - +#pragma mark Constituent render pass management + +void MVKCommandBuffer::recordBeginRenderPass(MVKCmdBeginRenderPass* mvkBeginRenderPass) { + _lastBeginRenderPass = mvkBeginRenderPass; + _lastTessellationPipeline = nullptr; + _lastTessellationDraw = nullptr; +} + +void MVKCommandBuffer::recordEndRenderPass(MVKCmdEndRenderPass* /*mvkEndRenderPass*/) { + // Unset the store override for the last draw call + if (_lastTessellationDraw != nullptr) + { + _lastTessellationDraw->setStoreOverride(false); + _lastBeginRenderPass->setStoreOverride(true); + } + _lastBeginRenderPass = nullptr; + _lastTessellationPipeline = nullptr; + _lastTessellationDraw = nullptr; +} + +void MVKCommandBuffer::recordBindPipeline(MVKCmdBindPipeline* mvkBindPipeline) { + if (mvkBindPipeline->isTessellationPipeline()) + _lastTessellationPipeline = mvkBindPipeline; + else + _lastTessellationPipeline = nullptr; +} + +void MVKCommandBuffer::recordDraw(MVKLoadStoreOverride* mvkDraw) { + if (_lastTessellationPipeline != nullptr) { + // If a multi-pass pipeline is bound and we've already drawn something, need to override load actions + mvkDraw->setLoadOverride(true); + mvkDraw->setStoreOverride(true); + _lastTessellationDraw = mvkDraw; + } +} + + #pragma mark - #pragma mark MVKCommandEncoder @@ -219,14 +258,16 @@ void MVKCommandEncoder::beginRenderpass(VkSubpassContents subpassContents, MVKRenderPass* renderPass, MVKFramebuffer* framebuffer, VkRect2D& renderArea, - MVKVector* clearValues) { + MVKVector* clearValues, + bool loadOverride, + bool storeOverride) { _renderPass = renderPass; _framebuffer = framebuffer; _renderArea = renderArea; _isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) && mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D())); _clearValues.assign(clearValues->begin(), clearValues->end()); - setSubpass(subpassContents, 0); + setSubpass(subpassContents, 0, loadOverride, storeOverride); } void MVKCommandEncoder::beginNextSubpass(VkSubpassContents contents) { @@ -234,20 +275,20 @@ void MVKCommandEncoder::beginNextSubpass(VkSubpassContents contents) { } // Sets the current render subpass to the subpass with the specified index. -void MVKCommandEncoder::setSubpass(VkSubpassContents subpassContents, uint32_t subpassIndex) { +void MVKCommandEncoder::setSubpass(VkSubpassContents subpassContents, uint32_t subpassIndex, bool loadOverride, bool storeOverride) { _subpassContents = subpassContents; _renderSubpassIndex = subpassIndex; - beginMetalRenderPass(); + beginMetalRenderPass(loadOverride, storeOverride); } // Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder. -void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride) { +void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride, bool storeOverride) { endCurrentMetalEncoding(); MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor]; - getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues, _isRenderingEntireAttachment, loadOverride); + getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues, _isRenderingEntireAttachment, loadOverride, storeOverride); mtlRPDesc.visibilityResultBuffer = _occlusionQueryState.getVisibilityResultMTLBuffer(); if (_device->_pMetalFeatures->layeredRendering) { diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index cd5ef52d..b671f790 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -277,10 +277,10 @@ void MVKDepthStencilCommandEncoderState::setStencilWriteMask(VkStencilFaceFlags } void MVKDepthStencilCommandEncoderState::encodeImpl(uint32_t stage) { - if (stage != kMVKGraphicsStageRasterization) { return; } + if (stage != kMVKGraphicsStageRasterization && stage != kMVKGraphicsStageVertex) { return; } MVKRenderSubpass *subpass = _cmdEncoder->getSubpass(); id mtlDSS = nil; - if (subpass->getDepthStencilFormat() != VK_FORMAT_UNDEFINED) { + if (stage != kMVKGraphicsStageVertex && subpass->getDepthStencilFormat() != VK_FORMAT_UNDEFINED) { mtlDSS = _cmdEncoder->getCommandEncodingPool()->getMTLDepthStencilState(_depthStencilData); } else { // If there is no depth attachment but the depth/stencil state contains a non-always depth diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h index f8196335..918fdd5d 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h @@ -168,7 +168,7 @@ kernel void cmdCopyBufferToImage3DDecompressTempBufferDXTn(constant uint8_t* src } \n\ } \n\ \n\ -#if __METAL_VERSION__ == 210 \n\ +#if __METAL_VERSION__ >= 210 \n\ // This structure is missing from the MSL headers. :/ \n\ struct MTLStageInRegionIndirectArguments { \n\ uint32_t stageInOrigin[3]; \n\ diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm index fad8ff66..f948dae4 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm @@ -386,8 +386,8 @@ id MVKCommandResourceFactory::newCmdCopyBufferToImage3D } id MVKCommandResourceFactory::newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed) { - return newMTLComputePipelineState(getFunctionNamed(indexed ? "cmdDrawIndirectConvertBuffers" : - "cmdDrawIndexedIndirectConvertBuffers")); + return newMTLComputePipelineState(getFunctionNamed(indexed ? "cmdDrawIndexedIndirectConvertBuffers" : + "cmdDrawIndirectConvertBuffers")); } id MVKCommandResourceFactory::newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type) { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h index 769c9fa9..45c87888 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h @@ -59,7 +59,8 @@ public: MVKFramebuffer* framebuffer, MVKVector& clearValues, bool isRenderingEntireAttachment, - bool loadOverride = false); + bool loadOverride = false, + bool storeOverride = false); /** * Populates the specified vector with the attachments that need to be cleared @@ -113,7 +114,8 @@ public: bool isRenderingEntireAttachment, bool hasResolveAttachment, bool isStencil, - bool loadOverride = false); + bool loadOverride = false, + bool storeOverride = false); /** Returns whether this attachment should be cleared in the subpass. */ bool shouldUseClearAttachment(MVKRenderSubpass* subpass); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm index 67c2980b..fd58aecd 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm @@ -69,7 +69,8 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* MVKFramebuffer* framebuffer, MVKVector& clearValues, bool isRenderingEntireAttachment, - bool loadOverride) { + bool loadOverride, + bool storeOverride) { // Populate the Metal color attachments uint32_t caCnt = getColorAttachmentCount(); for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { @@ -91,7 +92,8 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* if (clrMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlColorAttDesc, this, isRenderingEntireAttachment, hasResolveAttachment, false, - loadOverride)) { + loadOverride, + storeOverride)) { mtlColorAttDesc.clearColor = mvkMTLClearColorFromVkClearValue(clearValues[clrRPAttIdx], clrMVKRPAtt->getFormat()); } @@ -113,7 +115,8 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this, isRenderingEntireAttachment, false, false, - loadOverride)) { + loadOverride, + storeOverride)) { mtlDepthAttDesc.clearDepth = mvkMTLClearDepthFromVkClearValue(clearValues[dsRPAttIdx]); } } @@ -123,7 +126,8 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this, isRenderingEntireAttachment, false, true, - loadOverride)) { + loadOverride, + storeOverride)) { mtlStencilAttDesc.clearStencil = mvkMTLClearStencilFromVkClearValue(clearValues[dsRPAttIdx]); } } @@ -257,7 +261,8 @@ bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRende bool isRenderingEntireAttachment, bool hasResolveAttachment, bool isStencil, - bool loadOverride) { + bool loadOverride, + bool storeOverride) { bool willClear = false; // Assume the attachment won't be cleared @@ -278,6 +283,8 @@ bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRende // to the entire attachment and we're in the last subpass. if (hasResolveAttachment && !_renderPass->getDevice()->getPhysicalDevice()->getMetalFeatures()->combinedStoreResolveAction) { mtlAttDesc.storeAction = MTLStoreActionMultisampleResolve; + } else if ( storeOverride ) { + mtlAttDesc.storeAction = MTLStoreActionStore; } else if ( isRenderingEntireAttachment && (subpass->_subpassIndex == _lastUseSubpassIdx) ) { VkAttachmentStoreOp storeOp = isStencil ? _info.stencilStoreOp : _info.storeOp; mtlAttDesc.storeAction = mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment);