Merge pull request #303 from cdavis5e/component-swizzle
Support arbitrary swizzles of image data.
This commit is contained in:
commit
91c1947889
@ -1 +1 @@
|
||||
c9210427b9ab547d41f1af804dedae581b382965
|
||||
cc5c0204d8bcdadbb4add03e53346df98bf27fa4
|
||||
|
@ -48,7 +48,7 @@ extern "C" {
|
||||
*/
|
||||
#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)
|
||||
|
@ -25,6 +25,8 @@
|
||||
class MVKCommandEncoder;
|
||||
class MVKOcclusionQueryPool;
|
||||
|
||||
struct MVKShaderAuxBufferBinding;
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark MVKCommandEncoderState
|
||||
@ -388,6 +390,16 @@ protected:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
_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 @@ protected:
|
||||
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 @@ public:
|
||||
/** 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 @@ protected:
|
||||
std::vector<MVKMTLBufferBinding> _bufferBindings;
|
||||
std::vector<MVKMTLTextureBinding> _textureBindings;
|
||||
std::vector<MVKMTLSamplerStateBinding> _samplerStateBindings;
|
||||
MVKMTLBufferBinding _auxBufferBinding;
|
||||
|
||||
bool _areBufferBindingsDirty = false;
|
||||
bool _areTextureBindingsDirty = false;
|
||||
|
@ -425,6 +425,15 @@ void MVKGraphicsResourcesCommandEncoderState::bindFragmentSamplerState(const MVK
|
||||
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 @@ void MVKGraphicsResourcesCommandEncoderState::markDirty() {
|
||||
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 @@ void MVKGraphicsResourcesCommandEncoderState::encodeImpl() {
|
||||
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 @@ void MVKGraphicsResourcesCommandEncoderState::resetImpl() {
|
||||
_fragmentTextureBindings.clear();
|
||||
_vertexSamplerStateBindings.clear();
|
||||
_fragmentSamplerStateBindings.clear();
|
||||
_vertexAuxBufferBinding.mtlBuffer = nil;
|
||||
_fragmentAuxBufferBinding.mtlBuffer = nil;
|
||||
|
||||
_areVertexBufferBindingsDirty = false;
|
||||
_areFragmentBufferBindingsDirty = false;
|
||||
@ -491,6 +532,8 @@ void MVKGraphicsResourcesCommandEncoderState::resetImpl() {
|
||||
_areFragmentTextureBindingsDirty = false;
|
||||
_areVertexSamplerStateBindingsDirty = false;
|
||||
_areFragmentSamplerStateBindingsDirty = false;
|
||||
_vertexAuxBufferBinding.isDirty = false;
|
||||
_fragmentAuxBufferBinding.isDirty = false;
|
||||
}
|
||||
|
||||
|
||||
@ -509,16 +552,30 @@ void MVKComputeResourcesCommandEncoderState::bindSamplerState(const MVKMTLSample
|
||||
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 @@ void MVKComputeResourcesCommandEncoderState::encodeImpl() {
|
||||
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 @@ void MVKComputeResourcesCommandEncoderState::resetImpl() {
|
||||
_bufferBindings.clear();
|
||||
_textureBindings.clear();
|
||||
_samplerStateBindings.clear();
|
||||
_auxBufferBinding.mtlBuffer = nil;
|
||||
|
||||
_areBufferBindingsDirty = false;
|
||||
_areTextureBindingsDirty = false;
|
||||
_areSamplerStateBindingsDirty = false;
|
||||
_auxBufferBinding.isDirty = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -100,6 +100,7 @@ public:
|
||||
|
||||
protected:
|
||||
friend class MVKDescriptorBinding;
|
||||
friend class MVKPipelineLayout;
|
||||
|
||||
VkResult initMetalResourceIndexOffsets(MVKShaderStageResourceBinding* pBindingIndexes,
|
||||
MVKShaderStageResourceBinding* pDescSetCounts,
|
||||
|
@ -111,6 +111,11 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
|
||||
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 @@ void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
|
||||
|
||||
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 @@ void MVKDescriptorSetLayoutBinding::push(MVKCommandEncoder* cmdEncoder,
|
||||
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 @@ void MVKDescriptorSetLayoutBinding::push(MVKCommandEncoder* cmdEncoder,
|
||||
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 @@ void MVKDescriptorSetLayoutBinding::push(MVKCommandEncoder* cmdEncoder,
|
||||
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;
|
||||
|
@ -261,6 +261,9 @@ public:
|
||||
/** 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 @@ public:
|
||||
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 @@ protected:
|
||||
std::mutex _lock;
|
||||
MTLPixelFormat _mtlPixelFormat;
|
||||
MTLTextureType _mtlTextureType;
|
||||
uint32_t _packedSwizzle;
|
||||
bool _useMTLTextureView;
|
||||
};
|
||||
|
||||
|
@ -702,10 +702,12 @@ MVKImageView::MVKImageView(MVKDevice* device, const VkImageViewCreateInfo* pCrea
|
||||
_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 @@ void MVKImageView::validateImageViewConfig(const VkImageViewCreateInfo* pCreateI
|
||||
// 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 @@ MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkCompon
|
||||
}
|
||||
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 @@ MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkCompon
|
||||
}
|
||||
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 @@ MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkCompon
|
||||
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 @@ MTLPixelFormat MVKImageView::getSwizzledMTLPixelFormat(VkFormat format, VkCompon
|
||||
}
|
||||
|
||||
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 @@ const char* MVKImageView::getSwizzleName(VkComponentSwizzle swizzle) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ bool MVKImageView::matchesSwizzle(VkComponentMapping components, VkComponentMapp
|
||||
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() {
|
||||
|
@ -33,6 +33,16 @@ class MVKCommandEncoder;
|
||||
class MVKPipelineCache;
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark MVKShaderAuxBufferBinding
|
||||
|
||||
struct MVKShaderAuxBufferBinding {
|
||||
uint32_t vertex;
|
||||
uint32_t fragment;
|
||||
uint32_t compute;
|
||||
};
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark MVKPipelineLayout
|
||||
|
||||
@ -61,6 +71,12 @@ public:
|
||||
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 @@ private:
|
||||
std::vector<MVKShaderResourceBinding> _dslMTLResourceIndexOffsets;
|
||||
std::vector<VkPushConstantRange> _pushConstants;
|
||||
MVKShaderResourceBinding _pushConstantsMTLResourceIndexOffsets;
|
||||
MVKShaderAuxBufferBinding _auxBufferIndex;
|
||||
uint32_t _numTextures;
|
||||
};
|
||||
|
||||
|
||||
@ -83,12 +101,17 @@ public:
|
||||
/** 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 @@ public:
|
||||
/** 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 @@ protected:
|
||||
|
||||
bool _dynamicStateEnabled[VK_DYNAMIC_STATE_RANGE_SIZE];
|
||||
bool _hasDepthStencilInfo;
|
||||
bool _needsVertexAuxBuffer;
|
||||
bool _needsFragmentAuxBuffer;
|
||||
};
|
||||
|
||||
|
||||
@ -152,6 +183,9 @@ public:
|
||||
/** 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 @@ protected:
|
||||
|
||||
id<MTLComputePipelineState> _mtlPipelineState;
|
||||
MTLSize _mtlThreadgroupSize;
|
||||
bool _needsAuxBuffer;
|
||||
};
|
||||
|
||||
|
||||
|
@ -107,6 +107,46 @@ void MVKPipelineLayout::populateShaderConverterContext(SPIRVToMSLConverterContex
|
||||
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 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
if (_device->_pFeatures->depthClamp) {
|
||||
[mtlCmdEnc setDepthClipMode: _mtlDepthClipMode];
|
||||
}
|
||||
|
||||
cmdEncoder->_graphicsResourcesState.bindAuxBuffer(_auxBuffer, _auxBufferIndex, _needsVertexAuxBuffer, _needsFragmentAuxBuffer);
|
||||
}
|
||||
|
||||
bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
|
||||
@ -295,6 +337,9 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
|
||||
|
||||
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* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
|
||||
|
||||
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 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
|
||||
// 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 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
|
||||
}
|
||||
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 @@ MTLRenderPipelineDescriptor* MVKGraphicsPipeline::getMTLRenderPipelineDescriptor
|
||||
}
|
||||
|
||||
// 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 @@ MVKGraphicsPipeline::~MVKGraphicsPipeline() {
|
||||
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 @@ MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
|
||||
} 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 @@ MVKMTLFunction MVKComputePipeline::getMTLFunction(const VkComputePipelineCreateI
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -201,9 +201,11 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConverterContext&
|
||||
|
||||
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 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConverterContext&
|
||||
// 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
|
||||
|
@ -37,10 +37,12 @@ namespace mvk {
|
||||
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user