Merge branch 'master' of https://github.com/billhollings/MoltenVK into xcode12
diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h
index 4fe27b4..d153126 100644
--- a/Common/MVKCommonEnvironment.h
+++ b/Common/MVKCommonEnvironment.h
@@ -75,6 +75,9 @@
/** Directive to identify public symbols. */
#define MVK_PUBLIC_SYMBOL __attribute__((visibility("default")))
+/** Directive to make a public alias of another symbol. */
+#define MVK_PUBLIC_ALIAS(ALIAS, TARGET) asm(".globl _" #ALIAS "\n\t_" #ALIAS " = _" #TARGET)
+
#ifdef __cplusplus
}
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
index a573e92..793b789 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
@@ -537,7 +537,11 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
+<<<<<<< HEAD
LastUpgradeCheck = 1200;
+=======
+ LastUpgradeCheck = 1170;
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "API-Samples" */;
compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
index 6dfcf40..72c7418 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
+<<<<<<< HEAD
LastUpgradeVersion = "1200"
+=======
+ LastUpgradeVersion = "1170"
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
index 4e9d68a..24bd8fb 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
+<<<<<<< HEAD
LastUpgradeVersion = "1200"
+=======
+ LastUpgradeVersion = "1170"
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
index e8259c9..3f8e86d 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
@@ -244,7 +244,11 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
+<<<<<<< HEAD
LastUpgradeCheck = 1200;
+=======
+ LastUpgradeCheck = 1170;
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Cube" */;
compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
index 90782be..8b26c54 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
+<<<<<<< HEAD
LastUpgradeVersion = "1200"
+=======
+ LastUpgradeVersion = "1170"
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
index e4a0e11..7f01964 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
+<<<<<<< HEAD
LastUpgradeVersion = "1200"
+=======
+ LastUpgradeVersion = "1170"
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-tvOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-tvOS.xcscheme
index 7ec8e93..bf3b23c 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-tvOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-tvOS.xcscheme
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
+<<<<<<< HEAD
LastUpgradeVersion = "1200"
+=======
+ LastUpgradeVersion = "1170"
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
index 019e6ab..ffbf078 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
@@ -292,7 +292,11 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
+<<<<<<< HEAD
LastUpgradeCheck = 1200;
+=======
+ LastUpgradeCheck = 1170;
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hologram" */;
compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
index b045bc2..50ff9d4 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
+<<<<<<< HEAD
LastUpgradeVersion = "1200"
+=======
+ LastUpgradeVersion = "1170"
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
index 222a360..7e228c3 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
+<<<<<<< HEAD
LastUpgradeVersion = "1200"
+=======
+ LastUpgradeVersion = "1170"
+>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 2794bc7..28e913f 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -54,7 +54,7 @@
About **MoltenVK**
------------------
-**MoltenVK** is a layered implementation of [*Vulkan 1.0*](https://www.khronos.org/vulkan)
+**MoltenVK** is a layered implementation of [*Vulkan 1.1*](https://www.khronos.org/vulkan)
graphics and compute functionality, that is built on Apple's [*Metal*](https://developer.apple.com/metal)
graphics and compute framework on *macOS*, *iOS*, and *tvOS*. **MoltenVK** allows you to use *Vulkan*
graphics and compute functionality to develop modern, cross-platform, high-performance graphical games
@@ -272,6 +272,7 @@
- `VK_KHR_16bit_storage`
- `VK_KHR_8bit_storage`
- `VK_KHR_bind_memory2`
+- `VK_KHR_create_renderpass2`
- `VK_KHR_dedicated_allocation`
- `VK_KHR_descriptor_update_template`
- `VK_KHR_device_group`
@@ -284,6 +285,7 @@
- `VK_KHR_maintenance1`
- `VK_KHR_maintenance2`
- `VK_KHR_maintenance3`
+- `VK_KHR_multiview`
- `VK_KHR_push_descriptor`
- `VK_KHR_relaxed_block_layout`
- `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)*
@@ -310,7 +312,7 @@
- `VK_EXT_scalar_block_layout`
- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
- `VK_EXT_shader_viewport_index_layer`
-- `VK_EXT_swapchain_colorspace` *(macOS)*
+- `VK_EXT_swapchain_colorspace`
- `VK_EXT_vertex_attribute_divisor`
- `VK_EXT_texel_buffer_alignment` *(requires Metal 2.0)*
- `VK_EXTX_portability_subset`
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 8b545bc..b34e5a7 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -13,17 +13,36 @@
-MoltenVK 1.0.45
----------------
+MoltenVK 1.1.0
+--------------
-Released TBD
+Released 2020/09/28
+- Add support for Vulkan 1.1, including:
+ - The `vkEnumerateInstanceVersion()` function
+ - The `vkGetDeviceQueue2()` function
+ - Protected memory (non-functional)
+ - 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_create_renderpass2`
+ - `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
+ extensions, including support for GCD and Mach semaphores)
+ - `VK_KHR_external_semaphore` (non-functional groundwork for future
+ `MTLSharedEvent` Vulkan extension)
+ - `VK_KHR_external_semaphore_capabilities` (non-functional groundwork for
+ future `MTLSharedEvent` Vulkan extension)
+ - `VK_KHR_multiview`
- Improve performance of tessellation control pipeline stage by processing multiple
patches per workgroup.
- `vkCmdBindDescriptorSets` order `pDynamicOffsets` by descriptor binding number
within each descriptor set.
- `vkCmdCopyImage` on macOS flush non-coherent image memory before copy operation.
- Re-add support for bitcode generation on *iOS* and *tvOS*.
+- Fix Metal validation error when occlusion query and renderpass are in separate
+ Vulkan command buffers.
diff --git a/ExternalDependencies.xcodeproj/project.pbxproj b/ExternalDependencies.xcodeproj/project.pbxproj
index 71f4424..b52a0e6 100644
--- a/ExternalDependencies.xcodeproj/project.pbxproj
+++ b/ExternalDependencies.xcodeproj/project.pbxproj
@@ -3876,7 +3876,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1200;
+ LastUpgradeCheck = 1170;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = {
2FEA0ADD2490320500EEF3AD = {
diff --git "a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme" "b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
index afa2716..eeb4b7c 100644
--- "a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
+++ "b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies \050Debug\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
index 69f3f9f..00d6ccf 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
index e53e9e2..a10009e 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-tvOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-tvOS.xcscheme
index b804f9e..ee4c160 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-tvOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies-tvOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
index ae2d752..47b84ab 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/ExternalDependencies.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
index 1f9576d..e8ab466 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
index 9b539bb..a6d64eb 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-tvOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-tvOS.xcscheme
index 562b580..518e1ad 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-tvOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Cross-tvOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
index 9bf3dd8..3564426 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
index 528e4fe..fe1badc 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-tvOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-tvOS.xcscheme
index 37e0ccf..ab6dae1 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-tvOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/SPIRV-Tools-tvOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
index b18ada4..fce9a75 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
index 6747a73..daa0316 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-tvOS.xcscheme b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-tvOS.xcscheme
index b3502e7..79aa0ff 100644
--- a/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-tvOS.xcscheme
+++ b/ExternalDependencies.xcodeproj/xcshareddata/xcschemes/glslang-tvOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index b5dd43e..152dbde 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-0376576d2dc0721edfb2c5a0257fdc275f6f39dc
+bad9dab8df6f2e6b80da9693db247b9357aebd2f
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index 5eb205f..73a4aa9 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -1102,7 +1102,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1200;
+ LastUpgradeCheck = 1170;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = {
A9B8EE091A98D796009C5A02 = {
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
index b0535fc..74b9b10 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
index 2195546..4abb1f4 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-tvOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-tvOS.xcscheme
index e4527e8..86f8f1c 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-tvOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-tvOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index 2c4eb20..309097a 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -49,8 +49,8 @@
* - 401215 (version 4.12.15)
*/
#define MVK_VERSION_MAJOR 1
-#define MVK_VERSION_MINOR 0
-#define MVK_VERSION_PATCH 45
+#define MVK_VERSION_MINOR 1
+#define MVK_VERSION_PATCH 0
#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
index a731001..964af0d 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
@@ -137,7 +137,6 @@
switch (stage) {
case kMVKGraphicsStageVertex: {
- cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) {
vtxOutBuff = cmdEncoder->getTempMTLBuffer(_vertexCount * _instanceCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents);
@@ -243,17 +242,20 @@
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass();
} else {
+ MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
+ uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
+ uint32_t instanceCount = _instanceCount * viewCount;
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
vertexStart: _firstVertex
vertexCount: _vertexCount
- instanceCount: _instanceCount
+ instanceCount: instanceCount
baseInstance: _firstInstance];
} else {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
vertexStart: _firstVertex
vertexCount: _vertexCount
- instanceCount: _instanceCount];
+ instanceCount: instanceCount];
}
}
break;
@@ -328,7 +330,6 @@
switch (stage) {
case kMVKGraphicsStageVertex: {
- cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) {
vtxOutBuff = cmdEncoder->getTempMTLBuffer(_indexCount * _instanceCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents);
@@ -440,13 +441,16 @@
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass();
} else {
+ MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
+ uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
+ uint32_t instanceCount = _instanceCount * viewCount;
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexCount: _indexCount
indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer
indexBufferOffset: idxBuffOffset
- instanceCount: _instanceCount
+ instanceCount: instanceCount
baseVertex: _vertexOffset
baseInstance: _firstInstance];
} else {
@@ -455,7 +459,7 @@
indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer
indexBufferOffset: idxBuffOffset
- instanceCount: _instanceCount];
+ instanceCount: instanceCount];
}
}
break;
@@ -499,11 +503,13 @@
void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline();
+ bool needsInstanceAdjustment = cmdEncoder->getSubpass()->isMultiview() &&
+ cmdEncoder->getDevice()->getPhysicalDevice()->canUseInstancingForMultiview();
// The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats.
// We have to convert from the drawPrimitives:... format to them.
// While we're at it, we can create the temporary output buffers once and reuse them
// for each draw.
- const MVKMTLBufferAllocation* tcIndirectBuff = nullptr;
+ const MVKMTLBufferAllocation* tempIndirectBuff = nullptr;
const MVKMTLBufferAllocation* tcParamsBuff = nullptr;
const MVKMTLBufferAllocation* vtxOutBuff = nullptr;
const MVKMTLBufferAllocation* tcOutBuff = nullptr;
@@ -513,7 +519,8 @@
uint32_t inControlPointCount = 0, outControlPointCount = 0;
VkDeviceSize paramsIncr = 0;
- VkDeviceSize mtlTCIndBuffOfst = 0;
+ id<MTLBuffer> mtlIndBuff = _mtlIndirectBuffer;
+ VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
VkDeviceSize mtlParmBuffOfst = 0;
NSUInteger vtxThreadExecWidth = 0;
NSUInteger tcWorkgroupSize = 0;
@@ -533,8 +540,9 @@
}
paramsIncr = std::max((size_t)cmdEncoder->getDevice()->_pProperties->limits.minUniformBufferOffsetAlignment, sizeof(uint32_t) * 2);
VkDeviceSize paramsSize = paramsIncr * _drawCount;
- tcIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
- mtlTCIndBuffOfst = tcIndirectBuff->_offset;
+ tempIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
+ mtlIndBuff = tempIndirectBuff->_mtlBuffer;
+ mtlIndBuffOfst = tempIndirectBuff->_offset;
tcParamsBuff = cmdEncoder->getTempMTLBuffer(paramsSize);
mtlParmBuffOfst = tcParamsBuff->_offset;
if (pipeline->needsVertexOutputBuffer()) {
@@ -555,31 +563,35 @@
sgSize >>= 1;
tcWorkgroupSize = mvkLeastCommonMultiple(outControlPointCount, sgSize);
}
+ } else if (needsInstanceAdjustment) {
+ // In this case, we need to adjust the instance count for the views being drawn.
+ VkDeviceSize indirectSize = sizeof(MTLDrawPrimitivesIndirectArguments) * _drawCount;
+ tempIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
+ mtlIndBuff = tempIndirectBuff->_mtlBuffer;
+ mtlIndBuffOfst = tempIndirectBuff->_offset;
}
MVKPiplineStages stages;
pipeline->getStages(stages);
- VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
-
for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) {
for (uint32_t s : stages) {
auto stage = MVKGraphicsStage(s);
id<MTLComputeCommandEncoder> mtlTessCtlEncoder = nil;
- if (drawIdx == 0 && stage == kMVKGraphicsStageVertex) {
+ if (drawIdx == 0 && stage == kMVKGraphicsStageVertex && pipeline->isTessellationPipeline()) {
// We need the indirect buffers now. This must be done before finalizing
// draw state, or the pipeline will get overridden. This is a good time
// to do it, since it will require switching to compute anyway. Do it all
// at once to get it over with.
cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
- id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectConvertBuffersMTLComputePipelineState(false);
+ id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(false);
[mtlTessCtlEncoder setComputePipelineState: mtlConvertState];
[mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer
offset: _mtlIndirectBufferOffset
atIndex: 0];
- [mtlTessCtlEncoder setBuffer: tcIndirectBuff->_mtlBuffer
- offset: tcIndirectBuff->_offset
+ [mtlTessCtlEncoder setBuffer: tempIndirectBuff->_mtlBuffer
+ offset: tempIndirectBuff->_offset
atIndex: 1];
[mtlTessCtlEncoder setBuffer: tcParamsBuff->_mtlBuffer
offset: tcParamsBuff->_offset
@@ -617,6 +629,45 @@
[mtlTessCtlEncoder dispatchThreadgroups: MTLSizeMake(mvkCeilingDivide<NSUInteger>(_drawCount, mtlConvertState.threadExecutionWidth), 1, 1)
threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)];
}
+ } else if (drawIdx == 0 && needsInstanceAdjustment) {
+ // Similarly, for multiview, we need to adjust the instance count now.
+ // Unfortunately, this requires switching to compute.
+ // TODO: Consider using tile shaders to avoid this cost.
+ cmdEncoder->encodeStoreActions(true);
+ id<MTLComputeCommandEncoder> mtlConvertEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseMultiviewInstanceCountAdjust);
+ id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(false);
+ uint32_t viewCount;
+ [mtlConvertEncoder setComputePipelineState: mtlConvertState];
+ [mtlConvertEncoder setBuffer: _mtlIndirectBuffer
+ offset: _mtlIndirectBufferOffset
+ atIndex: 0];
+ [mtlConvertEncoder setBuffer: tempIndirectBuff->_mtlBuffer
+ offset: tempIndirectBuff->_offset
+ atIndex: 1];
+ cmdEncoder->setComputeBytes(mtlConvertEncoder,
+ &_mtlIndirectBufferStride,
+ sizeof(_mtlIndirectBufferStride),
+ 2);
+ cmdEncoder->setComputeBytes(mtlConvertEncoder,
+ &_drawCount,
+ sizeof(_drawCount),
+ 3);
+ viewCount = cmdEncoder->getSubpass()->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex());
+ cmdEncoder->setComputeBytes(mtlConvertEncoder,
+ &viewCount,
+ sizeof(viewCount),
+ 4);
+ if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
+#if MVK_MACOS_OR_IOS
+ [mtlConvertEncoder dispatchThreads: MTLSizeMake(_drawCount, 1, 1)
+ threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)];
+#endif
+ } else {
+ [mtlConvertEncoder dispatchThreadgroups: MTLSizeMake(mvkCeilingDivide<NSUInteger>(_drawCount, mtlConvertState.threadExecutionWidth), 1, 1)
+ threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)];
+ }
+ // Switch back to rendering now, since we don't have compute stages to run anyway.
+ cmdEncoder->beginMetalRenderPass(true);
}
cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal
@@ -625,7 +676,6 @@
switch (stage) {
case kMVKGraphicsStageVertex:
- cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) {
[mtlTessCtlEncoder setBuffer: vtxOutBuff->_mtlBuffer
@@ -635,14 +685,14 @@
// We must assume we can read up to the maximum number of vertices.
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(0, 0, vertexCount, vertexCount)];
if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) {
- [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst];
- mtlTCIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments);
+ [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlIndBuffOfst];
+ mtlIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments);
}
- [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst
+ [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
- mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
+ mtlIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
// Mark pipeline, resources, and tess control push constants as dirty
// so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
@@ -674,10 +724,10 @@
offset: vtxOutBuff->_offset
atIndex: kMVKTessCtlInputBufferIndex];
}
- [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst
+ [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(tcWorkgroupSize, 1, 1)];
- mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
+ mtlIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
// Running this stage prematurely ended the render pass, so we have to start it up again.
// TODO: On iOS, maybe we could use a tile shader to avoid this.
cmdEncoder->beginMetalRenderPass(true);
@@ -705,22 +755,22 @@
[cmdEncoder->_mtlRenderEncoder drawPatches: outControlPointCount
patchIndexBuffer: nil
patchIndexBufferOffset: 0
- indirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst];
+ indirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlIndBuffOfst];
#endif
}
- mtlTCIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments);
- // Mark pipeline, resources, and tess control push constants as dirty
+ mtlIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments);
+ // 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 {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
- indirectBuffer: _mtlIndirectBuffer
+ indirectBuffer: mtlIndBuff
indirectBufferOffset: mtlIndBuffOfst];
- mtlIndBuffOfst += _mtlIndirectBufferStride;
+ mtlIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawPrimitivesIndirectArguments) : _mtlIndirectBufferStride;
}
break;
}
@@ -759,11 +809,13 @@
MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline();
+ bool needsInstanceAdjustment = cmdEncoder->getSubpass()->isMultiview() &&
+ cmdEncoder->getDevice()->getPhysicalDevice()->canUseInstancingForMultiview();
// The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats.
// We have to convert from the drawIndexedPrimitives:... format to them.
// While we're at it, we can create the temporary output buffers once and reuse them
// for each draw.
- const MVKMTLBufferAllocation* tcIndirectBuff = nullptr;
+ const MVKMTLBufferAllocation* tempIndirectBuff = nullptr;
const MVKMTLBufferAllocation* tcParamsBuff = nullptr;
const MVKMTLBufferAllocation* vtxOutBuff = nullptr;
const MVKMTLBufferAllocation* tcOutBuff = nullptr;
@@ -774,7 +826,9 @@
uint32_t inControlPointCount = 0, outControlPointCount = 0;
VkDeviceSize paramsIncr = 0;
- VkDeviceSize mtlTCIndBuffOfst = 0;
+ id<MTLBuffer> mtlIndBuff = _mtlIndirectBuffer;
+ VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
+ VkDeviceSize mtlTempIndBuffOfst = _mtlIndirectBufferOffset;
VkDeviceSize mtlParmBuffOfst = 0;
NSUInteger vtxThreadExecWidth = 0;
NSUInteger tcWorkgroupSize = 0;
@@ -794,9 +848,10 @@
}
paramsIncr = std::max((size_t)cmdEncoder->getDevice()->_pProperties->limits.minUniformBufferOffsetAlignment, sizeof(uint32_t) * 2);
VkDeviceSize paramsSize = paramsIncr * _drawCount;
- tcIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
- mtlTCIndBuffOfst = tcIndirectBuff->_offset;
- tcParamsBuff = cmdEncoder->getTempMTLBuffer(paramsSize);
+ tempIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
+ mtlIndBuff = tempIndirectBuff->_mtlBuffer;
+ mtlTempIndBuffOfst = tempIndirectBuff->_offset;
+ tcParamsBuff = cmdEncoder->getTempMTLBuffer(paramsSize);
mtlParmBuffOfst = tcParamsBuff->_offset;
if (pipeline->needsVertexOutputBuffer()) {
vtxOutBuff = cmdEncoder->getTempMTLBuffer(vertexCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents);
@@ -820,18 +875,22 @@
sgSize >>= 1;
tcWorkgroupSize = mvkLeastCommonMultiple(outControlPointCount, sgSize);
}
+ } else if (needsInstanceAdjustment) {
+ // In this case, we need to adjust the instance count for the views being drawn.
+ VkDeviceSize indirectSize = sizeof(MTLDrawIndexedPrimitivesIndirectArguments) * _drawCount;
+ tempIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
+ mtlIndBuff = tempIndirectBuff->_mtlBuffer;
+ mtlTempIndBuffOfst = tempIndirectBuff->_offset;
}
MVKPiplineStages stages;
pipeline->getStages(stages);
- VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
-
for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) {
for (uint32_t s : stages) {
auto stage = MVKGraphicsStage(s);
id<MTLComputeCommandEncoder> mtlTessCtlEncoder = nil;
- if (stage == kMVKGraphicsStageVertex) {
+ if (stage == kMVKGraphicsStageVertex && pipeline->isTessellationPipeline()) {
cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
// We need the indirect buffers now. This must be done before finalizing
@@ -839,13 +898,13 @@
// to do it, since it will require switching to compute anyway. Do it all
// at once to get it over with.
if (drawIdx == 0) {
- id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectConvertBuffersMTLComputePipelineState(true);
+ id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(true);
[mtlTessCtlEncoder setComputePipelineState: mtlConvertState];
[mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer
offset: _mtlIndirectBufferOffset
atIndex: 0];
- [mtlTessCtlEncoder setBuffer: tcIndirectBuff->_mtlBuffer
- offset: tcIndirectBuff->_offset
+ [mtlTessCtlEncoder setBuffer: tempIndirectBuff->_mtlBuffer
+ offset: tempIndirectBuff->_offset
atIndex: 1];
[mtlTessCtlEncoder setBuffer: tcParamsBuff->_mtlBuffer
offset: tcParamsBuff->_offset
@@ -891,10 +950,50 @@
[mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer
offset: mtlIndBuffOfst
atIndex: 2];
- [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst
+ [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
mtlIndBuffOfst += sizeof(MTLDrawIndexedPrimitivesIndirectArguments);
+ } 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
+ // have to copy the index buffer.
+ // TODO: Consider using tile shaders to avoid this cost.
+ cmdEncoder->encodeStoreActions(true);
+ id<MTLComputeCommandEncoder> mtlConvertEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseMultiviewInstanceCountAdjust);
+ id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(true);
+ uint32_t viewCount;
+ [mtlConvertEncoder setComputePipelineState: mtlConvertState];
+ [mtlConvertEncoder setBuffer: _mtlIndirectBuffer
+ offset: _mtlIndirectBufferOffset
+ atIndex: 0];
+ [mtlConvertEncoder setBuffer: tempIndirectBuff->_mtlBuffer
+ offset: tempIndirectBuff->_offset
+ atIndex: 1];
+ cmdEncoder->setComputeBytes(mtlConvertEncoder,
+ &_mtlIndirectBufferStride,
+ sizeof(_mtlIndirectBufferStride),
+ 2);
+ cmdEncoder->setComputeBytes(mtlConvertEncoder,
+ &_drawCount,
+ sizeof(_drawCount),
+ 3);
+ viewCount = cmdEncoder->getSubpass()->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex());
+ cmdEncoder->setComputeBytes(mtlConvertEncoder,
+ &viewCount,
+ sizeof(viewCount),
+ 4);
+ if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
+#if MVK_MACOS_OR_IOS
+ [mtlConvertEncoder dispatchThreads: MTLSizeMake(_drawCount, 1, 1)
+ threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)];
+#endif
+ } else {
+ [mtlConvertEncoder dispatchThreadgroups: MTLSizeMake(mvkCeilingDivide<NSUInteger>(_drawCount, mtlConvertState.threadExecutionWidth), 1, 1)
+ threadsPerThreadgroup: MTLSizeMake(mtlConvertState.threadExecutionWidth, 1, 1)];
+ }
+ // Switch back to rendering now, since we don't have compute stages to run anyway.
+ cmdEncoder->beginMetalRenderPass(true);
}
cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal
@@ -903,7 +1002,6 @@
switch (stage) {
case kMVKGraphicsStageVertex:
- cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) {
[mtlTessCtlEncoder setBuffer: vtxOutBuff->_mtlBuffer
@@ -915,14 +1013,14 @@
atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]];
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(0, 0, vertexCount, vertexCount)];
if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) {
- [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst];
- mtlTCIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments);
+ [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlTempIndBuffOfst];
+ mtlTempIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments);
}
- [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst
+ [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
- mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
+ mtlTempIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
// Mark pipeline, resources, and tess control push constants as dirty
// so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
@@ -954,10 +1052,10 @@
offset: vtxOutBuff->_offset
atIndex: kMVKTessCtlInputBufferIndex];
}
- [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst
+ [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(tcWorkgroupSize, 1, 1)];
- mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
+ mtlTempIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
// Running this stage prematurely ended the render pass, so we have to start it up again.
// TODO: On iOS, maybe we could use a tile shader to avoid this.
cmdEncoder->beginMetalRenderPass(true);
@@ -985,12 +1083,12 @@
[cmdEncoder->_mtlRenderEncoder drawPatches: outControlPointCount
patchIndexBuffer: nil
patchIndexBufferOffset: 0
- indirectBuffer: tcIndirectBuff->_mtlBuffer
- indirectBufferOffset: mtlTCIndBuffOfst];
+ indirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlTempIndBuffOfst];
#endif
}
- mtlTCIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments);
+ mtlTempIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments);
// Mark pipeline, resources, and tess control push constants as dirty
// so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
@@ -1001,9 +1099,9 @@
indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer
indexBufferOffset: ibb.offset
- indirectBuffer: _mtlIndirectBuffer
- indirectBufferOffset: mtlIndBuffOfst];
- mtlIndBuffOfst += _mtlIndirectBufferStride;
+ indirectBuffer: mtlIndBuff
+ indirectBufferOffset: mtlTempIndBuffOfst];
+ mtlTempIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) : _mtlIndirectBufferStride;
}
break;
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdQueries.mm b/MoltenVK/MoltenVK/Commands/MVKCmdQueries.mm
index f5360ac..b8de931 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdQueries.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdQueries.mm
@@ -52,7 +52,13 @@
}
void MVKCmdBeginQuery::encode(MVKCommandEncoder* cmdEncoder) {
- _queryPool->beginQuery(_query, _flags, cmdEncoder);
+ // In a multiview render pass, multiple queries are produced, one for each view.
+ // Therefore, when encoding, we must offset the query by the number of views already
+ // drawn in all previous Metal passes.
+ uint32_t query = _query;
+ if (cmdEncoder->getMultiviewPassIndex() > 0)
+ query += cmdEncoder->getSubpass()->getViewCountUpToMetalPass(cmdEncoder->getMultiviewPassIndex() - 1);
+ _queryPool->beginQuery(query, _flags, cmdEncoder);
}
@@ -60,7 +66,10 @@
#pragma mark MVKCmdEndQuery
void MVKCmdEndQuery::encode(MVKCommandEncoder* cmdEncoder) {
- _queryPool->endQuery(_query, cmdEncoder);
+ uint32_t query = _query;
+ if (cmdEncoder->getMultiviewPassIndex() > 0)
+ query += cmdEncoder->getSubpass()->getViewCountUpToMetalPass(cmdEncoder->getMultiviewPassIndex() - 1);
+ _queryPool->endQuery(query, cmdEncoder);
}
@@ -80,7 +89,10 @@
}
void MVKCmdWriteTimestamp::encode(MVKCommandEncoder* cmdEncoder) {
- cmdEncoder->markTimestamp(_queryPool, _query);
+ uint32_t query = _query;
+ if (cmdEncoder->getMultiviewPassIndex() > 0)
+ query += cmdEncoder->getSubpass()->getViewCountUpToMetalPass(cmdEncoder->getMultiviewPassIndex() - 1);
+ cmdEncoder->markTimestamp(_queryPool, query);
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
index 76573a6..1dd2ea5 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
@@ -29,6 +29,31 @@
#pragma mark -
+#pragma mark MVKCmdBeginRenderPassBase
+
+/**
+ * Abstract base class of MVKCmdBeginRenderPass.
+ * Contains all pieces that are independent of the templated portions.
+ */
+class MVKCmdBeginRenderPassBase : public MVKCommand {
+
+public:
+ VkResult setContent(MVKCommandBuffer* cmdBuff,
+ const VkRenderPassBeginInfo* pRenderPassBegin,
+ VkSubpassContents contents);
+
+ inline MVKRenderPass* getRenderPass() { return _renderPass; }
+
+protected:
+
+ MVKRenderPass* _renderPass;
+ MVKFramebuffer* _framebuffer;
+ VkRect2D _renderArea;
+ VkSubpassContents _contents;
+};
+
+
+#pragma mark -
#pragma mark MVKCmdBeginRenderPass
/**
@@ -36,12 +61,15 @@
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
-class MVKCmdBeginRenderPass : public MVKCommand {
+class MVKCmdBeginRenderPass : public MVKCmdBeginRenderPassBase {
public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents);
+ VkResult setContent(MVKCommandBuffer* cmdBuff,
+ const VkRenderPassBeginInfo* pRenderPassBegin,
+ const VkSubpassBeginInfo* pSubpassBeginInfo);
void encode(MVKCommandEncoder* cmdEncoder) override;
@@ -49,10 +77,6 @@
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
MVKSmallVector<VkClearValue, N> _clearValues;
- MVKRenderPass* _renderPass;
- MVKFramebuffer* _framebuffer;
- VkRect2D _renderArea;
- VkSubpassContents _contents;
};
// Concrete template class implementations.
@@ -70,6 +94,9 @@
public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
VkSubpassContents contents);
+ VkResult setContent(MVKCommandBuffer* cmdBuff,
+ const VkSubpassBeginInfo* pSubpassBeginInfo,
+ const VkSubpassEndInfo* pSubpassEndInfo);
void encode(MVKCommandEncoder* cmdEncoder) override;
@@ -88,6 +115,8 @@
public:
VkResult setContent(MVKCommandBuffer* cmdBuff);
+ VkResult setContent(MVKCommandBuffer* cmdBuff,
+ const VkSubpassEndInfo* pSubpassEndInfo);
void encode(MVKCommandEncoder* cmdEncoder) override;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
index a0666c6..2e1e5ad 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
@@ -26,16 +26,28 @@
#pragma mark -
+#pragma mark MVKCmdBeginRenderPassBase
+
+VkResult MVKCmdBeginRenderPassBase::setContent(MVKCommandBuffer* cmdBuff,
+ const VkRenderPassBeginInfo* pRenderPassBegin,
+ VkSubpassContents contents) {
+ _contents = contents;
+ _renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass;
+ _framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
+ _renderArea = pRenderPassBegin->renderArea;
+
+ return VK_SUCCESS;
+}
+
+
+#pragma mark -
#pragma mark MVKCmdBeginRenderPass
template <size_t N>
VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents) {
- _contents = contents;
- _renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass;
- _framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
- _renderArea = pRenderPassBegin->renderArea;
+ MVKCmdBeginRenderPassBase::setContent(cmdBuff, pRenderPassBegin, contents);
// Add clear values
uint32_t cvCnt = pRenderPassBegin->clearValueCount;
@@ -49,9 +61,16 @@
}
template <size_t N>
+VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
+ const VkRenderPassBeginInfo* pRenderPassBegin,
+ const VkSubpassBeginInfo* pSubpassBeginInfo) {
+ return setContent(cmdBuff, pRenderPassBegin, pSubpassBeginInfo->contents);
+}
+
+template <size_t N>
void MVKCmdBeginRenderPass<N>::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
- cmdEncoder->beginRenderpass(_contents, _renderPass, _framebuffer, _renderArea, _clearValues.contents());
+ cmdEncoder->beginRenderpass(this, _contents, _renderPass, _framebuffer, _renderArea, _clearValues.contents());
}
template class MVKCmdBeginRenderPass<1>;
@@ -69,8 +88,17 @@
return VK_SUCCESS;
}
+VkResult MVKCmdNextSubpass::setContent(MVKCommandBuffer* cmdBuff,
+ const VkSubpassBeginInfo* pBeginSubpassInfo,
+ const VkSubpassEndInfo* pEndSubpassInfo) {
+ return setContent(cmdBuff, pBeginSubpassInfo->contents);
+}
+
void MVKCmdNextSubpass::encode(MVKCommandEncoder* cmdEncoder) {
- cmdEncoder->beginNextSubpass(_contents);
+ if (cmdEncoder->getMultiviewPassIndex() + 1 < cmdEncoder->getSubpass()->getMultiviewMetalPassCount())
+ cmdEncoder->beginNextMultiviewPass();
+ else
+ cmdEncoder->beginNextSubpass(this, _contents);
}
@@ -81,9 +109,17 @@
return VK_SUCCESS;
}
+VkResult MVKCmdEndRenderPass::setContent(MVKCommandBuffer* cmdBuff,
+ const VkSubpassEndInfo* pEndSubpassInfo) {
+ return VK_SUCCESS;
+}
+
void MVKCmdEndRenderPass::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdEndRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
- cmdEncoder->endRenderpass();
+ if (cmdEncoder->getMultiviewPassIndex() + 1 < cmdEncoder->getSubpass()->getMultiviewMetalPassCount())
+ cmdEncoder->beginNextMultiviewPass();
+ else
+ cmdEncoder->endRenderpass();
}
@@ -100,6 +136,7 @@
for (uint32_t cbIdx = 0; cbIdx < commandBuffersCount; cbIdx++) {
_secondaryCommandBuffers.push_back(MVKCommandBuffer::getMVKCommandBuffer(pCommandBuffers[cbIdx]));
}
+ cmdBuff->recordExecuteCommands(_secondaryCommandBuffers.contents());
return VK_SUCCESS;
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
index 7e9d911..4bc8b11 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
@@ -254,10 +254,12 @@
void encode(MVKCommandEncoder* cmdEncoder) override;
protected:
- uint32_t getVertexCount();
- void populateVertices(simd::float4* vertices, float attWidth, float attHeight);
- uint32_t populateVertices(simd::float4* vertices, uint32_t startVertex,
- VkClearRect& clearRect, float attWidth, float attHeight);
+ uint32_t getVertexCount(MVKCommandEncoder* cmdEncoder);
+ void populateVertices(MVKCommandEncoder* cmdEncoder, simd::float4* vertices,
+ float attWidth, float attHeight);
+ uint32_t populateVertices(MVKCommandEncoder* cmdEncoder, simd::float4* vertices,
+ uint32_t startVertex, VkClearRect& clearRect,
+ float attWidth, float attHeight);
virtual VkClearValue& getClearValue(uint32_t attIdx) = 0;
virtual void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) = 0;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index 84d56bc..f494748 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -124,11 +124,18 @@
// Extent is provided in source texels. If the source is compressed but the
// destination is not, each destination pixel will consume an entire source block,
// so we must downscale the destination extent by the size of the source block.
+ // Likewise if the destination is compressed and source is not, each source pixel
+ // will map to a block of pixels in the destination texture, and we need to
+ // adjust destination's extent accordingly.
VkExtent3D dstExtent = vkIC.extent;
if (isSrcCompressed && !isDstCompressed) {
VkExtent2D srcBlockExtent = pixFmts->getBlockTexelSize(srcMTLPixFmt);
dstExtent.width /= srcBlockExtent.width;
dstExtent.height /= srcBlockExtent.height;
+ } else if (!isSrcCompressed && isDstCompressed) {
+ VkExtent2D dstBlockExtent = pixFmts->getBlockTexelSize(dstMTLPixFmt);
+ dstExtent.width *= dstBlockExtent.width;
+ dstExtent.height *= dstBlockExtent.height;
}
auto& dstCpy = vkDstCopies[copyIdx];
dstCpy.bufferOffset = tmpBuffSize;
@@ -948,27 +955,34 @@
// Returns the total number of vertices needed to clear all layers of all rectangles.
template <size_t N>
-uint32_t MVKCmdClearAttachments<N>::getVertexCount() {
+uint32_t MVKCmdClearAttachments<N>::getVertexCount(MVKCommandEncoder* cmdEncoder) {
uint32_t vtxCnt = 0;
- for (auto& rect : _clearRects) {
- vtxCnt += 6 * rect.layerCount;
+ if (cmdEncoder->getSubpass()->isMultiview()) {
+ // In this case, all the layer counts will be one. We want to use the number of views in the current multiview pass.
+ vtxCnt = (uint32_t)_clearRects.size() * cmdEncoder->getSubpass()->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) * 6;
+ } else {
+ for (auto& rect : _clearRects) {
+ vtxCnt += 6 * rect.layerCount;
+ }
}
return vtxCnt;
}
// Populates the vertices for all clear rectangles within an attachment of the specified size.
template <size_t N>
-void MVKCmdClearAttachments<N>::populateVertices(simd::float4* vertices, float attWidth, float attHeight) {
+void MVKCmdClearAttachments<N>::populateVertices(MVKCommandEncoder* cmdEncoder, simd::float4* vertices,
+ float attWidth, float attHeight) {
uint32_t vtxIdx = 0;
for (auto& rect : _clearRects) {
- vtxIdx = populateVertices(vertices, vtxIdx, rect, attWidth, attHeight);
+ vtxIdx = populateVertices(cmdEncoder, vertices, vtxIdx, rect, attWidth, attHeight);
}
}
// Populates the vertices, starting at the vertex, from the specified rectangle within
// an attachment of the specified size. Returns the next vertex that needs to be populated.
template <size_t N>
-uint32_t MVKCmdClearAttachments<N>::populateVertices(simd::float4* vertices,
+uint32_t MVKCmdClearAttachments<N>::populateVertices(MVKCommandEncoder* cmdEncoder,
+ simd::float4* vertices,
uint32_t startVertex,
VkClearRect& clearRect,
float attWidth,
@@ -990,8 +1004,17 @@
simd::float4 vtx;
uint32_t vtxIdx = startVertex;
- uint32_t startLayer = clearRect.baseArrayLayer;
- uint32_t endLayer = startLayer + clearRect.layerCount;
+ uint32_t startLayer, endLayer;
+ if (cmdEncoder->getSubpass()->isMultiview()) {
+ // In a multiview pass, the baseArrayLayer will be 0 and the layerCount will be 1.
+ // Use the view count instead. We already set the base slice properly in the
+ // MTLRenderPassDescriptor, so we don't need to offset the starting layer.
+ startLayer = 0;
+ endLayer = cmdEncoder->getSubpass()->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex());
+ } else {
+ startLayer = clearRect.baseArrayLayer;
+ endLayer = startLayer + clearRect.layerCount;
+ }
for (uint32_t layer = startLayer; layer < endLayer; layer++) {
vtx.z = 0.0;
@@ -1032,12 +1055,12 @@
template <size_t N>
void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
- uint32_t vtxCnt = getVertexCount();
+ uint32_t vtxCnt = getVertexCount(cmdEncoder);
simd::float4 vertices[vtxCnt];
simd::float4 clearColors[kMVKClearAttachmentCount];
VkExtent2D fbExtent = cmdEncoder->_framebuffer->getExtent2D();
- populateVertices(vertices, fbExtent.width, fbExtent.height);
+ populateVertices(cmdEncoder, vertices, fbExtent.width, fbExtent.height);
MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
@@ -1045,7 +1068,10 @@
// Populate the render pipeline state attachment key with info from the subpass and framebuffer.
_rpsKey.mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getSampleCount());
- if (cmdEncoder->_canUseLayeredRendering && cmdEncoder->_framebuffer->getLayerCount() > 1) { _rpsKey.enableLayeredRendering(); }
+ if (cmdEncoder->_canUseLayeredRendering &&
+ (cmdEncoder->_framebuffer->getLayerCount() > 1 || cmdEncoder->getSubpass()->isMultiview())) {
+ _rpsKey.enableLayeredRendering();
+ }
uint32_t caCnt = subpass->getColorAttachmentCount();
for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) {
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index a1957ea..9002d59 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -33,6 +33,8 @@
class MVKQueueCommandBufferSubmission;
class MVKCommandEncoder;
class MVKCommandEncodingPool;
+class MVKCmdBeginRenderPassBase;
+class MVKCmdNextSubpass;
class MVKRenderPass;
class MVKFramebuffer;
class MVKRenderSubpass;
@@ -95,6 +97,8 @@
*/
id<MTLBuffer> _initialVisibilityResultMTLBuffer;
+ /** Called when a MVKCmdExecuteCommands is added to this command buffer. */
+ void recordExecuteCommands(const MVKArrayRef<MVKCommandBuffer*> secondaryCommandBuffers);
#pragma mark Tessellation constituent command management
@@ -105,6 +109,24 @@
MVKCmdBindPipeline* _lastTessellationPipeline;
+#pragma mark Multiview render pass command management
+
+ /** Update the last recorded multiview render pass */
+ void recordBeginRenderPass(MVKCmdBeginRenderPassBase* mvkBeginRenderPass);
+
+ /** Update the last recorded multiview subpass */
+ void recordNextSubpass();
+
+ /** Forget the last recorded multiview render pass */
+ void recordEndRenderPass();
+
+ /** The most recent recorded multiview render subpass */
+ MVKRenderSubpass* _lastMultiviewSubpass;
+
+ /** Returns the currently active multiview render subpass, even for secondary command buffers */
+ MVKRenderSubpass* getLastMultiviewSubpass();
+
+
#pragma mark Construction
MVKCommandBuffer(MVKDevice* device) : MVKDeviceTrackingMixin(device) {}
@@ -249,14 +271,18 @@
void encodeSecondary(MVKCommandBuffer* secondaryCmdBuffer);
/** Begins a render pass and establishes initial draw state. */
- void beginRenderpass(VkSubpassContents subpassContents,
+ void beginRenderpass(MVKCommand* passCmd,
+ VkSubpassContents subpassContents,
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues);
/** Begins the next render subpass. */
- void beginNextSubpass(VkSubpassContents renderpassContents);
+ void beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents renderpassContents);
+
+ /** Begins the next multiview Metal render pass. */
+ void beginNextMultiviewPass();
/** Begins a Metal render pass for the current render subpass. */
void beginMetalRenderPass(bool loadOverride = false);
@@ -267,6 +293,9 @@
/** Returns the render subpass that is currently active. */
MVKRenderSubpass* getSubpass();
+ /** Returns the index of the currently active multiview subpass, or zero if the current render pass is not multiview. */
+ uint32_t getMultiviewPassIndex();
+
/** Binds a pipeline to a bind point. */
void bindPipeline(VkPipelineBindPoint pipelineBindPoint, MVKPipeline* pipeline);
@@ -428,14 +457,16 @@
protected:
void addActivatedQuery(MVKQueryPool* pQueryPool, uint32_t query);
void finishQueries();
- void setSubpass(VkSubpassContents subpassContents, uint32_t subpassIndex);
+ void setSubpass(MVKCommand* passCmd, VkSubpassContents subpassContents, uint32_t subpassIndex);
void clearRenderArea();
const MVKMTLBufferAllocation* copyToTempMTLBufferAllocation(const void* bytes, NSUInteger length);
NSString* getMTLRenderCommandEncoderName();
VkSubpassContents _subpassContents;
MVKRenderPass* _renderPass;
+ MVKCommand* _lastMultiviewPassCmd;
uint32_t _renderSubpassIndex;
+ uint32_t _multiviewPassIndex;
VkRect2D _renderArea;
MVKActivatedQueries* _pActivatedQueries;
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index ef1cf0d..24b65a4 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -26,6 +26,7 @@
#include "MVKLogging.h"
#include "MTLRenderPassDescriptor+MoltenVK.h"
#include "MVKCmdDraw.h"
+#include "MVKCmdRenderPass.h"
using namespace std;
@@ -76,6 +77,7 @@
_commandCount = 0;
_initialVisibilityResultMTLBuffer = nil; // not retained
_lastTessellationPipeline = nullptr;
+ _lastMultiviewSubpass = nullptr;
setConfigurationResult(VK_NOT_READY);
if (mvkAreAllFlagsEnabled(flags, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT)) {
@@ -193,6 +195,19 @@
reset(0);
}
+// If the initial visibility result buffer has not been set, promote the first visibility result buffer
+// found among any of the secondary command buffers, to support the case where a render pass is started in
+// the primary command buffer but the visibility query is started inside one of the secondary command buffers.
+void MVKCommandBuffer::recordExecuteCommands(const MVKArrayRef<MVKCommandBuffer*> secondaryCommandBuffers) {
+ if (_initialVisibilityResultMTLBuffer == nil) {
+ for (MVKCommandBuffer* cmdBuff : secondaryCommandBuffers) {
+ if (cmdBuff->_initialVisibilityResultMTLBuffer) {
+ _initialVisibilityResultMTLBuffer = cmdBuff->_initialVisibilityResultMTLBuffer;
+ break;
+ }
+ }
+ }
+}
#pragma mark -
#pragma mark Tessellation constituent command management
@@ -203,11 +218,40 @@
#pragma mark -
+#pragma mark Multiview render pass command management
+
+void MVKCommandBuffer::recordBeginRenderPass(MVKCmdBeginRenderPassBase* mvkBeginRenderPass) {
+ MVKRenderPass* mvkRendPass = mvkBeginRenderPass->getRenderPass();
+ _lastMultiviewSubpass = mvkRendPass->isMultiview() ? mvkRendPass->getSubpass(0) : nullptr;
+}
+
+void MVKCommandBuffer::recordNextSubpass() {
+ if (_lastMultiviewSubpass) {
+ _lastMultiviewSubpass = _lastMultiviewSubpass->getRenderPass()->getSubpass(_lastMultiviewSubpass->getSubpassIndex() + 1);
+ }
+}
+
+void MVKCommandBuffer::recordEndRenderPass() {
+ _lastMultiviewSubpass = nullptr;
+}
+
+MVKRenderSubpass* MVKCommandBuffer::getLastMultiviewSubpass() {
+ if (_doesContinueRenderPass) {
+ MVKRenderSubpass* subpass = ((MVKRenderPass*)_secondaryInheritanceInfo.renderPass)->getSubpass(_secondaryInheritanceInfo.subpass);
+ if (subpass->isMultiview()) { return subpass; }
+ }
+ return _lastMultiviewSubpass;
+}
+
+
+#pragma mark -
#pragma mark MVKCommandEncoder
void MVKCommandEncoder::encode(id<MTLCommandBuffer> mtlCmdBuff) {
+ _renderPass = nullptr;
_subpassContents = VK_SUBPASS_CONTENTS_INLINE;
_renderSubpassIndex = 0;
+ _multiviewPassIndex = 0;
_canUseLayeredRendering = false;
_mtlCmdBuffer = mtlCmdBuff; // not retained
@@ -216,8 +260,15 @@
MVKCommand* cmd = _cmdBuffer->_head;
while (cmd) {
+ uint32_t prevMVPassIdx = _multiviewPassIndex;
cmd->encode(this);
- cmd = cmd->_next;
+ if (_multiviewPassIndex > prevMVPassIdx) {
+ // This means we're in a multiview render pass, and we moved on to the
+ // next view group. Re-encode all commands in the subpass again for this group.
+ cmd = _lastMultiviewPassCmd->_next;
+ } else {
+ cmd = cmd->_next;
+ }
}
endCurrentMetalEncoding();
@@ -232,7 +283,8 @@
}
}
-void MVKCommandEncoder::beginRenderpass(VkSubpassContents subpassContents,
+void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
+ VkSubpassContents subpassContents,
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
@@ -243,19 +295,23 @@
_isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) &&
mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D()));
_clearValues.assign(clearValues.begin(), clearValues.end());
- setSubpass(subpassContents, 0);
+ setSubpass(passCmd, subpassContents, 0);
}
-void MVKCommandEncoder::beginNextSubpass(VkSubpassContents contents) {
- setSubpass(contents, _renderSubpassIndex + 1);
+void MVKCommandEncoder::beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents contents) {
+ setSubpass(subpassCmd, contents, _renderSubpassIndex + 1);
}
// Sets the current render subpass to the subpass with the specified index.
-void MVKCommandEncoder::setSubpass(VkSubpassContents subpassContents, uint32_t subpassIndex) {
+void MVKCommandEncoder::setSubpass(MVKCommand* subpassCmd,
+ VkSubpassContents subpassContents,
+ uint32_t subpassIndex) {
encodeStoreActions();
+ _lastMultiviewPassCmd = subpassCmd;
_subpassContents = subpassContents;
_renderSubpassIndex = subpassIndex;
+ _multiviewPassIndex = 0;
_canUseLayeredRendering = (_device->_pMetalFeatures->layeredRendering &&
(_device->_pMetalFeatures->multisampleLayeredRendering ||
@@ -264,20 +320,34 @@
beginMetalRenderPass();
}
+void MVKCommandEncoder::beginNextMultiviewPass() {
+ encodeStoreActions();
+ _multiviewPassIndex++;
+ beginMetalRenderPass();
+}
+
+uint32_t MVKCommandEncoder::getMultiviewPassIndex() { return _multiviewPassIndex; }
+
// Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder.
void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride) {
endCurrentMetalEncoding();
MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
- getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues.contents(), _isRenderingEntireAttachment, loadOverride);
+ getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _multiviewPassIndex, _framebuffer, _clearValues.contents(), _isRenderingEntireAttachment, loadOverride);
mtlRPDesc.visibilityResultBuffer = _occlusionQueryState.getVisibilityResultMTLBuffer();
VkExtent2D fbExtent = _framebuffer->getExtent2D();
mtlRPDesc.renderTargetWidthMVK = min(_renderArea.offset.x + _renderArea.extent.width, fbExtent.width);
mtlRPDesc.renderTargetHeightMVK = min(_renderArea.offset.y + _renderArea.extent.height, fbExtent.height);
if (_canUseLayeredRendering) {
- mtlRPDesc.renderTargetArrayLengthMVK = _framebuffer->getLayerCount();
+ if (getSubpass()->isMultiview()) {
+ // In the case of a multiview pass, the framebuffer layer count will be one.
+ // We need to use the view count for this multiview pass.
+ mtlRPDesc.renderTargetArrayLengthMVK = getSubpass()->getViewCountInMetalPass(_multiviewPassIndex);
+ } else {
+ mtlRPDesc.renderTargetArrayLengthMVK = _framebuffer->getLayerCount();
+ }
}
_mtlRenderEncoder = [_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPDesc]; // not retained
@@ -361,6 +431,10 @@
}
void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) {
+ if (stage == kMVKGraphicsStageVertex) {
+ // Must happen before switching encoders.
+ encodeStoreActions(true);
+ }
_graphicsPipelineState.encode(stage); // Must do first..it sets others
_graphicsResourcesState.encode(stage);
_viewportState.encode(stage);
@@ -386,16 +460,36 @@
if (clearAttCnt == 0) { return; }
- VkClearRect clearRect;
- clearRect.rect = _renderArea;
- clearRect.baseArrayLayer = 0;
- clearRect.layerCount = _framebuffer->getLayerCount();
+ if (!getSubpass()->isMultiview()) {
+ VkClearRect clearRect;
+ clearRect.rect = _renderArea;
+ clearRect.baseArrayLayer = 0;
+ clearRect.layerCount = _framebuffer->getLayerCount();
- // Create and execute a temporary clear attachments command.
- // To be threadsafe...do NOT acquire and return the command from the pool.
- MVKCmdClearMultiAttachments<1> cmd;
- cmd.setContent(_cmdBuffer, clearAttCnt, clearAtts.data(), 1, &clearRect);
- cmd.encode(this);
+ // Create and execute a temporary clear attachments command.
+ // To be threadsafe...do NOT acquire and return the command from the pool.
+ MVKCmdClearMultiAttachments<1> cmd;
+ cmd.setContent(_cmdBuffer, clearAttCnt, clearAtts.data(), 1, &clearRect);
+ cmd.encode(this);
+ } else {
+ // For multiview, it is possible that some attachments need different layers cleared.
+ // In that case, we'll have to clear them individually. :/
+ for (auto& clearAtt : clearAtts) {
+ MVKSmallVector<VkClearRect, 1> clearRects;
+ getSubpass()->populateMultiviewClearRects(clearRects, this, clearAtt.colorAttachment, clearAtt.aspectMask);
+ // Create and execute a temporary clear attachments command.
+ // To be threadsafe...do NOT acquire and return the command from the pool.
+ if (clearRects.size() == 1) {
+ MVKCmdClearSingleAttachment<1> cmd;
+ cmd.setContent(_cmdBuffer, 1, &clearAtt, (uint32_t)clearRects.size(), clearRects.data());
+ cmd.encode(this);
+ } else {
+ MVKCmdClearSingleAttachment<4> cmd;
+ cmd.setContent(_cmdBuffer, 1, &clearAtt, (uint32_t)clearRects.size(), clearRects.data());
+ cmd.encode(this);
+ }
+ }
+ }
}
void MVKCommandEncoder::finalizeDispatchState() {
@@ -559,7 +653,13 @@
// Marks the specified query as activated
void MVKCommandEncoder::addActivatedQuery(MVKQueryPool* pQueryPool, uint32_t query) {
if ( !_pActivatedQueries ) { _pActivatedQueries = new MVKActivatedQueries(); }
- (*_pActivatedQueries)[pQueryPool].push_back(query);
+ uint32_t endQuery = query + 1;
+ if (_renderPass && getSubpass()->isMultiview()) {
+ endQuery = query + getSubpass()->getViewCountInMetalPass(_multiviewPassIndex);
+ }
+ while (query < endQuery) {
+ (*_pActivatedQueries)[pQueryPool].push_back(query++);
+ }
}
// Register a command buffer completion handler that finishes each activated query.
@@ -653,6 +753,7 @@
case kMVKCommandUseCopyImageToBuffer: return @"vkCmdCopyImageToBuffer ComputeEncoder";
case kMVKCommandUseFillBuffer: return @"vkCmdFillBuffer 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";
default: return @"Unknown Use ComputeEncoder";
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 660c74e..0c6cd71 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -427,6 +427,7 @@
MVKMTLBufferBinding swizzleBufferBinding;
MVKMTLBufferBinding bufferSizeBufferBinding;
+ MVKMTLBufferBinding viewRangeBufferBinding;
bool areBufferBindingsDirty = false;
bool areTextureBindingsDirty = false;
@@ -446,6 +447,7 @@
areSamplerStateBindingsDirty = false;
swizzleBufferBinding.isDirty = false;
bufferSizeBufferBinding.isDirty = false;
+ viewRangeBufferBinding.isDirty = false;
needsSwizzle = false;
}
@@ -493,6 +495,11 @@
bool needTessEvalSizeBuffer,
bool needFragmentSizeBuffer);
+ /** Sets the current view range buffer state. */
+ void bindViewRangeBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needVertexViewBuffer,
+ bool needFragmentViewBuffer);
+
void encodeBindings(MVKShaderStage stage,
const char* pStageName,
bool fullImageViewSwizzle,
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index 47be2d9..450ccaf 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -557,6 +557,18 @@
_shaderStageResourceBindings[kMVKShaderStageFragment].bufferSizeBufferBinding.isDirty = needFragmentSizeBuffer;
}
+void MVKGraphicsResourcesCommandEncoderState::bindViewRangeBuffer(const MVKShaderImplicitRezBinding& binding,
+ bool needVertexViewBuffer,
+ bool needFragmentViewBuffer) {
+ for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+ _shaderStageResourceBindings[i].viewRangeBufferBinding.index = binding.stages[i];
+ }
+ _shaderStageResourceBindings[kMVKShaderStageVertex].viewRangeBufferBinding.isDirty = needVertexViewBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageTessCtl].viewRangeBufferBinding.isDirty = false;
+ _shaderStageResourceBindings[kMVKShaderStageTessEval].viewRangeBufferBinding.isDirty = false;
+ _shaderStageResourceBindings[kMVKShaderStageFragment].viewRangeBufferBinding.isDirty = needFragmentViewBuffer;
+}
+
void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stage,
const char* pStageName,
bool fullImageViewSwizzle,
@@ -587,6 +599,13 @@
bindImplicitBuffer(_cmdEncoder, shaderStage.bufferSizeBufferBinding, shaderStage.bufferSizes.contents());
}
+ if (shaderStage.viewRangeBufferBinding.isDirty) {
+ MVKSmallVector<uint32_t, 2> viewRange;
+ viewRange.push_back(_cmdEncoder->getSubpass()->getFirstViewIndexInMetalPass(_cmdEncoder->getMultiviewPassIndex()));
+ viewRange.push_back(_cmdEncoder->getSubpass()->getViewCountInMetalPass(_cmdEncoder->getMultiviewPassIndex()));
+ bindImplicitBuffer(_cmdEncoder, shaderStage.viewRangeBufferBinding, viewRange.contents());
+ }
+
encodeBinding<MVKMTLTextureBinding>(shaderStage.textureBindings, shaderStage.areTextureBindingsDirty, bindTexture);
encodeBinding<MVKMTLSamplerStateBinding>(shaderStage.samplerStateBindings, shaderStage.areSamplerStateBindingsDirty, bindSampler);
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
index fc17e59..52e4704 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.h
@@ -112,8 +112,11 @@
/** Returns a MTLComputePipelineState for decompressing a buffer into a 3D image. */
id<MTLComputePipelineState> getCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needsTempBuff);
+ /** Returns a MTLComputePipelineState for converting an indirect buffer for use in a multiview draw. */
+ id<MTLComputePipelineState> getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed);
+
/** Returns a MTLComputePipelineState for converting an indirect buffer for use in a tessellated draw. */
- id<MTLComputePipelineState> getCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed);
+ id<MTLComputePipelineState> getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed);
/** Returns a MTLComputePipelineState for copying an index buffer for use in an indirect tessellated draw. */
id<MTLComputePipelineState> getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type);
@@ -149,7 +152,8 @@
id<MTLComputePipelineState> _mtlCopyBufferBytesComputePipelineState = nil;
id<MTLComputePipelineState> _mtlFillBufferComputePipelineState = nil;
id<MTLComputePipelineState> _mtlCopyBufferToImage3DDecompressComputePipelineState[2] = {nil, nil};
- id<MTLComputePipelineState> _mtlDrawIndirectConvertBuffersComputePipelineState[2] = {nil, nil};
+ id<MTLComputePipelineState> _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[2] = {nil, nil};
+ id<MTLComputePipelineState> _mtlDrawIndirectTessConvertBuffersComputePipelineState[2] = {nil, nil};
id<MTLComputePipelineState> _mtlDrawIndexedCopyIndexBufferComputePipelineState[2] = {nil, nil};
id<MTLComputePipelineState> _mtlCopyQueryPoolResultsComputePipelineState = nil;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
index 19d2c90..da0e661 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncodingPool.mm
@@ -106,8 +106,12 @@
MVK_ENC_REZ_ACCESS(_mtlCopyBufferToImage3DDecompressComputePipelineState[needsTempBuff ? 1 : 0], newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(needsTempBuff, _commandPool));
}
-id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed) {
- MVK_ENC_REZ_ACCESS(_mtlDrawIndirectConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectConvertBuffersMTLComputePipelineState(indexed, _commandPool));
+id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed) {
+ MVK_ENC_REZ_ACCESS(_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(indexed, _commandPool));
+}
+
+id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed) {
+ MVK_ENC_REZ_ACCESS(_mtlDrawIndirectTessConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(indexed, _commandPool));
}
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type) {
@@ -179,10 +183,15 @@
_mtlCopyBufferToImage3DDecompressComputePipelineState[0] = nil;
_mtlCopyBufferToImage3DDecompressComputePipelineState[1] = nil;
- [_mtlDrawIndirectConvertBuffersComputePipelineState[0] release];
- [_mtlDrawIndirectConvertBuffersComputePipelineState[1] release];
- _mtlDrawIndirectConvertBuffersComputePipelineState[0] = nil;
- _mtlDrawIndirectConvertBuffersComputePipelineState[1] = nil;
+ [_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] release];
+ [_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] release];
+ _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] = nil;
+ _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] = nil;
+
+ [_mtlDrawIndirectTessConvertBuffersComputePipelineState[0] release];
+ [_mtlDrawIndirectTessConvertBuffersComputePipelineState[1] release];
+ _mtlDrawIndirectTessConvertBuffersComputePipelineState[0] = nil;
+ _mtlDrawIndirectTessConvertBuffersComputePipelineState[1] = nil;
[_mtlDrawIndexedCopyIndexBufferComputePipelineState[0] release];
[_mtlDrawIndexedCopyIndexBufferComputePipelineState[1] release];
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
index c74508f..124f6d9 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandPipelineStateFactoryShaderSource.h
@@ -170,17 +170,41 @@
}; \n\
#endif \n\
\n\
+kernel void cmdDrawIndirectMultiviewConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\
+ device MTLDrawPrimitivesIndirectArguments* destBuff [[buffer(1)]],\n\
+ constant uint32_t& srcStride [[buffer(2)]], \n\
+ constant uint32_t& drawCount [[buffer(3)]], \n\
+ constant uint32_t& viewCount [[buffer(4)]], \n\
+ uint idx [[thread_position_in_grid]]) { \n\
+ if (idx >= drawCount) { return; } \n\
+ const device auto& src = *reinterpret_cast<const device MTLDrawPrimitivesIndirectArguments*>(srcBuff + idx * srcStride);\n\
+ destBuff[idx] = src; \n\
+ destBuff[idx].instanceCount *= viewCount; \n\
+} \n\
+ \n\
+kernel void cmdDrawIndexedIndirectMultiviewConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\
+ device MTLDrawIndexedPrimitivesIndirectArguments* destBuff [[buffer(1)]],\n\
+ constant uint32_t& srcStride [[buffer(2)]], \n\
+ constant uint32_t& drawCount [[buffer(3)]], \n\
+ constant uint32_t& viewCount [[buffer(4)]], \n\
+ uint idx [[thread_position_in_grid]]) { \n\
+ if (idx >= drawCount) { return; } \n\
+ const device auto& src = *reinterpret_cast<const device MTLDrawIndexedPrimitivesIndirectArguments*>(srcBuff + idx * srcStride);\n\
+ destBuff[idx] = src; \n\
+ destBuff[idx].instanceCount *= viewCount; \n\
+} \n\
+ \n\
#if __METAL_VERSION__ >= 120 \n\
-kernel void cmdDrawIndirectConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\
- device char* destBuff [[buffer(1)]], \n\
- device char* paramsBuff [[buffer(2)]], \n\
- constant uint32_t& srcStride [[buffer(3)]], \n\
- constant uint32_t& inControlPointCount [[buffer(4)]], \n\
- constant uint32_t& outControlPointCount [[buffer(5)]], \n\
- constant uint32_t& drawCount [[buffer(6)]], \n\
- constant uint32_t& vtxThreadExecWidth [[buffer(7)]], \n\
- constant uint32_t& tcWorkgroupSize [[buffer(8)]], \n\
- uint idx [[thread_position_in_grid]]) { \n\
+kernel void cmdDrawIndirectTessConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\
+ device char* destBuff [[buffer(1)]], \n\
+ device char* paramsBuff [[buffer(2)]], \n\
+ constant uint32_t& srcStride [[buffer(3)]], \n\
+ constant uint32_t& inControlPointCount [[buffer(4)]], \n\
+ constant uint32_t& outControlPointCount [[buffer(5)]], \n\
+ constant uint32_t& drawCount [[buffer(6)]], \n\
+ constant uint32_t& vtxThreadExecWidth [[buffer(7)]], \n\
+ constant uint32_t& tcWorkgroupSize [[buffer(8)]], \n\
+ uint idx [[thread_position_in_grid]]) { \n\
if (idx >= drawCount) { return; } \n\
const device auto& src = *reinterpret_cast<const device MTLDrawPrimitivesIndirectArguments*>(srcBuff + idx * srcStride);\n\
device char* dest; \n\
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
index 213f124..7672fed 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
@@ -421,9 +421,13 @@
id<MTLComputePipelineState> newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needTempBuf,
MVKVulkanAPIDeviceObject* owner);
+ /** Returns a new MTLComputePipelineState for converting an indirect buffer for use in a multiview draw. */
+ id<MTLComputePipelineState> newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed,
+ MVKVulkanAPIDeviceObject* owner);
+
/** Returns a new MTLComputePipelineState for converting an indirect buffer for use in a tessellated draw. */
- id<MTLComputePipelineState> newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed,
- MVKVulkanAPIDeviceObject* owner);
+ id<MTLComputePipelineState> newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed,
+ MVKVulkanAPIDeviceObject* owner);
/** Returns a new MTLComputePipelineState for copying an index buffer for use in a tessellated draw. */
id<MTLComputePipelineState> newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type,
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
index a92b86e..a616a64 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.mm
@@ -417,11 +417,18 @@
: "cmdCopyBufferToImage3DDecompressDXTn", owner);
}
-id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed,
- MVKVulkanAPIDeviceObject* owner) {
+id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed,
+ MVKVulkanAPIDeviceObject* owner) {
return newMTLComputePipelineState(indexed
- ? "cmdDrawIndexedIndirectConvertBuffers"
- : "cmdDrawIndirectConvertBuffers", owner);
+ ? "cmdDrawIndexedIndirectMultiviewConvertBuffers"
+ : "cmdDrawIndirectMultiviewConvertBuffers", owner);
+}
+
+id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed,
+ MVKVulkanAPIDeviceObject* owner) {
+ return newMTLComputePipelineState(indexed
+ ? "cmdDrawIndexedIndirectTessConvertBuffers"
+ : "cmdDrawIndirectTessConvertBuffers", owner);
}
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index ed4896f..a7aa0d7 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -17,6 +17,7 @@
*/
#include "MVKDescriptorSet.h"
+#include "MVKInstance.h"
#include "MVKOSExtensions.h"
@@ -554,7 +555,8 @@
const VkDescriptorSetLayout* pSetLayouts,
VkDescriptorSet* pDescriptorSets) {
if (_allocatedSets.size() + count > _maxSets) {
- if (_device->_enabledExtensions.vk_KHR_maintenance1.enabled) {
+ if (_device->_enabledExtensions.vk_KHR_maintenance1.enabled ||
+ _device->getInstance()->getAPIVersion() >= VK_API_VERSION_1_1) {
return VK_ERROR_OUT_OF_POOL_MEMORY; // Failure is an acceptable test...don't log as error.
} else {
return reportError(VK_ERROR_INITIALIZATION_FAILED, "The maximum number of descriptor sets that can be allocated by this descriptor pool is %d.", _maxSets);
@@ -576,8 +578,9 @@
VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets) {
for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) {
MVKDescriptorSet* mvkDS = (MVKDescriptorSet*)pDescriptorSets[dsIdx];
- freeDescriptorSet(mvkDS);
- _allocatedSets.erase(mvkDS);
+ if (_allocatedSets.erase(mvkDS)) {
+ freeDescriptorSet(mvkDS);
+ }
}
return VK_SUCCESS;
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index 08718f3..23d74f5 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -137,6 +137,14 @@
void getExternalBufferProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
VkExternalBufferProperties* pExternalBufferProperties);
+ /** Populates the external fence properties supported on this device. */
+ void getExternalFenceProperties(const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+ VkExternalFenceProperties* pExternalFenceProperties);
+
+ /** Populates the external semaphore properties supported on this device. */
+ void getExternalSemaphoreProperties(const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+ VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+
#pragma mark Surfaces
/**
@@ -297,6 +305,9 @@
/** Populates the specified structure with the Metal-specific features of this device. */
inline const MVKPhysicalDeviceMetalFeatures* getMetalFeatures() { return &_metalFeatures; }
+ /** Returns whether or not vertex instancing can be used to implement multiview. */
+ inline bool canUseInstancingForMultiview() { return _metalFeatures.layeredRendering && _metalFeatures.deferredStoreActions; }
+
/** Returns the underlying Metal device. */
inline id<MTLDevice> getMTLDevice() { return _mtlDevice; }
@@ -415,6 +426,9 @@
/** Returns the queue at the specified index within the specified family. */
MVKQueue* getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex);
+ /** Returns the queue described by the specified structure. */
+ MVKQueue* getQueue(const VkDeviceQueueInfo2* queueInfo);
+
/** Retrieves the queue at the lowest queue and queue family indices used by the app. */
MVKQueue* getAnyQueue();
@@ -549,6 +563,8 @@
MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator);
+ MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo2* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator);
void destroyRenderPass(MVKRenderPass* mvkRP,
const VkAllocationCallbacks* pAllocator);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 123eb9f..5aaf418 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -91,6 +91,28 @@
f16Features->shaderInt8 = true;
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES: {
+ auto* multiviewFeatures = (VkPhysicalDeviceMultiviewFeatures*)next;
+ multiviewFeatures->multiview = true;
+ multiviewFeatures->multiviewGeometryShader = false;
+ multiviewFeatures->multiviewTessellationShader = false; // FIXME
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES: {
+ auto* protectedMemFeatures = (VkPhysicalDeviceProtectedMemoryFeatures*)next;
+ protectedMemFeatures->protectedMemory = false;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
+ auto* samplerYcbcrConvFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)next;
+ samplerYcbcrConvFeatures->samplerYcbcrConversion = true;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES: {
+ auto* shaderDrawParamsFeatures = (VkPhysicalDeviceShaderDrawParametersFeatures*)next;
+ shaderDrawParamsFeatures->shaderDrawParameters = true;
+ break;
+ }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {
auto* uboLayoutFeatures = (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR*)next;
uboLayoutFeatures->uniformBufferStandardLayout = true;
@@ -151,11 +173,6 @@
portabilityFeatures->samplerMipLodBias = false;
break;
}
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES: {
- auto* samplerYcbcrConvFeatures = (VkPhysicalDeviceSamplerYcbcrConversionFeatures*)next;
- samplerYcbcrConvFeatures->samplerYcbcrConversion = true;
- break;
- }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: {
auto* shaderIntFuncsFeatures = (VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL*)next;
shaderIntFuncsFeatures->shaderIntegerFunctions2 = true;
@@ -182,9 +199,19 @@
properties->properties = _properties;
for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) {
switch ((uint32_t)next->sType) {
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
- auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
- pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: {
+ auto* physicalDeviceDriverProps = (VkPhysicalDeviceDriverPropertiesKHR*)next;
+ strcpy(physicalDeviceDriverProps->driverName, "MoltenVK");
+ strcpy(physicalDeviceDriverProps->driverInfo, mvkGetMoltenVKVersionString(MVK_VERSION).c_str());
+ physicalDeviceDriverProps->driverID = VK_DRIVER_ID_MOLTENVK;
+ physicalDeviceDriverProps->conformanceVersion.major = 0;
+ physicalDeviceDriverProps->conformanceVersion.minor = 0;
+ physicalDeviceDriverProps->conformanceVersion.subminor = 0;
+ physicalDeviceDriverProps->conformanceVersion.patch = 0;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
+ populate((VkPhysicalDeviceIDProperties*)next);
break;
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
@@ -193,51 +220,31 @@
maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize;
break;
}
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES: {
+ auto* multiviewProps = (VkPhysicalDeviceMultiviewProperties*)next;
+ multiviewProps->maxMultiviewViewCount = 32;
+ if (canUseInstancingForMultiview()) {
+ multiviewProps->maxMultiviewInstanceIndex = std::numeric_limits<uint32_t>::max() / 32;
+ } else {
+ multiviewProps->maxMultiviewInstanceIndex = std::numeric_limits<uint32_t>::max();
+ }
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: {
+ auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next;
+ pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES: {
+ auto* protectedMemProps = (VkPhysicalDeviceProtectedMemoryProperties*)next;
+ protectedMemProps->protectedNoFault = false;
+ break;
+ }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
break;
}
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: {
- auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next;
- // This isn't implemented yet, but when it is, I expect that we'll wind up
- // doing it manually.
- robustness2Props->robustStorageBufferAccessSizeAlignment = 1;
- robustness2Props->robustUniformBufferAccessSizeAlignment = 1;
- break;
- }
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: {
- auto* texelBuffAlignProps = (VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT*)next;
- // Save the 'next' pointer; we'll unintentionally overwrite it
- // on the next line. Put it back when we're done.
- void* savedNext = texelBuffAlignProps->pNext;
- *texelBuffAlignProps = _texelBuffAlignProperties;
- texelBuffAlignProps->pNext = savedNext;
- break;
- }
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
- auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
- divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
- break;
- }
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: {
- populate((VkPhysicalDeviceIDProperties*)next);
- break;
- }
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
- auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
- portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
- break;
- }
- 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;
- break;
- }
#if MVK_MACOS
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES:
if (mvkOSVersionIsAtLeast(10.14)) {
@@ -260,15 +267,40 @@
}
break;
#endif
- case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: {
- auto* physicalDeviceDriverProps = (VkPhysicalDeviceDriverPropertiesKHR*)next;
- strcpy(physicalDeviceDriverProps->driverName, "MoltenVK");
- strcpy(physicalDeviceDriverProps->driverInfo, mvkGetMoltenVKVersionString(MVK_VERSION).c_str());
- physicalDeviceDriverProps->driverID = VK_DRIVER_ID_MOLTENVK;
- physicalDeviceDriverProps->conformanceVersion.major = 0;
- physicalDeviceDriverProps->conformanceVersion.minor = 0;
- physicalDeviceDriverProps->conformanceVersion.subminor = 0;
- physicalDeviceDriverProps->conformanceVersion.patch = 0;
+ 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;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_EXT: {
+ auto* robustness2Props = (VkPhysicalDeviceRobustness2PropertiesEXT*)next;
+ // This isn't implemented yet, but when it is, I expect that we'll wind up
+ // doing it manually.
+ robustness2Props->robustStorageBufferAccessSizeAlignment = 1;
+ robustness2Props->robustUniformBufferAccessSizeAlignment = 1;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT: {
+ auto* texelBuffAlignProps = (VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT*)next;
+ // Save the 'next' pointer; we'll unintentionally overwrite it
+ // on the next line. Put it back when we're done.
+ void* savedNext = texelBuffAlignProps->pNext;
+ *texelBuffAlignProps = _texelBuffAlignProperties;
+ texelBuffAlignProps->pNext = savedNext;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT: {
+ auto* divisorProps = (VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT*)next;
+ divisorProps->maxVertexAttribDivisor = kMVKUndefinedLargeUInt32;
+ break;
+ }
+ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_EXTX: {
+ auto* portabilityProps = (VkPhysicalDevicePortabilitySubsetPropertiesEXTX*)next;
+ portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment;
break;
}
default:
@@ -577,6 +609,24 @@
}
}
+static const VkExternalFenceProperties _emptyExtFenceProps = {VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES, nullptr, 0, 0, 0};
+
+void MVKPhysicalDevice::getExternalFenceProperties(const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+ VkExternalFenceProperties* pExternalFenceProperties) {
+ void* next = pExternalFenceProperties->pNext;
+ *pExternalFenceProperties = _emptyExtFenceProps;
+ pExternalFenceProperties->pNext = next;
+}
+
+static const VkExternalSemaphoreProperties _emptyExtSemProps = {VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES, nullptr, 0, 0, 0};
+
+void MVKPhysicalDevice::getExternalSemaphoreProperties(const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+ VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+ void* next = pExternalSemaphoreProperties->pNext;
+ *pExternalSemaphoreProperties = _emptyExtSemProps;
+ pExternalSemaphoreProperties->pNext = next;
+}
+
#pragma mark Surfaces
@@ -2335,10 +2385,11 @@
// Returns core device commands and enabled extension device commands.
PFN_vkVoidFunction MVKDevice::getProcAddr(const char* pName) {
MVKEntryPoint* pMVKPA = _physicalDevice->_mvkInstance->getEntryPoint(pName);
+ uint32_t apiVersion = _physicalDevice->_mvkInstance->_appInfo.apiVersion;
- bool isSupported = (pMVKPA && // Command exists and...
- pMVKPA->isDevice && // ...is a device command and...
- pMVKPA->isEnabled(_enabledExtensions)); // ...is a core or enabled extension command.
+ bool isSupported = (pMVKPA && // Command exists and...
+ pMVKPA->isDevice && // ...is a device command and...
+ pMVKPA->isEnabled(apiVersion, _enabledExtensions)); // ...is a core or enabled extension command.
return isSupported ? pMVKPA->functionPointer : nullptr;
}
@@ -2347,6 +2398,10 @@
return _queuesByQueueFamilyIndex[queueFamilyIndex][queueIndex];
}
+MVKQueue* MVKDevice::getQueue(const VkDeviceQueueInfo2* queueInfo) {
+ return _queuesByQueueFamilyIndex[queueInfo->queueFamilyIndex][queueInfo->queueIndex];
+}
+
MVKQueue* MVKDevice::getAnyQueue() {
for (auto& queues : _queuesByQueueFamilyIndex) {
for (MVKQueue* q : queues) {
@@ -2741,6 +2796,11 @@
return new MVKRenderPass(this, pCreateInfo);
}
+MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo2* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator) {
+ return new MVKRenderPass(this, pCreateInfo);
+}
+
void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP,
const VkAllocationCallbacks* pAllocator) {
if (mvkRP) { mvkRP->destroy(); }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
index 6195691..3ff1a95 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
@@ -37,13 +37,15 @@
/** Tracks info about entry point function pointer addresses. */
typedef struct {
PFN_vkVoidFunction functionPointer;
+ uint32_t apiVersion;
const char* ext1Name;
const char* ext2Name;
bool isDevice;
bool isCore() { return !ext1Name && !ext2Name; }
- bool isEnabled(const MVKExtensionList& extList) {
- return isCore() || extList.isEnabled(ext1Name) || extList.isEnabled(ext2Name);
+ bool isEnabled(uint32_t enabledVersion, const MVKExtensionList& extList) {
+ return (isCore() && MVK_VULKAN_API_VERSION_CONFORM(enabledVersion) >= apiVersion) ||
+ extList.isEnabled(ext1Name) || extList.isEnabled(ext2Name);
}
} MVKEntryPoint;
@@ -65,6 +67,9 @@
/** Returns a pointer to the Vulkan instance. */
MVKInstance* getInstance() override { return this; }
+ /** Returns the maximum version of Vulkan the application supports. */
+ inline uint32_t getAPIVersion() { return _appInfo.apiVersion; }
+
/** Returns a pointer to the layer manager. */
inline MVKLayerManager* getLayerManager() { return MVKLayerManager::globalManager(); }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
index 48c6c48..e8d42d6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -39,9 +39,9 @@
PFN_vkVoidFunction MVKInstance::getProcAddr(const char* pName) {
MVKEntryPoint* pMVKPA = getEntryPoint(pName);
- bool isSupported = (pMVKPA && // Command exists and...
- (pMVKPA->isDevice || // ...is a device command or...
- pMVKPA->isEnabled(_enabledExtensions))); // ...is a core or enabled extension command.
+ bool isSupported = (pMVKPA && // Command exists and...
+ (pMVKPA->isDevice || // ...is a device command or...
+ pMVKPA->isEnabled(_appInfo.apiVersion, _enabledExtensions))); // ...is a core or enabled extension command.
return isSupported ? pMVKPA->functionPointer : nullptr;
}
@@ -336,8 +336,8 @@
initDebugCallbacks(pCreateInfo); // Do before any creation activities
- _appInfo.apiVersion = MVK_VULKAN_API_VERSION; // Default
mvkSetOrClear(&_appInfo, pCreateInfo->pApplicationInfo);
+ if (_appInfo.apiVersion == 0) { _appInfo.apiVersion = VK_API_VERSION_1_0; } // Default
initProcAddrs(); // Init function pointers
initConfig();
@@ -349,18 +349,6 @@
getDriverLayer()->getSupportedInstanceExtensions()));
logVersions(); // Log the MoltenVK and Vulkan versions
- // If we only support Vulkan 1.0, we must report an error if a larger Vulkan version is requested.
- // If we support Vulkan 1.1 or better, per spec, we never report an error.
- if ((MVK_VULKAN_API_VERSION_CONFORM(MVK_VULKAN_API_VERSION) <
- MVK_VULKAN_API_VERSION_CONFORM(VK_API_VERSION_1_1)) &&
- (MVK_VULKAN_API_VERSION_CONFORM(MVK_VULKAN_API_VERSION) <
- MVK_VULKAN_API_VERSION_CONFORM(_appInfo.apiVersion))) {
- setConfigurationResult(reportError(VK_ERROR_INCOMPATIBLE_DRIVER,
- "Request for Vulkan version %s is not compatible with supported version %s.",
- mvkGetVulkanVersionString(_appInfo.apiVersion).c_str(),
- mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION).c_str()));
- }
-
// Populate the array of physical GPU devices.
// This effort creates a number of autoreleased instances of Metal
// and other Obj-C classes, so wrap it all in an autorelease pool.
@@ -403,16 +391,19 @@
}
}
-#define ADD_ENTRY_POINT(func, ext1, ext2, isDev) _entryPoints[""#func] = { (PFN_vkVoidFunction)&func, ext1, ext2, isDev }
+#define ADD_ENTRY_POINT(func, api, ext1, ext2, isDev) _entryPoints[""#func] = { (PFN_vkVoidFunction)&func, api, ext1, ext2, isDev }
-#define ADD_INST_ENTRY_POINT(func) ADD_ENTRY_POINT(func, nullptr, nullptr, false)
-#define ADD_DVC_ENTRY_POINT(func) ADD_ENTRY_POINT(func, nullptr, nullptr, true)
+#define ADD_INST_ENTRY_POINT(func) ADD_ENTRY_POINT(func, VK_API_VERSION_1_0, nullptr, nullptr, false)
+#define ADD_DVC_ENTRY_POINT(func) ADD_ENTRY_POINT(func, VK_API_VERSION_1_0, nullptr, nullptr, true)
-#define ADD_INST_EXT_ENTRY_POINT(func, EXT) ADD_ENTRY_POINT(func, VK_ ##EXT ##_EXTENSION_NAME, nullptr, false)
-#define ADD_DVC_EXT_ENTRY_POINT(func, EXT) ADD_ENTRY_POINT(func, VK_ ##EXT ##_EXTENSION_NAME, nullptr, true)
+#define ADD_INST_1_1_ENTRY_POINT(func) ADD_ENTRY_POINT(func, VK_API_VERSION_1_1, nullptr, nullptr, false)
+#define ADD_DVC_1_1_ENTRY_POINT(func) ADD_ENTRY_POINT(func, VK_API_VERSION_1_1, nullptr, nullptr, true)
-#define ADD_INST_EXT2_ENTRY_POINT(func, EXT1, EXT2) ADD_ENTRY_POINT(func, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, false)
-#define ADD_DVC_EXT2_ENTRY_POINT(func, EXT1, EXT2) ADD_ENTRY_POINT(func, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, true)
+#define ADD_INST_EXT_ENTRY_POINT(func, EXT) ADD_ENTRY_POINT(func, 0, VK_ ##EXT ##_EXTENSION_NAME, nullptr, false)
+#define ADD_DVC_EXT_ENTRY_POINT(func, EXT) ADD_ENTRY_POINT(func, 0, VK_ ##EXT ##_EXTENSION_NAME, nullptr, true)
+
+#define ADD_INST_EXT2_ENTRY_POINT(func, EXT1, EXT2) ADD_ENTRY_POINT(func, 0, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, false)
+#define ADD_DVC_EXT2_ENTRY_POINT(func, EXT1, EXT2) ADD_ENTRY_POINT(func, 0, VK_ ##EXT1 ##_EXTENSION_NAME, VK_ ##EXT2 ##_EXTENSION_NAME, true)
// Initializes the function pointer map.
void MVKInstance::initProcAddrs() {
@@ -432,6 +423,18 @@
ADD_INST_ENTRY_POINT(vkEnumerateDeviceLayerProperties);
ADD_INST_ENTRY_POINT(vkGetPhysicalDeviceSparseImageFormatProperties);
+ ADD_INST_1_1_ENTRY_POINT(vkEnumeratePhysicalDeviceGroups);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceFeatures2);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceProperties2);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceFormatProperties2);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceImageFormatProperties2);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceQueueFamilyProperties2);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceMemoryProperties2);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceSparseImageFormatProperties2);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceExternalFenceProperties);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceExternalBufferProperties);
+ ADD_INST_1_1_ENTRY_POINT(vkGetPhysicalDeviceExternalSemaphoreProperties);
+
// Device functions:
ADD_DVC_ENTRY_POINT(vkGetDeviceProcAddr);
ADD_DVC_ENTRY_POINT(vkDestroyDevice);
@@ -555,8 +558,28 @@
ADD_DVC_ENTRY_POINT(vkCmdEndRenderPass);
ADD_DVC_ENTRY_POINT(vkCmdExecuteCommands);
+ ADD_DVC_1_1_ENTRY_POINT(vkGetDeviceQueue2);
+ ADD_DVC_1_1_ENTRY_POINT(vkBindBufferMemory2);
+ ADD_DVC_1_1_ENTRY_POINT(vkBindImageMemory2);
+ ADD_DVC_1_1_ENTRY_POINT(vkGetBufferMemoryRequirements2);
+ ADD_DVC_1_1_ENTRY_POINT(vkGetImageMemoryRequirements2);
+ ADD_DVC_1_1_ENTRY_POINT(vkGetImageSparseMemoryRequirements2);
+ ADD_DVC_1_1_ENTRY_POINT(vkGetDeviceGroupPeerMemoryFeatures);
+ ADD_DVC_1_1_ENTRY_POINT(vkCreateDescriptorUpdateTemplate);
+ ADD_DVC_1_1_ENTRY_POINT(vkDestroyDescriptorUpdateTemplate);
+ ADD_DVC_1_1_ENTRY_POINT(vkUpdateDescriptorSetWithTemplate);
+ ADD_DVC_1_1_ENTRY_POINT(vkGetDescriptorSetLayoutSupport);
+ ADD_DVC_1_1_ENTRY_POINT(vkCreateSamplerYcbcrConversion);
+ ADD_DVC_1_1_ENTRY_POINT(vkDestroySamplerYcbcrConversion);
+ ADD_DVC_1_1_ENTRY_POINT(vkTrimCommandPool);
+ ADD_DVC_1_1_ENTRY_POINT(vkCmdSetDeviceMask);
+ ADD_DVC_1_1_ENTRY_POINT(vkCmdDispatchBase);
+
// Instance extension functions:
ADD_INST_EXT_ENTRY_POINT(vkEnumeratePhysicalDeviceGroupsKHR, KHR_DEVICE_GROUP_CREATION);
+ ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceExternalFencePropertiesKHR, KHR_EXTERNAL_FENCE_CAPABILITIES);
+ ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceExternalBufferPropertiesKHR, KHR_EXTERNAL_MEMORY_CAPABILITIES);
+ ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, KHR_EXTERNAL_SEMAPHORE_CAPABILITIES);
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceFeatures2KHR, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2);
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceProperties2KHR, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2);
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceFormatProperties2KHR, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2);
@@ -609,6 +632,10 @@
// Device extension functions:
ADD_DVC_EXT_ENTRY_POINT(vkBindBufferMemory2KHR, KHR_BIND_MEMORY_2);
ADD_DVC_EXT_ENTRY_POINT(vkBindImageMemory2KHR, KHR_BIND_MEMORY_2);
+ ADD_DVC_EXT_ENTRY_POINT(vkCreateRenderPass2KHR, KHR_CREATE_RENDERPASS_2);
+ ADD_DVC_EXT_ENTRY_POINT(vkCmdBeginRenderPass2KHR, KHR_CREATE_RENDERPASS_2);
+ ADD_DVC_EXT_ENTRY_POINT(vkCmdNextSubpass2KHR, KHR_CREATE_RENDERPASS_2);
+ ADD_DVC_EXT_ENTRY_POINT(vkCmdEndRenderPass2KHR, KHR_CREATE_RENDERPASS_2);
ADD_DVC_EXT_ENTRY_POINT(vkCreateDescriptorUpdateTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE);
ADD_DVC_EXT_ENTRY_POINT(vkDestroyDescriptorUpdateTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE);
ADD_DVC_EXT_ENTRY_POINT(vkUpdateDescriptorSetWithTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 37e9808..9b9b40a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -25,6 +25,7 @@
#include "MVKSmallVector.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVReflection.h>
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
+#include <unordered_map>
#include <unordered_set>
#include <ostream>
@@ -78,6 +79,9 @@
/** Returns the current buffer size buffer bindings. */
const MVKShaderImplicitRezBinding& getBufferSizeBufferIndex() { return _bufferSizeBufferIndex; }
+ /** Returns the current view range buffer binding for multiview draws. */
+ const MVKShaderImplicitRezBinding& getViewRangeBufferIndex() { return _viewRangeBufferIndex; }
+
/** Returns the current indirect parameter buffer bindings. */
const MVKShaderImplicitRezBinding& getIndirectParamsIndex() { return _indirectParamsIndex; }
@@ -113,6 +117,7 @@
MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
MVKShaderImplicitRezBinding _swizzleBufferIndex;
MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
+ MVKShaderImplicitRezBinding _viewRangeBufferIndex;
MVKShaderImplicitRezBinding _indirectParamsIndex;
MVKShaderImplicitRezBinding _outputBufferIndex;
uint32_t _tessCtlPatchOutputBufferIndex = 0;
@@ -282,6 +287,7 @@
bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& prevOutput);
template<class T>
bool addVertexInputToPipeline(T* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, const SPIRVToMSLConversionConfiguration& shaderContext);
+ void adjustVertexInputForMultiview(MTLVertexDescriptor* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, uint32_t viewCount, uint32_t oldViewCount = 1);
void addTessellationToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkPipelineTessellationStateCreateInfo* pTS);
void addFragmentOutputToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo);
bool isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo);
@@ -309,6 +315,7 @@
id<MTLComputePipelineState> _mtlTessVertexStageIndex32State = nil;
id<MTLComputePipelineState> _mtlTessControlStageState = nil;
id<MTLRenderPipelineState> _mtlPipelineState = nil;
+ std::unordered_map<uint32_t, id<MTLRenderPipelineState>> _multiviewMTLPipelineStates;
MTLCullMode _mtlCullMode;
MTLWinding _mtlFrontWinding;
MTLTriangleFillMode _mtlFillMode;
@@ -317,6 +324,7 @@
float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 };
uint32_t _outputControlPointCount;
+ MVKShaderImplicitRezBinding _viewRangeBufferIndex;
MVKShaderImplicitRezBinding _outputBufferIndex;
uint32_t _tessCtlPatchOutputBufferIndex = 0;
uint32_t _tessCtlLevelBufferIndex = 0;
@@ -325,6 +333,7 @@
bool _hasDepthStencilInfo;
bool _needsVertexSwizzleBuffer = false;
bool _needsVertexBufferSizeBuffer = false;
+ bool _needsVertexViewRangeBuffer = false;
bool _needsVertexOutputBuffer = false;
bool _needsTessCtlSwizzleBuffer = false;
bool _needsTessCtlBufferSizeBuffer = false;
@@ -335,6 +344,7 @@
bool _needsTessEvalBufferSizeBuffer = false;
bool _needsFragmentSwizzleBuffer = false;
bool _needsFragmentBufferSizeBuffer = false;
+ bool _needsFragmentViewRangeBuffer = false;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 253c9c4..ce836c1 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -149,6 +149,10 @@
_tessCtlLevelBufferIndex = _tessCtlPatchOutputBufferIndex + 1;
}
}
+ // Since we currently can't use multiview with tessellation or geometry shaders,
+ // to conserve the number of buffer bindings, use the same bindings for the
+ // view range buffer as for the indirect paramters buffer.
+ _viewRangeBufferIndex = _indirectParamsIndex;
}
MVKPipelineLayout::~MVKPipelineLayout() {
@@ -232,7 +236,11 @@
if ( !_mtlPipelineState ) { return; } // Abort if pipeline could not be created.
// Render pipeline state
- [mtlCmdEnc setRenderPipelineState: _mtlPipelineState];
+ if (cmdEncoder->getSubpass()->isMultiview() && !isTessellationPipeline() && !_multiviewMTLPipelineStates.empty()) {
+ [mtlCmdEnc setRenderPipelineState: _multiviewMTLPipelineStates[cmdEncoder->getSubpass()->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex())]];
+ } else {
+ [mtlCmdEnc setRenderPipelineState: _mtlPipelineState];
+ }
// Depth stencil state
if (_hasDepthStencilInfo) {
@@ -263,6 +271,7 @@
}
cmdEncoder->_graphicsResourcesState.bindSwizzleBuffer(_swizzleBufferIndex, _needsVertexSwizzleBuffer, _needsTessCtlSwizzleBuffer, _needsTessEvalSwizzleBuffer, _needsFragmentSwizzleBuffer);
cmdEncoder->_graphicsResourcesState.bindBufferSizeBuffer(_bufferSizeBufferIndex, _needsVertexBufferSizeBuffer, _needsTessCtlBufferSizeBuffer, _needsTessEvalBufferSizeBuffer, _needsFragmentBufferSizeBuffer);
+ cmdEncoder->_graphicsResourcesState.bindViewRangeBuffer(_viewRangeBufferIndex, _needsVertexViewRangeBuffer, _needsFragmentViewRangeBuffer);
}
bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
@@ -468,7 +477,35 @@
if (!isTessellationPipeline()) {
MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData); // temp retain
if (plDesc) {
- getOrCompilePipeline(plDesc, _mtlPipelineState);
+ MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass;
+ MVKRenderSubpass* mvkSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass);
+ if (mvkSubpass->isMultiview()) {
+ // We need to adjust the step rate for per-instance attributes to account for the
+ // extra instances needed to render all views. But, there's a problem: vertex input
+ // descriptions are static pipeline state. If we need multiple passes, and some have
+ // different numbers of views to render than others, then the step rate must be different
+ // for these passes. We'll need to make a pipeline for every pass view count we can see
+ // in the render pass. This really sucks.
+ std::unordered_set<uint32_t> viewCounts;
+ for (uint32_t passIdx = 0; passIdx < mvkSubpass->getMultiviewMetalPassCount(); ++passIdx) {
+ viewCounts.insert(mvkSubpass->getViewCountInMetalPass(passIdx));
+ }
+ auto count = viewCounts.cbegin();
+ adjustVertexInputForMultiview(plDesc.vertexDescriptor, pCreateInfo->pVertexInputState, *count);
+ getOrCompilePipeline(plDesc, _mtlPipelineState);
+ if (viewCounts.size() > 1) {
+ _multiviewMTLPipelineStates[*count] = _mtlPipelineState;
+ uint32_t oldCount = *count++;
+ for (auto last = viewCounts.cend(); count != last; ++count) {
+ if (_multiviewMTLPipelineStates.count(*count)) { continue; }
+ adjustVertexInputForMultiview(plDesc.vertexDescriptor, pCreateInfo->pVertexInputState, *count, oldCount);
+ getOrCompilePipeline(plDesc, _multiviewMTLPipelineStates[*count]);
+ oldCount = *count;
+ }
+ }
+ } else {
+ getOrCompilePipeline(plDesc, _mtlPipelineState);
+ }
}
[plDesc release]; // temp release
} else {
@@ -816,8 +853,9 @@
shaderContext.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageVertex];
shaderContext.options.mslOptions.shader_output_buffer_index = _outputBufferIndex.stages[kMVKShaderStageVertex];
shaderContext.options.mslOptions.buffer_size_buffer_index = _bufferSizeBufferIndex.stages[kMVKShaderStageVertex];
- shaderContext.options.mslOptions.capture_output_to_buffer = isTessellationPipeline();
- shaderContext.options.mslOptions.disable_rasterization = isTessellationPipeline() || (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable));
+ shaderContext.options.mslOptions.view_mask_buffer_index = _viewRangeBufferIndex.stages[kMVKShaderStageVertex];
+ shaderContext.options.mslOptions.capture_output_to_buffer = false;
+ shaderContext.options.mslOptions.disable_rasterization = pCreateInfo->pRasterizationState && pCreateInfo->pRasterizationState->rasterizerDiscardEnable;
addVertexInputToShaderConverterContext(shaderContext, pCreateInfo);
MVKMTLFunction func = ((MVKShaderModule*)_pVertexSS->module)->getMTLFunction(&shaderContext, _pVertexSS->pSpecializationInfo, _pipelineCache);
@@ -832,6 +870,7 @@
plDesc.rasterizationEnabled = !funcRslts.isRasterizationDisabled;
_needsVertexSwizzleBuffer = funcRslts.needsSwizzleBuffer;
_needsVertexBufferSizeBuffer = funcRslts.needsBufferSizeBuffer;
+ _needsVertexViewRangeBuffer = funcRslts.needsViewRangeBuffer;
_needsVertexOutputBuffer = funcRslts.needsOutputBuffer;
// If we need the swizzle buffer and there's no place to put it, we're in serious trouble.
@@ -849,6 +888,9 @@
if (!verifyImplicitBuffer(_needsVertexOutputBuffer, _indirectParamsIndex, kMVKShaderStageVertex, "indirect parameters", vbCnt)) {
return false;
}
+ if (!verifyImplicitBuffer(_needsVertexViewRangeBuffer, _viewRangeBufferIndex, kMVKShaderStageVertex, "view range", vbCnt)) {
+ return false;
+ }
return true;
}
@@ -1006,6 +1048,7 @@
shaderContext.options.entryPointStage = spv::ExecutionModelFragment;
shaderContext.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageFragment];
shaderContext.options.mslOptions.buffer_size_buffer_index = _bufferSizeBufferIndex.stages[kMVKShaderStageFragment];
+ shaderContext.options.mslOptions.view_mask_buffer_index = _viewRangeBufferIndex.stages[kMVKShaderStageFragment];
shaderContext.options.entryPointName = _pFragmentSS->pName;
shaderContext.options.mslOptions.capture_output_to_buffer = false;
if (pCreateInfo->pMultisampleState && pCreateInfo->pMultisampleState->pSampleMask && pCreateInfo->pMultisampleState->pSampleMask[0] != 0xffffffff) {
@@ -1024,12 +1067,16 @@
auto& funcRslts = func.shaderConversionResults;
_needsFragmentSwizzleBuffer = funcRslts.needsSwizzleBuffer;
_needsFragmentBufferSizeBuffer = funcRslts.needsBufferSizeBuffer;
+ _needsFragmentViewRangeBuffer = funcRslts.needsViewRangeBuffer;
if (!verifyImplicitBuffer(_needsFragmentSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageFragment, "swizzle", 0)) {
return false;
}
if (!verifyImplicitBuffer(_needsFragmentBufferSizeBuffer, _bufferSizeBufferIndex, kMVKShaderStageFragment, "buffer size", 0)) {
return false;
}
+ if (!verifyImplicitBuffer(_needsFragmentViewRangeBuffer, _viewRangeBufferIndex, kMVKShaderStageFragment, "view range", 0)) {
+ return false;
+ }
}
return true;
}
@@ -1182,6 +1229,24 @@
const VkPipelineVertexInputStateCreateInfo* pVI,
const SPIRVToMSLConversionConfiguration& shaderContext);
+// Adjusts step rates for per-instance vertex buffers based on the number of views to be drawn.
+void MVKGraphicsPipeline::adjustVertexInputForMultiview(MTLVertexDescriptor* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, uint32_t viewCount, uint32_t oldViewCount) {
+ uint32_t vbCnt = pVI->vertexBindingDescriptionCount;
+ const VkVertexInputBindingDescription* pVKVB = pVI->pVertexBindingDescriptions;
+ for (uint32_t i = 0; i < vbCnt; ++i, ++pVKVB) {
+ uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
+ if (inputDesc.layouts[vbIdx].stepFunction == MTLVertexStepFunctionPerInstance) {
+ inputDesc.layouts[vbIdx].stepRate = inputDesc.layouts[vbIdx].stepRate / oldViewCount * viewCount;
+ for (auto& xltdBind : _translatedVertexBindings) {
+ if (xltdBind.binding == pVKVB->binding) {
+ uint32_t vbXltdIdx = getMetalBufferIndexForVertexAttributeBinding(xltdBind.translationBinding);
+ inputDesc.layouts[vbXltdIdx].stepRate = inputDesc.layouts[vbXltdIdx].stepRate / oldViewCount * viewCount;
+ }
+ }
+ }
+ }
+}
+
// Returns a translated binding for the existing binding and translation offset, creating it if needed.
uint32_t MVKGraphicsPipeline::getTranslatedVertexBinding(uint32_t binding, uint32_t translationOffset, uint32_t maxBinding) {
// See if a translated binding already exists (for example if more than one VA needs the same translation).
@@ -1323,6 +1388,7 @@
_outputBufferIndex = layout->getOutputBufferIndex();
_tessCtlPatchOutputBufferIndex = layout->getTessCtlPatchOutputBufferIndex();
_tessCtlLevelBufferIndex = layout->getTessCtlLevelBufferIndex();
+ _viewRangeBufferIndex = layout->getViewRangeBufferIndex();
MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass;
MVKRenderSubpass* mvkRenderSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass);
@@ -1345,6 +1411,9 @@
shaderContext.options.shouldFlipVertexY = _device->_pMVKConfig->shaderConversionFlipVertexY;
shaderContext.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle;
shaderContext.options.mslOptions.tess_domain_origin_lower_left = pTessDomainOriginState && pTessDomainOriginState->domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
+ shaderContext.options.mslOptions.multiview = mvkRendPass->isMultiview();
+ shaderContext.options.mslOptions.multiview_layered_rendering = getDevice()->getPhysicalDevice()->canUseInstancingForMultiview();
+ shaderContext.options.mslOptions.view_index_from_device_index = mvkAreAllFlagsEnabled(pCreateInfo->flags, VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT);
shaderContext.options.tessPatchKind = reflectData.patchKind;
shaderContext.options.numTessControlPoints = reflectData.numControlPoints;
@@ -1481,7 +1550,7 @@
const VkComputePipelineCreateInfo* pCreateInfo) :
MVKPipeline(device, pipelineCache, (MVKPipelineLayout*)pCreateInfo->layout, parent) {
- _allowsDispatchBase = mvkAreAllFlagsEnabled(pCreateInfo->flags, VK_PIPELINE_CREATE_DISPATCH_BASE); // sic; drafters forgot the 'BIT' suffix
+ _allowsDispatchBase = mvkAreAllFlagsEnabled(pCreateInfo->flags, VK_PIPELINE_CREATE_DISPATCH_BASE_BIT);
MVKMTLFunction func = getMTLFunction(pCreateInfo);
_mtlThreadgroupSize = func.threadGroupSize;
@@ -1815,6 +1884,7 @@
opt.swizzle_texture_samples,
opt.tess_domain_origin_lower_left,
opt.multiview,
+ opt.multiview_layered_rendering,
opt.view_index_from_device_index,
opt.dispatch_base,
opt.texture_1D_as_2D,
@@ -1942,7 +2012,8 @@
scr.needsPatchOutputBuffer,
scr.needsBufferSizeBuffer,
scr.needsInputThreadgroupMem,
- scr.needsDispatchBaseBuffer);
+ scr.needsDispatchBaseBuffer,
+ scr.needsViewRangeBuffer);
}
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
index e0d89d4..68db119 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
@@ -18,6 +18,7 @@
#include "MVKQueryPool.h"
#include "MVKBuffer.h"
+#include "MVKRenderPass.h"
#include "MVKCommandBuffer.h"
#include "MVKCommandEncodingPool.h"
#include "MVKOSExtensions.h"
@@ -30,8 +31,11 @@
#pragma mark MVKQueryPool
void MVKQueryPool::endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder) {
+ uint32_t queryCount = cmdEncoder->getSubpass()->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex());
lock_guard<mutex> lock(_availabilityLock);
- _availability[query] = DeviceAvailable;
+ for (uint32_t i = query; i < query + queryCount; ++i) {
+ _availability[i] = DeviceAvailable;
+ }
lock_guard<mutex> copyLock(_deferredCopiesLock);
if (!_deferredCopies.empty()) {
// Partition by readiness.
@@ -287,7 +291,12 @@
void MVKOcclusionQueryPool::beginQueryAddedTo(uint32_t query, MVKCommandBuffer* cmdBuffer) {
NSUInteger offset = getVisibilityResultOffset(query);
- NSUInteger maxOffset = getDevice()->_pMetalFeatures->maxQueryBufferSize - kMVKQuerySlotSizeInBytes;
+ NSUInteger queryCount = 1;
+ if (cmdBuffer->getLastMultiviewSubpass()) {
+ // In multiview passes, one query is used for each view.
+ queryCount = cmdBuffer->getLastMultiviewSubpass()->getViewCount();
+ }
+ NSUInteger maxOffset = getDevice()->_pMetalFeatures->maxQueryBufferSize - kMVKQuerySlotSizeInBytes * queryCount;
if (offset > maxOffset) {
cmdBuffer->setConfigurationResult(reportError(VK_ERROR_OUT_OF_DEVICE_MEMORY, "vkCmdBeginQuery(): The query offset value %lu is larger than the maximum offset value %lu available on this device.", offset, maxOffset));
}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index a0b4bc7..f8decda 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -46,6 +46,12 @@
/** Returns the Vulkan API opaque object controlling this object. */
MVKVulkanAPIObject* getVulkanAPIObject() override;
+ /** Returns the parent render pass of this subpass. */
+ inline MVKRenderPass* getRenderPass() { return _renderPass; }
+
+ /** Returns the index of this subpass in its parent render pass. */
+ inline uint32_t getSubpassIndex() { return _subpassIndex; }
+
/** Returns the number of color attachments, which may be zero for depth-only rendering. */
inline uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); }
@@ -61,11 +67,31 @@
/** Returns the Vulkan sample count of the attachments used in this subpass. */
VkSampleCountFlagBits getSampleCount();
+ /** Returns whether or not this is a multiview subpass. */
+ bool isMultiview() const { return _viewMask != 0; }
+
+ /** Returns the total number of views to be rendered. */
+ inline uint32_t getViewCount() const { return __builtin_popcount(_viewMask); }
+
+ /** Returns the number of Metal render passes needed to render all views. */
+ uint32_t getMultiviewMetalPassCount() const;
+
+ /** Returns the first view to be rendered in the given multiview pass. */
+ uint32_t getFirstViewIndexInMetalPass(uint32_t passIdx) const;
+
+ /** Returns the number of views to be rendered in the given multiview pass. */
+ uint32_t getViewCountInMetalPass(uint32_t passIdx) const;
+
+ /** Returns the number of views to be rendered in all multiview passes up to the given one. */
+ uint32_t getViewCountUpToMetalPass(uint32_t passIdx) const;
+
/**
* Populates the specified Metal MTLRenderPassDescriptor with content from this
- * instance, the specified framebuffer, and the specified array of clear values.
+ * instance, the specified framebuffer, and the specified array of clear values
+ * for the specified multiview pass.
*/
void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
+ uint32_t passIdx,
MVKFramebuffer* framebuffer,
const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
@@ -78,26 +104,42 @@
void populateClearAttachments(MVKClearAttachments& clearAtts,
const MVKArrayRef<VkClearValue>& clearValues);
+ /**
+ * Populates the specified vector with VkClearRects for clearing views of a specified multiview
+ * attachment on first use, when the render area is smaller than the full framebuffer size
+ * and/or not all views used in this subpass need to be cleared.
+ */
+ void populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects,
+ MVKCommandEncoder* cmdEncoder,
+ uint32_t caIdx, VkImageAspectFlags aspectMask);
+
/** If a render encoder is active, sets the store actions for all attachments to it. */
void encodeStoreActions(MVKCommandEncoder* cmdEncoder, bool isRenderingEntireAttachment, bool storeOverride = false);
/** Constructs an instance for the specified parent renderpass. */
- MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription* pCreateInfo);
+ MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription* pCreateInfo,
+ const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects,
+ uint32_t viewMask);
+
+ /** Constructs an instance for the specified parent renderpass. */
+ MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription2* pCreateInfo);
private:
friend class MVKRenderPass;
friend class MVKRenderPassAttachment;
+ uint32_t getViewMaskGroupForMetalPass(uint32_t passIdx);
MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx);
MVKRenderPass* _renderPass;
uint32_t _subpassIndex;
- MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _inputAttachments;
- MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _colorAttachments;
- MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _resolveAttachments;
+ uint32_t _viewMask;
+ MVKSmallVector<VkAttachmentReference2, kMVKDefaultAttachmentCount> _inputAttachments;
+ MVKSmallVector<VkAttachmentReference2, kMVKDefaultAttachmentCount> _colorAttachments;
+ MVKSmallVector<VkAttachmentReference2, kMVKDefaultAttachmentCount> _resolveAttachments;
MVKSmallVector<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
- VkAttachmentReference _depthStencilAttachment;
+ VkAttachmentReference2 _depthStencilAttachment;
id<MTLTexture> _mtlDummyTex = nil;
};
@@ -139,6 +181,9 @@
bool isStencil,
bool storeOverride = false);
+ /** Populates the specified vector with VkClearRects for clearing views of a multiview attachment on first use. */
+ void populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects, MVKCommandEncoder* cmdEncoder);
+
/** Returns whether this attachment should be cleared in the subpass. */
bool shouldUseClearAttachment(MVKRenderSubpass* subpass);
@@ -146,18 +191,27 @@
MVKRenderPassAttachment(MVKRenderPass* renderPass,
const VkAttachmentDescription* pCreateInfo);
+ /** Constructs an instance for the specified parent renderpass. */
+ MVKRenderPassAttachment(MVKRenderPass* renderPass,
+ const VkAttachmentDescription2* pCreateInfo);
+
protected:
+ bool isFirstUseOfAttachment(MVKRenderSubpass* subpass);
+ bool isLastUseOfAttachment(MVKRenderSubpass* subpass);
MTLStoreAction getMTLStoreAction(MVKRenderSubpass* subpass,
bool isRenderingEntireAttachment,
bool hasResolveAttachment,
bool isStencil,
bool storeOverride);
+ void validateFormat();
- VkAttachmentDescription _info;
+ VkAttachmentDescription2 _info;
MVKRenderPass* _renderPass;
uint32_t _attachmentIndex;
uint32_t _firstUseSubpassIdx;
uint32_t _lastUseSubpassIdx;
+ MVKSmallVector<uint32_t> _firstUseViewMasks;
+ MVKSmallVector<uint32_t> _lastUseViewMasks;
};
@@ -181,9 +235,15 @@
/** Returns the format of the color attachment at the specified index. */
MVKRenderSubpass* getSubpass(uint32_t subpassIndex);
+ /** Returns whether or not this render pass is a multiview render pass. */
+ bool isMultiview() const;
+
/** Constructs an instance for the specified device. */
MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo* pCreateInfo);
+ /** Constructs an instance for the specified device. */
+ MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo2* pCreateInfo);
+
protected:
friend class MVKRenderSubpass;
friend class MVKRenderPassAttachment;
@@ -192,7 +252,7 @@
MVKSmallVector<MVKRenderPassAttachment> _attachments;
MVKSmallVector<MVKRenderSubpass> _subpasses;
- MVKSmallVector<VkSubpassDependency> _subpassDependencies;
+ MVKSmallVector<VkSubpassDependency2> _subpassDependencies;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 9d84d9f..c3eeb6a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -21,6 +21,7 @@
#include "MVKCommandBuffer.h"
#include "MVKFoundation.h"
#include "mvk_datatypes.hpp"
+#include <cassert>
using namespace std;
@@ -67,7 +68,109 @@
return VK_SAMPLE_COUNT_1_BIT;
}
+// Extract the first view, number of views, and the portion of the mask to be rendered from
+// the lowest clump of set bits in a view mask.
+static uint32_t getNextViewMaskGroup(uint32_t viewMask, uint32_t* startView, uint32_t* viewCount, uint32_t *groupMask = nullptr) {
+ // First, find the first set bit. This is the start of the next clump of views to be rendered.
+ // n.b. ffs(3) returns a 1-based index. This actually bit me during development of this feature.
+ int pos = ffs(viewMask) - 1;
+ int end = pos;
+ if (groupMask) { *groupMask = 0; }
+ // Now we'll step through the bits one at a time until we find a bit that isn't set.
+ // This is one past the end of the next clump. Clear the bits as we go, so we can use
+ // ffs(3) again on the next clump.
+ // TODO: Find a way to make this faster.
+ while (viewMask & (1 << end)) {
+ if (groupMask) { *groupMask |= viewMask & (1 << end); }
+ viewMask &= ~(1 << (end++));
+ }
+ if (startView) { *startView = pos; }
+ if (viewCount) { *viewCount = end - pos; }
+ return viewMask;
+}
+
+// Get the portion of the view mask that will be rendered in the specified Metal render pass.
+uint32_t MVKRenderSubpass::getViewMaskGroupForMetalPass(uint32_t passIdx) {
+ if (!_viewMask) { return 0; }
+ assert(passIdx < getMultiviewMetalPassCount());
+ if (!_renderPass->getDevice()->getPhysicalDevice()->canUseInstancingForMultiview()) {
+ return 1 << getFirstViewIndexInMetalPass(passIdx);
+ }
+ uint32_t mask = _viewMask, groupMask = 0;
+ for (uint32_t i = 0; i <= passIdx; ++i) {
+ mask = getNextViewMaskGroup(mask, nullptr, nullptr, &groupMask);
+ }
+ return groupMask;
+}
+
+uint32_t MVKRenderSubpass::getMultiviewMetalPassCount() const {
+ if (!_viewMask) { return 0; }
+ if (!_renderPass->getDevice()->getPhysicalDevice()->canUseInstancingForMultiview()) {
+ // If we can't use instanced drawing for this, we'll have to unroll the render pass.
+ return __builtin_popcount(_viewMask);
+ }
+ uint32_t mask = _viewMask;
+ uint32_t count;
+ // Step through each clump until there are no more clumps. I'll know this has
+ // happened when the mask becomes 0, since getNextViewMaskGroup() clears each group of bits
+ // as it finds them, and returns the remainder of the mask.
+ for (count = 0; mask != 0; ++count) {
+ mask = getNextViewMaskGroup(mask, nullptr, nullptr);
+ }
+ return count;
+}
+
+uint32_t MVKRenderSubpass::getFirstViewIndexInMetalPass(uint32_t passIdx) const {
+ if (!_viewMask) { return 0; }
+ assert(passIdx < getMultiviewMetalPassCount());
+ uint32_t mask = _viewMask;
+ uint32_t startView = 0, viewCount = 0;
+ if (!_renderPass->getDevice()->getPhysicalDevice()->canUseInstancingForMultiview()) {
+ for (uint32_t i = 0; mask != 0; ++i) {
+ mask = getNextViewMaskGroup(mask, &startView, &viewCount);
+ while (passIdx-- > 0 && viewCount-- > 0) {
+ startView++;
+ }
+ }
+ } else {
+ for (uint32_t i = 0; i <= passIdx; ++i) {
+ mask = getNextViewMaskGroup(mask, &startView, nullptr);
+ }
+ }
+ return startView;
+}
+
+uint32_t MVKRenderSubpass::getViewCountInMetalPass(uint32_t passIdx) const {
+ if (!_viewMask) { return 0; }
+ assert(passIdx < getMultiviewMetalPassCount());
+ if (!_renderPass->getDevice()->getPhysicalDevice()->canUseInstancingForMultiview()) {
+ return 1;
+ }
+ uint32_t mask = _viewMask;
+ uint32_t viewCount = 0;
+ for (uint32_t i = 0; i <= passIdx; ++i) {
+ mask = getNextViewMaskGroup(mask, nullptr, &viewCount);
+ }
+ return viewCount;
+}
+
+uint32_t MVKRenderSubpass::getViewCountUpToMetalPass(uint32_t passIdx) const {
+ if (!_viewMask) { return 0; }
+ if (!_renderPass->getDevice()->getPhysicalDevice()->canUseInstancingForMultiview()) {
+ return passIdx+1;
+ }
+ uint32_t mask = _viewMask;
+ uint32_t totalViewCount = 0;
+ for (uint32_t i = 0; i <= passIdx; ++i) {
+ uint32_t viewCount;
+ mask = getNextViewMaskGroup(mask, nullptr, &viewCount);
+ totalViewCount += viewCount;
+ }
+ return totalViewCount;
+}
+
void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
+ uint32_t passIdx,
MVKFramebuffer* framebuffer,
const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
@@ -89,6 +192,15 @@
bool hasResolveAttachment = (rslvRPAttIdx != VK_ATTACHMENT_UNUSED);
if (hasResolveAttachment) {
framebuffer->getAttachment(rslvRPAttIdx)->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc);
+ // In a multiview render pass, we need to override the starting layer to ensure
+ // only the enabled views are loaded.
+ if (isMultiview()) {
+ uint32_t startView = getFirstViewIndexInMetalPass(passIdx);
+ if (mtlColorAttDesc.resolveTexture.textureType == MTLTextureType3D)
+ mtlColorAttDesc.resolveDepthPlane += startView;
+ else
+ mtlColorAttDesc.resolveSlice += startView;
+ }
}
// Configure the color attachment
@@ -100,6 +212,13 @@
loadOverride)) {
mtlColorAttDesc.clearColor = pixFmts->getMTLClearColor(clearValues[clrRPAttIdx], clrMVKRPAtt->getFormat());
}
+ if (isMultiview()) {
+ uint32_t startView = getFirstViewIndexInMetalPass(passIdx);
+ if (mtlColorAttDesc.texture.textureType == MTLTextureType3D)
+ mtlColorAttDesc.depthPlane += startView;
+ else
+ mtlColorAttDesc.slice += startView;
+ }
}
}
@@ -119,6 +238,9 @@
loadOverride)) {
mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[dsRPAttIdx]);
}
+ if (isMultiview()) {
+ mtlDepthAttDesc.slice += getFirstViewIndexInMetalPass(passIdx);
+ }
}
if (pixFmts->isStencilFormat(mtlDSFormat)) {
MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment;
@@ -129,6 +251,9 @@
loadOverride)) {
mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[dsRPAttIdx]);
}
+ if (isMultiview()) {
+ mtlStencilAttDesc.slice += getFirstViewIndexInMetalPass(passIdx);
+ }
}
}
@@ -145,7 +270,10 @@
// Add a dummy attachment so this passes validation.
VkExtent2D fbExtent = framebuffer->getExtent2D();
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatR8Unorm width: fbExtent.width height: fbExtent.height mipmapped: NO];
- if (framebuffer->getLayerCount() > 1) {
+ if (isMultiview()) {
+ mtlTexDesc.textureType = MTLTextureType2DArray;
+ mtlTexDesc.arrayLength = getViewCountInMetalPass(passIdx);
+ } else if (framebuffer->getLayerCount() > 1) {
mtlTexDesc.textureType = MTLTextureType2DArray;
mtlTexDesc.arrayLength = framebuffer->getLayerCount();
}
@@ -222,6 +350,24 @@
}
}
+void MVKRenderSubpass::populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects,
+ MVKCommandEncoder* cmdEncoder,
+ uint32_t caIdx, VkImageAspectFlags aspectMask) {
+ uint32_t attIdx;
+ assert(this == cmdEncoder->getSubpass());
+ if (mvkIsAnyFlagEnabled(aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) {
+ attIdx = _depthStencilAttachment.attachment;
+ if (attIdx != VK_ATTACHMENT_UNUSED) {
+ _renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder);
+ }
+ return;
+ }
+ attIdx = _colorAttachments[caIdx].attachment;
+ if (attIdx != VK_ATTACHMENT_UNUSED) {
+ _renderPass->_attachments[attIdx].populateMultiviewClearRects(clearRects, cmdEncoder);
+ }
+}
+
// Returns the format capabilities required by this render subpass.
// It is possible for a subpass to use a single framebuffer attachment for multiple purposes.
// For example, a subpass may use a color or depth attachment as an input attachment as well.
@@ -253,9 +399,60 @@
}
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
- const VkSubpassDescription* pCreateInfo) {
+ const VkSubpassDescription* pCreateInfo,
+ const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects,
+ uint32_t viewMask) {
_renderPass = renderPass;
_subpassIndex = (uint32_t)_renderPass->_subpasses.size();
+ _viewMask = viewMask;
+
+ // Add attachments
+ _inputAttachments.reserve(pCreateInfo->inputAttachmentCount);
+ for (uint32_t i = 0; i < pCreateInfo->inputAttachmentCount; i++) {
+ const VkAttachmentReference& att = pCreateInfo->pInputAttachments[i];
+ _inputAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0});
+ }
+ if (pInputAspects && pInputAspects->aspectReferenceCount) {
+ for (uint32_t i = 0; i < pInputAspects->aspectReferenceCount; i++) {
+ const VkInputAttachmentAspectReference& aspectRef = pInputAspects->pAspectReferences[i];
+ if (aspectRef.subpass == _subpassIndex) {
+ _inputAttachments[aspectRef.inputAttachmentIndex].aspectMask = aspectRef.aspectMask;
+ }
+ }
+ }
+
+ _colorAttachments.reserve(pCreateInfo->colorAttachmentCount);
+ for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) {
+ const VkAttachmentReference& att = pCreateInfo->pColorAttachments[i];
+ _colorAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0});
+ }
+
+ if (pCreateInfo->pResolveAttachments) {
+ _resolveAttachments.reserve(pCreateInfo->colorAttachmentCount);
+ for (uint32_t i = 0; i < pCreateInfo->colorAttachmentCount; i++) {
+ const VkAttachmentReference& att = pCreateInfo->pResolveAttachments[i];
+ _resolveAttachments.push_back({VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2, nullptr, att.attachment, att.layout, 0});
+ }
+ }
+
+ if (pCreateInfo->pDepthStencilAttachment) {
+ _depthStencilAttachment.attachment = pCreateInfo->pDepthStencilAttachment->attachment;
+ _depthStencilAttachment.layout = pCreateInfo->pDepthStencilAttachment->layout;
+ } else {
+ _depthStencilAttachment.attachment = VK_ATTACHMENT_UNUSED;
+ }
+
+ _preserveAttachments.reserve(pCreateInfo->preserveAttachmentCount);
+ for (uint32_t i = 0; i < pCreateInfo->preserveAttachmentCount; i++) {
+ _preserveAttachments.push_back(pCreateInfo->pPreserveAttachments[i]);
+ }
+}
+
+MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
+ const VkSubpassDescription2* pCreateInfo) {
+ _renderPass = renderPass;
+ _subpassIndex = (uint32_t)_renderPass->_subpasses.size();
+ _viewMask = pCreateInfo->viewMask;
// Add attachments
_inputAttachments.reserve(pCreateInfo->inputAttachmentCount);
@@ -310,7 +507,7 @@
// attachment AND we're in the first subpass.
if ( loadOverride ) {
mtlAttDesc.loadAction = MTLLoadActionLoad;
- } else if ( isRenderingEntireAttachment && (subpass->_subpassIndex == _firstUseSubpassIdx) ) {
+ } else if ( isRenderingEntireAttachment && isFirstUseOfAttachment(subpass) ) {
VkAttachmentLoadOp loadOp = isStencil ? _info.stencilLoadOp : _info.loadOp;
mtlAttDesc.loadAction = mvkMTLLoadActionFromVkAttachmentLoadOp(loadOp);
willClear = (loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
@@ -338,13 +535,48 @@
bool storeOverride) {
MTLStoreAction storeAction = getMTLStoreAction(subpass, isRenderingEntireAttachment, hasResolveAttachment, isStencil, storeOverride);
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
- if (pixFmts->isDepthFormat(pixFmts->getMTLPixelFormat(_info.format)) && !isStencil) {
- [cmdEncoder->_mtlRenderEncoder setDepthStoreAction: storeAction];
- } else if (pixFmts->isStencilFormat(pixFmts->getMTLPixelFormat(_info.format)) && isStencil) {
- [cmdEncoder->_mtlRenderEncoder setStencilStoreAction: storeAction];
- } else {
- [cmdEncoder->_mtlRenderEncoder setColorStoreAction: storeAction atIndex: caIdx];
- }
+
+ MTLPixelFormat mtlFmt = pixFmts->getMTLPixelFormat(_info.format);
+ bool isDepthFormat = pixFmts->isDepthFormat(mtlFmt);
+ bool isStencilFormat = pixFmts->isStencilFormat(mtlFmt);
+ bool isColorFormat = !(isDepthFormat || isStencilFormat);
+
+ if (isColorFormat) {
+ [cmdEncoder->_mtlRenderEncoder setColorStoreAction: storeAction atIndex: caIdx];
+ } else if (isDepthFormat && !isStencil) {
+ [cmdEncoder->_mtlRenderEncoder setDepthStoreAction: storeAction];
+ } else if (isStencilFormat && isStencil) {
+ [cmdEncoder->_mtlRenderEncoder setStencilStoreAction: storeAction];
+ }
+}
+
+void MVKRenderPassAttachment::populateMultiviewClearRects(MVKSmallVector<VkClearRect, 1>& clearRects, MVKCommandEncoder* cmdEncoder) {
+ MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
+ uint32_t clearMask = subpass->getViewMaskGroupForMetalPass(cmdEncoder->getMultiviewPassIndex()) & _firstUseViewMasks[subpass->_subpassIndex];
+
+ if (!clearMask) { return; }
+ VkRect2D renderArea = cmdEncoder->clipToRenderArea({{0, 0}, {kMVKUndefinedLargeUInt32, kMVKUndefinedLargeUInt32}});
+ uint32_t startView, viewCount;
+ do {
+ clearMask = getNextViewMaskGroup(clearMask, &startView, &viewCount);
+ clearRects.push_back({renderArea, startView, viewCount});
+ } while (clearMask);
+}
+
+bool MVKRenderPassAttachment::isFirstUseOfAttachment(MVKRenderSubpass* subpass) {
+ if ( subpass->isMultiview() ) {
+ return _firstUseViewMasks[subpass->_subpassIndex] == subpass->_viewMask;
+ } else {
+ return _firstUseSubpassIdx == subpass->_subpassIndex;
+ }
+}
+
+bool MVKRenderPassAttachment::isLastUseOfAttachment(MVKRenderSubpass* subpass) {
+ if ( subpass->isMultiview() ) {
+ return _lastUseViewMasks[subpass->_subpassIndex] == subpass->_viewMask;
+ } else {
+ return _lastUseSubpassIdx == subpass->_subpassIndex;
+ }
}
MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subpass,
@@ -361,7 +593,7 @@
if ( storeOverride ) {
return hasResolveAttachment ? MTLStoreActionStoreAndMultisampleResolve : MTLStoreActionStore;
}
- if ( isRenderingEntireAttachment && (subpass->_subpassIndex == _lastUseSubpassIdx) ) {
+ if ( isRenderingEntireAttachment && isLastUseOfAttachment(subpass) ) {
VkAttachmentStoreOp storeOp = isStencil ? _info.stencilStoreOp : _info.storeOp;
return mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment);
}
@@ -371,17 +603,16 @@
bool MVKRenderPassAttachment::shouldUseClearAttachment(MVKRenderSubpass* subpass) {
// If the subpass is not the first subpass to use this attachment, don't clear this attachment
- if (subpass->_subpassIndex != _firstUseSubpassIdx) { return false; }
+ if (subpass->isMultiview()) {
+ if (_firstUseViewMasks[subpass->_subpassIndex] == 0) { return false; }
+ } else {
+ if (subpass->_subpassIndex != _firstUseSubpassIdx) { return false; }
+ }
return (_info.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
}
-MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
- const VkAttachmentDescription* pCreateInfo) {
- _info = *pCreateInfo;
- _renderPass = renderPass;
- _attachmentIndex = uint32_t(_renderPass->_attachments.size());
-
+void MVKRenderPassAttachment::validateFormat() {
// Validate pixel format is supported
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
if ( !pixFmts->isSupportedOrSubstitutable(_info.format) ) {
@@ -391,6 +622,10 @@
// Determine the indices of the first and last render subpasses to use this attachment.
_firstUseSubpassIdx = kMVKUndefinedLargeUInt32;
_lastUseSubpassIdx = 0;
+ if ( _renderPass->isMultiview() ) {
+ _firstUseViewMasks.reserve(_renderPass->_subpasses.size());
+ _lastUseViewMasks.reserve(_renderPass->_subpasses.size());
+ }
for (auto& subPass : _renderPass->_subpasses) {
// If it uses this attachment, the subpass will identify required format capabilities.
MVKMTLFmtCaps reqCaps = subPass.getRequiredFormatCapabilitiesForAttachmentAt(_attachmentIndex);
@@ -398,6 +633,13 @@
uint32_t spIdx = subPass._subpassIndex;
_firstUseSubpassIdx = min(spIdx, _firstUseSubpassIdx);
_lastUseSubpassIdx = max(spIdx, _lastUseSubpassIdx);
+ if ( subPass.isMultiview() ) {
+ uint32_t viewMask = subPass._viewMask;
+ std::for_each(_lastUseViewMasks.begin(), _lastUseViewMasks.end(), [viewMask](uint32_t& mask) { mask &= ~viewMask; });
+ _lastUseViewMasks.push_back(viewMask);
+ std::for_each(_firstUseViewMasks.begin(), _firstUseViewMasks.end(), [&viewMask](uint32_t mask) { viewMask &= ~mask; });
+ _firstUseViewMasks.push_back(viewMask);
+ }
// Validate that the attachment pixel format supports the capabilities required by the subpass.
// Use MTLPixelFormat to look up capabilities to permit Metal format substitution.
@@ -408,6 +650,32 @@
}
}
+MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
+ const VkAttachmentDescription* pCreateInfo) {
+ _info.flags = pCreateInfo->flags;
+ _info.format = pCreateInfo->format;
+ _info.samples = pCreateInfo->samples;
+ _info.loadOp = pCreateInfo->loadOp;
+ _info.storeOp = pCreateInfo->storeOp;
+ _info.stencilLoadOp = pCreateInfo->stencilLoadOp;
+ _info.stencilStoreOp = pCreateInfo->stencilStoreOp;
+ _info.initialLayout = pCreateInfo->initialLayout;
+ _info.finalLayout = pCreateInfo->finalLayout;
+ _renderPass = renderPass;
+ _attachmentIndex = uint32_t(_renderPass->_attachments.size());
+
+ validateFormat();
+}
+
+MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
+ const VkAttachmentDescription2* pCreateInfo) {
+ _info = *pCreateInfo;
+ _renderPass = renderPass;
+ _attachmentIndex = uint32_t(_renderPass->_attachments.size());
+
+ validateFormat();
+}
+
#pragma mark -
#pragma mark MVKRenderPass
@@ -416,9 +684,67 @@
MVKRenderSubpass* MVKRenderPass::getSubpass(uint32_t subpassIndex) { return &_subpasses[subpassIndex]; }
+bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); }
+
MVKRenderPass::MVKRenderPass(MVKDevice* device,
const VkRenderPassCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
+ const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspectCreateInfo = nullptr;
+ const VkRenderPassMultiviewCreateInfo* pMultiviewCreateInfo = nullptr;
+ for (auto* next = (const VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) {
+ switch (next->sType) {
+ case VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO:
+ pInputAspectCreateInfo = (const VkRenderPassInputAttachmentAspectCreateInfo*)next;
+ break;
+ case VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO:
+ pMultiviewCreateInfo = (const VkRenderPassMultiviewCreateInfo*)next;
+ break;
+ default:
+ break;
+ }
+ }
+
+ const uint32_t* viewMasks = nullptr;
+ const int32_t* viewOffsets = nullptr;
+ if (pMultiviewCreateInfo && pMultiviewCreateInfo->subpassCount) {
+ viewMasks = pMultiviewCreateInfo->pViewMasks;
+ }
+ if (pMultiviewCreateInfo && pMultiviewCreateInfo->dependencyCount) {
+ viewOffsets = pMultiviewCreateInfo->pViewOffsets;
+ }
+
+ // Add subpasses and dependencies first
+ _subpasses.reserve(pCreateInfo->subpassCount);
+ for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
+ _subpasses.emplace_back(this, &pCreateInfo->pSubpasses[i], pInputAspectCreateInfo, viewMasks ? viewMasks[i] : 0);
+ }
+ _subpassDependencies.reserve(pCreateInfo->dependencyCount);
+ for (uint32_t i = 0; i < pCreateInfo->dependencyCount; i++) {
+ VkSubpassDependency2 dependency = {
+ .sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
+ .pNext = nullptr,
+ .srcSubpass = pCreateInfo->pDependencies[i].srcSubpass,
+ .dstSubpass = pCreateInfo->pDependencies[i].dstSubpass,
+ .srcStageMask = pCreateInfo->pDependencies[i].srcStageMask,
+ .dstStageMask = pCreateInfo->pDependencies[i].dstStageMask,
+ .srcAccessMask = pCreateInfo->pDependencies[i].srcAccessMask,
+ .dstAccessMask = pCreateInfo->pDependencies[i].dstAccessMask,
+ .dependencyFlags = pCreateInfo->pDependencies[i].dependencyFlags,
+ .viewOffset = viewOffsets ? viewOffsets[i] : 0,
+ };
+ _subpassDependencies.push_back(dependency);
+ }
+
+ // Add attachments after subpasses, so each attachment can link to subpasses
+ _attachments.reserve(pCreateInfo->attachmentCount);
+ for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
+ _attachments.emplace_back(this, &pCreateInfo->pAttachments[i]);
+ }
+}
+
+MVKRenderPass::MVKRenderPass(MVKDevice* device,
+ const VkRenderPassCreateInfo2* pCreateInfo) : MVKVulkanAPIDeviceObject(device) {
+
// Add subpasses and dependencies first
_subpasses.reserve(pCreateInfo->subpassCount);
for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
index 91e5b8c..604b211 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm
@@ -239,6 +239,7 @@
for (auto& otherPair : other->_shaderLibraries) {
if ( !findShaderLibrary(&otherPair.first) ) {
_shaderLibraries.emplace_back(otherPair.first, new MVKShaderLibrary(*otherPair.second));
+ _shaderLibraries.back().second->_owner = _owner;
}
}
}
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index 9826c51..cbb1f16 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -42,13 +42,18 @@
MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE)
MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE)
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_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)
MVK_EXTENSION(KHR_driver_properties, KHR_DRIVER_PROPERTIES, DEVICE)
+MVK_EXTENSION(KHR_external_fence, KHR_EXTERNAL_FENCE, DEVICE)
+MVK_EXTENSION(KHR_external_fence_capabilities, KHR_EXTERNAL_FENCE_CAPABILITIES, INSTANCE)
MVK_EXTENSION(KHR_external_memory, KHR_EXTERNAL_MEMORY, DEVICE)
MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE)
+MVK_EXTENSION(KHR_external_semaphore, KHR_EXTERNAL_SEMAPHORE, DEVICE)
+MVK_EXTENSION(KHR_external_semaphore_capabilities, KHR_EXTERNAL_SEMAPHORE_CAPABILITIES, INSTANCE)
MVK_EXTENSION(KHR_get_memory_requirements2, KHR_GET_MEMORY_REQUIREMENTS_2, DEVICE)
MVK_EXTENSION(KHR_get_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE)
MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE)
@@ -56,6 +61,7 @@
MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE)
MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE)
MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, DEVICE)
+MVK_EXTENSION(KHR_multiview, KHR_MULTIVIEW, 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)
diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
index 2e1c982..1b93fad 100644
--- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
+++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
@@ -35,8 +35,8 @@
#endif
/** Macro to determine the Vulkan version supported by MoltenVK. */
-#define MVK_VULKAN_API_VERSION VK_MAKE_VERSION(VK_VERSION_MAJOR(VK_API_VERSION_1_0), \
- VK_VERSION_MINOR(VK_API_VERSION_1_0), \
+#define MVK_VULKAN_API_VERSION VK_MAKE_VERSION(VK_VERSION_MAJOR(VK_API_VERSION_1_1), \
+ VK_VERSION_MINOR(VK_API_VERSION_1_1), \
VK_HEADER_VERSION)
/**
diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
index b9b44c1..9748abc 100644
--- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h
+++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
@@ -86,6 +86,7 @@
kMVKCommandUseResetQueryPool, /**< vkCmdResetQueryPool. */
kMVKCommandUseDispatch, /**< vkCmdDispatch. */
kMVKCommandUseTessellationVertexTessCtl,/**< vkCmdDraw* - vertex and tessellation control stages. */
+ kMVKCommandUseMultiviewInstanceCountAdjust,/**< vkCmdDrawIndirect* - adjust instance count for multiview. */
kMVKCommandUseCopyQueryPoolResults /**< vkCmdCopyQueryPoolResults. */
} MVKCommandUse;
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index b84a88c..f0e1824 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -158,9 +158,12 @@
MVKAddCmd(baseCmdType ##Multi, vkCmdBuff, ##__VA_ARGS__); \
}
+// Define an extension call as an alias of a core call
+#define MVK_PUBLIC_CORE_ALIAS(vkf) MVK_PUBLIC_ALIAS(vkf##KHR, vkf)
+
#pragma mark -
-#pragma mark Vulkan calls
+#pragma mark Vulkan 1.0 calls
MVK_PUBLIC_SYMBOL VkResult vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
@@ -278,6 +281,8 @@
func = (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties;
} else if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) {
func = (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties;
+ } else if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) {
+ func = (PFN_vkVoidFunction)vkEnumerateInstanceVersion;
} else if (instance) {
MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
func = mvkInst->getProcAddr(pName);
@@ -1900,12 +1905,156 @@
#pragma mark -
-#pragma mark VK_KHR_bind_memory2 extension
+#pragma mark Vulkan 1.1 calls
-MVK_PUBLIC_SYMBOL VkResult vkBindBufferMemory2KHR(
+MVK_PUBLIC_SYMBOL VkResult vkEnumerateInstanceVersion(
+ uint32_t* pApiVersion) {
+
+ MVKTraceVulkanCallStart();
+ *pApiVersion = MVK_VULKAN_API_VERSION;
+ MVKTraceVulkanCallEnd();
+ return VK_SUCCESS;
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkEnumeratePhysicalDeviceGroups(
+ VkInstance instance,
+ uint32_t* pPhysicalDeviceGroupCount,
+ VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ MVKTraceVulkanCallStart();
+ MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
+ VkResult rslt = mvkInst->getPhysicalDeviceGroups(pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+ MVKTraceVulkanCallEnd();
+ return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFeatures2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceFeatures2* pFeatures) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getFeatures(pFeatures);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceProperties2* pProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getProperties(pProperties);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkFormat format,
+ VkFormatProperties2* pFormatProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getFormatProperties(format, pFormatProperties);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkGetPhysicalDeviceImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
+ VkImageFormatProperties2* pImageFormatProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ VkResult rslt = mvkPD->getImageFormatProperties(pImageFormatInfo, pImageFormatProperties);
+ MVKTraceVulkanCallEnd();
+ return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceQueueFamilyProperties2(
+ VkPhysicalDevice physicalDevice,
+ uint32_t* pQueueFamilyPropertyCount,
+ VkQueueFamilyProperties2* pQueueFamilyProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getQueueFamilyProperties(pQueueFamilyPropertyCount, pQueueFamilyProperties);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceMemoryProperties2(
+ VkPhysicalDevice physicalDevice,
+ VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getMemoryProperties(pMemoryProperties);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceSparseImageFormatProperties2(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
+ uint32_t* pPropertyCount,
+ VkSparseImageFormatProperties2* pProperties) {
+
+ MVKTraceVulkanCallStart();
+
+ // Metal does not support sparse images.
+ // Vulkan spec: "If VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given arguments,
+ // pPropertyCount will be set to zero upon return, and no data will be written to pProperties.".
+
+ *pPropertyCount = 0;
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalFenceProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
+ VkExternalFenceProperties* pExternalFenceProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getExternalFenceProperties(pExternalFenceInfo, pExternalFenceProperties);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalBufferProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
+ VkExternalBufferProperties* pExternalBufferProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getExternalBufferProperties(pExternalBufferInfo, pExternalBufferProperties);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalSemaphoreProperties(
+ VkPhysicalDevice physicalDevice,
+ const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
+ VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+
+ MVKTraceVulkanCallStart();
+ MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
+ mvkPD->getExternalSemaphoreProperties(pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetDeviceQueue2(
+ VkDevice device,
+ const VkDeviceQueueInfo2* pQueueInfo,
+ VkQueue* pQueue) {
+
+ MVKTraceVulkanCallStart();
+ MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+ *pQueue = mvkDev->getQueue(pQueueInfo)->getVkQueue();
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkBindBufferMemory2(
VkDevice device,
uint32_t bindInfoCount,
- const VkBindBufferMemoryInfoKHR* pBindInfos) {
+ const VkBindBufferMemoryInfo* pBindInfos) {
MVKTraceVulkanCallStart();
VkResult rslt = VK_SUCCESS;
@@ -1918,10 +2067,10 @@
return rslt;
}
-MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2KHR(
+MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2(
VkDevice device,
uint32_t bindInfoCount,
- const VkBindImageMemoryInfoKHR* pBindInfos) {
+ const VkBindImageMemoryInfo* pBindInfos) {
MVKTraceVulkanCallStart();
VkResult rslt = VK_SUCCESS;
@@ -1934,29 +2083,76 @@
return rslt;
}
+MVK_PUBLIC_SYMBOL void vkGetBufferMemoryRequirements2(
+ VkDevice device,
+ const VkBufferMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements) {
-#pragma mark -
-#pragma mark VK_KHR_descriptor_update_template extension
+ MVKTraceVulkanCallStart();
+ MVKBuffer* mvkBuff = (MVKBuffer*)pInfo->buffer;
+ mvkBuff->getMemoryRequirements(pInfo, pMemoryRequirements);
+ MVKTraceVulkanCallEnd();
+}
-MVK_PUBLIC_SYMBOL VkResult vkCreateDescriptorUpdateTemplateKHR(
+MVK_PUBLIC_SYMBOL void vkGetImageMemoryRequirements2(
+ VkDevice device,
+ const VkImageMemoryRequirementsInfo2* pInfo,
+ VkMemoryRequirements2* pMemoryRequirements) {
+
+ MVKTraceVulkanCallStart();
+ auto* mvkImg = (MVKImage*)pInfo->image;
+ mvkImg->getMemoryRequirements(pInfo, pMemoryRequirements);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetImageSparseMemoryRequirements2(
+ VkDevice device,
+ const VkImageSparseMemoryRequirementsInfo2* pInfo,
+ uint32_t* pSparseMemoryRequirementCount,
+ VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+
+ MVKTraceVulkanCallStart();
+
+ // Metal does not support sparse images.
+ // Vulkan spec: "If the image was not created with VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then
+ // pSparseMemoryRequirementCount will be set to zero and pSparseMemoryRequirements will not be written to.".
+
+ *pSparseMemoryRequirementCount = 0;
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkGetDeviceGroupPeerMemoryFeatures(
+ VkDevice device,
+ uint32_t heapIndex,
+ uint32_t localDeviceIndex,
+ uint32_t remoteDeviceIndex,
+ VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+
+ MVKTraceVulkanCallStart();
+ MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+ mvkDev->getPeerMemoryFeatures(heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL VkResult vkCreateDescriptorUpdateTemplate(
VkDevice device,
- const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
+ const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
- VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate) {
+ VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
MVKTraceVulkanCallStart();
MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
auto *mvkDUT = mvkDev->createDescriptorUpdateTemplate(pCreateInfo,
pAllocator);
- *pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplateKHR)mvkDUT;
+ *pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplate)mvkDUT;
VkResult rslt = mvkDUT->getConfigurationResult();
MVKTraceVulkanCallEnd();
return rslt;
}
-MVK_PUBLIC_SYMBOL void vkDestroyDescriptorUpdateTemplateKHR(
+MVK_PUBLIC_SYMBOL void vkDestroyDescriptorUpdateTemplate(
VkDevice device,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const VkAllocationCallbacks* pAllocator) {
MVKTraceVulkanCallStart();
@@ -1965,10 +2161,10 @@
MVKTraceVulkanCallEnd();
}
-MVK_PUBLIC_SYMBOL void vkUpdateDescriptorSetWithTemplateKHR(
+MVK_PUBLIC_SYMBOL void vkUpdateDescriptorSetWithTemplate(
VkDevice device,
VkDescriptorSet descriptorSet,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
+ VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const void* pData) {
MVKTraceVulkanCallStart();
@@ -1976,24 +2172,56 @@
MVKTraceVulkanCallEnd();
}
-
-#pragma mark -
-#pragma mark VK_KHR_device_group extension
-
-MVK_PUBLIC_SYMBOL void vkGetDeviceGroupPeerMemoryFeaturesKHR(
+MVK_PUBLIC_SYMBOL void vkGetDescriptorSetLayoutSupport(
VkDevice device,
- uint32_t heapIndex,
- uint32_t localDeviceIndex,
- uint32_t remoteDeviceIndex,
- VkPeerMemoryFeatureFlagsKHR* pPeerMemoryFeatures) {
+ const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
+ VkDescriptorSetLayoutSupport* pSupport) {
- MVKTraceVulkanCallStart();
- MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
- mvkDev->getPeerMemoryFeatures(heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
- MVKTraceVulkanCallEnd();
+ MVKTraceVulkanCallStart();
+ MVKDevice* mvkDevice = MVKDevice::getMVKDevice(device);
+ mvkDevice->getDescriptorSetLayoutSupport(pCreateInfo, pSupport);
+ MVKTraceVulkanCallEnd();
}
-MVK_PUBLIC_SYMBOL void vkCmdSetDeviceMaskKHR(
+MVK_PUBLIC_SYMBOL VkResult vkCreateSamplerYcbcrConversion(
+ VkDevice device,
+ const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkSamplerYcbcrConversion* pYcbcrConversion) {
+
+ MVKTraceVulkanCallStart();
+ MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+ MVKSamplerYcbcrConversion* mvkSampConv = mvkDev->createSamplerYcbcrConversion(pCreateInfo, pAllocator);
+ *pYcbcrConversion = (VkSamplerYcbcrConversion)mvkSampConv;
+ VkResult rslt = mvkSampConv->getConfigurationResult();
+ MVKTraceVulkanCallEnd();
+ return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkDestroySamplerYcbcrConversion(
+ VkDevice device,
+ VkSamplerYcbcrConversion ycbcrConversion,
+ const VkAllocationCallbacks* pAllocator) {
+
+ MVKTraceVulkanCallStart();
+ if ( !ycbcrConversion ) { return; }
+ MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+ mvkDev->destroySamplerYcbcrConversion((MVKSamplerYcbcrConversion*)ycbcrConversion, pAllocator);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkTrimCommandPool(
+ VkDevice device,
+ VkCommandPool commandPool,
+ VkCommandPoolTrimFlags flags) {
+
+ MVKTraceVulkanCallStart();
+ MVKCommandPool* mvkCmdPool = (MVKCommandPool*)commandPool;
+ mvkCmdPool->trim();
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkCmdSetDeviceMask(
VkCommandBuffer commandBuffer,
uint32_t deviceMask) {
@@ -2003,7 +2231,7 @@
MVKTraceVulkanCallEnd();
}
-MVK_PUBLIC_SYMBOL void vkCmdDispatchBaseKHR(
+MVK_PUBLIC_SYMBOL void vkCmdDispatchBase(
VkCommandBuffer commandBuffer,
uint32_t baseGroupX,
uint32_t baseGroupY,
@@ -2019,174 +2247,130 @@
#pragma mark -
+#pragma mark VK_KHR_bind_memory2 extension
+
+MVK_PUBLIC_CORE_ALIAS(vkBindBufferMemory2);
+MVK_PUBLIC_CORE_ALIAS(vkBindImageMemory2);
+
+
+#pragma mark -
+#pragma mark VK_KHR_create_renderpass2 extension
+
+MVK_PUBLIC_SYMBOL VkResult vkCreateRenderPass2KHR(
+ VkDevice device,
+ const VkRenderPassCreateInfo2* pCreateInfo,
+ const VkAllocationCallbacks* pAllocator,
+ VkRenderPass* pRenderPass) {
+
+ MVKTraceVulkanCallStart();
+ MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
+ MVKRenderPass* mvkRendPass = mvkDev->createRenderPass(pCreateInfo, pAllocator);
+ *pRenderPass = (VkRenderPass)mvkRendPass;
+ VkResult rslt = mvkRendPass->getConfigurationResult();
+ MVKTraceVulkanCallEnd();
+ return rslt;
+}
+
+MVK_PUBLIC_SYMBOL void vkCmdBeginRenderPass2KHR(
+ VkCommandBuffer commandBuffer,
+ const VkRenderPassBeginInfo* pRenderPassBegin,
+ const VkSubpassBeginInfo* pSubpassBeginInfo) {
+
+ MVKTraceVulkanCallStart();
+ MVKAddCmdFrom2Thresholds(BeginRenderPass, pRenderPassBegin->clearValueCount, 1, 2, commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkCmdNextSubpass2KHR(
+ VkCommandBuffer commandBuffer,
+ const VkSubpassBeginInfo* pSubpassBeginInfo,
+ const VkSubpassEndInfo* pSubpassEndInfo) {
+
+ MVKTraceVulkanCallStart();
+ MVKAddCmd(NextSubpass, commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+ MVKTraceVulkanCallEnd();
+}
+
+MVK_PUBLIC_SYMBOL void vkCmdEndRenderPass2KHR(
+ VkCommandBuffer commandBuffer,
+ const VkSubpassEndInfo* pSubpassEndInfo) {
+
+ MVKTraceVulkanCallStart();
+ MVKAddCmd(EndRenderPass, commandBuffer, pSubpassEndInfo);
+ MVKTraceVulkanCallEnd();
+}
+
+
+#pragma mark -
+#pragma mark VK_KHR_descriptor_update_template extension
+
+MVK_PUBLIC_CORE_ALIAS(vkCreateDescriptorUpdateTemplate);
+MVK_PUBLIC_CORE_ALIAS(vkDestroyDescriptorUpdateTemplate);
+MVK_PUBLIC_CORE_ALIAS(vkUpdateDescriptorSetWithTemplate);
+
+
+#pragma mark -
+#pragma mark VK_KHR_device_group extension
+
+MVK_PUBLIC_CORE_ALIAS(vkGetDeviceGroupPeerMemoryFeatures);
+MVK_PUBLIC_CORE_ALIAS(vkCmdSetDeviceMask);
+MVK_PUBLIC_CORE_ALIAS(vkCmdDispatchBase);
+
+
+#pragma mark -
#pragma mark VK_KHR_device_group_creation extension
-MVK_PUBLIC_SYMBOL VkResult vkEnumeratePhysicalDeviceGroupsKHR(
- VkInstance instance,
- uint32_t* pPhysicalDeviceGroupCount,
- VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties) {
- MVKTraceVulkanCallStart();
- MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
- VkResult rslt = mvkInst->getPhysicalDeviceGroups(pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
- MVKTraceVulkanCallEnd();
- return rslt;
-}
+MVK_PUBLIC_CORE_ALIAS(vkEnumeratePhysicalDeviceGroups);
+
+
+#pragma mark -
+#pragma mark VK_KHR_external_fence_capabilities extension
+
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceExternalFenceProperties);
+
+
+#pragma mark -
+#pragma mark VK_KHR_external_memory_capabilities extension
+
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceExternalBufferProperties);
+
+
+#pragma mark -
+#pragma mark VK_KHR_external_semaphore_capabilities extension
+
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceExternalSemaphoreProperties);
#pragma mark -
#pragma mark VK_KHR_get_memory_requirements2 extension
-MVK_PUBLIC_SYMBOL void vkGetBufferMemoryRequirements2KHR(
- VkDevice device,
- const VkBufferMemoryRequirementsInfo2KHR* pInfo,
- VkMemoryRequirements2KHR* pMemoryRequirements) {
-
- MVKTraceVulkanCallStart();
- MVKBuffer* mvkBuff = (MVKBuffer*)pInfo->buffer;
- mvkBuff->getMemoryRequirements(pInfo, pMemoryRequirements);
- MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetImageMemoryRequirements2KHR(
- VkDevice device,
- const VkImageMemoryRequirementsInfo2KHR* pInfo,
- VkMemoryRequirements2KHR* pMemoryRequirements) {
-
- MVKTraceVulkanCallStart();
- auto* mvkImg = (MVKImage*)pInfo->image;
- mvkImg->getMemoryRequirements(pInfo, pMemoryRequirements);
- MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetImageSparseMemoryRequirements2KHR(
- VkDevice device,
- const VkImageSparseMemoryRequirementsInfo2KHR* pInfo,
- uint32_t* pSparseMemoryRequirementCount,
- VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements) {
-
- MVKTraceVulkanCallStart();
-
- // Metal does not support sparse images.
- // Vulkan spec: "If the image was not created with VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT then
- // pSparseMemoryRequirementCount will be set to zero and pSparseMemoryRequirements will not be written to.".
-
- *pSparseMemoryRequirementCount = 0;
- MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetBufferMemoryRequirements2);
+MVK_PUBLIC_CORE_ALIAS(vkGetImageMemoryRequirements2);
+MVK_PUBLIC_CORE_ALIAS(vkGetImageSparseMemoryRequirements2);
#pragma mark -
#pragma mark VK_KHR_get_physical_device_properties2 extension
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFeatures2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceFeatures2KHR* pFeatures) {
-
- MVKTraceVulkanCallStart();
- MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- mvkPD->getFeatures(pFeatures);
- MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceProperties2KHR* pProperties) {
-
- MVKTraceVulkanCallStart();
- MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- mvkPD->getProperties(pProperties);
- MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFormatProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkFormatProperties2KHR* pFormatProperties) {
-
- MVKTraceVulkanCallStart();
- MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- mvkPD->getFormatProperties(format, pFormatProperties);
- MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL VkResult vkGetPhysicalDeviceImageFormatProperties2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo,
- VkImageFormatProperties2KHR* pImageFormatProperties) {
-
- MVKTraceVulkanCallStart();
- MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- VkResult rslt = mvkPD->getImageFormatProperties(pImageFormatInfo, pImageFormatProperties);
- MVKTraceVulkanCallEnd();
- return rslt;
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceQueueFamilyProperties2KHR(
- VkPhysicalDevice physicalDevice,
- uint32_t* pQueueFamilyPropertyCount,
- VkQueueFamilyProperties2KHR* pQueueFamilyProperties) {
-
- MVKTraceVulkanCallStart();
- MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- mvkPD->getQueueFamilyProperties(pQueueFamilyPropertyCount, pQueueFamilyProperties);
- MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceMemoryProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties) {
-
- MVKTraceVulkanCallStart();
- MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- mvkPD->getMemoryProperties(pMemoryProperties);
- MVKTraceVulkanCallEnd();
-}
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
- uint32_t* pPropertyCount,
- VkSparseImageFormatProperties2KHR* pProperties) {
-
- MVKTraceVulkanCallStart();
-
- // Metal does not support sparse images.
- // Vulkan spec: "If VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT is not supported for the given arguments,
- // pPropertyCount will be set to zero upon return, and no data will be written to pProperties.".
-
- *pPropertyCount = 0;
- MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceFeatures2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceFormatProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceImageFormatProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceQueueFamilyProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceMemoryProperties2);
+MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceSparseImageFormatProperties2);
#pragma mark -
#pragma mark VK_KHR_maintenance1 extension
-MVK_PUBLIC_SYMBOL void vkTrimCommandPoolKHR(
- VkDevice device,
- VkCommandPool commandPool,
- VkCommandPoolTrimFlagsKHR flags) {
-
- MVKTraceVulkanCallStart();
- MVKCommandPool* mvkCmdPool = (MVKCommandPool*)commandPool;
- mvkCmdPool->trim();
- MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkTrimCommandPool);
#pragma mark -
#pragma mark VK_KHR_maintenance3 extension
-MVK_PUBLIC_SYMBOL void vkGetDescriptorSetLayoutSupportKHR(
- VkDevice device,
- const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
- VkDescriptorSetLayoutSupportKHR* pSupport) {
-
- MVKTraceVulkanCallStart();
- MVKDevice* mvkDevice = MVKDevice::getMVKDevice(device);
- mvkDevice->getDescriptorSetLayoutSupport(pCreateInfo, pSupport);
- MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkGetDescriptorSetLayoutSupport);
#pragma mark -
@@ -2221,32 +2405,8 @@
#pragma mark -
#pragma mark VK_KHR_sampler_ycbcr_conversion extension
-MVK_PUBLIC_SYMBOL VkResult vkCreateSamplerYcbcrConversionKHR(
- VkDevice device,
- const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSamplerYcbcrConversion* pYcbcrConversion) {
-
- MVKTraceVulkanCallStart();
- MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
- MVKSamplerYcbcrConversion* mvkSampConv = mvkDev->createSamplerYcbcrConversion(pCreateInfo, pAllocator);
- *pYcbcrConversion = (VkSamplerYcbcrConversion)mvkSampConv;
- VkResult rslt = mvkSampConv->getConfigurationResult();
- MVKTraceVulkanCallEnd();
- return rslt;
-}
-
-MVK_PUBLIC_SYMBOL void vkDestroySamplerYcbcrConversionKHR(
- VkDevice device,
- VkSamplerYcbcrConversion ycbcrConversion,
- const VkAllocationCallbacks* pAllocator) {
-
- MVKTraceVulkanCallStart();
- if ( !ycbcrConversion ) { return; }
- MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
- mvkDev->destroySamplerYcbcrConversion((MVKSamplerYcbcrConversion*)ycbcrConversion, pAllocator);
- MVKTraceVulkanCallEnd();
-}
+MVK_PUBLIC_CORE_ALIAS(vkCreateSamplerYcbcrConversion);
+MVK_PUBLIC_CORE_ALIAS(vkDestroySamplerYcbcrConversion);
#pragma mark -
@@ -2717,21 +2877,6 @@
#pragma mark -
-#pragma mark VK_KHR_external_memory_capabilities extension
-
-MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceExternalBufferPropertiesKHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
- VkExternalBufferProperties* pExternalBufferProperties) {
-
- MVKTraceVulkanCallStart();
- MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
- mvkPD->getExternalBufferProperties(pExternalBufferInfo, pExternalBufferProperties);
- MVKTraceVulkanCallEnd();
-}
-
-
-#pragma mark -
#pragma mark VK_EXT_metal_surface extension
MVK_PUBLIC_SYMBOL VkResult vkCreateMetalSurfaceEXT(
diff --git a/MoltenVKPackaging.xcodeproj/project.pbxproj b/MoltenVKPackaging.xcodeproj/project.pbxproj
index 13028ec..541efd7 100644
--- a/MoltenVKPackaging.xcodeproj/project.pbxproj
+++ b/MoltenVKPackaging.xcodeproj/project.pbxproj
@@ -321,7 +321,7 @@
A90B2B1D1A9B6170008EE819 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1200;
+ LastUpgradeCheck = 1170;
TargetAttributes = {
A9FEADBC1F3517480010240E = {
DevelopmentTeam = VU3TCKU48B;
diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
index e47c806..b300822 100644
--- a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
+++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
index aad07d6..4069895 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
index 5aaea44..3251a53 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
index 7ab1b49..514ad1a 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050tvOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050tvOS only\051.xcscheme"
index f7fd93e..09c16ca 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050tvOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050tvOS only\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
index 27522e3..3918e2b 100644
--- a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
+++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "NO"
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
index d14283b..705bb72 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.cpp
@@ -302,6 +302,7 @@
_shaderConversionResults.needsBufferSizeBuffer = pMSLCompiler && pMSLCompiler->needs_buffer_size_buffer();
_shaderConversionResults.needsInputThreadgroupMem = pMSLCompiler && pMSLCompiler->needs_input_threadgroup_mem();
_shaderConversionResults.needsDispatchBaseBuffer = pMSLCompiler && pMSLCompiler->needs_dispatch_base_buffer();
+ _shaderConversionResults.needsViewRangeBuffer = pMSLCompiler && pMSLCompiler->needs_view_mask_buffer();
for (auto& ctxSI : context.shaderInputs) {
ctxSI.isUsedByShader = pMSLCompiler->is_msl_shader_input_used(ctxSI.shaderInput.location);
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
index 22d405b..f642644 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h
@@ -209,6 +209,7 @@
bool needsBufferSizeBuffer = false;
bool needsInputThreadgroupMem = false;
bool needsDispatchBaseBuffer = false;
+ bool needsViewRangeBuffer = false;
void reset() { *this = SPIRVToMSLConversionResults(); }
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
index d6f3bf6..f71d67e 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
@@ -512,7 +512,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1200;
+ LastUpgradeCheck = 1170;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = {
A9092A8C1A81717B00051823 = {
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
index 5be07e3..0ec7c34 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
index 9a4b0c5..b53d82d 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-tvOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-tvOS.xcscheme
index 6e6aa72..b2f6ebc 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-tvOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-tvOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
index 700af80..0b5a9f4 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
index cc11d58..d58a425 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-tvOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-tvOS.xcscheme
index 67dcdba..6f7462c 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-tvOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-tvOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
index a768ebf..dc03203 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1200"
+ LastUpgradeVersion = "1170"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/README.md b/README.md
index 04c6ccb..a546e3c 100644
--- a/README.md
+++ b/README.md
@@ -58,7 +58,7 @@
Introduction to MoltenVK
------------------------
-**MoltenVK** is a layered implementation of [*Vulkan 1.0*](https://www.khronos.org/vulkan)
+**MoltenVK** is a layered implementation of [*Vulkan 1.1*](https://www.khronos.org/vulkan)
graphics and compute functionality, that is built on Apple's [*Metal*](https://developer.apple.com/metal)
graphics and compute framework on *macOS*, *iOS*, and *tvOS*. **MoltenVK** allows you to use *Vulkan*
graphics and compute functionality to develop modern, cross-platform, high-performance graphical
@@ -76,7 +76,7 @@
The **MoltenVK** runtime package contains two products:
- **MoltenVK** is a implementation of an almost-complete subset of the
- [*Vulkan 1.0*](https://www.khronos.org/vulkan) graphics and compute API.
+ [*Vulkan 1.1*](https://www.khronos.org/vulkan) graphics and compute API.
- **MoltenVKShaderConverter** converts *SPIR-V* shader code to *Metal Shading Language (MSL)*
shader code, and converts *GLSL* shader source code to *SPIR-V* shader code and/or
@@ -272,11 +272,11 @@
**MoltenVK** and *Vulkan* Compliance
------------------------------------
-**MoltenVK** is designed to be an implementation of a *Vulkan 1.0* subset that runs on *macOS*, *iOS*,
+**MoltenVK** is designed to be an implementation of a *Vulkan 1.1* subset that runs on *macOS*, *iOS*,
and *tvOS* platforms by mapping *Vulkan* capability to native *Metal* capability.
The fundamental design and development goal of **MoltenVK** is to provide this capability in a way that
-is both maximally compliant with the *Vulkan 1.0* specification, and maximally performant.
+is both maximally compliant with the *Vulkan 1.1* specification, and maximally performant.
Such compliance and performance is inherently affected by the capability available through *Metal*, as the
native graphics driver on *macOS*, *iOS*, and *tvOS* platforms. *Vulkan* compliance may fall into one of