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