Merge pull request #1058 from billhollings/xcode12
Sync Xcode12 branch from master and support Xcode 11.7.
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 28e913f..f1fc211 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -274,6 +274,7 @@
- `VK_KHR_bind_memory2`
- `VK_KHR_create_renderpass2`
- `VK_KHR_dedicated_allocation`
+- `VK_KHR_depth_stencil_resolve`
- `VK_KHR_descriptor_update_template`
- `VK_KHR_device_group`
- `VK_KHR_device_group_creation`
@@ -286,6 +287,7 @@
- `VK_KHR_maintenance2`
- `VK_KHR_maintenance3`
- `VK_KHR_multiview`
+- `VK_KHR_portability_subset`
- `VK_KHR_push_descriptor`
- `VK_KHR_relaxed_block_layout`
- `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)*
@@ -315,7 +317,6 @@
- `VK_EXT_swapchain_colorspace`
- `VK_EXT_vertex_attribute_divisor`
- `VK_EXT_texel_buffer_alignment` *(requires Metal 2.0)*
-- `VK_EXTX_portability_subset`
- `VK_MVK_ios_surface` *(iOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)*
- `VK_MVK_macos_surface` *(macOS) (Obsolete. Use `VK_EXT_metal_surface` instead.)*
- `VK_MVK_moltenvk`
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index b34e5a7..6ee632b 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -18,6 +18,8 @@
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
@@ -25,7 +27,9 @@
- A feature struct for `VK_KHR_shader_draw_parameters`
- All extensions that were promoted to core in Vulkan 1.1
- Add support for extensions:
+ - `VK_KHR_portability_subset`
- `VK_KHR_create_renderpass2`
+ - `VK_KHR_depth_stencil_resolve`
- `VK_KHR_external_fence` (non-functional groundwork for future extensions,
including support for GCD and Mach semaphores)
- `VK_KHR_external_fence_capabilities` (non-functional groundwork for future
@@ -35,6 +39,13 @@
- `VK_KHR_external_semaphore_capabilities` (non-functional groundwork for
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
diff --git a/ExternalRevisions/Vulkan-Headers_repo_revision b/ExternalRevisions/Vulkan-Headers_repo_revision
index d347369..77ca791 100644
--- a/ExternalRevisions/Vulkan-Headers_repo_revision
+++ b/ExternalRevisions/Vulkan-Headers_repo_revision
@@ -1 +1 @@
-83825d55c7d522931124696ecb07ed48f2693e5c
+7f9879b1b1fab53f719a9ed5e6e29533b10972b2
diff --git a/ExternalRevisions/Vulkan-Portability_repo_revision b/ExternalRevisions/Vulkan-Portability_repo_revision
deleted file mode 100644
index 3a9f9eb..0000000
--- a/ExternalRevisions/Vulkan-Portability_repo_revision
+++ /dev/null
@@ -1 +0,0 @@
-53be040f04ce55463d0e5b25fd132f45f003e903
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index b3b771f..4c1567c 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -124,6 +124,16 @@
2FEA0AB424902F9F00EEF3AD /* MVKCmdDebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C90ED229455B300A061DA /* MVKCmdDebug.mm */; };
45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
45003E74214AD4E600E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
+ 453638322508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = 4536382D2508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h */; };
+ 453638342508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = 4536382D2508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h */; };
+ 453638352508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */; };
+ 453638362508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */; };
+ 453638372508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */; };
+ 453638382508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 453638302508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m */; };
+ 4536383A2508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 453638302508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m */; };
+ 4536383B2508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = 453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */; };
+ 4536383C2508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = 453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */; };
+ 4536383D2508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = 453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */; };
4553AEFB2251617100E8EBCD /* MVKBlockObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4553AEF62251617100E8EBCD /* MVKBlockObserver.m */; };
4553AEFC2251617100E8EBCD /* MVKBlockObserver.m in Sources */ = {isa = PBXBuildFile; fileRef = 4553AEF62251617100E8EBCD /* MVKBlockObserver.m */; };
4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */ = {isa = PBXBuildFile; fileRef = 4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */; };
@@ -451,6 +461,10 @@
/* Begin PBXFileReference section */
2FEA0ABA24902F9F00EEF3AD /* libMoltenVK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVK.a; sourceTree = BUILT_PRODUCTS_DIR; };
45003E6F214AD4C900E989CB /* MVKExtensions.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKExtensions.def; sourceTree = "<group>"; };
+ 4536382D2508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
+ 4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
+ 453638302508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m"; sourceTree = "<group>"; };
+ 453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
4553AEF62251617100E8EBCD /* MVKBlockObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVKBlockObserver.m; sourceTree = "<group>"; };
4553AEFA2251617100E8EBCD /* MVKBlockObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKBlockObserver.h; sourceTree = "<group>"; };
45557A4D21C9EFF3008868BD /* MVKCodec.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MVKCodec.cpp; sourceTree = "<group>"; };
@@ -571,7 +585,6 @@
A9E53DFE21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPipelineDescriptor+MoltenVK.h"; sourceTree = "<group>"; };
A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommonEnvironment.h; sourceTree = "<group>"; };
A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKLogging.h; sourceTree = "<group>"; };
- A9F2559121F96814008C7785 /* vulkan-portability */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vulkan-portability"; sourceTree = "<group>"; };
A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVectorAllocator.h; sourceTree = "<group>"; };
A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVector.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -750,7 +763,6 @@
isa = PBXGroup;
children = (
A9AD67C72054DD6C00ED3C08 /* vulkan */,
- A9F2559121F96814008C7785 /* vulkan-portability */,
);
path = include;
sourceTree = "<group>";
@@ -760,8 +772,12 @@
children = (
A9E53DD12100B197002781DD /* CAMetalLayer+MoltenVK.h */,
A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */,
+ 453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */,
+ 4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */,
A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */,
A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */,
+ 4536382D2508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h */,
+ 453638302508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m */,
A9E53DFE21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.h */,
A9E53DFA21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m */,
A9E53DD32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h */,
@@ -873,6 +889,7 @@
2FEA0A7524902F9F00EEF3AD /* MVKCmdDebug.h in Headers */,
2FEA0A7624902F9F00EEF3AD /* MVKWatermarkTextureContent.h in Headers */,
2FEA0A7724902F9F00EEF3AD /* MVKFoundation.h in Headers */,
+ 4536383C2508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */,
2FEA0A7824902F9F00EEF3AD /* MVKDeviceMemory.h in Headers */,
2FEA0A7924902F9F00EEF3AD /* MVKMTLResourceBindings.h in Headers */,
2FEA0A7A24902F9F00EEF3AD /* MVKExtensions.def in Headers */,
@@ -908,6 +925,7 @@
45557A5421C9EFF3008868BD /* MVKCodec.h in Headers */,
A94FB8041C7DFB4800632CA3 /* MVKRenderPass.h in Headers */,
A9F042A61FB4CF83009FCCB8 /* MVKLogging.h in Headers */,
+ 453638322508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h in Headers */,
A94FB8001C7DFB4800632CA3 /* MVKQueue.h in Headers */,
A94FB7EC1C7DFB4800632CA3 /* MVKFramebuffer.h in Headers */,
83A4AD2C21BD75570006C935 /* MVKVectorAllocator.h in Headers */,
@@ -951,6 +969,7 @@
A9CEAAD5227378D400FAF779 /* mvk_datatypes.hpp in Headers */,
A90C8DEA1F45354D009CB32C /* MVKCommandEncodingPool.h in Headers */,
A94FB8081C7DFB4800632CA3 /* MVKResource.h in Headers */,
+ 4536383B2508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */,
A9E53DDD2100B197002781DD /* MTLTextureDescriptor+MoltenVK.h in Headers */,
A9653FBA24129C84005999D7 /* MVKPixelFormats.h in Headers */,
A981496B1FB6A998005F00B4 /* MVKStrings.h in Headers */,
@@ -980,6 +999,7 @@
45557A5521C9EFF3008868BD /* MVKCodec.h in Headers */,
A94FB8051C7DFB4800632CA3 /* MVKRenderPass.h in Headers */,
A9F042A71FB4CF83009FCCB8 /* MVKLogging.h in Headers */,
+ 453638342508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h in Headers */,
A94FB8011C7DFB4800632CA3 /* MVKQueue.h in Headers */,
A94FB7ED1C7DFB4800632CA3 /* MVKFramebuffer.h in Headers */,
83A4AD2D21BD75570006C935 /* MVKVectorAllocator.h in Headers */,
@@ -1023,6 +1043,7 @@
A9CEAAD6227378D400FAF779 /* mvk_datatypes.hpp in Headers */,
A90C8DEB1F45354D009CB32C /* MVKCommandEncodingPool.h in Headers */,
A94FB8091C7DFB4800632CA3 /* MVKResource.h in Headers */,
+ 4536383D2508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h in Headers */,
A9E53DDE2100B197002781DD /* MTLTextureDescriptor+MoltenVK.h in Headers */,
A9653FBB24129C84005999D7 /* MVKPixelFormats.h in Headers */,
A981496C1FB6A998005F00B4 /* MVKStrings.h in Headers */,
@@ -1377,6 +1398,7 @@
2FEA0A9B24902F9F00EEF3AD /* MVKFoundation.cpp in Sources */,
2FEA0A9C24902F9F00EEF3AD /* MVKPixelFormats.mm in Sources */,
2FEA0A9D24902F9F00EEF3AD /* MVKDevice.mm in Sources */,
+ 453638362508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */,
2FEA0A9E24902F9F00EEF3AD /* MTLRenderPassDescriptor+MoltenVK.m in Sources */,
2FEA0A9F24902F9F00EEF3AD /* MVKDescriptor.mm in Sources */,
2FEA0AA024902F9F00EEF3AD /* MVKPipeline.mm in Sources */,
@@ -1419,6 +1441,7 @@
A981494D1FB6A3F7005F00B4 /* MVKBaseObject.mm in Sources */,
A9E53DE52100B197002781DD /* NSString+MoltenVK.mm in Sources */,
A94FB8321C7DFB4800632CA3 /* vulkan.mm in Sources */,
+ 453638352508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */,
A94FB8121C7DFB4800632CA3 /* MVKSurface.mm in Sources */,
A94FB7FE1C7DFB4800632CA3 /* MVKQueryPool.mm in Sources */,
A94FB7F61C7DFB4800632CA3 /* MVKInstance.mm in Sources */,
@@ -1453,6 +1476,7 @@
A94FB7BE1C7DFB4800632CA3 /* MVKCmdPipeline.mm in Sources */,
A94FB81E1C7DFB4800632CA3 /* MVKLayers.mm in Sources */,
A94FB7EE1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */,
+ 453638382508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
A9C96DD21DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */,
A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */,
A9096E5E1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */,
@@ -1476,6 +1500,7 @@
A981494E1FB6A3F7005F00B4 /* MVKBaseObject.mm in Sources */,
A9E53DE62100B197002781DD /* NSString+MoltenVK.mm in Sources */,
A94FB8331C7DFB4800632CA3 /* vulkan.mm in Sources */,
+ 453638372508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m in Sources */,
A94FB8131C7DFB4800632CA3 /* MVKSurface.mm in Sources */,
A94FB7FF1C7DFB4800632CA3 /* MVKQueryPool.mm in Sources */,
A94FB7F71C7DFB4800632CA3 /* MVKInstance.mm in Sources */,
@@ -1510,6 +1535,7 @@
A94FB7BF1C7DFB4800632CA3 /* MVKCmdPipeline.mm in Sources */,
A94FB81F1C7DFB4800632CA3 /* MVKLayers.mm in Sources */,
A94FB7EF1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */,
+ 4536383A2508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */,
A9C96DD31DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */,
A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */,
A9096E5F1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */,
diff --git a/MoltenVK/MoltenVK/API/mvk_datatypes.h b/MoltenVK/MoltenVK/API/mvk_datatypes.h
index 3f9e601..12628c5 100644
--- a/MoltenVK/MoltenVK/API/mvk_datatypes.h
+++ b/MoltenVK/MoltenVK/API/mvk_datatypes.h
@@ -362,6 +362,14 @@
/** Returns the Metal MTLStoreAction corresponding to the specified Vulkan VkAttachmentStoreOp. */
MTLStoreAction mvkMTLStoreActionFromVkAttachmentStoreOp(VkAttachmentStoreOp vkStoreOp, bool hasResolveAttachment);
+/** Returns the Metal MTLMultisampleDepthResolveFilter corresponding to the specified Vulkan VkResolveModeFlagBits. */
+MTLMultisampleDepthResolveFilter mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(VkResolveModeFlagBits vkResolveMode);
+
+#if MVK_MACOS_OR_IOS
+/** Returns the Metal MTLMultisampleStencilResolveFilter corresponding to the specified Vulkan VkResolveModeFlagBits. */
+MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(VkResolveModeFlagBits vkResolveMode);
+#endif
+
/** Returns the Metal MTLViewport corresponding to the specified Vulkan VkViewport. */
MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport);
diff --git a/MoltenVK/MoltenVK/API/mvk_vulkan.h b/MoltenVK/MoltenVK/API/mvk_vulkan.h
index 757bb7e..f234ead 100644
--- a/MoltenVK/MoltenVK/API/mvk_vulkan.h
+++ b/MoltenVK/MoltenVK/API/mvk_vulkan.h
@@ -35,6 +35,8 @@
#define VK_USE_PLATFORM_METAL_EXT 1
+#define VK_ENABLE_BETA_EXTENSIONS 1 // VK_KHR_portability_subset
+
#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
# define VK_USE_PLATFORM_IOS_MVK 1
#endif
@@ -44,6 +46,5 @@
#endif
#include <vulkan/vulkan.h>
-#include <vulkan-portability/vk_extx_portability_subset.h>
#endif
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index 309097a..80f1e10 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -617,6 +617,10 @@
VkBool32 nonUniformThreadgroups; /**< If true, the device supports arbitrary-sized grids in compute workloads. */
VkBool32 renderWithoutAttachments; /**< If true, we don't have to create a dummy attachment for a render pass if there isn't one. */
VkBool32 deferredStoreActions; /**< If true, render pass store actions can be specified after the render encoder is created. */
+ 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. */
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
index 964af0d..e657b04 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
@@ -629,6 +629,11 @@
[mtlTessCtlEncoder dispatchThreadgroups: MTLSizeMake(mvkCeilingDivide<NSUInteger>(_drawCount, mtlConvertState.threadExecutionWidth), 1, 1)
threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)];
}
+ // Mark pipelines, resources, and vertex push constants as dirty
+ // so I apply them during the next stage.
+ cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
+ cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
+ cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass();
} else if (drawIdx == 0 && needsInstanceAdjustment) {
// Similarly, for multiview, we need to adjust the instance count now.
// Unfortunately, this requires switching to compute.
@@ -954,6 +959,11 @@
indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
mtlIndBuffOfst += sizeof(MTLDrawIndexedPrimitivesIndirectArguments);
+ // Mark pipeline, resources, and vertex push constants as dirty
+ // so I apply them during the next stage.
+ cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
+ cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
+ cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass();
} else if (drawIdx == 0 && needsInstanceAdjustment) {
// Similarly, for multiview, we need to adjust the instance count now.
// Unfortunately, this requires switching to compute. Luckily, we don't also
@@ -1089,11 +1099,11 @@
}
mtlTempIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments);
- // Mark pipeline, resources, and tess control push constants as dirty
+ // Mark pipeline, resources, and vertex push constants as dirty
// so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
- cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass();
+ cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass();
} else {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexType: (MTLIndexType)ibb.mtlIndexType
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
index b2985ee..98616cb 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
@@ -139,11 +139,13 @@
void encode(MVKCommandEncoder* cmdEncoder) override;
+ ~MVKCmdBindDescriptorSetsStatic() override;
+
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
MVKSmallVector<MVKDescriptorSet*, N> _descriptorSets;
- MVKPipelineLayout* _pipelineLayout;
+ MVKPipelineLayout* _pipelineLayout = nullptr;
VkPipelineBindPoint _pipelineBindPoint;
uint32_t _firstSet;
};
@@ -211,7 +213,6 @@
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
MVKSmallVector<char, N> _pushConstants;
- MVKPipelineLayout* _pipelineLayout;
VkShaderStageFlags _stageFlags;
uint32_t _offset;
};
@@ -245,7 +246,7 @@
void clearDescriptorWrites();
MVKSmallVector<VkWriteDescriptorSet, 1> _descriptorWrites;
- MVKPipelineLayout* _pipelineLayout;
+ MVKPipelineLayout* _pipelineLayout = nullptr;
VkPipelineBindPoint _pipelineBindPoint;
uint32_t _set;
};
@@ -272,7 +273,7 @@
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
MVKDescriptorUpdateTemplate* _descUpdateTemplate;
- MVKPipelineLayout* _pipelineLayout;
+ MVKPipelineLayout* _pipelineLayout = nullptr;
void* _pData = nullptr;
uint32_t _set;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
index 4e12de5..00029a6 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
@@ -193,10 +193,14 @@
uint32_t firstSet,
uint32_t setCount,
const VkDescriptorSet* pDescriptorSets) {
+ if (_pipelineLayout) { _pipelineLayout->release(); }
+
_pipelineBindPoint = pipelineBindPoint;
_pipelineLayout = (MVKPipelineLayout*)layout;
_firstSet = firstSet;
+ _pipelineLayout->retain();
+
// Add the descriptor sets
_descriptorSets.clear(); // Clear for reuse
_descriptorSets.reserve(setCount);
@@ -212,6 +216,11 @@
_pipelineLayout->bindDescriptorSets(cmdEncoder, _descriptorSets.contents(), _firstSet, MVKArrayRef<uint32_t>());
}
+template <size_t N>
+MVKCmdBindDescriptorSetsStatic<N>::~MVKCmdBindDescriptorSetsStatic() {
+ if (_pipelineLayout) { _pipelineLayout->release(); }
+}
+
template class MVKCmdBindDescriptorSetsStatic<1>;
template class MVKCmdBindDescriptorSetsStatic<4>;
template class MVKCmdBindDescriptorSetsStatic<8>;
@@ -262,7 +271,6 @@
uint32_t offset,
uint32_t size,
const void* pValues) {
- _pipelineLayout = (MVKPipelineLayout*)layout;
_stageFlags = stageFlags;
_offset = offset;
@@ -302,10 +310,14 @@
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites) {
+ if (_pipelineLayout) { _pipelineLayout->release(); }
+
_pipelineBindPoint = pipelineBindPoint;
_pipelineLayout = (MVKPipelineLayout*)layout;
_set = set;
+ _pipelineLayout->retain();
+
// Add the descriptor writes
MVKDevice* mvkDvc = cmdBuff->getDevice();
clearDescriptorWrites(); // Clear for reuse
@@ -360,6 +372,7 @@
MVKCmdPushDescriptorSet::~MVKCmdPushDescriptorSet() {
clearDescriptorWrites();
+ if (_pipelineLayout) { _pipelineLayout->release(); }
}
void MVKCmdPushDescriptorSet::clearDescriptorWrites() {
@@ -393,9 +406,14 @@
VkPipelineLayout layout,
uint32_t set,
const void* pData) {
+ if (_pipelineLayout) { _pipelineLayout->release(); }
+
_descUpdateTemplate = (MVKDescriptorUpdateTemplate*)descUpdateTemplate;
_pipelineLayout = (MVKPipelineLayout*)layout;
_set = set;
+
+ _pipelineLayout->retain();
+
if (_pData) delete[] (char*)_pData;
// Work out how big the memory block in pData is.
const VkDescriptorUpdateTemplateEntryKHR* pEntry =
@@ -443,6 +461,7 @@
}
MVKCmdPushDescriptorSetWithTemplate::~MVKCmdPushDescriptorSetWithTemplate() {
+ if (_pipelineLayout) { _pipelineLayout->release(); }
if (_pData) delete[] (char*)_pData;
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
index 4bc8b11..849d51c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
@@ -125,9 +125,8 @@
/** Describes Metal texture resolve parameters. */
typedef struct {
- VkImageCopy* copyRegion;
- uint32_t level;
- uint32_t slice;
+ VkImageSubresource srcSubresource;
+ VkImageSubresource dstSubresource;
} MVKMetalResolveSlice;
/**
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index f494748..15e4b1f 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -77,11 +77,6 @@
_vkImageCopies.push_back(vkIR);
}
- // Validate
- if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
- return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdCopyImage(): Metal does not support copying to or from slices of a 3D texture.");
- }
-
return VK_SUCCESS;
}
@@ -160,25 +155,62 @@
// If copies can be performed using direct texture-texture copying, do so
uint32_t srcLevel = vkIC.srcSubresource.mipLevel;
MTLOrigin srcOrigin = mvkMTLOriginFromVkOffset3D(vkIC.srcOffset);
- MTLSize srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
- srcOrigin,
- mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcPlaneIndex, srcLevel)));
+ MTLSize srcSize;
+ uint32_t layCnt;
+ if ((_srcImage->getMTLTextureType() == MTLTextureType3D) != (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
+ // In the case, the number of layers to copy is in extent.depth. Use that value,
+ // then clamp the depth so we don't try to copy more than Metal will allow.
+ layCnt = vkIC.extent.depth;
+ srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
+ srcOrigin,
+ mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcPlaneIndex, srcLevel)));
+ srcSize.depth = 1;
+ } else {
+ layCnt = vkIC.srcSubresource.layerCount;
+ srcSize = mvkClampMTLSize(mvkMTLSizeFromVkExtent3D(vkIC.extent),
+ srcOrigin,
+ mvkMTLSizeFromVkExtent3D(_srcImage->getExtent3D(srcPlaneIndex, srcLevel)));
+ }
uint32_t dstLevel = vkIC.dstSubresource.mipLevel;
MTLOrigin dstOrigin = mvkMTLOriginFromVkOffset3D(vkIC.dstOffset);
uint32_t srcBaseLayer = vkIC.srcSubresource.baseArrayLayer;
uint32_t dstBaseLayer = vkIC.dstSubresource.baseArrayLayer;
- uint32_t layCnt = vkIC.srcSubresource.layerCount;
-
+
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
- [mtlBlitEnc copyFromTexture: srcMTLTex
- sourceSlice: srcBaseLayer + layIdx
- sourceLevel: srcLevel
- sourceOrigin: srcOrigin
- sourceSize: srcSize
- toTexture: dstMTLTex
- destinationSlice: dstBaseLayer + layIdx
- destinationLevel: dstLevel
- destinationOrigin: dstOrigin];
+ // We can copy between a 3D and a 2D image easily. Just copy between
+ // one slice of the 2D image and one plane of the 3D image at a time.
+ if ((_srcImage->getMTLTextureType() == MTLTextureType3D) == (_dstImage->getMTLTextureType() == MTLTextureType3D)) {
+ [mtlBlitEnc copyFromTexture: srcMTLTex
+ sourceSlice: srcBaseLayer + layIdx
+ sourceLevel: srcLevel
+ sourceOrigin: srcOrigin
+ sourceSize: srcSize
+ toTexture: dstMTLTex
+ destinationSlice: dstBaseLayer + layIdx
+ destinationLevel: dstLevel
+ destinationOrigin: dstOrigin];
+ } else if (_srcImage->getMTLTextureType() == MTLTextureType3D) {
+ [mtlBlitEnc copyFromTexture: srcMTLTex
+ sourceSlice: srcBaseLayer
+ sourceLevel: srcLevel
+ sourceOrigin: MTLOriginMake(srcOrigin.x, srcOrigin.y, srcOrigin.z + layIdx)
+ sourceSize: srcSize
+ toTexture: dstMTLTex
+ destinationSlice: dstBaseLayer + layIdx
+ destinationLevel: dstLevel
+ destinationOrigin: dstOrigin];
+ } else {
+ assert(_dstImage->getMTLTextureType() == MTLTextureType3D);
+ [mtlBlitEnc copyFromTexture: srcMTLTex
+ sourceSlice: srcBaseLayer + layIdx
+ sourceLevel: srcLevel
+ sourceOrigin: srcOrigin
+ sourceSize: srcSize
+ toTexture: dstMTLTex
+ destinationSlice: dstBaseLayer
+ destinationLevel: dstLevel
+ destinationOrigin: MTLOriginMake(dstOrigin.x, dstOrigin.y, dstOrigin.z + layIdx)];
+ }
}
}
}
@@ -396,6 +428,18 @@
MVKRPSKeyBlitImg blitKey;
blitKey.srcMTLPixelFormat = _srcImage->getMTLPixelFormat(srcPlaneIndex);
blitKey.srcMTLTextureType = _srcImage->getMTLTextureType();
+ if (blitKey.srcMTLTextureType == MTLTextureTypeCube || blitKey.srcMTLTextureType == MTLTextureTypeCubeArray) {
+ // In this case, I'll use a temp 2D array view. That way, I don't have to
+ // deal with mapping the blit coordinates to a cube direction vector.
+ blitKey.srcMTLTextureType = MTLTextureType2DArray;
+ srcMTLTex = [srcMTLTex newTextureViewWithPixelFormat: (MTLPixelFormat)blitKey.srcMTLPixelFormat
+ textureType: MTLTextureType2DArray
+ levels: NSMakeRange(0, srcMTLTex.mipmapLevelCount)
+ slices: NSMakeRange(0, srcMTLTex.arrayLength)];
+ [cmdEncoder->_mtlCmdBuffer addCompletedHandler: ^(id<MTLCommandBuffer>) {
+ [srcMTLTex release];
+ }];
+ }
blitKey.dstMTLPixelFormat = _dstImage->getMTLPixelFormat(dstPlaneIndex);
blitKey.srcFilter = mvkMTLSamplerMinMagFilterFromVkFilter(_filter);
blitKey.dstSampleCount = mvkSampleCountFromVkSampleCountFlagBits(_dstImage->getSampleCount());
@@ -406,12 +450,31 @@
mtlColorAttDesc.level = mvkIBR.region.dstSubresource.mipLevel;
uint32_t layCnt = mvkIBR.region.srcSubresource.layerCount;
+ if (_dstImage->getMTLTextureType() == MTLTextureType3D) {
+ layCnt = mvkAbsDiff(mvkIBR.region.dstOffsets[1].z, mvkIBR.region.dstOffsets[0].z);
+ }
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
// Update the render pass descriptor for the texture level and slice, and create a render encoder.
- mtlColorAttDesc.slice = mvkIBR.region.dstSubresource.baseArrayLayer + layIdx;
+ if (_dstImage->getMTLTextureType() == MTLTextureType3D) {
+ mtlColorAttDesc.depthPlane = mvkIBR.region.dstOffsets[0].z + (mvkIBR.region.dstOffsets[1].z > mvkIBR.region.dstOffsets[0].z ? layIdx : -(layIdx + 1));
+ } else {
+ mtlColorAttDesc.slice = mvkIBR.region.dstSubresource.baseArrayLayer + layIdx;
+ }
id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(commandUse));
+ if (blitKey.srcMTLTextureType == MTLTextureType3D) {
+ // In this case, I need to interpolate along the third dimension manually.
+ VkExtent3D srcExtent = _srcImage->getExtent3D(srcPlaneIndex, mvkIBR.region.dstSubresource.mipLevel);
+ VkOffset3D so0 = mvkIBR.region.srcOffsets[0], so1 = mvkIBR.region.srcOffsets[1];
+ VkOffset3D do0 = mvkIBR.region.dstOffsets[0], do1 = mvkIBR.region.dstOffsets[1];
+ CGFloat startZ = (CGFloat)so0.z / (CGFloat)srcExtent.depth;
+ CGFloat endZ = (CGFloat)so1.z / (CGFloat)srcExtent.depth;
+ CGFloat zIncr = (endZ - startZ) / mvkAbsDiff(do1.z, do0.z);
+ for (uint32_t i = 0; i < kMVKBlitVertexCount; ++i) {
+ mvkIBR.vertices[i].texCoord.z = startZ + layIdx * zIncr;
+ }
+ }
[mtlRendEnc pushDebugGroup: @"vkCmdBlitImage"];
[mtlRendEnc setRenderPipelineState: mtlRPS];
cmdEncoder->setVertexBytes(mtlRendEnc, mvkIBR.vertices, sizeof(mvkIBR.vertices), vtxBuffIdx);
@@ -490,68 +553,75 @@
uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.srcSubresource.aspectMask);
uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(vkIR.dstSubresource.aspectMask);
- uint32_t mipLvl = vkIR.dstSubresource.mipLevel;
- VkExtent3D srcImgExt = _srcImage->getExtent3D(srcPlaneIndex, mipLvl);
- VkExtent3D dstImgExt = _dstImage->getExtent3D(dstPlaneIndex, mipLvl);
+ VkExtent3D srcImgExt = _srcImage->getExtent3D(srcPlaneIndex, vkIR.srcSubresource.mipLevel);
+ VkExtent3D dstImgExt = _dstImage->getExtent3D(dstPlaneIndex, vkIR.dstSubresource.mipLevel);
- // If the region does not cover the entire content of the source level, expand the
- // destination content in the region to the temporary image. The purpose of this
+ // If the region does not cover the entire content of the destination level, expand
+ // the destination content in the region to the temporary image. The purpose of this
// expansion is to render the existing content of the destination image to the
// temporary transfer multisample image, so that regions of that temporary transfer
// image can then be overwritten with content from the source image, prior to
- // resolving it back to the destination image. The source of this temporary content
- // move is the full extent of the DESTINATION image of the resolve command, and the
- // destination of this temporary content move is the full extent of the SOURCE image.
- if ( !mvkVkExtent3DsAreEqual(srcImgExt, vkIR.extent) ) {
+ // resolving it back to the destination image.
+ if ( !mvkVkExtent3DsAreEqual(dstImgExt, vkIR.extent) ) {
VkImageBlit& expRgn = expansionRegions[expCnt++];
expRgn.srcSubresource = vkIR.dstSubresource;
expRgn.srcOffsets[0] = { 0, 0, 0 };
expRgn.srcOffsets[1] = { int32_t(dstImgExt.width), int32_t(dstImgExt.height), int32_t(dstImgExt.depth) };
expRgn.dstSubresource = vkIR.dstSubresource;
expRgn.dstOffsets[0] = { 0, 0, 0 };
- expRgn.dstOffsets[1] = { int32_t(srcImgExt.width), int32_t(srcImgExt.height), int32_t(srcImgExt.depth) };
+ expRgn.dstOffsets[1] = { int32_t(dstImgExt.width), int32_t(dstImgExt.height), int32_t(dstImgExt.depth) };
}
// Copy the region from the source image to the temporary multisample image,
// prior to the temporary image being resolved back to the destination image.
// The source of this copy stage is the source image, and the destination of
// this copy stage is the temporary transfer image.
- VkImageCopy& cpyRgn = copyRegions[copyCnt++];
- cpyRgn.srcSubresource = vkIR.srcSubresource;
- cpyRgn.srcOffset = vkIR.srcOffset;
- cpyRgn.dstSubresource = vkIR.srcSubresource;
- cpyRgn.dstOffset = vkIR.srcOffset;
- cpyRgn.extent = vkIR.extent;
+ bool needXfrImage = !mvkVkExtent3DsAreEqual(srcImgExt, vkIR.extent) || !mvkVkExtent3DsAreEqual(dstImgExt, vkIR.extent);
+ if ( needXfrImage ) {
+ VkImageCopy& cpyRgn = copyRegions[copyCnt++];
+ cpyRgn.srcSubresource = vkIR.srcSubresource;
+ cpyRgn.srcOffset = vkIR.srcOffset;
+ cpyRgn.dstSubresource = vkIR.dstSubresource;
+ cpyRgn.dstOffset = vkIR.dstOffset;
+ cpyRgn.extent = vkIR.extent;
+ }
// Adds a resolve slice struct for each destination layer in the resolve region.
- uint32_t baseLayer = vkIR.dstSubresource.baseArrayLayer;
+ // Note that the source subresource for this is that of the SOURCE image if we're doing a
+ // direct resolve, but that of the DESTINATION if we need a temporary transfer image.
uint32_t layCnt = vkIR.dstSubresource.layerCount;
for (uint32_t layIdx = 0; layIdx < layCnt; layIdx++) {
MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sliceCnt++];
- rslvSlice.copyRegion = &cpyRgn;
- rslvSlice.level = vkIR.dstSubresource.mipLevel;
- rslvSlice.slice = baseLayer + layIdx;
+ rslvSlice.dstSubresource.aspectMask = vkIR.dstSubresource.aspectMask;
+ rslvSlice.dstSubresource.mipLevel = vkIR.dstSubresource.mipLevel;
+ rslvSlice.dstSubresource.arrayLayer = vkIR.dstSubresource.baseArrayLayer + layIdx;
+ rslvSlice.srcSubresource.aspectMask = needXfrImage ? vkIR.dstSubresource.aspectMask : vkIR.srcSubresource.aspectMask;
+ rslvSlice.srcSubresource.mipLevel = needXfrImage ? vkIR.dstSubresource.mipLevel : vkIR.srcSubresource.mipLevel;
+ rslvSlice.srcSubresource.arrayLayer = needXfrImage ? vkIR.dstSubresource.baseArrayLayer : vkIR.srcSubresource.baseArrayLayer;
+ rslvSlice.srcSubresource.arrayLayer += layIdx;
}
}
// Expansion and copying is not required. Each mip level of the source image
// is being resolved entirely. Resolve directly from the source image.
MVKImage* xfrImage = _srcImage;
- if (expCnt) {
- // Expansion and copying is required. Acquire a temporary transfer image, expand
- // the destination image into it, copy from the source image to the temporary image,
- // and then resolve from the temporary image to the destination image.
+ if (copyCnt) {
+ // Expansion and/or copying is required. Acquire a temporary transfer image, expand
+ // the destination image into it if necessary, copy from the source image to the
+ // temporary image, and then resolve from the temporary image to the destination image.
MVKImageDescriptorData xferImageData;
_dstImage->getTransferDescriptorData(xferImageData);
xferImageData.samples = _srcImage->getSampleCount();
xfrImage = cmdEncoder->getCommandEncodingPool()->getTransferMVKImage(xferImageData);
- // Expand the current content of the destination image to the temporary transfer image.
- MVKCmdBlitImage<N> expCmd;
- expCmd.setContent(cmdEncoder->_cmdBuffer,
- (VkImage)_dstImage, _dstLayout, (VkImage)xfrImage, _dstLayout,
- expCnt, expansionRegions, VK_FILTER_LINEAR);
- expCmd.encode(cmdEncoder, kMVKCommandUseResolveExpandImage);
+ if (expCnt) {
+ // Expand the current content of the destination image to the temporary transfer image.
+ MVKCmdBlitImage<N> expCmd;
+ expCmd.setContent(cmdEncoder->_cmdBuffer,
+ (VkImage)_dstImage, _dstLayout, (VkImage)xfrImage, _dstLayout,
+ expCnt, expansionRegions, VK_FILTER_LINEAR);
+ expCmd.encode(cmdEncoder, kMVKCommandUseResolveExpandImage);
+ }
// Copy the resolve regions of the source image to the temporary transfer image.
MVKCmdCopyImage<N> copyCmd;
@@ -573,15 +643,15 @@
// the texture level and slice and create a render encoder.
for (uint32_t sIdx = 0; sIdx < sliceCnt; sIdx++) {
MVKMetalResolveSlice& rslvSlice = mtlResolveSlices[sIdx];
- uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.copyRegion->srcSubresource.aspectMask);
- uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.copyRegion->dstSubresource.aspectMask);
+ uint8_t srcPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.srcSubresource.aspectMask);
+ uint8_t dstPlaneIndex = MVKImage::getPlaneFromVkImageAspectFlags(rslvSlice.dstSubresource.aspectMask);
mtlColorAttDesc.texture = xfrImage->getMTLTexture(srcPlaneIndex);
mtlColorAttDesc.resolveTexture = _dstImage->getMTLTexture(dstPlaneIndex);
- mtlColorAttDesc.level = rslvSlice.level;
- mtlColorAttDesc.slice = rslvSlice.slice;
- mtlColorAttDesc.resolveLevel = rslvSlice.level;
- mtlColorAttDesc.resolveSlice = rslvSlice.slice;
+ mtlColorAttDesc.level = rslvSlice.srcSubresource.mipLevel;
+ mtlColorAttDesc.slice = rslvSlice.srcSubresource.arrayLayer;
+ mtlColorAttDesc.resolveLevel = rslvSlice.dstSubresource.mipLevel;
+ mtlColorAttDesc.resolveSlice = rslvSlice.dstSubresource.arrayLayer;
id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPD];
setLabelIfNotNil(mtlRendEnc, mvkMTLRenderCommandEncoderLabel(kMVKCommandUseResolveImage));
@@ -1159,8 +1229,8 @@
// Validate
MVKMTLFmtCaps mtlFmtCaps = cmdBuff->getPixelFormats()->getCapabilities(_image->getMTLPixelFormat(planeIndex));
- if ((isDS && !mvkAreAllFlagsEnabled(mtlFmtCaps, kMVKMTLFmtCapsDSAtt)) ||
- ( !isDS && !mvkAreAllFlagsEnabled(mtlFmtCaps, kMVKMTLFmtCapsColorAtt))) {
+ uint32_t reqCap = isDS ? kMVKMTLFmtCapsDSAtt : (_image->getIsLinear() ? kMVKMTLFmtCapsWrite : kMVKMTLFmtCapsColorAtt);
+ if (!mvkAreAllFlagsEnabled(mtlFmtCaps, reqCap)) {
return cmdBuff->reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClear%sImage(): Format %s cannot be cleared on this device.", (isDS ? "DepthStencil" : "Color"), cmdBuff->getPixelFormats()->getName(_image->getVkFormat()));
}
@@ -1186,9 +1256,35 @@
MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
for (auto& srRange : _subresourceRanges) {
- id<MTLTexture> imgMTLTex = _image->getMTLTexture(MVKImage::getPlaneFromVkImageAspectFlags(srRange.aspectMask));
+ uint8_t planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(srRange.aspectMask);
+ id<MTLTexture> imgMTLTex = _image->getMTLTexture(planeIndex);
if ( !imgMTLTex ) { continue; }
+#if MVK_MACOS
+ if ( _image->getIsLinear() ) {
+ // These images cannot be rendered. Instead, use a compute shader.
+ // Luckily for us, linear images only have one mip and one array layer under Metal.
+ assert( !isDS );
+ id<MTLComputePipelineState> mtlClearState = cmdEncoder->getCommandEncodingPool()->getCmdClearColorImageMTLComputePipelineState(pixFmts->getFormatType(_image->getVkFormat()));
+ id<MTLComputeCommandEncoder> mtlComputeEnc = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseClearColorImage);
+ [mtlComputeEnc pushDebugGroup: @"vkCmdClearColorImage"];
+ [mtlComputeEnc setComputePipelineState: mtlClearState];
+ [mtlComputeEnc setTexture: imgMTLTex atIndex: 0];
+ cmdEncoder->setComputeBytes(mtlComputeEnc, &_clearValue, sizeof(_clearValue), 0);
+ MTLSize gridSize = mvkMTLSizeFromVkExtent3D(_image->getExtent3D());
+ MTLSize tgSize = MTLSizeMake(mtlClearState.threadExecutionWidth, 1, 1);
+ if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
+ [mtlComputeEnc dispatchThreads: gridSize threadsPerThreadgroup: tgSize];
+ } else {
+ MTLSize tgCount = MTLSizeMake(gridSize.width / tgSize.width, gridSize.height, gridSize.depth);
+ if (gridSize.width % tgSize.width) { tgCount.width += 1; }
+ [mtlComputeEnc dispatchThreadgroups: tgCount threadsPerThreadgroup: tgSize];
+ }
+ [mtlComputeEnc popDebugGroup];
+ continue;
+ }
+#endif
+
MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
MTLRenderPassColorAttachmentDescriptor* mtlRPCADesc = nil;
MTLRenderPassDepthAttachmentDescriptor* mtlRPDADesc = nil;
@@ -1230,7 +1326,8 @@
: (mipLvlStart + mipLvlCnt));
// Extract the cube or array layers (slices) that are to be updated
- uint32_t layerStart = srRange.baseArrayLayer;
+ bool is3D = _image->getMTLTextureType() == MTLTextureType3D;
+ uint32_t layerStart = is3D ? 0 : srRange.baseArrayLayer;
uint32_t layerCnt = srRange.layerCount;
uint32_t layerEnd = (layerCnt == VK_REMAINING_ARRAY_LAYERS
? _image->getLayerCount()
@@ -1242,10 +1339,22 @@
mtlRPDADesc.level = mipLvl;
mtlRPSADesc.level = mipLvl;
+ // If a 3D image, we need to get the depth for each level.
+ if (is3D) {
+ layerCnt = _image->getExtent3D(planeIndex, mipLvl).depth;
+ layerEnd = layerStart + layerCnt;
+ }
+
for (uint32_t layer = layerStart; layer < layerEnd; layer++) {
- mtlRPCADesc.slice = layer;
- mtlRPDADesc.slice = layer;
- mtlRPSADesc.slice = layer;
+ if (is3D) {
+ mtlRPCADesc.depthPlane = layer;
+ mtlRPDADesc.depthPlane = layer;
+ mtlRPSADesc.depthPlane = layer;
+ } else {
+ mtlRPCADesc.slice = layer;
+ mtlRPDADesc.slice = layer;
+ mtlRPSADesc.slice = layer;
+ }
id<MTLRenderCommandEncoder> mtlRendEnc = [cmdEncoder->_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPDesc];
setLabelIfNotNil(mtlRendEnc, mtlRendEncName);
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 24b65a4..0889577 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -752,6 +752,7 @@
case kMVKCommandUseCopyBufferToImage: return @"vkCmdCopyBufferToImage ComputeEncoder";
case kMVKCommandUseCopyImageToBuffer: return @"vkCmdCopyImageToBuffer ComputeEncoder";
case kMVKCommandUseFillBuffer: return @"vkCmdFillBuffer ComputeEncoder";
+ case kMVKCommandUseClearColorImage: return @"vkCmdClearColorImage ComputeEncoder";
case kMVKCommandUseTessellationVertexTessCtl: return @"vkCmdDraw (vertex and tess control stages) ComputeEncoder";
case kMVKCommandUseMultiviewInstanceCountAdjust: return @"vkCmdDraw (multiview instance count adjustment) ComputeEncoder";
case kMVKCommandUseCopyQueryPoolResults:return @"vkCmdCopyQueryPoolResults ComputeEncoder";
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
index 52e4704..eac9f3f 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
@@ -109,6 +109,11 @@
/** Returns a MTLComputePipelineState for filling a buffer. */
id<MTLComputePipelineState> getCmdFillBufferMTLComputePipelineState();
+#if MVK_MACOS
+ /** Returns a MTLComputePipelineState for clearing an image. Currently only used for 2D linear images on Mac. */
+ id<MTLComputePipelineState> getCmdClearColorImageMTLComputePipelineState(MVKFormatType type);
+#endif
+
/** Returns a MTLComputePipelineState for decompressing a buffer into a 3D image. */
id<MTLComputePipelineState> getCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needsTempBuff);
@@ -151,6 +156,9 @@
id<MTLDepthStencilState> _cmdClearDefaultDepthStencilState = nil;
id<MTLComputePipelineState> _mtlCopyBufferBytesComputePipelineState = nil;
id<MTLComputePipelineState> _mtlFillBufferComputePipelineState = nil;
+#if MVK_MACOS
+ id<MTLComputePipelineState> _mtlClearColorImageComputePipelineState[3] = {nil, nil, nil};
+#endif
id<MTLComputePipelineState> _mtlCopyBufferToImage3DDecompressComputePipelineState[2] = {nil, nil};
id<MTLComputePipelineState> _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[2] = {nil, nil};
id<MTLComputePipelineState> _mtlDrawIndirectTessConvertBuffersComputePipelineState[2] = {nil, nil};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
index da0e661..b1a5a26 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
@@ -102,6 +102,30 @@
MVK_ENC_REZ_ACCESS(_mtlFillBufferComputePipelineState, newCmdFillBufferMTLComputePipelineState(_commandPool));
}
+#if MVK_MACOS
+static inline uint32_t getClearStateIndex(MVKFormatType type) {
+ switch (type) {
+ case kMVKFormatColorHalf:
+ case kMVKFormatColorFloat:
+ return 0;
+ case kMVKFormatColorInt8:
+ case kMVKFormatColorInt16:
+ case kMVKFormatColorInt32:
+ return 1;
+ case kMVKFormatColorUInt8:
+ case kMVKFormatColorUInt16:
+ case kMVKFormatColorUInt32:
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdClearColorImageMTLComputePipelineState(MVKFormatType type) {
+ MVK_ENC_REZ_ACCESS(_mtlClearColorImageComputePipelineState[getClearStateIndex(type)], newCmdClearColorImageMTLComputePipelineState(type, _commandPool));
+}
+#endif
+
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needsTempBuff) {
MVK_ENC_REZ_ACCESS(_mtlCopyBufferToImage3DDecompressComputePipelineState[needsTempBuff ? 1 : 0], newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(needsTempBuff, _commandPool));
}
@@ -178,6 +202,15 @@
[_mtlFillBufferComputePipelineState release];
_mtlFillBufferComputePipelineState = nil;
+#if MVK_MACOS
+ [_mtlClearColorImageComputePipelineState[0] release];
+ [_mtlClearColorImageComputePipelineState[1] release];
+ [_mtlClearColorImageComputePipelineState[2] release];
+ _mtlClearColorImageComputePipelineState[0] = nil;
+ _mtlClearColorImageComputePipelineState[1] = nil;
+ _mtlClearColorImageComputePipelineState[2] = nil;
+#endif
+
[_mtlCopyBufferToImage3DDecompressComputePipelineState[0] release];
[_mtlCopyBufferToImage3DDecompressComputePipelineState[1] release];
_mtlCopyBufferToImage3DDecompressComputePipelineState[0] = nil;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
index 124f6d9..d562183 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
@@ -29,12 +29,12 @@
\n\
typedef struct { \n\
float2 a_position [[attribute(0)]]; \n\
- float2 a_texCoord [[attribute(1)]]; \n\
+ float3 a_texCoord [[attribute(1)]]; \n\
} AttributesPosTex; \n\
\n\
typedef struct { \n\
float4 v_position [[position]]; \n\
- float2 v_texCoord; \n\
+ float3 v_texCoord; \n\
} VaryingsPosTex; \n\
\n\
typedef size_t VkDeviceSize; \n\
@@ -91,13 +91,31 @@
for (size_t i = 0; i < info.size; i++) { \n\
dst[i + info.dstOffset] = src[i + info.srcOffset]; \n\
} \n\
-}; \n\
+} \n\
\n\
kernel void cmdFillBuffer(device uint32_t* dst [[ buffer(0) ]], \n\
constant uint32_t& fillValue [[ buffer(1) ]], \n\
uint pos [[thread_position_in_grid]]) { \n\
dst[pos] = fillValue; \n\
-}; \n\
+} \n\
+ \n\
+kernel void cmdClearColorImage2DFloat(texture2d<float, access::write> dst [[ texture(0) ]], \n\
+ constant float4& clearValue [[ buffer(0) ]], \n\
+ uint2 pos [[thread_position_in_grid]]) { \n\
+ dst.write(clearValue, pos); \n\
+} \n\
+ \n\
+kernel void cmdClearColorImage2DUInt(texture2d<uint, access::write> dst [[ texture(0) ]], \n\
+ constant uint4& clearValue [[ buffer(0) ]], \n\
+ uint2 pos [[thread_position_in_grid]]) { \n\
+ dst.write(clearValue, pos); \n\
+} \n\
+ \n\
+kernel void cmdClearColorImage2DInt(texture2d<int, access::write> dst [[ texture(0) ]], \n\
+ constant int4& clearValue [[ buffer(0) ]], \n\
+ uint2 pos [[thread_position_in_grid]]) { \n\
+ dst.write(clearValue, pos); \n\
+} \n\
\n\
typedef struct { \n\
uint32_t srcRowStride; \n\
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
index fb20ebf..7e8d55a 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandPool.mm
@@ -59,7 +59,10 @@
// Command buffers start out in a VK_NOT_READY config result
VkResult cbRslt = mvkCmdBuff->getConfigurationResult();
- if (rslt == VK_SUCCESS && cbRslt != VK_NOT_READY) { rslt = cbRslt; }
+ if (cbRslt != VK_NOT_READY) {
+ if (rslt == VK_SUCCESS) { rslt = cbRslt; }
+ freeCommandBuffers(1, &pCmdBuffer[cbIdx]);
+ }
}
return rslt;
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
index 7672fed..105483f 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
@@ -58,6 +58,8 @@
inline MTLSamplerMinMagFilter getSrcMTLSamplerMinMagFilter() { return (MTLSamplerMinMagFilter)srcFilter; }
+ inline MTLTextureType getSrcMTLTextureType() { return (MTLTextureType)srcMTLTextureType; }
+
inline bool isSrcArrayType() {
return (srcMTLTextureType == MTLTextureType2DArray ||
#if MVK_MACOS
@@ -417,6 +419,12 @@
/** Returns a new MTLComputePipelineState for filling a buffer. */
id<MTLComputePipelineState> newCmdFillBufferMTLComputePipelineState(MVKVulkanAPIDeviceObject* owner);
+#if MVK_MACOS
+ /** Returns a new MTLComputePipelineState for clearing an image. */
+ id<MTLComputePipelineState> newCmdClearColorImageMTLComputePipelineState(MVKFormatType type,
+ MVKVulkanAPIDeviceObject* owner);
+#endif
+
/** Returns a new MTLComputePipelineState for copying between a buffer holding compressed data and a 3D image. */
id<MTLComputePipelineState> newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needTempBuf,
MVKVulkanAPIDeviceObject* owner);
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
index a616a64..51640ae 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
@@ -57,14 +57,14 @@
vaDesc.format = MTLVertexFormatFloat2;
vaDesc.bufferIndex = vtxBuffIdx;
vaDesc.offset = vtxStride;
- vtxStride += sizeof(simd::float2);
+ vtxStride += sizeof(simd::float4);
// Vertex texture coords
vaDesc = vaDescArray[1];
- vaDesc.format = MTLVertexFormatFloat2;
+ vaDesc.format = MTLVertexFormatFloat3;
vaDesc.bufferIndex = vtxBuffIdx;
vaDesc.offset = vtxStride;
- vtxStride += sizeof(simd::float2);
+ vtxStride += sizeof(simd::float4);
// Vertex attribute buffer.
MTLVertexBufferLayoutDescriptorArray* vbDescArray = vtxDesc.layouts;
@@ -158,7 +158,34 @@
bool isArrayType = blitKey.isSrcArrayType();
bool isLinearFilter = (blitKey.getSrcMTLSamplerMinMagFilter() == MTLSamplerMinMagFilterLinear);
- NSString* arraySuffix = isArrayType ? @"_array" : @"";
+ NSString* typeSuffix;
+ NSString* coordArg;
+ switch (blitKey.getSrcMTLTextureType()) {
+ case MTLTextureType1D:
+ typeSuffix = @"1d";
+ coordArg = @".x";
+ break;
+ case MTLTextureType1DArray:
+ typeSuffix = @"1d_array";
+ coordArg = @".x";
+ break;
+ case MTLTextureType2D:
+ typeSuffix = @"2d";
+ coordArg = @".xy";
+ break;
+ case MTLTextureType2DArray:
+ typeSuffix = @"2d_array";
+ coordArg = @".xy";
+ break;
+ case MTLTextureType3D:
+ typeSuffix = @"3d";
+ coordArg = @"";
+ break;
+ default:
+ typeSuffix = @"unsupported";
+ coordArg = @"";
+ break;
+ }
NSString* sliceArg = isArrayType ? @", subRez.slice" : @"";
NSString* srcFilter = isLinearFilter ? @"linear" : @"nearest";
@@ -168,7 +195,7 @@
[msl appendLineMVK];
[msl appendLineMVK: @"typedef struct {"];
[msl appendLineMVK: @" float4 v_position [[position]];"];
- [msl appendLineMVK: @" float2 v_texCoord;"];
+ [msl appendLineMVK: @" float3 v_texCoord;"];
[msl appendLineMVK: @"} VaryingsPosTex;"];
[msl appendLineMVK];
[msl appendLineMVK: @"typedef struct {"];
@@ -183,10 +210,10 @@
NSString* funcName = @"fragCmdBlitImage";
[msl appendFormat: @"fragment %@4 %@(VaryingsPosTex varyings [[stage_in]],", typeStr, funcName];
[msl appendLineMVK];
- [msl appendFormat: @" texture2d%@<%@> tex [[texture(0)]],", arraySuffix, typeStr];
+ [msl appendFormat: @" texture%@<%@> tex [[texture(0)]],", typeSuffix, typeStr];
[msl appendLineMVK];
[msl appendLineMVK: @" constant TexSubrez& subRez [[buffer(0)]]) {"];
- [msl appendFormat: @" return tex.sample(ce_sampler, varyings.v_texCoord%@, level(subRez.lod));", sliceArg];
+ [msl appendFormat: @" return tex.sample(ce_sampler, varyings.v_texCoord%@%@, level(subRez.lod));", coordArg, sliceArg];
[msl appendLineMVK];
[msl appendLineMVK: @"}"];
@@ -410,6 +437,34 @@
return newMTLComputePipelineState("cmdFillBuffer", owner);
}
+#if MVK_MACOS
+id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdClearColorImageMTLComputePipelineState(MVKFormatType type,
+ MVKVulkanAPIDeviceObject* owner) {
+ const char* funcName;
+ switch (type) {
+ case kMVKFormatColorHalf:
+ case kMVKFormatColorFloat:
+ funcName = "cmdClearColorImage2DFloat";
+ break;
+ case kMVKFormatColorInt8:
+ case kMVKFormatColorInt16:
+ case kMVKFormatColorInt32:
+ funcName = "cmdClearColorImage2DInt";
+ break;
+ case kMVKFormatColorUInt8:
+ case kMVKFormatColorUInt16:
+ case kMVKFormatColorUInt32:
+ funcName = "cmdClearColorImage2DUInt";
+ break;
+ default:
+ owner->reportError(VK_ERROR_FORMAT_NOT_SUPPORTED,
+ "Format type %u is not supported for clearing with a compute shader.", type);
+ return nil;
+ }
+ return newMTLComputePipelineState(funcName, owner);
+}
+#endif
+
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needTempBuf,
MVKVulkanAPIDeviceObject* owner) {
return newMTLComputePipelineState(needTempBuf
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
index 92d39f2..de17272 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKBuffer.mm
@@ -84,7 +84,7 @@
#if MVK_MACOS
if (_deviceMemory) {
- _isHostCoherentTexelBuffer = _deviceMemory->isMemoryHostCoherent() && mvkIsAnyFlagEnabled(_usage, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
+ _isHostCoherentTexelBuffer = !_device->_pMetalFeatures->sharedLinearTextures && _deviceMemory->isMemoryHostCoherent() && mvkIsAnyFlagEnabled(_usage, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
}
#endif
@@ -272,7 +272,7 @@
}
id<MTLBuffer> mtlBuff;
VkDeviceSize mtlBuffOffset;
- if (MVK_MACOS && _buffer->isMemoryHostCoherent()) {
+ if ( !_device->_pMetalFeatures->sharedLinearTextures && _buffer->isMemoryHostCoherent() ) {
mtlBuff = _buffer->getMTLBufferCache();
mtlBuffOffset = _offset;
} else {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index 23d74f5..e3013e1 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -362,7 +362,6 @@
void initPipelineCacheUUID();
uint32_t getHighestMTLFeatureSet();
uint64_t getMoltenVKGitRevision();
- bool getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo);
void populate(VkPhysicalDeviceIDProperties* pDevIdProps);
void logGPUInfo();
@@ -678,7 +677,7 @@
const VkPhysicalDeviceScalarBlockLayoutFeaturesEXT _enabledScalarLayoutFeatures;
const VkPhysicalDeviceTexelBufferAlignmentFeaturesEXT _enabledTexelBuffAlignFeatures;
const VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT _enabledVtxAttrDivFeatures;
- const VkPhysicalDevicePortabilitySubsetFeaturesEXTX _enabledPortabilityFeatures;
+ const VkPhysicalDevicePortabilitySubsetFeaturesKHR _enabledPortabilityFeatures;
/** The list of Vulkan extensions, indicating whether each has been enabled by the app for this device. */
const MVKExtensionList _enabledExtensions;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 5aaf418..e485d39 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -164,13 +164,24 @@
divisorFeatures->vertexAttributeInstanceRateZeroDivisor = true;
break;
}
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX: {
- auto* portabilityFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesEXTX*)next;
- portabilityFeatures->triangleFans = false;
- portabilityFeatures->separateStencilMaskRef = true;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR: {
+ auto* portabilityFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesKHR*)next;
+ portabilityFeatures->constantAlphaColorBlendFactors = true;
portabilityFeatures->events = true;
- portabilityFeatures->standardImageViews = _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle || _metalFeatures.nativeTextureSwizzle;
+ portabilityFeatures->imageViewFormatReinterpretation = true;
+ portabilityFeatures->imageViewFormatSwizzle = (_metalFeatures.nativeTextureSwizzle ||
+ _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle);
+ portabilityFeatures->imageView2DOn3DImage = false;
+ portabilityFeatures->multisampleArrayImage = _metalFeatures.multisampleArrayTextures;
+ portabilityFeatures->mutableComparisonSamplers = _metalFeatures.depthSampleCompare;
+ portabilityFeatures->pointPolygons = false;
portabilityFeatures->samplerMipLodBias = false;
+ portabilityFeatures->separateStencilMaskRef = true;
+ portabilityFeatures->shaderSampleRateInterpolationFunctions = false;
+ portabilityFeatures->tessellationIsolines = false;
+ portabilityFeatures->tessellationPointMode = false;
+ portabilityFeatures->triangleFans = false;
+ portabilityFeatures->vertexAttributeAccessBeyondStride = true; // Costs additional buffers. Should make configuration switch.
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: {
@@ -199,6 +210,23 @@
properties->properties = _properties;
for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) {
switch ((uint32_t)next->sType) {
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES: {
+ auto* depthStencilResolveProps = (VkPhysicalDeviceDepthStencilResolveProperties*)next;
+
+ // We can always support resolve from sample zero. Other modes require additional capabilities.
+ depthStencilResolveProps->supportedDepthResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
+ if (_metalFeatures.depthResolve) {
+ depthStencilResolveProps->supportedDepthResolveModes |= VK_RESOLVE_MODE_MIN_BIT | VK_RESOLVE_MODE_MAX_BIT;
+ }
+ // Metal allows you to set the stencil resolve filter to either
+ // Sample0 or DepthResolvedSample--in other words, you can always use sample 0,
+ // but you can also use the sample chosen for depth resolve. This is impossible
+ // to express in Vulkan.
+ depthStencilResolveProps->supportedStencilResolveModes = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
+ depthStencilResolveProps->independentResolveNone = true;
+ depthStencilResolveProps->independentResolve = true;
+ break;
+ }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: {
auto* physicalDeviceDriverProps = (VkPhysicalDeviceDriverPropertiesKHR*)next;
strcpy(physicalDeviceDriverProps->driverName, "MoltenVK");
@@ -270,10 +298,10 @@
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: {
@@ -298,8 +326,8 @@
divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
break;
}
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
- auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR: {
+ auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesKHR*)next;
portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
break;
}
@@ -384,6 +412,8 @@
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)) {
@@ -391,11 +421,19 @@
}
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;
@@ -408,10 +446,7 @@
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;
@@ -425,29 +460,42 @@
// 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;
@@ -455,14 +503,22 @@
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;
@@ -472,7 +528,8 @@
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
@@ -532,7 +589,7 @@
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:
@@ -542,52 +599,12 @@
if ( !_pixelFormats.isSupported(pImageFormatInfo->format) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
- if ( !getImageViewIsSupported(pImageFormatInfo) ) { return VK_ERROR_FORMAT_NOT_SUPPORTED; }
-
return getImageFormatProperties(pImageFormatInfo->format, pImageFormatInfo->type,
pImageFormatInfo->tiling, pImageFormatInfo->usage,
pImageFormatInfo->flags,
&pImageFormatProperties->imageFormatProperties);
}
-// If the image format info links portability image view info, test if an image view of that configuration is supported
-bool MVKPhysicalDevice::getImageViewIsSupported(const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo) {
- for (const auto* next = (VkBaseInStructure*)pImageFormatInfo->pNext; next; next = next->pNext) {
- switch ((uint32_t)next->sType) {
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_VIEW_SUPPORT_EXTX: {
- auto* portImgViewInfo = (VkPhysicalDeviceImageViewSupportEXTX*)next;
-
- // Create an image view and test whether it could be configured
- VkImageViewCreateInfo viewInfo = {
- .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
- .pNext = portImgViewInfo->pNext,
- .flags = portImgViewInfo->flags,
- .image = nullptr,
- .viewType = portImgViewInfo->viewType,
- .format = portImgViewInfo->format,
- .components = portImgViewInfo->components,
- .subresourceRange = {
- .aspectMask = portImgViewInfo->aspectMask,
- .baseMipLevel = 0,
- .levelCount = 1,
- .baseArrayLayer = 0,
- .layerCount = 1},
- };
- MTLPixelFormat mtlPixFmt = _pixelFormats.getMTLPixelFormat(viewInfo.format);
- bool useSwizzle;
- return (MVKImageView::validateSwizzledMTLPixelFormat(&viewInfo, this,
- _metalFeatures.nativeTextureSwizzle,
- _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle,
- mtlPixFmt, useSwizzle) == VK_SUCCESS);
- }
- default:
- break;
- }
- }
-
- return true;
-}
-
void MVKPhysicalDevice::getExternalBufferProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
VkExternalBufferProperties* pExternalBufferProperties) {
pExternalBufferProperties->externalMemoryProperties = getExternalBufferProperties(pExternalBufferInfo->handleType);
@@ -1002,6 +1019,7 @@
_metalFeatures.maxPerStageBufferCount = 31;
_metalFeatures.maxMTLBufferSize = (256 * MEBI);
_metalFeatures.dynamicMTLBufferSize = 0;
+ _metalFeatures.maxPerStageDynamicMTLBufferCount = 0;
_metalFeatures.maxPerStageSamplerCount = 16;
_metalFeatures.maxQueryBufferSize = (64 * KIBI);
@@ -1026,6 +1044,8 @@
_metalFeatures.texelBuffers = true;
_metalFeatures.maxTextureDimension = (8 * KIBI);
_metalFeatures.dynamicMTLBufferSize = (4 * KIBI);
+ _metalFeatures.sharedLinearTextures = true;
+ _metalFeatures.maxPerStageDynamicMTLBufferCount = _metalFeatures.maxPerStageBufferCount;
if (supportsMTLFeatureSet(tvOS_GPUFamily1_v2)) {
_metalFeatures.mslVersionEnum = MTLLanguageVersion1_2;
@@ -1055,6 +1075,7 @@
_metalFeatures.depthSampleCompare = true;
_metalFeatures.arrayOfTextures = true;
_metalFeatures.arrayOfSamplers = true;
+ _metalFeatures.depthResolve = true;
}
if ( mvkOSVersionIsAtLeast(13.0) ) {
@@ -1073,11 +1094,13 @@
_metalFeatures.mtlCopyBufferAlignment = 1;
_metalFeatures.texelBuffers = true;
_metalFeatures.maxTextureDimension = (4 * KIBI);
+ _metalFeatures.sharedLinearTextures = true;
if (supportsMTLFeatureSet(iOS_GPUFamily1_v2)) {
_metalFeatures.mslVersionEnum = MTLLanguageVersion1_1;
_metalFeatures.dynamicMTLBufferSize = (4 * KIBI);
_metalFeatures.maxTextureDimension = (8 * KIBI);
+ _metalFeatures.maxPerStageDynamicMTLBufferCount = _metalFeatures.maxPerStageBufferCount;
}
if (supportsMTLFeatureSet(iOS_GPUFamily1_v3)) {
@@ -1106,6 +1129,7 @@
_metalFeatures.mtlBufferAlignment = 16; // Min float4 alignment for typical vertex buffers. MTLBuffer may go down to 4 bytes for other data.
_metalFeatures.maxTextureDimension = (16 * KIBI);
_metalFeatures.depthSampleCompare = true;
+ _metalFeatures.depthResolve = true;
}
if (supportsMTLFeatureSet(iOS_GPUFamily3_v2)) {
@@ -1124,6 +1148,7 @@
_metalFeatures.layeredRendering = true;
_metalFeatures.stencilFeedback = true;
_metalFeatures.indirectTessellationDrawing = true;
+ _metalFeatures.stencilResolve = true;
}
if ( mvkOSVersionIsAtLeast(13.0) ) {
@@ -1157,6 +1182,7 @@
_metalFeatures.combinedStoreResolveAction = true;
_metalFeatures.deferredStoreActions = true;
_metalFeatures.maxMTLBufferSize = (1 * GIBI);
+ _metalFeatures.maxPerStageDynamicMTLBufferCount = 14;
}
if (supportsMTLFeatureSet(macOS_GPUFamily1_v3)) {
@@ -1180,12 +1206,17 @@
if (supportsMTLFeatureSet(macOS_GPUFamily2_v1)) {
_metalFeatures.multisampleLayeredRendering = _metalFeatures.layeredRendering;
_metalFeatures.stencilFeedback = true;
+ _metalFeatures.depthResolve = true;
+ _metalFeatures.stencilResolve = true;
}
if ( mvkOSVersionIsAtLeast(10.15) ) {
_metalFeatures.mslVersionEnum = MTLLanguageVersion2_2;
_metalFeatures.native3DCompressedTextures = true;
_metalFeatures.renderWithoutAttachments = true;
+ if ( mvkOSVersionIsAtLeast(mvkMakeOSVersion(10, 15, 5)) ) {
+ _metalFeatures.sharedLinearTextures = true;
+ }
if (supportsMTLGPUFamily(Mac2)) {
_metalFeatures.nativeTextureSwizzle = true;
_metalFeatures.placementHeaps = useMTLHeaps;
@@ -1220,9 +1251,12 @@
_metalFeatures.mslVersion = SPIRV_CROSS_NAMESPACE::CompilerMSL::Options::make_msl_version(maj, min);
switch (_metalFeatures.mslVersionEnum) {
+#if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101600) || \
+ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140000) // also covers tvOS
case MTLLanguageVersion2_3:
setMSLVersion(2, 3);
break;
+#endif
case MTLLanguageVersion2_2:
setMSLVersion(2, 2);
break;
@@ -1268,7 +1302,6 @@
_features.shaderClipDistance = true;
_features.shaderInt16 = true;
_features.multiDrawIndirect = true;
- _features.variableMultisampleRate = true;
_features.inheritedQueries = true;
_features.shaderSampledImageArrayDynamicIndexing = _metalFeatures.arrayOfTextures;
@@ -1410,7 +1443,7 @@
// VkBool32 sparseResidency8Samples;
// VkBool32 sparseResidency16Samples;
// VkBool32 sparseResidencyAliased;
-// VkBool32 variableMultisampleRate; // done
+// VkBool32 variableMultisampleRate;
// VkBool32 inheritedQueries; // done
//} VkPhysicalDeviceFeatures;
@@ -1522,7 +1555,6 @@
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
@@ -2264,6 +2296,11 @@
MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_supportedExtensions;
pWritableExtns->disableAllButEnabledDeviceExtensions();
+#if MVK_IOS_OR_TVOS
+ if (!_metalFeatures.depthResolve) {
+ pWritableExtns->vk_KHR_depth_stencil_resolve.enabled = false;
+ }
+#endif
if (!_metalFeatures.rasterOrderGroups) {
pWritableExtns->vk_EXT_fragment_shader_interlock.enabled = false;
}
@@ -2961,8 +2998,15 @@
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;
}
@@ -3175,8 +3219,8 @@
mvkClear(&_enabledPortabilityFeatures);
// Fetch the available physical device features.
- VkPhysicalDevicePortabilitySubsetFeaturesEXTX pdPortabilityFeatures;
- pdPortabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX;
+ VkPhysicalDevicePortabilitySubsetFeaturesKHR pdPortabilityFeatures;
+ pdPortabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR;
pdPortabilityFeatures.pNext = NULL;
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT pdVtxAttrDivFeatures;
@@ -3322,11 +3366,11 @@
&pdVtxAttrDivFeatures.vertexAttributeInstanceRateDivisor, 2);
break;
}
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_EXTX: {
- auto* requestedFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesEXTX*)next;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR: {
+ auto* requestedFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesKHR*)next;
enableFeatures(&_enabledPortabilityFeatures.triangleFans,
&requestedFeatures->triangleFans,
- &pdPortabilityFeatures.triangleFans, 5);
+ &pdPortabilityFeatures.triangleFans, 15);
break;
}
default:
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
index cfa410e..593be4d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.mm
@@ -308,8 +308,10 @@
if (!((MVKImage*)dedicatedImage)->_isLinear) {
setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Host-coherent VkDeviceMemory objects cannot be associated with optimal-tiling images."));
} else {
- // Need to use the managed mode for images.
- _mtlStorageMode = MTLStorageModeManaged;
+ if (!_device->_pMetalFeatures->sharedLinearTextures) {
+ // Need to use the managed mode for images.
+ _mtlStorageMode = MTLStorageModeManaged;
+ }
// Nonetheless, we need a buffer to be able to map the memory at will.
if (!ensureMTLBuffer() ) {
setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "Could not allocate a host-coherent VkDeviceMemory of size %llu bytes. The maximum memory-aligned size of a host-coherent VkDeviceMemory is %llu bytes.", _allocationSize, _device->_pMetalFeatures->maxMTLBufferSize));
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index a4eae12..227fe3e 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -144,8 +144,10 @@
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;
};
@@ -366,6 +368,9 @@
bool _isLinear;
bool _is3DCompressed;
bool _isAliasable;
+ bool _hasExtendedUsage;
+ bool _hasMutableFormat;
+ bool _isLinearForAtomics;
};
@@ -586,6 +591,7 @@
* 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,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
index 4bcf46d..b99eef9 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm
@@ -51,10 +51,10 @@
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 @@
mtlTexDesc.mipmapLevelCount = _image->_mipLevels;
mtlTexDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(_image->_samples);
mtlTexDesc.arrayLength = _image->_arrayLayers;
- mtlTexDesc.usageMVK = _image->getPixelFormats()->getMTLTextureUsage(_image->_usage, mtlPixFmt, minUsage, _image->_isLinear);
+ 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 @@
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 @@
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,13 +393,34 @@
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
-#if MVK_MACOS
- // macOS cannot use shared memory for texel buffers.
- _usesTexelBuffer = _usesTexelBuffer && !isMemoryHostCoherent();
-#endif
+ // macOS before 10.15.5 cannot use shared memory for texel buffers.
+ 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;
@@ -422,6 +444,9 @@
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
@@ -430,17 +455,16 @@
VkPipelineStageFlags dstStageMask,
MVKPipelineBarrier& barrier) {
#if MVK_MACOS
- // On macOS, texture memory is never host-coherent, so don't test for it.
return ((barrier.newLayout == VK_IMAGE_LAYOUT_GENERAL) &&
mvkIsAnyFlagEnabled(barrier.dstAccessMask, (VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_READ_BIT)) &&
- isMemoryHostAccessible());
+ isMemoryHostAccessible() && (!_device->_pMetalFeatures->sharedLinearTextures || !isMemoryHostCoherent()));
#endif
#if MVK_IOS_OR_TVOS
return false;
#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.
@@ -492,14 +516,12 @@
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]; }
}
@@ -532,7 +554,7 @@
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;
}
@@ -540,14 +562,16 @@
}
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,
@@ -607,10 +631,11 @@
VkResult MVKImage::getMemoryRequirements(const void* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
uint8_t planeIndex = 0;
- for (auto* next = (VkBaseOutStructure*)pMemoryRequirements->pNext; next; next = next->pNext) {
+ const auto* pImageInfo = (const VkImageMemoryRequirementsInfo2*)pInfo;
+ for (const auto* next = (const VkBaseInStructure*)pImageInfo->pNext; next; next = next->pNext) {
switch (next->sType) {
case VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO: {
- auto* planeReqs = (VkImagePlaneMemoryRequirementsInfo*)next;
+ const auto* planeReqs = (const VkImagePlaneMemoryRequirementsInfo*)next;
planeIndex = MVKImage::getPlaneFromVkImageAspectFlags(planeReqs->planeAspect);
break;
}
@@ -618,7 +643,9 @@
break;
}
}
- return getMemoryRequirements(&pMemoryRequirements->memoryRequirements, planeIndex);
+ VkResult rslt = getMemoryRequirements(&pMemoryRequirements->memoryRequirements, planeIndex);
+ if (rslt != VK_SUCCESS) { return rslt; }
+ return _memoryBindings[planeIndex]->getMemoryRequirements(pInfo, pMemoryRequirements);
}
VkResult MVKImage::bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) {
@@ -762,8 +789,10 @@
if (_ioSurface && stgMode == MTLStorageModePrivate) { stgMode = MTLStorageModeShared; }
#if MVK_MACOS
- // For macOS, textures cannot use Shared storage mode, so change to Managed storage mode.
- if (stgMode == MTLStorageModeShared) { stgMode = MTLStorageModeManaged; }
+ // For macOS prior to 10.15.5, textures cannot use Shared storage mode, so change to Managed storage mode.
+ if (stgMode == MTLStorageModeShared && !_device->_pMetalFeatures->sharedLinearTextures) {
+ stgMode = MTLStorageModeManaged;
+ }
#endif
return stgMode;
}
@@ -802,7 +831,16 @@
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));
@@ -839,6 +877,16 @@
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);
@@ -878,6 +926,10 @@
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 ) {
@@ -898,6 +950,7 @@
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) {
@@ -914,6 +967,16 @@
}
#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."));
}
@@ -937,6 +1000,10 @@
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;
@@ -960,6 +1027,14 @@
setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : If tiling is VK_IMAGE_TILING_LINEAR, format must not be a depth/stencil format."));
isLin = false;
}
+ if (getPixelFormats()->getFormatType(pCreateInfo->format) == kMVKFormatCompressed) {
+ 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."));
@@ -1311,7 +1386,7 @@
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
@@ -1340,6 +1415,7 @@
bool useSwizzle;
_imageView->setConfigurationResult(_imageView->validateSwizzledMTLPixelFormat(pCreateInfo,
+ _imageView->_usage,
_imageView,
_device->_pMetalFeatures->nativeTextureSwizzle,
_device->_pMVKConfig->fullImageViewSwizzle,
@@ -1464,15 +1540,15 @@
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));
@@ -1480,6 +1556,7 @@
}
VkResult MVKImageView::validateSwizzledMTLPixelFormat(const VkImageViewCreateInfo* pCreateInfo,
+ VkImageUsageFlags usage,
MVKVulkanAPIObject* apiObject,
bool hasNativeSwizzleSupport,
bool hasShaderSwizzleSupport,
@@ -1494,7 +1571,8 @@
// 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
@@ -1551,7 +1629,8 @@
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;
@@ -1562,7 +1641,8 @@
#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;
@@ -1700,7 +1780,9 @@
MTLSamplerDescriptor* mtlSampDesc = [MTLSamplerDescriptor new]; // retained
mtlSampDesc.sAddressMode = mvkMTLSamplerAddressModeFromVkSamplerAddressMode(pCreateInfo->addressModeU);
mtlSampDesc.tAddressMode = mvkMTLSamplerAddressModeFromVkSamplerAddressMode(pCreateInfo->addressModeV);
- mtlSampDesc.rAddressMode = mvkMTLSamplerAddressModeFromVkSamplerAddressMode(pCreateInfo->addressModeW);
+ if (!pCreateInfo->unnormalizedCoordinates) {
+ mtlSampDesc.rAddressMode = mvkMTLSamplerAddressModeFromVkSamplerAddressMode(pCreateInfo->addressModeW);
+ }
mtlSampDesc.minFilter = mvkMTLSamplerMinMagFilterFromVkFilter(pCreateInfo->minFilter);
mtlSampDesc.magFilter = mvkMTLSamplerMinMagFilterFromVkFilter(pCreateInfo->magFilter);
mtlSampDesc.mipFilter = (pCreateInfo->unnormalizedCoordinates
@@ -1754,9 +1836,11 @@
_requiresConstExprSampler = (pCreateInfo->compareEnable && !_device->_pMetalFeatures->depthSampleCompare) || _ycbcrConversion;
- MTLSamplerDescriptor* mtlSampDesc = newMTLSamplerDescriptor(pCreateInfo); // temp retain
- _mtlSamplerState = [getMTLDevice() newSamplerStateWithDescriptor: mtlSampDesc];
- [mtlSampDesc release]; // temp release
+ @autoreleasepool {
+ MTLSamplerDescriptor* mtlSampDesc = newMTLSamplerDescriptor(pCreateInfo); // temp retain
+ _mtlSamplerState = [getMTLDevice() newSamplerStateWithDescriptor: mtlSampDesc];
+ [mtlSampDesc release]; // temp release
+ }
initConstExprSampler(pCreateInfo);
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index ce836c1..28d7c9c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -194,7 +194,7 @@
id<MTLRenderCommandEncoder> mtlCmdEnc = cmdEncoder->_mtlRenderEncoder;
id<MTLComputeCommandEncoder> tessCtlEnc;
- if ( stage != kMVKGraphicsStageTessControl && !mtlCmdEnc ) { return; } // Pre-renderpass. Come back later.
+ if ( stage == kMVKGraphicsStageRasterization && !mtlCmdEnc ) { return; } // Pre-renderpass. Come back later.
switch (stage) {
@@ -386,6 +386,11 @@
_mtlPrimitiveType = MTLPrimitiveTypePoint;
if (pCreateInfo->pInputAssemblyState && !isRenderingPoints(pCreateInfo)) {
_mtlPrimitiveType = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(pCreateInfo->pInputAssemblyState->topology);
+ // Explicitly fail creation with triangle fan topology.
+ if (pCreateInfo->pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) {
+ setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "Metal does not support triangle fans."));
+ return;
+ }
}
// Tessellation
@@ -1134,8 +1139,8 @@
vbCnt = pVertexInputDivisorState->vertexBindingDivisorCount;
for (uint32_t i = 0; i < vbCnt; i++) {
const VkVertexInputBindingDivisorDescriptionEXT* pVKVB = &pVertexInputDivisorState->pVertexBindingDivisors[i];
- uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
- if (shaderContext.isVertexBufferUsed(vbIdx)) {
+ if (shaderContext.isVertexBufferUsed(pVKVB->binding)) {
+ uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
if ((NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionPerInstance ||
(NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionThreadPositionInGridY) {
if (pVKVB->divisor == 0)
@@ -1353,6 +1358,7 @@
// Multisampling
if (pCreateInfo->pMultisampleState) {
plDesc.sampleCount = mvkSampleCountFromVkSampleCountFlagBits(pCreateInfo->pMultisampleState->rasterizationSamples);
+ mvkRenderSubpass->setDefaultSampleCount(pCreateInfo->pMultisampleState->rasterizationSamples);
plDesc.alphaToCoverageEnabled = pCreateInfo->pMultisampleState->alphaToCoverageEnable;
plDesc.alphaToOneEnabled = pCreateInfo->pMultisampleState->alphaToOneEnable;
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
index 1df4621..fa576ab 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h
@@ -77,6 +77,61 @@
kMVKMTLFmtCapsMultiPlanar = kMVKMTLFmtCapsChromaSubsampling,
} MVKMTLFmtCaps;
+inline MVKMTLFmtCaps operator|(MVKMTLFmtCaps leftCaps, MVKMTLFmtCaps rightCaps) {
+ return static_cast<MVKMTLFmtCaps>(static_cast<uint32_t>(leftCaps) | rightCaps);
+}
+
+inline MVKMTLFmtCaps& operator|=(MVKMTLFmtCaps& leftCaps, MVKMTLFmtCaps rightCaps) {
+ return (leftCaps = leftCaps | rightCaps);
+}
+
+
+#pragma mark -
+#pragma mark Metal view classes
+
+enum class MVKMTLViewClass : uint8_t {
+ None,
+ Color8,
+ Color16,
+ Color32,
+ Color64,
+ Color128,
+ PVRTC_RGB_2BPP,
+ PVRTC_RGB_4BPP,
+ PVRTC_RGBA_2BPP,
+ PVRTC_RGBA_4BPP,
+ EAC_R11,
+ EAC_RG11,
+ EAC_RGBA8,
+ ETC2_RGB8,
+ ETC2_RGB8A1,
+ ASTC_4x4,
+ ASTC_5x4,
+ ASTC_5x5,
+ ASTC_6x5,
+ ASTC_6x6,
+ ASTC_8x5,
+ ASTC_8x6,
+ ASTC_8x8,
+ ASTC_10x5,
+ ASTC_10x6,
+ ASTC_10x8,
+ ASTC_10x10,
+ ASTC_12x10,
+ ASTC_12x12,
+ BC1_RGBA,
+ BC2_RGBA,
+ BC3_RGBA,
+ BC4_R,
+ BC5_RG,
+ BC6H_RGB,
+ BC7_RGBA,
+ Depth24_Stencil8,
+ Depth32_Stencil8,
+ BGRA10_XR,
+ BGR10_XR
+};
+
#pragma mark -
#pragma mark Format descriptors
@@ -114,6 +169,7 @@
};
VkFormat vkFormat;
MVKMTLFmtCaps mtlFmtCaps;
+ MVKMTLViewClass mtlViewClass;
const char* name;
inline bool isSupported() const { return (mtlPixelFormat != MTLPixelFormatInvalid) && (mtlFmtCaps != kMVKMTLFmtCapsNone); };
@@ -200,6 +256,9 @@
/** 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]);
@@ -254,10 +313,16 @@
VkFormatProperties& getVkFormatProperties(VkFormat vkFormat);
/** Returns the Metal format capabilities supported by the specified Vulkan format, without substitution. */
- MVKMTLFmtCaps getCapabilities(VkFormat vkFormat);
+ MVKMTLFmtCaps getCapabilities(VkFormat vkFormat, bool isExtended = false);
/** Returns the Metal format capabilities supported by the specified Metal format. */
- MVKMTLFmtCaps getCapabilities(MTLPixelFormat mtlFormat);
+ 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);
/** Returns the name of the specified Vulkan format. */
const char* getName(VkFormat vkFormat);
@@ -283,12 +348,16 @@
/**
* Returns the Metal texture usage from the Vulkan image usage and Metal format, ensuring that at least the
* usages in minUsage are included, even if they wouldn't naturally be included based on the other two parameters.
- * isLinear further restricts the allowed usage to those that are valid for linear textures.
+ * isLinear further restricts the allowed usage to those that are valid for linear textures.
+ * isExtended expands the allowed usage to those that are valid for all formats which
+ * can be used in a view created from the specified format.
*/
MTLTextureUsage getMTLTextureUsage(VkImageUsageFlags vkImageUsageFlags,
MTLPixelFormat mtlFormat,
MTLTextureUsage minUsage = MTLTextureUsageUnknown,
- bool isLinear = false);
+ bool isLinear = false,
+ bool isMutableFormat = true,
+ bool isExtended = false);
/** Enumerates all formats that support the given features, calling a specified function for each one. */
void enumerateSupportedFormats(VkFormatProperties properties, bool any, std::function<bool(VkFormat)> func);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
index 65caf00..d937e7b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm
@@ -190,7 +190,7 @@
// 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::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 @@
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};
@@ -320,12 +337,27 @@
return getVkFormatDesc(vkFormat).properties;
}
-MVKMTLFmtCaps MVKPixelFormats::getCapabilities(VkFormat vkFormat) {
- return getMTLPixelFormatDesc(getVkFormatDesc(vkFormat).mtlPixelFormat).mtlFmtCaps;
+MVKMTLFmtCaps MVKPixelFormats::getCapabilities(VkFormat vkFormat, bool isExtended) {
+ return getCapabilities(getVkFormatDesc(vkFormat).mtlPixelFormat, isExtended);
}
-MVKMTLFmtCaps MVKPixelFormats::getCapabilities(MTLPixelFormat mtlFormat) {
- return getMTLPixelFormatDesc(mtlFormat).mtlFmtCaps;
+MVKMTLFmtCaps MVKPixelFormats::getCapabilities(MTLPixelFormat mtlFormat, bool isExtended) {
+ MVKMTLFormatDesc& mtlDesc = getMTLPixelFormatDesc(mtlFormat);
+ MVKMTLFmtCaps caps = mtlDesc.mtlFmtCaps;
+ if (!isExtended || mtlDesc.mtlViewClass == MVKMTLViewClass::None) { return caps; }
+ // Now get caps of all formats in the view class.
+ for (auto& otherDesc : _mtlPixelFormatDescriptions) {
+ if (otherDesc.mtlViewClass == mtlDesc.mtlViewClass) { caps |= otherDesc.mtlFmtCaps; }
+ }
+ return caps;
+}
+
+MVKMTLViewClass MVKPixelFormats::getViewClass(VkFormat vkFormat) {
+ return getMTLPixelFormatDesc(getVkFormatDesc(vkFormat).mtlPixelFormat).mtlViewClass;
+}
+
+MVKMTLViewClass MVKPixelFormats::getViewClass(MTLPixelFormat mtlFormat) {
+ return getMTLPixelFormatDesc(mtlFormat).mtlViewClass;
}
const char* MVKPixelFormats::getName(VkFormat vkFormat) {
@@ -453,13 +485,15 @@
MTLTextureUsage MVKPixelFormats::getMTLTextureUsage(VkImageUsageFlags vkImageUsageFlags,
MTLPixelFormat mtlFormat,
MTLTextureUsage minUsage,
- bool isLinear) {
+ bool isLinear,
+ bool isMutableFormat,
+ bool isExtended) {
bool isDepthFmt = isDepthFormat(mtlFormat);
bool isStencilFmt = isStencilFormat(mtlFormat);
bool isCombinedDepthStencilFmt = isDepthFmt && isStencilFmt;
bool isColorFormat = !(isDepthFmt || isStencilFmt);
bool supportsStencilViews = _physicalDevice ? _physicalDevice->getMetalFeatures()->stencilViews : false;
- MVKMTLFmtCaps mtlFmtCaps = getCapabilities(mtlFormat);
+ MVKMTLFmtCaps mtlFmtCaps = getCapabilities(mtlFormat, isExtended);
MTLTextureUsage mtlUsage = minUsage;
@@ -477,6 +511,14 @@
mvkEnableFlags(mtlUsage, MTLTextureUsageShaderWrite);
}
+#if MVK_MACOS
+ // Clearing a linear image may use shader writes.
+ if (mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_TRANSFER_DST_BIT)) &&
+ mvkIsAnyFlagEnabled(mtlFmtCaps, kMVKMTLFmtCapsWrite) && isLinear) {
+
+ mvkEnableFlags(mtlUsage, MTLTextureUsageShaderWrite);
+ }
+#endif
// Render to but only if format supports rendering...
if (mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
@@ -494,13 +536,21 @@
}
// 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);
}
@@ -817,9 +867,9 @@
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 );
@@ -827,9 +877,9 @@
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 );
@@ -848,11 +898,11 @@
// When adding to this list, be sure to ensure _vkFormatCount is large enough for the format count
}
-#define addMTLPixelFormatDesc(MTL_FMT, IOS_CAPS, MACOS_CAPS) \
+#define addMTLPixelFormatDesc(MTL_FMT, VIEW_CLASS, IOS_CAPS, MACOS_CAPS) \
MVKAssert(fmtIdx < _mtlPixelFormatCount, "Attempting to describe %d MTLPixelFormats, but only have space for %d. Increase the value of _mtlPixelFormatCount", fmtIdx + 1, _mtlPixelFormatCount); \
_mtlPixelFormatDescriptions[fmtIdx++] = { .mtlPixelFormat = MTLPixelFormat ##MTL_FMT, VK_FORMAT_UNDEFINED, \
mvkSelectPlatformValue<MVKMTLFmtCaps>(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \
- "MTLPixelFormat" #MTL_FMT }
+ MVKMTLViewClass:: VIEW_CLASS, "MTLPixelFormat" #MTL_FMT }
void MVKPixelFormats::initMTLPixelFormatCapabilities() {
@@ -863,159 +913,157 @@
// When adding to this list, be sure to ensure _mtlPixelFormatCount is large enough for the format count
// MTLPixelFormatInvalid must come first.
- addMTLPixelFormatDesc( Invalid, None, None );
+ addMTLPixelFormatDesc( Invalid, None, None, None );
// Ordinary 8-bit pixel formats
- addMTLPixelFormatDesc( A8Unorm, RF, RF );
- addMTLPixelFormatDesc( R8Unorm, All, All );
- addMTLPixelFormatDesc( R8Unorm_sRGB, RFCMRB, None );
- addMTLPixelFormatDesc( R8Snorm, RFWCMB, All );
- addMTLPixelFormatDesc( R8Uint, RWCM, RWCM );
- addMTLPixelFormatDesc( R8Sint, RWCM, RWCM );
+ addMTLPixelFormatDesc( A8Unorm, Color8, RF, RF );
+ addMTLPixelFormatDesc( R8Unorm, Color8, All, All );
+ addMTLPixelFormatDesc( R8Unorm_sRGB, Color8, RFCMRB, None );
+ addMTLPixelFormatDesc( R8Snorm, Color8, RFWCMB, All );
+ addMTLPixelFormatDesc( R8Uint, Color8, RWCM, RWCM );
+ addMTLPixelFormatDesc( R8Sint, Color8, RWCM, RWCM );
// Ordinary 16-bit pixel formats
- addMTLPixelFormatDesc( R16Unorm, RFWCMB, All );
- addMTLPixelFormatDesc( R16Snorm, RFWCMB, All );
- addMTLPixelFormatDesc( R16Uint, RWCM, RWCM );
- addMTLPixelFormatDesc( R16Sint, RWCM, RWCM );
- addMTLPixelFormatDesc( R16Float, All, All );
+ addMTLPixelFormatDesc( R16Unorm, Color16, RFWCMB, All );
+ addMTLPixelFormatDesc( R16Snorm, Color16, RFWCMB, All );
+ addMTLPixelFormatDesc( R16Uint, Color16, RWCM, RWCM );
+ addMTLPixelFormatDesc( R16Sint, Color16, RWCM, RWCM );
+ addMTLPixelFormatDesc( R16Float, Color16, All, All );
- addMTLPixelFormatDesc( RG8Unorm, All, All );
- addMTLPixelFormatDesc( RG8Unorm_sRGB, RFCMRB, None );
- addMTLPixelFormatDesc( RG8Snorm, RFWCMB, All );
- addMTLPixelFormatDesc( RG8Uint, RWCM, RWCM );
- addMTLPixelFormatDesc( RG8Sint, RWCM, RWCM );
+ addMTLPixelFormatDesc( RG8Unorm, Color16, All, All );
+ addMTLPixelFormatDesc( RG8Unorm_sRGB, Color16, RFCMRB, None );
+ addMTLPixelFormatDesc( RG8Snorm, Color16, RFWCMB, All );
+ addMTLPixelFormatDesc( RG8Uint, Color16, RWCM, RWCM );
+ addMTLPixelFormatDesc( RG8Sint, Color16, RWCM, RWCM );
// Packed 16-bit pixel formats
- addMTLPixelFormatDesc( B5G6R5Unorm, RFCMRB, None );
- addMTLPixelFormatDesc( A1BGR5Unorm, RFCMRB, None );
- addMTLPixelFormatDesc( ABGR4Unorm, RFCMRB, None );
- addMTLPixelFormatDesc( BGR5A1Unorm, RFCMRB, None );
+ addMTLPixelFormatDesc( B5G6R5Unorm, Color16, RFCMRB, None );
+ addMTLPixelFormatDesc( A1BGR5Unorm, Color16, RFCMRB, None );
+ addMTLPixelFormatDesc( ABGR4Unorm, Color16, RFCMRB, None );
+ addMTLPixelFormatDesc( BGR5A1Unorm, Color16, RFCMRB, None );
// Ordinary 32-bit pixel formats
- addMTLPixelFormatDesc( R32Uint, RC, RWCM );
- addMTLPixelFormatDesc( R32Sint, RC, RWCM );
- addMTLPixelFormatDesc( R32Float, RCMB, All );
+ addMTLPixelFormatDesc( R32Uint, Color32, RC, RWCM );
+ addMTLPixelFormatDesc( R32Sint, Color32, RC, RWCM );
+ addMTLPixelFormatDesc( R32Float, Color32, RCMB, All );
- addMTLPixelFormatDesc( RG16Unorm, RFWCMB, All );
- addMTLPixelFormatDesc( RG16Snorm, RFWCMB, All );
- addMTLPixelFormatDesc( RG16Uint, RWCM, RWCM );
- addMTLPixelFormatDesc( RG16Sint, RWCM, RWCM );
- addMTLPixelFormatDesc( RG16Float, All, All );
+ addMTLPixelFormatDesc( RG16Unorm, Color32, RFWCMB, All );
+ addMTLPixelFormatDesc( RG16Snorm, Color32, RFWCMB, All );
+ addMTLPixelFormatDesc( RG16Uint, Color32, RWCM, RWCM );
+ addMTLPixelFormatDesc( RG16Sint, Color32, RWCM, RWCM );
+ addMTLPixelFormatDesc( RG16Float, Color32, All, All );
- addMTLPixelFormatDesc( RGBA8Unorm, All, All );
- addMTLPixelFormatDesc( RGBA8Unorm_sRGB, RFCMRB, RFCMRB );
- addMTLPixelFormatDesc( RGBA8Snorm, RFWCMB, All );
- addMTLPixelFormatDesc( RGBA8Uint, RWCM, RWCM );
- addMTLPixelFormatDesc( RGBA8Sint, RWCM, RWCM );
+ addMTLPixelFormatDesc( RGBA8Unorm, Color32, All, All );
+ addMTLPixelFormatDesc( RGBA8Unorm_sRGB, Color32, RFCMRB, RFCMRB );
+ addMTLPixelFormatDesc( RGBA8Snorm, Color32, RFWCMB, All );
+ addMTLPixelFormatDesc( RGBA8Uint, Color32, RWCM, RWCM );
+ addMTLPixelFormatDesc( RGBA8Sint, Color32, RWCM, RWCM );
- addMTLPixelFormatDesc( BGRA8Unorm, All, All );
- addMTLPixelFormatDesc( BGRA8Unorm_sRGB, RFCMRB, RFCMRB );
+ addMTLPixelFormatDesc( BGRA8Unorm, Color32, All, All );
+ addMTLPixelFormatDesc( BGRA8Unorm_sRGB, Color32, RFCMRB, RFCMRB );
// Packed 32-bit pixel formats
- addMTLPixelFormatDesc( RGB10A2Unorm, RFCMRB, All );
- addMTLPixelFormatDesc( RGB10A2Uint, RCM, RWCM );
- addMTLPixelFormatDesc( RG11B10Float, RFCMRB, All );
- addMTLPixelFormatDesc( RGB9E5Float, RFCMRB, RF );
+ addMTLPixelFormatDesc( RGB10A2Unorm, Color32, RFCMRB, All );
+ addMTLPixelFormatDesc( RGB10A2Uint, Color32, RCM, RWCM );
+ addMTLPixelFormatDesc( RG11B10Float, Color32, RFCMRB, All );
+ addMTLPixelFormatDesc( RGB9E5Float, Color32, RFCMRB, RF );
// Ordinary 64-bit pixel formats
- addMTLPixelFormatDesc( RG32Uint, RC, RWCM );
- addMTLPixelFormatDesc( RG32Sint, RC, RWCM );
- addMTLPixelFormatDesc( RG32Float, RCB, All );
+ addMTLPixelFormatDesc( RG32Uint, Color64, RC, RWCM );
+ addMTLPixelFormatDesc( RG32Sint, Color64, RC, RWCM );
+ addMTLPixelFormatDesc( RG32Float, Color64, RCB, All );
- addMTLPixelFormatDesc( RGBA16Unorm, RFWCMB, All );
- addMTLPixelFormatDesc( RGBA16Snorm, RFWCMB, All );
- addMTLPixelFormatDesc( RGBA16Uint, RWCM, RWCM );
- addMTLPixelFormatDesc( RGBA16Sint, RWCM, RWCM );
- addMTLPixelFormatDesc( RGBA16Float, All, All );
+ addMTLPixelFormatDesc( RGBA16Unorm, Color64, RFWCMB, All );
+ addMTLPixelFormatDesc( RGBA16Snorm, Color64, RFWCMB, All );
+ addMTLPixelFormatDesc( RGBA16Uint, Color64, RWCM, RWCM );
+ addMTLPixelFormatDesc( RGBA16Sint, Color64, RWCM, RWCM );
+ addMTLPixelFormatDesc( RGBA16Float, Color64, All, All );
// Ordinary 128-bit pixel formats
- addMTLPixelFormatDesc( RGBA32Uint, RC, RWCM );
- addMTLPixelFormatDesc( RGBA32Sint, RC, RWCM );
- addMTLPixelFormatDesc( RGBA32Float, RC, All );
+ addMTLPixelFormatDesc( RGBA32Uint, Color128, RC, RWCM );
+ addMTLPixelFormatDesc( RGBA32Sint, Color128, RC, RWCM );
+ addMTLPixelFormatDesc( RGBA32Float, Color128, RC, All );
// Compressed pixel formats
- addMTLPixelFormatDesc( PVRTC_RGBA_2BPP, RF, None );
- addMTLPixelFormatDesc( PVRTC_RGBA_4BPP, RF, None );
- addMTLPixelFormatDesc( PVRTC_RGBA_2BPP_sRGB, RF, None );
- addMTLPixelFormatDesc( PVRTC_RGBA_4BPP_sRGB, RF, None );
+ addMTLPixelFormatDesc( PVRTC_RGBA_2BPP, PVRTC_RGBA_2BPP, RF, None );
+ addMTLPixelFormatDesc( PVRTC_RGBA_4BPP, PVRTC_RGBA_4BPP, RF, None );
+ addMTLPixelFormatDesc( PVRTC_RGBA_2BPP_sRGB, PVRTC_RGBA_2BPP, RF, None );
+ addMTLPixelFormatDesc( PVRTC_RGBA_4BPP_sRGB, PVRTC_RGBA_4BPP, RF, None );
- addMTLPixelFormatDesc( ETC2_RGB8, RF, None );
- addMTLPixelFormatDesc( ETC2_RGB8_sRGB, RF, None );
- addMTLPixelFormatDesc( ETC2_RGB8A1, RF, None );
- addMTLPixelFormatDesc( ETC2_RGB8A1_sRGB, RF, None );
- addMTLPixelFormatDesc( EAC_RGBA8, RF, None );
- addMTLPixelFormatDesc( EAC_RGBA8_sRGB, RF, None );
- addMTLPixelFormatDesc( EAC_R11Unorm, RF, None );
- addMTLPixelFormatDesc( EAC_R11Snorm, RF, None );
- addMTLPixelFormatDesc( EAC_RG11Unorm, RF, None );
- addMTLPixelFormatDesc( EAC_RG11Snorm, RF, None );
+ addMTLPixelFormatDesc( ETC2_RGB8, ETC2_RGB8, RF, None );
+ addMTLPixelFormatDesc( ETC2_RGB8_sRGB, ETC2_RGB8, RF, None );
+ addMTLPixelFormatDesc( ETC2_RGB8A1, ETC2_RGB8A1, RF, None );
+ addMTLPixelFormatDesc( ETC2_RGB8A1_sRGB, ETC2_RGB8A1, RF, None );
+ addMTLPixelFormatDesc( EAC_RGBA8, EAC_RGBA8, RF, None );
+ addMTLPixelFormatDesc( EAC_RGBA8_sRGB, EAC_RGBA8, RF, None );
+ addMTLPixelFormatDesc( EAC_R11Unorm, EAC_R11, RF, None );
+ addMTLPixelFormatDesc( EAC_R11Snorm, EAC_R11, RF, None );
+ addMTLPixelFormatDesc( EAC_RG11Unorm, EAC_RG11, RF, None );
+ addMTLPixelFormatDesc( EAC_RG11Snorm, EAC_RG11, RF, None );
- addMTLPixelFormatDesc( ASTC_4x4_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_4x4_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_5x4_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_5x4_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_5x5_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_5x5_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_6x5_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_6x5_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_6x6_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_6x6_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_8x5_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_8x5_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_8x6_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_8x6_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_8x8_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_8x8_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_10x5_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_10x5_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_10x6_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_10x6_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_10x8_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_10x8_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_10x10_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_10x10_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_12x10_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_12x10_sRGB, None, None );
- addMTLPixelFormatDesc( ASTC_12x12_LDR, None, None );
- addMTLPixelFormatDesc( ASTC_12x12_sRGB, None, None );
+ addMTLPixelFormatDesc( ASTC_4x4_LDR, ASTC_4x4, None, None );
+ addMTLPixelFormatDesc( ASTC_4x4_sRGB, ASTC_4x4, None, None );
+ addMTLPixelFormatDesc( ASTC_5x4_LDR, ASTC_5x4, None, None );
+ addMTLPixelFormatDesc( ASTC_5x4_sRGB, ASTC_5x4, None, None );
+ addMTLPixelFormatDesc( ASTC_5x5_LDR, ASTC_5x5, None, None );
+ addMTLPixelFormatDesc( ASTC_5x5_sRGB, ASTC_5x5, None, None );
+ addMTLPixelFormatDesc( ASTC_6x5_LDR, ASTC_6x5, None, None );
+ addMTLPixelFormatDesc( ASTC_6x5_sRGB, ASTC_6x5, None, None );
+ addMTLPixelFormatDesc( ASTC_6x6_LDR, ASTC_6x6, None, None );
+ addMTLPixelFormatDesc( ASTC_6x6_sRGB, ASTC_6x6, None, None );
+ addMTLPixelFormatDesc( ASTC_8x5_LDR, ASTC_8x5, None, None );
+ addMTLPixelFormatDesc( ASTC_8x5_sRGB, ASTC_8x5, None, None );
+ addMTLPixelFormatDesc( ASTC_8x6_LDR, ASTC_8x6, None, None );
+ addMTLPixelFormatDesc( ASTC_8x6_sRGB, ASTC_8x6, None, None );
+ addMTLPixelFormatDesc( ASTC_8x8_LDR, ASTC_8x8, None, None );
+ addMTLPixelFormatDesc( ASTC_8x8_sRGB, ASTC_8x8, None, None );
+ addMTLPixelFormatDesc( ASTC_10x5_LDR, ASTC_10x5, None, None );
+ addMTLPixelFormatDesc( ASTC_10x5_sRGB, ASTC_10x5, None, None );
+ addMTLPixelFormatDesc( ASTC_10x6_LDR, ASTC_10x6, None, None );
+ addMTLPixelFormatDesc( ASTC_10x6_sRGB, ASTC_10x6, None, None );
+ addMTLPixelFormatDesc( ASTC_10x8_LDR, ASTC_10x8, None, None );
+ addMTLPixelFormatDesc( ASTC_10x8_sRGB, ASTC_10x8, None, None );
+ addMTLPixelFormatDesc( ASTC_10x10_LDR, ASTC_10x10, None, None );
+ addMTLPixelFormatDesc( ASTC_10x10_sRGB, ASTC_10x10, None, None );
+ addMTLPixelFormatDesc( ASTC_12x10_LDR, ASTC_12x10, None, None );
+ addMTLPixelFormatDesc( ASTC_12x10_sRGB, ASTC_12x10, None, None );
+ addMTLPixelFormatDesc( ASTC_12x12_LDR, ASTC_12x12, None, None );
+ addMTLPixelFormatDesc( ASTC_12x12_sRGB, ASTC_12x12, None, None );
- addMTLPixelFormatDesc( BC1_RGBA, None, RF );
- addMTLPixelFormatDesc( BC1_RGBA_sRGB, None, RF );
- addMTLPixelFormatDesc( BC1_RGBA, None, RF );
- addMTLPixelFormatDesc( BC1_RGBA_sRGB, None, RF );
- addMTLPixelFormatDesc( BC2_RGBA, None, RF );
- addMTLPixelFormatDesc( BC2_RGBA_sRGB, None, RF );
- addMTLPixelFormatDesc( BC3_RGBA, None, RF );
- addMTLPixelFormatDesc( BC3_RGBA_sRGB, None, RF );
- addMTLPixelFormatDesc( BC4_RUnorm, None, RF );
- addMTLPixelFormatDesc( BC4_RSnorm, None, RF );
- addMTLPixelFormatDesc( BC5_RGUnorm, None, RF );
- addMTLPixelFormatDesc( BC5_RGSnorm, None, RF );
- addMTLPixelFormatDesc( BC6H_RGBUfloat, None, RF );
- addMTLPixelFormatDesc( BC6H_RGBFloat, None, RF );
- addMTLPixelFormatDesc( BC7_RGBAUnorm, None, RF );
- addMTLPixelFormatDesc( BC7_RGBAUnorm_sRGB, None, RF );
+ addMTLPixelFormatDesc( BC1_RGBA, BC1_RGBA, None, RF );
+ addMTLPixelFormatDesc( BC1_RGBA_sRGB, BC1_RGBA, None, RF );
+ addMTLPixelFormatDesc( BC2_RGBA, BC2_RGBA, None, RF );
+ addMTLPixelFormatDesc( BC2_RGBA_sRGB, BC2_RGBA, None, RF );
+ addMTLPixelFormatDesc( BC3_RGBA, BC3_RGBA, None, RF );
+ addMTLPixelFormatDesc( BC3_RGBA_sRGB, BC3_RGBA, None, RF );
+ addMTLPixelFormatDesc( BC4_RUnorm, BC4_R, None, RF );
+ addMTLPixelFormatDesc( BC4_RSnorm, BC4_R, None, RF );
+ addMTLPixelFormatDesc( BC5_RGUnorm, BC5_RG, None, RF );
+ addMTLPixelFormatDesc( BC5_RGSnorm, BC5_RG, None, RF );
+ addMTLPixelFormatDesc( BC6H_RGBUfloat, BC6H_RGB, None, RF );
+ addMTLPixelFormatDesc( BC6H_RGBFloat, BC6H_RGB, None, RF );
+ addMTLPixelFormatDesc( BC7_RGBAUnorm, BC7_RGBA, None, RF );
+ addMTLPixelFormatDesc( BC7_RGBAUnorm_sRGB, BC7_RGBA, None, RF );
// YUV pixel formats
- addMTLPixelFormatDesc( GBGR422, RF, RF );
- addMTLPixelFormatDesc( BGRG422, RF, RF );
+ addMTLPixelFormatDesc( GBGR422, None, RF, RF );
+ addMTLPixelFormatDesc( BGRG422, None, RF, RF );
// Extended range and wide color pixel formats
- addMTLPixelFormatDesc( BGRA10_XR, None, None );
- addMTLPixelFormatDesc( BGRA10_XR_sRGB, None, None );
- addMTLPixelFormatDesc( BGR10_XR, None, None );
- addMTLPixelFormatDesc( BGR10_XR_sRGB, None, None );
- addMTLPixelFormatDesc( BGR10A2Unorm, None, None );
+ addMTLPixelFormatDesc( BGRA10_XR, BGRA10_XR, None, None );
+ addMTLPixelFormatDesc( BGRA10_XR_sRGB, BGRA10_XR, None, None );
+ addMTLPixelFormatDesc( BGR10_XR, BGR10_XR, None, None );
+ addMTLPixelFormatDesc( BGR10_XR_sRGB, BGR10_XR, None, None );
+ addMTLPixelFormatDesc( BGR10A2Unorm, Color32, None, None );
// Depth and stencil pixel formats
- addMTLPixelFormatDesc( Depth16Unorm, None, None );
- addMTLPixelFormatDesc( Depth32Float, DRM, DRFMR );
- addMTLPixelFormatDesc( Stencil8, DRM, DRM );
- addMTLPixelFormatDesc( Depth24Unorm_Stencil8, None, None );
- addMTLPixelFormatDesc( Depth32Float_Stencil8, DRM, DRFMR );
- addMTLPixelFormatDesc( X24_Stencil8, None, DRM );
- addMTLPixelFormatDesc( X32_Stencil8, DRM, DRM );
+ addMTLPixelFormatDesc( Depth16Unorm, None, None, None );
+ addMTLPixelFormatDesc( Depth32Float, None, DRM, DRFMR );
+ addMTLPixelFormatDesc( Stencil8, None, DRM, DRMR );
+ addMTLPixelFormatDesc( Depth24Unorm_Stencil8, Depth24_Stencil8, None, None );
+ addMTLPixelFormatDesc( Depth32Float_Stencil8, Depth32_Stencil8, DRM, DRFMR );
+ addMTLPixelFormatDesc( X24_Stencil8, Depth24_Stencil8, None, DRMR );
+ addMTLPixelFormatDesc( X32_Stencil8, Depth32_Stencil8, DRM, DRMR );
// When adding to this list, be sure to ensure _mtlPixelFormatCount is large enough for the format count
}
@@ -1024,7 +1072,7 @@
MVKAssert(fmtIdx < _mtlVertexFormatCount, "Attempting to describe %d MTLVertexFormats, but only have space for %d. Increase the value of _mtlVertexFormatCount", fmtIdx + 1, _mtlVertexFormatCount); \
_mtlVertexFormatDescriptions[fmtIdx++] = { .mtlVertexFormat = MTLVertexFormat ##MTL_VTX_FMT, VK_FORMAT_UNDEFINED, \
mvkSelectPlatformValue<MVKMTLFmtCaps>(kMVKMTLFmtCaps ##MACOS_CAPS, kMVKMTLFmtCaps ##IOS_CAPS), \
- "MTLVertexFormat" #MTL_VTX_FMT }
+ MVKMTLViewClass::None, "MTLVertexFormat" #MTL_VTX_FMT }
void MVKPixelFormats::initMTLVertexFormatCapabilities() {
@@ -1322,6 +1370,7 @@
addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, Depth32Float, DRMR );
addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, Depth32Float_Stencil8, DRMR );
+ addFeatSetMTLPixFmtCaps( tvOS_GPUFamily2_v1, Stencil8, DRMR );
addFeatSetMTLPixFmtCaps(tvOS_GPUFamily2_v1, BGRA10_XR, All );
addFeatSetMTLPixFmtCaps(tvOS_GPUFamily2_v1, BGRA10_XR_sRGB, All );
@@ -1460,6 +1509,7 @@
addFeatSetMTLPixFmtCaps( iOS_GPUFamily3_v1, Depth32Float, DRMR );
addFeatSetMTLPixFmtCaps( iOS_GPUFamily3_v1, Depth32Float_Stencil8, DRMR );
+ addFeatSetMTLPixFmtCaps( iOS_GPUFamily3_v1, Stencil8, DRMR );
addFeatSetMTLPixFmtCaps( iOS_GPUFamily3_v2, BGRA10_XR, All );
addFeatSetMTLPixFmtCaps( iOS_GPUFamily3_v2, BGRA10_XR_sRGB, All );
@@ -1600,9 +1650,7 @@
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 |
@@ -1630,12 +1678,13 @@
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) {
@@ -1650,8 +1699,15 @@
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;
@@ -1666,9 +1722,10 @@
#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);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index f8decda..7706fd3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -67,6 +67,9 @@
/** Returns the Vulkan sample count of the attachments used in this subpass. */
VkSampleCountFlagBits getSampleCount();
+ /** Sets the default sample count for when there are no attachments used in this subpass. */
+ void setDefaultSampleCount(VkSampleCountFlagBits count) { _defaultSampleCount = count; }
+
/** Returns whether or not this is a multiview subpass. */
bool isMultiview() const { return _viewMask != 0; }
@@ -140,7 +143,11 @@
MVKSmallVector<VkAttachmentReference2, kMVKDefaultAttachmentCount> _resolveAttachments;
MVKSmallVector<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
VkAttachmentReference2 _depthStencilAttachment;
+ VkAttachmentReference2 _depthStencilResolveAttachment;
+ VkResolveModeFlagBits _depthResolveMode = VK_RESOLVE_MODE_NONE;
+ VkResolveModeFlagBits _stencilResolveMode = VK_RESOLVE_MODE_NONE;
id<MTLTexture> _mtlDummyTex = nil;
+ VkSampleCountFlagBits _defaultSampleCount = VK_SAMPLE_COUNT_1_BIT;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index c3eeb6a..52d21bc 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -21,6 +21,10 @@
#include "MVKCommandBuffer.h"
#include "MVKFoundation.h"
#include "mvk_datatypes.hpp"
+#include "MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h"
+#if MVK_MACOS_OR_IOS
+#include "MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h"
+#endif
#include <cassert>
using namespace std;
@@ -224,17 +228,31 @@
// Populate the Metal depth and stencil attachments
uint32_t dsRPAttIdx = _depthStencilAttachment.attachment;
+ uint32_t dsRslvRPAttIdx = _depthStencilResolveAttachment.attachment;
if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) {
MVKRenderPassAttachment* dsMVKRPAtt = &_renderPass->_attachments[dsRPAttIdx];
MVKImageView* dsImage = framebuffer->getAttachment(dsRPAttIdx);
+ MVKImageView* dsRslvImage = nullptr;
MTLPixelFormat mtlDSFormat = dsImage->getMTLPixelFormat(0);
+ if (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED) {
+ dsRslvImage = framebuffer->getAttachment(dsRslvRPAttIdx);
+ }
+
if (pixFmts->isDepthFormat(mtlDSFormat)) {
MTLRenderPassDepthAttachmentDescriptor* mtlDepthAttDesc = mtlRPDesc.depthAttachment;
+ bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _depthResolveMode != VK_RESOLVE_MODE_NONE);
+ if (hasResolveAttachment) {
+ dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlDepthAttDesc);
+ mtlDepthAttDesc.depthResolveFilterMVK = mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(_depthResolveMode);
+ if (isMultiview()) {
+ mtlDepthAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx);
+ }
+ }
dsImage->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc);
if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlDepthAttDesc, this,
isRenderingEntireAttachment,
- false, false,
+ hasResolveAttachment, false,
loadOverride)) {
mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[dsRPAttIdx]);
}
@@ -244,10 +262,20 @@
}
if (pixFmts->isStencilFormat(mtlDSFormat)) {
MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment;
+ bool hasResolveAttachment = (dsRslvRPAttIdx != VK_ATTACHMENT_UNUSED && _stencilResolveMode != VK_RESOLVE_MODE_NONE);
+ if (hasResolveAttachment) {
+ dsRslvImage->populateMTLRenderPassAttachmentDescriptorResolve(mtlStencilAttDesc);
+#if MVK_MACOS_OR_IOS
+ mtlStencilAttDesc.stencilResolveFilterMVK = mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(_stencilResolveMode);
+#endif
+ if (isMultiview()) {
+ mtlStencilAttDesc.resolveSlice += getFirstViewIndexInMetalPass(passIdx);
+ }
+ }
dsImage->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc);
if (dsMVKRPAtt->populateMTLRenderPassAttachmentDescriptor(mtlStencilAttDesc, this,
isRenderingEntireAttachment,
- false, true,
+ hasResolveAttachment, true,
loadOverride)) {
mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[dsRPAttIdx]);
}
@@ -259,10 +287,11 @@
_mtlDummyTex = nil;
if (caUsedCnt == 0 && dsRPAttIdx == VK_ATTACHMENT_UNUSED) {
+ uint32_t sampleCount = mvkSampleCountFromVkSampleCountFlagBits(_defaultSampleCount);
if (_renderPass->getDevice()->_pMetalFeatures->renderWithoutAttachments) {
// We support having no attachments.
#if MVK_MACOS_OR_IOS
- mtlRPDesc.defaultRasterSampleCount = 1;
+ mtlRPDesc.defaultRasterSampleCount = sampleCount;
#endif
return;
}
@@ -271,11 +300,32 @@
VkExtent2D fbExtent = framebuffer->getExtent2D();
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatR8Unorm width: fbExtent.width height: fbExtent.height mipmapped: NO];
if (isMultiview()) {
+#if MVK_MACOS
+ if (sampleCount > 1 && _renderPass->getDevice()->_pMetalFeatures->multisampleLayeredRendering) {
+ mtlTexDesc.textureType = MTLTextureType2DMultisampleArray;
+ mtlTexDesc.sampleCount = sampleCount;
+ } else {
+ mtlTexDesc.textureType = MTLTextureType2DArray;
+ }
+#else
mtlTexDesc.textureType = MTLTextureType2DArray;
+#endif
mtlTexDesc.arrayLength = getViewCountInMetalPass(passIdx);
} else if (framebuffer->getLayerCount() > 1) {
+#if MVK_MACOS
+ if (sampleCount > 1 && _renderPass->getDevice()->_pMetalFeatures->multisampleLayeredRendering) {
+ mtlTexDesc.textureType = MTLTextureType2DMultisampleArray;
+ mtlTexDesc.sampleCount = sampleCount;
+ } else {
+ mtlTexDesc.textureType = MTLTextureType2DArray;
+ }
+#else
mtlTexDesc.textureType = MTLTextureType2DArray;
+#endif
mtlTexDesc.arrayLength = framebuffer->getLayerCount();
+ } else if (sampleCount > 1) {
+ mtlTexDesc.textureType = MTLTextureType2DMultisample;
+ mtlTexDesc.sampleCount = sampleCount;
}
#if MVK_IOS
if ([_renderPass->getMTLDevice() supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily1_v3]) {
@@ -315,8 +365,11 @@
}
uint32_t dsRPAttIdx = _depthStencilAttachment.attachment;
if (dsRPAttIdx != VK_ATTACHMENT_UNUSED) {
- _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, false, 0, false, storeOverride);
- _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, false, 0, true, storeOverride);
+ bool hasResolveAttachment = _depthStencilResolveAttachment.attachment != VK_ATTACHMENT_UNUSED;
+ bool hasDepthResolveAttachment = hasResolveAttachment && _depthResolveMode != VK_RESOLVE_MODE_NONE;
+ bool hasStencilResolveAttachment = hasResolveAttachment && _stencilResolveMode != VK_RESOLVE_MODE_NONE;
+ _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, hasDepthResolveAttachment, 0, false, storeOverride);
+ _renderPass->_attachments[dsRPAttIdx].encodeStoreAction(cmdEncoder, this, isRenderingEntireAttachment, hasStencilResolveAttachment, 0, true, storeOverride);
}
}
@@ -394,6 +447,7 @@
}
}
if (_depthStencilAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsDSAtt); }
+ if (_depthStencilResolveAttachment.attachment == rpAttIdx) { mvkEnableFlags(caps, kMVKMTLFmtCapsResolve); }
return caps;
}
@@ -442,6 +496,8 @@
_depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED;
}
+ _depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED;
+
_preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) {
_preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]);
@@ -450,6 +506,18 @@
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
const VkSubpassDescription2* pCreateInfo) {
+
+ VkSubpassDescriptionDepthStencilResolve* pDSResolveInfo = nullptr;
+ for (auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE:
+ pDSResolveInfo = (VkSubpassDescriptionDepthStencilResolve*)next;
+ break;
+ default:
+ break;
+ }
+ }
+
_renderPass = renderPass;
_subpassIndex = (uint32_t)_renderPass->_subpasses.size();
_viewMask = pCreateInfo->viewMask;
@@ -478,6 +546,14 @@
_depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED;
}
+ if (pDSResolveInfo && pDSResolveInfo->pDepthStencilResolveAttachment) {
+ _depthStencilResolveAttachment = *pDSResolveInfo->pDepthStencilResolveAttachment;
+ _depthResolveMode = pDSResolveInfo->depthResolveMode;
+ _stencilResolveMode = pDSResolveInfo->stencilResolveMode;
+ } else {
+ _depthStencilResolveAttachment.attachment = VK_ATTACHMENT_UNUSED;
+ }
+
_preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount);
for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) {
_preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]);
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index cbb1f16..cd54eb6 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -44,6 +44,7 @@
MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, DEVICE)
MVK_EXTENSION(KHR_create_renderpass2, KHR_CREATE_RENDERPASS_2, DEVICE)
MVK_EXTENSION(KHR_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE)
+MVK_EXTENSION(KHR_depth_stencil_resolve, KHR_DEPTH_STENCIL_RESOLVE, DEVICE)
MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, DEVICE)
MVK_EXTENSION(KHR_device_group, KHR_DEVICE_GROUP, DEVICE)
MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE)
@@ -62,6 +63,7 @@
MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE)
MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE)
MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, DEVICE)
+MVK_EXTENSION(KHR_portability_subset, KHR_PORTABILITY_SUBSET, DEVICE)
MVK_EXTENSION(KHR_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE)
MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, DEVICE)
MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, DEVICE)
@@ -92,7 +94,6 @@
MVK_EXTENSION(EXT_swapchain_colorspace, EXT_SWAPCHAIN_COLOR_SPACE, INSTANCE)
MVK_EXTENSION(EXT_texel_buffer_alignment, EXT_TEXEL_BUFFER_ALIGNMENT, DEVICE)
MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR, DEVICE)
-MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET, DEVICE)
MVK_EXTENSION(MVK_ios_surface, MVK_IOS_SURFACE, INSTANCE)
MVK_EXTENSION(MVK_macos_surface, MVK_MACOS_SURFACE, INSTANCE)
MVK_EXTENSION(MVK_moltenvk, MVK_MOLTENVK, INSTANCE)
diff --git a/MoltenVK/MoltenVK/OS/MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h b/MoltenVK/MoltenVK/OS/MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h
new file mode 100644
index 0000000..4ea08a5
--- /dev/null
+++ b/MoltenVK/MoltenVK/OS/MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h
@@ -0,0 +1,34 @@
+/*
+ * MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h
+ *
+ * Copyright (c) 2020 Chip Davis for CodeWeavers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#import <Metal/Metal.h>
+
+/** Extensions to MTLRenderPassDepthAttachmentDescriptor to support MoltenVK. */
+@interface MTLRenderPassDepthAttachmentDescriptor (MoltenVK)
+
+/**
+ * Replacement for the depthResolveFilter property.
+ *
+ * This property allows support under all OS versions. Delegates to the depthResolveFilter
+ * property if it is available. Otherwise, returns MTLMultisampleDepthResolveFilterSample0 when read and does nothing when set.
+ */
+@property(nonatomic, readwrite) MTLMultisampleDepthResolveFilter depthResolveFilterMVK;
+
+@end
diff --git a/MoltenVK/MoltenVK/OS/MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m b/MoltenVK/MoltenVK/OS/MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m
new file mode 100644
index 0000000..eb249da
--- /dev/null
+++ b/MoltenVK/MoltenVK/OS/MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m
@@ -0,0 +1,42 @@
+/*
+ * MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m
+ *
+ * Copyright (c) 2020 Chip Davis for CodeWeavers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h"
+#include "MVKEnvironment.h"
+
+@implementation MTLRenderPassDepthAttachmentDescriptor (MoltenVK)
+
+-(MTLMultisampleDepthResolveFilter) depthResolveFilterMVK {
+
+ if ( [self respondsToSelector: @selector(depthResolveFilter)] ) {
+ return self.depthResolveFilter;
+ }
+ return MTLMultisampleDepthResolveFilterSample0;
+
+}
+
+-(void) setDepthResolveFilterMVK: (MTLMultisampleDepthResolveFilter) filter {
+
+ if ( [self respondsToSelector: @selector(setDepthResolveFilter:)] ) {
+ self.depthResolveFilter = filter;
+ }
+
+}
+
+@end
diff --git a/MoltenVK/MoltenVK/OS/MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h b/MoltenVK/MoltenVK/OS/MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h
new file mode 100644
index 0000000..d2fb4fe
--- /dev/null
+++ b/MoltenVK/MoltenVK/OS/MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h
@@ -0,0 +1,34 @@
+/*
+ * MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h
+ *
+ * Copyright (c) 2020 Chip Davis for CodeWeavers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#import <Metal/Metal.h>
+
+/** Extensions to MTLRenderPassStencilAttachmentDescriptor to support MoltenVK. */
+@interface MTLRenderPassStencilAttachmentDescriptor (MoltenVK)
+
+/**
+ * Replacement for the stencilResolveFilter property.
+ *
+ * This property allows support under all OS versions. Delegates to the stencilResolveFilter
+ * property if it is available. Otherwise, returns MTLMultisampleStencilResolveFilterSample0 when read and does nothing when set.
+ */
+@property(nonatomic, readwrite) MTLMultisampleStencilResolveFilter stencilResolveFilterMVK;
+
+@end
diff --git a/MoltenVK/MoltenVK/OS/MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m b/MoltenVK/MoltenVK/OS/MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m
new file mode 100644
index 0000000..4cbda58
--- /dev/null
+++ b/MoltenVK/MoltenVK/OS/MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m
@@ -0,0 +1,42 @@
+/*
+ * MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m
+ *
+ * Copyright (c) 2020 Chip Davis for CodeWeavers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "MTLRenderPassStencilAttachmentDescriptor+MoltenVK.h"
+#include "MVKEnvironment.h"
+
+@implementation MTLRenderPassStencilAttachmentDescriptor (MoltenVK)
+
+-(MTLMultisampleStencilResolveFilter) stencilResolveFilterMVK {
+
+ if ( [self respondsToSelector: @selector(stencilResolveFilter)] ) {
+ return self.stencilResolveFilter;
+ }
+ return MTLMultisampleStencilResolveFilterSample0;
+
+}
+
+-(void) setStencilResolveFilterMVK: (MTLMultisampleStencilResolveFilter) filter {
+
+ if ( [self respondsToSelector: @selector(setStencilResolveFilter:)] ) {
+ self.stencilResolveFilter = filter;
+ }
+
+}
+
+@end
diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
index 9748abc..d8d1ed2 100644
--- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h
+++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
@@ -54,7 +54,7 @@
/** 2D vertex position and texcoord content. */
typedef struct {
simd::float2 position;
- simd::float2 texCoord;
+ simd::float3 texCoord;
} MVKVertexPosTex;
@@ -376,6 +376,12 @@
}
};
+/** Returns the absolute value of the difference of two numbers. */
+template<typename T, typename U>
+constexpr typename std::common_type<T, U>::type mvkAbsDiff(T x, U y) {
+ return x >= y ? x - y : y - x;
+}
+
/** Returns the greatest common divisor of two numbers. */
template<typename T>
constexpr T mvkGreatestCommonDivisorImpl(T a, T b) {
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
index be0c519..7a2a5d9 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.hpp
@@ -62,6 +62,14 @@
MTLStoreAction mvkMTLStoreActionFromVkAttachmentStoreOpInObj(VkAttachmentStoreOp vkStoreOp, bool hasResolveAttachment, MVKBaseObject* mvkObj);
#define mvkMTLStoreActionFromVkAttachmentStoreOp(vkStoreOp, hasResolveAttachment) mvkMTLStoreActionFromVkAttachmentStoreOpInObj(vkStoreOp, hasResolveAttachment, this)
+MTLMultisampleDepthResolveFilter mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBitsInObj(VkResolveModeFlagBits vkResolveMode, MVKBaseObject* mvkObj);
+#define mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(vkResolveMode) mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBitsInObj(vkResolveMode, this)
+
+#if MVK_MACOS_OR_IOS
+MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBitsInObj(VkResolveModeFlagBits vkResolveMode, MVKBaseObject* mvkObj);
+#define mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(vkResolveMode) mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBitsInObj(vkResolveMode, this)
+#endif
+
MVKShaderStage mvkShaderStageFromVkShaderStageFlagBitsInObj(VkShaderStageFlagBits vkStage, MVKBaseObject* mvkObj);
#define mvkShaderStageFromVkShaderStageFlagBits(vkStage) mvkShaderStageFromVkShaderStageFlagBitsInObj(vkStage, this)
diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
index 57d6de1..8bee86e 100644
--- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
+++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm
@@ -509,6 +509,40 @@
}
}
+#undef mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits
+MVK_PUBLIC_SYMBOL MTLMultisampleDepthResolveFilter mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBits(VkResolveModeFlagBits vkResolveMode) {
+ return mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBitsInObj(vkResolveMode, nullptr);
+}
+
+MTLMultisampleDepthResolveFilter mvkMTLMultisampleDepthResolveFilterFromVkResolveModeFlagBitsInObj(VkResolveModeFlagBits vkResolveMode, MVKBaseObject* mvkObj) {
+ switch (vkResolveMode) {
+ case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: return MTLMultisampleDepthResolveFilterSample0;
+ case VK_RESOLVE_MODE_MIN_BIT: return MTLMultisampleDepthResolveFilterMin;
+ case VK_RESOLVE_MODE_MAX_BIT: return MTLMultisampleDepthResolveFilterMax;
+
+ default:
+ MVKBaseObject::reportError(mvkObj, VK_ERROR_FORMAT_NOT_SUPPORTED, "VkResolveModeFlagBits value %d is not supported.", vkResolveMode);
+ return MTLMultisampleDepthResolveFilterSample0;
+ }
+}
+
+#if MVK_MACOS_OR_IOS
+#undef mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits
+MVK_PUBLIC_SYMBOL MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBits(VkResolveModeFlagBits vkResolveMode) {
+ return mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBitsInObj(vkResolveMode, nullptr);
+}
+
+MTLMultisampleStencilResolveFilter mvkMTLMultisampleStencilResolveFilterFromVkResolveModeFlagBitsInObj(VkResolveModeFlagBits vkResolveMode, MVKBaseObject* mvkObj) {
+ switch (vkResolveMode) {
+ case VK_RESOLVE_MODE_SAMPLE_ZERO_BIT: return MTLMultisampleStencilResolveFilterSample0;
+
+ default:
+ MVKBaseObject::reportError(mvkObj, VK_ERROR_FORMAT_NOT_SUPPORTED, "VkResolveModeFlagBits value %d is not supported.", vkResolveMode);
+ return MTLMultisampleStencilResolveFilterSample0;
+ }
+}
+#endif
+
MVK_PUBLIC_SYMBOL MTLViewport mvkMTLViewportFromVkViewport(VkViewport vkViewport) {
MTLViewport mtlViewport;
mtlViewport.originX = vkViewport.x;
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index f0e1824..1fecb88 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -174,6 +174,7 @@
MVKInstance* mvkInst = new MVKInstance(pCreateInfo);
*pInstance = mvkInst->getVkInstance();
VkResult rslt = mvkInst->getConfigurationResult();
+ if (rslt < 0) { *pInstance = nullptr; mvkInst->destroy(); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -313,6 +314,7 @@
MVKDevice* mvkDev = new MVKDevice(mvkPD, pCreateInfo);
*pDevice = mvkDev->getVkDevice();
VkResult rslt = mvkDev->getConfigurationResult();
+ if (rslt < 0) { *pDevice = nullptr; mvkDev->destroy(); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -428,6 +430,7 @@
MVKDeviceMemory* mvkMem = mvkDev->allocateMemory(pAllocateInfo, pAllocator);
VkResult rslt = mvkMem->getConfigurationResult();
*pMem = (VkDeviceMemory)((rslt == VK_SUCCESS) ? mvkMem : VK_NULL_HANDLE);
+ if (rslt != VK_SUCCESS) { mvkDev->freeMemory(mvkMem, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -618,6 +621,7 @@
MVKFence* mvkFence = mvkDev->createFence(pCreateInfo, pAllocator);
*pFence = (VkFence)mvkFence;
VkResult rslt = mvkFence->getConfigurationResult();
+ if (rslt < 0) { *pFence = VK_NULL_HANDLE; mvkDev->destroyFence(mvkFence, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -680,6 +684,7 @@
MVKSemaphore* mvkSem4 = mvkDev->createSemaphore(pCreateInfo, pAllocator);
*pSemaphore = (VkSemaphore)mvkSem4;
VkResult rslt = mvkSem4->getConfigurationResult();
+ if (rslt < 0) { *pSemaphore = VK_NULL_HANDLE; mvkDev->destroySemaphore(mvkSem4, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -706,6 +711,7 @@
MVKEvent* mvkEvent = mvkDev->createEvent(pCreateInfo, pAllocator);
*pEvent = (VkEvent)mvkEvent;
VkResult rslt = mvkEvent->getConfigurationResult();
+ if (rslt < 0) { *pEvent = VK_NULL_HANDLE; mvkDev->destroyEvent(mvkEvent, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -765,6 +771,7 @@
MVKQueryPool* mvkQP = mvkDev->createQueryPool(pCreateInfo, pAllocator);
*pQueryPool = (VkQueryPool)mvkQP;
VkResult rslt = mvkQP->getConfigurationResult();
+ if (rslt < 0) { *pQueryPool = VK_NULL_HANDLE; mvkDev->destroyQueryPool(mvkQP, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -808,6 +815,7 @@
MVKBuffer* mvkBuff = mvkDev->createBuffer(pCreateInfo, pAllocator);
*pBuffer = (VkBuffer)mvkBuff;
VkResult rslt = mvkBuff->getConfigurationResult();
+ if (rslt < 0) { *pBuffer = VK_NULL_HANDLE; mvkDev->destroyBuffer(mvkBuff, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -834,6 +842,7 @@
MVKBufferView* mvkBuffView = mvkDev->createBufferView(pCreateInfo, pAllocator);
*pView = (VkBufferView)mvkBuffView;
VkResult rslt = mvkBuffView->getConfigurationResult();
+ if (rslt < 0) { *pView = VK_NULL_HANDLE; mvkDev->destroyBufferView(mvkBuffView, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -860,6 +869,7 @@
MVKImage* mvkImg = mvkDev->createImage(pCreateInfo, pAllocator);
*pImage = (VkImage)mvkImg;
VkResult rslt = mvkImg->getConfigurationResult();
+ if (rslt < 0) { *pImage = VK_NULL_HANDLE; mvkDev->destroyImage(mvkImg, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -898,6 +908,7 @@
MVKImageView* mvkImgView = mvkDev->createImageView(pCreateInfo, pAllocator);
*pView = (VkImageView)mvkImgView;
VkResult rslt = mvkImgView->getConfigurationResult();
+ if (rslt < 0) { *pView = VK_NULL_HANDLE; mvkDev->destroyImageView(mvkImgView, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -924,6 +935,7 @@
MVKShaderModule* mvkShdrMod = mvkDev->createShaderModule(pCreateInfo, pAllocator);
*pShaderModule = (VkShaderModule)mvkShdrMod;
VkResult rslt = mvkShdrMod->getConfigurationResult();
+ if (rslt < 0) { *pShaderModule = VK_NULL_HANDLE; mvkDev->destroyShaderModule(mvkShdrMod, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -950,6 +962,7 @@
MVKPipelineCache* mvkPLC = mvkDev->createPipelineCache(pCreateInfo, pAllocator);
*pPipelineCache = (VkPipelineCache)mvkPLC;
VkResult rslt = mvkPLC->getConfigurationResult();
+ if (rslt < 0) { *pPipelineCache = VK_NULL_HANDLE; mvkDev->destroyPipelineCache(mvkPLC, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -1043,6 +1056,7 @@
MVKPipelineLayout* mvkPLL = mvkDev->createPipelineLayout(pCreateInfo, pAllocator);
*pPipelineLayout = (VkPipelineLayout)mvkPLL;
VkResult rslt = mvkPLL->getConfigurationResult();
+ if (rslt < 0) { *pPipelineLayout = VK_NULL_HANDLE; mvkDev->destroyPipelineLayout(mvkPLL, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -1069,6 +1083,7 @@
MVKSampler* mvkSamp = mvkDev->createSampler(pCreateInfo, pAllocator);
*pSampler = (VkSampler)mvkSamp;
VkResult rslt = mvkSamp->getConfigurationResult();
+ if (rslt < 0) { *pSampler = VK_NULL_HANDLE; mvkDev->destroySampler(mvkSamp, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -1095,6 +1110,7 @@
MVKDescriptorSetLayout* mvkDSL = mvkDev->createDescriptorSetLayout(pCreateInfo, pAllocator);
*pSetLayout = (VkDescriptorSetLayout)mvkDSL;
VkResult rslt = mvkDSL->getConfigurationResult();
+ if (rslt < 0) { *pSetLayout = VK_NULL_HANDLE; mvkDev->destroyDescriptorSetLayout(mvkDSL, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -1121,6 +1137,7 @@
MVKDescriptorPool* mvkDP = mvkDev->createDescriptorPool(pCreateInfo, pAllocator);
*pDescriptorPool = (VkDescriptorPool)mvkDP;
VkResult rslt = mvkDP->getConfigurationResult();
+ if (rslt < 0) { *pDescriptorPool = VK_NULL_HANDLE; mvkDev->destroyDescriptorPool(mvkDP, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -1198,6 +1215,7 @@
MVKFramebuffer* mvkFB = mvkDev->createFramebuffer(pCreateInfo, pAllocator);
*pFramebuffer = (VkFramebuffer)mvkFB;
VkResult rslt = mvkFB->getConfigurationResult();
+ if (rslt < 0) { *pFramebuffer = VK_NULL_HANDLE; mvkDev->destroyFramebuffer(mvkFB, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -1224,6 +1242,7 @@
MVKRenderPass* mvkRendPass = mvkDev->createRenderPass(pCreateInfo, pAllocator);
*pRenderPass = (VkRenderPass)mvkRendPass;
VkResult rslt = mvkRendPass->getConfigurationResult();
+ if (rslt < 0) { *pRenderPass = VK_NULL_HANDLE; mvkDev->destroyRenderPass(mvkRendPass, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -1261,6 +1280,7 @@
MVKCommandPool* mvkCmdPool = mvkDev->createCommandPool(pCreateInfo, pAllocator);
*pCmdPool = (VkCommandPool)mvkCmdPool;
VkResult rslt = mvkCmdPool->getConfigurationResult();
+ if (rslt < 0) { *pCmdPool = VK_NULL_HANDLE; mvkDev->destroyCommandPool(mvkCmdPool, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2146,6 +2166,10 @@
pAllocator);
*pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplate)mvkDUT;
VkResult rslt = mvkDUT->getConfigurationResult();
+ if (rslt < 0) {
+ *pDescriptorUpdateTemplate = VK_NULL_HANDLE;
+ mvkDev->destroyDescriptorUpdateTemplate(mvkDUT, pAllocator);
+ }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2194,6 +2218,10 @@
MVKSamplerYcbcrConversion* mvkSampConv = mvkDev->createSamplerYcbcrConversion(pCreateInfo, pAllocator);
*pYcbcrConversion = (VkSamplerYcbcrConversion)mvkSampConv;
VkResult rslt = mvkSampConv->getConfigurationResult();
+ if (rslt < 0) {
+ *pYcbcrConversion = VK_NULL_HANDLE;
+ mvkDev->destroySamplerYcbcrConversion(mvkSampConv, pAllocator);
+ }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2267,6 +2295,7 @@
MVKRenderPass* mvkRendPass = mvkDev->createRenderPass(pCreateInfo, pAllocator);
*pRenderPass = (VkRenderPass)mvkRendPass;
VkResult rslt = mvkRendPass->getConfigurationResult();
+ if (rslt < 0) { *pRenderPass = VK_NULL_HANDLE; mvkDev->destroyRenderPass(mvkRendPass, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2423,6 +2452,7 @@
MVKSwapchain* mvkSwpChn = mvkDev->createSwapchain(pCreateInfo, pAllocator);
*pSwapchain = (VkSwapchainKHR)(mvkSwpChn);
VkResult rslt = mvkSwpChn->getConfigurationResult();
+ if (rslt < 0) { *pSwapchain = VK_NULL_HANDLE; mvkDev->destroySwapchain(mvkSwpChn, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2647,6 +2677,7 @@
MVKDebugReportCallback* mvkDRCB = mvkInst->createDebugReportCallback(pCreateInfo, pAllocator);
*pCallback = (VkDebugReportCallbackEXT)mvkDRCB;
VkResult rslt = mvkDRCB->getConfigurationResult();
+ if (rslt < 0) { *pCallback = VK_NULL_HANDLE; mvkInst->destroyDebugReportCallback(mvkDRCB, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2814,6 +2845,7 @@
MVKDebugUtilsMessenger* mvkDUM = mvkInst->createDebugUtilsMessenger(pCreateInfo, pAllocator);
*pMessenger = (VkDebugUtilsMessengerEXT)mvkDUM;
VkResult rslt = mvkDUM->getConfigurationResult();
+ if (rslt < 0) { *pMessenger = VK_NULL_HANDLE; mvkInst->destroyDebugUtilsMessenger(mvkDUM, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2890,6 +2922,7 @@
MVKSurface* mvkSrfc = mvkInst->createSurface(pCreateInfo, pAllocator);
*pSurface = (VkSurfaceKHR)mvkSrfc;
VkResult rslt = mvkSrfc->getConfigurationResult();
+ if (rslt < 0) { *pSurface = VK_NULL_HANDLE; mvkInst->destroySurface(mvkSrfc, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
@@ -2934,6 +2967,7 @@
MVKSurface* mvkSrfc = mvkInst->createSurface(pCreateInfo, pAllocator);
*pSurface = (VkSurfaceKHR)mvkSrfc;
VkResult rslt = mvkSrfc->getConfigurationResult();
+ if (rslt < 0) { *pSurface = VK_NULL_HANDLE; mvkInst->destroySurface(mvkSrfc, pAllocator); }
MVKTraceVulkanCallEnd();
return rslt;
}
diff --git a/MoltenVK/include/vulkan-portability b/MoltenVK/include/vulkan-portability
deleted file mode 120000
index cfe721d..0000000
--- a/MoltenVK/include/vulkan-portability
+++ /dev/null
@@ -1 +0,0 @@
-../../External/Vulkan-Portability/include/vulkan
\ No newline at end of file
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
index 8157a46..5b64a99 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
@@ -770,7 +770,6 @@
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
GCC_WARN_UNUSED_PARAMETER = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/tvOS\"";
PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 11.0;
@@ -785,7 +784,6 @@
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
GCC_WARN_UNUSED_PARAMETER = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/tvOS\"";
PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 11.0;
@@ -800,7 +798,6 @@
"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
);
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/tvOS\"";
PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 11.0;
@@ -815,7 +812,6 @@
"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
);
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/tvOS\"";
PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
SDKROOT = appletvos;
TVOS_DEPLOYMENT_TARGET = 11.0;
@@ -858,7 +854,6 @@
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
GCC_WARN_UNUSED_PARAMETER = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/iOS\"";
PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
SDKROOT = iphoneos;
};
@@ -872,7 +867,6 @@
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
GCC_WARN_UNUSED_PARAMETER = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/iOS\"";
PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
SDKROOT = iphoneos;
};
@@ -886,7 +880,6 @@
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
GCC_WARN_UNUSED_PARAMETER = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/macOS\"";
PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
SDKROOT = macosx;
};
@@ -900,7 +893,6 @@
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = NO;
GCC_WARN_CHECK_SWITCH_STATEMENTS = NO;
GCC_WARN_UNUSED_PARAMETER = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/macOS\"";
PRODUCT_NAME = MoltenVKGLSLToSPIRVConverter;
SDKROOT = macosx;
};
@@ -914,7 +906,6 @@
"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
);
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/iOS\"";
PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
SDKROOT = iphoneos;
};
@@ -928,7 +919,6 @@
"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
);
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/iOS\"";
PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
SDKROOT = iphoneos;
};
@@ -942,7 +932,6 @@
"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
);
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/macOS\"";
PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
SDKROOT = macosx;
};
@@ -956,7 +945,6 @@
"SPIRV_CROSS_NAMESPACE_OVERRIDE=MVK_spirv_cross",
);
GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
- LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/../External/build/Latest/macOS\"";
PRODUCT_NAME = MoltenVKSPIRVToMSLConverter;
SDKROOT = macosx;
};
diff --git a/fetchDependencies b/fetchDependencies
index 08a2cb0..28bd8d7 100755
--- a/fetchDependencies
+++ b/fetchDependencies
@@ -252,18 +252,6 @@
update_repo ${REPO_NAME} ${REPO_URL} ${REPO_REV}
fi
-# ----------------- Vulkan-Portability -------------------
-
-echo
-echo ========== Vulkan-Portability ==========
-echo
-
-REPO_NAME=Vulkan-Portability
-REPO_URL="https://github.com/KhronosGroup/${REPO_NAME}.git"
-REPO_REV=$(cat "${EXT_REV_DIR}/${REPO_NAME}_repo_revision")
-
-update_repo ${REPO_NAME} ${REPO_URL} ${REPO_REV}
-
# ----------------- SPIRV-Cross -------------------