Merge pull request #623 from cdavis5e/no-viewports-assertion
Don't assert if no viewports or scissor rects were given.
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index b7fe472..2b892c4 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-c125bbd2482815f2f1b6a92ec4f06e1c01b47c5b
+cb686a5dba9a7086a778fe21900383beed9ea5d3
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDebug.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDebug.mm
index 45ee566..ae28ec3 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDebug.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDebug.mm
@@ -41,9 +41,14 @@
#pragma mark MVKCmdDebugMarkerBegin
// Vulkan debug groups are more general than Metal's.
-// Always push on command buffer instead of the encoder.
+// If a renderpass is active, push on the render command encoder, otherwise push on the command buffer.
void MVKCmdDebugMarkerBegin::encode(MVKCommandEncoder* cmdEncoder) {
- [cmdEncoder->_mtlCmdBuffer pushDebugGroup: _markerName];
+ id<MTLRenderCommandEncoder> mtlCmdEnc = cmdEncoder->_mtlRenderEncoder;
+ if (mtlCmdEnc) {
+ [mtlCmdEnc pushDebugGroup: _markerName];
+ } else {
+ [cmdEncoder->_mtlCmdBuffer pushDebugGroup: _markerName];
+ }
}
MVKCmdDebugMarkerBegin::MVKCmdDebugMarkerBegin(MVKCommandTypePool<MVKCmdDebugMarkerBegin>* pool)
@@ -54,9 +59,14 @@
#pragma mark MVKCmdDebugMarkerEnd
// Vulkan debug groups are more general than Metal's.
-// Always pop from command buffer instead of the encoder.
+// If a renderpass is active, pop from the render command encoder, otherwise pop from the command buffer.
void MVKCmdDebugMarkerEnd::encode(MVKCommandEncoder* cmdEncoder) {
- [cmdEncoder->_mtlCmdBuffer popDebugGroup];
+ id<MTLRenderCommandEncoder> mtlCmdEnc = cmdEncoder->_mtlRenderEncoder;
+ if (mtlCmdEnc) {
+ [mtlCmdEnc popDebugGroup];
+ } else {
+ [cmdEncoder->_mtlCmdBuffer popDebugGroup];
+ }
}
MVKCmdDebugMarkerEnd::MVKCmdDebugMarkerEnd(MVKCommandTypePool<MVKCmdDebugMarkerEnd>* pool)
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
index 3646abf..4d46a5b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
@@ -74,7 +74,7 @@
void MVKCmdEndRenderPass::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdEndRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
- cmdEncoder->endMetalRenderEncoding();
+ cmdEncoder->endRenderpass();
}
MVKCmdEndRenderPass::MVKCmdEndRenderPass(MVKCommandTypePool<MVKCmdEndRenderPass>* pool)
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index ba86b4b..2591f74 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -301,6 +301,9 @@
/** Called by each compute dispatch command to establish any outstanding state just prior to performing the dispatch. */
void finalizeDispatchState();
+ /** Ends the current renderpass. */
+ void endRenderpass();
+
/**
* Ends all encoding operations on the current Metal command encoder.
*
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 7548626..7df3be2 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -332,7 +332,12 @@
// Returns a name for use as a MTLRenderCommandEncoder label
NSString* MVKCommandEncoder::getMTLRenderCommandEncoderName() {
- NSString* rpName = _renderPass ? _renderPass->getDebugName() : nil;
+ NSString* rpName;
+
+ rpName = _renderPass->getDebugName();
+ if (rpName) { return rpName; }
+
+ rpName = _cmdBuffer->getDebugName();
if (rpName) { return rpName; }
MVKCommandUse cmdUse = (_renderSubpassIndex == 0) ? kMVKCommandUseBeginRenderPass : kMVKCommandUseNextSubpass;
@@ -418,6 +423,14 @@
_computePushConstants.encode();
}
+void MVKCommandEncoder::endRenderpass() {
+ endMetalRenderEncoding();
+
+ _renderPass = nullptr;
+ _framebuffer = nullptr;
+ _renderSubpassIndex = 0;
+}
+
void MVKCommandEncoder::endMetalRenderEncoding() {
// MVKLogDebugIf(_mtlRenderEncoder, "Render subpass end MTLRenderCommandEncoder.");
[_mtlRenderEncoder endEncoding];
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 843c209..901f457 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -403,7 +403,7 @@
}
}
- void updateSwizzle(MVKVector<uint32_t> &constants, uint32_t index, uint32_t swizzle);
+ void updateImplicitBuffer(MVKVector<uint32_t> &contents, uint32_t index, uint32_t value);
void assertMissingSwizzles(bool needsSwizzle, const char* stageName, MVKVector<MVKMTLTextureBinding>& texBindings);
};
@@ -434,18 +434,25 @@
_mtlIndexBufferBinding = binding; // No need to track dirty state
}
- /** Sets the current auxiliary buffer state. */
- void bindAuxBuffer(const MVKShaderImplicitRezBinding& binding,
- bool needVertexAuxBuffer,
- bool needTessCtlAuxBuffer,
- bool needTessEvalAuxBuffer,
- bool needFragmentAuxBuffer);
+ /** Sets the current swizzle buffer state. */
+ void bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needVertexSwizzleBuffer,
+ bool needTessCtlSwizzleBuffer,
+ bool needTessEvalSwizzleBuffer,
+ bool needFragmentSwizzleBuffer);
+
+ /** Sets the current buffer size buffer state. */
+ void bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needVertexSizeBuffer,
+ bool needTessCtlSizeBuffer,
+ bool needTessEvalSizeBuffer,
+ bool needFragmentSizeBuffer);
void encodeBindings(MVKShaderStage stage,
const char* pStageName,
bool fullImageViewSwizzle,
std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&)> bindBuffer,
- std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindAuxBuffer,
+ std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindImplicitBuffer,
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler);
@@ -464,7 +471,9 @@
MVKVectorInline<MVKMTLTextureBinding, 8> textureBindings;
MVKVectorInline<MVKMTLSamplerStateBinding, 8> samplerStateBindings;
MVKVectorInline<uint32_t, 8> swizzleConstants;
- MVKMTLBufferBinding auxBufferBinding;
+ MVKVectorInline<uint32_t, 8> bufferSizes;
+ MVKMTLBufferBinding swizzleBufferBinding;
+ MVKMTLBufferBinding bufferSizeBufferBinding;
bool areBufferBindingsDirty = false;
bool areTextureBindingsDirty = false;
@@ -494,8 +503,11 @@
/** Binds the specified sampler state. */
void bindSamplerState(const MVKMTLSamplerStateBinding& binding);
- /** Sets the current auxiliary buffer state. */
- void bindAuxBuffer(const MVKShaderImplicitRezBinding& binding, bool needAuxBuffer);
+ /** Sets the current swizzle buffer state. */
+ void bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding, bool needSwizzleBuffer);
+
+ /** Sets the current buffer size buffer state. */
+ void bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding, bool needSizeBuffer);
#pragma mark Construction
@@ -511,13 +523,15 @@
MVKVectorDefault<MVKMTLTextureBinding> _textureBindings;
MVKVectorDefault<MVKMTLSamplerStateBinding> _samplerStateBindings;
MVKVectorDefault<uint32_t> _swizzleConstants;
- MVKMTLBufferBinding _auxBufferBinding;
+ MVKVectorDefault<uint32_t> _bufferSizes;
+ MVKMTLBufferBinding _swizzleBufferBinding;
+ MVKMTLBufferBinding _bufferSizeBufferBinding;
bool _areBufferBindingsDirty = false;
bool _areTextureBindingsDirty = false;
bool _areSamplerStateBindingsDirty = false;
- bool _needsSwizzle = false;
+ bool _needsSwizzle = false;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index b80de27..328ff5c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -447,10 +447,10 @@
#pragma mark -
#pragma mark MVKResourcesCommandEncoderState
-// Updates the swizzle for an image in the given vector.
-void MVKResourcesCommandEncoderState::updateSwizzle(MVKVector<uint32_t> &constants, uint32_t index, uint32_t swizzle) {
- if (index >= constants.size()) { constants.resize(index + 1); }
- constants[index] = swizzle;
+// Updates a value at the given index in the given vector.
+void MVKResourcesCommandEncoderState::updateImplicitBuffer(MVKVector<uint32_t> &contents, uint32_t index, uint32_t value) {
+ if (index >= contents.size()) { contents.resize(index + 1); }
+ contents[index] = value;
}
// If a swizzle is needed for this stage, iterates all the bindings and logs errors for those that need texture swizzling.
@@ -486,42 +486,64 @@
bind(binding, _shaderStages[stage].samplerStateBindings, _shaderStages[stage].areSamplerStateBindingsDirty);
}
-void MVKGraphicsResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderImplicitRezBinding& binding,
- bool needVertexAuxBuffer,
- bool needTessCtlAuxBuffer,
- bool needTessEvalAuxBuffer,
- bool needFragmentAuxBuffer) {
+void MVKGraphicsResourcesCommandEncoderState::bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needVertexSwizzleBuffer,
+ bool needTessCtlSwizzleBuffer,
+ bool needTessEvalSwizzleBuffer,
+ bool needFragmentSwizzleBuffer) {
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
- _shaderStages[i].auxBufferBinding.index = binding.stages[i];
+ _shaderStages[i].swizzleBufferBinding.index = binding.stages[i];
}
- _shaderStages[kMVKShaderStageVertex].auxBufferBinding.isDirty = needVertexAuxBuffer;
- _shaderStages[kMVKShaderStageTessCtl].auxBufferBinding.isDirty = needTessCtlAuxBuffer;
- _shaderStages[kMVKShaderStageTessEval].auxBufferBinding.isDirty = needTessEvalAuxBuffer;
- _shaderStages[kMVKShaderStageFragment].auxBufferBinding.isDirty = needFragmentAuxBuffer;
+ _shaderStages[kMVKShaderStageVertex].swizzleBufferBinding.isDirty = needVertexSwizzleBuffer;
+ _shaderStages[kMVKShaderStageTessCtl].swizzleBufferBinding.isDirty = needTessCtlSwizzleBuffer;
+ _shaderStages[kMVKShaderStageTessEval].swizzleBufferBinding.isDirty = needTessEvalSwizzleBuffer;
+ _shaderStages[kMVKShaderStageFragment].swizzleBufferBinding.isDirty = needFragmentSwizzleBuffer;
+}
+
+void MVKGraphicsResourcesCommandEncoderState::bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needVertexSizeBuffer,
+ bool needTessCtlSizeBuffer,
+ bool needTessEvalSizeBuffer,
+ bool needFragmentSizeBuffer) {
+ for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
+ _shaderStages[i].bufferSizeBufferBinding.index = binding.stages[i];
+ }
+ _shaderStages[kMVKShaderStageVertex].bufferSizeBufferBinding.isDirty = needVertexSizeBuffer;
+ _shaderStages[kMVKShaderStageTessCtl].bufferSizeBufferBinding.isDirty = needTessCtlSizeBuffer;
+ _shaderStages[kMVKShaderStageTessEval].bufferSizeBufferBinding.isDirty = needTessEvalSizeBuffer;
+ _shaderStages[kMVKShaderStageFragment].bufferSizeBufferBinding.isDirty = needFragmentSizeBuffer;
}
void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stage,
const char* pStageName,
bool fullImageViewSwizzle,
std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&)> bindBuffer,
- std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindAuxBuffer,
+ std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindImplicitBuffer,
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler) {
auto& shaderStage = _shaderStages[stage];
encodeBinding<MVKMTLBufferBinding>(shaderStage.bufferBindings, shaderStage.areBufferBindingsDirty, bindBuffer);
- if (shaderStage.auxBufferBinding.isDirty) {
+ if (shaderStage.swizzleBufferBinding.isDirty) {
for (auto& b : shaderStage.textureBindings) {
- if (b.isDirty) { updateSwizzle(shaderStage.swizzleConstants, b.index, b.swizzle); }
+ if (b.isDirty) { updateImplicitBuffer(shaderStage.swizzleConstants, b.index, b.swizzle); }
}
- bindAuxBuffer(_cmdEncoder, shaderStage.auxBufferBinding, shaderStage.swizzleConstants);
+ bindImplicitBuffer(_cmdEncoder, shaderStage.swizzleBufferBinding, shaderStage.swizzleConstants);
} else {
assertMissingSwizzles(shaderStage.needsSwizzle && !fullImageViewSwizzle, pStageName, shaderStage.textureBindings);
}
+ if (shaderStage.bufferSizeBufferBinding.isDirty) {
+ for (auto& b : shaderStage.bufferBindings) {
+ if (b.isDirty) { updateImplicitBuffer(shaderStage.bufferSizes, b.index, b.size); }
+ }
+
+ bindImplicitBuffer(_cmdEncoder, shaderStage.bufferSizeBufferBinding, shaderStage.bufferSizes);
+ }
+
encodeBinding<MVKMTLTextureBinding>(shaderStage.textureBindings, shaderStage.areTextureBindingsDirty, bindTexture);
encodeBinding<MVKMTLSamplerStateBinding>(shaderStage.samplerStateBindings, shaderStage.areSamplerStateBindingsDirty, bindSampler);
}
@@ -622,7 +644,7 @@
atIndex: b.index];
},
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
- cmdEncoder->setFragmentBytes(cmdEncoder->_mtlRenderEncoder,
+ cmdEncoder->setFragmentBytes(cmdEncoder->_mtlRenderEncoder,
s.data(),
s.size() * sizeof(uint32_t),
b.index);
@@ -644,11 +666,13 @@
_shaderStages[i].textureBindings.clear();
_shaderStages[i].samplerStateBindings.clear();
_shaderStages[i].swizzleConstants.clear();
+ _shaderStages[i].bufferSizes.clear();
_shaderStages[i].areBufferBindingsDirty = false;
_shaderStages[i].areTextureBindingsDirty = false;
_shaderStages[i].areSamplerStateBindingsDirty = false;
- _shaderStages[i].auxBufferBinding.isDirty = false;
+ _shaderStages[i].swizzleBufferBinding.isDirty = false;
+ _shaderStages[i].bufferSizeBufferBinding.isDirty = false;
_shaderStages[i].needsSwizzle = false;
}
@@ -663,17 +687,23 @@
}
void MVKComputeResourcesCommandEncoderState::bindTexture(const MVKMTLTextureBinding& binding) {
- bind(binding, _textureBindings, _areTextureBindingsDirty, _needsSwizzle);
+ bind(binding, _textureBindings, _areTextureBindingsDirty, _needsSwizzle);
}
void MVKComputeResourcesCommandEncoderState::bindSamplerState(const MVKMTLSamplerStateBinding& binding) {
bind(binding, _samplerStateBindings, _areSamplerStateBindingsDirty);
}
-void MVKComputeResourcesCommandEncoderState::bindAuxBuffer(const MVKShaderImplicitRezBinding& binding,
- bool needAuxBuffer) {
- _auxBufferBinding.index = binding.stages[kMVKShaderStageCompute];
- _auxBufferBinding.isDirty = needAuxBuffer;
+void MVKComputeResourcesCommandEncoderState::bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needSwizzleBuffer) {
+ _swizzleBufferBinding.index = binding.stages[kMVKShaderStageCompute];
+ _swizzleBufferBinding.isDirty = needSwizzleBuffer;
+}
+
+void MVKComputeResourcesCommandEncoderState::bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needBufferSizeBuffer) {
+ _bufferSizeBufferBinding.index = binding.stages[kMVKShaderStageCompute];
+ _bufferSizeBufferBinding.isDirty = needBufferSizeBuffer;
}
// Mark everything as dirty
@@ -698,21 +728,33 @@
atIndex: b.index];
});
- if (_auxBufferBinding.isDirty) {
+ if (_swizzleBufferBinding.isDirty) {
for (auto& b : _textureBindings) {
- if (b.isDirty) { updateSwizzle(_swizzleConstants, b.index, b.swizzle); }
+ if (b.isDirty) { updateImplicitBuffer(_swizzleConstants, b.index, b.swizzle); }
}
_cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
_swizzleConstants.data(),
_swizzleConstants.size() * sizeof(uint32_t),
- _auxBufferBinding.index);
+ _swizzleBufferBinding.index);
} else {
assertMissingSwizzles(_needsSwizzle && !fullImageViewSwizzle, "compute", _textureBindings);
}
+ if (_bufferSizeBufferBinding.isDirty) {
+ for (auto& b : _bufferBindings) {
+ if (b.isDirty) { updateImplicitBuffer(_bufferSizes, b.index, b.size); }
+ }
+
+ _cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
+ _bufferSizes.data(),
+ _bufferSizes.size() * sizeof(uint32_t),
+ _bufferSizeBufferBinding.index);
+
+ }
+
encodeBinding<MVKMTLTextureBinding>(_textureBindings, _areTextureBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setTexture: b.mtlTexture
@@ -731,11 +773,13 @@
_textureBindings.clear();
_samplerStateBindings.clear();
_swizzleConstants.clear();
+ _bufferSizes.clear();
_areBufferBindingsDirty = false;
_areTextureBindingsDirty = false;
_areSamplerStateBindingsDirty = false;
- _auxBufferBinding.isDirty = false;
+ _swizzleBufferBinding.isDirty = false;
+ _bufferSizeBufferBinding.isDirty = false;
_needsSwizzle = false;
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
index 3316594..cfdf82c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
@@ -40,6 +40,7 @@
union { id<MTLBuffer> mtlBuffer = nil; id<MTLBuffer> mtlResource; }; // aliases
NSUInteger offset = 0;
uint32_t index = 0;
+ uint32_t size = 0;
bool isDirty = true;
} MVKMTLBufferBinding;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index 3a62682..28a1ff6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -105,6 +105,7 @@
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
bb.mtlBuffer = descBinding._mtlBuffers[rezIdx];
bb.offset = descBinding._mtlBufferOffsets[rezIdx] + bufferDynamicOffset;
+ bb.size = (uint32_t)((MVKBuffer*)descBinding._bufferBindings[rezIdx].buffer)->getByteCount();
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
if (_applyToStage[i]) {
bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx;
@@ -236,6 +237,7 @@
MVKBuffer* buffer = (MVKBuffer*)bufferInfo.buffer;
bb.mtlBuffer = buffer->getMTLBuffer();
bb.offset = bufferInfo.offset;
+ bb.size = (uint32_t)buffer->getByteCount();
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
if (_applyToStage[i]) {
bb.index = mtlIdxs.stages[i].bufferIndex + rezIdx;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index bdaba80..f84d7b7 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -69,8 +69,11 @@
uint32_t set,
const void* pData);
- /** Returns the current auxiliary buffer bindings. */
- const MVKShaderImplicitRezBinding& getAuxBufferIndex() { return _auxBufferIndex; }
+ /** Returns the current swizzle buffer bindings. */
+ const MVKShaderImplicitRezBinding& getSwizzleBufferIndex() { return _swizzleBufferIndex; }
+
+ /** Returns the current buffer size buffer bindings. */
+ const MVKShaderImplicitRezBinding& getBufferSizeBufferIndex() { return _bufferSizeBufferIndex; }
/** Returns the current indirect parameter buffer bindings. */
const MVKShaderImplicitRezBinding& getIndirectParamsIndex() { return _indirectParamsIndex; }
@@ -84,9 +87,12 @@
/** Returns the current tessellation level buffer binding for the tess. control shader. */
uint32_t getTessCtlLevelBufferIndex() { return _tessCtlLevelBufferIndex; }
- /** Returns the number of textures in this layout. This is used to calculate the size of the auxiliary buffer. */
+ /** Returns the number of textures in this layout. This is used to calculate the size of the swizzle buffer. */
uint32_t getTextureCount() { return _pushConstantsMTLResourceIndexes.getMaxTextureIndex(); }
+ /** Returns the number of buffers in this layout. This is used to calculate the size of the buffer size buffer. */
+ uint32_t getBufferCount() { return _pushConstantsMTLResourceIndexes.getMaxBufferIndex(); }
+
/** Constructs an instance for the specified device. */
MVKPipelineLayout(MVKDevice* device, const VkPipelineLayoutCreateInfo* pCreateInfo);
@@ -97,7 +103,8 @@
MVKVectorInline<MVKShaderResourceBinding, 8> _dslMTLResourceIndexOffsets;
MVKVectorInline<VkPushConstantRange, 8> _pushConstants;
MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
- MVKShaderImplicitRezBinding _auxBufferIndex;
+ MVKShaderImplicitRezBinding _swizzleBufferIndex;
+ MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
MVKShaderImplicitRezBinding _indirectParamsIndex;
MVKShaderImplicitRezBinding _outputBufferIndex;
uint32_t _tessCtlPatchOutputBufferIndex = 0;
@@ -131,8 +138,11 @@
/** Binds this pipeline to the specified command encoder. */
virtual void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) = 0;
- /** Returns the current auxiliary buffer bindings. */
- const MVKShaderImplicitRezBinding& getAuxBufferIndex() { return _auxBufferIndex; }
+ /** Returns the current swizzle buffer bindings. */
+ const MVKShaderImplicitRezBinding& getSwizzleBufferIndex() { return _swizzleBufferIndex; }
+
+ /** Returns the current buffer size buffer bindings. */
+ const MVKShaderImplicitRezBinding& getBufferSizeBufferIndex() { return _bufferSizeBufferIndex; }
/** Returns whether or not full image view swizzling is enabled for this pipeline. */
bool fullImageViewSwizzle() const { return _fullImageViewSwizzle; }
@@ -146,7 +156,8 @@
void propogateDebugName() override {}
MVKPipelineCache* _pipelineCache;
- MVKShaderImplicitRezBinding _auxBufferIndex;
+ MVKShaderImplicitRezBinding _swizzleBufferIndex;
+ MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
bool _fullImageViewSwizzle;
};
@@ -230,6 +241,7 @@
void addTessellationToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkPipelineTessellationStateCreateInfo* pTS);
void addFragmentOutputToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkGraphicsPipelineCreateInfo* pCreateInfo, bool isTessellationVertexPipeline = false);
bool isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
+ bool verifyImplicitBuffer(bool needsBuffer, MVKShaderImplicitRezBinding& index, MVKShaderStage stage, const char* name, uint32_t reservedBuffers);
const VkPipelineShaderStageCreateInfo* _pVertexSS = nullptr;
const VkPipelineShaderStageCreateInfo* _pTessCtlSS = nullptr;
@@ -265,14 +277,18 @@
bool _dynamicStateEnabled[VK_DYNAMIC_STATE_RANGE_SIZE];
bool _hasDepthStencilInfo;
- bool _needsVertexAuxBuffer = false;
+ bool _needsVertexSwizzleBuffer = false;
+ bool _needsVertexBufferSizeBuffer = false;
bool _needsVertexOutputBuffer = false;
- bool _needsTessCtlAuxBuffer = false;
+ bool _needsTessCtlSwizzleBuffer = false;
+ bool _needsTessCtlBufferSizeBuffer = false;
bool _needsTessCtlOutputBuffer = false;
bool _needsTessCtlPatchOutputBuffer = false;
bool _needsTessCtlInput = false;
- bool _needsTessEvalAuxBuffer = false;
- bool _needsFragmentAuxBuffer = false;
+ bool _needsTessEvalSwizzleBuffer = false;
+ bool _needsTessEvalBufferSizeBuffer = false;
+ bool _needsFragmentSwizzleBuffer = false;
+ bool _needsFragmentBufferSizeBuffer = false;
};
@@ -303,7 +319,8 @@
id<MTLComputePipelineState> _mtlPipelineState;
MTLSize _mtlThreadgroupSize;
- bool _needsAuxBuffer = false;
+ bool _needsSwizzleBuffer = false;
+ bool _needsBufferSizeBuffer = false;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 9136263..21976c6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -135,9 +135,14 @@
}
// Set implicit buffer indices
+ // FIXME: Many of these are optional. We shouldn't set the ones that aren't
+ // present--or at least, we should move the ones that are down to avoid
+ // running over the limit of available buffers. But we can't know that
+ // until we compile the shaders.
for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageMax; i++) {
- _auxBufferIndex.stages[i] = _pushConstantsMTLResourceIndexes.stages[i].bufferIndex + 1;
- _indirectParamsIndex.stages[i] = _auxBufferIndex.stages[i] + 1;
+ _swizzleBufferIndex.stages[i] = _pushConstantsMTLResourceIndexes.stages[i].bufferIndex + 1;
+ _bufferSizeBufferIndex.stages[i] = _swizzleBufferIndex.stages[i] + 1;
+ _indirectParamsIndex.stages[i] = _bufferSizeBufferIndex.stages[i] + 1;
_outputBufferIndex.stages[i] = _indirectParamsIndex.stages[i] + 1;
if (i == kMVKShaderStageTessCtl) {
_tessCtlPatchOutputBufferIndex = _outputBufferIndex.stages[i] + 1;
@@ -232,7 +237,8 @@
break;
}
- cmdEncoder->_graphicsResourcesState.bindAuxBuffer(_auxBufferIndex, _needsVertexAuxBuffer, _needsTessCtlAuxBuffer, _needsTessEvalAuxBuffer, _needsFragmentAuxBuffer);
+ cmdEncoder->_graphicsResourcesState.bindSwizzleBuffer(_swizzleBufferIndex, _needsVertexSwizzleBuffer, _needsTessCtlSwizzleBuffer, _needsTessEvalSwizzleBuffer, _needsFragmentSwizzleBuffer);
+ cmdEncoder->_graphicsResourcesState.bindBufferSizeBuffer(_bufferSizeBufferIndex, _needsVertexBufferSizeBuffer, _needsTessCtlBufferSizeBuffer, _needsTessEvalBufferSizeBuffer, _needsFragmentBufferSizeBuffer);
}
bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
@@ -700,14 +706,29 @@
return plDesc;
}
+bool MVKGraphicsPipeline::verifyImplicitBuffer(bool needsBuffer, MVKShaderImplicitRezBinding& index, MVKShaderStage stage, const char* name, uint32_t reservedBuffers) {
+ const char* stageNames[] = {
+ "Vertex",
+ "Tessellation control",
+ "Tessellation evaluation",
+ "Fragment"
+ };
+ if (needsBuffer && index.stages[stage] >= _device->_pMetalFeatures->maxPerStageBufferCount - reservedBuffers) {
+ setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "%s shader requires %s buffer, but there is no free slot to pass it.", stageNames[stage], name));
+ return false;
+ }
+ return true;
+}
+
// Adds a vertex shader to the pipeline description.
bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConverterContext& shaderContext) {
uint32_t vbCnt = pCreateInfo->pVertexInputState->vertexBindingDescriptionCount;
shaderContext.options.entryPointStage = spv::ExecutionModelVertex;
shaderContext.options.entryPointName = _pVertexSS->pName;
- shaderContext.options.auxBufferIndex = _auxBufferIndex.stages[kMVKShaderStageVertex];
+ shaderContext.options.swizzleBufferIndex = _swizzleBufferIndex.stages[kMVKShaderStageVertex];
shaderContext.options.indirectParamsBufferIndex = _indirectParamsIndex.stages[kMVKShaderStageVertex];
shaderContext.options.outputBufferIndex = _outputBufferIndex.stages[kMVKShaderStageVertex];
+ shaderContext.options.bufferSizeBufferIndex = _bufferSizeBufferIndex.stages[kMVKShaderStageVertex];
shaderContext.options.shouldCaptureOutput = isTessellationPipeline();
shaderContext.options.isRasterizationDisabled = isTessellationPipeline() || (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable));
addVertexInputToShaderConverterContext(shaderContext, pCreateInfo);
@@ -718,20 +739,22 @@
}
plDesc.vertexFunction = mtlFunction;
plDesc.rasterizationEnabled = !shaderContext.options.isRasterizationDisabled;
- _needsVertexAuxBuffer = shaderContext.options.needsAuxBuffer;
+ _needsVertexSwizzleBuffer = shaderContext.options.needsSwizzleBuffer;
+ _needsVertexBufferSizeBuffer = shaderContext.options.needsBufferSizeBuffer;
_needsVertexOutputBuffer = shaderContext.options.needsOutputBuffer;
- // If we need the auxiliary buffer and there's no place to put it, we're in serious trouble.
- if (_needsVertexAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageVertex] >= _device->_pMetalFeatures->maxPerStageBufferCount - vbCnt) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader requires auxiliary buffer, but there is no free slot to pass it."));
+ // If we need the swizzle buffer and there's no place to put it, we're in serious trouble.
+ if (!verifyImplicitBuffer(_needsVertexSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageVertex, "swizzle", vbCnt)) {
+ return false;
+ }
+ // Ditto buffer size buffer.
+ if (!verifyImplicitBuffer(_needsVertexBufferSizeBuffer, _bufferSizeBufferIndex, kMVKShaderStageVertex, "buffer size", vbCnt)) {
return false;
}
// Ditto captured output buffer.
- if (_needsVertexOutputBuffer && _outputBufferIndex.stages[kMVKShaderStageVertex] >= _device->_pMetalFeatures->maxPerStageBufferCount - vbCnt) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader requires output buffer, but there is no free slot to pass it."));
+ if (!verifyImplicitBuffer(_needsVertexOutputBuffer, _outputBufferIndex, kMVKShaderStageVertex, "output", vbCnt)) {
return false;
}
- if (_needsVertexOutputBuffer && _indirectParamsIndex.stages[kMVKShaderStageVertex] >= _device->_pMetalFeatures->maxPerStageBufferCount - vbCnt) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Vertex shader requires indirect parameters buffer, but there is no free slot to pass it."));
+ if (!verifyImplicitBuffer(_needsVertexOutputBuffer, _indirectParamsIndex, kMVKShaderStageVertex, "indirect parameters", vbCnt)) {
return false;
}
return true;
@@ -740,11 +763,12 @@
bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConverterContext& shaderContext, std::vector<SPIRVShaderOutput>& vtxOutputs) {
shaderContext.options.entryPointStage = spv::ExecutionModelTessellationControl;
shaderContext.options.entryPointName = _pTessCtlSS->pName;
- shaderContext.options.auxBufferIndex = _auxBufferIndex.stages[kMVKShaderStageTessCtl];
+ shaderContext.options.swizzleBufferIndex = _swizzleBufferIndex.stages[kMVKShaderStageTessCtl];
shaderContext.options.indirectParamsBufferIndex = _indirectParamsIndex.stages[kMVKShaderStageTessCtl];
shaderContext.options.outputBufferIndex = _outputBufferIndex.stages[kMVKShaderStageTessCtl];
shaderContext.options.patchOutputBufferIndex = _tessCtlPatchOutputBufferIndex;
shaderContext.options.tessLevelBufferIndex = _tessCtlLevelBufferIndex;
+ shaderContext.options.bufferSizeBufferIndex = _bufferSizeBufferIndex.stages[kMVKShaderStageTessCtl];
shaderContext.options.shouldCaptureOutput = true;
addPrevStageOutputToShaderConverterContext(shaderContext, vtxOutputs);
id<MTLFunction> mtlFunction = ((MVKShaderModule*)_pTessCtlSS->module)->getMTLFunction(&shaderContext, _pTessCtlSS->pSpecializationInfo, _pipelineCache).mtlFunction;
@@ -753,20 +777,21 @@
return false;
}
plDesc.computeFunction = mtlFunction;
- _needsTessCtlAuxBuffer = shaderContext.options.needsAuxBuffer;
+ _needsTessCtlSwizzleBuffer = shaderContext.options.needsSwizzleBuffer;
+ _needsTessCtlBufferSizeBuffer = shaderContext.options.needsBufferSizeBuffer;
_needsTessCtlOutputBuffer = shaderContext.options.needsOutputBuffer;
_needsTessCtlPatchOutputBuffer = shaderContext.options.needsPatchOutputBuffer;
_needsTessCtlInput = shaderContext.options.needsInputThreadgroupMem;
- if (_needsTessCtlAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageTessCtl] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires auxiliary buffer, but there is no free slot to pass it."));
+ if (!verifyImplicitBuffer(_needsTessCtlSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageTessCtl, "swizzle", kMVKTessCtlNumReservedBuffers)) {
return false;
}
- if (_indirectParamsIndex.stages[kMVKShaderStageTessCtl] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires indirect parameters buffer, but there is no free slot to pass it."));
+ if (!verifyImplicitBuffer(_needsTessCtlBufferSizeBuffer, _bufferSizeBufferIndex, kMVKShaderStageTessCtl, "buffer size", kMVKTessCtlNumReservedBuffers)) {
return false;
}
- if (_needsTessCtlOutputBuffer && _outputBufferIndex.stages[kMVKShaderStageTessCtl] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation control shader requires per-vertex output buffer, but there is no free slot to pass it."));
+ if (!verifyImplicitBuffer(true, _indirectParamsIndex, kMVKShaderStageTessCtl, "indirect parameters", kMVKTessCtlNumReservedBuffers)) {
+ return false;
+ }
+ if (!verifyImplicitBuffer(_needsTessCtlOutputBuffer, _outputBufferIndex, kMVKShaderStageTessCtl, "per-vertex output", kMVKTessCtlNumReservedBuffers)) {
return false;
}
if (_needsTessCtlPatchOutputBuffer && _tessCtlPatchOutputBufferIndex >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessCtlNumReservedBuffers) {
@@ -783,7 +808,8 @@
bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConverterContext& shaderContext, std::vector<SPIRVShaderOutput>& tcOutputs) {
shaderContext.options.entryPointStage = spv::ExecutionModelTessellationEvaluation;
shaderContext.options.entryPointName = _pTessEvalSS->pName;
- shaderContext.options.auxBufferIndex = _auxBufferIndex.stages[kMVKShaderStageTessEval];
+ shaderContext.options.swizzleBufferIndex = _swizzleBufferIndex.stages[kMVKShaderStageTessEval];
+ shaderContext.options.bufferSizeBufferIndex = _bufferSizeBufferIndex.stages[kMVKShaderStageTessEval];
shaderContext.options.shouldCaptureOutput = false;
shaderContext.options.isRasterizationDisabled = (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable));
addPrevStageOutputToShaderConverterContext(shaderContext, tcOutputs);
@@ -795,10 +821,12 @@
// Yeah, you read that right. Tess. eval functions are a kind of vertex function in Metal.
plDesc.vertexFunction = mtlFunction;
plDesc.rasterizationEnabled = !shaderContext.options.isRasterizationDisabled;
- _needsTessEvalAuxBuffer = shaderContext.options.needsAuxBuffer;
- // If we need the auxiliary buffer and there's no place to put it, we're in serious trouble.
- if (_needsTessEvalAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageTessEval] >= _device->_pMetalFeatures->maxPerStageBufferCount - kMVKTessEvalNumReservedBuffers) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Tessellation evaluation shader requires auxiliary buffer, but there is no free slot to pass it."));
+ _needsTessEvalSwizzleBuffer = shaderContext.options.needsSwizzleBuffer;
+ _needsTessEvalBufferSizeBuffer = shaderContext.options.needsBufferSizeBuffer;
+ if (!verifyImplicitBuffer(_needsTessEvalSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageTessEval, "swizzle", kMVKTessEvalNumReservedBuffers)) {
+ return false;
+ }
+ if (!verifyImplicitBuffer(_needsTessEvalBufferSizeBuffer, _bufferSizeBufferIndex, kMVKShaderStageTessEval, "buffer size", kMVKTessEvalNumReservedBuffers)) {
return false;
}
return true;
@@ -807,7 +835,8 @@
bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConverterContext& shaderContext) {
if (_pFragmentSS) {
shaderContext.options.entryPointStage = spv::ExecutionModelFragment;
- shaderContext.options.auxBufferIndex = _auxBufferIndex.stages[kMVKShaderStageFragment];
+ shaderContext.options.swizzleBufferIndex = _swizzleBufferIndex.stages[kMVKShaderStageFragment];
+ shaderContext.options.bufferSizeBufferIndex = _bufferSizeBufferIndex.stages[kMVKShaderStageFragment];
shaderContext.options.entryPointName = _pFragmentSS->pName;
shaderContext.options.shouldCaptureOutput = false;
id<MTLFunction> mtlFunction = ((MVKShaderModule*)_pFragmentSS->module)->getMTLFunction(&shaderContext, _pFragmentSS->pSpecializationInfo, _pipelineCache).mtlFunction;
@@ -816,9 +845,12 @@
return false;
}
plDesc.fragmentFunction = mtlFunction;
- _needsFragmentAuxBuffer = shaderContext.options.needsAuxBuffer;
- if (_needsFragmentAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageFragment] >= _device->_pMetalFeatures->maxPerStageBufferCount) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Fragment shader requires auxiliary buffer, but there is no free slot to pass it."));
+ _needsFragmentSwizzleBuffer = shaderContext.options.needsSwizzleBuffer;
+ _needsFragmentBufferSizeBuffer = shaderContext.options.needsBufferSizeBuffer;
+ if (!verifyImplicitBuffer(_needsFragmentSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageFragment, "swizzle", 0)) {
+ return false;
+ }
+ if (!verifyImplicitBuffer(_needsFragmentBufferSizeBuffer, _bufferSizeBufferIndex, kMVKShaderStageFragment, "buffer size", 0)) {
return false;
}
}
@@ -1029,7 +1061,8 @@
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
- _auxBufferIndex = layout->getAuxBufferIndex();
+ _swizzleBufferIndex = layout->getSwizzleBufferIndex();
+ _bufferSizeBufferIndex = layout->getBufferSizeBufferIndex();
_indirectParamsIndex = layout->getIndirectParamsIndex();
_outputBufferIndex = layout->getOutputBufferIndex();
_tessCtlPatchOutputBufferIndex = layout->getTessCtlPatchOutputBufferIndex();
@@ -1164,7 +1197,8 @@
void MVKComputePipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t) {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setComputePipelineState: _mtlPipelineState];
cmdEncoder->_mtlThreadgroupSize = _mtlThreadgroupSize;
- cmdEncoder->_computeResourcesState.bindAuxBuffer(_auxBufferIndex, _needsAuxBuffer);
+ cmdEncoder->_computeResourcesState.bindSwizzleBuffer(_swizzleBufferIndex, _needsSwizzleBuffer);
+ cmdEncoder->_computeResourcesState.bindBufferSizeBuffer(_bufferSizeBufferIndex, _needsBufferSizeBuffer);
}
MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
@@ -1191,8 +1225,11 @@
setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader function could not be compiled into pipeline. See previous logged error."));
}
- if (_needsAuxBuffer && _auxBufferIndex.stages[kMVKShaderStageCompute] > _device->_pMetalFeatures->maxPerStageBufferCount) {
- setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader requires auxiliary buffer, but there is no free slot to pass it."));
+ if (_needsSwizzleBuffer && _swizzleBufferIndex.stages[kMVKShaderStageCompute] > _device->_pMetalFeatures->maxPerStageBufferCount) {
+ setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader requires swizzle buffer, but there is no free slot to pass it."));
+ }
+ if (_needsBufferSizeBuffer && _bufferSizeBufferIndex.stages[kMVKShaderStageCompute] > _device->_pMetalFeatures->maxPerStageBufferCount) {
+ setConfigurationResult(reportError(VK_ERROR_INVALID_SHADER_NV, "Compute shader requires buffer size buffer, but there is no free slot to pass it."));
}
}
@@ -1211,12 +1248,15 @@
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
- _auxBufferIndex = layout->getAuxBufferIndex();
- shaderContext.options.auxBufferIndex = _auxBufferIndex.stages[kMVKShaderStageCompute];
+ _swizzleBufferIndex = layout->getSwizzleBufferIndex();
+ _bufferSizeBufferIndex = layout->getBufferSizeBufferIndex();
+ shaderContext.options.swizzleBufferIndex = _swizzleBufferIndex.stages[kMVKShaderStageCompute];
+ shaderContext.options.bufferSizeBufferIndex = _bufferSizeBufferIndex.stages[kMVKShaderStageCompute];
MVKShaderModule* mvkShdrMod = (MVKShaderModule*)pSS->module;
MVKMTLFunction func = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache);
- _needsAuxBuffer = shaderContext.options.needsAuxBuffer;
+ _needsSwizzleBuffer = shaderContext.options.needsSwizzleBuffer;
+ _needsBufferSizeBuffer = shaderContext.options.needsBufferSizeBuffer;
return func;
}
@@ -1241,6 +1281,7 @@
bool wasAdded = false;
MVKShaderLibraryCache* slCache = getShaderLibraryCache(shaderModule->getKey());
+ slCache->setShaderModule(shaderModule);
MVKShaderLibrary* shLib = slCache->getShaderLibrary(pContext, shaderModule, &wasAdded);
if (wasAdded) { markDirty(); }
return shLib;
@@ -1289,14 +1330,28 @@
void serialize(Archive & archive, SPIRVToMSLConverterOptions& opt) {
archive(opt.entryPointName,
opt.entryPointStage,
+ opt.tessPatchKind,
opt.mslVersion,
opt.texelBufferTextureWidth,
- opt.auxBufferIndex,
+ opt.swizzleBufferIndex,
+ opt.indirectParamsBufferIndex,
+ opt.outputBufferIndex,
+ opt.patchOutputBufferIndex,
+ opt.tessLevelBufferIndex,
+ opt.bufferSizeBufferIndex,
+ opt.inputThreadgroupMemIndex,
+ opt.numTessControlPoints,
opt.shouldFlipVertexY,
opt.isRenderingPoints,
opt.shouldSwizzleTextureSamples,
+ opt.shouldCaptureOutput,
+ opt.tessDomainOriginInLowerLeft,
opt.isRasterizationDisabled,
- opt.needsAuxBuffer);
+ opt.needsSwizzleBuffer,
+ opt.needsOutputBuffer,
+ opt.needsPatchOutputBuffer,
+ opt.needsBufferSizeBuffer,
+ opt.needsInputThreadgroupMem);
}
template<class Archive>
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
index d6fbbbe..b01add4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
@@ -55,9 +55,6 @@
/** Returns the Vulkan API opaque object controlling this object. */
MVKVulkanAPIObject* getVulkanAPIObject() override { return _owner->getVulkanAPIObject(); };
- /** Returns the Metal shader function, possibly specialized. */
- MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo);
-
/** Constructs an instance from the specified MSL source code. */
MVKShaderLibrary(MVKVulkanAPIDeviceObject* owner,
const std::string& mslSourceCode,
@@ -79,10 +76,14 @@
friend MVKShaderModule;
void propogateDebugName();
+ NSString* getDebugName();
+ void setShaderModule(MVKShaderModule* shaderModule);
+ MVKMTLFunction getMTLFunction(const VkSpecializationInfo* pSpecializationInfo);
void handleCompilationError(NSError* err, const char* opDesc);
MTLFunctionConstant* getFunctionConstant(NSArray<MTLFunctionConstant*>* mtlFCs, NSUInteger mtlFCID);
MVKVulkanAPIDeviceObject* _owner;
+ MVKShaderModule* _shaderModule = nullptr;
id<MTLLibrary> _mtlLibrary;
SPIRVEntryPoint _entryPoint;
std::string _msl;
@@ -110,6 +111,11 @@
MVKShaderLibrary* getShaderLibrary(SPIRVToMSLConverterContext* pContext,
MVKShaderModule* shaderModule,
bool* pWasAdded = nullptr);
+ /**
+ * Sets the shader module associated with this library cache.
+ * This is set after creation because libraries can be loaded from a pipeline cache.
+ */
+ void setShaderModule(MVKShaderModule* shaderModule);
MVKShaderLibraryCache(MVKVulkanAPIDeviceObject* owner) : _owner(owner) {};
@@ -128,6 +134,7 @@
void merge(MVKShaderLibraryCache* other);
MVKVulkanAPIDeviceObject* _owner;
+ MVKShaderModule* _shaderModule = nullptr;
std::vector<std::pair<SPIRVToMSLConverterContext, MVKShaderLibrary*>> _shaderLibraries;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
index 94f366f..974a29d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
@@ -31,7 +31,15 @@
#pragma mark -
#pragma mark MVKShaderLibrary
-void MVKShaderLibrary::propogateDebugName() { setLabelIfNotNil(_mtlLibrary, _owner->getDebugName()); }
+void MVKShaderLibrary::propogateDebugName() { setLabelIfNotNil(_mtlLibrary, getDebugName()); }
+
+// First choice is to name after shader module if it exists, otherwise name after owner.
+NSString* MVKShaderLibrary::getDebugName() {
+ NSString* dbName = _shaderModule ? _shaderModule-> getDebugName() : nil;
+ if (dbName) { return dbName; }
+
+ return _owner ? _owner-> getDebugName() : nil;
+}
// If the size of the workgroup dimension is specialized, extract it from the
// specialization info, otherwise use the value specified in the SPIR-V shader code.
@@ -89,11 +97,12 @@
fs->destroy();
}
}
- setLabelIfNotNil(mtlFunc, _owner->getDebugName());
} else {
reportError(VK_ERROR_INVALID_SHADER_NV, "Shader module does not contain an entry point named '%s'.", mtlFuncName.UTF8String);
}
+ setLabelIfNotNil(mtlFunc, getDebugName());
+
return { mtlFunc, MTLSizeMake(getWorkgroupDimensionSize(_entryPoint.workgroupSize.width, pSpecializationInfo),
getWorkgroupDimensionSize(_entryPoint.workgroupSize.height, pSpecializationInfo),
getWorkgroupDimensionSize(_entryPoint.workgroupSize.depth, pSpecializationInfo)) };
@@ -107,6 +116,13 @@
return nil;
}
+void MVKShaderLibrary::setShaderModule(MVKShaderModule* shaderModule) {
+ if (shaderModule == _shaderModule) { return; }
+
+ _shaderModule = shaderModule;
+ propogateDebugName();
+}
+
MVKShaderLibrary::MVKShaderLibrary(MVKVulkanAPIDeviceObject* owner, const string& mslSourceCode, const SPIRVEntryPoint& entryPoint) : _owner(owner) {
MVKShaderLibraryCompiler* slc = new MVKShaderLibraryCompiler(_owner);
_mtlLibrary = slc->newMTLLibrary(@(mslSourceCode.c_str())); // retained
@@ -140,6 +156,7 @@
_mtlLibrary = [other._mtlLibrary retain];
_entryPoint = other._entryPoint;
_msl = other._msl;
+ setShaderModule(other._shaderModule);
}
// If err object is nil, the compilation succeeded without any warnings.
@@ -204,6 +221,7 @@
const string& mslSourceCode,
const SPIRVEntryPoint& entryPoint) {
MVKShaderLibrary* shLib = new MVKShaderLibrary(_owner, mslSourceCode, entryPoint);
+ shLib->setShaderModule(_shaderModule);
_shaderLibraries.emplace_back(*pContext, shLib);
return shLib;
}
@@ -218,6 +236,13 @@
}
}
+void MVKShaderLibraryCache::setShaderModule(MVKShaderModule* shaderModule) {
+ if (shaderModule == _shaderModule) { return; }
+
+ _shaderModule = shaderModule;
+ for (auto& slPair : _shaderLibraries) { slPair.second->setShaderModule(_shaderModule); }
+}
+
MVKShaderLibraryCache::~MVKShaderLibraryCache() {
for (auto& slPair : _shaderLibraries) { slPair.second->destroy(); }
}
@@ -310,6 +335,7 @@
const VkShaderModuleCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device), _shaderLibraryCache(this) {
_defaultLibrary = nullptr;
+ _shaderLibraryCache.setShaderModule(this);
size_t codeSize = pCreateInfo->codeSize;
@@ -348,6 +374,7 @@
_spvConverter.setMSL(pMSLCode, nullptr);
_defaultLibrary = new MVKShaderLibrary(this, _spvConverter.getMSL().c_str(), _spvConverter.getEntryPoint());
+ _defaultLibrary->setShaderModule(this);
break;
}
@@ -362,6 +389,7 @@
_device->addActivityPerformance(_device->_performanceStatistics.shaderCompilation.hashShaderCode, startTime);
_defaultLibrary = new MVKShaderLibrary(this, (void*)(pMSLCode), mslCodeLen);
+ _defaultLibrary->setShaderModule(this);
break;
}
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
index ca8de1a..4258216 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
@@ -27,12 +27,6 @@
using namespace mvk;
using namespace std;
-// Verify that the spvAux structure used to pass auxilliary info between MoltenVK and SPIRV-Cross has not changed.
-#define MVK_SUPPORTED_MSL_AUX_BUFFER_STRUCT_VERSION 1
-#if MVK_SUPPORTED_MSL_AUX_BUFFER_STRUCT_VERSION != SPIRV_CROSS_MSL_AUX_BUFFER_STRUCT_VERSION
-# error "The version number of the MSL spvAux struct used to pass auxilliary info to shaders does not match between MoltenVK and SPIRV-Cross. If the spvAux struct definition is not the same between MoltenVK and shaders created by SPRIV-Cross, memory errors will occur."
-#endif
-
#pragma mark -
#pragma mark SPIRVToMSLConverterContext
@@ -48,11 +42,12 @@
if (entryPointStage != other.entryPointStage) { return false; }
if (mslVersion != other.mslVersion) { return false; }
if (texelBufferTextureWidth != other.texelBufferTextureWidth) { return false; }
- if (auxBufferIndex != other.auxBufferIndex) { return false; }
+ if (swizzleBufferIndex != other.swizzleBufferIndex) { return false; }
if (indirectParamsBufferIndex != other.indirectParamsBufferIndex) { return false; }
if (outputBufferIndex != other.outputBufferIndex) { return false; }
if (patchOutputBufferIndex != other.patchOutputBufferIndex) { return false; }
if (tessLevelBufferIndex != other.tessLevelBufferIndex) { return false; }
+ if (bufferSizeBufferIndex != other.bufferSizeBufferIndex) { return false; }
if (inputThreadgroupMemIndex != other.inputThreadgroupMemIndex) { return false; }
if (!!shouldFlipVertexY != !!other.shouldFlipVertexY) { return false; }
if (!!isRenderingPoints != !!other.isRenderingPoints) { return false; }
@@ -165,9 +160,10 @@
MVK_PUBLIC_SYMBOL void SPIRVToMSLConverterContext::alignWith(const SPIRVToMSLConverterContext& srcContext) {
options.isRasterizationDisabled = srcContext.options.isRasterizationDisabled;
- options.needsAuxBuffer = srcContext.options.needsAuxBuffer;
+ options.needsSwizzleBuffer = srcContext.options.needsSwizzleBuffer;
options.needsOutputBuffer = srcContext.options.needsOutputBuffer;
options.needsPatchOutputBuffer = srcContext.options.needsPatchOutputBuffer;
+ options.needsBufferSizeBuffer = srcContext.options.needsBufferSizeBuffer;
options.needsInputThreadgroupMem = srcContext.options.needsInputThreadgroupMem;
if (stageSupportsVertexAttributes()) {
@@ -249,11 +245,12 @@
mslOpts.platform = getCompilerMSLPlatform(context.options.platform);
mslOpts.msl_version = context.options.mslVersion;
mslOpts.texel_buffer_texture_width = context.options.texelBufferTextureWidth;
- mslOpts.aux_buffer_index = context.options.auxBufferIndex;
+ mslOpts.swizzle_buffer_index = context.options.swizzleBufferIndex;
mslOpts.indirect_params_buffer_index = context.options.indirectParamsBufferIndex;
mslOpts.shader_output_buffer_index = context.options.outputBufferIndex;
mslOpts.shader_patch_output_buffer_index = context.options.patchOutputBufferIndex;
mslOpts.shader_tess_factor_buffer_index = context.options.tessLevelBufferIndex;
+ mslOpts.buffer_size_buffer_index = context.options.bufferSizeBufferIndex;
mslOpts.shader_input_wg_index = context.options.inputThreadgroupMemIndex;
mslOpts.enable_point_size_builtin = context.options.isRenderingPoints;
mslOpts.disable_rasterization = context.options.isRasterizationDisabled;
@@ -324,9 +321,10 @@
// which vertex attributes and resource bindings are used by the shader
populateEntryPoint(_entryPoint, pMSLCompiler, context.options);
context.options.isRasterizationDisabled = pMSLCompiler && pMSLCompiler->get_is_rasterization_disabled();
- context.options.needsAuxBuffer = pMSLCompiler && pMSLCompiler->needs_aux_buffer();
+ context.options.needsSwizzleBuffer = pMSLCompiler && pMSLCompiler->needs_swizzle_buffer();
context.options.needsOutputBuffer = pMSLCompiler && pMSLCompiler->needs_output_buffer();
context.options.needsPatchOutputBuffer = pMSLCompiler && pMSLCompiler->needs_patch_output_buffer();
+ context.options.needsBufferSizeBuffer = pMSLCompiler && pMSLCompiler->needs_buffer_size_buffer();
context.options.needsInputThreadgroupMem = pMSLCompiler && pMSLCompiler->needs_input_threadgroup_mem();
if (context.stageSupportsVertexAttributes()) {
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
index 8a90dcc..61aa863 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
@@ -50,11 +50,12 @@
uint32_t mslVersion = makeMSLVersion(2, 1);
Platform platform = getNativePlatform();
uint32_t texelBufferTextureWidth = 4096;
- uint32_t auxBufferIndex = 0;
+ uint32_t swizzleBufferIndex = 0;
uint32_t indirectParamsBufferIndex = 0;
uint32_t outputBufferIndex = 0;
uint32_t patchOutputBufferIndex = 0;
uint32_t tessLevelBufferIndex = 0;
+ uint32_t bufferSizeBufferIndex = 0;
uint32_t inputThreadgroupMemIndex = 0;
uint32_t numTessControlPoints = 0;
bool shouldFlipVertexY = true;
@@ -64,9 +65,10 @@
bool tessDomainOriginInLowerLeft = false;
bool isRasterizationDisabled = false;
- bool needsAuxBuffer = false;
+ bool needsSwizzleBuffer = false;
bool needsOutputBuffer = false;
bool needsPatchOutputBuffer = false;
+ bool needsBufferSizeBuffer = false;
bool needsInputThreadgroupMem = false;
/**