Merge branch 'master' of https://github.com/billhollings/MoltenVK into xcode12

This commit is contained in:
Bill Hollings 2020-09-11 14:03:03 -04:00
commit 51777ca49c
82 changed files with 1740 additions and 524 deletions

View File

@ -75,6 +75,9 @@ extern "C" {
/** Directive to identify public symbols. */ /** Directive to identify public symbols. */
#define MVK_PUBLIC_SYMBOL __attribute__((visibility("default"))) #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 #ifdef __cplusplus
} }

View File

@ -537,7 +537,11 @@
29B97313FDCFA39411CA2CEA /* Project object */ = { 29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
<<<<<<< HEAD
LastUpgradeCheck = 1200; LastUpgradeCheck = 1200;
=======
LastUpgradeCheck = 1170;
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
}; };
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "API-Samples" */; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "API-Samples" */;
compatibilityVersion = "Xcode 8.0"; compatibilityVersion = "Xcode 8.0";

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
<<<<<<< HEAD
LastUpgradeVersion = "1200" LastUpgradeVersion = "1200"
=======
LastUpgradeVersion = "1170"
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
<<<<<<< HEAD
LastUpgradeVersion = "1200" LastUpgradeVersion = "1200"
=======
LastUpgradeVersion = "1170"
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -244,7 +244,11 @@
29B97313FDCFA39411CA2CEA /* Project object */ = { 29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
<<<<<<< HEAD
LastUpgradeCheck = 1200; LastUpgradeCheck = 1200;
=======
LastUpgradeCheck = 1170;
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
}; };
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Cube" */; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Cube" */;
compatibilityVersion = "Xcode 8.0"; compatibilityVersion = "Xcode 8.0";

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
<<<<<<< HEAD
LastUpgradeVersion = "1200" LastUpgradeVersion = "1200"
=======
LastUpgradeVersion = "1170"
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
<<<<<<< HEAD
LastUpgradeVersion = "1200" LastUpgradeVersion = "1200"
=======
LastUpgradeVersion = "1170"
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
<<<<<<< HEAD
LastUpgradeVersion = "1200" LastUpgradeVersion = "1200"
=======
LastUpgradeVersion = "1170"
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -292,7 +292,11 @@
29B97313FDCFA39411CA2CEA /* Project object */ = { 29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
<<<<<<< HEAD
LastUpgradeCheck = 1200; LastUpgradeCheck = 1200;
=======
LastUpgradeCheck = 1170;
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
}; };
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hologram" */; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hologram" */;
compatibilityVersion = "Xcode 8.0"; compatibilityVersion = "Xcode 8.0";

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
<<<<<<< HEAD
LastUpgradeVersion = "1200" LastUpgradeVersion = "1200"
=======
LastUpgradeVersion = "1170"
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
<<<<<<< HEAD
LastUpgradeVersion = "1200" LastUpgradeVersion = "1200"
=======
LastUpgradeVersion = "1170"
>>>>>>> d1353632775b86abd4a527c9f6114dda2d4405fa
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -54,7 +54,7 @@ distribution package, see the main [`README.md`](../README.md) document in the `
About **MoltenVK** 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 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 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 graphics and compute functionality to develop modern, cross-platform, high-performance graphical games
@ -272,6 +272,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
- `VK_KHR_16bit_storage` - `VK_KHR_16bit_storage`
- `VK_KHR_8bit_storage` - `VK_KHR_8bit_storage`
- `VK_KHR_bind_memory2` - `VK_KHR_bind_memory2`
- `VK_KHR_create_renderpass2`
- `VK_KHR_dedicated_allocation` - `VK_KHR_dedicated_allocation`
- `VK_KHR_descriptor_update_template` - `VK_KHR_descriptor_update_template`
- `VK_KHR_device_group` - `VK_KHR_device_group`
@ -284,6 +285,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
- `VK_KHR_maintenance1` - `VK_KHR_maintenance1`
- `VK_KHR_maintenance2` - `VK_KHR_maintenance2`
- `VK_KHR_maintenance3` - `VK_KHR_maintenance3`
- `VK_KHR_multiview`
- `VK_KHR_push_descriptor` - `VK_KHR_push_descriptor`
- `VK_KHR_relaxed_block_layout` - `VK_KHR_relaxed_block_layout`
- `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)* - `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)*
@ -310,7 +312,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
- `VK_EXT_scalar_block_layout` - `VK_EXT_scalar_block_layout`
- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)* - `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
- `VK_EXT_shader_viewport_index_layer` - `VK_EXT_shader_viewport_index_layer`
- `VK_EXT_swapchain_colorspace` *(macOS)* - `VK_EXT_swapchain_colorspace`
- `VK_EXT_vertex_attribute_divisor` - `VK_EXT_vertex_attribute_divisor`
- `VK_EXT_texel_buffer_alignment` *(requires Metal 2.0)* - `VK_EXT_texel_buffer_alignment` *(requires Metal 2.0)*
- `VK_EXTX_portability_subset` - `VK_EXTX_portability_subset`

View File

@ -13,17 +13,36 @@ For best results, use a Markdown reader.*
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 - Improve performance of tessellation control pipeline stage by processing multiple
patches per workgroup. patches per workgroup.
- `vkCmdBindDescriptorSets` order `pDynamicOffsets` by descriptor binding number - `vkCmdBindDescriptorSets` order `pDynamicOffsets` by descriptor binding number
within each descriptor set. within each descriptor set.
- `vkCmdCopyImage` on macOS flush non-coherent image memory before copy operation. - `vkCmdCopyImage` on macOS flush non-coherent image memory before copy operation.
- Re-add support for bitcode generation on *iOS* and *tvOS*. - 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.

View File

@ -3876,7 +3876,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = { A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1200; LastUpgradeCheck = 1170;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd."; ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = { TargetAttributes = {
2FEA0ADD2490320500EEF3AD = { 2FEA0ADD2490320500EEF3AD = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1 +1 @@
0376576d2dc0721edfb2c5a0257fdc275f6f39dc bad9dab8df6f2e6b80da9693db247b9357aebd2f

View File

@ -1102,7 +1102,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = { A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1200; LastUpgradeCheck = 1170;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd."; ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = { TargetAttributes = {
A9B8EE091A98D796009C5A02 = { A9B8EE091A98D796009C5A02 = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -49,8 +49,8 @@ typedef unsigned long MTLLanguageVersion;
* - 401215 (version 4.12.15) * - 401215 (version 4.12.15)
*/ */
#define MVK_VERSION_MAJOR 1 #define MVK_VERSION_MAJOR 1
#define MVK_VERSION_MINOR 0 #define MVK_VERSION_MINOR 1
#define MVK_VERSION_PATCH 45 #define MVK_VERSION_PATCH 0
#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) #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) #define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)

View File

@ -137,7 +137,6 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {
switch (stage) { switch (stage) {
case kMVKGraphicsStageVertex: { case kMVKGraphicsStageVertex: {
cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl); mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) { if (pipeline->needsVertexOutputBuffer()) {
vtxOutBuff = cmdEncoder->getTempMTLBuffer(_vertexCount * _instanceCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents); vtxOutBuff = cmdEncoder->getTempMTLBuffer(_vertexCount * _instanceCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents);
@ -243,17 +242,20 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass();
} else { } else {
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
uint32_t instanceCount = _instanceCount * viewCount;
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) { if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
vertexStart: _firstVertex vertexStart: _firstVertex
vertexCount: _vertexCount vertexCount: _vertexCount
instanceCount: _instanceCount instanceCount: instanceCount
baseInstance: _firstInstance]; baseInstance: _firstInstance];
} else { } else {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
vertexStart: _firstVertex vertexStart: _firstVertex
vertexCount: _vertexCount vertexCount: _vertexCount
instanceCount: _instanceCount]; instanceCount: instanceCount];
} }
} }
break; break;
@ -328,7 +330,6 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
switch (stage) { switch (stage) {
case kMVKGraphicsStageVertex: { case kMVKGraphicsStageVertex: {
cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl); mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) { if (pipeline->needsVertexOutputBuffer()) {
vtxOutBuff = cmdEncoder->getTempMTLBuffer(_indexCount * _instanceCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents); vtxOutBuff = cmdEncoder->getTempMTLBuffer(_indexCount * _instanceCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents);
@ -440,13 +441,16 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)->beginMetalRenderPass();
} else { } else {
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
uint32_t instanceCount = _instanceCount * viewCount;
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) { if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
indexCount: _indexCount indexCount: _indexCount
indexType: (MTLIndexType)ibb.mtlIndexType indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer indexBuffer: ibb.mtlBuffer
indexBufferOffset: idxBuffOffset indexBufferOffset: idxBuffOffset
instanceCount: _instanceCount instanceCount: instanceCount
baseVertex: _vertexOffset baseVertex: _vertexOffset
baseInstance: _firstInstance]; baseInstance: _firstInstance];
} else { } else {
@ -455,7 +459,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
indexType: (MTLIndexType)ibb.mtlIndexType indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer indexBuffer: ibb.mtlBuffer
indexBufferOffset: idxBuffOffset indexBufferOffset: idxBuffOffset
instanceCount: _instanceCount]; instanceCount: instanceCount];
} }
} }
break; break;
@ -499,11 +503,13 @@ static const uint32_t kMVKDrawIndirectVertexCountUpperBound = 131072;
void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); 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. // The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats.
// We have to convert from the drawPrimitives:... format to them. // 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 // While we're at it, we can create the temporary output buffers once and reuse them
// for each draw. // for each draw.
const MVKMTLBufferAllocation* tcIndirectBuff = nullptr; const MVKMTLBufferAllocation* tempIndirectBuff = nullptr;
const MVKMTLBufferAllocation* tcParamsBuff = nullptr; const MVKMTLBufferAllocation* tcParamsBuff = nullptr;
const MVKMTLBufferAllocation* vtxOutBuff = nullptr; const MVKMTLBufferAllocation* vtxOutBuff = nullptr;
const MVKMTLBufferAllocation* tcOutBuff = nullptr; const MVKMTLBufferAllocation* tcOutBuff = nullptr;
@ -513,7 +519,8 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
uint32_t inControlPointCount = 0, outControlPointCount = 0; uint32_t inControlPointCount = 0, outControlPointCount = 0;
VkDeviceSize paramsIncr = 0; VkDeviceSize paramsIncr = 0;
VkDeviceSize mtlTCIndBuffOfst = 0; id<MTLBuffer> mtlIndBuff = _mtlIndirectBuffer;
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
VkDeviceSize mtlParmBuffOfst = 0; VkDeviceSize mtlParmBuffOfst = 0;
NSUInteger vtxThreadExecWidth = 0; NSUInteger vtxThreadExecWidth = 0;
NSUInteger tcWorkgroupSize = 0; NSUInteger tcWorkgroupSize = 0;
@ -533,8 +540,9 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
} }
paramsIncr = std::max((size_t)cmdEncoder->getDevice()->_pProperties->limits.minUniformBufferOffsetAlignment, sizeof(uint32_t) * 2); paramsIncr = std::max((size_t)cmdEncoder->getDevice()->_pProperties->limits.minUniformBufferOffsetAlignment, sizeof(uint32_t) * 2);
VkDeviceSize paramsSize = paramsIncr * _drawCount; VkDeviceSize paramsSize = paramsIncr * _drawCount;
tcIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize); tempIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
mtlTCIndBuffOfst = tcIndirectBuff->_offset; mtlIndBuff = tempIndirectBuff->_mtlBuffer;
mtlIndBuffOfst = tempIndirectBuff->_offset;
tcParamsBuff = cmdEncoder->getTempMTLBuffer(paramsSize); tcParamsBuff = cmdEncoder->getTempMTLBuffer(paramsSize);
mtlParmBuffOfst = tcParamsBuff->_offset; mtlParmBuffOfst = tcParamsBuff->_offset;
if (pipeline->needsVertexOutputBuffer()) { if (pipeline->needsVertexOutputBuffer()) {
@ -555,31 +563,35 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
sgSize >>= 1; sgSize >>= 1;
tcWorkgroupSize = mvkLeastCommonMultiple(outControlPointCount, sgSize); 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; MVKPiplineStages stages;
pipeline->getStages(stages); pipeline->getStages(stages);
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) { for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) {
for (uint32_t s : stages) { for (uint32_t s : stages) {
auto stage = MVKGraphicsStage(s); auto stage = MVKGraphicsStage(s);
id<MTLComputeCommandEncoder> mtlTessCtlEncoder = nil; 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 // 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 // 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 // to do it, since it will require switching to compute anyway. Do it all
// at once to get it over with. // at once to get it over with.
cmdEncoder->encodeStoreActions(true); cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl); mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectConvertBuffersMTLComputePipelineState(false); id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(false);
[mtlTessCtlEncoder setComputePipelineState: mtlConvertState]; [mtlTessCtlEncoder setComputePipelineState: mtlConvertState];
[mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer [mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer
offset: _mtlIndirectBufferOffset offset: _mtlIndirectBufferOffset
atIndex: 0]; atIndex: 0];
[mtlTessCtlEncoder setBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder setBuffer: tempIndirectBuff->_mtlBuffer
offset: tcIndirectBuff->_offset offset: tempIndirectBuff->_offset
atIndex: 1]; atIndex: 1];
[mtlTessCtlEncoder setBuffer: tcParamsBuff->_mtlBuffer [mtlTessCtlEncoder setBuffer: tcParamsBuff->_mtlBuffer
offset: tcParamsBuff->_offset offset: tcParamsBuff->_offset
@ -617,6 +629,45 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
[mtlTessCtlEncoder dispatchThreadgroups: MTLSizeMake(mvkCeilingDivide<NSUInteger>(_drawCount, mtlConvertState.threadExecutionWidth), 1, 1) [mtlTessCtlEncoder dispatchThreadgroups: MTLSizeMake(mvkCeilingDivide<NSUInteger>(_drawCount, mtlConvertState.threadExecutionWidth), 1, 1)
threadsPerThreadgroup: MTLSizeMake(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 cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal
@ -625,7 +676,6 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
switch (stage) { switch (stage) {
case kMVKGraphicsStageVertex: case kMVKGraphicsStageVertex:
cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl); mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) { if (pipeline->needsVertexOutputBuffer()) {
[mtlTessCtlEncoder setBuffer: vtxOutBuff->_mtlBuffer [mtlTessCtlEncoder setBuffer: vtxOutBuff->_mtlBuffer
@ -635,14 +685,14 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
// We must assume we can read up to the maximum number of vertices. // We must assume we can read up to the maximum number of vertices.
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(0, 0, vertexCount, vertexCount)]; [mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(0, 0, vertexCount, vertexCount)];
if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) { if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) {
[mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst]; indirectBufferOffset: mtlIndBuffOfst];
mtlTCIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments); mtlIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments);
} }
[mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst indirectBufferOffset: mtlIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)]; threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments); mtlIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
// Mark pipeline, resources, and tess control push constants as dirty // Mark pipeline, resources, and tess control push constants as dirty
// so I apply them during the next stage. // so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
@ -674,10 +724,10 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
offset: vtxOutBuff->_offset offset: vtxOutBuff->_offset
atIndex: kMVKTessCtlInputBufferIndex]; atIndex: kMVKTessCtlInputBufferIndex];
} }
[mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst indirectBufferOffset: mtlIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(tcWorkgroupSize, 1, 1)]; 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. // 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. // TODO: On iOS, maybe we could use a tile shader to avoid this.
cmdEncoder->beginMetalRenderPass(true); cmdEncoder->beginMetalRenderPass(true);
@ -705,22 +755,22 @@ void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {
[cmdEncoder->_mtlRenderEncoder drawPatches: outControlPointCount [cmdEncoder->_mtlRenderEncoder drawPatches: outControlPointCount
patchIndexBuffer: nil patchIndexBuffer: nil
patchIndexBufferOffset: 0 patchIndexBufferOffset: 0
indirectBuffer: tcIndirectBuff->_mtlBuffer indirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst]; indirectBufferOffset: mtlIndBuffOfst];
#endif #endif
} }
mtlTCIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments); mtlIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments);
// Mark pipeline, resources, and tess control push constants as dirty // Mark pipeline, resources, and vertex push constants as dirty
// so I apply them during the next stage. // so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
cmdEncoder->_graphicsResourcesState.beginMetalRenderPass(); cmdEncoder->_graphicsResourcesState.beginMetalRenderPass();
cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass(); cmdEncoder->getPushConstants(VK_SHADER_STAGE_VERTEX_BIT)->beginMetalRenderPass();
} else { } else {
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType [cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
indirectBuffer: _mtlIndirectBuffer indirectBuffer: mtlIndBuff
indirectBufferOffset: mtlIndBuffOfst]; indirectBufferOffset: mtlIndBuffOfst];
mtlIndBuffOfst += _mtlIndirectBufferStride; mtlIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawPrimitivesIndirectArguments) : _mtlIndirectBufferStride;
} }
break; break;
} }
@ -759,11 +809,13 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding; MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline(); 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. // The indirect calls for dispatchThreadgroups:... and drawPatches:... have different formats.
// We have to convert from the drawIndexedPrimitives:... format to them. // 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 // While we're at it, we can create the temporary output buffers once and reuse them
// for each draw. // for each draw.
const MVKMTLBufferAllocation* tcIndirectBuff = nullptr; const MVKMTLBufferAllocation* tempIndirectBuff = nullptr;
const MVKMTLBufferAllocation* tcParamsBuff = nullptr; const MVKMTLBufferAllocation* tcParamsBuff = nullptr;
const MVKMTLBufferAllocation* vtxOutBuff = nullptr; const MVKMTLBufferAllocation* vtxOutBuff = nullptr;
const MVKMTLBufferAllocation* tcOutBuff = nullptr; const MVKMTLBufferAllocation* tcOutBuff = nullptr;
@ -774,7 +826,9 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
uint32_t inControlPointCount = 0, outControlPointCount = 0; uint32_t inControlPointCount = 0, outControlPointCount = 0;
VkDeviceSize paramsIncr = 0; VkDeviceSize paramsIncr = 0;
VkDeviceSize mtlTCIndBuffOfst = 0; id<MTLBuffer> mtlIndBuff = _mtlIndirectBuffer;
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
VkDeviceSize mtlTempIndBuffOfst = _mtlIndirectBufferOffset;
VkDeviceSize mtlParmBuffOfst = 0; VkDeviceSize mtlParmBuffOfst = 0;
NSUInteger vtxThreadExecWidth = 0; NSUInteger vtxThreadExecWidth = 0;
NSUInteger tcWorkgroupSize = 0; NSUInteger tcWorkgroupSize = 0;
@ -794,9 +848,10 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
} }
paramsIncr = std::max((size_t)cmdEncoder->getDevice()->_pProperties->limits.minUniformBufferOffsetAlignment, sizeof(uint32_t) * 2); paramsIncr = std::max((size_t)cmdEncoder->getDevice()->_pProperties->limits.minUniformBufferOffsetAlignment, sizeof(uint32_t) * 2);
VkDeviceSize paramsSize = paramsIncr * _drawCount; VkDeviceSize paramsSize = paramsIncr * _drawCount;
tcIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize); tempIndirectBuff = cmdEncoder->getTempMTLBuffer(indirectSize);
mtlTCIndBuffOfst = tcIndirectBuff->_offset; mtlIndBuff = tempIndirectBuff->_mtlBuffer;
tcParamsBuff = cmdEncoder->getTempMTLBuffer(paramsSize); mtlTempIndBuffOfst = tempIndirectBuff->_offset;
tcParamsBuff = cmdEncoder->getTempMTLBuffer(paramsSize);
mtlParmBuffOfst = tcParamsBuff->_offset; mtlParmBuffOfst = tcParamsBuff->_offset;
if (pipeline->needsVertexOutputBuffer()) { if (pipeline->needsVertexOutputBuffer()) {
vtxOutBuff = cmdEncoder->getTempMTLBuffer(vertexCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents); vtxOutBuff = cmdEncoder->getTempMTLBuffer(vertexCount * 4 * cmdEncoder->_pDeviceProperties->limits.maxVertexOutputComponents);
@ -820,18 +875,22 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
sgSize >>= 1; sgSize >>= 1;
tcWorkgroupSize = mvkLeastCommonMultiple(outControlPointCount, sgSize); 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; MVKPiplineStages stages;
pipeline->getStages(stages); pipeline->getStages(stages);
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) { for (uint32_t drawIdx = 0; drawIdx < _drawCount; drawIdx++) {
for (uint32_t s : stages) { for (uint32_t s : stages) {
auto stage = MVKGraphicsStage(s); auto stage = MVKGraphicsStage(s);
id<MTLComputeCommandEncoder> mtlTessCtlEncoder = nil; id<MTLComputeCommandEncoder> mtlTessCtlEncoder = nil;
if (stage == kMVKGraphicsStageVertex) { if (stage == kMVKGraphicsStageVertex && pipeline->isTessellationPipeline()) {
cmdEncoder->encodeStoreActions(true); cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl); mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
// We need the indirect buffers now. This must be done before finalizing // We need the indirect buffers now. This must be done before finalizing
@ -839,13 +898,13 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
// to do it, since it will require switching to compute anyway. Do it all // to do it, since it will require switching to compute anyway. Do it all
// at once to get it over with. // at once to get it over with.
if (drawIdx == 0) { if (drawIdx == 0) {
id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectConvertBuffersMTLComputePipelineState(true); id<MTLComputePipelineState> mtlConvertState = cmdEncoder->getCommandEncodingPool()->getCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(true);
[mtlTessCtlEncoder setComputePipelineState: mtlConvertState]; [mtlTessCtlEncoder setComputePipelineState: mtlConvertState];
[mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer [mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer
offset: _mtlIndirectBufferOffset offset: _mtlIndirectBufferOffset
atIndex: 0]; atIndex: 0];
[mtlTessCtlEncoder setBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder setBuffer: tempIndirectBuff->_mtlBuffer
offset: tcIndirectBuff->_offset offset: tempIndirectBuff->_offset
atIndex: 1]; atIndex: 1];
[mtlTessCtlEncoder setBuffer: tcParamsBuff->_mtlBuffer [mtlTessCtlEncoder setBuffer: tcParamsBuff->_mtlBuffer
offset: tcParamsBuff->_offset offset: tcParamsBuff->_offset
@ -891,10 +950,50 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
[mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer [mtlTessCtlEncoder setBuffer: _mtlIndirectBuffer
offset: mtlIndBuffOfst offset: mtlIndBuffOfst
atIndex: 2]; atIndex: 2];
[mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)]; threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
mtlIndBuffOfst += sizeof(MTLDrawIndexedPrimitivesIndirectArguments); 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 cmdEncoder->finalizeDrawState(stage); // Ensure all updated state has been submitted to Metal
@ -903,7 +1002,6 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
switch (stage) { switch (stage) {
case kMVKGraphicsStageVertex: case kMVKGraphicsStageVertex:
cmdEncoder->encodeStoreActions(true);
mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl); mtlTessCtlEncoder = cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl);
if (pipeline->needsVertexOutputBuffer()) { if (pipeline->needsVertexOutputBuffer()) {
[mtlTessCtlEncoder setBuffer: vtxOutBuff->_mtlBuffer [mtlTessCtlEncoder setBuffer: vtxOutBuff->_mtlBuffer
@ -915,14 +1013,14 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]]; atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]];
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(0, 0, vertexCount, vertexCount)]; [mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(0, 0, vertexCount, vertexCount)];
if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) { if ([mtlTessCtlEncoder respondsToSelector: @selector(setStageInRegionWithIndirectBuffer:indirectBufferOffset:)]) {
[mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder setStageInRegionWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst]; indirectBufferOffset: mtlTempIndBuffOfst];
mtlTCIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments); mtlTempIndBuffOfst += sizeof(MTLStageInRegionIndirectArguments);
} }
[mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)]; threadsPerThreadgroup: MTLSizeMake(vtxThreadExecWidth, 1, 1)];
mtlTCIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments); mtlTempIndBuffOfst += sizeof(MTLDispatchThreadgroupsIndirectArguments);
// Mark pipeline, resources, and tess control push constants as dirty // Mark pipeline, resources, and tess control push constants as dirty
// so I apply them during the next stage. // so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
@ -954,10 +1052,10 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
offset: vtxOutBuff->_offset offset: vtxOutBuff->_offset
atIndex: kMVKTessCtlInputBufferIndex]; atIndex: kMVKTessCtlInputBufferIndex];
} }
[mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: tcIndirectBuff->_mtlBuffer [mtlTessCtlEncoder dispatchThreadgroupsWithIndirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst indirectBufferOffset: mtlTempIndBuffOfst
threadsPerThreadgroup: MTLSizeMake(tcWorkgroupSize, 1, 1)]; 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. // 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. // TODO: On iOS, maybe we could use a tile shader to avoid this.
cmdEncoder->beginMetalRenderPass(true); cmdEncoder->beginMetalRenderPass(true);
@ -985,12 +1083,12 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
[cmdEncoder->_mtlRenderEncoder drawPatches: outControlPointCount [cmdEncoder->_mtlRenderEncoder drawPatches: outControlPointCount
patchIndexBuffer: nil patchIndexBuffer: nil
patchIndexBufferOffset: 0 patchIndexBufferOffset: 0
indirectBuffer: tcIndirectBuff->_mtlBuffer indirectBuffer: mtlIndBuff
indirectBufferOffset: mtlTCIndBuffOfst]; indirectBufferOffset: mtlTempIndBuffOfst];
#endif #endif
} }
mtlTCIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments); mtlTempIndBuffOfst += sizeof(MTLDrawPatchIndirectArguments);
// Mark pipeline, resources, and tess control push constants as dirty // Mark pipeline, resources, and tess control push constants as dirty
// so I apply them during the next stage. // so I apply them during the next stage.
cmdEncoder->_graphicsPipelineState.beginMetalRenderPass(); cmdEncoder->_graphicsPipelineState.beginMetalRenderPass();
@ -1001,9 +1099,9 @@ void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
indexType: (MTLIndexType)ibb.mtlIndexType indexType: (MTLIndexType)ibb.mtlIndexType
indexBuffer: ibb.mtlBuffer indexBuffer: ibb.mtlBuffer
indexBufferOffset: ibb.offset indexBufferOffset: ibb.offset
indirectBuffer: _mtlIndirectBuffer indirectBuffer: mtlIndBuff
indirectBufferOffset: mtlIndBuffOfst]; indirectBufferOffset: mtlTempIndBuffOfst];
mtlIndBuffOfst += _mtlIndirectBufferStride; mtlTempIndBuffOfst += needsInstanceAdjustment ? sizeof(MTLDrawIndexedPrimitivesIndirectArguments) : _mtlIndirectBufferStride;
} }
break; break;
} }

View File

@ -52,7 +52,13 @@ VkResult MVKCmdBeginQuery::setContent(MVKCommandBuffer* cmdBuff,
} }
void MVKCmdBeginQuery::encode(MVKCommandEncoder* cmdEncoder) { 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 @@ void MVKCmdBeginQuery::encode(MVKCommandEncoder* cmdEncoder) {
#pragma mark MVKCmdEndQuery #pragma mark MVKCmdEndQuery
void MVKCmdEndQuery::encode(MVKCommandEncoder* cmdEncoder) { 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 @@ VkResult MVKCmdWriteTimestamp::setContent(MVKCommandBuffer* cmdBuff,
} }
void MVKCmdWriteTimestamp::encode(MVKCommandEncoder* cmdEncoder) { 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);
} }

View File

@ -28,6 +28,31 @@ class MVKRenderPass;
class MVKFramebuffer; class MVKFramebuffer;
#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 -
#pragma mark MVKCmdBeginRenderPass #pragma mark MVKCmdBeginRenderPass
@ -36,12 +61,15 @@ class MVKFramebuffer;
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts. * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/ */
template <size_t N> template <size_t N>
class MVKCmdBeginRenderPass : public MVKCommand { class MVKCmdBeginRenderPass : public MVKCmdBeginRenderPassBase {
public: public:
VkResult setContent(MVKCommandBuffer* cmdBuff, VkResult setContent(MVKCommandBuffer* cmdBuff,
const VkRenderPassBeginInfo* pRenderPassBegin, const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents); VkSubpassContents contents);
VkResult setContent(MVKCommandBuffer* cmdBuff,
const VkRenderPassBeginInfo* pRenderPassBegin,
const VkSubpassBeginInfo* pSubpassBeginInfo);
void encode(MVKCommandEncoder* cmdEncoder) override; void encode(MVKCommandEncoder* cmdEncoder) override;
@ -49,10 +77,6 @@ protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override; MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
MVKSmallVector<VkClearValue, N> _clearValues; MVKSmallVector<VkClearValue, N> _clearValues;
MVKRenderPass* _renderPass;
MVKFramebuffer* _framebuffer;
VkRect2D _renderArea;
VkSubpassContents _contents;
}; };
// Concrete template class implementations. // Concrete template class implementations.
@ -70,6 +94,9 @@ class MVKCmdNextSubpass : public MVKCommand {
public: public:
VkResult setContent(MVKCommandBuffer* cmdBuff, VkResult setContent(MVKCommandBuffer* cmdBuff,
VkSubpassContents contents); VkSubpassContents contents);
VkResult setContent(MVKCommandBuffer* cmdBuff,
const VkSubpassBeginInfo* pSubpassBeginInfo,
const VkSubpassEndInfo* pSubpassEndInfo);
void encode(MVKCommandEncoder* cmdEncoder) override; void encode(MVKCommandEncoder* cmdEncoder) override;
@ -88,6 +115,8 @@ class MVKCmdEndRenderPass : public MVKCommand {
public: public:
VkResult setContent(MVKCommandBuffer* cmdBuff); VkResult setContent(MVKCommandBuffer* cmdBuff);
VkResult setContent(MVKCommandBuffer* cmdBuff,
const VkSubpassEndInfo* pSubpassEndInfo);
void encode(MVKCommandEncoder* cmdEncoder) override; void encode(MVKCommandEncoder* cmdEncoder) override;

View File

@ -25,6 +25,21 @@
#include "mvk_datatypes.hpp" #include "mvk_datatypes.hpp"
#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 -
#pragma mark MVKCmdBeginRenderPass #pragma mark MVKCmdBeginRenderPass
@ -32,10 +47,7 @@ template <size_t N>
VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff, VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
const VkRenderPassBeginInfo* pRenderPassBegin, const VkRenderPassBeginInfo* pRenderPassBegin,
VkSubpassContents contents) { VkSubpassContents contents) {
_contents = contents; MVKCmdBeginRenderPassBase::setContent(cmdBuff, pRenderPassBegin, contents);
_renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass;
_framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
_renderArea = pRenderPassBegin->renderArea;
// Add clear values // Add clear values
uint32_t cvCnt = pRenderPassBegin->clearValueCount; uint32_t cvCnt = pRenderPassBegin->clearValueCount;
@ -48,10 +60,17 @@ VkResult MVKCmdBeginRenderPass<N>::setContent(MVKCommandBuffer* cmdBuff,
return VK_SUCCESS; return VK_SUCCESS;
} }
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> template <size_t N>
void MVKCmdBeginRenderPass<N>::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdBeginRenderPass<N>::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdBeginRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds()); // 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>; template class MVKCmdBeginRenderPass<1>;
@ -69,8 +88,17 @@ VkResult MVKCmdNextSubpass::setContent(MVKCommandBuffer* cmdBuff,
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult MVKCmdNextSubpass::setContent(MVKCommandBuffer* cmdBuff,
const VkSubpassBeginInfo* pBeginSubpassInfo,
const VkSubpassEndInfo* pEndSubpassInfo) {
return setContent(cmdBuff, pBeginSubpassInfo->contents);
}
void MVKCmdNextSubpass::encode(MVKCommandEncoder* cmdEncoder) { 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 @@ VkResult MVKCmdEndRenderPass::setContent(MVKCommandBuffer* cmdBuff) {
return VK_SUCCESS; return VK_SUCCESS;
} }
VkResult MVKCmdEndRenderPass::setContent(MVKCommandBuffer* cmdBuff,
const VkSubpassEndInfo* pEndSubpassInfo) {
return VK_SUCCESS;
}
void MVKCmdEndRenderPass::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdEndRenderPass::encode(MVKCommandEncoder* cmdEncoder) {
// MVKLogDebug("Encoding vkCmdEndRenderPass(). Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds()); // 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 @@ VkResult MVKCmdExecuteCommands<N>::setContent(MVKCommandBuffer* cmdBuff,
for (uint32_t cbIdx = 0; cbIdx < commandBuffersCount; cbIdx++) { for (uint32_t cbIdx = 0; cbIdx < commandBuffersCount; cbIdx++) {
_secondaryCommandBuffers.push_back(MVKCommandBuffer::getMVKCommandBuffer(pCommandBuffers[cbIdx])); _secondaryCommandBuffers.push_back(MVKCommandBuffer::getMVKCommandBuffer(pCommandBuffers[cbIdx]));
} }
cmdBuff->recordExecuteCommands(_secondaryCommandBuffers.contents());
return VK_SUCCESS; return VK_SUCCESS;
} }

View File

@ -254,10 +254,12 @@ public:
void encode(MVKCommandEncoder* cmdEncoder) override; void encode(MVKCommandEncoder* cmdEncoder) override;
protected: protected:
uint32_t getVertexCount(); uint32_t getVertexCount(MVKCommandEncoder* cmdEncoder);
void populateVertices(simd::float4* vertices, float attWidth, float attHeight); void populateVertices(MVKCommandEncoder* cmdEncoder, simd::float4* vertices,
uint32_t populateVertices(simd::float4* vertices, uint32_t startVertex, float attWidth, float attHeight);
VkClearRect& clearRect, 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 VkClearValue& getClearValue(uint32_t attIdx) = 0;
virtual void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) = 0; virtual void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) = 0;

View File

@ -124,11 +124,18 @@ void MVKCmdCopyImage<N>::encode(MVKCommandEncoder* cmdEncoder, MVKCommandUse com
// Extent is provided in source texels. If the source is compressed but the // 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, // 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. // 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; VkExtent3D dstExtent = vkIC.extent;
if (isSrcCompressed && !isDstCompressed) { if (isSrcCompressed && !isDstCompressed) {
VkExtent2D srcBlockExtent = pixFmts->getBlockTexelSize(srcMTLPixFmt); VkExtent2D srcBlockExtent = pixFmts->getBlockTexelSize(srcMTLPixFmt);
dstExtent.width /= srcBlockExtent.width; dstExtent.width /= srcBlockExtent.width;
dstExtent.height /= srcBlockExtent.height; 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]; auto& dstCpy = vkDstCopies[copyIdx];
dstCpy.bufferOffset = tmpBuffSize; dstCpy.bufferOffset = tmpBuffSize;
@ -948,27 +955,34 @@ VkResult MVKCmdClearAttachments<N>::setContent(MVKCommandBuffer* cmdBuff,
// Returns the total number of vertices needed to clear all layers of all rectangles. // Returns the total number of vertices needed to clear all layers of all rectangles.
template <size_t N> template <size_t N>
uint32_t MVKCmdClearAttachments<N>::getVertexCount() { uint32_t MVKCmdClearAttachments<N>::getVertexCount(MVKCommandEncoder* cmdEncoder) {
uint32_t vtxCnt = 0; uint32_t vtxCnt = 0;
for (auto& rect : _clearRects) { if (cmdEncoder->getSubpass()->isMultiview()) {
vtxCnt += 6 * rect.layerCount; // 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; return vtxCnt;
} }
// Populates the vertices for all clear rectangles within an attachment of the specified size. // Populates the vertices for all clear rectangles within an attachment of the specified size.
template <size_t N> 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; uint32_t vtxIdx = 0;
for (auto& rect : _clearRects) { 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 // 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. // an attachment of the specified size. Returns the next vertex that needs to be populated.
template <size_t N> 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, uint32_t startVertex,
VkClearRect& clearRect, VkClearRect& clearRect,
float attWidth, float attWidth,
@ -990,8 +1004,17 @@ uint32_t MVKCmdClearAttachments<N>::populateVertices(simd::float4* vertices,
simd::float4 vtx; simd::float4 vtx;
uint32_t vtxIdx = startVertex; uint32_t vtxIdx = startVertex;
uint32_t startLayer = clearRect.baseArrayLayer; uint32_t startLayer, endLayer;
uint32_t endLayer = startLayer + clearRect.layerCount; 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++) { for (uint32_t layer = startLayer; layer < endLayer; layer++) {
vtx.z = 0.0; vtx.z = 0.0;
@ -1032,12 +1055,12 @@ uint32_t MVKCmdClearAttachments<N>::populateVertices(simd::float4* vertices,
template <size_t N> template <size_t N>
void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) { void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
uint32_t vtxCnt = getVertexCount(); uint32_t vtxCnt = getVertexCount(cmdEncoder);
simd::float4 vertices[vtxCnt]; simd::float4 vertices[vtxCnt];
simd::float4 clearColors[kMVKClearAttachmentCount]; simd::float4 clearColors[kMVKClearAttachmentCount];
VkExtent2D fbExtent = cmdEncoder->_framebuffer->getExtent2D(); VkExtent2D fbExtent = cmdEncoder->_framebuffer->getExtent2D();
populateVertices(vertices, fbExtent.width, fbExtent.height); populateVertices(cmdEncoder, vertices, fbExtent.width, fbExtent.height);
MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats(); MVKPixelFormats* pixFmts = cmdEncoder->getPixelFormats();
MVKRenderSubpass* subpass = cmdEncoder->getSubpass(); MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
@ -1045,7 +1068,10 @@ void MVKCmdClearAttachments<N>::encode(MVKCommandEncoder* cmdEncoder) {
// Populate the render pipeline state attachment key with info from the subpass and framebuffer. // Populate the render pipeline state attachment key with info from the subpass and framebuffer.
_rpsKey.mtlSampleCount = mvkSampleCountFromVkSampleCountFlagBits(subpass->getSampleCount()); _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(); uint32_t caCnt = subpass->getColorAttachmentCount();
for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) { for (uint32_t caIdx = 0; caIdx < caCnt; caIdx++) {

View File

@ -33,6 +33,8 @@ class MVKQueue;
class MVKQueueCommandBufferSubmission; class MVKQueueCommandBufferSubmission;
class MVKCommandEncoder; class MVKCommandEncoder;
class MVKCommandEncodingPool; class MVKCommandEncodingPool;
class MVKCmdBeginRenderPassBase;
class MVKCmdNextSubpass;
class MVKRenderPass; class MVKRenderPass;
class MVKFramebuffer; class MVKFramebuffer;
class MVKRenderSubpass; class MVKRenderSubpass;
@ -95,6 +97,8 @@ public:
*/ */
id<MTLBuffer> _initialVisibilityResultMTLBuffer; 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 #pragma mark Tessellation constituent command management
@ -105,6 +109,24 @@ public:
MVKCmdBindPipeline* _lastTessellationPipeline; 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 #pragma mark Construction
MVKCommandBuffer(MVKDevice* device) : MVKDeviceTrackingMixin(device) {} MVKCommandBuffer(MVKDevice* device) : MVKDeviceTrackingMixin(device) {}
@ -249,14 +271,18 @@ public:
void encodeSecondary(MVKCommandBuffer* secondaryCmdBuffer); void encodeSecondary(MVKCommandBuffer* secondaryCmdBuffer);
/** Begins a render pass and establishes initial draw state. */ /** Begins a render pass and establishes initial draw state. */
void beginRenderpass(VkSubpassContents subpassContents, void beginRenderpass(MVKCommand* passCmd,
VkSubpassContents subpassContents,
MVKRenderPass* renderPass, MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer, MVKFramebuffer* framebuffer,
VkRect2D& renderArea, VkRect2D& renderArea,
MVKArrayRef<VkClearValue> clearValues); MVKArrayRef<VkClearValue> clearValues);
/** Begins the next render subpass. */ /** 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. */ /** Begins a Metal render pass for the current render subpass. */
void beginMetalRenderPass(bool loadOverride = false); void beginMetalRenderPass(bool loadOverride = false);
@ -267,6 +293,9 @@ public:
/** Returns the render subpass that is currently active. */ /** Returns the render subpass that is currently active. */
MVKRenderSubpass* getSubpass(); 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. */ /** Binds a pipeline to a bind point. */
void bindPipeline(VkPipelineBindPoint pipelineBindPoint, MVKPipeline* pipeline); void bindPipeline(VkPipelineBindPoint pipelineBindPoint, MVKPipeline* pipeline);
@ -428,14 +457,16 @@ public:
protected: protected:
void addActivatedQuery(MVKQueryPool* pQueryPool, uint32_t query); void addActivatedQuery(MVKQueryPool* pQueryPool, uint32_t query);
void finishQueries(); void finishQueries();
void setSubpass(VkSubpassContents subpassContents, uint32_t subpassIndex); void setSubpass(MVKCommand* passCmd, VkSubpassContents subpassContents, uint32_t subpassIndex);
void clearRenderArea(); void clearRenderArea();
const MVKMTLBufferAllocation* copyToTempMTLBufferAllocation(const void* bytes, NSUInteger length); const MVKMTLBufferAllocation* copyToTempMTLBufferAllocation(const void* bytes, NSUInteger length);
NSString* getMTLRenderCommandEncoderName(); NSString* getMTLRenderCommandEncoderName();
VkSubpassContents _subpassContents; VkSubpassContents _subpassContents;
MVKRenderPass* _renderPass; MVKRenderPass* _renderPass;
MVKCommand* _lastMultiviewPassCmd;
uint32_t _renderSubpassIndex; uint32_t _renderSubpassIndex;
uint32_t _multiviewPassIndex;
VkRect2D _renderArea; VkRect2D _renderArea;
MVKActivatedQueries* _pActivatedQueries; MVKActivatedQueries* _pActivatedQueries;
MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues; MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;

View File

@ -26,6 +26,7 @@
#include "MVKLogging.h" #include "MVKLogging.h"
#include "MTLRenderPassDescriptor+MoltenVK.h" #include "MTLRenderPassDescriptor+MoltenVK.h"
#include "MVKCmdDraw.h" #include "MVKCmdDraw.h"
#include "MVKCmdRenderPass.h"
using namespace std; using namespace std;
@ -76,6 +77,7 @@ VkResult MVKCommandBuffer::reset(VkCommandBufferResetFlags flags) {
_commandCount = 0; _commandCount = 0;
_initialVisibilityResultMTLBuffer = nil; // not retained _initialVisibilityResultMTLBuffer = nil; // not retained
_lastTessellationPipeline = nullptr; _lastTessellationPipeline = nullptr;
_lastMultiviewSubpass = nullptr;
setConfigurationResult(VK_NOT_READY); setConfigurationResult(VK_NOT_READY);
if (mvkAreAllFlagsEnabled(flags, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT)) { if (mvkAreAllFlagsEnabled(flags, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT)) {
@ -193,6 +195,19 @@ MVKCommandBuffer::~MVKCommandBuffer() {
reset(0); 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 -
#pragma mark Tessellation constituent command management #pragma mark Tessellation constituent command management
@ -202,12 +217,41 @@ void MVKCommandBuffer::recordBindPipeline(MVKCmdBindPipeline* mvkBindPipeline) {
} }
#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 -
#pragma mark MVKCommandEncoder #pragma mark MVKCommandEncoder
void MVKCommandEncoder::encode(id<MTLCommandBuffer> mtlCmdBuff) { void MVKCommandEncoder::encode(id<MTLCommandBuffer> mtlCmdBuff) {
_renderPass = nullptr;
_subpassContents = VK_SUBPASS_CONTENTS_INLINE; _subpassContents = VK_SUBPASS_CONTENTS_INLINE;
_renderSubpassIndex = 0; _renderSubpassIndex = 0;
_multiviewPassIndex = 0;
_canUseLayeredRendering = false; _canUseLayeredRendering = false;
_mtlCmdBuffer = mtlCmdBuff; // not retained _mtlCmdBuffer = mtlCmdBuff; // not retained
@ -216,8 +260,15 @@ void MVKCommandEncoder::encode(id<MTLCommandBuffer> mtlCmdBuff) {
MVKCommand* cmd = _cmdBuffer->_head; MVKCommand* cmd = _cmdBuffer->_head;
while (cmd) { while (cmd) {
uint32_t prevMVPassIdx = _multiviewPassIndex;
cmd->encode(this); 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(); endCurrentMetalEncoding();
@ -232,7 +283,8 @@ void MVKCommandEncoder::encodeSecondary(MVKCommandBuffer* secondaryCmdBuffer) {
} }
} }
void MVKCommandEncoder::beginRenderpass(VkSubpassContents subpassContents, void MVKCommandEncoder::beginRenderpass(MVKCommand* passCmd,
VkSubpassContents subpassContents,
MVKRenderPass* renderPass, MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer, MVKFramebuffer* framebuffer,
VkRect2D& renderArea, VkRect2D& renderArea,
@ -243,19 +295,23 @@ void MVKCommandEncoder::beginRenderpass(VkSubpassContents subpassContents,
_isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) && _isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) &&
mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D())); mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D()));
_clearValues.assign(clearValues.begin(), clearValues.end()); _clearValues.assign(clearValues.begin(), clearValues.end());
setSubpass(subpassContents, 0); setSubpass(passCmd, subpassContents, 0);
} }
void MVKCommandEncoder::beginNextSubpass(VkSubpassContents contents) { void MVKCommandEncoder::beginNextSubpass(MVKCommand* subpassCmd, VkSubpassContents contents) {
setSubpass(contents, _renderSubpassIndex + 1); setSubpass(subpassCmd, contents, _renderSubpassIndex + 1);
} }
// Sets the current render subpass to the subpass with the specified index. // 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(); encodeStoreActions();
_lastMultiviewPassCmd = subpassCmd;
_subpassContents = subpassContents; _subpassContents = subpassContents;
_renderSubpassIndex = subpassIndex; _renderSubpassIndex = subpassIndex;
_multiviewPassIndex = 0;
_canUseLayeredRendering = (_device->_pMetalFeatures->layeredRendering && _canUseLayeredRendering = (_device->_pMetalFeatures->layeredRendering &&
(_device->_pMetalFeatures->multisampleLayeredRendering || (_device->_pMetalFeatures->multisampleLayeredRendering ||
@ -264,20 +320,34 @@ void MVKCommandEncoder::setSubpass(VkSubpassContents subpassContents, uint32_t s
beginMetalRenderPass(); 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. // Creates _mtlRenderEncoder and marks cached render state as dirty so it will be set into the _mtlRenderEncoder.
void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride) { void MVKCommandEncoder::beginMetalRenderPass(bool loadOverride) {
endCurrentMetalEncoding(); endCurrentMetalEncoding();
MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor]; 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(); mtlRPDesc.visibilityResultBuffer = _occlusionQueryState.getVisibilityResultMTLBuffer();
VkExtent2D fbExtent = _framebuffer->getExtent2D(); VkExtent2D fbExtent = _framebuffer->getExtent2D();
mtlRPDesc.renderTargetWidthMVK = min(_renderArea.offset.x + _renderArea.extent.width, fbExtent.width); mtlRPDesc.renderTargetWidthMVK = min(_renderArea.offset.x + _renderArea.extent.width, fbExtent.width);
mtlRPDesc.renderTargetHeightMVK = min(_renderArea.offset.y + _renderArea.extent.height, fbExtent.height); mtlRPDesc.renderTargetHeightMVK = min(_renderArea.offset.y + _renderArea.extent.height, fbExtent.height);
if (_canUseLayeredRendering) { 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 _mtlRenderEncoder = [_mtlCmdBuffer renderCommandEncoderWithDescriptor: mtlRPDesc]; // not retained
@ -361,6 +431,10 @@ VkRect2D MVKCommandEncoder::clipToRenderArea(VkRect2D scissor) {
} }
void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) { void MVKCommandEncoder::finalizeDrawState(MVKGraphicsStage stage) {
if (stage == kMVKGraphicsStageVertex) {
// Must happen before switching encoders.
encodeStoreActions(true);
}
_graphicsPipelineState.encode(stage); // Must do first..it sets others _graphicsPipelineState.encode(stage); // Must do first..it sets others
_graphicsResourcesState.encode(stage); _graphicsResourcesState.encode(stage);
_viewportState.encode(stage); _viewportState.encode(stage);
@ -386,16 +460,36 @@ void MVKCommandEncoder::clearRenderArea() {
if (clearAttCnt == 0) { return; } if (clearAttCnt == 0) { return; }
VkClearRect clearRect; if (!getSubpass()->isMultiview()) {
clearRect.rect = _renderArea; VkClearRect clearRect;
clearRect.baseArrayLayer = 0; clearRect.rect = _renderArea;
clearRect.layerCount = _framebuffer->getLayerCount(); clearRect.baseArrayLayer = 0;
clearRect.layerCount = _framebuffer->getLayerCount();
// Create and execute a temporary clear attachments command. // Create and execute a temporary clear attachments command.
// To be threadsafe...do NOT acquire and return the command from the pool. // To be threadsafe...do NOT acquire and return the command from the pool.
MVKCmdClearMultiAttachments<1> cmd; MVKCmdClearMultiAttachments<1> cmd;
cmd.setContent(_cmdBuffer, clearAttCnt, clearAtts.data(), 1, &clearRect); cmd.setContent(_cmdBuffer, clearAttCnt, clearAtts.data(), 1, &clearRect);
cmd.encode(this); 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() { void MVKCommandEncoder::finalizeDispatchState() {
@ -559,7 +653,13 @@ void MVKCommandEncoder::markTimestamp(MVKQueryPool* pQueryPool, uint32_t query)
// Marks the specified query as activated // Marks the specified query as activated
void MVKCommandEncoder::addActivatedQuery(MVKQueryPool* pQueryPool, uint32_t query) { void MVKCommandEncoder::addActivatedQuery(MVKQueryPool* pQueryPool, uint32_t query) {
if ( !_pActivatedQueries ) { _pActivatedQueries = new MVKActivatedQueries(); } 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. // Register a command buffer completion handler that finishes each activated query.
@ -653,6 +753,7 @@ NSString* mvkMTLComputeCommandEncoderLabel(MVKCommandUse cmdUse) {
case kMVKCommandUseCopyImageToBuffer: return @"vkCmdCopyImageToBuffer ComputeEncoder"; case kMVKCommandUseCopyImageToBuffer: return @"vkCmdCopyImageToBuffer ComputeEncoder";
case kMVKCommandUseFillBuffer: return @"vkCmdFillBuffer ComputeEncoder"; case kMVKCommandUseFillBuffer: return @"vkCmdFillBuffer ComputeEncoder";
case kMVKCommandUseTessellationVertexTessCtl: return @"vkCmdDraw (vertex and tess control stages) 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"; case kMVKCommandUseCopyQueryPoolResults:return @"vkCmdCopyQueryPoolResults ComputeEncoder";
default: return @"Unknown Use ComputeEncoder"; default: return @"Unknown Use ComputeEncoder";
} }

View File

@ -427,6 +427,7 @@ protected:
MVKMTLBufferBinding swizzleBufferBinding; MVKMTLBufferBinding swizzleBufferBinding;
MVKMTLBufferBinding bufferSizeBufferBinding; MVKMTLBufferBinding bufferSizeBufferBinding;
MVKMTLBufferBinding viewRangeBufferBinding;
bool areBufferBindingsDirty = false; bool areBufferBindingsDirty = false;
bool areTextureBindingsDirty = false; bool areTextureBindingsDirty = false;
@ -446,6 +447,7 @@ protected:
areSamplerStateBindingsDirty = false; areSamplerStateBindingsDirty = false;
swizzleBufferBinding.isDirty = false; swizzleBufferBinding.isDirty = false;
bufferSizeBufferBinding.isDirty = false; bufferSizeBufferBinding.isDirty = false;
viewRangeBufferBinding.isDirty = false;
needsSwizzle = false; needsSwizzle = false;
} }
@ -493,6 +495,11 @@ public:
bool needTessEvalSizeBuffer, bool needTessEvalSizeBuffer,
bool needFragmentSizeBuffer); bool needFragmentSizeBuffer);
/** Sets the current view range buffer state. */
void bindViewRangeBuffer(const MVKShaderImplicitRezBinding& binding,
bool needVertexViewBuffer,
bool needFragmentViewBuffer);
void encodeBindings(MVKShaderStage stage, void encodeBindings(MVKShaderStage stage,
const char* pStageName, const char* pStageName,
bool fullImageViewSwizzle, bool fullImageViewSwizzle,

View File

@ -557,6 +557,18 @@ void MVKGraphicsResourcesCommandEncoderState::bindBufferSizeBuffer(const MVKShad
_shaderStageResourceBindings[kMVKShaderStageFragment].bufferSizeBufferBinding.isDirty = needFragmentSizeBuffer; _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, void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stage,
const char* pStageName, const char* pStageName,
bool fullImageViewSwizzle, bool fullImageViewSwizzle,
@ -587,6 +599,13 @@ void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stag
bindImplicitBuffer(_cmdEncoder, shaderStage.bufferSizeBufferBinding, shaderStage.bufferSizes.contents()); 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<MVKMTLTextureBinding>(shaderStage.textureBindings, shaderStage.areTextureBindingsDirty, bindTexture);
encodeBinding<MVKMTLSamplerStateBinding>(shaderStage.samplerStateBindings, shaderStage.areSamplerStateBindingsDirty, bindSampler); encodeBinding<MVKMTLSamplerStateBinding>(shaderStage.samplerStateBindings, shaderStage.areSamplerStateBindingsDirty, bindSampler);
} }

View File

@ -112,8 +112,11 @@ public:
/** Returns a MTLComputePipelineState for decompressing a buffer into a 3D image. */ /** Returns a MTLComputePipelineState for decompressing a buffer into a 3D image. */
id<MTLComputePipelineState> getCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needsTempBuff); 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. */ /** 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. */ /** Returns a MTLComputePipelineState for copying an index buffer for use in an indirect tessellated draw. */
id<MTLComputePipelineState> getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type); id<MTLComputePipelineState> getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type);
@ -149,7 +152,8 @@ protected:
id<MTLComputePipelineState> _mtlCopyBufferBytesComputePipelineState = nil; id<MTLComputePipelineState> _mtlCopyBufferBytesComputePipelineState = nil;
id<MTLComputePipelineState> _mtlFillBufferComputePipelineState = nil; id<MTLComputePipelineState> _mtlFillBufferComputePipelineState = nil;
id<MTLComputePipelineState> _mtlCopyBufferToImage3DDecompressComputePipelineState[2] = {nil, 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> _mtlDrawIndexedCopyIndexBufferComputePipelineState[2] = {nil, nil};
id<MTLComputePipelineState> _mtlCopyQueryPoolResultsComputePipelineState = nil; id<MTLComputePipelineState> _mtlCopyQueryPoolResultsComputePipelineState = nil;
}; };

View File

@ -106,8 +106,12 @@ id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdCopyBufferToImage3DDec
MVK_ENC_REZ_ACCESS(_mtlCopyBufferToImage3DDecompressComputePipelineState[needsTempBuff ? 1 : 0], newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(needsTempBuff, _commandPool)); MVK_ENC_REZ_ACCESS(_mtlCopyBufferToImage3DDecompressComputePipelineState[needsTempBuff ? 1 : 0], newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(needsTempBuff, _commandPool));
} }
id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed) { id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed) {
MVK_ENC_REZ_ACCESS(_mtlDrawIndirectConvertBuffersComputePipelineState[indexed ? 1 : 0], newCmdDrawIndirectConvertBuffersMTLComputePipelineState(indexed, _commandPool)); 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) { id<MTLComputePipelineState> MVKCommandEncodingPool::getCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type) {
@ -179,10 +183,15 @@ void MVKCommandEncodingPool::destroyMetalResources() {
_mtlCopyBufferToImage3DDecompressComputePipelineState[0] = nil; _mtlCopyBufferToImage3DDecompressComputePipelineState[0] = nil;
_mtlCopyBufferToImage3DDecompressComputePipelineState[1] = nil; _mtlCopyBufferToImage3DDecompressComputePipelineState[1] = nil;
[_mtlDrawIndirectConvertBuffersComputePipelineState[0] release]; [_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] release];
[_mtlDrawIndirectConvertBuffersComputePipelineState[1] release]; [_mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] release];
_mtlDrawIndirectConvertBuffersComputePipelineState[0] = nil; _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[0] = nil;
_mtlDrawIndirectConvertBuffersComputePipelineState[1] = nil; _mtlDrawIndirectMultiviewConvertBuffersComputePipelineState[1] = nil;
[_mtlDrawIndirectTessConvertBuffersComputePipelineState[0] release];
[_mtlDrawIndirectTessConvertBuffersComputePipelineState[1] release];
_mtlDrawIndirectTessConvertBuffersComputePipelineState[0] = nil;
_mtlDrawIndirectTessConvertBuffersComputePipelineState[1] = nil;
[_mtlDrawIndexedCopyIndexBufferComputePipelineState[0] release]; [_mtlDrawIndexedCopyIndexBufferComputePipelineState[0] release];
[_mtlDrawIndexedCopyIndexBufferComputePipelineState[1] release]; [_mtlDrawIndexedCopyIndexBufferComputePipelineState[1] release];

View File

@ -170,17 +170,41 @@ struct MTLStageInRegionIndirectArguments {
}; \n\ }; \n\
#endif \n\ #endif \n\
\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\ #if __METAL_VERSION__ >= 120 \n\
kernel void cmdDrawIndirectConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\ kernel void cmdDrawIndirectTessConvertBuffers(const device char* srcBuff [[buffer(0)]], \n\
device char* destBuff [[buffer(1)]], \n\ device char* destBuff [[buffer(1)]], \n\
device char* paramsBuff [[buffer(2)]], \n\ device char* paramsBuff [[buffer(2)]], \n\
constant uint32_t& srcStride [[buffer(3)]], \n\ constant uint32_t& srcStride [[buffer(3)]], \n\
constant uint32_t& inControlPointCount [[buffer(4)]], \n\ constant uint32_t& inControlPointCount [[buffer(4)]], \n\
constant uint32_t& outControlPointCount [[buffer(5)]], \n\ constant uint32_t& outControlPointCount [[buffer(5)]], \n\
constant uint32_t& drawCount [[buffer(6)]], \n\ constant uint32_t& drawCount [[buffer(6)]], \n\
constant uint32_t& vtxThreadExecWidth [[buffer(7)]], \n\ constant uint32_t& vtxThreadExecWidth [[buffer(7)]], \n\
constant uint32_t& tcWorkgroupSize [[buffer(8)]], \n\ constant uint32_t& tcWorkgroupSize [[buffer(8)]], \n\
uint idx [[thread_position_in_grid]]) { \n\ uint idx [[thread_position_in_grid]]) { \n\
if (idx >= drawCount) { return; } \n\ if (idx >= drawCount) { return; } \n\
const device auto& src = *reinterpret_cast<const device MTLDrawPrimitivesIndirectArguments*>(srcBuff + idx * srcStride);\n\ const device auto& src = *reinterpret_cast<const device MTLDrawPrimitivesIndirectArguments*>(srcBuff + idx * srcStride);\n\
device char* dest; \n\ device char* dest; \n\

View File

@ -421,9 +421,13 @@ public:
id<MTLComputePipelineState> newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needTempBuf, id<MTLComputePipelineState> newCmdCopyBufferToImage3DDecompressMTLComputePipelineState(bool needTempBuf,
MVKVulkanAPIDeviceObject* owner); 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. */ /** Returns a new MTLComputePipelineState for converting an indirect buffer for use in a tessellated draw. */
id<MTLComputePipelineState> newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed, id<MTLComputePipelineState> newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed,
MVKVulkanAPIDeviceObject* owner); MVKVulkanAPIDeviceObject* owner);
/** Returns a new MTLComputePipelineState for copying an index buffer for use in a tessellated draw. */ /** Returns a new MTLComputePipelineState for copying an index buffer for use in a tessellated draw. */
id<MTLComputePipelineState> newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type, id<MTLComputePipelineState> newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type,

View File

@ -417,11 +417,18 @@ id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdCopyBufferToImage3D
: "cmdCopyBufferToImage3DDecompressDXTn", owner); : "cmdCopyBufferToImage3DDecompressDXTn", owner);
} }
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndirectConvertBuffersMTLComputePipelineState(bool indexed, id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndirectMultiviewConvertBuffersMTLComputePipelineState(bool indexed,
MVKVulkanAPIDeviceObject* owner) { MVKVulkanAPIDeviceObject* owner) {
return newMTLComputePipelineState(indexed return newMTLComputePipelineState(indexed
? "cmdDrawIndexedIndirectConvertBuffers" ? "cmdDrawIndexedIndirectMultiviewConvertBuffers"
: "cmdDrawIndirectConvertBuffers", owner); : "cmdDrawIndirectMultiviewConvertBuffers", owner);
}
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndirectTessConvertBuffersMTLComputePipelineState(bool indexed,
MVKVulkanAPIDeviceObject* owner) {
return newMTLComputePipelineState(indexed
? "cmdDrawIndexedIndirectTessConvertBuffers"
: "cmdDrawIndirectTessConvertBuffers", owner);
} }
id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type, id<MTLComputePipelineState> MVKCommandResourceFactory::newCmdDrawIndexedCopyIndexBufferMTLComputePipelineState(MTLIndexType type,

View File

@ -17,6 +17,7 @@
*/ */
#include "MVKDescriptorSet.h" #include "MVKDescriptorSet.h"
#include "MVKInstance.h"
#include "MVKOSExtensions.h" #include "MVKOSExtensions.h"
@ -554,7 +555,8 @@ VkResult MVKDescriptorPool::allocateDescriptorSets(uint32_t count,
const VkDescriptorSetLayout* pSetLayouts, const VkDescriptorSetLayout* pSetLayouts,
VkDescriptorSet* pDescriptorSets) { VkDescriptorSet* pDescriptorSets) {
if (_allocatedSets.size() + count > _maxSets) { 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. return VK_ERROR_OUT_OF_POOL_MEMORY; // Failure is an acceptable test...don't log as error.
} else { } else {
return reportError(VK_ERROR_INITIALIZATION_FAILED, "The maximum number of descriptor sets that can be allocated by this descriptor pool is %d.", _maxSets); 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::allocateDescriptorSets(uint32_t count,
VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets) { VkResult MVKDescriptorPool::freeDescriptorSets(uint32_t count, const VkDescriptorSet* pDescriptorSets) {
for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) { for (uint32_t dsIdx = 0; dsIdx < count; dsIdx++) {
MVKDescriptorSet* mvkDS = (MVKDescriptorSet*)pDescriptorSets[dsIdx]; MVKDescriptorSet* mvkDS = (MVKDescriptorSet*)pDescriptorSets[dsIdx];
freeDescriptorSet(mvkDS); if (_allocatedSets.erase(mvkDS)) {
_allocatedSets.erase(mvkDS); freeDescriptorSet(mvkDS);
}
} }
return VK_SUCCESS; return VK_SUCCESS;
} }

View File

@ -137,6 +137,14 @@ public:
void getExternalBufferProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, void getExternalBufferProperties(const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
VkExternalBufferProperties* pExternalBufferProperties); 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 #pragma mark Surfaces
/** /**
@ -297,6 +305,9 @@ public:
/** Populates the specified structure with the Metal-specific features of this device. */ /** Populates the specified structure with the Metal-specific features of this device. */
inline const MVKPhysicalDeviceMetalFeatures* getMetalFeatures() { return &_metalFeatures; } 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. */ /** Returns the underlying Metal device. */
inline id<MTLDevice> getMTLDevice() { return _mtlDevice; } inline id<MTLDevice> getMTLDevice() { return _mtlDevice; }
@ -415,6 +426,9 @@ public:
/** Returns the queue at the specified index within the specified family. */ /** Returns the queue at the specified index within the specified family. */
MVKQueue* getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex); 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. */ /** Retrieves the queue at the lowest queue and queue family indices used by the app. */
MVKQueue* getAnyQueue(); MVKQueue* getAnyQueue();
@ -549,6 +563,8 @@ public:
MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo* pCreateInfo, MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator); const VkAllocationCallbacks* pAllocator);
MVKRenderPass* createRenderPass(const VkRenderPassCreateInfo2* pCreateInfo,
const VkAllocationCallbacks* pAllocator);
void destroyRenderPass(MVKRenderPass* mvkRP, void destroyRenderPass(MVKRenderPass* mvkRP,
const VkAllocationCallbacks* pAllocator); const VkAllocationCallbacks* pAllocator);

View File

@ -91,6 +91,28 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
f16Features->shaderInt8 = true; f16Features->shaderInt8 = true;
break; 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: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_UNIFORM_BUFFER_STANDARD_LAYOUT_FEATURES_KHR: {
auto* uboLayoutFeatures = (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR*)next; auto* uboLayoutFeatures = (VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR*)next;
uboLayoutFeatures->uniformBufferStandardLayout = true; uboLayoutFeatures->uniformBufferStandardLayout = true;
@ -151,11 +173,6 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) {
portabilityFeatures->samplerMipLodBias = false; portabilityFeatures->samplerMipLodBias = false;
break; 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: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_FUNCTIONS_2_FEATURES_INTEL: {
auto* shaderIntFuncsFeatures = (VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL*)next; auto* shaderIntFuncsFeatures = (VkPhysicalDeviceShaderIntegerFunctions2FeaturesINTEL*)next;
shaderIntFuncsFeatures->shaderIntegerFunctions2 = true; shaderIntFuncsFeatures->shaderIntegerFunctions2 = true;
@ -182,9 +199,19 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
properties->properties = _properties; properties->properties = _properties;
for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) { for (auto* next = (VkBaseOutStructure*)properties->pNext; next; next = next->pNext) {
switch ((uint32_t)next->sType) { switch ((uint32_t)next->sType) {
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: {
auto* pointClipProps = (VkPhysicalDevicePointClippingProperties*)next; auto* physicalDeviceDriverProps = (VkPhysicalDeviceDriverPropertiesKHR*)next;
pointClipProps->pointClippingBehavior = VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES; 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; break;
} }
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES: {
@ -193,51 +220,31 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize; maint3Props->maxMemoryAllocationSize = _metalFeatures.maxMTLBufferSize;
break; 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: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR: {
auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next; auto* pushDescProps = (VkPhysicalDevicePushDescriptorPropertiesKHR*)next;
pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources; pushDescProps->maxPushDescriptors = _properties.limits.maxPerStageResources;
break; 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 #if MVK_MACOS
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES: case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES:
if (mvkOSVersionIsAtLeast(10.14)) { if (mvkOSVersionIsAtLeast(10.14)) {
@ -260,15 +267,40 @@ void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties2* properties) {
} }
break; break;
#endif #endif
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: { case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT: {
auto* physicalDeviceDriverProps = (VkPhysicalDeviceDriverPropertiesKHR*)next; auto* inlineUniformBlockProps = (VkPhysicalDeviceInlineUniformBlockPropertiesEXT*)next;
strcpy(physicalDeviceDriverProps->driverName, "MoltenVK"); inlineUniformBlockProps->maxInlineUniformBlockSize = _metalFeatures.dynamicMTLBufferSize;
strcpy(physicalDeviceDriverProps->driverInfo, mvkGetMoltenVKVersionString(MVK_VERSION).c_str()); inlineUniformBlockProps->maxPerStageDescriptorInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
physicalDeviceDriverProps->driverID = VK_DRIVER_ID_MOLTENVK; inlineUniformBlockProps->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = _properties.limits.maxPerStageDescriptorUniformBuffers;
physicalDeviceDriverProps->conformanceVersion.major = 0; inlineUniformBlockProps->maxDescriptorSetInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
physicalDeviceDriverProps->conformanceVersion.minor = 0; inlineUniformBlockProps->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = _properties.limits.maxDescriptorSetUniformBuffers;
physicalDeviceDriverProps->conformanceVersion.subminor = 0; break;
physicalDeviceDriverProps->conformanceVersion.patch = 0; }
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; break;
} }
default: default:
@ -577,6 +609,24 @@ VkExternalMemoryProperties& MVKPhysicalDevice::getExternalImageProperties(VkExte
} }
} }
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 #pragma mark Surfaces
@ -2335,10 +2385,11 @@ MVKPhysicalDevice::~MVKPhysicalDevice() {
// Returns core device commands and enabled extension device commands. // Returns core device commands and enabled extension device commands.
PFN_vkVoidFunction MVKDevice::getProcAddr(const char* pName) { PFN_vkVoidFunction MVKDevice::getProcAddr(const char* pName) {
MVKEntryPoint* pMVKPA = _physicalDevice->_mvkInstance->getEntryPoint(pName); MVKEntryPoint* pMVKPA = _physicalDevice->_mvkInstance->getEntryPoint(pName);
uint32_t apiVersion = _physicalDevice->_mvkInstance->_appInfo.apiVersion;
bool isSupported = (pMVKPA && // Command exists and... bool isSupported = (pMVKPA && // Command exists and...
pMVKPA->isDevice && // ...is a device command and... pMVKPA->isDevice && // ...is a device command and...
pMVKPA->isEnabled(_enabledExtensions)); // ...is a core or enabled extension command. pMVKPA->isEnabled(apiVersion, _enabledExtensions)); // ...is a core or enabled extension command.
return isSupported ? pMVKPA->functionPointer : nullptr; return isSupported ? pMVKPA->functionPointer : nullptr;
} }
@ -2347,6 +2398,10 @@ MVKQueue* MVKDevice::getQueue(uint32_t queueFamilyIndex, uint32_t queueIndex) {
return _queuesByQueueFamilyIndex[queueFamilyIndex][queueIndex]; return _queuesByQueueFamilyIndex[queueFamilyIndex][queueIndex];
} }
MVKQueue* MVKDevice::getQueue(const VkDeviceQueueInfo2* queueInfo) {
return _queuesByQueueFamilyIndex[queueInfo->queueFamilyIndex][queueInfo->queueIndex];
}
MVKQueue* MVKDevice::getAnyQueue() { MVKQueue* MVKDevice::getAnyQueue() {
for (auto& queues : _queuesByQueueFamilyIndex) { for (auto& queues : _queuesByQueueFamilyIndex) {
for (MVKQueue* q : queues) { for (MVKQueue* q : queues) {
@ -2741,6 +2796,11 @@ MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo* pCreate
return new MVKRenderPass(this, pCreateInfo); return new MVKRenderPass(this, pCreateInfo);
} }
MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo2* pCreateInfo,
const VkAllocationCallbacks* pAllocator) {
return new MVKRenderPass(this, pCreateInfo);
}
void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP, void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP,
const VkAllocationCallbacks* pAllocator) { const VkAllocationCallbacks* pAllocator) {
if (mvkRP) { mvkRP->destroy(); } if (mvkRP) { mvkRP->destroy(); }

View File

@ -37,13 +37,15 @@ class MVKDebugUtilsMessenger;
/** Tracks info about entry point function pointer addresses. */ /** Tracks info about entry point function pointer addresses. */
typedef struct { typedef struct {
PFN_vkVoidFunction functionPointer; PFN_vkVoidFunction functionPointer;
uint32_t apiVersion;
const char* ext1Name; const char* ext1Name;
const char* ext2Name; const char* ext2Name;
bool isDevice; bool isDevice;
bool isCore() { return !ext1Name && !ext2Name; } bool isCore() { return !ext1Name && !ext2Name; }
bool isEnabled(const MVKExtensionList& extList) { bool isEnabled(uint32_t enabledVersion, const MVKExtensionList& extList) {
return isCore() || extList.isEnabled(ext1Name) || extList.isEnabled(ext2Name); return (isCore() && MVK_VULKAN_API_VERSION_CONFORM(enabledVersion) >= apiVersion) ||
extList.isEnabled(ext1Name) || extList.isEnabled(ext2Name);
} }
} MVKEntryPoint; } MVKEntryPoint;
@ -65,6 +67,9 @@ public:
/** Returns a pointer to the Vulkan instance. */ /** Returns a pointer to the Vulkan instance. */
MVKInstance* getInstance() override { return this; } 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. */ /** Returns a pointer to the layer manager. */
inline MVKLayerManager* getLayerManager() { return MVKLayerManager::globalManager(); } inline MVKLayerManager* getLayerManager() { return MVKLayerManager::globalManager(); }

View File

@ -39,9 +39,9 @@ MVKEntryPoint* MVKInstance::getEntryPoint(const char* pName) {
PFN_vkVoidFunction MVKInstance::getProcAddr(const char* pName) { PFN_vkVoidFunction MVKInstance::getProcAddr(const char* pName) {
MVKEntryPoint* pMVKPA = getEntryPoint(pName); MVKEntryPoint* pMVKPA = getEntryPoint(pName);
bool isSupported = (pMVKPA && // Command exists and... bool isSupported = (pMVKPA && // Command exists and...
(pMVKPA->isDevice || // ...is a device command or... (pMVKPA->isDevice || // ...is a device command or...
pMVKPA->isEnabled(_enabledExtensions))); // ...is a core or enabled extension command. pMVKPA->isEnabled(_appInfo.apiVersion, _enabledExtensions))); // ...is a core or enabled extension command.
return isSupported ? pMVKPA->functionPointer : nullptr; return isSupported ? pMVKPA->functionPointer : nullptr;
} }
@ -336,8 +336,8 @@ MVKInstance::MVKInstance(const VkInstanceCreateInfo* pCreateInfo) : _enabledExte
initDebugCallbacks(pCreateInfo); // Do before any creation activities initDebugCallbacks(pCreateInfo); // Do before any creation activities
_appInfo.apiVersion = MVK_VULKAN_API_VERSION; // Default
mvkSetOrClear(&_appInfo, pCreateInfo->pApplicationInfo); mvkSetOrClear(&_appInfo, pCreateInfo->pApplicationInfo);
if (_appInfo.apiVersion == 0) { _appInfo.apiVersion = VK_API_VERSION_1_0; } // Default
initProcAddrs(); // Init function pointers initProcAddrs(); // Init function pointers
initConfig(); initConfig();
@ -349,18 +349,6 @@ MVKInstance::MVKInstance(const VkInstanceCreateInfo* pCreateInfo) : _enabledExte
getDriverLayer()->getSupportedInstanceExtensions())); getDriverLayer()->getSupportedInstanceExtensions()));
logVersions(); // Log the MoltenVK and Vulkan versions 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. // Populate the array of physical GPU devices.
// This effort creates a number of autoreleased instances of Metal // This effort creates a number of autoreleased instances of Metal
// and other Obj-C classes, so wrap it all in an autorelease pool. // and other Obj-C classes, so wrap it all in an autorelease pool.
@ -403,16 +391,19 @@ void MVKInstance::initDebugCallbacks(const VkInstanceCreateInfo* pCreateInfo) {
} }
} }
#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_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, nullptr, nullptr, true) #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_INST_1_1_ENTRY_POINT(func) ADD_ENTRY_POINT(func, VK_API_VERSION_1_1, nullptr, nullptr, false)
#define ADD_DVC_EXT_ENTRY_POINT(func, EXT) ADD_ENTRY_POINT(func, VK_ ##EXT ##_EXTENSION_NAME, nullptr, true) #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_INST_EXT_ENTRY_POINT(func, EXT) ADD_ENTRY_POINT(func, 0, VK_ ##EXT ##_EXTENSION_NAME, nullptr, 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_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. // Initializes the function pointer map.
void MVKInstance::initProcAddrs() { void MVKInstance::initProcAddrs() {
@ -432,6 +423,18 @@ void MVKInstance::initProcAddrs() {
ADD_INST_ENTRY_POINT(vkEnumerateDeviceLayerProperties); ADD_INST_ENTRY_POINT(vkEnumerateDeviceLayerProperties);
ADD_INST_ENTRY_POINT(vkGetPhysicalDeviceSparseImageFormatProperties); 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: // Device functions:
ADD_DVC_ENTRY_POINT(vkGetDeviceProcAddr); ADD_DVC_ENTRY_POINT(vkGetDeviceProcAddr);
ADD_DVC_ENTRY_POINT(vkDestroyDevice); ADD_DVC_ENTRY_POINT(vkDestroyDevice);
@ -555,8 +558,28 @@ void MVKInstance::initProcAddrs() {
ADD_DVC_ENTRY_POINT(vkCmdEndRenderPass); ADD_DVC_ENTRY_POINT(vkCmdEndRenderPass);
ADD_DVC_ENTRY_POINT(vkCmdExecuteCommands); 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: // Instance extension functions:
ADD_INST_EXT_ENTRY_POINT(vkEnumeratePhysicalDeviceGroupsKHR, KHR_DEVICE_GROUP_CREATION); 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(vkGetPhysicalDeviceFeatures2KHR, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2);
ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceProperties2KHR, 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); ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceFormatProperties2KHR, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2);
@ -609,6 +632,10 @@ void MVKInstance::initProcAddrs() {
// Device extension functions: // Device extension functions:
ADD_DVC_EXT_ENTRY_POINT(vkBindBufferMemory2KHR, KHR_BIND_MEMORY_2); 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(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(vkCreateDescriptorUpdateTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE);
ADD_DVC_EXT_ENTRY_POINT(vkDestroyDescriptorUpdateTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE); ADD_DVC_EXT_ENTRY_POINT(vkDestroyDescriptorUpdateTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE);
ADD_DVC_EXT_ENTRY_POINT(vkUpdateDescriptorSetWithTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE); ADD_DVC_EXT_ENTRY_POINT(vkUpdateDescriptorSetWithTemplateKHR, KHR_DESCRIPTOR_UPDATE_TEMPLATE);

View File

@ -25,6 +25,7 @@
#include "MVKSmallVector.h" #include "MVKSmallVector.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVReflection.h> #include <MoltenVKSPIRVToMSLConverter/SPIRVReflection.h>
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h> #include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <ostream> #include <ostream>
@ -78,6 +79,9 @@ public:
/** Returns the current buffer size buffer bindings. */ /** Returns the current buffer size buffer bindings. */
const MVKShaderImplicitRezBinding& getBufferSizeBufferIndex() { return _bufferSizeBufferIndex; } 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. */ /** Returns the current indirect parameter buffer bindings. */
const MVKShaderImplicitRezBinding& getIndirectParamsIndex() { return _indirectParamsIndex; } const MVKShaderImplicitRezBinding& getIndirectParamsIndex() { return _indirectParamsIndex; }
@ -113,6 +117,7 @@ protected:
MVKShaderResourceBinding _pushConstantsMTLResourceIndexes; MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
MVKShaderImplicitRezBinding _swizzleBufferIndex; MVKShaderImplicitRezBinding _swizzleBufferIndex;
MVKShaderImplicitRezBinding _bufferSizeBufferIndex; MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
MVKShaderImplicitRezBinding _viewRangeBufferIndex;
MVKShaderImplicitRezBinding _indirectParamsIndex; MVKShaderImplicitRezBinding _indirectParamsIndex;
MVKShaderImplicitRezBinding _outputBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex;
uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlPatchOutputBufferIndex = 0;
@ -282,6 +287,7 @@ protected:
bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& prevOutput); bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& prevOutput);
template<class T> template<class T>
bool addVertexInputToPipeline(T* inputDesc, const VkPipelineVertexInputStateCreateInfo* pVI, const SPIRVToMSLConversionConfiguration& shaderContext); 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 addTessellationToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkPipelineTessellationStateCreateInfo* pTS);
void addFragmentOutputToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo); void addFragmentOutputToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo);
bool isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo); bool isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo);
@ -309,6 +315,7 @@ protected:
id<MTLComputePipelineState> _mtlTessVertexStageIndex32State = nil; id<MTLComputePipelineState> _mtlTessVertexStageIndex32State = nil;
id<MTLComputePipelineState> _mtlTessControlStageState = nil; id<MTLComputePipelineState> _mtlTessControlStageState = nil;
id<MTLRenderPipelineState> _mtlPipelineState = nil; id<MTLRenderPipelineState> _mtlPipelineState = nil;
std::unordered_map<uint32_t, id<MTLRenderPipelineState>> _multiviewMTLPipelineStates;
MTLCullMode _mtlCullMode; MTLCullMode _mtlCullMode;
MTLWinding _mtlFrontWinding; MTLWinding _mtlFrontWinding;
MTLTriangleFillMode _mtlFillMode; MTLTriangleFillMode _mtlFillMode;
@ -317,6 +324,7 @@ protected:
float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 }; float _blendConstants[4] = { 0.0, 0.0, 0.0, 1.0 };
uint32_t _outputControlPointCount; uint32_t _outputControlPointCount;
MVKShaderImplicitRezBinding _viewRangeBufferIndex;
MVKShaderImplicitRezBinding _outputBufferIndex; MVKShaderImplicitRezBinding _outputBufferIndex;
uint32_t _tessCtlPatchOutputBufferIndex = 0; uint32_t _tessCtlPatchOutputBufferIndex = 0;
uint32_t _tessCtlLevelBufferIndex = 0; uint32_t _tessCtlLevelBufferIndex = 0;
@ -325,6 +333,7 @@ protected:
bool _hasDepthStencilInfo; bool _hasDepthStencilInfo;
bool _needsVertexSwizzleBuffer = false; bool _needsVertexSwizzleBuffer = false;
bool _needsVertexBufferSizeBuffer = false; bool _needsVertexBufferSizeBuffer = false;
bool _needsVertexViewRangeBuffer = false;
bool _needsVertexOutputBuffer = false; bool _needsVertexOutputBuffer = false;
bool _needsTessCtlSwizzleBuffer = false; bool _needsTessCtlSwizzleBuffer = false;
bool _needsTessCtlBufferSizeBuffer = false; bool _needsTessCtlBufferSizeBuffer = false;
@ -335,6 +344,7 @@ protected:
bool _needsTessEvalBufferSizeBuffer = false; bool _needsTessEvalBufferSizeBuffer = false;
bool _needsFragmentSwizzleBuffer = false; bool _needsFragmentSwizzleBuffer = false;
bool _needsFragmentBufferSizeBuffer = false; bool _needsFragmentBufferSizeBuffer = false;
bool _needsFragmentViewRangeBuffer = false;
}; };

View File

@ -149,6 +149,10 @@ MVKPipelineLayout::MVKPipelineLayout(MVKDevice* device,
_tessCtlLevelBufferIndex = _tessCtlPatchOutputBufferIndex + 1; _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() { MVKPipelineLayout::~MVKPipelineLayout() {
@ -232,7 +236,11 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
if ( !_mtlPipelineState ) { return; } // Abort if pipeline could not be created. if ( !_mtlPipelineState ) { return; } // Abort if pipeline could not be created.
// Render pipeline state // 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 // Depth stencil state
if (_hasDepthStencilInfo) { if (_hasDepthStencilInfo) {
@ -263,6 +271,7 @@ void MVKGraphicsPipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t stage)
} }
cmdEncoder->_graphicsResourcesState.bindSwizzleBuffer(_swizzleBufferIndex, _needsVertexSwizzleBuffer, _needsTessCtlSwizzleBuffer, _needsTessEvalSwizzleBuffer, _needsFragmentSwizzleBuffer); cmdEncoder->_graphicsResourcesState.bindSwizzleBuffer(_swizzleBufferIndex, _needsVertexSwizzleBuffer, _needsTessCtlSwizzleBuffer, _needsTessEvalSwizzleBuffer, _needsFragmentSwizzleBuffer);
cmdEncoder->_graphicsResourcesState.bindBufferSizeBuffer(_bufferSizeBufferIndex, _needsVertexBufferSizeBuffer, _needsTessCtlBufferSizeBuffer, _needsTessEvalBufferSizeBuffer, _needsFragmentBufferSizeBuffer); cmdEncoder->_graphicsResourcesState.bindBufferSizeBuffer(_bufferSizeBufferIndex, _needsVertexBufferSizeBuffer, _needsTessCtlBufferSizeBuffer, _needsTessEvalBufferSizeBuffer, _needsFragmentBufferSizeBuffer);
cmdEncoder->_graphicsResourcesState.bindViewRangeBuffer(_viewRangeBufferIndex, _needsVertexViewRangeBuffer, _needsFragmentViewRangeBuffer);
} }
bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) { bool MVKGraphicsPipeline::supportsDynamicState(VkDynamicState state) {
@ -468,7 +477,35 @@ void MVKGraphicsPipeline::initMTLRenderPipelineState(const VkGraphicsPipelineCre
if (!isTessellationPipeline()) { if (!isTessellationPipeline()) {
MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData); // temp retain MTLRenderPipelineDescriptor* plDesc = newMTLRenderPipelineDescriptor(pCreateInfo, reflectData); // temp retain
if (plDesc) { 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 [plDesc release]; // temp release
} else { } else {
@ -816,8 +853,9 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor*
shaderContext.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageVertex]; shaderContext.options.mslOptions.indirect_params_buffer_index = _indirectParamsIndex.stages[kMVKShaderStageVertex];
shaderContext.options.mslOptions.shader_output_buffer_index = _outputBufferIndex.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.buffer_size_buffer_index = _bufferSizeBufferIndex.stages[kMVKShaderStageVertex];
shaderContext.options.mslOptions.capture_output_to_buffer = isTessellationPipeline(); shaderContext.options.mslOptions.view_mask_buffer_index = _viewRangeBufferIndex.stages[kMVKShaderStageVertex];
shaderContext.options.mslOptions.disable_rasterization = isTessellationPipeline() || (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->rasterizerDiscardEnable)); shaderContext.options.mslOptions.capture_output_to_buffer = false;
shaderContext.options.mslOptions.disable_rasterization = pCreateInfo->pRasterizationState && pCreateInfo->pRasterizationState->rasterizerDiscardEnable;
addVertexInputToShaderConverterContext(shaderContext, pCreateInfo); addVertexInputToShaderConverterContext(shaderContext, pCreateInfo);
MVKMTLFunction func = ((MVKShaderModule*)_pVertexSS->module)->getMTLFunction(&shaderContext, _pVertexSS->pSpecializationInfo, _pipelineCache); MVKMTLFunction func = ((MVKShaderModule*)_pVertexSS->module)->getMTLFunction(&shaderContext, _pVertexSS->pSpecializationInfo, _pipelineCache);
@ -832,6 +870,7 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor*
plDesc.rasterizationEnabled = !funcRslts.isRasterizationDisabled; plDesc.rasterizationEnabled = !funcRslts.isRasterizationDisabled;
_needsVertexSwizzleBuffer = funcRslts.needsSwizzleBuffer; _needsVertexSwizzleBuffer = funcRslts.needsSwizzleBuffer;
_needsVertexBufferSizeBuffer = funcRslts.needsBufferSizeBuffer; _needsVertexBufferSizeBuffer = funcRslts.needsBufferSizeBuffer;
_needsVertexViewRangeBuffer = funcRslts.needsViewRangeBuffer;
_needsVertexOutputBuffer = funcRslts.needsOutputBuffer; _needsVertexOutputBuffer = funcRslts.needsOutputBuffer;
// If we need the swizzle buffer and there's no place to put it, we're in serious trouble. // If we need the swizzle buffer and there's no place to put it, we're in serious trouble.
@ -849,6 +888,9 @@ bool MVKGraphicsPipeline::addVertexShaderToPipeline(MTLRenderPipelineDescriptor*
if (!verifyImplicitBuffer(_needsVertexOutputBuffer, _indirectParamsIndex, kMVKShaderStageVertex, "indirect parameters", vbCnt)) { if (!verifyImplicitBuffer(_needsVertexOutputBuffer, _indirectParamsIndex, kMVKShaderStageVertex, "indirect parameters", vbCnt)) {
return false; return false;
} }
if (!verifyImplicitBuffer(_needsVertexViewRangeBuffer, _viewRangeBufferIndex, kMVKShaderStageVertex, "view range", vbCnt)) {
return false;
}
return true; return true;
} }
@ -1006,6 +1048,7 @@ bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescripto
shaderContext.options.entryPointStage = spv::ExecutionModelFragment; shaderContext.options.entryPointStage = spv::ExecutionModelFragment;
shaderContext.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageFragment]; shaderContext.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageFragment];
shaderContext.options.mslOptions.buffer_size_buffer_index = _bufferSizeBufferIndex.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.entryPointName = _pFragmentSS->pName;
shaderContext.options.mslOptions.capture_output_to_buffer = false; shaderContext.options.mslOptions.capture_output_to_buffer = false;
if (pCreateInfo->pMultisampleState && pCreateInfo->pMultisampleState->pSampleMask && pCreateInfo->pMultisampleState->pSampleMask[0] != 0xffffffff) { if (pCreateInfo->pMultisampleState && pCreateInfo->pMultisampleState->pSampleMask && pCreateInfo->pMultisampleState->pSampleMask[0] != 0xffffffff) {
@ -1024,12 +1067,16 @@ bool MVKGraphicsPipeline::addFragmentShaderToPipeline(MTLRenderPipelineDescripto
auto& funcRslts = func.shaderConversionResults; auto& funcRslts = func.shaderConversionResults;
_needsFragmentSwizzleBuffer = funcRslts.needsSwizzleBuffer; _needsFragmentSwizzleBuffer = funcRslts.needsSwizzleBuffer;
_needsFragmentBufferSizeBuffer = funcRslts.needsBufferSizeBuffer; _needsFragmentBufferSizeBuffer = funcRslts.needsBufferSizeBuffer;
_needsFragmentViewRangeBuffer = funcRslts.needsViewRangeBuffer;
if (!verifyImplicitBuffer(_needsFragmentSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageFragment, "swizzle", 0)) { if (!verifyImplicitBuffer(_needsFragmentSwizzleBuffer, _swizzleBufferIndex, kMVKShaderStageFragment, "swizzle", 0)) {
return false; return false;
} }
if (!verifyImplicitBuffer(_needsFragmentBufferSizeBuffer, _bufferSizeBufferIndex, kMVKShaderStageFragment, "buffer size", 0)) { if (!verifyImplicitBuffer(_needsFragmentBufferSizeBuffer, _bufferSizeBufferIndex, kMVKShaderStageFragment, "buffer size", 0)) {
return false; return false;
} }
if (!verifyImplicitBuffer(_needsFragmentViewRangeBuffer, _viewRangeBufferIndex, kMVKShaderStageFragment, "view range", 0)) {
return false;
}
} }
return true; return true;
} }
@ -1182,6 +1229,24 @@ template bool MVKGraphicsPipeline::addVertexInputToPipeline<MTLStageInputOutputD
const VkPipelineVertexInputStateCreateInfo* pVI, const VkPipelineVertexInputStateCreateInfo* pVI,
const SPIRVToMSLConversionConfiguration& shaderContext); 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. // 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) { 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). // See if a translated binding already exists (for example if more than one VA needs the same translation).
@ -1323,6 +1388,7 @@ void MVKGraphicsPipeline::initMVKShaderConverterContext(SPIRVToMSLConversionConf
_outputBufferIndex = layout->getOutputBufferIndex(); _outputBufferIndex = layout->getOutputBufferIndex();
_tessCtlPatchOutputBufferIndex = layout->getTessCtlPatchOutputBufferIndex(); _tessCtlPatchOutputBufferIndex = layout->getTessCtlPatchOutputBufferIndex();
_tessCtlLevelBufferIndex = layout->getTessCtlLevelBufferIndex(); _tessCtlLevelBufferIndex = layout->getTessCtlLevelBufferIndex();
_viewRangeBufferIndex = layout->getViewRangeBufferIndex();
MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass; MVKRenderPass* mvkRendPass = (MVKRenderPass*)pCreateInfo->renderPass;
MVKRenderSubpass* mvkRenderSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass); MVKRenderSubpass* mvkRenderSubpass = mvkRendPass->getSubpass(pCreateInfo->subpass);
@ -1345,6 +1411,9 @@ void MVKGraphicsPipeline::initMVKShaderConverterContext(SPIRVToMSLConversionConf
shaderContext.options.shouldFlipVertexY = _device->_pMVKConfig->shaderConversionFlipVertexY; shaderContext.options.shouldFlipVertexY = _device->_pMVKConfig->shaderConversionFlipVertexY;
shaderContext.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle; 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.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.tessPatchKind = reflectData.patchKind;
shaderContext.options.numTessControlPoints = reflectData.numControlPoints; shaderContext.options.numTessControlPoints = reflectData.numControlPoints;
@ -1481,7 +1550,7 @@ MVKComputePipeline::MVKComputePipeline(MVKDevice* device,
const VkComputePipelineCreateInfo* pCreateInfo) : const VkComputePipelineCreateInfo* pCreateInfo) :
MVKPipeline(device, pipelineCache, (MVKPipelineLayout*)pCreateInfo->layout, parent) { 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); MVKMTLFunction func = getMTLFunction(pCreateInfo);
_mtlThreadgroupSize = func.threadGroupSize; _mtlThreadgroupSize = func.threadGroupSize;
@ -1815,6 +1884,7 @@ namespace SPIRV_CROSS_NAMESPACE {
opt.swizzle_texture_samples, opt.swizzle_texture_samples,
opt.tess_domain_origin_lower_left, opt.tess_domain_origin_lower_left,
opt.multiview, opt.multiview,
opt.multiview_layered_rendering,
opt.view_index_from_device_index, opt.view_index_from_device_index,
opt.dispatch_base, opt.dispatch_base,
opt.texture_1D_as_2D, opt.texture_1D_as_2D,
@ -1942,7 +2012,8 @@ namespace mvk {
scr.needsPatchOutputBuffer, scr.needsPatchOutputBuffer,
scr.needsBufferSizeBuffer, scr.needsBufferSizeBuffer,
scr.needsInputThreadgroupMem, scr.needsInputThreadgroupMem,
scr.needsDispatchBaseBuffer); scr.needsDispatchBaseBuffer,
scr.needsViewRangeBuffer);
} }
} }

View File

@ -18,6 +18,7 @@
#include "MVKQueryPool.h" #include "MVKQueryPool.h"
#include "MVKBuffer.h" #include "MVKBuffer.h"
#include "MVKRenderPass.h"
#include "MVKCommandBuffer.h" #include "MVKCommandBuffer.h"
#include "MVKCommandEncodingPool.h" #include "MVKCommandEncodingPool.h"
#include "MVKOSExtensions.h" #include "MVKOSExtensions.h"
@ -30,8 +31,11 @@ using namespace std;
#pragma mark MVKQueryPool #pragma mark MVKQueryPool
void MVKQueryPool::endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder) { void MVKQueryPool::endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder) {
uint32_t queryCount = cmdEncoder->getSubpass()->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex());
lock_guard<mutex> lock(_availabilityLock); 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); lock_guard<mutex> copyLock(_deferredCopiesLock);
if (!_deferredCopies.empty()) { if (!_deferredCopies.empty()) {
// Partition by readiness. // Partition by readiness.
@ -287,7 +291,12 @@ void MVKOcclusionQueryPool::encodeSetResultBuffer(MVKCommandEncoder* cmdEncoder,
void MVKOcclusionQueryPool::beginQueryAddedTo(uint32_t query, MVKCommandBuffer* cmdBuffer) { void MVKOcclusionQueryPool::beginQueryAddedTo(uint32_t query, MVKCommandBuffer* cmdBuffer) {
NSUInteger offset = getVisibilityResultOffset(query); 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) { 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)); 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));
} }

View File

@ -46,6 +46,12 @@ public:
/** Returns the Vulkan API opaque object controlling this object. */ /** Returns the Vulkan API opaque object controlling this object. */
MVKVulkanAPIObject* getVulkanAPIObject() override; 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. */ /** Returns the number of color attachments, which may be zero for depth-only rendering. */
inline uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); } inline uint32_t getColorAttachmentCount() { return uint32_t(_colorAttachments.size()); }
@ -61,11 +67,31 @@ public:
/** Returns the Vulkan sample count of the attachments used in this subpass. */ /** Returns the Vulkan sample count of the attachments used in this subpass. */
VkSampleCountFlagBits getSampleCount(); 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 * 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, void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx,
MVKFramebuffer* framebuffer, MVKFramebuffer* framebuffer,
const MVKArrayRef<VkClearValue>& clearValues, const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment, bool isRenderingEntireAttachment,
@ -78,26 +104,42 @@ public:
void populateClearAttachments(MVKClearAttachments& clearAtts, void populateClearAttachments(MVKClearAttachments& clearAtts,
const MVKArrayRef<VkClearValue>& clearValues); 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. */ /** If a render encoder is active, sets the store actions for all attachments to it. */
void encodeStoreActions(MVKCommandEncoder* cmdEncoder, bool isRenderingEntireAttachment, bool storeOverride = false); void encodeStoreActions(MVKCommandEncoder* cmdEncoder, bool isRenderingEntireAttachment, bool storeOverride = false);
/** Constructs an instance for the specified parent renderpass. */ /** 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: private:
friend class MVKRenderPass; friend class MVKRenderPass;
friend class MVKRenderPassAttachment; friend class MVKRenderPassAttachment;
uint32_t getViewMaskGroupForMetalPass(uint32_t passIdx);
MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx); MVKMTLFmtCaps getRequiredFormatCapabilitiesForAttachmentAt(uint32_t rpAttIdx);
MVKRenderPass* _renderPass; MVKRenderPass* _renderPass;
uint32_t _subpassIndex; uint32_t _subpassIndex;
MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _inputAttachments; uint32_t _viewMask;
MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _colorAttachments; MVKSmallVector<VkAttachmentReference2, kMVKDefaultAttachmentCount> _inputAttachments;
MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _resolveAttachments; MVKSmallVector<VkAttachmentReference2, kMVKDefaultAttachmentCount> _colorAttachments;
MVKSmallVector<VkAttachmentReference2, kMVKDefaultAttachmentCount> _resolveAttachments;
MVKSmallVector<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments; MVKSmallVector<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
VkAttachmentReference _depthStencilAttachment; VkAttachmentReference2 _depthStencilAttachment;
id<MTLTexture> _mtlDummyTex = nil; id<MTLTexture> _mtlDummyTex = nil;
}; };
@ -139,6 +181,9 @@ public:
bool isStencil, bool isStencil,
bool storeOverride = false); 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. */ /** Returns whether this attachment should be cleared in the subpass. */
bool shouldUseClearAttachment(MVKRenderSubpass* subpass); bool shouldUseClearAttachment(MVKRenderSubpass* subpass);
@ -146,18 +191,27 @@ public:
MVKRenderPassAttachment(MVKRenderPass* renderPass, MVKRenderPassAttachment(MVKRenderPass* renderPass,
const VkAttachmentDescription* pCreateInfo); const VkAttachmentDescription* pCreateInfo);
/** Constructs an instance for the specified parent renderpass. */
MVKRenderPassAttachment(MVKRenderPass* renderPass,
const VkAttachmentDescription2* pCreateInfo);
protected: protected:
bool isFirstUseOfAttachment(MVKRenderSubpass* subpass);
bool isLastUseOfAttachment(MVKRenderSubpass* subpass);
MTLStoreAction getMTLStoreAction(MVKRenderSubpass* subpass, MTLStoreAction getMTLStoreAction(MVKRenderSubpass* subpass,
bool isRenderingEntireAttachment, bool isRenderingEntireAttachment,
bool hasResolveAttachment, bool hasResolveAttachment,
bool isStencil, bool isStencil,
bool storeOverride); bool storeOverride);
void validateFormat();
VkAttachmentDescription _info; VkAttachmentDescription2 _info;
MVKRenderPass* _renderPass; MVKRenderPass* _renderPass;
uint32_t _attachmentIndex; uint32_t _attachmentIndex;
uint32_t _firstUseSubpassIdx; uint32_t _firstUseSubpassIdx;
uint32_t _lastUseSubpassIdx; uint32_t _lastUseSubpassIdx;
MVKSmallVector<uint32_t> _firstUseViewMasks;
MVKSmallVector<uint32_t> _lastUseViewMasks;
}; };
@ -181,9 +235,15 @@ public:
/** Returns the format of the color attachment at the specified index. */ /** Returns the format of the color attachment at the specified index. */
MVKRenderSubpass* getSubpass(uint32_t subpassIndex); 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. */ /** Constructs an instance for the specified device. */
MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo* pCreateInfo); MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo* pCreateInfo);
/** Constructs an instance for the specified device. */
MVKRenderPass(MVKDevice* device, const VkRenderPassCreateInfo2* pCreateInfo);
protected: protected:
friend class MVKRenderSubpass; friend class MVKRenderSubpass;
friend class MVKRenderPassAttachment; friend class MVKRenderPassAttachment;
@ -192,7 +252,7 @@ protected:
MVKSmallVector<MVKRenderPassAttachment> _attachments; MVKSmallVector<MVKRenderPassAttachment> _attachments;
MVKSmallVector<MVKRenderSubpass> _subpasses; MVKSmallVector<MVKRenderSubpass> _subpasses;
MVKSmallVector<VkSubpassDependency> _subpassDependencies; MVKSmallVector<VkSubpassDependency2> _subpassDependencies;
}; };

View File

@ -21,6 +21,7 @@
#include "MVKCommandBuffer.h" #include "MVKCommandBuffer.h"
#include "MVKFoundation.h" #include "MVKFoundation.h"
#include "mvk_datatypes.hpp" #include "mvk_datatypes.hpp"
#include <cassert>
using namespace std; using namespace std;
@ -67,7 +68,109 @@ VkSampleCountFlagBits MVKRenderSubpass::getSampleCount() {
return VK_SAMPLE_COUNT_1_BIT; 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, void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
uint32_t passIdx,
MVKFramebuffer* framebuffer, MVKFramebuffer* framebuffer,
const MVKArrayRef<VkClearValue>& clearValues, const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment, bool isRenderingEntireAttachment,
@ -89,6 +192,15 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
bool hasResolveAttachment = (rslvRPAttIdx != VK_ATTACHMENT_UNUSED); bool hasResolveAttachment = (rslvRPAttIdx != VK_ATTACHMENT_UNUSED);
if (hasResolveAttachment) { if (hasResolveAttachment) {
framebuffer->getAttachment(rslvRPAttIdx)->populateMTLRenderPassAttachmentDescriptorResolve(mtlColorAttDesc); 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 // Configure the color attachment
@ -100,6 +212,13 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
loadOverride)) { loadOverride)) {
mtlColorAttDesc.clearColor = pixFmts->getMTLClearColor(clearValues[clrRPAttIdx], clrMVKRPAtt->getFormat()); 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 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
loadOverride)) { loadOverride)) {
mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[dsRPAttIdx]); mtlDepthAttDesc.clearDepth = pixFmts->getMTLClearDepthValue(clearValues[dsRPAttIdx]);
} }
if (isMultiview()) {
mtlDepthAttDesc.slice += getFirstViewIndexInMetalPass(passIdx);
}
} }
if (pixFmts->isStencilFormat(mtlDSFormat)) { if (pixFmts->isStencilFormat(mtlDSFormat)) {
MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment; MTLRenderPassStencilAttachmentDescriptor* mtlStencilAttDesc = mtlRPDesc.stencilAttachment;
@ -129,6 +251,9 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
loadOverride)) { loadOverride)) {
mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[dsRPAttIdx]); mtlStencilAttDesc.clearStencil = pixFmts->getMTLClearStencilValue(clearValues[dsRPAttIdx]);
} }
if (isMultiview()) {
mtlStencilAttDesc.slice += getFirstViewIndexInMetalPass(passIdx);
}
} }
} }
@ -145,7 +270,10 @@ void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor*
// Add a dummy attachment so this passes validation. // Add a dummy attachment so this passes validation.
VkExtent2D fbExtent = framebuffer->getExtent2D(); VkExtent2D fbExtent = framebuffer->getExtent2D();
MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: MTLPixelFormatR8Unorm width: fbExtent.width height: fbExtent.height mipmapped: NO]; 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.textureType = MTLTextureType2DArray;
mtlTexDesc.arrayLength = framebuffer->getLayerCount(); mtlTexDesc.arrayLength = framebuffer->getLayerCount();
} }
@ -222,6 +350,24 @@ void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts,
} }
} }
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. // Returns the format capabilities required by this render subpass.
// It is possible for a subpass to use a single framebuffer attachment for multiple purposes. // 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. // For example, a subpass may use a color or depth attachment as an input attachment as well.
@ -253,9 +399,60 @@ MVKMTLFmtCaps MVKRenderSubpass::getRequiredFormatCapabilitiesForAttachmentAt(uin
} }
MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass, MVKRenderSubpass::MVKRenderSubpass(MVKRenderPass* renderPass,
const VkSubpassDescription* pCreateInfo) { const VkSubpassDescription* pCreateInfo,
const VkRenderPassInputAttachmentAspectCreateInfo* pInputAspects,
uint32_t viewMask) {
_renderPass = renderPass; _renderPass = renderPass;
_subpassIndex = (uint32_t)_renderPass->_subpasses.size(); _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 // Add attachments
_inputAttachments.reserve(pCreateInfo->inputAttachmentCount); _inputAttachments.reserve(pCreateInfo->inputAttachmentCount);
@ -310,7 +507,7 @@ bool MVKRenderPassAttachment::populateMTLRenderPassAttachmentDescriptor(MTLRende
// attachment AND we're in the first subpass. // attachment AND we're in the first subpass.
if ( loadOverride ) { if ( loadOverride ) {
mtlAttDesc.loadAction = MTLLoadActionLoad; mtlAttDesc.loadAction = MTLLoadActionLoad;
} else if ( isRenderingEntireAttachment && (subpass->_subpassIndex == _firstUseSubpassIdx) ) { } else if ( isRenderingEntireAttachment && isFirstUseOfAttachment(subpass) ) {
VkAttachmentLoadOp loadOp = isStencil ? _info.stencilLoadOp : _info.loadOp; VkAttachmentLoadOp loadOp = isStencil ? _info.stencilLoadOp : _info.loadOp;
mtlAttDesc.loadAction = mvkMTLLoadActionFromVkAttachmentLoadOp(loadOp); mtlAttDesc.loadAction = mvkMTLLoadActionFromVkAttachmentLoadOp(loadOp);
willClear = (loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR); willClear = (loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
@ -338,13 +535,48 @@ void MVKRenderPassAttachment::encodeStoreAction(MVKCommandEncoder* cmdEncoder,
bool storeOverride) { bool storeOverride) {
MTLStoreAction storeAction = getMTLStoreAction(subpass, isRenderingEntireAttachment, hasResolveAttachment, isStencil, storeOverride); MTLStoreAction storeAction = getMTLStoreAction(subpass, isRenderingEntireAttachment, hasResolveAttachment, isStencil, storeOverride);
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
if (pixFmts->isDepthFormat(pixFmts->getMTLPixelFormat(_info.format)) && !isStencil) {
[cmdEncoder->_mtlRenderEncoder setDepthStoreAction: storeAction]; MTLPixelFormat mtlFmt = pixFmts->getMTLPixelFormat(_info.format);
} else if (pixFmts->isStencilFormat(pixFmts->getMTLPixelFormat(_info.format)) && isStencil) { bool isDepthFormat = pixFmts->isDepthFormat(mtlFmt);
[cmdEncoder->_mtlRenderEncoder setStencilStoreAction: storeAction]; bool isStencilFormat = pixFmts->isStencilFormat(mtlFmt);
} else { bool isColorFormat = !(isDepthFormat || isStencilFormat);
[cmdEncoder->_mtlRenderEncoder setColorStoreAction: storeAction atIndex: caIdx];
} 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, MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subpass,
@ -361,7 +593,7 @@ MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subp
if ( storeOverride ) { if ( storeOverride ) {
return hasResolveAttachment ? MTLStoreActionStoreAndMultisampleResolve : MTLStoreActionStore; return hasResolveAttachment ? MTLStoreActionStoreAndMultisampleResolve : MTLStoreActionStore;
} }
if ( isRenderingEntireAttachment && (subpass->_subpassIndex == _lastUseSubpassIdx) ) { if ( isRenderingEntireAttachment && isLastUseOfAttachment(subpass) ) {
VkAttachmentStoreOp storeOp = isStencil ? _info.stencilStoreOp : _info.storeOp; VkAttachmentStoreOp storeOp = isStencil ? _info.stencilStoreOp : _info.storeOp;
return mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment); return mvkMTLStoreActionFromVkAttachmentStoreOp(storeOp, hasResolveAttachment);
} }
@ -371,17 +603,16 @@ MTLStoreAction MVKRenderPassAttachment::getMTLStoreAction(MVKRenderSubpass* subp
bool MVKRenderPassAttachment::shouldUseClearAttachment(MVKRenderSubpass* subpass) { bool MVKRenderPassAttachment::shouldUseClearAttachment(MVKRenderSubpass* subpass) {
// If the subpass is not the first subpass to use this attachment, don't clear this attachment // 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); return (_info.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
} }
MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass, void MVKRenderPassAttachment::validateFormat() {
const VkAttachmentDescription* pCreateInfo) {
_info = *pCreateInfo;
_renderPass = renderPass;
_attachmentIndex = uint32_t(_renderPass->_attachments.size());
// Validate pixel format is supported // Validate pixel format is supported
MVKPixelFormats* pixFmts = _renderPass->getPixelFormats(); MVKPixelFormats* pixFmts = _renderPass->getPixelFormats();
if ( !pixFmts->isSupportedOrSubstitutable(_info.format) ) { if ( !pixFmts->isSupportedOrSubstitutable(_info.format) ) {
@ -391,6 +622,10 @@ MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
// Determine the indices of the first and last render subpasses to use this attachment. // Determine the indices of the first and last render subpasses to use this attachment.
_firstUseSubpassIdx = kMVKUndefinedLargeUInt32; _firstUseSubpassIdx = kMVKUndefinedLargeUInt32;
_lastUseSubpassIdx = 0; _lastUseSubpassIdx = 0;
if ( _renderPass->isMultiview() ) {
_firstUseViewMasks.reserve(_renderPass->_subpasses.size());
_lastUseViewMasks.reserve(_renderPass->_subpasses.size());
}
for (auto& subPass : _renderPass->_subpasses) { for (auto& subPass : _renderPass->_subpasses) {
// If it uses this attachment, the subpass will identify required format capabilities. // If it uses this attachment, the subpass will identify required format capabilities.
MVKMTLFmtCaps reqCaps = subPass.getRequiredFormatCapabilitiesForAttachmentAt(_attachmentIndex); MVKMTLFmtCaps reqCaps = subPass.getRequiredFormatCapabilitiesForAttachmentAt(_attachmentIndex);
@ -398,6 +633,13 @@ MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
uint32_t spIdx = subPass._subpassIndex; uint32_t spIdx = subPass._subpassIndex;
_firstUseSubpassIdx = min(spIdx, _firstUseSubpassIdx); _firstUseSubpassIdx = min(spIdx, _firstUseSubpassIdx);
_lastUseSubpassIdx = max(spIdx, _lastUseSubpassIdx); _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. // Validate that the attachment pixel format supports the capabilities required by the subpass.
// Use MTLPixelFormat to look up capabilities to permit Metal format substitution. // Use MTLPixelFormat to look up capabilities to permit Metal format substitution.
@ -408,6 +650,32 @@ MVKRenderPassAttachment::MVKRenderPassAttachment(MVKRenderPass* renderPass,
} }
} }
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 -
#pragma mark MVKRenderPass #pragma mark MVKRenderPass
@ -416,9 +684,67 @@ VkExtent2D MVKRenderPass::getRenderAreaGranularity() { return { 1, 1 }; }
MVKRenderSubpass* MVKRenderPass::getSubpass(uint32_t subpassIndex) { return &_subpasses[subpassIndex]; } MVKRenderSubpass* MVKRenderPass::getSubpass(uint32_t subpassIndex) { return &_subpasses[subpassIndex]; }
bool MVKRenderPass::isMultiview() const { return _subpasses[0].isMultiview(); }
MVKRenderPass::MVKRenderPass(MVKDevice* device, MVKRenderPass::MVKRenderPass(MVKDevice* device,
const VkRenderPassCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(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 // Add subpasses and dependencies first
_subpasses.reserve(pCreateInfo->subpassCount); _subpasses.reserve(pCreateInfo->subpassCount);
for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) { for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {

View File

@ -239,6 +239,7 @@ void MVKShaderLibraryCache::merge(MVKShaderLibraryCache* other) {
for (auto& otherPair : other->_shaderLibraries) { for (auto& otherPair : other->_shaderLibraries) {
if ( !findShaderLibrary(&otherPair.first) ) { if ( !findShaderLibrary(&otherPair.first) ) {
_shaderLibraries.emplace_back(otherPair.first, new MVKShaderLibrary(*otherPair.second)); _shaderLibraries.emplace_back(otherPair.first, new MVKShaderLibrary(*otherPair.second));
_shaderLibraries.back().second->_owner = _owner;
} }
} }
} }

View File

@ -42,13 +42,18 @@
MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE) MVK_EXTENSION(KHR_16bit_storage, KHR_16BIT_STORAGE, DEVICE)
MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE) MVK_EXTENSION(KHR_8bit_storage, KHR_8BIT_STORAGE, DEVICE)
MVK_EXTENSION(KHR_bind_memory2, KHR_BIND_MEMORY_2, 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_dedicated_allocation, KHR_DEDICATED_ALLOCATION, DEVICE)
MVK_EXTENSION(KHR_descriptor_update_template, KHR_DESCRIPTOR_UPDATE_TEMPLATE, 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, KHR_DEVICE_GROUP, DEVICE)
MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE) MVK_EXTENSION(KHR_device_group_creation, KHR_DEVICE_GROUP_CREATION, INSTANCE)
MVK_EXTENSION(KHR_driver_properties, KHR_DRIVER_PROPERTIES, DEVICE) 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, KHR_EXTERNAL_MEMORY, DEVICE)
MVK_EXTENSION(KHR_external_memory_capabilities, KHR_EXTERNAL_MEMORY_CAPABILITIES, INSTANCE) 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_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_physical_device_properties2, KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2, INSTANCE)
MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE) MVK_EXTENSION(KHR_get_surface_capabilities2, KHR_GET_SURFACE_CAPABILITIES_2, INSTANCE)
@ -56,6 +61,7 @@ MVK_EXTENSION(KHR_image_format_list, KHR_IMAGE_FORMAT_LIST, DEVICE)
MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE) MVK_EXTENSION(KHR_maintenance1, KHR_MAINTENANCE1, DEVICE)
MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE) MVK_EXTENSION(KHR_maintenance2, KHR_MAINTENANCE2, DEVICE)
MVK_EXTENSION(KHR_maintenance3, KHR_MAINTENANCE3, 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_push_descriptor, KHR_PUSH_DESCRIPTOR, DEVICE)
MVK_EXTENSION(KHR_relaxed_block_layout, KHR_RELAXED_BLOCK_LAYOUT, 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) MVK_EXTENSION(KHR_sampler_mirror_clamp_to_edge, KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE, DEVICE)

View File

@ -35,8 +35,8 @@
#endif #endif
/** Macro to determine the Vulkan version supported by MoltenVK. */ /** 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), \ #define MVK_VULKAN_API_VERSION VK_MAKE_VERSION(VK_VERSION_MAJOR(VK_API_VERSION_1_1), \
VK_VERSION_MINOR(VK_API_VERSION_1_0), \ VK_VERSION_MINOR(VK_API_VERSION_1_1), \
VK_HEADER_VERSION) VK_HEADER_VERSION)
/** /**

View File

@ -86,6 +86,7 @@ typedef enum : uint8_t {
kMVKCommandUseResetQueryPool, /**< vkCmdResetQueryPool. */ kMVKCommandUseResetQueryPool, /**< vkCmdResetQueryPool. */
kMVKCommandUseDispatch, /**< vkCmdDispatch. */ kMVKCommandUseDispatch, /**< vkCmdDispatch. */
kMVKCommandUseTessellationVertexTessCtl,/**< vkCmdDraw* - vertex and tessellation control stages. */ kMVKCommandUseTessellationVertexTessCtl,/**< vkCmdDraw* - vertex and tessellation control stages. */
kMVKCommandUseMultiviewInstanceCountAdjust,/**< vkCmdDrawIndirect* - adjust instance count for multiview. */
kMVKCommandUseCopyQueryPoolResults /**< vkCmdCopyQueryPoolResults. */ kMVKCommandUseCopyQueryPoolResults /**< vkCmdCopyQueryPoolResults. */
} MVKCommandUse; } MVKCommandUse;

View File

@ -158,9 +158,12 @@ static inline void MVKTraceVulkanCallEndImpl(const char* funcName, uint64_t star
MVKAddCmd(baseCmdType ##Multi, vkCmdBuff, ##__VA_ARGS__); \ 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 -
#pragma mark Vulkan calls #pragma mark Vulkan 1.0 calls
MVK_PUBLIC_SYMBOL VkResult vkCreateInstance( MVK_PUBLIC_SYMBOL VkResult vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo, const VkInstanceCreateInfo* pCreateInfo,
@ -278,6 +281,8 @@ MVK_PUBLIC_SYMBOL PFN_vkVoidFunction vkGetInstanceProcAddr(
func = (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties; func = (PFN_vkVoidFunction)vkEnumerateInstanceExtensionProperties;
} else if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) { } else if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) {
func = (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties; func = (PFN_vkVoidFunction)vkEnumerateInstanceLayerProperties;
} else if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) {
func = (PFN_vkVoidFunction)vkEnumerateInstanceVersion;
} else if (instance) { } else if (instance) {
MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance); MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
func = mvkInst->getProcAddr(pName); func = mvkInst->getProcAddr(pName);
@ -1900,12 +1905,156 @@ MVK_PUBLIC_SYMBOL void vkCmdExecuteCommands(
#pragma mark - #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, VkDevice device,
uint32_t bindInfoCount, uint32_t bindInfoCount,
const VkBindBufferMemoryInfoKHR* pBindInfos) { const VkBindBufferMemoryInfo* pBindInfos) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
VkResult rslt = VK_SUCCESS; VkResult rslt = VK_SUCCESS;
@ -1918,10 +2067,10 @@ MVK_PUBLIC_SYMBOL VkResult vkBindBufferMemory2KHR(
return rslt; return rslt;
} }
MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2KHR( MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2(
VkDevice device, VkDevice device,
uint32_t bindInfoCount, uint32_t bindInfoCount,
const VkBindImageMemoryInfoKHR* pBindInfos) { const VkBindImageMemoryInfo* pBindInfos) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
VkResult rslt = VK_SUCCESS; VkResult rslt = VK_SUCCESS;
@ -1934,29 +2083,76 @@ MVK_PUBLIC_SYMBOL VkResult vkBindImageMemory2KHR(
return rslt; return rslt;
} }
MVK_PUBLIC_SYMBOL void vkGetBufferMemoryRequirements2(
VkDevice device,
const VkBufferMemoryRequirementsInfo2* pInfo,
VkMemoryRequirements2* pMemoryRequirements) {
#pragma mark - MVKTraceVulkanCallStart();
#pragma mark VK_KHR_descriptor_update_template extension 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, VkDevice device,
const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator, const VkAllocationCallbacks* pAllocator,
VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate) { VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKDevice* mvkDev = MVKDevice::getMVKDevice(device); MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
auto *mvkDUT = mvkDev->createDescriptorUpdateTemplate(pCreateInfo, auto *mvkDUT = mvkDev->createDescriptorUpdateTemplate(pCreateInfo,
pAllocator); pAllocator);
*pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplateKHR)mvkDUT; *pDescriptorUpdateTemplate = (VkDescriptorUpdateTemplate)mvkDUT;
VkResult rslt = mvkDUT->getConfigurationResult(); VkResult rslt = mvkDUT->getConfigurationResult();
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
return rslt; return rslt;
} }
MVK_PUBLIC_SYMBOL void vkDestroyDescriptorUpdateTemplateKHR( MVK_PUBLIC_SYMBOL void vkDestroyDescriptorUpdateTemplate(
VkDevice device, VkDevice device,
VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const VkAllocationCallbacks* pAllocator) { const VkAllocationCallbacks* pAllocator) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
@ -1965,10 +2161,10 @@ MVK_PUBLIC_SYMBOL void vkDestroyDescriptorUpdateTemplateKHR(
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
MVK_PUBLIC_SYMBOL void vkUpdateDescriptorSetWithTemplateKHR( MVK_PUBLIC_SYMBOL void vkUpdateDescriptorSetWithTemplate(
VkDevice device, VkDevice device,
VkDescriptorSet descriptorSet, VkDescriptorSet descriptorSet,
VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate, VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const void* pData) { const void* pData) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
@ -1976,24 +2172,56 @@ MVK_PUBLIC_SYMBOL void vkUpdateDescriptorSetWithTemplateKHR(
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
MVK_PUBLIC_SYMBOL void vkGetDescriptorSetLayoutSupport(
#pragma mark -
#pragma mark VK_KHR_device_group extension
MVK_PUBLIC_SYMBOL void vkGetDeviceGroupPeerMemoryFeaturesKHR(
VkDevice device, VkDevice device,
uint32_t heapIndex, const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
uint32_t localDeviceIndex, VkDescriptorSetLayoutSupport* pSupport) {
uint32_t remoteDeviceIndex,
VkPeerMemoryFeatureFlagsKHR* pPeerMemoryFeatures) {
MVKTraceVulkanCallStart(); MVKTraceVulkanCallStart();
MVKDevice* mvkDev = MVKDevice::getMVKDevice(device); MVKDevice* mvkDevice = MVKDevice::getMVKDevice(device);
mvkDev->getPeerMemoryFeatures(heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures); mvkDevice->getDescriptorSetLayoutSupport(pCreateInfo, pSupport);
MVKTraceVulkanCallEnd(); 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, VkCommandBuffer commandBuffer,
uint32_t deviceMask) { uint32_t deviceMask) {
@ -2003,7 +2231,7 @@ MVK_PUBLIC_SYMBOL void vkCmdSetDeviceMaskKHR(
MVKTraceVulkanCallEnd(); MVKTraceVulkanCallEnd();
} }
MVK_PUBLIC_SYMBOL void vkCmdDispatchBaseKHR( MVK_PUBLIC_SYMBOL void vkCmdDispatchBase(
VkCommandBuffer commandBuffer, VkCommandBuffer commandBuffer,
uint32_t baseGroupX, uint32_t baseGroupX,
uint32_t baseGroupY, uint32_t baseGroupY,
@ -2018,175 +2246,131 @@ MVK_PUBLIC_SYMBOL void vkCmdDispatchBaseKHR(
} }
#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 -
#pragma mark VK_KHR_device_group_creation extension #pragma mark VK_KHR_device_group_creation extension
MVK_PUBLIC_SYMBOL VkResult vkEnumeratePhysicalDeviceGroupsKHR( MVK_PUBLIC_CORE_ALIAS(vkEnumeratePhysicalDeviceGroups);
VkInstance instance,
uint32_t* pPhysicalDeviceGroupCount,
VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties) { #pragma mark -
MVKTraceVulkanCallStart(); #pragma mark VK_KHR_external_fence_capabilities extension
MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
VkResult rslt = mvkInst->getPhysicalDeviceGroups(pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties); MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceExternalFenceProperties);
MVKTraceVulkanCallEnd();
return rslt;
} #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 -
#pragma mark VK_KHR_get_memory_requirements2 extension #pragma mark VK_KHR_get_memory_requirements2 extension
MVK_PUBLIC_SYMBOL void vkGetBufferMemoryRequirements2KHR( MVK_PUBLIC_CORE_ALIAS(vkGetBufferMemoryRequirements2);
VkDevice device, MVK_PUBLIC_CORE_ALIAS(vkGetImageMemoryRequirements2);
const VkBufferMemoryRequirementsInfo2KHR* pInfo, MVK_PUBLIC_CORE_ALIAS(vkGetImageSparseMemoryRequirements2);
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();
}
#pragma mark - #pragma mark -
#pragma mark VK_KHR_get_physical_device_properties2 extension #pragma mark VK_KHR_get_physical_device_properties2 extension
MVK_PUBLIC_SYMBOL void vkGetPhysicalDeviceFeatures2KHR( MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceFeatures2);
VkPhysicalDevice physicalDevice, MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceProperties2);
VkPhysicalDeviceFeatures2KHR* pFeatures) { MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceFormatProperties2);
MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceImageFormatProperties2);
MVKTraceVulkanCallStart(); MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceQueueFamilyProperties2);
MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice); MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceMemoryProperties2);
mvkPD->getFeatures(pFeatures); MVK_PUBLIC_CORE_ALIAS(vkGetPhysicalDeviceSparseImageFormatProperties2);
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();
}
#pragma mark - #pragma mark -
#pragma mark VK_KHR_maintenance1 extension #pragma mark VK_KHR_maintenance1 extension
MVK_PUBLIC_SYMBOL void vkTrimCommandPoolKHR( MVK_PUBLIC_CORE_ALIAS(vkTrimCommandPool);
VkDevice device,
VkCommandPool commandPool,
VkCommandPoolTrimFlagsKHR flags) {
MVKTraceVulkanCallStart();
MVKCommandPool* mvkCmdPool = (MVKCommandPool*)commandPool;
mvkCmdPool->trim();
MVKTraceVulkanCallEnd();
}
#pragma mark - #pragma mark -
#pragma mark VK_KHR_maintenance3 extension #pragma mark VK_KHR_maintenance3 extension
MVK_PUBLIC_SYMBOL void vkGetDescriptorSetLayoutSupportKHR( MVK_PUBLIC_CORE_ALIAS(vkGetDescriptorSetLayoutSupport);
VkDevice device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
VkDescriptorSetLayoutSupportKHR* pSupport) {
MVKTraceVulkanCallStart();
MVKDevice* mvkDevice = MVKDevice::getMVKDevice(device);
mvkDevice->getDescriptorSetLayoutSupport(pCreateInfo, pSupport);
MVKTraceVulkanCallEnd();
}
#pragma mark - #pragma mark -
@ -2221,32 +2405,8 @@ MVK_PUBLIC_SYMBOL void vkCmdPushDescriptorSetWithTemplateKHR(
#pragma mark - #pragma mark -
#pragma mark VK_KHR_sampler_ycbcr_conversion extension #pragma mark VK_KHR_sampler_ycbcr_conversion extension
MVK_PUBLIC_SYMBOL VkResult vkCreateSamplerYcbcrConversionKHR( MVK_PUBLIC_CORE_ALIAS(vkCreateSamplerYcbcrConversion);
VkDevice device, MVK_PUBLIC_CORE_ALIAS(vkDestroySamplerYcbcrConversion);
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();
}
#pragma mark - #pragma mark -
@ -2716,21 +2876,6 @@ MVK_PUBLIC_SYMBOL void vkResetQueryPoolEXT(
} }
#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 -
#pragma mark VK_EXT_metal_surface extension #pragma mark VK_EXT_metal_surface extension

View File

@ -321,7 +321,7 @@
A90B2B1D1A9B6170008EE819 /* Project object */ = { A90B2B1D1A9B6170008EE819 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1200; LastUpgradeCheck = 1170;
TargetAttributes = { TargetAttributes = {
A9FEADBC1F3517480010240E = { A9FEADBC1F3517480010240E = {
DevelopmentTeam = VU3TCKU48B; DevelopmentTeam = VU3TCKU48B;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "NO" parallelizeBuildables = "NO"

View File

@ -302,6 +302,7 @@ MVK_PUBLIC_SYMBOL bool SPIRVToMSLConverter::convert(SPIRVToMSLConversionConfigur
_shaderConversionResults.needsBufferSizeBuffer = pMSLCompiler && pMSLCompiler->needs_buffer_size_buffer(); _shaderConversionResults.needsBufferSizeBuffer = pMSLCompiler && pMSLCompiler->needs_buffer_size_buffer();
_shaderConversionResults.needsInputThreadgroupMem = pMSLCompiler && pMSLCompiler->needs_input_threadgroup_mem(); _shaderConversionResults.needsInputThreadgroupMem = pMSLCompiler && pMSLCompiler->needs_input_threadgroup_mem();
_shaderConversionResults.needsDispatchBaseBuffer = pMSLCompiler && pMSLCompiler->needs_dispatch_base_buffer(); _shaderConversionResults.needsDispatchBaseBuffer = pMSLCompiler && pMSLCompiler->needs_dispatch_base_buffer();
_shaderConversionResults.needsViewRangeBuffer = pMSLCompiler && pMSLCompiler->needs_view_mask_buffer();
for (auto& ctxSI : context.shaderInputs) { for (auto& ctxSI : context.shaderInputs) {
ctxSI.isUsedByShader = pMSLCompiler->is_msl_shader_input_used(ctxSI.shaderInput.location); ctxSI.isUsedByShader = pMSLCompiler->is_msl_shader_input_used(ctxSI.shaderInput.location);

View File

@ -209,6 +209,7 @@ namespace mvk {
bool needsBufferSizeBuffer = false; bool needsBufferSizeBuffer = false;
bool needsInputThreadgroupMem = false; bool needsInputThreadgroupMem = false;
bool needsDispatchBaseBuffer = false; bool needsDispatchBaseBuffer = false;
bool needsViewRangeBuffer = false;
void reset() { *this = SPIRVToMSLConversionResults(); } void reset() { *this = SPIRVToMSLConversionResults(); }

View File

@ -512,7 +512,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = { A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1200; LastUpgradeCheck = 1170;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd."; ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = { TargetAttributes = {
A9092A8C1A81717B00051823 = { A9092A8C1A81717B00051823 = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1200" LastUpgradeVersion = "1170"
version = "2.0"> version = "2.0">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -58,7 +58,7 @@ document in the `Docs` directory.
Introduction to MoltenVK 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 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 framework on *macOS*, *iOS*, and *tvOS*. **MoltenVK** allows you to use *Vulkan*
graphics and compute functionality to develop modern, cross-platform, high-performance graphical graphics and compute functionality to develop modern, cross-platform, high-performance graphical
@ -76,7 +76,7 @@ channels, including *Apple's App Store*.
The **MoltenVK** runtime package contains two products: The **MoltenVK** runtime package contains two products:
- **MoltenVK** is a implementation of an almost-complete subset of the - **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)* - **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 shader code, and converts *GLSL* shader source code to *SPIR-V* shader code and/or
@ -272,11 +272,11 @@ the contents of that directory out of this **MoltenVK** repository into your own
**MoltenVK** and *Vulkan* Compliance **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. 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 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 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 native graphics driver on *macOS*, *iOS*, and *tvOS* platforms. *Vulkan* compliance may fall into one of