Merge branch 'master' of https://github.com/billhollings/MoltenVK into xcode12
This commit is contained in:
commit
f3b6b9c582
@ -18,6 +18,8 @@ MoltenVK 1.1.0
|
||||
|
||||
Released 2020/09/28
|
||||
|
||||
>**_Note:_** This release contains changes to library paths and framework linking options.
|
||||
|
||||
- Add support for Vulkan 1.1, including:
|
||||
- The `vkEnumerateInstanceVersion()` function
|
||||
- The `vkGetDeviceQueue2()` function
|
||||
@ -38,6 +40,12 @@ Released 2020/09/28
|
||||
future `MTLSharedEvent` Vulkan extension)
|
||||
- `VK_KHR_multiview`
|
||||
- Remove support for obsolete `VK_EXTX_portability_subset` extension.
|
||||
- Redesign build and linking options that leverage newer framework technology:
|
||||
- Add comprehensive support for multi-platform, multi-architecture `XCFrameworks`.
|
||||
- Build fat single-platform, multi-architecture `dylibs`.
|
||||
- Add support for *Apple Silicon* builds for *macOS* and *Simulators*.
|
||||
- Remove support for distinct legacy frameworks and static libraries.
|
||||
- Remove support for fat libraries and frameworks that span device and simulators.
|
||||
- Improve performance of tessellation control pipeline stage by processing multiple
|
||||
patches per workgroup.
|
||||
- `vkCmdBindDescriptorSets` order `pDynamicOffsets` by descriptor binding number
|
||||
|
@ -620,6 +620,7 @@ typedef struct {
|
||||
VkBool32 sharedLinearTextures; /**< If true, linear textures and texture buffers can be created from buffers in Shared storage. */
|
||||
VkBool32 depthResolve; /**< If true, resolving depth textures with filters other than Sample0 is supported. */
|
||||
VkBool32 stencilResolve; /**< If true, resolving stencil textures with filters other than Sample0 is supported. */
|
||||
uint32_t maxPerStageDynamicMTLBufferCount; /**< The maximum number of inline buffers that can be set on a command buffer. */
|
||||
} MVKPhysicalDeviceMetalFeatures;
|
||||
|
||||
/** MoltenVK performance of a particular type of activity. */
|
||||
|
@ -298,10 +298,10 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: {
|
||||
auto* inlineUniformBlockProps = (VkPhysicalDeviceInlineUniformBlockPropertiesEXT*)next;
|
||||
inlineUniformBlockProps->maxInlineUniformBlockSize = _metalFeatures.dynamicMTLBufferSize;
|
||||
inlineUniformBlockProps->maxPerStageDescriptorInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
|
||||
inlineUniformBlockProps->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
|
||||
inlineUniformBlockProps->maxDescriptorSetInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
|
||||
inlineUniformBlockProps->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
|
||||
inlineUniformBlockProps->maxPerStageDescriptorInlineUniformBlocks = _metalFeatures.dynamicMTLBufferSize ? _metalFeatures.maxPerStageDynamicMTLBufferCount - 1 : 0; // Less one for push constants
|
||||
inlineUniformBlockProps->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = inlineUniformBlockProps->maxPerStageDescriptorInlineUniformBlocks;
|
||||
inlineUniformBlockProps->maxDescriptorSetInlineUniformBlocks = (inlineUniformBlockProps->maxPerStageDescriptorInlineUniformBlocks * 4);
|
||||
inlineUniformBlockProps->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = (inlineUniformBlockProps->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks * 4);
|
||||
break;
|
||||
}
|
||||
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: {
|
||||
@ -412,6 +412,8 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
|
||||
|
||||
if ( !pImageFormatProperties ) { return VK_SUCCESS; }
|
||||
|
||||
mvkClear(pImageFormatProperties);
|
||||
|
||||
// Metal does not support creating uncompressed views of compressed formats.
|
||||
// Metal does not support split-instance images.
|
||||
if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT | VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT)) {
|
||||
@ -419,11 +421,19 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
|
||||
}
|
||||
|
||||
MVKFormatType mvkFmt = _pixelFormats.getFormatType(format);
|
||||
bool isChromaSubsampled = _pixelFormats.getChromaSubsamplingPlaneCount(format) > 0;
|
||||
bool isMultiPlanar = _pixelFormats.getChromaSubsamplingPlaneCount(format) > 1;
|
||||
bool isBGRG = isChromaSubsampled && !isMultiPlanar && _pixelFormats.getBlockTexelSize(format).width > 1;
|
||||
bool hasAttachmentUsage = mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT));
|
||||
|
||||
// Disjoint memory requires a multiplanar format.
|
||||
if (!isMultiPlanar && mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_DISJOINT_BIT)) {
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceLimits* pLimits = &_properties.limits;
|
||||
VkExtent3D maxExt = { 1, 1, 1};
|
||||
uint32_t maxLevels = 1;
|
||||
@ -436,10 +446,7 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
|
||||
case VK_IMAGE_TYPE_1D:
|
||||
maxExt.height = 1;
|
||||
maxExt.depth = 1;
|
||||
if (mvkTreatTexture1DAs2D()) {
|
||||
maxExt.width = pLimits->maxImageDimension2D;
|
||||
maxLevels = mvkMipmapLevels3D(maxExt);
|
||||
} else {
|
||||
if (!mvkTreatTexture1DAs2D()) {
|
||||
maxExt.width = pLimits->maxImageDimension1D;
|
||||
maxLevels = 1;
|
||||
sampleCounts = VK_SAMPLE_COUNT_1_BIT;
|
||||
@ -453,29 +460,42 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
|
||||
// Metal does not allow compressed or depth/stencil formats on native 1D textures
|
||||
if (mvkFmt == kMVKFormatDepthStencil) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
|
||||
if (mvkFmt == kMVKFormatCompressed) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
|
||||
if (isChromaSubsampled) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// A 420 1D image doesn't make much sense.
|
||||
if (isChromaSubsampled && _pixelFormats.getBlockTexelSize(format).height > 1) {
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
// Vulkan doesn't allow 1D multisampled images.
|
||||
sampleCounts = VK_SAMPLE_COUNT_1_BIT;
|
||||
/* fallthrough */
|
||||
case VK_IMAGE_TYPE_2D:
|
||||
if (mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ) {
|
||||
// Chroma-subsampled cube images aren't supported.
|
||||
if (isChromaSubsampled) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
|
||||
// 1D cube images aren't supported.
|
||||
if (type == VK_IMAGE_TYPE_1D) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
|
||||
maxExt.width = pLimits->maxImageDimensionCube;
|
||||
maxExt.height = pLimits->maxImageDimensionCube;
|
||||
} else {
|
||||
maxExt.width = pLimits->maxImageDimension2D;
|
||||
maxExt.height = pLimits->maxImageDimension2D;
|
||||
maxExt.height = (type == VK_IMAGE_TYPE_1D ? 1 : pLimits->maxImageDimension2D);
|
||||
}
|
||||
maxExt.depth = 1;
|
||||
if (tiling == VK_IMAGE_TILING_LINEAR) {
|
||||
// Linear textures have additional restrictions under Metal:
|
||||
// - They may not be depth/stencil or compressed textures.
|
||||
if (mvkFmt == kMVKFormatDepthStencil || mvkFmt == kMVKFormatCompressed) {
|
||||
// - They may not be depth/stencil, compressed, or chroma subsampled textures.
|
||||
// We allow multi-planar formats because those internally use non-subsampled formats.
|
||||
if (mvkFmt == kMVKFormatDepthStencil || mvkFmt == kMVKFormatCompressed || isBGRG) {
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
#if MVK_MACOS
|
||||
// - On macOS, Linear textures may not be used as framebuffer attachments.
|
||||
if (hasAttachmentUsage) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
|
||||
#endif
|
||||
// Linear textures may only have one mip level. layer & sample
|
||||
// Linear textures may only have one mip level, layer & sample.
|
||||
maxLevels = 1;
|
||||
maxLayers = 1;
|
||||
sampleCounts = VK_SAMPLE_COUNT_1_BIT;
|
||||
@ -483,14 +503,22 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
|
||||
VkFormatProperties fmtProps;
|
||||
getFormatProperties(format, &fmtProps);
|
||||
// Compressed multisampled textures aren't supported.
|
||||
// Chroma-subsampled multisampled textures aren't supported.
|
||||
// Multisampled cube textures aren't supported.
|
||||
// Non-renderable multisampled textures aren't supported.
|
||||
if (mvkFmt == kMVKFormatCompressed ||
|
||||
if (mvkFmt == kMVKFormatCompressed || isChromaSubsampled ||
|
||||
mvkIsAnyFlagEnabled(flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) ||
|
||||
!mvkIsAnyFlagEnabled(fmtProps.optimalTilingFeatures, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) ) {
|
||||
sampleCounts = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
maxLevels = mvkMipmapLevels3D(maxExt);
|
||||
// BGRG and GBGR images may only have one mip level and one layer.
|
||||
// Other chroma subsampled formats may have multiple mip levels, but still only one layer.
|
||||
if (isChromaSubsampled) {
|
||||
maxLevels = isBGRG ? 1 : mvkMipmapLevels3D(maxExt);
|
||||
maxLayers = 1;
|
||||
} else {
|
||||
maxLevels = mvkMipmapLevels3D(maxExt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -500,7 +528,8 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(VkFormat format,
|
||||
return VK_ERROR_FORMAT_NOT_SUPPORTED;
|
||||
}
|
||||
// Metal does not allow compressed or depth/stencil formats on 3D textures
|
||||
if (mvkFmt == kMVKFormatDepthStencil
|
||||
if (mvkFmt == kMVKFormatDepthStencil ||
|
||||
isChromaSubsampled
|
||||
#if MVK_IOS_OR_TVOS
|
||||
|| mvkFmt == kMVKFormatCompressed
|
||||
#endif
|
||||
@ -560,7 +589,7 @@ VkResult MVKPhysicalDevice::getImageFormatProperties(const VkPhysicalDeviceImage
|
||||
switch (nextProps->sType) {
|
||||
case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: {
|
||||
auto* samplerYcbcrConvProps = (VkSamplerYcbcrConversionImageFormatProperties*)nextProps;
|
||||
samplerYcbcrConvProps->combinedImageSamplerDescriptorCount = _pixelFormats.getChromaSubsamplingPlaneCount(pImageFormatInfo->format);
|
||||
samplerYcbcrConvProps->combinedImageSamplerDescriptorCount = std::max(_pixelFormats.getChromaSubsamplingPlaneCount(pImageFormatInfo->format), (uint8_t)1u);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -990,6 +1019,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
||||
_metalFeatures.maxPerStageBufferCount = 31;
|
||||
_metalFeatures.maxMTLBufferSize = (256 * MEBI);
|
||||
_metalFeatures.dynamicMTLBufferSize = 0;
|
||||
_metalFeatures.maxPerStageDynamicMTLBufferCount = 0;
|
||||
|
||||
_metalFeatures.maxPerStageSamplerCount = 16;
|
||||
_metalFeatures.maxQueryBufferSize = (64 * KIBI);
|
||||
@ -1015,6 +1045,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
||||
_metalFeatures.maxTextureDimension = (8 * KIBI);
|
||||
_metalFeatures.dynamicMTLBufferSize = (4 * KIBI);
|
||||
_metalFeatures.sharedLinearTextures = true;
|
||||
_metalFeatures.maxPerStageDynamicMTLBufferCount = _metalFeatures.maxPerStageBufferCount;
|
||||
|
||||
if (supportsMTLFeatureSet(tvOS_GPUFamily1_v2)) {
|
||||
_metalFeatures.mslVersionEnum = MTLLanguageVersion1_2;
|
||||
@ -1069,6 +1100,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
||||
_metalFeatures.mslVersionEnum = MTLLanguageVersion1_1;
|
||||
_metalFeatures.dynamicMTLBufferSize = (4 * KIBI);
|
||||
_metalFeatures.maxTextureDimension = (8 * KIBI);
|
||||
_metalFeatures.maxPerStageDynamicMTLBufferCount = _metalFeatures.maxPerStageBufferCount;
|
||||
}
|
||||
|
||||
if (supportsMTLFeatureSet(iOS_GPUFamily1_v3)) {
|
||||
@ -1150,6 +1182,7 @@ void MVKPhysicalDevice::initMetalFeatures() {
|
||||
_metalFeatures.combinedStoreResolveAction = true;
|
||||
_metalFeatures.deferredStoreActions = true;
|
||||
_metalFeatures.maxMTLBufferSize = (1 * GIBI);
|
||||
_metalFeatures.maxPerStageDynamicMTLBufferCount = 14;
|
||||
}
|
||||
|
||||
if (supportsMTLFeatureSet(macOS_GPUFamily1_v3)) {
|
||||
@ -1522,7 +1555,6 @@ void MVKPhysicalDevice::initProperties() {
|
||||
uint32_t maxStorage = 0, maxUniform = 0;
|
||||
bool singleTexelStorage = true, singleTexelUniform = true;
|
||||
_pixelFormats.enumerateSupportedFormats({0, 0, VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT}, true, [&](VkFormat vk) {
|
||||
if ( _pixelFormats.getChromaSubsamplingComponentBits(vk) > 0 ) { return false; } // Skip chroma subsampling formats
|
||||
MTLPixelFormat mtlFmt = _pixelFormats.getMTLPixelFormat(vk);
|
||||
if ( !mtlFmt ) { return false; } // If format is invalid, avoid validation errors on MTLDevice format alignment calls
|
||||
|
||||
@ -2966,8 +2998,15 @@ uint32_t MVKDevice::getMetalBufferIndexForVertexAttributeBinding(uint32_t bindin
|
||||
VkDeviceSize MVKDevice::getVkFormatTexelBufferAlignment(VkFormat format, MVKBaseObject* mvkObj) {
|
||||
VkDeviceSize deviceAlignment = 0;
|
||||
id<MTLDevice> mtlDev = getMTLDevice();
|
||||
MVKPixelFormats* mvkPixFmts = getPixelFormats();
|
||||
if ([mtlDev respondsToSelector: @selector(minimumLinearTextureAlignmentForPixelFormat:)]) {
|
||||
deviceAlignment = [mtlDev minimumLinearTextureAlignmentForPixelFormat: getPixelFormats()->getMTLPixelFormat(format)];
|
||||
MTLPixelFormat mtlPixFmt = mvkPixFmts->getMTLPixelFormat(format);
|
||||
if (mvkPixFmts->getChromaSubsamplingPlaneCount(format) >= 2) {
|
||||
// Use plane 1 to get the alignment requirements. In a 2-plane format, this will
|
||||
// typically have stricter alignment requirements due to it being a 2-component format.
|
||||
mtlPixFmt = mvkPixFmts->getChromaSubsamplingPlaneMTLPixelFormat(format, 1);
|
||||
}
|
||||
deviceAlignment = [mtlDev minimumLinearTextureAlignmentForPixelFormat: mtlPixFmt];
|
||||
}
|
||||
return deviceAlignment ? deviceAlignment : _pProperties->limits.minTexelBufferOffsetAlignment;
|
||||
}
|
||||
|
@ -144,8 +144,10 @@ protected:
|
||||
MVKImageMemoryBinding(MVKDevice* device, MVKImage* image, uint8_t planeIndex);
|
||||
|
||||
MVKImage* _image;
|
||||
id<MTLBuffer> _mtlTexelBuffer = nil;
|
||||
NSUInteger _mtlTexelBufferOffset = 0;
|
||||
uint8_t _planeIndex;
|
||||
bool _usesTexelBuffer;
|
||||
bool _ownsTexelBuffer = false;
|
||||
};
|
||||
|
||||
|
||||
@ -367,6 +369,8 @@ protected:
|
||||
bool _is3DCompressed;
|
||||
bool _isAliasable;
|
||||
bool _hasExtendedUsage;
|
||||
bool _hasMutableFormat;
|
||||
bool _isLinearForAtomics;
|
||||
};
|
||||
|
||||
|
||||
@ -587,6 +591,7 @@ public:
|
||||
* This is a static function that can be used to validate image view formats prior to creating one.
|
||||
*/
|
||||
static VkResult validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo,
|
||||
VkImageUsageFlags usage,
|
||||
MVKVulkanAPIObject* apiObject,
|
||||
bool hasNativeSwizzleSupport,
|
||||
bool hasShaderSwizzleSupport,
|
||||
|
@ -51,10 +51,10 @@ id<MTLTexture> MVKImagePlane::getMTLTexture() {
|
||||
newTextureWithDescriptor: mtlTexDesc
|
||||
iosurface: _image->_ioSurface
|
||||
plane: _planeIndex];
|
||||
} else if (memoryBinding->_usesTexelBuffer) {
|
||||
_mtlTexture = [memoryBinding->_deviceMemory->getMTLBuffer()
|
||||
} else if (memoryBinding->_mtlTexelBuffer) {
|
||||
_mtlTexture = [memoryBinding->_mtlTexelBuffer
|
||||
newTextureWithDescriptor: mtlTexDesc
|
||||
offset: memoryBinding->getDeviceMemoryOffset()
|
||||
offset: memoryBinding->_mtlTexelBufferOffset
|
||||
bytesPerRow: _subresources[0].layout.rowPitch];
|
||||
} else if (memoryBinding->_deviceMemory->getMTLHeap() && !_image->getIsDepthStencil()) {
|
||||
// Metal support for depth/stencil from heaps is flaky
|
||||
@ -123,7 +123,7 @@ MTLTextureDescriptor* MVKImagePlane::newMTLTextureDescriptor() {
|
||||
mtlTexDesc.mipmapLevelCount = _image->_mipLevels;
|
||||
mtlTexDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(_image->_samples);
|
||||
mtlTexDesc.arrayLength = _image->_arrayLayers;
|
||||
mtlTexDesc.usageMVK = _image->getPixelFormats()->getMTLTextureUsage(_image->_usage, mtlPixFmt, minUsage, _image->_isLinear, _image->_hasExtendedUsage);
|
||||
mtlTexDesc.usageMVK = _image->getPixelFormats()->getMTLTextureUsage(_image->_usage, mtlPixFmt, minUsage, _image->_isLinear, _image->_hasMutableFormat, _image->_hasExtendedUsage);
|
||||
mtlTexDesc.storageModeMVK = _image->getMTLStorageMode();
|
||||
mtlTexDesc.cpuCacheMode = _image->getMTLCPUCacheMode();
|
||||
|
||||
@ -306,7 +306,7 @@ void MVKImagePlane::applyImageMemoryBarrier(VkPipelineStageFlags srcStageMask,
|
||||
|
||||
MVKImageMemoryBinding* memBind = getMemoryBinding();
|
||||
bool needsSync = memBind->needsHostReadSync(srcStageMask, dstStageMask, barrier);
|
||||
bool needsPull = (!memBind->_usesTexelBuffer &&
|
||||
bool needsPull = ((!memBind->_mtlTexelBuffer || memBind->_ownsTexelBuffer) &&
|
||||
memBind->isMemoryHostCoherent() &&
|
||||
barrier.newLayout == VK_IMAGE_LAYOUT_GENERAL &&
|
||||
mvkIsAnyFlagEnabled(barrier.dstAccessMask, (VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_READ_BIT)));
|
||||
@ -375,9 +375,10 @@ VkResult MVKImageMemoryBinding::getMemoryRequirements(const void*, VkMemoryRequi
|
||||
case VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS: {
|
||||
auto* dedicatedReqs = (VkMemoryDedicatedRequirements*)next;
|
||||
bool writable = mvkIsAnyFlagEnabled(_image->_usage, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||
bool canUseTexelBuffer = _device->_pMetalFeatures->texelBuffers && _image->_isLinear && !_image->getIsCompressed();
|
||||
dedicatedReqs->requiresDedicatedAllocation = _requiresDedicatedMemoryAllocation;
|
||||
dedicatedReqs->prefersDedicatedAllocation = (dedicatedReqs->requiresDedicatedAllocation ||
|
||||
(!_usesTexelBuffer && (writable || !_device->_pMetalFeatures->placementHeaps)));
|
||||
(!canUseTexelBuffer && (writable || !_device->_pMetalFeatures->placementHeaps)));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -392,11 +393,34 @@ VkResult MVKImageMemoryBinding::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDevi
|
||||
if (_deviceMemory) { _deviceMemory->removeImageMemoryBinding(this); }
|
||||
MVKResource::bindDeviceMemory(mvkMem, memOffset);
|
||||
|
||||
_usesTexelBuffer = _device->_pMetalFeatures->texelBuffers && _deviceMemory && _deviceMemory->_mtlBuffer; // Texel buffers available
|
||||
_usesTexelBuffer = _usesTexelBuffer && (isMemoryHostAccessible() || _device->_pMetalFeatures->placementHeaps) && _image->_isLinear && !_image->getIsCompressed(); // Applicable memory layout
|
||||
bool usesTexelBuffer = _device->_pMetalFeatures->texelBuffers && _deviceMemory; // Texel buffers available
|
||||
usesTexelBuffer = usesTexelBuffer && (isMemoryHostAccessible() || _device->_pMetalFeatures->placementHeaps) && _image->_isLinear && !_image->getIsCompressed(); // Applicable memory layout
|
||||
|
||||
// macOS before 10.15.5 cannot use shared memory for texel buffers.
|
||||
_usesTexelBuffer = _usesTexelBuffer && (_device->_pMetalFeatures->sharedLinearTextures || !isMemoryHostCoherent());
|
||||
usesTexelBuffer = usesTexelBuffer && (_device->_pMetalFeatures->sharedLinearTextures || !isMemoryHostCoherent());
|
||||
|
||||
if (_image->_isLinearForAtomics) {
|
||||
if (usesTexelBuffer && _deviceMemory->ensureMTLBuffer()) {
|
||||
_mtlTexelBuffer = _deviceMemory->_mtlBuffer;
|
||||
_mtlTexelBufferOffset = getDeviceMemoryOffset();
|
||||
} else {
|
||||
// Create our own buffer for this.
|
||||
if (_deviceMemory && _deviceMemory->_mtlHeap && _image->getMTLStorageMode() == _deviceMemory->_mtlStorageMode) {
|
||||
_mtlTexelBuffer = [_deviceMemory->_mtlHeap newBufferWithLength: _byteCount options: _deviceMemory->getMTLResourceOptions() offset: getDeviceMemoryOffset()];
|
||||
if (_image->_isAliasable) { [_mtlTexelBuffer makeAliasable]; }
|
||||
} else {
|
||||
_mtlTexelBuffer = [getMTLDevice() newBufferWithLength: _byteCount options: _image->getMTLStorageMode() << MTLResourceStorageModeShift];
|
||||
}
|
||||
if (!_mtlTexelBuffer) {
|
||||
return reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not create an MTLBuffer for an image that requires a buffer backing store. Images that can be used for atomic accesses must have a texel buffer backing them.");
|
||||
}
|
||||
_mtlTexelBufferOffset = 0;
|
||||
_ownsTexelBuffer = true;
|
||||
}
|
||||
} else if (usesTexelBuffer && _deviceMemory->_mtlBuffer) {
|
||||
_mtlTexelBuffer = _deviceMemory->_mtlBuffer;
|
||||
_mtlTexelBufferOffset = getDeviceMemoryOffset();
|
||||
}
|
||||
|
||||
flushToDevice(getDeviceMemoryOffset(), getByteCount());
|
||||
return _deviceMemory ? _deviceMemory->addImageMemoryBinding(this) : VK_SUCCESS;
|
||||
@ -420,6 +444,9 @@ void MVKImageMemoryBinding::propagateDebugName() {
|
||||
for(uint8_t planeIndex = beginPlaneIndex(); planeIndex < endPlaneIndex(); planeIndex++) {
|
||||
_image->_planes[planeIndex]->propagateDebugName();
|
||||
}
|
||||
if (_ownsTexelBuffer) {
|
||||
setLabelIfNotNil(_mtlTexelBuffer, _image->_debugName);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether the specified image memory barrier requires a sync between this
|
||||
@ -437,7 +464,7 @@ bool MVKImageMemoryBinding::needsHostReadSync(VkPipelineStageFlags srcStageMask,
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MVKImageMemoryBinding::shouldFlushHostMemory() { return isMemoryHostAccessible() && !_usesTexelBuffer; }
|
||||
bool MVKImageMemoryBinding::shouldFlushHostMemory() { return isMemoryHostAccessible() && (!_mtlTexelBuffer || _ownsTexelBuffer); }
|
||||
|
||||
// Flushes the device memory at the specified memory range into the MTLTexture. Updates
|
||||
// all subresources that overlap the specified range and are in an updatable layout state.
|
||||
@ -489,14 +516,12 @@ uint8_t MVKImageMemoryBinding::endPlaneIndex() const {
|
||||
return (_image->_memoryBindings.size() > 1) ? _planeIndex : (uint8_t)_image->_memoryBindings.size();
|
||||
}
|
||||
|
||||
MVKImageMemoryBinding::MVKImageMemoryBinding(MVKDevice* device, MVKImage* image, uint8_t planeIndex) : MVKResource(device) {
|
||||
_image = image;
|
||||
_planeIndex = planeIndex;
|
||||
_usesTexelBuffer = false;
|
||||
MVKImageMemoryBinding::MVKImageMemoryBinding(MVKDevice* device, MVKImage* image, uint8_t planeIndex) : MVKResource(device), _image(image), _planeIndex(planeIndex) {
|
||||
}
|
||||
|
||||
MVKImageMemoryBinding::~MVKImageMemoryBinding() {
|
||||
if (_deviceMemory) { _deviceMemory->removeImageMemoryBinding(this); }
|
||||
if (_ownsTexelBuffer) { [_mtlTexelBuffer release]; }
|
||||
}
|
||||
|
||||
|
||||
@ -529,7 +554,7 @@ bool MVKImage::getIsCompressed() { return getPixelFormats()->getFormatType(_vkFo
|
||||
|
||||
VkExtent3D MVKImage::getExtent3D(uint8_t planeIndex, uint32_t mipLevel) {
|
||||
VkExtent3D extent = _extent;
|
||||
if (_hasChromaSubsampling) {
|
||||
if (_hasChromaSubsampling && planeIndex > 0) {
|
||||
extent.width /= _planes[planeIndex]->_blockTexelSize.width;
|
||||
extent.height /= _planes[planeIndex]->_blockTexelSize.height;
|
||||
}
|
||||
@ -537,14 +562,16 @@ VkExtent3D MVKImage::getExtent3D(uint8_t planeIndex, uint32_t mipLevel) {
|
||||
}
|
||||
|
||||
VkDeviceSize MVKImage::getBytesPerRow(uint8_t planeIndex, uint32_t mipLevel) {
|
||||
size_t bytesPerRow = getPixelFormats()->getBytesPerRow(_vkFormat, getExtent3D(planeIndex, mipLevel).width);
|
||||
MTLPixelFormat planeMTLPixFmt = getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_vkFormat, planeIndex);
|
||||
size_t bytesPerRow = getPixelFormats()->getBytesPerRow(planeMTLPixFmt, getExtent3D(planeIndex, mipLevel).width);
|
||||
return mvkAlignByteCount(bytesPerRow, _rowByteAlignment);
|
||||
}
|
||||
|
||||
VkDeviceSize MVKImage::getBytesPerLayer(uint8_t planeIndex, uint32_t mipLevel) {
|
||||
MTLPixelFormat planeMTLPixFmt = getPixelFormats()->getChromaSubsamplingPlaneMTLPixelFormat(_vkFormat, planeIndex);
|
||||
VkExtent3D extent = getExtent3D(planeIndex, mipLevel);
|
||||
size_t bytesPerRow = getBytesPerRow(planeIndex, mipLevel);
|
||||
return getPixelFormats()->getBytesPerLayer(_vkFormat, bytesPerRow, extent.height);
|
||||
return getPixelFormats()->getBytesPerLayer(planeMTLPixFmt, bytesPerRow, extent.height);
|
||||
}
|
||||
|
||||
VkResult MVKImage::getSubresourceLayout(const VkImageSubresource* pSubresource,
|
||||
@ -804,8 +831,16 @@ MVKImage::MVKImage(MVKDevice* device, const VkImageCreateInfo* pCreateInfo) : MV
|
||||
MVKPixelFormats* pixFmts = getPixelFormats();
|
||||
_vkFormat = pCreateInfo->format;
|
||||
_usage = pCreateInfo->usage;
|
||||
_hasMutableFormat = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT);
|
||||
_hasExtendedUsage = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_EXTENDED_USAGE_BIT);
|
||||
|
||||
// If this is a storage image of format R32_UINT or R32_SINT, or MUTABLE_FORMAT is set
|
||||
// and R32_UINT is in the set of possible view formats, then we must use a texel buffer,
|
||||
// or image atomics won't work.
|
||||
// TODO: Also add handling for VK_KHR_image_format_list here.
|
||||
_isLinearForAtomics = _isLinear && mvkIsAnyFlagEnabled(_usage, VK_IMAGE_USAGE_STORAGE_BIT) &&
|
||||
((_vkFormat == VK_FORMAT_R32_UINT || _vkFormat == VK_FORMAT_R32_SINT) ||
|
||||
(_hasMutableFormat && pixFmts->getViewClass(_vkFormat) == MVKMTLViewClass::Color32));
|
||||
_is3DCompressed = (getImageType() == VK_IMAGE_TYPE_3D) && (pixFmts->getFormatType(pCreateInfo->format) == kMVKFormatCompressed) && !_device->_pMetalFeatures->native3DCompressedTextures;
|
||||
_isDepthStencilAttachment = (mvkAreAllFlagsEnabled(pCreateInfo->usage, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ||
|
||||
mvkAreAllFlagsEnabled(pixFmts->getVkFormatProperties(pCreateInfo->format).optimalTilingFeatures, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT));
|
||||
@ -842,6 +877,16 @@ MVKImage::MVKImage(MVKDevice* device, const VkImageCreateInfo* pCreateInfo) : MV
|
||||
memoryBinding->_byteCount += sizeAndAlign.size;
|
||||
memoryBinding->_byteAlignment = std::max(memoryBinding->_byteAlignment, (VkDeviceSize)sizeAndAlign.align);
|
||||
_isAliasable = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_ALIAS_BIT);
|
||||
} else if (_isLinearForAtomics && _device->_pMetalFeatures->placementHeaps) {
|
||||
NSUInteger bufferLength = 0;
|
||||
for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
|
||||
VkExtent3D mipExtent = getExtent3D(planeIndex, mipLvl);
|
||||
bufferLength += getBytesPerLayer(planeIndex, mipLvl) * mipExtent.depth * _arrayLayers;
|
||||
}
|
||||
MTLSizeAndAlign sizeAndAlign = [_device->getMTLDevice() heapBufferSizeAndAlignWithLength: bufferLength options: MTLResourceStorageModePrivate];
|
||||
memoryBinding->_byteCount += sizeAndAlign.size;
|
||||
memoryBinding->_byteAlignment = std::max(std::max(memoryBinding->_byteAlignment, _rowByteAlignment), (VkDeviceSize)sizeAndAlign.align);
|
||||
_isAliasable = mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_ALIAS_BIT);
|
||||
} else {
|
||||
for (uint32_t mipLvl = 0; mipLvl < _mipLevels; mipLvl++) {
|
||||
VkExtent3D mipExtent = getExtent3D(planeIndex, mipLvl);
|
||||
@ -881,6 +926,10 @@ VkSampleCountFlagBits MVKImage::validateSamples(const VkImageCreateInfo* pCreate
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, multisampling cannot be used with compressed images. Setting sample count to 1."));
|
||||
validSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
if (getPixelFormats()->getChromaSubsamplingPlaneCount(pCreateInfo->format) > 0) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, multisampling cannot be used with chroma subsampled images. Setting sample count to 1."));
|
||||
validSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
|
||||
if (pCreateInfo->arrayLayers > 1) {
|
||||
if ( !_device->_pMetalFeatures->multisampleArrayTextures ) {
|
||||
@ -901,6 +950,7 @@ void MVKImage::validateConfig(const VkImageCreateInfo* pCreateInfo, bool isAttac
|
||||
|
||||
bool is2D = (getImageType() == VK_IMAGE_TYPE_2D);
|
||||
bool isCompressed = pixFmts->getFormatType(pCreateInfo->format) == kMVKFormatCompressed;
|
||||
bool isChromaSubsampled = pixFmts->getChromaSubsamplingPlaneCount(pCreateInfo->format) > 0;
|
||||
|
||||
#if MVK_IOS_OR_TVOS
|
||||
if (isCompressed && !is2D) {
|
||||
@ -917,6 +967,16 @@ void MVKImage::validateConfig(const VkImageCreateInfo* pCreateInfo, bool isAttac
|
||||
}
|
||||
#endif
|
||||
|
||||
if (isChromaSubsampled && !is2D) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, chroma subsampled formats may only be used with 2D images."));
|
||||
}
|
||||
if (isChromaSubsampled && mvkIsAnyFlagEnabled(pCreateInfo->flags, VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, chroma subsampled formats may not be used with cube images."));
|
||||
}
|
||||
if (isChromaSubsampled && (pCreateInfo->arrayLayers > 1)) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Chroma-subsampled formats may only have one array layer."));
|
||||
}
|
||||
|
||||
if ((pixFmts->getFormatType(pCreateInfo->format) == kMVKFormatDepthStencil) && !is2D ) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, depth/stencil formats may only be used with 2D images."));
|
||||
}
|
||||
@ -940,6 +1000,10 @@ uint32_t MVKImage::validateMipLevels(const VkImageCreateInfo* pCreateInfo, bool
|
||||
|
||||
if (validMipLevels == 1) { return validMipLevels; }
|
||||
|
||||
if (getPixelFormats()->getChromaSubsamplingPlaneCount(pCreateInfo->format) == 1) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, GBGR and BGRG images cannot use mipmaps. Setting mip levels to 1."));
|
||||
validMipLevels = 1;
|
||||
}
|
||||
if (getImageType() == VK_IMAGE_TYPE_1D) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, native 1D images cannot use mipmaps. Setting mip levels to 1. Consider enabling MVK_CONFIG_TEXTURE_1D_AS_2D."));
|
||||
validMipLevels = 1;
|
||||
@ -967,6 +1031,10 @@ bool MVKImage::validateLinear(const VkImageCreateInfo* pCreateInfo, bool isAttac
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, format must not be a compressed format."));
|
||||
isLin = false;
|
||||
}
|
||||
if (getPixelFormats()->getChromaSubsamplingPlaneCount(pCreateInfo->format) == 1) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, format must not be a single-plane chroma subsampled format."));
|
||||
isLin = false;
|
||||
}
|
||||
|
||||
if (pCreateInfo->mipLevels > 1) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, mipLevels must be 1."));
|
||||
@ -1318,7 +1386,7 @@ id<MTLTexture> MVKImageViewPlane::newMTLTexture() {
|
||||
mtlTextureType = MTLTextureType3D;
|
||||
sliceRange = NSMakeRange(0, 1);
|
||||
}
|
||||
id<MTLTexture> mtlTex = _imageView->_image->getMTLTexture(MVKImage::getPlaneFromVkImageAspectFlags(_imageView->_subresourceRange.aspectMask));
|
||||
id<MTLTexture> mtlTex = _imageView->_image->getMTLTexture(_planeIndex);
|
||||
if (_device->_pMetalFeatures->nativeTextureSwizzle && _packedSwizzle) {
|
||||
return [mtlTex newTextureViewWithPixelFormat: _mtlPixFmt
|
||||
textureType: mtlTextureType
|
||||
@ -1347,6 +1415,7 @@ MVKImageViewPlane::MVKImageViewPlane(MVKImageView* imageView,
|
||||
|
||||
bool useSwizzle;
|
||||
_imageView->setConfigurationResult(_imageView->validateSwizzledMTLPixelFormat(pCreateInfo,
|
||||
_imageView->_usage,
|
||||
_imageView,
|
||||
_device->_pMetalFeatures->nativeTextureSwizzle,
|
||||
_device->_pMVKConfig->fullImageViewSwizzle,
|
||||
@ -1471,15 +1540,15 @@ MVKImageView::MVKImageView(MVKDevice* device,
|
||||
beginPlaneIndex = 0,
|
||||
endPlaneIndex = subsamplingPlaneCount;
|
||||
if (subsamplingPlaneCount == 0) {
|
||||
endPlaneIndex = 1;
|
||||
mtlPixFmtOfPlane[0] = getPixelFormats()->getMTLPixelFormat(pCreateInfo->format);
|
||||
if (_subresourceRange.aspectMask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) {
|
||||
beginPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(_subresourceRange.aspectMask);
|
||||
}
|
||||
endPlaneIndex = beginPlaneIndex + 1;
|
||||
mtlPixFmtOfPlane[beginPlaneIndex] = getPixelFormats()->getMTLPixelFormat(pCreateInfo->format);
|
||||
} else {
|
||||
if (!mvkVkComponentMappingsMatch(pCreateInfo->components, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A})) {
|
||||
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Image view swizzling for multi planar formats is not supported."));
|
||||
}
|
||||
if (_subresourceRange.aspectMask & (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) {
|
||||
beginPlaneIndex = endPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(_subresourceRange.aspectMask);
|
||||
}
|
||||
}
|
||||
for (uint8_t planeIndex = beginPlaneIndex; planeIndex < endPlaneIndex; planeIndex++) {
|
||||
_planes.push_back(new MVKImageViewPlane(this, planeIndex, mtlPixFmtOfPlane[planeIndex], pCreateInfo));
|
||||
@ -1487,6 +1556,7 @@ MVKImageView::MVKImageView(MVKDevice* device,
|
||||
}
|
||||
|
||||
VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo,
|
||||
VkImageUsageFlags usage,
|
||||
MVKVulkanAPIObject* apiObject,
|
||||
bool hasNativeSwizzleSupport,
|
||||
bool hasShaderSwizzleSupport,
|
||||
@ -1501,7 +1571,8 @@ VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInf
|
||||
// If we have an identity swizzle, we're all good.
|
||||
if (SWIZZLE_MATCHES(R, G, B, A)) {
|
||||
// Change to stencil-only format if only stencil aspect is requested
|
||||
if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT &&
|
||||
mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) {
|
||||
if (mtlPixFmt == MTLPixelFormatDepth32Float_Stencil8)
|
||||
mtlPixFmt = MTLPixelFormatX32_Stencil8;
|
||||
#if MVK_MACOS
|
||||
@ -1558,7 +1629,8 @@ VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInf
|
||||
|
||||
case MTLPixelFormatDepth32Float_Stencil8:
|
||||
// If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed
|
||||
if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT &&
|
||||
mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) {
|
||||
mtlPixFmt = MTLPixelFormatX32_Stencil8;
|
||||
if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) {
|
||||
return VK_SUCCESS;
|
||||
@ -1569,7 +1641,8 @@ VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInf
|
||||
#if MVK_MACOS
|
||||
case MTLPixelFormatDepth24Unorm_Stencil8:
|
||||
// If aspect mask looking only for stencil then change to stencil-only format even if shader swizzling is needed
|
||||
if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) {
|
||||
if (pCreateInfo->subresourceRange.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT &&
|
||||
mvkIsAnyFlagEnabled(usage, (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))) {
|
||||
mtlPixFmt = MTLPixelFormatX24_Stencil8;
|
||||
if (SWIZZLE_MATCHES(R, ANY, ANY, ANY)) {
|
||||
return VK_SUCCESS;
|
||||
|
@ -256,6 +256,9 @@ public:
|
||||
/** Returns the MSLFormatResolution of the specified chroma-subsampling (YCbCr) VkFormat */
|
||||
SPIRV_CROSS_NAMESPACE::MSLFormatResolution getChromaSubsamplingResolution(VkFormat vkFormat);
|
||||
|
||||
/** Returns the MTLPixelFormat of the specified chroma-subsampling (YCbCr) VkFormat for the specified plane. */
|
||||
MTLPixelFormat getChromaSubsamplingPlaneMTLPixelFormat(VkFormat vkFormat, uint8_t planeIndex);
|
||||
|
||||
/** Returns the number of planes, blockTexelSize, bytesPerBlock and mtlPixFmt of each plane of the specified chroma-subsampling (YCbCr) VkFormat into the given arrays */
|
||||
uint8_t getChromaSubsamplingPlanes(VkFormat vkFormat, VkExtent2D blockTexelSize[3], uint32_t bytesPerBlock[3], MTLPixelFormat mtlPixFmt[3]);
|
||||
|
||||
@ -315,6 +318,9 @@ public:
|
||||
/** Returns the Metal format capabilities supported by the specified Metal format. */
|
||||
MVKMTLFmtCaps getCapabilities(MTLPixelFormat mtlFormat, bool isExtended = false);
|
||||
|
||||
/** Returns the Metal view class of the specified Vulkan format. */
|
||||
MVKMTLViewClass getViewClass(VkFormat vkFormat);
|
||||
|
||||
/** Returns the Metal view class of the specified Metal format. */
|
||||
MVKMTLViewClass getViewClass(MTLPixelFormat mtlFormat);
|
||||
|
||||
@ -350,6 +356,7 @@ public:
|
||||
MTLPixelFormat mtlFormat,
|
||||
MTLTextureUsage minUsage = MTLTextureUsageUnknown,
|
||||
bool isLinear = false,
|
||||
bool isMutableFormat = true,
|
||||
bool isExtended = false);
|
||||
|
||||
/** Enumerates all formats that support the given features, calling a specified function for each one. */
|
||||
|
@ -190,7 +190,7 @@ MTLPixelFormat MVKPixelFormats::getMTLPixelFormat(VkFormat vkFormat) {
|
||||
|
||||
// If the MTLPixelFormat is not supported but VkFormat is valid,
|
||||
// attempt to substitute a different format and potentially report an error.
|
||||
if ( !mtlPixFmt && vkFormat ) {
|
||||
if ( !mtlPixFmt && vkFormat && vkDesc.chromaSubsamplingPlaneCount <= 1 ) {
|
||||
mtlPixFmt = vkDesc.mtlPixelFormatSubstitute;
|
||||
|
||||
// Report an error if there is no substitute, or the first time a substitution is made.
|
||||
@ -250,6 +250,23 @@ SPIRV_CROSS_NAMESPACE::MSLFormatResolution MVKPixelFormats::getChromaSubsampling
|
||||
: SPIRV_CROSS_NAMESPACE::MSL_FORMAT_RESOLUTION_420;
|
||||
}
|
||||
|
||||
MTLPixelFormat MVKPixelFormats::getChromaSubsamplingPlaneMTLPixelFormat(VkFormat vkFormat, uint8_t planeIndex) {
|
||||
uint8_t planes = getChromaSubsamplingPlaneCount(vkFormat);
|
||||
uint8_t bits = getChromaSubsamplingComponentBits(vkFormat);
|
||||
switch(planes) {
|
||||
default:
|
||||
case 1:
|
||||
return getMTLPixelFormat(vkFormat);
|
||||
case 2:
|
||||
if (planeIndex == 1) {
|
||||
return (bits == 8) ? MTLPixelFormatRG8Unorm : MTLPixelFormatRG16Unorm;
|
||||
}
|
||||
/* fallthrough */
|
||||
case 3:
|
||||
return (bits == 8) ? MTLPixelFormatR8Unorm : MTLPixelFormatR16Unorm;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t MVKPixelFormats::getChromaSubsamplingPlanes(VkFormat vkFormat, VkExtent2D blockTexelSize[3], uint32_t bytesPerBlock[3], MTLPixelFormat mtlPixFmt[3]) {
|
||||
uint8_t planes = getChromaSubsamplingPlaneCount(vkFormat);
|
||||
uint8_t bits = getChromaSubsamplingComponentBits(vkFormat);
|
||||
@ -273,7 +290,7 @@ uint8_t MVKPixelFormats::getChromaSubsamplingPlanes(VkFormat vkFormat, VkExtent2
|
||||
return 0;
|
||||
case 1:
|
||||
bytesPerBlock[0] *= 4;
|
||||
mtlPixFmt[0] = (bits == 8) ? MTLPixelFormatRGBA8Unorm : MTLPixelFormatRGBA16Unorm;
|
||||
mtlPixFmt[0] = getMTLPixelFormat(vkFormat);
|
||||
break;
|
||||
case 2:
|
||||
blockTexelSize[0] = VkExtent2D{1, 1};
|
||||
@ -335,6 +352,10 @@ MVKMTLFmtCaps MVKPixelFormats::getCapabilities(MTLPixelFormat mtlFormat, bool is
|
||||
return caps;
|
||||
}
|
||||
|
||||
MVKMTLViewClass MVKPixelFormats::getViewClass(VkFormat vkFormat) {
|
||||
return getMTLPixelFormatDesc(getVkFormatDesc(vkFormat).mtlPixelFormat).mtlViewClass;
|
||||
}
|
||||
|
||||
MVKMTLViewClass MVKPixelFormats::getViewClass(MTLPixelFormat mtlFormat) {
|
||||
return getMTLPixelFormatDesc(mtlFormat).mtlViewClass;
|
||||
}
|
||||
@ -465,6 +486,7 @@ MTLTextureUsage MVKPixelFormats::getMTLTextureUsage(VkImageUsageFlags vkImageUsa
|
||||
MTLPixelFormat mtlFormat,
|
||||
MTLTextureUsage minUsage,
|
||||
bool isLinear,
|
||||
bool isMutableFormat,
|
||||
bool isExtended) {
|
||||
bool isDepthFmt = isDepthFormat(mtlFormat);
|
||||
bool isStencilFmt = isStencilFormat(mtlFormat);
|
||||
@ -514,13 +536,21 @@ MTLTextureUsage MVKPixelFormats::getMTLTextureUsage(VkImageUsageFlags vkImageUsa
|
||||
}
|
||||
|
||||
// Create view on, but only on color formats, or combined depth-stencil formats if supported by the GPU...
|
||||
if (mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | // May use temp view if transfer involves format change
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
if ((mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) || // May use temp view if transfer involves format change
|
||||
(isMutableFormat &&
|
||||
mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)))) &&
|
||||
isColorFormat) {
|
||||
|
||||
mvkEnableFlags(mtlUsage, MTLTextureUsagePixelFormatView);
|
||||
}
|
||||
if (mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | // May use temp view if transfer involves format change
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_STORAGE_BIT |
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) &&
|
||||
(isColorFormat || (isCombinedDepthStencilFmt && supportsStencilViews))) {
|
||||
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) &&
|
||||
isCombinedDepthStencilFmt && supportsStencilViews) {
|
||||
|
||||
mvkEnableFlags(mtlUsage, MTLTextureUsagePixelFormatView);
|
||||
}
|
||||
@ -837,9 +867,9 @@ void MVKPixelFormats::initVkFormatCapabilities() {
|
||||
addVkFormatDescChromaSubsampling( G8_B8_R8_3PLANE_422_UNORM, Invalid, 3, 8, 2, 1, 4 );
|
||||
addVkFormatDescChromaSubsampling( G8_B8R8_2PLANE_422_UNORM, Invalid, 2, 8, 2, 1, 4 );
|
||||
addVkFormatDescChromaSubsampling( G8_B8_R8_3PLANE_444_UNORM, Invalid, 3, 8, 1, 1, 3 );
|
||||
addVkFormatDescChromaSubsampling( R10X6_UNORM_PACK16, Invalid, 0, 10, 1, 1, 2 );
|
||||
addVkFormatDescChromaSubsampling( R10X6G10X6_UNORM_2PACK16, Invalid, 0, 10, 1, 1, 4 );
|
||||
addVkFormatDescChromaSubsampling( R10X6G10X6B10X6A10X6_UNORM_4PACK16, Invalid, 0, 10, 1, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( R10X6_UNORM_PACK16, R16Unorm, 0, 10, 1, 1, 2 );
|
||||
addVkFormatDescChromaSubsampling( R10X6G10X6_UNORM_2PACK16, RG16Unorm, 0, 10, 1, 1, 4 );
|
||||
addVkFormatDescChromaSubsampling( R10X6G10X6B10X6A10X6_UNORM_4PACK16, RGBA16Unorm, 0, 10, 1, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( G10X6B10X6G10X6R10X6_422_UNORM_4PACK16, Invalid, 1, 10, 2, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( B10X6G10X6R10X6G10X6_422_UNORM_4PACK16, Invalid, 1, 10, 2, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16, Invalid, 3, 10, 2, 2, 12 );
|
||||
@ -847,9 +877,9 @@ void MVKPixelFormats::initVkFormatCapabilities() {
|
||||
addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16, Invalid, 3, 10, 2, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16, Invalid, 2, 10, 2, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16, Invalid, 3, 10, 1, 1, 6 );
|
||||
addVkFormatDescChromaSubsampling( R12X4_UNORM_PACK16, Invalid, 0, 12, 1, 1, 2 );
|
||||
addVkFormatDescChromaSubsampling( R12X4G12X4_UNORM_2PACK16, Invalid, 0, 12, 1, 1, 4 );
|
||||
addVkFormatDescChromaSubsampling( R12X4G12X4B12X4A12X4_UNORM_4PACK16, Invalid, 0, 12, 1, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( R12X4_UNORM_PACK16, R16Unorm, 0, 12, 1, 1, 2 );
|
||||
addVkFormatDescChromaSubsampling( R12X4G12X4_UNORM_2PACK16, RG16Unorm, 0, 12, 1, 1, 4 );
|
||||
addVkFormatDescChromaSubsampling( R12X4G12X4B12X4A12X4_UNORM_4PACK16, RGBA16Unorm, 0, 12, 1, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( G12X4B12X4G12X4R12X4_422_UNORM_4PACK16, Invalid, 1, 12, 2, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( B12X4G12X4R12X4G12X4_422_UNORM_4PACK16, Invalid, 1, 12, 2, 1, 8 );
|
||||
addVkFormatDescChromaSubsampling( G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16, Invalid, 3, 12, 2, 2, 12 );
|
||||
@ -1620,9 +1650,7 @@ typedef enum : VkFormatFeatureFlags {
|
||||
kMVKVkFormatFeatureFlagsTexDSAtt = (VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT),
|
||||
kMVKVkFormatFeatureFlagsTexBlend = (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT),
|
||||
kMVKVkFormatFeatureFlagsTexTransfer = (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
|
||||
VK_FORMAT_FEATURE_TRANSFER_DST_BIT |
|
||||
VK_FORMAT_FEATURE_BLIT_SRC_BIT |
|
||||
VK_FORMAT_FEATURE_BLIT_DST_BIT),
|
||||
VK_FORMAT_FEATURE_TRANSFER_DST_BIT),
|
||||
kMVKVkFormatFeatureFlagsTexChromaSubsampling = (VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR |
|
||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR),
|
||||
kMVKVkFormatFeatureFlagsTexMultiPlanar = (VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR |
|
||||
@ -1650,12 +1678,13 @@ void MVKPixelFormats::setFormatProperties(MVKVkFormatDesc& vkDesc) {
|
||||
vkProps.linearTilingFeatures = kMVKVkFormatFeatureFlagsTexNone;
|
||||
|
||||
// Chroma subsampling and multi planar features
|
||||
if (getChromaSubsamplingComponentBits(vkDesc.vkFormat) > 0) {
|
||||
vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexTransfer;
|
||||
}
|
||||
uint8_t chromaSubsamplingPlaneCount = getChromaSubsamplingPlaneCount(vkDesc.vkFormat);
|
||||
if (chromaSubsamplingPlaneCount > 0) {
|
||||
mtlPixFmtCaps = kMVKMTLFmtCapsRF;
|
||||
uint8_t chromaSubsamplingComponentBits = getChromaSubsamplingComponentBits(vkDesc.vkFormat);
|
||||
if (chromaSubsamplingComponentBits > 0) {
|
||||
if (mtlPixFmtCaps != 0 || chromaSubsamplingPlaneCount > 1) {
|
||||
mtlPixFmtCaps = kMVKMTLFmtCapsRF;
|
||||
vkProps.optimalTilingFeatures = kMVKVkFormatFeatureFlagsTexTransfer;
|
||||
}
|
||||
enableFormatFeatures(ChromaSubsampling, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
|
||||
}
|
||||
if (chromaSubsamplingPlaneCount > 1) {
|
||||
@ -1670,8 +1699,15 @@ void MVKPixelFormats::setFormatProperties(MVKVkFormatDesc& vkDesc) {
|
||||
enableFormatFeatures(DSAtt, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
|
||||
enableFormatFeatures(Blend, Tex, mtlPixFmtCaps, vkProps.optimalTilingFeatures);
|
||||
|
||||
if (chromaSubsamplingComponentBits > 0) {
|
||||
// Vulkan forbids blits between chroma-subsampled formats.
|
||||
mvkDisableFlags(vkProps.optimalTilingFeatures, (VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT));
|
||||
}
|
||||
|
||||
// Linear tiling is not available to depth/stencil or compressed formats.
|
||||
if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed) ) {
|
||||
// GBGR and BGRG formats also do not support linear tiling in Metal.
|
||||
if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed ||
|
||||
(chromaSubsamplingPlaneCount == 1 && vkDesc.blockTexelSize.width > 1)) ) {
|
||||
// Start with optimal tiling features, and modify.
|
||||
vkProps.linearTilingFeatures = vkProps.optimalTilingFeatures;
|
||||
|
||||
@ -1686,9 +1722,10 @@ void MVKPixelFormats::setFormatProperties(MVKVkFormatDesc& vkDesc) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Texel buffers are not available to depth/stencil or compressed formats.
|
||||
// Texel buffers are not available to depth/stencil, compressed, or chroma subsampled formats.
|
||||
vkProps.bufferFeatures = kMVKVkFormatFeatureFlagsTexNone;
|
||||
if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed) ) {
|
||||
if ( !(vkDesc.formatType == kMVKFormatDepthStencil || vkDesc.formatType == kMVKFormatCompressed ||
|
||||
chromaSubsamplingComponentBits > 0) ) {
|
||||
enableFormatFeatures(Read, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
|
||||
enableFormatFeatures(Write, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
|
||||
enableFormatFeatures(Atomic, Buf, mtlPixFmtCaps, vkProps.bufferFeatures);
|
||||
|
Loading…
x
Reference in New Issue
Block a user