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 -------------------