Merge pull request #304 from cdavis5e/wolf2-packed-pixels
Correct MTLPixelFormats for a couple of formats.
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index 91450c6..6ab048f 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-c9210427b9ab547d41f1af804dedae581b382965
+cc5c0204d8bcdadbb4add03e53346df98bf27fa4
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index 72de183..d34b019 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -48,7 +48,7 @@
*/
#define MVK_VERSION_MAJOR 1
#define MVK_VERSION_MINOR 0
-#define MVK_VERSION_PATCH 23
+#define MVK_VERSION_PATCH 24
#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 8e54826..bd23b84 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -25,6 +25,8 @@
class MVKCommandEncoder;
class MVKOcclusionQueryPool;
+struct MVKShaderAuxBufferBinding;
+
#pragma mark -
#pragma mark MVKCommandEncoderState
@@ -388,6 +390,16 @@
}
}
}
+
+ struct AuxBuffer {
+ uint32_t swizzleConst[1];
+ };
+
+ // Updates the swizzle for an image in the given buffer.
+ void updateSwizzle(id<MTLBuffer> buffer, uint32_t index, uint32_t swizzle) {
+ auto* aux = (AuxBuffer*)buffer.contents;
+ aux->swizzleConst[index] = swizzle;
+ }
};
@@ -425,6 +437,9 @@
_mtlIndexBufferBinding = binding; // No need to track dirty state
}
+ /** Sets the current auxiliary buffer state. */
+ void bindAuxBuffer(id<MTLBuffer> buffer, const MVKShaderAuxBufferBinding& binding, bool needVertexAuxBuffer, bool needFragmentAuxBuffer);
+
#pragma mark Construction
@@ -442,6 +457,8 @@
std::vector<MVKMTLTextureBinding> _fragmentTextureBindings;
std::vector<MVKMTLSamplerStateBinding> _vertexSamplerStateBindings;
std::vector<MVKMTLSamplerStateBinding> _fragmentSamplerStateBindings;
+ MVKMTLBufferBinding _vertexAuxBufferBinding;
+ MVKMTLBufferBinding _fragmentAuxBufferBinding;
bool _areVertexBufferBindingsDirty = false;
bool _areFragmentBufferBindingsDirty = false;
@@ -469,6 +486,8 @@
/** Binds the specified sampler state. */
void bindSamplerState(const MVKMTLSamplerStateBinding& binding);
+ /** Sets the current auxiliary buffer state. */
+ void bindAuxBuffer(id<MTLBuffer> buffer, const MVKShaderAuxBufferBinding& binding);
#pragma mark Construction
@@ -483,6 +502,7 @@
std::vector<MVKMTLBufferBinding> _bufferBindings;
std::vector<MVKMTLTextureBinding> _textureBindings;
std::vector<MVKMTLSamplerStateBinding> _samplerStateBindings;
+ MVKMTLBufferBinding _auxBufferBinding;
bool _areBufferBindingsDirty = false;
bool _areTextureBindingsDirty = false;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index 4c560c1..a8ae908 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -425,6 +425,15 @@
bind(binding, _fragmentSamplerStateBindings, _areFragmentSamplerStateBindingsDirty);
}
+void MVKGraphicsResourcesCommandEncoderState::bindAuxBuffer(id<MTLBuffer> buffer, const MVKShaderAuxBufferBinding& binding, bool needVertexAuxBuffer, bool needFragmentAuxBuffer) {
+ _vertexAuxBufferBinding.mtlBuffer = needVertexAuxBuffer ? buffer : nil;
+ _vertexAuxBufferBinding.index = binding.vertex;
+ _vertexAuxBufferBinding.isDirty = needVertexAuxBuffer;
+ _fragmentAuxBufferBinding.mtlBuffer = needFragmentAuxBuffer ? buffer : nil;
+ _fragmentAuxBufferBinding.index = binding.fragment;
+ _fragmentAuxBufferBinding.isDirty = needFragmentAuxBuffer;
+}
+
// Mark everything as dirty
void MVKGraphicsResourcesCommandEncoderState::markDirty() {
MVKCommandEncoderState::markDirty();
@@ -434,10 +443,26 @@
MVKResourcesCommandEncoderState::markDirty(_fragmentTextureBindings, _areFragmentTextureBindingsDirty);
MVKResourcesCommandEncoderState::markDirty(_vertexSamplerStateBindings, _areVertexSamplerStateBindingsDirty);
MVKResourcesCommandEncoderState::markDirty(_fragmentSamplerStateBindings, _areFragmentSamplerStateBindingsDirty);
+ _vertexAuxBufferBinding.isDirty = true;
+ _fragmentAuxBufferBinding.isDirty = true;
}
void MVKGraphicsResourcesCommandEncoderState::encodeImpl() {
+ if (_vertexAuxBufferBinding.mtlBuffer) {
+ for (auto& b : _vertexTextureBindings) {
+ if (b.isDirty)
+ updateSwizzle(_vertexAuxBufferBinding.mtlBuffer, b.index, b.swizzle);
+ }
+ }
+
+ if (_fragmentAuxBufferBinding.mtlBuffer) {
+ for (auto& b : _fragmentTextureBindings) {
+ if (b.isDirty)
+ updateSwizzle(_fragmentAuxBufferBinding.mtlBuffer, b.index, b.swizzle);
+ }
+ }
+
encodeBinding<MVKMTLBufferBinding>(_vertexBufferBindings, _areVertexBufferBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
[cmdEncoder->_mtlRenderEncoder setVertexBuffer: b.mtlBuffer
@@ -452,6 +477,20 @@
atIndex: b.index];
});
+ if (_vertexAuxBufferBinding.isDirty) {
+ _vertexAuxBufferBinding.isDirty = false;
+ [_cmdEncoder->_mtlRenderEncoder setVertexBuffer: _vertexAuxBufferBinding.mtlBuffer
+ offset: 0
+ atIndex: _vertexAuxBufferBinding.index];
+ }
+
+ if (_fragmentAuxBufferBinding.isDirty) {
+ _fragmentAuxBufferBinding.isDirty = false;
+ [_cmdEncoder->_mtlRenderEncoder setFragmentBuffer: _fragmentAuxBufferBinding.mtlBuffer
+ offset: 0
+ atIndex: _fragmentAuxBufferBinding.index];
+ }
+
encodeBinding<MVKMTLTextureBinding>(_vertexTextureBindings, _areVertexTextureBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
[cmdEncoder->_mtlRenderEncoder setVertexTexture: b.mtlTexture
@@ -484,6 +523,8 @@
_fragmentTextureBindings.clear();
_vertexSamplerStateBindings.clear();
_fragmentSamplerStateBindings.clear();
+ _vertexAuxBufferBinding.mtlBuffer = nil;
+ _fragmentAuxBufferBinding.mtlBuffer = nil;
_areVertexBufferBindingsDirty = false;
_areFragmentBufferBindingsDirty = false;
@@ -491,6 +532,8 @@
_areFragmentTextureBindingsDirty = false;
_areVertexSamplerStateBindingsDirty = false;
_areFragmentSamplerStateBindingsDirty = false;
+ _vertexAuxBufferBinding.isDirty = false;
+ _fragmentAuxBufferBinding.isDirty = false;
}
@@ -509,16 +552,30 @@
bind(binding, _samplerStateBindings, _areSamplerStateBindingsDirty);
}
+void MVKComputeResourcesCommandEncoderState::bindAuxBuffer(id<MTLBuffer> buffer, const MVKShaderAuxBufferBinding& binding) {
+ _auxBufferBinding.mtlBuffer = buffer;
+ _auxBufferBinding.index = binding.compute;
+ _auxBufferBinding.isDirty = buffer != nil;
+}
+
// Mark everything as dirty
void MVKComputeResourcesCommandEncoderState::markDirty() {
MVKCommandEncoderState::markDirty();
MVKResourcesCommandEncoderState::markDirty(_bufferBindings, _areBufferBindingsDirty);
MVKResourcesCommandEncoderState::markDirty(_textureBindings, _areTextureBindingsDirty);
MVKResourcesCommandEncoderState::markDirty(_samplerStateBindings, _areSamplerStateBindingsDirty);
+ _auxBufferBinding.isDirty = true;
}
void MVKComputeResourcesCommandEncoderState::encodeImpl() {
+ if (_auxBufferBinding.mtlBuffer) {
+ for (auto& b : _textureBindings) {
+ if (b.isDirty)
+ updateSwizzle(_auxBufferBinding.mtlBuffer, b.index, b.swizzle);
+ }
+ }
+
encodeBinding<MVKMTLBufferBinding>(_bufferBindings, _areBufferBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setBuffer: b.mtlBuffer
@@ -526,6 +583,13 @@
atIndex: b.index];
});
+ if (_auxBufferBinding.isDirty) {
+ _auxBufferBinding.isDirty = false;
+ [_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setBuffer: _auxBufferBinding.mtlBuffer
+ offset: 0
+ atIndex: _auxBufferBinding.index];
+ }
+
encodeBinding<MVKMTLTextureBinding>(_textureBindings, _areTextureBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setTexture: b.mtlTexture
@@ -543,10 +607,12 @@
_bufferBindings.clear();
_textureBindings.clear();
_samplerStateBindings.clear();
+ _auxBufferBinding.mtlBuffer = nil;
_areBufferBindingsDirty = false;
_areTextureBindingsDirty = false;
_areSamplerStateBindingsDirty = false;
+ _auxBufferBinding.isDirty = false;
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
index 140f12e..ddb615a 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLResourceBindings.h
@@ -24,6 +24,7 @@
typedef struct {
union { id<MTLTexture> mtlTexture = nil; id<MTLTexture> mtlResource; }; // aliases
uint32_t index = 0;
+ uint32_t swizzle = 0;
bool isDirty = true;
} MVKMTLTextureBinding;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index d2c0f79..71e9f1f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -100,6 +100,7 @@
protected:
friend class MVKDescriptorBinding;
+ friend class MVKPipelineLayout;
VkResult initMetalResourceIndexOffsets(MVKShaderStageResourceBinding* pBindingIndexes,
MVKShaderStageResourceBinding* pDescSetCounts,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index a8367e2..909b665 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -111,6 +111,11 @@
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {
tb.mtlTexture = descBinding._mtlTextures[rezIdx];
+ if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && tb.mtlTexture) {
+ tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle();
+ } else {
+ tb.swizzle = 0;
+ }
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexTexture(tb);
@@ -145,6 +150,11 @@
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
tb.mtlTexture = descBinding._mtlTextures[rezIdx];
+ if (tb.mtlTexture) {
+ tb.swizzle = ((MVKImageView*)descBinding._imageBindings[rezIdx].imageView)->getPackedSwizzle();
+ } else {
+ tb.swizzle = 0;
+ }
sb.mtlSamplerState = descBinding._mtlSamplers[rezIdx];
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
@@ -243,6 +253,11 @@
const auto& imageInfo = get<VkDescriptorImageInfo>(pData, stride, rezIdx - dstArrayElement);
MVKImageView* imageView = (MVKImageView*)imageInfo.imageView;
tb.mtlTexture = imageView->getMTLTexture();
+ if (_info.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE && imageView) {
+ tb.swizzle = imageView->getPackedSwizzle();
+ } else {
+ tb.swizzle = 0;
+ }
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexTexture(tb);
@@ -262,6 +277,7 @@
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: {
auto* bufferView = get<MVKBufferView*>(pData, stride, rezIdx - dstArrayElement);
tb.mtlTexture = bufferView->getMTLTexture();
+ tb.swizzle = 0;
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
cmdEncoder->_graphicsResourcesState.bindVertexTexture(tb);
@@ -304,6 +320,11 @@
MVKImageView* imageView = (MVKImageView*)imageInfo.imageView;
MVKSampler* sampler = _immutableSamplers.empty() ? (MVKSampler*)imageInfo.sampler : _immutableSamplers[rezIdx];
tb.mtlTexture = imageView->getMTLTexture();
+ if (imageView) {
+ tb.swizzle = imageView->getPackedSwizzle();
+ } else {
+ tb.swizzle = 0;
+ }
sb.mtlSamplerState = sampler->getMTLSamplerState();
if (_applyToVertexStage) {
tb.index = mtlIdxs.vertexStage.textureIndex + rezIdx;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index c68cc77..9c3c98b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -261,6 +261,9 @@
/** Returns the Metal texture type of this image view. */
inline MTLTextureType getMTLTextureType() { return _mtlTextureType; }
+ /** Returns the packed component swizzle of this image view. */
+ inline uint32_t getPackedSwizzle() { return _packedSwizzle; }
+
/**
* Populates the texture of the specified render pass descriptor
* with the Metal texture underlying this image.
@@ -283,10 +286,10 @@
protected:
id<MTLTexture> newMTLTexture();
void initMTLTextureViewSupport();
- MTLPixelFormat getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components);
+ MTLPixelFormat getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components, bool& useSwizzle);
bool matchesSwizzle(VkComponentMapping components, VkComponentMapping pattern);
const char* getSwizzleName(VkComponentSwizzle swizzle);
- void setSwizzleFormatError(VkFormat format, VkComponentMapping components);
+ uint32_t packSwizzle(VkComponentMapping components);
void validateImageViewConfig(const VkImageViewCreateInfo* pCreateInfo);
MVKImage* _image;
@@ -296,6 +299,7 @@
std::mutex _lock;
MTLPixelFormat _mtlPixelFormat;
MTLTextureType _mtlTextureType;
+ uint32_t _packedSwizzle;
bool _useMTLTextureView;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 8d936a5..3e0703b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -702,10 +702,12 @@
_subresourceRange.layerCount = _image->getLayerCount() - _subresourceRange.baseArrayLayer;
}
+ bool useSwizzle;
_mtlTexture = nil;
- _mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components);
+ _mtlPixelFormat = getSwizzledMTLPixelFormat(pCreateInfo->format, pCreateInfo->components, useSwizzle);
_mtlTextureType = mvkMTLTextureTypeFromVkImageViewType(pCreateInfo->viewType, (_image->getSampleCount() != VK_SAMPLE_COUNT_1_BIT));
initMTLTextureViewSupport();
+ _packedSwizzle = useSwizzle ? packSwizzle(pCreateInfo->components) : 0;
}
// Validate whether the image view configuration can be supported
@@ -731,9 +733,10 @@
// Metal does not support general per-texture swizzles, and so this function relies on a few coincidental
// alignments of existing MTLPixelFormats of the same structure. If swizzling is not possible for a
// particular combination of format and swizzle spec, the original MTLPixelFormat is returned.
-MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components) {
+MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkComponentMapping components, bool& useSwizzle) {
MTLPixelFormat mtlPF = mtlPixelFormatFromVkFormat(format);
+ useSwizzle = false;
switch (mtlPF) {
case MTLPixelFormatR8Unorm:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_R} ) ) {
@@ -741,16 +744,6 @@
}
break;
- case MTLPixelFormatR8Snorm:
-#if MVK_IOS
- case MTLPixelFormatR8Unorm_sRGB:
-#endif
- if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_ZERO, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_R} ) ) {
- setSwizzleFormatError(format, components);
- return MTLPixelFormatA8Unorm;
- }
- break;
-
case MTLPixelFormatA8Unorm:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_ZERO} ) ) {
return MTLPixelFormatR8Unorm;
@@ -769,13 +762,6 @@
}
break;
- case MTLPixelFormatRGBA8Snorm:
- if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A} ) ) {
- setSwizzleFormatError(format, components);
- return MTLPixelFormatBGRA8Unorm;
- }
- break;
-
case MTLPixelFormatBGRA8Unorm:
if (matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A} ) ) {
return MTLPixelFormatRGBA8Unorm;
@@ -789,16 +775,20 @@
break;
case MTLPixelFormatDepth32Float_Stencil8:
- if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT &&
- matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM} ) ) {
+ if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
+ if (!matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM} ) ) {
+ useSwizzle = true;
+ }
return MTLPixelFormatX32_Stencil8;
}
break;
#if MVK_MACOS
case MTLPixelFormatDepth24Unorm_Stencil8:
- if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT &&
- matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM} ) ) {
+ if (_subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
+ if (!matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM, VK_COMPONENT_SWIZZLE_MAX_ENUM} ) ) {
+ useSwizzle = true;
+ }
return MTLPixelFormatX24_Stencil8;
}
break;
@@ -809,7 +799,7 @@
}
if ( !matchesSwizzle(components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A} ) ) {
- setSwizzleFormatError(format, components);
+ useSwizzle = true;
}
return mtlPF;
}
@@ -827,17 +817,6 @@
}
}
-// Sets a standard swizzle format error during instance construction.
-void MVKImageView::setSwizzleFormatError(VkFormat format, VkComponentMapping components) {
- setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_FORMAT_NOT_SUPPORTED,
- "VkImageView format %s and swizzle (%s, %s, %s, %s) does not map to a valid MTLPixelFormat.\n",
- mvkVkFormatName(format),
- getSwizzleName(components.r),
- getSwizzleName(components.g),
- getSwizzleName(components.b),
- getSwizzleName(components.a)));
-}
-
// Returns whether the swizzle components of the internal VkComponentMapping matches the
// swizzle pattern, by comparing corresponding elements of the two structures. The pattern
// supports wildcards, in that any element of pattern can be set to VK_COMPONENT_SWIZZLE_MAX_ENUM
@@ -855,6 +834,12 @@
return true;
}
+// Packs a VkComponentMapping structure into a single 32-bit word.
+uint32_t MVKImageView::packSwizzle(VkComponentMapping components) {
+ return ((components.r & 0xFF) << 0) | ((components.g & 0xFF) << 8) |
+ ((components.b & 0xFF) << 16) | ((components.a & 0xFF) << 24);
+}
+
// Determine whether this image view should use a Metal texture view,
// and set the _useMTLTextureView variable appropriately.
void MVKImageView::initMTLTextureViewSupport() {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 951b153..d6e0557 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -34,6 +34,16 @@
#pragma mark -
+#pragma mark MVKShaderAuxBufferBinding
+
+struct MVKShaderAuxBufferBinding {
+ uint32_t vertex;
+ uint32_t fragment;
+ uint32_t compute;
+};
+
+
+#pragma mark -
#pragma mark MVKPipelineLayout
/** Represents a Vulkan pipeline layout. */
@@ -61,6 +71,12 @@
uint32_t set,
const void* pData);
+ /** Returns the current auxiliary buffer bindings. */
+ const MVKShaderAuxBufferBinding& getAuxBufferIndex() { return _auxBufferIndex; }
+
+ /** Returns the number of textures in this layout. This is used to calculate the size of the auxiliary buffer. */
+ uint32_t getNumTextures() { return _numTextures; }
+
/** Constructs an instance for the specified device. */
MVKPipelineLayout(MVKDevice* device, const VkPipelineLayoutCreateInfo* pCreateInfo);
@@ -69,6 +85,8 @@
std::vector<MVKShaderResourceBinding> _dslMTLResourceIndexOffsets;
std::vector<VkPushConstantRange> _pushConstants;
MVKShaderResourceBinding _pushConstantsMTLResourceIndexOffsets;
+ MVKShaderAuxBufferBinding _auxBufferIndex;
+ uint32_t _numTextures;
};
@@ -83,12 +101,17 @@
/** Binds this pipeline to the specified command encoder. */
virtual void encode(MVKCommandEncoder* cmdEncoder) = 0;
+ /** Returns the current auxiliary buffer bindings. */
+ const MVKShaderAuxBufferBinding& getAuxBufferIndex() { return _auxBufferIndex; }
+
/** Constructs an instance for the device. layout, and parent (which may be NULL). */
MVKPipeline(MVKDevice* device, MVKPipelineCache* pipelineCache, MVKPipeline* parent) : MVKBaseDeviceObject(device),
_pipelineCache(pipelineCache) {}
protected:
MVKPipelineCache* _pipelineCache;
+ MVKShaderAuxBufferBinding _auxBufferIndex;
+ id<MTLBuffer> _auxBuffer = nil;
};
@@ -107,6 +130,12 @@
/** Returns whether this pipeline permits dynamic setting of the specifie state. */
bool supportsDynamicState(VkDynamicState state);
+ /** Returns whether or not the vertex shader needs a buffer to hold auxiliary state. */
+ bool needsVertexAuxBuffer() { return _needsVertexAuxBuffer; }
+
+ /** Returns whether or not the fragment shader needs a buffer to hold auxiliary state. */
+ bool needsFragmentAuxBuffer() { return _needsFragmentAuxBuffer; }
+
/** Constructs an instance for the device and parent (which may be NULL). */
MVKGraphicsPipeline(MVKDevice* device,
MVKPipelineCache* pipelineCache,
@@ -138,6 +167,8 @@
bool _dynamicStateEnabled[VK_DYNAMIC_STATE_RANGE_SIZE];
bool _hasDepthStencilInfo;
+ bool _needsVertexAuxBuffer;
+ bool _needsFragmentAuxBuffer;
};
@@ -152,6 +183,9 @@
/** Binds this pipeline to the specified command encoder. */
void encode(MVKCommandEncoder* cmdEncoder) override;
+ /** Returns whether or not the compute shader needs a buffer to hold auxiliary state. */
+ bool needsAuxBuffer() { return _needsAuxBuffer; }
+
/** Constructs an instance for the device and parent (which may be NULL). */
MVKComputePipeline(MVKDevice* device,
MVKPipelineCache* pipelineCache,
@@ -165,6 +199,7 @@
id<MTLComputePipelineState> _mtlPipelineState;
MTLSize _mtlThreadgroupSize;
+ bool _needsAuxBuffer;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index eeb209d..c35e66c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -107,6 +107,46 @@
spv::ExecutionModelGLCompute,
kPushConstDescSet,
kPushConstBinding);
+
+ // Scan the resource bindings, looking for an unused buffer index.
+ // FIXME: If we ever encounter a device that supports more than 31 buffer
+ // bindings, we'll need to update this code.
+ unordered_map<uint32_t, uint32_t> freeBufferMasks;
+ freeBufferMasks[spv::ExecutionModelVertex] = freeBufferMasks[spv::ExecutionModelFragment] = freeBufferMasks[spv::ExecutionModelGLCompute] = (1 << _device->_pMetalFeatures->maxPerStageBufferCount) - 1;
+ _numTextures = 0;
+ for (auto& binding : context.resourceBindings) {
+ if (binding.descriptorSet == kPushConstDescSet && binding.binding == kPushConstBinding) {
+ // This is the special push constant buffer.
+ freeBufferMasks[binding.stage] &= ~(1 << binding.mslBuffer);
+ continue;
+ }
+ VkDescriptorType descriptorType = _descriptorSetLayouts[binding.descriptorSet]._bindings[binding.binding]._info.descriptorType;
+ switch (descriptorType) {
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ // This buffer is being used.
+ freeBufferMasks[binding.stage] &= ~(1 << binding.mslBuffer);
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ // If it results in a texture binding, we need to account for it so
+ // we know how big to make the auxiliary buffer.
+ if (binding.mslTexture + 1 > _numTextures)
+ _numTextures = binding.mslTexture + 1;
+ break;
+ default:
+ break;
+ }
+ }
+ // Pick the lowest index that isn't used.
+ _auxBufferIndex.vertex = ffs(freeBufferMasks[spv::ExecutionModelVertex]) - 1;
+ _auxBufferIndex.fragment = ffs(freeBufferMasks[spv::ExecutionModelFragment]) - 1;
+ _auxBufferIndex.compute = ffs(freeBufferMasks[spv::ExecutionModelGLCompute]) - 1;
}
MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
@@ -174,6 +214,8 @@
if (_device->_pFeatures->depthClamp) {
[mtlCmdEnc setDepthClipMode: _mtlDepthClipMode];
}
+
+ cmdEncoder->_graphicsResourcesState.bindAuxBuffer(_auxBuffer, _auxBufferIndex, _needsVertexAuxBuffer, _needsFragmentAuxBuffer);
}
bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
@@ -295,6 +337,9 @@
SPIRVToMSLConverterContext shaderContext;
initMVKShaderConverterContext(shaderContext, pCreateInfo);
+ auto* mvkLayout = (MVKPipelineLayout*)pCreateInfo->layout;
+ _auxBufferIndex = mvkLayout->getAuxBufferIndex();
+ uint32_t auxBufferSize = sizeof(uint32_t) * mvkLayout->getNumTextures();
// Retrieve the render subpass for which this pipeline is being constructed
MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass;
@@ -302,6 +347,8 @@
MTLRenderPipelineDescriptor* plDesc = [[MTLRenderPipelineDescriptor new] autorelease];
+ uint32_t vbCnt = pCreateInfo->pVertexInputState->vertexBindingDescriptionCount;
+
// Add shader stages
for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
const VkPipelineShaderStageCreateInfo* pSS = &pCreateInfo->pStages[i];
@@ -312,6 +359,7 @@
// Vertex shader
if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_VERTEX_BIT)) {
shaderContext.options.entryPointStage = spv::ExecutionModelVertex;
+ shaderContext.options.auxBufferIndex = _auxBufferIndex.vertex;
id<MTLFunction> mtlFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction;
if ( !mtlFunction ) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader function could not be compiled into pipeline. See previous error."));
@@ -319,19 +367,36 @@
}
plDesc.vertexFunction = mtlFunction;
plDesc.rasterizationEnabled = !shaderContext.options.isRasterizationDisabled;
+ _needsVertexAuxBuffer = shaderContext.options.needsAuxBuffer;
+ // If we need the auxiliary buffer and there's no place to put it,
+ // we're in serious trouble.
+ if (_needsVertexAuxBuffer && (_auxBufferIndex.vertex == ~0u || _auxBufferIndex.vertex >= _device->_pMetalFeatures->maxPerStageBufferCount - vbCnt) ) {
+ setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Vertex shader requires auxiliary buffer, but there is no free slot to pass it."));
+ return nil;
+ }
}
// Fragment shader
if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_FRAGMENT_BIT)) {
shaderContext.options.entryPointStage = spv::ExecutionModelFragment;
+ shaderContext.options.auxBufferIndex = _auxBufferIndex.fragment;
id<MTLFunction> mtlFunction = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache).mtlFunction;
if ( !mtlFunction ) {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Fragment shader function could not be compiled into pipeline. See previous error."));
}
plDesc.fragmentFunction = mtlFunction;
+ _needsFragmentAuxBuffer = shaderContext.options.needsAuxBuffer;
+ if (_needsFragmentAuxBuffer && _auxBufferIndex.fragment == ~0u) {
+ setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Fragment shader requires auxiliary buffer, but there is no free slot to pass it."));
+ return nil;
+ }
}
}
+ if (_needsVertexAuxBuffer || _needsFragmentAuxBuffer) {
+ _auxBuffer = [_device->getMTLDevice() newBufferWithLength: auxBufferSize options: MTLResourceStorageModeShared];
+ }
+
// Vertex attributes
uint32_t vaCnt = pCreateInfo->pVertexInputState->vertexAttributeDescriptionCount;
for (uint32_t i = 0; i < vaCnt; i++) {
@@ -345,7 +410,6 @@
}
// Vertex buffer bindings
- uint32_t vbCnt = pCreateInfo->pVertexInputState->vertexBindingDescriptionCount;
for (uint32_t i = 0; i < vbCnt; i++) {
const VkVertexInputBindingDescription* pVKVB = &pCreateInfo->pVertexInputState->pVertexBindingDescriptions[i];
uint32_t vbIdx = _device->getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
@@ -481,6 +545,7 @@
void MVKComputePipeline::encode(MVKCommandEncoder* cmdEncoder) {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setComputePipelineState: _mtlPipelineState];
cmdEncoder->_mtlThreadgroupSize = _mtlThreadgroupSize;
+ cmdEncoder->_computeResourcesState.bindAuxBuffer(_auxBuffer, _auxBufferIndex);
}
MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
@@ -499,6 +564,10 @@
} else {
setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Compute shader function could not be compiled into pipeline. See previous error."));
}
+
+ if (_needsAuxBuffer && _auxBufferIndex.compute == ~0u) {
+ setConfigurationResult(mvkNotifyErrorWithText(VK_ERROR_INITIALIZATION_FAILED, "Compute shader requires auxiliary buffer, but there is no free slot to pass it."));
+ }
}
// Returns a MTLFunction to use when creating the MTLComputePipelineState.
@@ -514,9 +583,17 @@
MVKPipelineLayout* layout = (MVKPipelineLayout*)pCreateInfo->layout;
layout->populateShaderConverterContext(shaderContext);
+ _auxBufferIndex = layout->getAuxBufferIndex();
+ uint32_t auxBufferSize = sizeof(uint32_t) * layout->getNumTextures();
+ shaderContext.options.auxBufferIndex = _auxBufferIndex.compute;
MVKShaderModule* mvkShdrMod = (MVKShaderModule*)pSS->module;
- return mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache);
+ auto func = mvkShdrMod->getMTLFunction(&shaderContext, pSS->pSpecializationInfo, _pipelineCache);
+ _needsAuxBuffer = shaderContext.options.needsAuxBuffer;
+ if (_needsAuxBuffer) {
+ _auxBuffer = [_device->getMTLDevice() newBufferWithLength: auxBufferSize options: MTLResourceStorageModeShared];
+ }
+ return func;
}
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
index 9c131bf..2b8040a 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
@@ -201,9 +201,11 @@
mslOpts.msl_version = context.options.mslVersion;
mslOpts.texel_buffer_texture_width = context.options.texelBufferTextureWidth;
+ mslOpts.aux_buffer_index = context.options.auxBufferIndex;
mslOpts.enable_point_size_builtin = context.options.isRenderingPoints;
mslOpts.disable_rasterization = context.options.isRasterizationDisabled;
mslOpts.resolve_specialized_array_lengths = true;
+ mslOpts.swizzle_texture_samples = true;
pMSLCompiler->set_msl_options(mslOpts);
auto scOpts = pMSLCompiler->get_common_options();
@@ -229,6 +231,7 @@
// Populate content extracted from the SPRI-V compiler.
populateEntryPoint(_entryPoint, pMSLCompiler, context.options);
context.options.isRasterizationDisabled = pMSLCompiler && pMSLCompiler->get_is_rasterization_disabled();
+ context.options.needsAuxBuffer = pMSLCompiler && pMSLCompiler->needs_aux_buffer();
delete pMSLCompiler;
// Copy whether the vertex attributes and resource bindings are used by the shader
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
index 25b6c3e..751e752 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
@@ -37,10 +37,12 @@
uint32_t mslVersion = makeMSLVersion(2);
uint32_t texelBufferTextureWidth = 4096;
+ uint32_t auxBufferIndex = 0;
bool shouldFlipVertexY = true;
bool isRenderingPoints = false;
bool isRasterizationDisabled = false;
+ bool needsAuxBuffer = false;
/**
* Returns whether the specified options match this one.