Merge pull request #662 from billhollings/master
Multiple fixes to image clear and texture memory (CTS)
diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h
index b2c59ba..a3e9792 100644
--- a/MoltenVK/MoltenVK/API/mvk_datatypes.h
+++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h
@@ -464,8 +464,8 @@
/** Returns the Metal CPU cache mode corresponding to the specified Vulkan memory flags. */
MTLCPUCacheMode mvkMTLCPUCacheModeFromVkMemoryPropertyFlags(VkMemoryPropertyFlags vkFlags);
-/** Returns the Metal resource option flags corresponding to the specified Vulkan memory flags. */
-MTLResourceOptions mvkMTLResourceOptionsFromVkMemoryPropertyFlags(VkMemoryPropertyFlags vkFlags);
+/** Returns the Metal resource option flags corresponding to the Metal storage mode and cache mode. */
+MTLResourceOptions mvkMTLResourceOptions(MTLStorageMode mtlStorageMode, MTLCPUCacheMode mtlCPUCacheMode);
#ifdef __cplusplus
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index 237c9c3..c7b9087 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -1055,8 +1055,15 @@
for (uint32_t i = 0; i < rangeCount; i++) {
_subresourceRanges.push_back(pRanges[i]);
}
+
+ // Validate
+ if ( !_image->getSupportsAllFormatFeatures(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClearImage(): Format %s cannot be cleared on this device.", mvkVkFormatName(_image->getVkFormat())));
+ }
}
void MVKCmdClearImage::encode(MVKCommandEncoder* cmdEncoder) {
+ if (getConfigurationResult()) { return; }
+
id<MTLTexture> imgMTLTex = _image->getMTLTexture();
if ( !imgMTLTex ) { return; }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
index 18da46f..f56cd86 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
@@ -45,6 +45,12 @@
pMemoryRequirements->size = getByteCount();
pMemoryRequirements->alignment = _byteAlignment;
pMemoryRequirements->memoryTypeBits = _device->getPhysicalDevice()->getAllMemoryTypes();
+#if MVK_MACOS
+ // Textures must not use shared memory
+ if (mvkIsAnyFlagEnabled(_usage, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT)) {
+ mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
+ }
+#endif
#if MVK_IOS
// Memoryless storage is not allowed for buffers
mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getLazilyAllocatedMemoryTypes());
@@ -160,17 +166,9 @@
width: _textureSize.width
height: _textureSize.height
mipmapped: NO];
-#if MVK_MACOS
- // Textures on Mac cannot use shared storage, so force managed.
- if (_buffer->getMTLBuffer().storageMode == MTLStorageModeShared) {
- mtlTexDesc.storageMode = MTLStorageModeManaged;
- } else {
- mtlTexDesc.storageMode = _buffer->getMTLBuffer().storageMode;
- }
-#else
- mtlTexDesc.storageMode = _buffer->getMTLBuffer().storageMode;
-#endif
- mtlTexDesc.cpuCacheMode = _buffer->getMTLBuffer().cpuCacheMode;
+ id<MTLBuffer> mtlBuff = _buffer->getMTLBuffer();
+ mtlTexDesc.storageMode = mtlBuff.storageMode;
+ mtlTexDesc.cpuCacheMode = mtlBuff.cpuCacheMode;
mtlTexDesc.usage = MTLTextureUsageShaderRead;
if ( mvkIsAnyFlagEnabled(_buffer->getUsage(), VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) ) {
mtlTexDesc.usage |= MTLTextureUsageShaderWrite;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
index 5c13988..c87b443 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
@@ -101,7 +101,7 @@
inline MTLCPUCacheMode getMTLCPUCacheMode() { return _mtlCPUCacheMode; }
/** Returns the Metal reource options used by this memory allocation. */
- inline MTLResourceOptions getMTLResourceOptions() { return _mtlResourceOptions; }
+ inline MTLResourceOptions getMTLResourceOptions() { return mvkMTLResourceOptions(_mtlStorageMode, _mtlCPUCacheMode); }
#pragma mark Construction
@@ -139,7 +139,6 @@
void* _pHostMemory = nullptr;
bool _isMapped = false;
bool _isDedicated = false;
- MTLResourceOptions _mtlResourceOptions;
MTLStorageMode _mtlStorageMode;
MTLCPUCacheMode _mtlCPUCacheMode;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
index b179646..ee4aedf 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
@@ -163,10 +163,10 @@
// If host memory was already allocated, it is copied into the new MTLBuffer, and then released.
if (_pHostMemory) {
- _mtlBuffer = [getMTLDevice() newBufferWithBytes: _pHostMemory length: memLen options: _mtlResourceOptions]; // retained
+ _mtlBuffer = [getMTLDevice() newBufferWithBytes: _pHostMemory length: memLen options: getMTLResourceOptions()]; // retained
freeHostMemory();
} else {
- _mtlBuffer = [getMTLDevice() newBufferWithLength: memLen options: _mtlResourceOptions]; // retained
+ _mtlBuffer = [getMTLDevice() newBufferWithLength: memLen options: getMTLResourceOptions()]; // retained
}
_pMemory = isMemoryHostAccessible() ? _mtlBuffer.contents : nullptr;
@@ -210,7 +210,6 @@
const VkAllocationCallbacks* pAllocator) : MVKVulkanAPIDeviceObject(device) {
// Set Metal memory parameters
VkMemoryPropertyFlags vkMemProps = _device->_pMemoryProperties->memoryTypes[pAllocateInfo->memoryTypeIndex].propertyFlags;
- _mtlResourceOptions = mvkMTLResourceOptionsFromVkMemoryPropertyFlags(vkMemProps);
_mtlStorageMode = mvkMTLStorageModeFromVkMemoryPropertyFlags(vkMemProps);
_mtlCPUCacheMode = mvkMTLCPUCacheModeFromVkMemoryPropertyFlags(vkMemProps);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index 7403d03..0c5e3bf 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -61,9 +61,21 @@
/** Returns the Vulkan image format of this image. */
VkFormat getVkFormat();
- /** Returns whether this texture is compressed. */
+ /** Returns whether this image is compressed. */
bool getIsCompressed();
+ /**
+ * Returns whether the format of this image supports ANY of the indicated feature flags,
+ * taking into consideration whether this image is using linear or optimal tiling.
+ */
+ bool getSupportsAnyFormatFeature(VkFormatFeatureFlags requiredFormatFeatureFlags);
+
+ /**
+ * Returns whether the format of this image supports ALL of the indicated feature flags,
+ * taking into consideration whether this image is using linear or optimal tiling.
+ */
+ bool getSupportsAllFormatFeatures(VkFormatFeatureFlags requiredFormatFeatureFlags);
+
/**
* Returns the 3D extent of this image at the base mipmap level.
* For 2D or cube images, the Z component will be 1.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index c08c036..de49bb3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -45,6 +45,20 @@
return mvkFormatTypeFromMTLPixelFormat(_mtlPixelFormat) == kMVKFormatCompressed;
}
+bool MVKImage::getSupportsAnyFormatFeature(VkFormatFeatureFlags requiredFormatFeatureFlags) {
+ VkFormatProperties props;
+ _device->getPhysicalDevice()->getFormatProperties(getVkFormat(), &props);
+ VkFormatFeatureFlags imageFeatureFlags = _isLinear ? props.linearTilingFeatures : props.optimalTilingFeatures;
+ return mvkIsAnyFlagEnabled(imageFeatureFlags, requiredFormatFeatureFlags);
+}
+
+bool MVKImage::getSupportsAllFormatFeatures(VkFormatFeatureFlags requiredFormatFeatureFlags) {
+ VkFormatProperties props;
+ _device->getPhysicalDevice()->getFormatProperties(getVkFormat(), &props);
+ VkFormatFeatureFlags imageFeatureFlags = _isLinear ? props.linearTilingFeatures : props.optimalTilingFeatures;
+ return mvkAreAllFlagsEnabled(imageFeatureFlags, requiredFormatFeatureFlags);
+}
+
VkExtent3D MVKImage::getExtent3D(uint32_t mipLevel) {
return mvkMipmapLevelSizeFromBaseSize3D(_extent, mipLevel);
}
@@ -161,9 +175,8 @@
? _device->getPhysicalDevice()->getPrivateMemoryTypes()
: _device->getPhysicalDevice()->getAllMemoryTypes());
#if MVK_MACOS
- if (!_isLinear) { // XXX Linear images must support host-coherent memory
- mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
- }
+ // Textures must not use shared memory
+ mvkDisableFlag(pMemoryRequirements->memoryTypeBits, _device->getPhysicalDevice()->getHostCoherentMemoryTypes());
#endif
#if MVK_IOS
// Only transient attachments may use memoryless storage
@@ -388,13 +401,10 @@
mvkDisableFlag(usage, MTLTextureUsagePixelFormatView);
}
- // If this format doesn't support being blitted to, and the usage
- // doesn't specify use as an attachment, turn off
- // MTLTextureUsageRenderTarget.
- VkFormatProperties props;
- _device->getPhysicalDevice()->getFormatProperties(getVkFormat(), &props);
- if (!mvkAreAllFlagsEnabled(_isLinear ? props.linearTilingFeatures : props.optimalTilingFeatures, VK_FORMAT_FEATURE_BLIT_DST_BIT) &&
- !mvkIsAnyFlagEnabled(_usage, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
+ // If this format doesn't support being rendered to, disable MTLTextureUsageRenderTarget.
+ if ( !getSupportsAnyFormatFeature(VK_FORMAT_FEATURE_BLIT_DST_BIT |
+ VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT |
+ VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) ) {
mvkDisableFlag(usage, MTLTextureUsageRenderTarget);
}
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
index 4e4390e..b58a603 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
@@ -1395,44 +1395,9 @@
return MTLCPUCacheModeDefaultCache;
}
-MVK_PUBLIC_SYMBOL MTLResourceOptions mvkMTLResourceOptionsFromVkMemoryPropertyFlags(VkMemoryPropertyFlags vkFlags) {
- MTLResourceOptions mtlFlags = 0;
-
- // First set the resource CPU cache mode
- MTLCPUCacheMode mtlCPUMode = mvkMTLCPUCacheModeFromVkMemoryPropertyFlags(vkFlags);
- switch (mtlCPUMode) {
- case MTLCPUCacheModeDefaultCache:
- mvkEnableFlag(mtlFlags, MTLResourceCPUCacheModeDefaultCache);
- break;
- case MTLCPUCacheModeWriteCombined:
- mvkEnableFlag(mtlFlags, MTLResourceCPUCacheModeWriteCombined);
- break;
- }
-
- // Then set the resource storage mode
- MTLStorageMode mtlStgMode = mvkMTLStorageModeFromVkMemoryPropertyFlags(vkFlags);
- switch (mtlStgMode) {
- case MTLStorageModePrivate:
- mvkEnableFlag(mtlFlags, MTLResourceStorageModePrivate);
- break;
- case MTLStorageModeShared:
- mvkEnableFlag(mtlFlags, MTLResourceStorageModeShared);
- break;
-#if MVK_MACOS
- case MTLStorageModeManaged:
- mvkEnableFlag(mtlFlags, MTLResourceStorageModeManaged);
- break;
-#endif
-#if MVK_IOS
- case MTLStorageModeMemoryless:
- mvkEnableFlag(mtlFlags, MTLResourceStorageModeMemoryless);
- break;
-#endif
- default: // Silence erroneous -Wswitch-enum warning on MTLResourceStorageModeManaged under iOS
- break;
- }
-
- return mtlFlags;
+MVK_PUBLIC_SYMBOL MTLResourceOptions mvkMTLResourceOptions(MTLStorageMode mtlStorageMode,
+ MTLCPUCacheMode mtlCPUCacheMode) {
+ return (mtlStorageMode << MTLResourceStorageModeShift) | (mtlCPUCacheMode << MTLResourceCPUCacheModeShift);
}