Merge pull request #882 from billhollings/master
Add MVKSmallVector as a more memory efficient substitute of MVKVector, and use throughout MoltenVK.
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
index b63defa..adb88b3 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/project.pbxproj
@@ -547,7 +547,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1140;
+ LastUpgradeCheck = 1150;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "API-Samples" */;
compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
index 620a035..fd267bd 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
index 283d573..029bc89 100644
--- a/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/API-Samples/API-Samples.xcodeproj/xcshareddata/xcschemes/API-Samples-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
index afb8606..75030f0 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/project.pbxproj
@@ -234,7 +234,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1140;
+ LastUpgradeCheck = 1150;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Cube" */;
compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
index b6cace4..23b9271 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
index 7a4cf00..756dba9 100644
--- a/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Cube/Cube.xcodeproj/xcshareddata/xcschemes/Cube-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
index 9058306..9129ae3 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/project.pbxproj
@@ -265,7 +265,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1140;
+ LastUpgradeCheck = 1150;
};
buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Hologram" */;
compatibilityVersion = "Xcode 8.0";
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
index 38a9ae3..d2069b0 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
index 7ad255a..30d2b38 100644
--- a/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
+++ b/Demos/LunarG-VulkanSamples/Hologram/Hologram.xcodeproj/xcshareddata/xcschemes/Hologram-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 2b7845c..47fdd4c 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -34,6 +34,7 @@
through `vkGetPerformanceStatisticsMVK()`.
- Add `MVK_CONFIG_PERFORMANCE_LOGGING_INLINE` env var to enable/disable
logging of performance of each activity when it happens.
+- Support Xcode 11.5.
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index cf3c94c..dc88117 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -233,6 +233,10 @@
A9F042A51FB4CF83009FCCB8 /* MVKCommonEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */; };
A9F042A61FB4CF83009FCCB8 /* MVKLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */; };
A9F042A71FB4CF83009FCCB8 /* MVKLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */; };
+ A9F3D9DC24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; };
+ A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */; };
+ A9F3D9DE24732A4D00745190 /* MVKSmallVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */; };
+ A9F3D9DF24732A4D00745190 /* MVKSmallVector.h in Headers */ = {isa = PBXBuildFile; fileRef = A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -424,6 +428,8 @@
A9F0429D1FB4CF82009FCCB8 /* MVKCommonEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKCommonEnvironment.h; sourceTree = "<group>"; };
A9F0429E1FB4CF82009FCCB8 /* MVKLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKLogging.h; sourceTree = "<group>"; };
A9F2559121F96814008C7785 /* vulkan-portability */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vulkan-portability"; sourceTree = "<group>"; };
+ A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVectorAllocator.h; sourceTree = "<group>"; };
+ A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKSmallVector.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXGroup section */
@@ -570,6 +576,8 @@
A98149451FB6A3F7005F00B4 /* MVKFoundation.cpp */,
A98149441FB6A3F7005F00B4 /* MVKFoundation.h */,
A98149461FB6A3F7005F00B4 /* MVKObjectPool.h */,
+ A9F3D9DB24732A4D00745190 /* MVKSmallVector.h */,
+ A9F3D9D924732A4C00745190 /* MVKSmallVectorAllocator.h */,
83A4AD2521BD75570006C935 /* MVKVector.h */,
83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */,
A98149491FB6A3F7005F00B4 /* MVKWatermark.h */,
@@ -688,6 +696,7 @@
A9E53DE32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
A94FB8181C7DFB4800632CA3 /* MVKSync.h in Headers */,
A94FB7E41C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+ A9F3D9DE24732A4D00745190 /* MVKSmallVector.h in Headers */,
83A4AD2A21BD75570006C935 /* MVKVector.h in Headers */,
A94FB7D41C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
A94FB80C1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
@@ -705,6 +714,7 @@
A9B51BD9225E986A00AC74D2 /* MVKOSExtensions.h in Headers */,
A94FB7C41C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */,
A94FB7BC1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
+ A9F3D9DC24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */,
A94FB7F81C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
A94FB7F01C7DFB4800632CA3 /* MVKImage.h in Headers */,
4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
@@ -758,6 +768,7 @@
A9E53DE42100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
A94FB8191C7DFB4800632CA3 /* MVKSync.h in Headers */,
A94FB7E51C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+ A9F3D9DF24732A4D00745190 /* MVKSmallVector.h in Headers */,
83A4AD2B21BD75570006C935 /* MVKVector.h in Headers */,
A94FB7D51C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
A94FB80D1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
@@ -775,6 +786,7 @@
A9B51BDA225E986A00AC74D2 /* MVKOSExtensions.h in Headers */,
A94FB7C51C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */,
A94FB7BD1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */,
+ A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */,
A94FB7F91C7DFB4800632CA3 /* MVKPipeline.h in Headers */,
A94FB7F11C7DFB4800632CA3 /* MVKImage.h in Headers */,
4553AEFE2251617100E8EBCD /* MVKBlockObserver.h in Headers */,
@@ -848,7 +860,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1140;
+ LastUpgradeCheck = 1150;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = {
A9B8EE091A98D796009C5A02 = {
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
index fcfb674..5be3d34 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
index 6e4b83f..7c9db07 100644
--- a/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
+++ b/MoltenVK/MoltenVK.xcodeproj/xcshareddata/xcschemes/MoltenVK-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
index 4425309..1d67b39 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
@@ -20,7 +20,7 @@
#include "MVKCommand.h"
#include "MVKMTLResourceBindings.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#import <Metal/Metal.h>
@@ -47,7 +47,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<MVKMTLBufferBinding, N> _bindings;
+ MVKSmallVector<MVKMTLBufferBinding, N> _bindings;
};
// Concrete template class implementations.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
index 26f833e..14abfc7 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
@@ -108,7 +108,7 @@
auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline();
- MVKVectorInline<uint32_t, 4> stages;
+ MVKPiplineStages stages;
pipeline->getStages(stages);
const MVKMTLBufferAllocation* vtxOutBuff = nullptr;
@@ -302,7 +302,7 @@
auto* pipeline = (MVKGraphicsPipeline*)cmdEncoder->_graphicsPipelineState.getPipeline();
- MVKVectorInline<uint32_t, 4> stages;
+ MVKPiplineStages stages;
pipeline->getStages(stages);
MVKIndexMTLBufferBinding& ibb = cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding;
@@ -588,7 +588,7 @@
}
}
- MVKVectorInline<uint32_t, 4> stages;
+ MVKPiplineStages stages;
pipeline->getStages(stages);
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
@@ -816,7 +816,7 @@
tcIndexBuff = cmdEncoder->getTempMTLBuffer(patchCount * outControlPointCount * idxSize);
}
- MVKVectorInline<uint32_t, 4> stages;
+ MVKPiplineStages stages;
pipeline->getStages(stages);
VkDeviceSize mtlIndBuffOfst = _mtlIndirectBufferOffset;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
index 5b862ba..b2985ee 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
@@ -21,7 +21,7 @@
#include "MVKCommand.h"
#include "MVKMTLResourceBindings.h"
#include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
class MVKCommandBuffer;
class MVKPipeline;
@@ -58,7 +58,7 @@
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
bool coversTextures();
- MVKVectorInline<MVKPipelineBarrier, N> _barriers;
+ MVKSmallVector<MVKPipelineBarrier, N> _barriers;
VkPipelineStageFlags _srcStageMask;
VkPipelineStageFlags _dstStageMask;
VkDependencyFlags _dependencyFlags;
@@ -142,7 +142,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<MVKDescriptorSet*, N> _descriptorSets;
+ MVKSmallVector<MVKDescriptorSet*, N> _descriptorSets;
MVKPipelineLayout* _pipelineLayout;
VkPipelineBindPoint _pipelineBindPoint;
uint32_t _firstSet;
@@ -179,7 +179,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<uint32_t, N> _dynamicOffsets;
+ MVKSmallVector<uint32_t, N> _dynamicOffsets;
};
// Concrete template class implementations.
@@ -210,7 +210,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<char, N> _pushConstants;
+ MVKSmallVector<char, N> _pushConstants;
MVKPipelineLayout* _pipelineLayout;
VkShaderStageFlags _stageFlags;
uint32_t _offset;
@@ -244,7 +244,7 @@
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
void clearDescriptorWrites();
- MVKVectorInline<VkWriteDescriptorSet, 1> _descriptorWrites;
+ MVKSmallVector<VkWriteDescriptorSet, 1> _descriptorWrites;
MVKPipelineLayout* _pipelineLayout;
VkPipelineBindPoint _pipelineBindPoint;
uint32_t _set;
@@ -354,7 +354,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<MVKEvent*, N> _mvkEvents;
+ MVKSmallVector<MVKEvent*, N> _mvkEvents;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
index 0d6dad8..13bfe6f 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
@@ -207,7 +207,7 @@
template <size_t N>
void MVKCmdBindDescriptorSetsStatic<N>::encode(MVKCommandEncoder* cmdEncoder) {
- _pipelineLayout->bindDescriptorSets(cmdEncoder, _descriptorSets, _firstSet, nullptr);
+ _pipelineLayout->bindDescriptorSets(cmdEncoder, _descriptorSets.contents(), _firstSet, MVKArrayRef<uint32_t>());
}
template class MVKCmdBindDescriptorSetsStatic<1>;
@@ -243,7 +243,7 @@
template <size_t N>
void MVKCmdBindDescriptorSetsDynamic<N>::encode(MVKCommandEncoder* cmdEncoder) {
- MVKCmdBindDescriptorSetsStatic<N>::_pipelineLayout->bindDescriptorSets(cmdEncoder, MVKCmdBindDescriptorSetsStatic<N>::_descriptorSets, MVKCmdBindDescriptorSetsStatic<N>::_firstSet, &_dynamicOffsets);
+ MVKCmdBindDescriptorSetsStatic<N>::_pipelineLayout->bindDescriptorSets(cmdEncoder, MVKCmdBindDescriptorSetsStatic<N>::_descriptorSets.contents(), MVKCmdBindDescriptorSetsStatic<N>::_firstSet, _dynamicOffsets.contents());
}
template class MVKCmdBindDescriptorSetsDynamic<4>;
@@ -281,7 +281,7 @@
};
for (auto stage : stages) {
if (mvkAreAllFlagsEnabled(_stageFlags, stage)) {
- cmdEncoder->getPushConstants(stage)->setPushConstants(_offset, _pushConstants);
+ cmdEncoder->getPushConstants(stage)->setPushConstants(_offset, _pushConstants.contents());
}
}
}
@@ -353,7 +353,7 @@
}
void MVKCmdPushDescriptorSet::encode(MVKCommandEncoder* cmdEncoder) {
- _pipelineLayout->pushDescriptorSet(cmdEncoder, _descriptorWrites, _set);
+ _pipelineLayout->pushDescriptorSet(cmdEncoder, _descriptorWrites.contents(), _set);
}
MVKCmdPushDescriptorSet::~MVKCmdPushDescriptorSet() {
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
index 4a4eff7..300b197 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
@@ -20,7 +20,7 @@
#include "MVKCommand.h"
#include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#import <Metal/Metal.h>
@@ -48,7 +48,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<VkClearValue, N> _clearValues;
+ MVKSmallVector<VkClearValue, N> _clearValues;
MVKRenderPass* _renderPass;
MVKFramebuffer* _framebuffer;
VkRect2D _renderArea;
@@ -117,7 +117,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<MVKCommandBuffer*, N> _secondaryCommandBuffers;
+ MVKSmallVector<MVKCommandBuffer*, N> _secondaryCommandBuffers;
};
// Concrete template class implementations.
@@ -146,7 +146,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<VkViewport, N> _viewports;
+ MVKSmallVector<VkViewport, N> _viewports;
uint32_t _firstViewport;
};
@@ -176,7 +176,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<VkRect2D, N> _scissors;
+ MVKSmallVector<VkRect2D, N> _scissors;
uint32_t _firstScissor;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
index c31292c..6db1a8c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.mm
@@ -55,7 +55,7 @@
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, _loadOverride, _storeOverride);
+ cmdEncoder->beginRenderpass(_contents, _renderPass, _framebuffer, _renderArea, _clearValues.contents(), _loadOverride, _storeOverride);
}
template class MVKCmdBeginRenderPass<1>;
@@ -138,7 +138,7 @@
template <size_t N>
void MVKCmdSetViewport<N>::encode(MVKCommandEncoder* cmdEncoder) {
- cmdEncoder->_viewportState.setViewports(_viewports, _firstViewport, true);
+ cmdEncoder->_viewportState.setViewports(_viewports.contents(), _firstViewport, true);
}
template class MVKCmdSetViewport<1>;
@@ -165,7 +165,7 @@
template <size_t N>
void MVKCmdSetScissor<N>::encode(MVKCommandEncoder* cmdEncoder) {
- cmdEncoder->_scissorState.setScissors(_scissors, _firstScissor, true);
+ cmdEncoder->_scissorState.setScissors(_scissors.contents(), _firstScissor, true);
}
template class MVKCmdSetScissor<1>;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
index 0e341c4..54723c8 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.h
@@ -22,7 +22,7 @@
#include "MVKMTLBufferAllocation.h"
#include "MVKCommandResourceFactory.h"
#include "MVKFoundation.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#import <Metal/Metal.h>
@@ -56,7 +56,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<VkImageCopy, N> _vkImageCopies;
+ MVKSmallVector<VkImageCopy, N> _vkImageCopies;
MVKImage* _srcImage;
MVKImage* _dstImage;
VkImageLayout _srcLayout;
@@ -107,7 +107,7 @@
bool canCopy(const VkImageBlit& region);
void populateVertices(MVKVertexPosTex* vertices, const VkImageBlit& region);
- MVKVectorInline<VkImageBlit, N> _vkImageBlits;
+ MVKSmallVector<VkImageBlit, N> _vkImageBlits;
MVKImage* _srcImage;
MVKImage* _dstImage;
VkImageLayout _srcLayout;
@@ -150,7 +150,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<VkImageResolve, N> _vkImageResolves;
+ MVKSmallVector<VkImageResolve, N> _vkImageResolves;
MVKImage* _srcImage;
MVKImage* _dstImage;
VkImageLayout _srcLayout;
@@ -184,7 +184,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorInline<VkBufferCopy, N> _bufferCopyRegions;
+ MVKSmallVector<VkBufferCopy, N> _bufferCopyRegions;
MVKBuffer* _srcBuffer;
MVKBuffer* _dstBuffer;
};
@@ -219,7 +219,7 @@
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
bool isArrayTexture();
- MVKVectorInline<VkBufferImageCopy, N> _bufferImageCopyRegions;
+ MVKSmallVector<VkBufferImageCopy, N> _bufferImageCopyRegions;
MVKBuffer* _buffer;
MVKImage* _image;
VkImageLayout _imageLayout;
@@ -259,7 +259,7 @@
virtual VkClearValue& getClearValue(uint32_t attIdx) = 0;
virtual void setClearValue(uint32_t attIdx, const VkClearValue& clearValue) = 0;
- MVKVectorInline<VkClearRect, N> _clearRects;
+ MVKSmallVector<VkClearRect, N> _clearRects;
MVKRPSKeyClearAtt _rpsKey;
bool _isClearingDepth;
bool _isClearingStencil;
@@ -338,7 +338,7 @@
void populateVertices(MVKVertexPosTex* vertices, const VkImageBlit* pRegion);
virtual bool isDepthStencilClear() = 0;
- MVKVectorInline<VkImageSubresourceRange, N> _subresourceRanges;
+ MVKSmallVector<VkImageSubresourceRange, N> _subresourceRanges;
MVKImage* _image;
VkClearValue _clearValue;
};
@@ -424,7 +424,7 @@
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
- MVKVectorDefault<uint8_t> _srcDataCache;
+ MVKSmallVector<uint8_t> _srcDataCache;
MVKBuffer* _dstBuffer;
VkDeviceSize _dstOffset;
VkDeviceSize _dataSize;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index a42d588..02bd38d 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -22,9 +22,10 @@
#include "MVKCommand.h"
#include "MVKCommandEncoderState.h"
#include "MVKMTLBufferAllocation.h"
+#include "MVKRenderPass.h"
#include "MVKCmdPipeline.h"
#include "MVKQueryPool.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <unordered_map>
class MVKCommandPool;
@@ -241,7 +242,7 @@
/*** Holds a collection of active queries for each query pool. */
-typedef std::unordered_map<MVKQueryPool*, MVKVectorInline<uint32_t, kMVKDefaultQueryCount>> MVKActivatedQueries;
+typedef std::unordered_map<MVKQueryPool*, MVKSmallVector<uint32_t, kMVKDefaultQueryCount>> MVKActivatedQueries;
/**
* MVKCommandEncoder uses a visitor design pattern iterate the commands in a MVKCommandBuffer,
@@ -268,7 +269,7 @@
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
- MVKVector<VkClearValue>* clearValues,
+ MVKArrayRef<VkClearValue> clearValues,
bool loadOverride = false,
bool storeOverride = false);
@@ -452,7 +453,7 @@
uint32_t _renderSubpassIndex;
VkRect2D _renderArea;
MVKActivatedQueries* _pActivatedQueries;
- MVKVectorInline<VkClearValue, 8> _clearValues;
+ MVKSmallVector<VkClearValue, kMVKDefaultAttachmentCount> _clearValues;
id<MTLComputeCommandEncoder> _mtlComputeEncoder;
MVKCommandUse _mtlComputeEncoderUse;
id<MTLBlitCommandEncoder> _mtlBlitEncoder;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 775c24f..ad8396c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -20,7 +20,6 @@
#include "MVKCommandPool.h"
#include "MVKQueue.h"
#include "MVKPipeline.h"
-#include "MVKRenderPass.h"
#include "MVKFramebuffer.h"
#include "MVKQueryPool.h"
#include "MVKFoundation.h"
@@ -266,7 +265,7 @@
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
- MVKVector<VkClearValue>* clearValues,
+ MVKArrayRef<VkClearValue> clearValues,
bool loadOverride,
bool storeOverride) {
_renderPass = renderPass;
@@ -274,7 +273,7 @@
_renderArea = renderArea;
_isRenderingEntireAttachment = (mvkVkOffset2DsAreEqual(_renderArea.offset, {0,0}) &&
mvkVkExtent2DsAreEqual(_renderArea.extent, _framebuffer->getExtent2D()));
- _clearValues.assign(clearValues->begin(), clearValues->end());
+ _clearValues.assign(clearValues.begin(), clearValues.end());
setSubpass(subpassContents, 0, loadOverride, storeOverride);
}
@@ -301,7 +300,7 @@
endCurrentMetalEncoding();
MTLRenderPassDescriptor* mtlRPDesc = [MTLRenderPassDescriptor renderPassDescriptor];
- getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues, _isRenderingEntireAttachment, loadOverride, storeOverride);
+ getSubpass()->populateMTLRenderPassDescriptor(mtlRPDesc, _framebuffer, _clearValues.contents(), _isRenderingEntireAttachment, loadOverride, storeOverride);
mtlRPDesc.visibilityResultBuffer = _occlusionQueryState.getVisibilityResultMTLBuffer();
// Only set the layered rendering properties if layered rendering is supported and the framebuffer really has multiple layers
@@ -407,8 +406,8 @@
// Clears the render area of the framebuffer attachments.
void MVKCommandEncoder::clearRenderArea() {
- MVKVectorInline<VkClearAttachment, kMVKDefaultAttachmentCount> clearAtts;
- getSubpass()->populateClearAttachments(clearAtts, _clearValues);
+ MVKClearAttachments clearAtts;
+ getSubpass()->populateClearAttachments(clearAtts, _clearValues.contents());
uint32_t clearAttCnt = (uint32_t)clearAtts.size();
@@ -597,7 +596,7 @@
MVKActivatedQueries* pAQs = _pActivatedQueries;
[_mtlCmdBuffer addCompletedHandler: ^(id<MTLCommandBuffer> mtlCmdBuff) {
for (auto& qryPair : *pAQs) {
- qryPair.first->finishQueries(qryPair.second);
+ qryPair.first->finishQueries(qryPair.second.contents());
}
delete pAQs;
}];
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 05c9c18..660c74e 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -21,7 +21,7 @@
#include "MVKMTLResourceBindings.h"
#include "MVKCommandResourceFactory.h"
#include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <unordered_map>
class MVKCommandEncoder;
@@ -140,7 +140,7 @@
* The isSettingDynamically indicates that the scissor is being changed dynamically,
* which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR.
*/
- void setViewports(const MVKVector<VkViewport> &viewports,
+ void setViewports(const MVKArrayRef<VkViewport> viewports,
uint32_t firstViewport,
bool isSettingDynamically);
@@ -152,7 +152,7 @@
void encodeImpl(uint32_t stage) override;
void resetImpl() override;
- MVKVectorInline<VkViewport, kMVKCachedViewportScissorCount> _viewports, _dynamicViewports;
+ MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports, _dynamicViewports;
};
@@ -169,7 +169,7 @@
* The isSettingDynamically indicates that the scissor is being changed dynamically,
* which is only allowed if the pipeline was created as VK_DYNAMIC_STATE_SCISSOR.
*/
- void setScissors(const MVKVector<VkRect2D> &scissors,
+ void setScissors(const MVKArrayRef<VkRect2D> scissors,
uint32_t firstScissor,
bool isSettingDynamically);
@@ -181,7 +181,7 @@
void encodeImpl(uint32_t stage) override;
void resetImpl() override;
- MVKVectorInline<VkRect2D, kMVKCachedViewportScissorCount> _scissors, _dynamicScissors;
+ MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors, _dynamicScissors;
};
@@ -194,7 +194,7 @@
public:
/** Sets the specified push constants. */
- void setPushConstants(uint32_t offset, MVKVector<char>& pushConstants);
+ void setPushConstants(uint32_t offset, MVKArrayRef<char> pushConstants);
/** Sets the index of the Metal buffer used to hold the push constants. */
void setMTLBufferIndex(uint32_t mtlBufferIndex);
@@ -209,7 +209,7 @@
void resetImpl() override;
bool isTessellating();
- MVKVectorInline<char, 128> _pushConstants;
+ MVKSmallVector<char, 128> _pushConstants;
VkShaderStageFlagBits _shaderStage;
uint32_t _mtlBufferIndex = 0;
};
@@ -365,8 +365,8 @@
// Template function that updates an existing binding or adds a new binding to a vector
// of bindings, and marks the binding, the vector, and this instance as dirty
- template<class T, class U>
- void bind(const T& b, U& bindings, bool& bindingsDirtyFlag) {
+ template<class T, class V>
+ void bind(const T& b, V& bindings, bool& bindingsDirtyFlag) {
if ( !b.mtlResource ) { return; }
@@ -385,31 +385,71 @@
}
// For texture bindings, we also keep track of whether any bindings need a texture swizzle
- void bind(const MVKMTLTextureBinding& tb, MVKVector<MVKMTLTextureBinding>& texBindings,
- bool& bindingsDirtyFlag, bool& needsSwizzleFlag) {
+ template<class V>
+ void bind(const MVKMTLTextureBinding& tb, V& texBindings, bool& bindingsDirtyFlag, bool& needsSwizzleFlag) {
bind(tb, texBindings, bindingsDirtyFlag);
if (tb.swizzle != 0) { needsSwizzleFlag = true; }
}
// Template function that executes a lambda expression on each dirty element of
// a vector of bindings, and marks the bindings and the vector as no longer dirty.
- template<class T>
- void encodeBinding(MVKVector<T>& bindings,
- bool& bindingsDirtyFlag,
- std::function<void(MVKCommandEncoder* cmdEncoder, T& b)> mtlOperation) {
- if (bindingsDirtyFlag) {
- bindingsDirtyFlag = false;
- for (auto& b : bindings) {
- if (b.isDirty) {
- mtlOperation(_cmdEncoder, b);
- b.isDirty = false;
- }
- }
- }
- }
+ template<class T, class V>
+ void encodeBinding(V& bindings,
+ bool& bindingsDirtyFlag,
+ std::function<void(MVKCommandEncoder* cmdEncoder, T& b)> mtlOperation) {
+ if (bindingsDirtyFlag) {
+ bindingsDirtyFlag = false;
+ for (auto& b : bindings) {
+ if (b.isDirty) {
+ mtlOperation(_cmdEncoder, b);
+ b.isDirty = false;
+ }
+ }
+ }
+ }
- void updateImplicitBuffer(MVKVector<uint32_t> &contents, uint32_t index, uint32_t value);
- void assertMissingSwizzles(bool needsSwizzle, const char* stageName, MVKVector<MVKMTLTextureBinding>& texBindings);
+ // Updates a value at the given index in the given vector, resizing if needed.
+ template<class V>
+ void updateImplicitBuffer(V &contents, uint32_t index, uint32_t value) {
+ if (index >= contents.size()) { contents.resize(index + 1); }
+ contents[index] = value;
+ }
+
+ void assertMissingSwizzles(bool needsSwizzle, const char* stageName, const MVKArrayRef<MVKMTLTextureBinding>& texBindings);
+
+ template<size_t N>
+ struct ResourceBindings {
+ MVKSmallVector<MVKMTLBufferBinding, N> bufferBindings;
+ MVKSmallVector<MVKMTLTextureBinding, N> textureBindings;
+ MVKSmallVector<MVKMTLSamplerStateBinding, N> samplerStateBindings;
+ MVKSmallVector<uint32_t, N> swizzleConstants;
+ MVKSmallVector<uint32_t, N> bufferSizes;
+
+ MVKMTLBufferBinding swizzleBufferBinding;
+ MVKMTLBufferBinding bufferSizeBufferBinding;
+
+ bool areBufferBindingsDirty = false;
+ bool areTextureBindingsDirty = false;
+ bool areSamplerStateBindingsDirty = false;
+
+ bool needsSwizzle = false;
+
+ void reset() {
+ bufferBindings.clear();
+ textureBindings.clear();
+ samplerStateBindings.clear();
+ swizzleConstants.clear();
+ bufferSizes.clear();
+
+ areBufferBindingsDirty = false;
+ areTextureBindingsDirty = false;
+ areSamplerStateBindingsDirty = false;
+ swizzleBufferBinding.isDirty = false;
+ bufferSizeBufferBinding.isDirty = false;
+
+ needsSwizzle = false;
+ }
+ };
};
@@ -457,7 +497,7 @@
const char* pStageName,
bool fullImageViewSwizzle,
std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&)> bindBuffer,
- std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindImplicitBuffer,
+ std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, const MVKArrayRef<uint32_t>&)> bindImplicitBuffer,
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler);
@@ -471,23 +511,7 @@
void resetImpl() override;
void markDirty() override;
- struct ShaderStage {
- MVKVectorInline<MVKMTLBufferBinding, 8> bufferBindings;
- MVKVectorInline<MVKMTLTextureBinding, 8> textureBindings;
- MVKVectorInline<MVKMTLSamplerStateBinding, 8> samplerStateBindings;
- MVKVectorInline<uint32_t, 8> swizzleConstants;
- MVKVectorInline<uint32_t, 8> bufferSizes;
- MVKMTLBufferBinding swizzleBufferBinding;
- MVKMTLBufferBinding bufferSizeBufferBinding;
-
- bool areBufferBindingsDirty = false;
- bool areTextureBindingsDirty = false;
- bool areSamplerStateBindingsDirty = false;
-
- bool needsSwizzle = false;
- };
-
- ShaderStage _shaderStages[4];
+ ResourceBindings<8> _shaderStageResourceBindings[4];
};
@@ -525,19 +549,7 @@
void encodeImpl(uint32_t) override;
void resetImpl() override;
- MVKVectorInline<MVKMTLBufferBinding, 4> _bufferBindings;
- MVKVectorInline<MVKMTLTextureBinding, 4> _textureBindings;
- MVKVectorInline<MVKMTLSamplerStateBinding, 4> _samplerStateBindings;
- MVKVectorInline<uint32_t, 4> _swizzleConstants;
- MVKVectorInline<uint32_t, 4> _bufferSizes;
- MVKMTLBufferBinding _swizzleBufferBinding;
- MVKMTLBufferBinding _bufferSizeBufferBinding;
-
- bool _areBufferBindingsDirty = false;
- bool _areTextureBindingsDirty = false;
- bool _areSamplerStateBindingsDirty = false;
-
- bool _needsSwizzle = false;
+ ResourceBindings<4> _resourceBindings;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index 8920101..d63ba37 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -58,11 +58,11 @@
#pragma mark -
#pragma mark MVKViewportCommandEncoderState
-void MVKViewportCommandEncoderState::setViewports(const MVKVector<VkViewport> &viewports,
+void MVKViewportCommandEncoderState::setViewports(const MVKArrayRef<VkViewport> viewports,
uint32_t firstViewport,
bool isSettingDynamically) {
- size_t vpCnt = viewports.size();
+ size_t vpCnt = viewports.size;
uint32_t maxViewports = _cmdEncoder->getDevice()->_pProperties->limits.maxViewports;
if ((firstViewport + vpCnt > maxViewports) ||
(firstViewport >= maxViewports) ||
@@ -111,11 +111,11 @@
#pragma mark -
#pragma mark MVKScissorCommandEncoderState
-void MVKScissorCommandEncoderState::setScissors(const MVKVector<VkRect2D> &scissors,
+void MVKScissorCommandEncoderState::setScissors(const MVKArrayRef<VkRect2D> scissors,
uint32_t firstScissor,
bool isSettingDynamically) {
- size_t sCnt = scissors.size();
+ size_t sCnt = scissors.size;
uint32_t maxScissors = _cmdEncoder->getDevice()->_pProperties->limits.maxViewports;
if ((firstScissor + sCnt > maxScissors) ||
(firstScissor >= maxScissors) ||
@@ -164,12 +164,12 @@
#pragma mark -
#pragma mark MVKPushConstantsCommandEncoderState
-void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, MVKVector<char>& pushConstants) {
+void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, MVKArrayRef<char> pushConstants) {
// MSL structs can have a larger size than the equivalent C struct due to MSL alignment needs.
// Typically any MSL struct that contains a float4 will also have a size that is rounded up to a multiple of a float4 size.
// Ensure that we pass along enough content to cover this extra space even if it is never actually accessed by the shader.
size_t pcSizeAlign = _cmdEncoder->getDevice()->_pMetalFeatures->pushConstantSizeAlignment;
- size_t pcSize = pushConstants.size();
+ size_t pcSize = pushConstants.size;
size_t pcBuffSize = mvkAlignByteCount(offset + pcSize, pcSizeAlign);
mvkEnsureSize(_pushConstants, pcBuffSize);
copy(pushConstants.begin(), pushConstants.end(), _pushConstants.begin() + offset);
@@ -491,16 +491,10 @@
#pragma mark -
#pragma mark MVKResourcesCommandEncoderState
-// Updates a value at the given index in the given vector.
-void MVKResourcesCommandEncoderState::updateImplicitBuffer(MVKVector<uint32_t> &contents, uint32_t index, uint32_t value) {
- if (index >= contents.size()) { contents.resize(index + 1); }
- contents[index] = value;
-}
-
// If a swizzle is needed for this stage, iterates all the bindings and logs errors for those that need texture swizzling.
-void MVKResourcesCommandEncoderState::assertMissingSwizzles(bool needsSwizzle, const char* stageName, MVKVector<MVKMTLTextureBinding>& texBindings) {
+void MVKResourcesCommandEncoderState::assertMissingSwizzles(bool needsSwizzle, const char* stageName, const MVKArrayRef<MVKMTLTextureBinding>& texBindings) {
if (needsSwizzle) {
- for (MVKMTLTextureBinding& tb : texBindings) {
+ for (auto& tb : texBindings) {
VkComponentMapping vkcm = mvkUnpackSwizzle(tb.swizzle);
if (!mvkVkComponentMappingsMatch(vkcm, {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A})) {
MVKLogError("Pipeline does not support component swizzle (%s, %s, %s, %s) required by a VkImageView used in the %s shader."
@@ -519,15 +513,15 @@
#pragma mark MVKGraphicsResourcesCommandEncoderState
void MVKGraphicsResourcesCommandEncoderState::bindBuffer(MVKShaderStage stage, const MVKMTLBufferBinding& binding) {
- bind(binding, _shaderStages[stage].bufferBindings, _shaderStages[stage].areBufferBindingsDirty);
+ bind(binding, _shaderStageResourceBindings[stage].bufferBindings, _shaderStageResourceBindings[stage].areBufferBindingsDirty);
}
void MVKGraphicsResourcesCommandEncoderState::bindTexture(MVKShaderStage stage, const MVKMTLTextureBinding& binding) {
- bind(binding, _shaderStages[stage].textureBindings, _shaderStages[stage].areTextureBindingsDirty, _shaderStages[stage].needsSwizzle);
+ bind(binding, _shaderStageResourceBindings[stage].textureBindings, _shaderStageResourceBindings[stage].areTextureBindingsDirty, _shaderStageResourceBindings[stage].needsSwizzle);
}
void MVKGraphicsResourcesCommandEncoderState::bindSamplerState(MVKShaderStage stage, const MVKMTLSamplerStateBinding& binding) {
- bind(binding, _shaderStages[stage].samplerStateBindings, _shaderStages[stage].areSamplerStateBindingsDirty);
+ bind(binding, _shaderStageResourceBindings[stage].samplerStateBindings, _shaderStageResourceBindings[stage].areSamplerStateBindingsDirty);
}
void MVKGraphicsResourcesCommandEncoderState::bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding,
@@ -535,13 +529,13 @@
bool needTessCtlSwizzleBuffer,
bool needTessEvalSwizzleBuffer,
bool needFragmentSwizzleBuffer) {
- for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
- _shaderStages[i].swizzleBufferBinding.index = binding.stages[i];
+ for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+ _shaderStageResourceBindings[i].swizzleBufferBinding.index = binding.stages[i];
}
- _shaderStages[kMVKShaderStageVertex].swizzleBufferBinding.isDirty = needVertexSwizzleBuffer;
- _shaderStages[kMVKShaderStageTessCtl].swizzleBufferBinding.isDirty = needTessCtlSwizzleBuffer;
- _shaderStages[kMVKShaderStageTessEval].swizzleBufferBinding.isDirty = needTessEvalSwizzleBuffer;
- _shaderStages[kMVKShaderStageFragment].swizzleBufferBinding.isDirty = needFragmentSwizzleBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageVertex].swizzleBufferBinding.isDirty = needVertexSwizzleBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageTessCtl].swizzleBufferBinding.isDirty = needTessCtlSwizzleBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageTessEval].swizzleBufferBinding.isDirty = needTessEvalSwizzleBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageFragment].swizzleBufferBinding.isDirty = needFragmentSwizzleBuffer;
}
void MVKGraphicsResourcesCommandEncoderState::bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding,
@@ -549,23 +543,23 @@
bool needTessCtlSizeBuffer,
bool needTessEvalSizeBuffer,
bool needFragmentSizeBuffer) {
- for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
- _shaderStages[i].bufferSizeBufferBinding.index = binding.stages[i];
+ for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+ _shaderStageResourceBindings[i].bufferSizeBufferBinding.index = binding.stages[i];
}
- _shaderStages[kMVKShaderStageVertex].bufferSizeBufferBinding.isDirty = needVertexSizeBuffer;
- _shaderStages[kMVKShaderStageTessCtl].bufferSizeBufferBinding.isDirty = needTessCtlSizeBuffer;
- _shaderStages[kMVKShaderStageTessEval].bufferSizeBufferBinding.isDirty = needTessEvalSizeBuffer;
- _shaderStages[kMVKShaderStageFragment].bufferSizeBufferBinding.isDirty = needFragmentSizeBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageVertex].bufferSizeBufferBinding.isDirty = needVertexSizeBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageTessCtl].bufferSizeBufferBinding.isDirty = needTessCtlSizeBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageTessEval].bufferSizeBufferBinding.isDirty = needTessEvalSizeBuffer;
+ _shaderStageResourceBindings[kMVKShaderStageFragment].bufferSizeBufferBinding.isDirty = needFragmentSizeBuffer;
}
void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stage,
const char* pStageName,
bool fullImageViewSwizzle,
std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&)> bindBuffer,
- std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, MVKVector<uint32_t>&)> bindImplicitBuffer,
+ std::function<void(MVKCommandEncoder*, MVKMTLBufferBinding&, const MVKArrayRef<uint32_t>&)> bindImplicitBuffer,
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler) {
- auto& shaderStage = _shaderStages[stage];
+ auto& shaderStage = _shaderStageResourceBindings[stage];
encodeBinding<MVKMTLBufferBinding>(shaderStage.bufferBindings, shaderStage.areBufferBindingsDirty, bindBuffer);
if (shaderStage.swizzleBufferBinding.isDirty) {
@@ -574,10 +568,10 @@
if (b.isDirty) { updateImplicitBuffer(shaderStage.swizzleConstants, b.index, b.swizzle); }
}
- bindImplicitBuffer(_cmdEncoder, shaderStage.swizzleBufferBinding, shaderStage.swizzleConstants);
+ bindImplicitBuffer(_cmdEncoder, shaderStage.swizzleBufferBinding, shaderStage.swizzleConstants.contents());
} else {
- assertMissingSwizzles(shaderStage.needsSwizzle && !fullImageViewSwizzle, pStageName, shaderStage.textureBindings);
+ assertMissingSwizzles(shaderStage.needsSwizzle && !fullImageViewSwizzle, pStageName, shaderStage.textureBindings.contents());
}
if (shaderStage.bufferSizeBufferBinding.isDirty) {
@@ -585,7 +579,7 @@
if (b.isDirty) { updateImplicitBuffer(shaderStage.bufferSizes, b.index, b.size); }
}
- bindImplicitBuffer(_cmdEncoder, shaderStage.bufferSizeBufferBinding, shaderStage.bufferSizes);
+ bindImplicitBuffer(_cmdEncoder, shaderStage.bufferSizeBufferBinding, shaderStage.bufferSizes.contents());
}
encodeBinding<MVKMTLTextureBinding>(shaderStage.textureBindings, shaderStage.areTextureBindingsDirty, bindTexture);
@@ -595,10 +589,10 @@
// Mark everything as dirty
void MVKGraphicsResourcesCommandEncoderState::markDirty() {
MVKCommandEncoderState::markDirty();
- for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
- MVKResourcesCommandEncoderState::markDirty(_shaderStages[i].bufferBindings, _shaderStages[i].areBufferBindingsDirty);
- MVKResourcesCommandEncoderState::markDirty(_shaderStages[i].textureBindings, _shaderStages[i].areTextureBindingsDirty);
- MVKResourcesCommandEncoderState::markDirty(_shaderStages[i].samplerStateBindings, _shaderStages[i].areSamplerStateBindingsDirty);
+ for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+ MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].bufferBindings, _shaderStageResourceBindings[i].areBufferBindingsDirty);
+ MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].textureBindings, _shaderStageResourceBindings[i].areTextureBindingsDirty);
+ MVKResourcesCommandEncoderState::markDirty(_shaderStageResourceBindings[i].samplerStateBindings, _shaderStageResourceBindings[i].areSamplerStateBindingsDirty);
}
}
@@ -621,10 +615,10 @@
offset: b.offset
atIndex: b.index];
},
- [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+ [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder,
- s.data(),
- s.size() * sizeof(uint32_t),
+ s.data,
+ s.size * sizeof(uint32_t),
b.index);
},
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -651,10 +645,10 @@
offset: b.offset
atIndex: b.index];
},
- [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+ [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
cmdEncoder->setComputeBytes(cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationControl),
- s.data(),
- s.size() * sizeof(uint32_t),
+ s.data,
+ s.size * sizeof(uint32_t),
b.index);
},
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -681,10 +675,10 @@
offset: b.offset
atIndex: b.index];
},
- [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+ [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
cmdEncoder->setVertexBytes(cmdEncoder->_mtlRenderEncoder,
- s.data(),
- s.size() * sizeof(uint32_t),
+ s.data,
+ s.size * sizeof(uint32_t),
b.index);
},
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -711,10 +705,10 @@
offset: b.offset
atIndex: b.index];
},
- [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, MVKVector<uint32_t>& s)->void {
+ [](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b, const MVKArrayRef<uint32_t>& s)->void {
cmdEncoder->setFragmentBytes(cmdEncoder->_mtlRenderEncoder,
- s.data(),
- s.size() * sizeof(uint32_t),
+ s.data,
+ s.size * sizeof(uint32_t),
b.index);
},
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
@@ -729,21 +723,9 @@
}
void MVKGraphicsResourcesCommandEncoderState::resetImpl() {
- for (uint32_t i = kMVKShaderStageVertex; i < kMVKShaderStageCompute; i++) {
- _shaderStages[i].bufferBindings.clear();
- _shaderStages[i].textureBindings.clear();
- _shaderStages[i].samplerStateBindings.clear();
- _shaderStages[i].swizzleConstants.clear();
- _shaderStages[i].bufferSizes.clear();
-
- _shaderStages[i].areBufferBindingsDirty = false;
- _shaderStages[i].areTextureBindingsDirty = false;
- _shaderStages[i].areSamplerStateBindingsDirty = false;
- _shaderStages[i].swizzleBufferBinding.isDirty = false;
- _shaderStages[i].bufferSizeBufferBinding.isDirty = false;
-
- _shaderStages[i].needsSwizzle = false;
- }
+ for (uint32_t i = kMVKShaderStageVertex; i <= kMVKShaderStageFragment; i++) {
+ _shaderStageResourceBindings[i].reset();
+ }
}
@@ -751,35 +733,35 @@
#pragma mark MVKComputeResourcesCommandEncoderState
void MVKComputeResourcesCommandEncoderState::bindBuffer(const MVKMTLBufferBinding& binding) {
- bind(binding, _bufferBindings, _areBufferBindingsDirty);
+ bind(binding, _resourceBindings.bufferBindings, _resourceBindings.areBufferBindingsDirty);
}
void MVKComputeResourcesCommandEncoderState::bindTexture(const MVKMTLTextureBinding& binding) {
- bind(binding, _textureBindings, _areTextureBindingsDirty, _needsSwizzle);
+ bind(binding, _resourceBindings.textureBindings, _resourceBindings.areTextureBindingsDirty, _resourceBindings.needsSwizzle);
}
void MVKComputeResourcesCommandEncoderState::bindSamplerState(const MVKMTLSamplerStateBinding& binding) {
- bind(binding, _samplerStateBindings, _areSamplerStateBindingsDirty);
+ bind(binding, _resourceBindings.samplerStateBindings, _resourceBindings.areSamplerStateBindingsDirty);
}
void MVKComputeResourcesCommandEncoderState::bindSwizzleBuffer(const MVKShaderImplicitRezBinding& binding,
bool needSwizzleBuffer) {
- _swizzleBufferBinding.index = binding.stages[kMVKShaderStageCompute];
- _swizzleBufferBinding.isDirty = needSwizzleBuffer;
+ _resourceBindings.swizzleBufferBinding.index = binding.stages[kMVKShaderStageCompute];
+ _resourceBindings.swizzleBufferBinding.isDirty = needSwizzleBuffer;
}
void MVKComputeResourcesCommandEncoderState::bindBufferSizeBuffer(const MVKShaderImplicitRezBinding& binding,
bool needBufferSizeBuffer) {
- _bufferSizeBufferBinding.index = binding.stages[kMVKShaderStageCompute];
- _bufferSizeBufferBinding.isDirty = needBufferSizeBuffer;
+ _resourceBindings.bufferSizeBufferBinding.index = binding.stages[kMVKShaderStageCompute];
+ _resourceBindings.bufferSizeBufferBinding.isDirty = needBufferSizeBuffer;
}
// Mark everything as dirty
void MVKComputeResourcesCommandEncoderState::markDirty() {
MVKCommandEncoderState::markDirty();
- MVKResourcesCommandEncoderState::markDirty(_bufferBindings, _areBufferBindingsDirty);
- MVKResourcesCommandEncoderState::markDirty(_textureBindings, _areTextureBindingsDirty);
- MVKResourcesCommandEncoderState::markDirty(_samplerStateBindings, _areSamplerStateBindingsDirty);
+ MVKResourcesCommandEncoderState::markDirty(_resourceBindings.bufferBindings, _resourceBindings.areBufferBindingsDirty);
+ MVKResourcesCommandEncoderState::markDirty(_resourceBindings.textureBindings, _resourceBindings.areTextureBindingsDirty);
+ MVKResourcesCommandEncoderState::markDirty(_resourceBindings.samplerStateBindings, _resourceBindings.areSamplerStateBindingsDirty);
}
void MVKComputeResourcesCommandEncoderState::encodeImpl(uint32_t) {
@@ -789,7 +771,7 @@
if (pipeline)
fullImageViewSwizzle = pipeline->fullImageViewSwizzle();
- encodeBinding<MVKMTLBufferBinding>(_bufferBindings, _areBufferBindingsDirty,
+ encodeBinding<MVKMTLBufferBinding>(_resourceBindings.bufferBindings, _resourceBindings.areBufferBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLBufferBinding& b)->void {
if (b.isInline)
cmdEncoder->setComputeBytes(cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
@@ -802,40 +784,40 @@
atIndex: b.index];
});
- if (_swizzleBufferBinding.isDirty) {
+ if (_resourceBindings.swizzleBufferBinding.isDirty) {
- for (auto& b : _textureBindings) {
- if (b.isDirty) { updateImplicitBuffer(_swizzleConstants, b.index, b.swizzle); }
+ for (auto& b : _resourceBindings.textureBindings) {
+ if (b.isDirty) { updateImplicitBuffer(_resourceBindings.swizzleConstants, b.index, b.swizzle); }
}
_cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
- _swizzleConstants.data(),
- _swizzleConstants.size() * sizeof(uint32_t),
- _swizzleBufferBinding.index);
+ _resourceBindings.swizzleConstants.data(),
+ _resourceBindings.swizzleConstants.size() * sizeof(uint32_t),
+ _resourceBindings.swizzleBufferBinding.index);
} else {
- assertMissingSwizzles(_needsSwizzle && !fullImageViewSwizzle, "compute", _textureBindings);
+ assertMissingSwizzles(_resourceBindings.needsSwizzle && !fullImageViewSwizzle, "compute", _resourceBindings.textureBindings.contents());
}
- if (_bufferSizeBufferBinding.isDirty) {
- for (auto& b : _bufferBindings) {
- if (b.isDirty) { updateImplicitBuffer(_bufferSizes, b.index, b.size); }
+ if (_resourceBindings.bufferSizeBufferBinding.isDirty) {
+ for (auto& b : _resourceBindings.bufferBindings) {
+ if (b.isDirty) { updateImplicitBuffer(_resourceBindings.bufferSizes, b.index, b.size); }
}
_cmdEncoder->setComputeBytes(_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch),
- _bufferSizes.data(),
- _bufferSizes.size() * sizeof(uint32_t),
- _bufferSizeBufferBinding.index);
+ _resourceBindings.bufferSizes.data(),
+ _resourceBindings.bufferSizes.size() * sizeof(uint32_t),
+ _resourceBindings.bufferSizeBufferBinding.index);
}
- encodeBinding<MVKMTLTextureBinding>(_textureBindings, _areTextureBindingsDirty,
+ encodeBinding<MVKMTLTextureBinding>(_resourceBindings.textureBindings, _resourceBindings.areTextureBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLTextureBinding& b)->void {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setTexture: b.mtlTexture
atIndex: b.index];
});
- encodeBinding<MVKMTLSamplerStateBinding>(_samplerStateBindings, _areSamplerStateBindingsDirty,
+ encodeBinding<MVKMTLSamplerStateBinding>(_resourceBindings.samplerStateBindings, _resourceBindings.areSamplerStateBindingsDirty,
[](MVKCommandEncoder* cmdEncoder, MVKMTLSamplerStateBinding& b)->void {
[cmdEncoder->getMTLComputeEncoder(kMVKCommandUseDispatch) setSamplerState: b.mtlSamplerState
atIndex: b.index];
@@ -843,19 +825,7 @@
}
void MVKComputeResourcesCommandEncoderState::resetImpl() {
- _bufferBindings.clear();
- _textureBindings.clear();
- _samplerStateBindings.clear();
- _swizzleConstants.clear();
- _bufferSizes.clear();
-
- _areBufferBindingsDirty = false;
- _areTextureBindingsDirty = false;
- _areSamplerStateBindingsDirty = false;
- _swizzleBufferBinding.isDirty = false;
- _bufferSizeBufferBinding.isDirty = false;
-
- _needsSwizzle = false;
+ _resourceBindings.reset();
}
diff --git a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
index 17f9589..c8dc025 100644
--- a/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
+++ b/MoltenVK/MoltenVK/Commands/MVKMTLBufferAllocation.h
@@ -22,7 +22,7 @@
#include "MVKFoundation.h"
#include "MVKObjectPool.h"
#include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
class MVKMTLBufferAllocationPool;
@@ -97,7 +97,7 @@
NSUInteger _nextOffset;
NSUInteger _allocationLength;
NSUInteger _mtlBufferLength;
- MVKVectorInline<id<MTLBuffer>, 64> _mtlBuffers;
+ MVKSmallVector<id<MTLBuffer>, 64> _mtlBuffers;
MVKDevice* _device;
};
@@ -142,7 +142,7 @@
~MVKMTLBufferAllocator() override;
protected:
- MVKVectorInline<MVKMTLBufferAllocationPool*, 32> _regionPools;
+ MVKSmallVector<MVKMTLBufferAllocationPool*, 32> _regionPools;
NSUInteger _maxAllocationLength;
bool _makeThreadSafe;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
index c19f2eb..65131c7 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.h
@@ -19,8 +19,7 @@
#pragma once
#include "MVKImage.h"
-#include "MVKVector.h"
-#include <vector>
+#include "MVKSmallVector.h"
class MVKDescriptorSet;
class MVKDescriptorSetLayout;
@@ -89,7 +88,7 @@
MVKDescriptorSet* descSet,
uint32_t descStartIndex,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex);
/** Encodes this binding layout and the specified descriptor on the specified command encoder immediately. */
@@ -123,7 +122,7 @@
MVKDescriptorSetLayout* _layout;
VkDescriptorSetLayoutBinding _info;
- std::vector<MVKSampler*> _immutableSamplers;
+ MVKSmallVector<MVKSampler*> _immutableSamplers;
MVKShaderResourceBinding _mtlResourceIndexOffsets;
bool _applyToStage[kMVKShaderStageMax];
};
@@ -148,7 +147,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) = 0;
/**
@@ -202,7 +201,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) override;
void write(MVKDescriptorSet* mvkDescSet,
@@ -280,7 +279,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) override;
void write(MVKDescriptorSet* mvkDescSet,
@@ -319,7 +318,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) override;
void write(MVKDescriptorSet* mvkDescSet,
@@ -391,7 +390,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex);
void write(MVKDescriptorSet* mvkDescSet,
@@ -433,7 +432,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) override;
void write(MVKDescriptorSet* mvkDescSet,
@@ -473,7 +472,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) override;
void write(MVKDescriptorSet* mvkDescSet,
@@ -511,7 +510,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) override;
void write(MVKDescriptorSet* mvkDescSet,
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
index 3179cc2..7fa99d5 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptor.mm
@@ -83,7 +83,7 @@
MVKDescriptorSet* descSet,
uint32_t descStartIndex,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
// Establish the resource indices to use, by combining the offsets of the DSL and this DSL binding.
@@ -93,7 +93,7 @@
for (uint32_t descIdx = 0; descIdx < descCnt; descIdx++) {
MVKDescriptor* mvkDesc = descSet->getDescriptor(descStartIndex + descIdx);
mvkDesc->bind(cmdEncoder, _info.descriptorType, descIdx, _applyToStage,
- mtlIdxs, pDynamicOffsets, pDynamicOffsetIndex);
+ mtlIdxs, dynamicOffsets, pDynamicOffsetIndex);
}
return descCnt;
}
@@ -476,7 +476,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
MVKMTLBufferBinding bb;
NSUInteger bufferDynamicOffset = 0;
@@ -485,9 +485,8 @@
// After determining dynamic part of offset (zero otherwise), fall through to non-dynamic handling
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
- if (pDynamicOffsets) {
- bufferDynamicOffset = (*pDynamicOffsets)[*pDynamicOffsetIndex];
- (*pDynamicOffsetIndex)++; // Move on to next dynamic offset (and feedback to caller)
+ if (dynamicOffsets.size > *pDynamicOffsetIndex) {
+ bufferDynamicOffset = dynamicOffsets[(*pDynamicOffsetIndex)++]; // Move on to next dynamic offset (and feedback to caller)
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
@@ -579,12 +578,12 @@
// A null cmdEncoder can be passed to perform a validation pass
void MVKInlineUniformBlockDescriptor::bind(MVKCommandEncoder* cmdEncoder,
- VkDescriptorType descriptorType,
- uint32_t descriptorIndex,
- bool stages[],
- MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
- uint32_t* pDynamicOffsetIndex) {
+ VkDescriptorType descriptorType,
+ uint32_t descriptorIndex,
+ bool stages[],
+ MVKShaderResourceBinding& mtlIndexes,
+ MVKArrayRef<uint32_t> dynamicOffsets,
+ uint32_t* pDynamicOffsetIndex) {
MVKMTLBufferBinding bb;
switch (descriptorType) {
@@ -680,7 +679,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
MVKMTLTextureBinding tb;
MVKMTLBufferBinding bb;
@@ -798,7 +797,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
MVKMTLSamplerStateBinding sb;
switch (descriptorType) {
@@ -916,12 +915,12 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_SAMPLER: {
MVKSamplerDescriptorMixin::bind(cmdEncoder, descriptorType, descriptorIndex, stages,
- mtlIndexes, pDynamicOffsets, pDynamicOffsetIndex);
+ mtlIndexes, dynamicOffsets, pDynamicOffsetIndex);
break;
}
@@ -985,14 +984,14 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
switch (descriptorType) {
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: {
MVKImageDescriptor::bind(cmdEncoder, descriptorType, descriptorIndex, stages,
- mtlIndexes, pDynamicOffsets, pDynamicOffsetIndex);
+ mtlIndexes, dynamicOffsets, pDynamicOffsetIndex);
MVKSamplerDescriptorMixin::bind(cmdEncoder, descriptorType, descriptorIndex, stages,
- mtlIndexes, pDynamicOffsets, pDynamicOffsetIndex);
+ mtlIndexes, dynamicOffsets, pDynamicOffsetIndex);
break;
}
@@ -1059,7 +1058,7 @@
uint32_t descriptorIndex,
bool stages[],
MVKShaderResourceBinding& mtlIndexes,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
MVKMTLTextureBinding tb;
MVKMTLBufferBinding bb;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index a5cbe57..1ed6b15 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -19,6 +19,7 @@
#pragma once
#include "MVKDescriptor.h"
+#include "MVKSmallVector.h"
#include <unordered_set>
#include <unordered_map>
#include <vector>
@@ -46,13 +47,13 @@
void bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
MVKDescriptorSet* descSet,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex);
/** Encodes this descriptor set layout and the specified descriptor updates on the specified command encoder immediately. */
void pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
- MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+ MVKArrayRef<VkWriteDescriptorSet>& descriptorWrites,
MVKShaderResourceBinding& dslMTLRezIdxOffsets);
@@ -85,7 +86,7 @@
uint32_t getDescriptorIndex(uint32_t binding, uint32_t elementIndex);
inline MVKDescriptorSetLayoutBinding* getBinding(uint32_t binding) { return &_bindings[_bindingToIndex[binding]]; }
- std::vector<MVKDescriptorSetLayoutBinding> _bindings;
+ MVKSmallVector<MVKDescriptorSetLayoutBinding> _bindings;
std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
MVKShaderResourceBinding _mtlResourceCounts;
uint32_t _descriptorCount;
@@ -137,7 +138,7 @@
MVKDescriptorSetLayout* _layout;
MVKDescriptorPool* _pool;
- std::vector<MVKDescriptor*> _descriptors;
+ MVKSmallVector<MVKDescriptor*> _descriptors;
};
@@ -164,8 +165,8 @@
void freeDescriptor(MVKDescriptor* mvkDesc);
void reset();
- std::vector<DescriptorClass> _descriptors;
- std::vector<bool> _availability;
+ MVKSmallVector<DescriptorClass> _descriptors;
+ MVKSmallVector<bool> _availability;
uint32_t _nextAvailableIndex;
bool _supportAvailability;
};
@@ -283,7 +284,7 @@
void propogateDebugName() override {}
VkDescriptorUpdateTemplateTypeKHR _type;
- MVKVectorInline<VkDescriptorUpdateTemplateEntryKHR, 1> _entries;
+ MVKSmallVector<VkDescriptorUpdateTemplateEntryKHR, 1> _entries;
};
#pragma mark -
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index 59c2902..9b2526d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -38,15 +38,15 @@
void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
MVKDescriptorSet* descSet,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- MVKVector<uint32_t>* pDynamicOffsets,
+ MVKArrayRef<uint32_t> dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
if (_isPushDescriptorLayout) return;
clearConfigurationResult();
- uint32_t bindCnt = (uint32_t)_bindings.size();
+ size_t bindCnt = _bindings.size();
for (uint32_t descIdx = 0, bindIdx = 0; bindIdx < bindCnt; bindIdx++) {
descIdx += _bindings[bindIdx].bind(cmdEncoder, descSet, descIdx,
- dslMTLRezIdxOffsets, pDynamicOffsets,
+ dslMTLRezIdxOffsets, dynamicOffsets,
pDynamicOffsetIndex);
}
}
@@ -94,7 +94,7 @@
// A null cmdEncoder can be passed to perform a validation pass
void MVKDescriptorSetLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
- MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+ MVKArrayRef<VkWriteDescriptorSet>& descriptorWrites,
MVKShaderResourceBinding& dslMTLRezIdxOffsets) {
if (!_isPushDescriptorLayout) return;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index d23ad13..4232b5c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -23,7 +23,7 @@
#include "MVKMTLResourceBindings.h"
#include "MVKLayers.h"
#include "MVKObjectPool.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include "MVKPixelFormats.h"
#include "MVKOSExtensions.h"
#include "mvk_datatypes.hpp"
@@ -346,7 +346,7 @@
uint64_t getCurrentAllocatedSize();
void initExternalMemoryProperties();
void initExtensions();
- MVKVector<MVKQueueFamily*>& getQueueFamilies();
+ MVKArrayRef<MVKQueueFamily*> getQueueFamilies();
void initPipelineCacheUUID();
uint32_t getHighestMTLFeatureSet();
uint64_t getSpirvCrossRevision();
@@ -362,7 +362,7 @@
VkPhysicalDeviceProperties _properties;
VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT _texelBuffAlignProperties;
VkPhysicalDeviceMemoryProperties _memoryProperties;
- MVKVectorInline<MVKQueueFamily*, kMVKQueueFamilyCount> _queueFamilies;
+ MVKSmallVector<MVKQueueFamily*, kMVKQueueFamilyCount> _queueFamilies;
MVKPixelFormats _pixelFormats;
uint32_t _allMemoryTypes;
uint32_t _hostVisibleMemoryTypes;
@@ -712,8 +712,8 @@
MVKPhysicalDevice* _physicalDevice;
MVKCommandResourceFactory* _commandResourceFactory;
MTLCompileOptions* _mtlCompileOptions;
- MVKVectorInline<MVKVectorInline<MVKQueue*, kMVKQueueCountPerQueueFamily>, kMVKQueueFamilyCount> _queuesByQueueFamilyIndex;
- MVKVectorInline<MVKResource*, 256> _resources;
+ MVKSmallVector<MVKSmallVector<MVKQueue*, kMVKQueueCountPerQueueFamily>, kMVKQueueFamilyCount> _queuesByQueueFamilyIndex;
+ MVKSmallVector<MVKResource*, 256> _resources;
std::mutex _rezLock;
std::mutex _perfLock;
id<MTLBuffer> _globalVisibilityResultMTLBuffer;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index bde8c19..a367988 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -559,7 +559,7 @@
MTLPixelFormatBGR10A2Unorm,
};
- MVKVectorInline<VkColorSpaceKHR, 16> colorSpaces;
+ MVKSmallVector<VkColorSpaceKHR, 16> colorSpaces;
colorSpaces.push_back(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR);
if (getInstance()->_enabledExtensions.vk_EXT_swapchain_colorspace.enabled) {
#if MVK_MACOS
@@ -719,7 +719,7 @@
// In addition, Metal queues are always general purpose, so the default behaviour is for all
// queue families to support graphics + compute + transfer, unless the app indicates it
// requires queue family specialization.
-MVKVector<MVKQueueFamily*>& MVKPhysicalDevice::getQueueFamilies() {
+MVKArrayRef<MVKQueueFamily*> MVKPhysicalDevice::getQueueFamilies() {
if (_queueFamilies.empty()) {
VkQueueFamilyProperties qfProps;
bool specialize = _mvkInstance->getMoltenVKConfiguration()->specializedQueueFamilies;
@@ -747,14 +747,13 @@
MVKAssert(kMVKQueueFamilyCount >= _queueFamilies.size(), "Adjust value of kMVKQueueFamilyCount.");
}
- return _queueFamilies;
+ return _queueFamilies.contents();
}
VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
VkQueueFamilyProperties* pQueueFamilyProperties) {
-
- auto& qFams = getQueueFamilies();
- uint32_t qfCnt = uint32_t(qFams.size());
+ auto qFams = getQueueFamilies();
+ uint32_t qfCnt = uint32_t(qFams.size);
// If properties aren't actually being requested yet, simply update the returned count
if ( !pQueueFamilyProperties ) {
@@ -778,7 +777,6 @@
VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount,
VkQueueFamilyProperties2KHR* pQueueFamilyProperties) {
-
VkResult rslt;
if (pQueueFamilyProperties) {
// Populate temp array of VkQueueFamilyProperties then copy into array of VkQueueFamilyProperties2KHR.
@@ -3024,7 +3022,7 @@
// Create the command queues
void MVKDevice::initQueues(const VkDeviceCreateInfo* pCreateInfo) {
- auto& qFams = _physicalDevice->getQueueFamilies();
+ auto qFams = _physicalDevice->getQueueFamilies();
uint32_t qrCnt = pCreateInfo->queueCreateInfoCount;
for (uint32_t qrIdx = 0; qrIdx < qrCnt; qrIdx++) {
const VkDeviceQueueCreateInfo* pQFInfo = &pCreateInfo->pQueueCreateInfos[qrIdx];
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
index 0a51525..687937f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDeviceMemory.h
@@ -19,7 +19,7 @@
#pragma once
#include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <mutex>
#import <Metal/Metal.h>
@@ -147,8 +147,8 @@
MVKResource* getDedicatedResource();
void initExternalMemory(VkExternalMemoryHandleTypeFlags handleTypes);
- MVKVectorInline<MVKBuffer*, 4> _buffers;
- MVKVectorInline<MVKImage*, 4> _images;
+ MVKSmallVector<MVKBuffer*, 4> _buffers;
+ MVKSmallVector<MVKImage*, 4> _images;
std::mutex _rezLock;
VkDeviceSize _allocationSize = 0;
VkDeviceSize _mapOffset = 0;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
index cd0838b..e5f2f60 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKFramebuffer.h
@@ -20,7 +20,7 @@
#include "MVKDevice.h"
#include "MVKImage.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#pragma mark MVKFramebuffer
@@ -56,6 +56,6 @@
VkExtent2D _extent;
uint32_t _layerCount;
- MVKVectorInline<MVKImageView*, 4> _attachments;
+ MVKSmallVector<MVKImageView*, 4> _attachments;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
index d655ab5..8d9e2d4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h
@@ -21,7 +21,7 @@
#include "MVKResource.h"
#include "MVKCommandResourceFactory.h"
#include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include <unordered_map>
#include <mutex>
@@ -252,7 +252,7 @@
VkPipelineStageFlags dstStageMask,
MVKPipelineBarrier& barrier);
- MVKVectorInline<MVKImageSubresource, 1> _subresources;
+ MVKSmallVector<MVKImageSubresource, 1> _subresources;
std::unordered_map<NSUInteger, id<MTLTexture>> _mtlTextureViews;
VkExtent3D _extent;
uint32_t _mipLevels;
@@ -369,7 +369,7 @@
id<CAMetalDrawable> _mtlDrawable;
MVKSwapchainImageAvailability _availability;
- MVKVectorInline<MVKSwapchainSignaler, 1> _availabilitySignalers;
+ MVKSmallVector<MVKSwapchainSignaler, 1> _availabilitySignalers;
MVKSwapchainSignaler _preSignaler;
std::mutex _availabilityLock;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
index 3a3018d..638c274 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h
@@ -22,7 +22,7 @@
#include "MVKDevice.h"
#include "MVKLayers.h"
#include "MVKVulkanAPIObject.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include "vk_mvk_moltenvk.h"
#include <unordered_map>
#include <string>
@@ -189,9 +189,9 @@
MVKConfiguration _mvkConfig;
VkApplicationInfo _appInfo;
- MVKVectorInline<MVKPhysicalDevice, 2> _physicalDevices;
- MVKVectorDefault<MVKDebugReportCallback*> _debugReportCallbacks;
- MVKVectorDefault<MVKDebugUtilsMessenger*> _debugUtilMessengers;
+ MVKSmallVector<MVKPhysicalDevice, 2> _physicalDevices;
+ MVKSmallVector<MVKDebugReportCallback*> _debugReportCallbacks;
+ MVKSmallVector<MVKDebugUtilsMessenger*> _debugUtilMessengers;
std::unordered_map<std::string, MVKEntryPoint> _entryPoints;
std::mutex _dcbLock;
bool _hasDebugReportCallbacks;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 3221299..8dd5e2c 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -22,7 +22,7 @@
#include "MVKDescriptorSet.h"
#include "MVKShaderModule.h"
#include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVReflection.h>
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include <unordered_set>
@@ -54,13 +54,13 @@
/** Binds descriptor sets to a command encoder. */
void bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
- MVKVector<MVKDescriptorSet*>& descriptorSets,
+ MVKArrayRef<MVKDescriptorSet*> descriptorSets,
uint32_t firstSet,
- MVKVector<uint32_t>* pDynamicOffsets);
+ MVKArrayRef<uint32_t> dynamicOffsets);
/** Updates a descriptor set in a command encoder. */
void pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
- MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+ MVKArrayRef<VkWriteDescriptorSet> descriptorWrites,
uint32_t set);
/** Updates a descriptor set from a template in a command encoder. */
@@ -107,9 +107,9 @@
protected:
void propogateDebugName() override {}
- MVKVectorInline<MVKDescriptorSetLayout*, 1> _descriptorSetLayouts;
- MVKVectorInline<MVKShaderResourceBinding, 1> _dslMTLResourceIndexOffsets;
- MVKVectorDefault<VkPushConstantRange> _pushConstants;
+ MVKSmallVector<MVKDescriptorSetLayout*, 1> _descriptorSetLayouts;
+ MVKSmallVector<MVKShaderResourceBinding, 1> _dslMTLResourceIndexOffsets;
+ MVKSmallVector<VkPushConstantRange> _pushConstants;
MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
MVKShaderImplicitRezBinding _swizzleBufferIndex;
MVKShaderImplicitRezBinding _bufferSizeBufferIndex;
@@ -143,9 +143,6 @@
/** Returns the debug report object type of this object. */
VkDebugReportObjectTypeEXT getVkDebugReportObjectType() override { return VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT; }
- /** Returns the order of stages in this pipeline. Draws and dispatches must encode this pipeline once per stage. */
- virtual void getStages(MVKVector<uint32_t>& stages) = 0;
-
/** Binds this pipeline to the specified command encoder. */
virtual void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) = 0;
@@ -187,6 +184,8 @@
#pragma mark -
#pragma mark MVKGraphicsPipeline
+typedef MVKSmallVector<MVKGraphicsStage, 4> MVKPiplineStages;
+
/** The number of dynamic states possible in Vulkan. */
static const uint32_t kMVKVkDynamicStateCount = 32;
@@ -195,8 +194,8 @@
public:
- /** Returns the number and order of stages in this pipeline. Draws and dispatches must encode this pipeline once per stage. */
- void getStages(MVKVector<uint32_t>& stages) override;
+ /** Returns the number and order of stages in this pipeline. Draws commands must encode this pipeline once per stage. */
+ void getStages(MVKPiplineStages& stages);
/** Binds this pipeline to the specified command encoder. */
void encode(MVKCommandEncoder* cmdEncoder, uint32_t stage = 0) override;
@@ -240,19 +239,21 @@
~MVKGraphicsPipeline() override;
protected:
+ typedef MVKSmallVector<SPIRVShaderOutput, 32> SPIRVShaderOutputs;
+
id<MTLRenderPipelineState> getOrCompilePipeline(MTLRenderPipelineDescriptor* plDesc, id<MTLRenderPipelineState>& plState);
id<MTLComputePipelineState> getOrCompilePipeline(MTLComputePipelineDescriptor* plDesc, id<MTLComputePipelineState>& plState, const char* compilerType);
void initMTLRenderPipelineState(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
void initMVKShaderConverterContext(SPIRVToMSLConversionConfiguration& _shaderContext, const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
void addVertexInputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, const VkGraphicsPipelineCreateInfo* pCreateInfo);
- void addPrevStageOutputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& outputs);
+ void addPrevStageOutputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& outputs);
MTLRenderPipelineDescriptor* newMTLRenderPipelineDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData);
MTLRenderPipelineDescriptor* newMTLTessVertexStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
MTLComputePipelineDescriptor* newMTLTessControlStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
MTLRenderPipelineDescriptor* newMTLTessRasterStageDescriptor(const VkGraphicsPipelineCreateInfo* pCreateInfo, const SPIRVTessReflectionData& reflectData, SPIRVToMSLConversionConfiguration& shaderContext);
bool addVertexShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext);
- bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& prevOutput);
- bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, std::vector<SPIRVShaderOutput>& prevOutput);
+ bool addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& prevOutput);
+ bool addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext, SPIRVShaderOutputs& prevOutput);
bool addFragmentShaderToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkGraphicsPipelineCreateInfo* pCreateInfo, SPIRVToMSLConversionConfiguration& shaderContext);
bool addVertexInputToPipeline(MTLRenderPipelineDescriptor* plDesc, const VkPipelineVertexInputStateCreateInfo* pVI, const SPIRVToMSLConversionConfiguration& shaderContext);
void addTessellationToPipeline(MTLRenderPipelineDescriptor* plDesc, const SPIRVTessReflectionData& reflectData, const VkPipelineTessellationStateCreateInfo* pTS);
@@ -269,8 +270,8 @@
VkPipelineRasterizationStateCreateInfo _rasterInfo;
VkPipelineDepthStencilStateCreateInfo _depthStencilInfo;
- MVKVectorInline<VkViewport, kMVKCachedViewportScissorCount> _viewports;
- MVKVectorInline<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
+ MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
+ MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
MTLComputePipelineDescriptor* _mtlTessControlStageDesc = nil;
@@ -316,9 +317,6 @@
public:
- /** Returns the number and order of stages in this pipeline. Draws and dispatches must encode this pipeline once per stage. */
- void getStages(MVKVector<uint32_t>& stages) override;
-
/** Binds this pipeline to the specified command encoder. */
void encode(MVKCommandEncoder* cmdEncoder, uint32_t = 0) override;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index d270906..781681a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -38,26 +38,26 @@
// A null cmdEncoder can be passed to perform a validation pass
void MVKPipelineLayout::bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
- MVKVector<MVKDescriptorSet*>& descriptorSets,
+ MVKArrayRef<MVKDescriptorSet*> descriptorSets,
uint32_t firstSet,
- MVKVector<uint32_t>* pDynamicOffsets) {
+ MVKArrayRef<uint32_t> dynamicOffsets) {
clearConfigurationResult();
uint32_t pDynamicOffsetIndex = 0;
- uint32_t dsCnt = (uint32_t)descriptorSets.size();
+ size_t dsCnt = descriptorSets.size;
for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
MVKDescriptorSet* descSet = descriptorSets[dsIdx];
uint32_t dslIdx = firstSet + dsIdx;
MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[dslIdx];
dsl->bindDescriptorSet(cmdEncoder, descSet,
_dslMTLResourceIndexOffsets[dslIdx],
- pDynamicOffsets, &pDynamicOffsetIndex);
+ dynamicOffsets, &pDynamicOffsetIndex);
setConfigurationResult(dsl->getConfigurationResult());
}
}
// A null cmdEncoder can be passed to perform a validation pass
void MVKPipelineLayout::pushDescriptorSet(MVKCommandEncoder* cmdEncoder,
- MVKVector<VkWriteDescriptorSet>& descriptorWrites,
+ MVKArrayRef<VkWriteDescriptorSet> descriptorWrites,
uint32_t set) {
clearConfigurationResult();
MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[set];
@@ -176,7 +176,7 @@
#pragma mark -
#pragma mark MVKGraphicsPipeline
-void MVKGraphicsPipeline::getStages(MVKVector<uint32_t>& stages) {
+void MVKGraphicsPipeline::getStages(MVKPiplineStages& stages) {
if (isTessellationPipeline()) {
stages.push_back(kMVKGraphicsStageVertex);
stages.push_back(kMVKGraphicsStageTessControl);
@@ -254,8 +254,8 @@
cmdEncoder->_blendColorState.setBlendColor(_blendConstants[0], _blendConstants[1],
_blendConstants[2], _blendConstants[3], false);
cmdEncoder->_depthBiasState.setDepthBias(_rasterInfo);
- cmdEncoder->_viewportState.setViewports(_viewports, 0, false);
- cmdEncoder->_scissorState.setScissors(_scissors, 0, false);
+ cmdEncoder->_viewportState.setViewports(_viewports.contents(), 0, false);
+ cmdEncoder->_scissorState.setScissors(_scissors.contents(), 0, false);
cmdEncoder->_mtlPrimitiveType = _mtlPrimitiveType;
[mtlCmdEnc setCullMode: _mtlCullMode];
@@ -606,9 +606,8 @@
SPIRVToMSLConversionConfiguration& shaderContext) {
MTLComputePipelineDescriptor* plDesc = [MTLComputePipelineDescriptor new]; // retained
- std::vector<SPIRVShaderOutput> vtxOutputs;
+ SPIRVShaderOutputs vtxOutputs;
std::string errorLog;
- // Unfortunately, MoltenVKShaderConverter doesn't know about MVKVector, so we can't use that here.
if (!getShaderOutputs(((MVKShaderModule*)_pVertexSS->module)->getSPIRV(), spv::ExecutionModelVertex, _pVertexSS->pName, vtxOutputs, errorLog) ) {
setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get vertex outputs: %s", errorLog.c_str()));
return nil;
@@ -654,7 +653,7 @@
SPIRVToMSLConversionConfiguration& shaderContext) {
MTLRenderPipelineDescriptor* plDesc = [MTLRenderPipelineDescriptor new]; // retained
- std::vector<SPIRVShaderOutput> tcOutputs;
+ SPIRVShaderOutputs tcOutputs;
std::string errorLog;
if (!getShaderOutputs(((MVKShaderModule*)_pTessCtlSS->module)->getSPIRV(), spv::ExecutionModelTessellationControl, _pTessCtlSS->pName, tcOutputs, errorLog) ) {
setConfigurationResult(reportError(VK_ERROR_INITIALIZATION_FAILED, "Failed to get tessellation control outputs: %s", errorLog.c_str()));
@@ -823,7 +822,7 @@
bool MVKGraphicsPipeline::addTessCtlShaderToPipeline(MTLComputePipelineDescriptor* plDesc,
const VkGraphicsPipelineCreateInfo* pCreateInfo,
SPIRVToMSLConversionConfiguration& shaderContext,
- std::vector<SPIRVShaderOutput>& vtxOutputs) {
+ SPIRVShaderOutputs& vtxOutputs) {
shaderContext.options.entryPointStage = spv::ExecutionModelTessellationControl;
shaderContext.options.entryPointName = _pTessCtlSS->pName;
shaderContext.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessCtl];
@@ -876,7 +875,7 @@
bool MVKGraphicsPipeline::addTessEvalShaderToPipeline(MTLRenderPipelineDescriptor* plDesc,
const VkGraphicsPipelineCreateInfo* pCreateInfo,
SPIRVToMSLConversionConfiguration& shaderContext,
- std::vector<SPIRVShaderOutput>& tcOutputs) {
+ SPIRVShaderOutputs& tcOutputs) {
shaderContext.options.entryPointStage = spv::ExecutionModelTessellationEvaluation;
shaderContext.options.entryPointName = _pTessEvalSS->pName;
shaderContext.options.mslOptions.swizzle_buffer_index = _swizzleBufferIndex.stages[kMVKShaderStageTessEval];
@@ -1241,7 +1240,7 @@
// Initializes the vertex attributes in a shader converter context from the previous stage output.
void MVKGraphicsPipeline::addPrevStageOutputToShaderConverterContext(SPIRVToMSLConversionConfiguration& shaderContext,
- std::vector<SPIRVShaderOutput>& shaderOutputs) {
+ SPIRVShaderOutputs& shaderOutputs) {
// Set the shader context vertex attribute information
shaderContext.vertexAttributes.clear();
uint32_t vaCnt = (uint32_t)shaderOutputs.size();
@@ -1288,10 +1287,6 @@
#pragma mark -
#pragma mark MVKComputePipeline
-void MVKComputePipeline::getStages(MVKVector<uint32_t>& stages) {
- stages.push_back(0);
-}
-
void MVKComputePipeline::encode(MVKCommandEncoder* cmdEncoder, uint32_t) {
if ( !_hasValidMTLPipelineStates ) { return; }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h
index 5bc06cf..4ba31da 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.h
@@ -19,7 +19,7 @@
#pragma once
#include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <mutex>
#include <condition_variable>
@@ -57,7 +57,7 @@
virtual void endQuery(uint32_t query, MVKCommandEncoder* cmdEncoder);
/** Finishes the specified queries and marks them as available. */
- virtual void finishQueries(MVKVector<uint32_t>& queries);
+ virtual void finishQueries(const MVKArrayRef<uint32_t>& queries);
/** Resets the results and availability status of the specified queries. */
virtual void resetResults(uint32_t firstQuery, uint32_t queryCount, MVKCommandEncoder* cmdEncoder);
@@ -127,8 +127,8 @@
Available /**< Query is available to the host. */
};
- MVKVectorInline<Status, kMVKDefaultQueryCount> _availability;
- MVKVectorInline<DeferredCopy, 4> _deferredCopies;
+ MVKSmallVector<Status, kMVKDefaultQueryCount> _availability;
+ MVKSmallVector<DeferredCopy, 4> _deferredCopies;
uint32_t _queryElementCount;
std::mutex _availabilityLock;
std::condition_variable _availabilityBlocker;
@@ -143,7 +143,7 @@
class MVKTimestampQueryPool : public MVKQueryPool {
public:
- void finishQueries(MVKVector<uint32_t>& queries) override;
+ void finishQueries(const MVKArrayRef<uint32_t>& queries) override;
#pragma mark Construction
@@ -156,7 +156,7 @@
id<MTLBuffer> getResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, NSUInteger& offset) override;
void encodeSetResultBuffer(MVKCommandEncoder* cmdEncoder, uint32_t firstQuery, uint32_t queryCount, uint32_t index) override;
- MVKVectorInline<uint64_t, kMVKDefaultQueryCount> _timestamps;
+ MVKSmallVector<uint64_t, kMVKDefaultQueryCount> _timestamps;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
index 41ba5bc..d604966 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm
@@ -47,7 +47,7 @@
}
// Mark queries as available
-void MVKQueryPool::finishQueries(MVKVector<uint32_t>& queries) {
+void MVKQueryPool::finishQueries(const MVKArrayRef<uint32_t>& queries) {
lock_guard<mutex> lock(_availabilityLock);
for (uint32_t qry : queries) { _availability[qry] = Available; }
_availabilityBlocker.notify_all(); // Predicate of each wait() call will check whether all required queries are available
@@ -184,7 +184,7 @@
#pragma mark MVKTimestampQueryPool
// Update timestamp values, then mark queries as available
-void MVKTimestampQueryPool::finishQueries(MVKVector<uint32_t>& queries) {
+void MVKTimestampQueryPool::finishQueries(const MVKArrayRef<uint32_t>& queries) {
uint64_t ts = mvkGetTimestamp();
for (uint32_t qry : queries) { _timestamps[qry] = ts; }
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
index 994e015..7f0a1f4 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
@@ -22,7 +22,7 @@
#include "MVKCommandBuffer.h"
#include "MVKImage.h"
#include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <mutex>
#import <Metal/Metal.h>
@@ -64,7 +64,7 @@
MVKPhysicalDevice* _physicalDevice;
uint32_t _queueFamilyIndex;
VkQueueFamilyProperties _properties;
- MVKVectorInline<id<MTLCommandQueue>, kMVKQueueCountPerQueueFamily> _mtlQueues;
+ MVKSmallVector<id<MTLCommandQueue>, kMVKQueueCountPerQueueFamily> _mtlQueues;
std::mutex _qLock;
};
@@ -179,7 +179,7 @@
friend class MVKQueue;
MVKQueue* _queue;
- MVKVectorInline<MVKSemaphore*, 8> _waitSemaphores;
+ MVKSmallVector<MVKSemaphore*> _waitSemaphores;
bool _trackPerformance;
};
@@ -193,10 +193,7 @@
public:
void execute() override;
- /** Constructs an instance for the queue. */
- MVKQueueCommandBufferSubmission(MVKQueue* queue,
- const VkSubmitInfo* pSubmit,
- VkFence fence);
+ MVKQueueCommandBufferSubmission(MVKQueue* queue, const VkSubmitInfo* pSubmit, VkFence fence);
protected:
friend MVKCommandBuffer;
@@ -205,14 +202,44 @@
void setActiveMTLCommandBuffer(id<MTLCommandBuffer> mtlCmdBuff);
void commitActiveMTLCommandBuffer(bool signalCompletion = false);
void finish();
+ virtual void submitCommandBuffers() {}
- MVKVectorInline<MVKCommandBuffer*, 32> _cmdBuffers;
- MVKVectorInline<MVKSemaphore*, 8> _signalSemaphores;
+ MVKSmallVector<MVKSemaphore*> _signalSemaphores;
MVKFence* _fence;
id<MTLCommandBuffer> _activeMTLCommandBuffer;
};
+/**
+ * Submits the commands in a set of command buffers to the queue.
+ * Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
+ */
+template <size_t N>
+class MVKQueueFullCommandBufferSubmission : public MVKQueueCommandBufferSubmission {
+
+public:
+ MVKQueueFullCommandBufferSubmission(MVKQueue* queue, const VkSubmitInfo* pSubmit, VkFence fence) :
+ MVKQueueCommandBufferSubmission(queue, pSubmit, fence) {
+
+ // pSubmit can be null if just tracking the fence alone
+ if (pSubmit) {
+ uint32_t cbCnt = pSubmit->commandBufferCount;
+ _cmdBuffers.reserve(cbCnt);
+ for (uint32_t i = 0; i < cbCnt; i++) {
+ MVKCommandBuffer* cb = MVKCommandBuffer::getMVKCommandBuffer(pSubmit->pCommandBuffers[i]);
+ _cmdBuffers.push_back(cb);
+ setConfigurationResult(cb->getConfigurationResult());
+ }
+ }
+ }
+
+protected:
+ void submitCommandBuffers() override { for (auto& cb : _cmdBuffers) { cb->submit(this); } }
+
+ MVKSmallVector<MVKCommandBuffer*, N> _cmdBuffers;
+};
+
+
#pragma mark -
#pragma mark MVKQueuePresentSurfaceSubmission
@@ -227,7 +254,7 @@
protected:
id<MTLCommandBuffer> getMTLCommandBuffer();
-
+
typedef struct {
MVKPresentableSwapchainImage* presentableImage;
bool hasPresentTime; // Keep track of whether present included VK_GOOGLE_display_timing
@@ -235,6 +262,6 @@
uint64_t desiredPresentTime; // VK_GOOGLE_display_timing desired presentation time in nanoseconds
} PresentInfo;
- MVKVectorInline<PresentInfo, 4> _presentInfo;
+ MVKSmallVector<PresentInfo, 4> _presentInfo;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
index ec2a157..fc70cc3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
@@ -97,7 +97,27 @@
VkResult rslt = VK_SUCCESS;
for (uint32_t sIdx = 0; sIdx < submitCount; sIdx++) {
VkFence fenceOrNil = (sIdx == (submitCount - 1)) ? fence : VK_NULL_HANDLE; // last one gets the fence
- VkResult subRslt = submit(new MVKQueueCommandBufferSubmission(this, &pSubmits[sIdx], fenceOrNil));
+
+ const VkSubmitInfo* pVkSub = &pSubmits[sIdx];
+ MVKQueueCommandBufferSubmission* mvkSub;
+ uint32_t cbCnt = pVkSub->commandBufferCount;
+ if (cbCnt <= 1) {
+ mvkSub = new MVKQueueFullCommandBufferSubmission<1>(this, pVkSub, fenceOrNil);
+ } else if (cbCnt <= 16) {
+ mvkSub = new MVKQueueFullCommandBufferSubmission<16>(this, pVkSub, fenceOrNil);
+ } else if (cbCnt <= 32) {
+ mvkSub = new MVKQueueFullCommandBufferSubmission<32>(this, pVkSub, fenceOrNil);
+ } else if (cbCnt <= 64) {
+ mvkSub = new MVKQueueFullCommandBufferSubmission<64>(this, pVkSub, fenceOrNil);
+ } else if (cbCnt <= 128) {
+ mvkSub = new MVKQueueFullCommandBufferSubmission<128>(this, pVkSub, fenceOrNil);
+ } else if (cbCnt <= 256) {
+ mvkSub = new MVKQueueFullCommandBufferSubmission<256>(this, pVkSub, fenceOrNil);
+ } else {
+ mvkSub = new MVKQueueFullCommandBufferSubmission<512>(this, pVkSub, fenceOrNil);
+ }
+
+ VkResult subRslt = submit(mvkSub);
if (rslt == VK_SUCCESS) { rslt = subRslt; }
}
return rslt;
@@ -226,7 +246,7 @@
for (auto* ws : _waitSemaphores) { ws->encodeWait(getActiveMTLCommandBuffer()); }
// Submit each command buffer.
- for (auto& cb : _cmdBuffers) { cb->submit(this); }
+ submitCommandBuffers();
// If using encoded semaphore signaling, do so now.
for (auto* ss : _signalSemaphores) { ss->encodeSignal(getActiveMTLCommandBuffer()); }
@@ -307,14 +327,6 @@
// pSubmit can be null if just tracking the fence alone
if (pSubmit) {
- uint32_t cbCnt = pSubmit->commandBufferCount;
- _cmdBuffers.reserve(cbCnt);
- for (uint32_t i = 0; i < cbCnt; i++) {
- MVKCommandBuffer* cb = MVKCommandBuffer::getMVKCommandBuffer(pSubmit->pCommandBuffers[i]);
- _cmdBuffers.push_back(cb);
- setConfigurationResult(cb->getConfigurationResult());
- }
-
uint32_t ssCnt = pSubmit->signalSemaphoreCount;
_signalSemaphores.reserve(ssCnt);
for (uint32_t i = 0; i < ssCnt; i++) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index 9c73c45..3534698 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -19,7 +19,7 @@
#pragma once
#include "MVKDevice.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#import <Metal/Metal.h>
@@ -30,6 +30,8 @@
// Parameters to define the sizing of inline collections
const static uint32_t kMVKDefaultAttachmentCount = 8;
+/** Collection of attachment clears . */
+typedef MVKSmallVector<VkClearAttachment, kMVKDefaultAttachmentCount> MVKClearAttachments;
#pragma mark -
#pragma mark MVKRenderSubpass
@@ -64,7 +66,7 @@
*/
void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
MVKFramebuffer* framebuffer,
- MVKVector<VkClearValue>& clearValues,
+ const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
bool loadOverride = false,
bool storeOverride = false);
@@ -73,8 +75,8 @@
* Populates the specified vector with the attachments that need to be cleared
* when the render area is smaller than the full framebuffer size.
*/
- void populateClearAttachments(MVKVector<VkClearAttachment>& clearAtts,
- MVKVector<VkClearValue>& clearValues);
+ void populateClearAttachments(MVKClearAttachments& clearAtts,
+ const MVKArrayRef<VkClearValue>& clearValues);
/** Constructs an instance for the specified parent renderpass. */
MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription* pCreateInfo);
@@ -88,10 +90,10 @@
MVKRenderPass* _renderPass;
uint32_t _subpassIndex;
- MVKVectorInline<VkAttachmentReference, kMVKDefaultAttachmentCount> _inputAttachments;
- MVKVectorInline<VkAttachmentReference, kMVKDefaultAttachmentCount> _colorAttachments;
- MVKVectorInline<VkAttachmentReference, kMVKDefaultAttachmentCount> _resolveAttachments;
- MVKVectorInline<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
+ MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _inputAttachments;
+ MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _colorAttachments;
+ MVKSmallVector<VkAttachmentReference, kMVKDefaultAttachmentCount> _resolveAttachments;
+ MVKSmallVector<uint32_t, kMVKDefaultAttachmentCount> _preserveAttachments;
VkAttachmentReference _depthStencilAttachment;
id<MTLTexture> _mtlDummyTex = nil;
};
@@ -171,9 +173,9 @@
void propogateDebugName() override {}
- MVKVectorInline<MVKRenderPassAttachment, kMVKDefaultAttachmentCount> _attachments;
- MVKVectorInline<MVKRenderSubpass, 1> _subpasses;
- MVKVectorDefault<VkSubpassDependency> _subpassDependencies;
+ MVKSmallVector<MVKRenderPassAttachment, kMVKDefaultAttachmentCount> _attachments;
+ MVKSmallVector<MVKRenderSubpass, 1> _subpasses;
+ MVKSmallVector<VkSubpassDependency> _subpassDependencies;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 7fe41fe..432a757 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -69,7 +69,7 @@
void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
MVKFramebuffer* framebuffer,
- MVKVector<VkClearValue>& clearValues,
+ const MVKArrayRef<VkClearValue>& clearValues,
bool isRenderingEntireAttachment,
bool loadOverride,
bool storeOverride) {
@@ -167,8 +167,8 @@
}
}
-void MVKRenderSubpass::populateClearAttachments(MVKVector<VkClearAttachment>& clearAtts,
- MVKVector<VkClearValue>& clearValues) {
+void MVKRenderSubpass::populateClearAttachments(MVKClearAttachments& clearAtts,
+ const MVKArrayRef<VkClearValue>& clearValues) {
VkClearAttachment cAtt;
uint32_t attIdx;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
index c4fdc0a..8071d3b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.h
@@ -20,7 +20,7 @@
#include "MVKDevice.h"
#include "MVKSync.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include <MoltenVKGLSLToSPIRVConverter/GLSLToSPIRVConverter.h>
#include <mutex>
@@ -151,7 +151,7 @@
void merge(MVKShaderLibraryCache* other);
MVKVulkanAPIDeviceObject* _owner;
- MVKVectorInline<std::pair<SPIRVToMSLConversionConfiguration, MVKShaderLibrary*>, 1> _shaderLibraries;
+ MVKSmallVector<std::pair<SPIRVToMSLConversionConfiguration, MVKShaderLibrary*>, 1> _shaderLibraries;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
index 79a25dc..3fe3866 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h
@@ -20,7 +20,7 @@
#include "MVKDevice.h"
#include "MVKImage.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#import "CAMetalLayer+MoltenVK.h"
#import <Metal/Metal.h>
@@ -117,7 +117,7 @@
CAMetalLayer* _mtlLayer;
MVKWatermark* _licenseWatermark;
- MVKVectorInline<MVKPresentableSwapchainImage*, kMVKMaxSwapchainImageCount> _presentableImages;
+ MVKSmallVector<MVKPresentableSwapchainImage*, kMVKMaxSwapchainImageCount> _presentableImages;
std::atomic<uint64_t> _currentAcquisitionID;
CGSize _mtlLayerOrigDrawSize;
uint64_t _lastFrameTime;
diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.h b/MoltenVK/MoltenVK/Layers/MVKLayers.h
index 76a00ff..993105a 100644
--- a/MoltenVK/MoltenVK/Layers/MVKLayers.h
+++ b/MoltenVK/MoltenVK/Layers/MVKLayers.h
@@ -20,7 +20,7 @@
#include "MVKBaseObject.h"
#include "MVKExtensions.h"
-#include "MVKVector.h"
+#include "MVKSmallVector.h"
#pragma mark MVKLayer
@@ -114,7 +114,7 @@
static MVKLayerManager* globalManager();
protected:
- MVKVectorInline<MVKLayer, 1> _layers;
+ MVKSmallVector<MVKLayer, 1> _layers;
};
diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
index d4ae601..a0f0eac 100644
--- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h
+++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h
@@ -370,6 +370,23 @@
#pragma mark Containers
+/**
+ * Structure to reference an array of typed elements in contiguous memory.
+ * Allocation and management of the memory is handled externally.
+ */
+template<typename Type>
+struct MVKArrayRef {
+ Type* data;
+ const size_t size;
+
+ const Type* begin() const { return data; }
+ const Type* end() const { return &data[size]; }
+ const Type& operator[]( const size_t i ) const { return data[i]; }
+ Type& operator[]( const size_t i ) { return data[i]; }
+ MVKArrayRef() : MVKArrayRef(nullptr, 0) {}
+ MVKArrayRef(Type* d, size_t s) : data(d), size(s) {}
+};
+
/** Ensures the size of the specified container is at least the specified size. */
template<typename C, typename S>
void mvkEnsureSize(C& container, S size) {
diff --git a/MoltenVK/MoltenVK/Utility/MVKSmallVector.h b/MoltenVK/MoltenVK/Utility/MVKSmallVector.h
new file mode 100755
index 0000000..1d1612b
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKSmallVector.h
@@ -0,0 +1,889 @@
+/*
+ * MVKSmallVector.h
+ *
+ * Copyright (c) 2012-2020 Dr. Torsten Hans (hans@ipacs.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// In case MVKSmallVector should use just std::vector instead
+#if 0
+
+template<typename T, size_t N = 0>
+using MVKSmallVector = std::vector<T>;
+
+#else
+
+// MVKSmallVector.h is a sequence container that (optionally) implements a small buffer optimization.
+// It behaves similarly to std::vector, except until a certain number of elements are reserved,
+// it does not use the heap. Like std::vector, MVKSmallVector is guaranteed to use contiguous memory,
+// so if the preallocated number of elements are exceeded, all elements are then in heap.
+// MVKSmallVector supports just the necessary members to be compatible with MoltenVK.
+// If C++17 will be the default in the future, code can be simplified quite a bit.
+//
+// Example:
+//
+// MVKSmallVector<int, 2> sv;
+// sv.push_back( 1 ); // no allocation, uses pre-allocated memory
+// sv.push_back( 2 ); // no allocation, uses pre-allocated memory
+// sv.push_back( 3 ); // adding another element now reserves memory from heap and copies from pre-allocated memory
+//
+// If you don't need any inline storage use:
+// MVKSmallVector<int> v; // this is essentially the same as using std::vector
+//
+// The per-instance memory overhead of MVKSmallVector (16 bytes) is smaller than MVKVector (40 bytes)
+// and std::vector (24 bytes), but MVKSmallVector lacks the polymorphism of MVKVector (or std::vector),
+// that allows them to be passed around to functions without reference to the pre-allocation size.
+// MVKSmallVector supports the contents() function to derive an MVKArrayRef from its contents,
+// which can be passed around without reference to the pre-allocaton size.
+
+#include "MVKSmallVectorAllocator.h"
+#include "MVKFoundation.h"
+#include <type_traits>
+#include <initializer_list>
+#include <utility>
+
+
+template<typename Type, typename Allocator = mvk_smallvector_allocator<Type, 0>>
+class MVKSmallVectorImpl
+{
+ Allocator alc;
+
+public:
+ class iterator : public std::iterator<std::random_access_iterator_tag, Type>
+ {
+ const MVKSmallVectorImpl *vector;
+ size_t index;
+
+ public:
+ typedef typename std::iterator_traits<iterator>::difference_type diff_type;
+
+ iterator() : vector{ nullptr }, index{ 0 } { }
+ iterator( const size_t _index, const MVKSmallVectorImpl &_vector ) : vector{ &_vector }, index{ _index } { }
+
+ iterator &operator=( const iterator &it )
+ {
+ vector = it.vector;
+ index = it.index;
+ return *this;
+ }
+
+ Type *operator->() { return &vector->alc.ptr[index]; }
+ Type &operator*() { return vector->alc.ptr[index]; }
+ operator Type*() { return &vector->alc.ptr[index]; }
+
+ bool operator==( const iterator &it ) const { return vector == it.vector && index == it.index; }
+ bool operator!=( const iterator &it ) const { return vector != it.vector || index != it.index; }
+
+ iterator& operator++() { ++index; return *this; }
+ iterator operator++( int ) { auto t = *this; ++index; return t; }
+ iterator& operator--() { --index; return *this; }
+ iterator operator--( int ) { auto t = *this; --index; return t; }
+
+ iterator operator+ (const diff_type n) { return iterator( index + n, *vector ); }
+ iterator& operator+= (const diff_type n) { index += n; return *this; }
+ iterator operator- (const diff_type n) { return iterator( index - n, *vector ); }
+ iterator& operator-= (const diff_type n) { index -= n; return *this; }
+
+ diff_type operator- (const iterator& it) { return index - it.index; }
+
+ bool operator< (const iterator& it) { return index < it.index; }
+ bool operator<= (const iterator& it) { return index <= it.index; }
+ bool operator> (const iterator& it) { return index > it.index; }
+ bool operator>= (const iterator& it) { return index >= it.index; }
+
+ const Type &operator[]( const diff_type i ) const { return vector->alc.ptr[index + i]; }
+ Type &operator[]( const diff_type i ) { return vector->alc.ptr[index + i]; }
+
+ bool is_valid() const { return index < vector->alc.size(); }
+ size_t get_position() const { return index; }
+ };
+
+private:
+ // this is the growth strategy -> adjust to your needs
+ size_t vector_GetNextCapacity() const
+ {
+ constexpr auto ELEMENTS_FOR_64_BYTES = 64 / sizeof( Type );
+ constexpr auto MINIMUM_CAPACITY = ELEMENTS_FOR_64_BYTES > 4 ? ELEMENTS_FOR_64_BYTES : 4;
+ const auto current_capacity = capacity();
+ return MINIMUM_CAPACITY + ( 3 * current_capacity ) / 2;
+ }
+
+ void vector_Allocate( const size_t s )
+ {
+ const auto new_reserved_size = s > size() ? s : size();
+
+ alc.allocate( new_reserved_size );
+ }
+
+ void vector_ReAllocate( const size_t s )
+ {
+ alc.re_allocate( s );
+ }
+
+public:
+ MVKSmallVectorImpl()
+ {
+ }
+
+ MVKSmallVectorImpl( const size_t n, const Type t )
+ {
+ if( n > 0 )
+ {
+ alc.allocate( n );
+
+ for( size_t i = 0; i < n; ++i )
+ {
+ alc.construct( &alc.ptr[i], t );
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ MVKSmallVectorImpl( const MVKSmallVectorImpl &a )
+ {
+ const size_t n = a.size();
+
+ if( n > 0 )
+ {
+ alc.allocate( n );
+
+ for( size_t i = 0; i < n; ++i )
+ {
+ alc.construct( &alc.ptr[i], a.alc.ptr[i] );
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ template<typename U>
+ MVKSmallVectorImpl( const U &a )
+ {
+ const size_t n = a.size();
+
+ if( n > 0 )
+ {
+ alc.allocate( n );
+
+ for( size_t i = 0; i < n; ++i )
+ {
+ alc.construct( &alc.ptr[i], a[i] );
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ MVKSmallVectorImpl( MVKSmallVectorImpl &&a ) : alc{ std::move( a.alc ) }
+ {
+ }
+
+ MVKSmallVectorImpl( std::initializer_list<Type> vector )
+ {
+ if( vector.size() > capacity() )
+ {
+ vector_Allocate( vector.size() );
+ }
+
+ // std::initializer_list does not yet support std::move, we use it anyway but it has no effect
+ for( auto &&element : vector )
+ {
+ alc.construct( &alc.ptr[alc.num_elements_used], std::move( element ) );
+ ++alc.num_elements_used;
+ }
+ }
+
+ ~MVKSmallVectorImpl()
+ {
+ }
+
+ template<typename U>
+ MVKSmallVectorImpl& operator=( const U &a )
+ {
+ static_assert( std::is_base_of<MVKSmallVectorImpl<Type>, U>::value, "argument is not of type MVKSmallVectorImpl" );
+
+ if( this != reinterpret_cast<const MVKSmallVectorImpl<Type>*>( &a ) )
+ {
+ const auto n = a.size();
+
+ if( alc.num_elements_used == n )
+ {
+ for( size_t i = 0; i < n; ++i )
+ {
+ alc.ptr[i] = a.alc.ptr[i];
+ }
+ }
+ else
+ {
+ if( n > capacity() )
+ {
+ vector_ReAllocate( n );
+ }
+ else
+ {
+ alc.template destruct_all<Type>();
+ }
+
+ for( size_t i = 0; i < n; ++i )
+ {
+ alc.construct( &alc.ptr[i], a[i] );
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ return *this;
+ }
+
+ MVKSmallVectorImpl& operator=( MVKSmallVectorImpl &&a )
+ {
+ alc.swap( a.alc );
+ return *this;
+ }
+
+ bool operator==( const MVKSmallVectorImpl &a ) const
+ {
+ if( alc.num_elements_used != a.alc.num_elements_used )
+ return false;
+ for( size_t i = 0; i < alc.num_elements_used; ++i )
+ {
+ if( alc[i] != a.alc[i] )
+ return false;
+ }
+ return true;
+ }
+
+ bool operator!=( const MVKSmallVectorImpl &a ) const
+ {
+ if( alc.num_elements_used != a.alc.num_elements_used )
+ return true;
+ for( size_t i = 0; i < alc.num_elements_used; ++i )
+ {
+ if( alc.ptr[i] != a.alc[i] )
+ return true;
+ }
+ return false;
+ }
+
+ void swap( MVKSmallVectorImpl &a )
+ {
+ alc.swap( a.alc );
+ }
+
+ iterator begin() const { return iterator( 0, *this ); }
+ iterator end() const { return iterator( alc.num_elements_used, *this ); }
+
+ const MVKArrayRef<Type> contents() const { return MVKArrayRef<Type>(data(), size()); }
+ MVKArrayRef<Type> contents() { return MVKArrayRef<Type>(data(), size()); }
+
+ const Type &operator[]( const size_t i ) const { return alc[i]; }
+ Type &operator[]( const size_t i ) { return alc[i]; }
+ const Type &at( const size_t i ) const { return alc[i]; }
+ Type &at( const size_t i ) { return alc[i]; }
+ const Type &front() const { return alc[0]; }
+ Type &front() { return alc[0]; }
+ const Type &back() const { return alc[alc.num_elements_used - 1]; }
+ Type &back() { return alc[alc.num_elements_used - 1]; }
+ const Type *data() const { return alc.ptr; }
+ Type *data() { return alc.ptr; }
+
+ size_t size() const { return alc.num_elements_used; }
+ bool empty() const { return alc.num_elements_used == 0; }
+ size_t capacity() const { return alc.get_capacity(); }
+
+ void pop_back()
+ {
+ if( alc.num_elements_used > 0 )
+ {
+ --alc.num_elements_used;
+ alc.destruct( &alc.ptr[alc.num_elements_used] );
+ }
+ }
+
+ void clear()
+ {
+ alc.template destruct_all<Type>();
+ }
+
+ void reset()
+ {
+ alc.deallocate();
+ }
+
+ void reserve( const size_t new_size )
+ {
+ if( new_size > capacity() )
+ {
+ vector_ReAllocate( new_size );
+ }
+ }
+
+ void assign( const size_t new_size, const Type &t )
+ {
+ if( new_size <= capacity() )
+ {
+ clear();
+ }
+ else
+ {
+ vector_Allocate( new_size );
+ }
+
+ for( size_t i = 0; i < new_size; ++i )
+ {
+ alc.construct( &alc.ptr[i], t );
+ }
+
+ alc.num_elements_used = new_size;
+ }
+
+ template <class InputIterator>
+ void assign( InputIterator first, InputIterator last )
+ {
+ clear();
+
+ while( first != last )
+ {
+ emplace_back( *first );
+ ++first;
+ }
+ }
+
+ void resize( const size_t new_size, const Type t = { } )
+ {
+ if( new_size == alc.num_elements_used )
+ {
+ return;
+ }
+
+ if( new_size == 0 )
+ {
+ clear();
+ return;
+ }
+
+ if( new_size > alc.num_elements_used )
+ {
+ if( new_size > capacity() )
+ {
+ vector_ReAllocate( new_size );
+ }
+
+ while( alc.num_elements_used < new_size )
+ {
+ alc.construct( &alc.ptr[alc.num_elements_used], t );
+ ++alc.num_elements_used;
+ }
+ }
+ else
+ {
+ //if constexpr( !std::is_trivially_destructible<Type>::value )
+ {
+ while( alc.num_elements_used > new_size )
+ {
+ --alc.num_elements_used;
+ alc.destruct( &alc.ptr[alc.num_elements_used] );
+ }
+ }
+ //else
+ //{
+ // alc.num_elements_used = new_size;
+ //}
+ }
+ }
+
+ // trims the capacity of the slist to the number of alc.ptr
+ void shrink_to_fit()
+ {
+ alc.shrink_to_fit();
+ }
+
+ void erase( const iterator it )
+ {
+ if( it.is_valid() )
+ {
+ --alc.num_elements_used;
+
+ for( size_t i = it.get_position(); i < alc.num_elements_used; ++i )
+ {
+ alc.ptr[i] = std::move( alc.ptr[i + 1] );
+ }
+
+ // this is required for types with a destructor
+ alc.destruct( &alc.ptr[alc.num_elements_used] );
+ }
+ }
+
+ void erase( const iterator first, const iterator last )
+ {
+ if( first.is_valid() )
+ {
+ size_t last_pos = last.is_valid() ? last.get_position() : size();
+ size_t n = last_pos - first.get_position();
+ alc.num_elements_used -= n;
+
+ for( size_t i = first.get_position(), e = last_pos; i < alc.num_elements_used && e < alc.num_elements_used + n; ++i, ++e )
+ {
+ alc.ptr[i] = std::move( alc.ptr[e] );
+ }
+
+ // this is required for types with a destructor
+ for( size_t i = alc.num_elements_used; i < alc.num_elements_used + n; ++i )
+ {
+ alc.destruct( &alc.ptr[i] );
+ }
+ }
+ }
+
+ // adds t before it and automatically resizes vector if necessary
+ void insert( const iterator it, Type t )
+ {
+ if( !it.is_valid() || alc.num_elements_used == 0 )
+ {
+ push_back( std::move( t ) );
+ }
+ else
+ {
+ if( alc.num_elements_used == capacity() )
+ vector_ReAllocate( vector_GetNextCapacity() );
+
+ // move construct last element
+ alc.construct( &alc.ptr[alc.num_elements_used], std::move( alc.ptr[alc.num_elements_used - 1] ) );
+
+ // move the remaining elements
+ const size_t it_position = it.get_position();
+ for( size_t i = alc.num_elements_used - 1; i > it_position; --i )
+ {
+ alc.ptr[i] = std::move( alc.ptr[i - 1] );
+ }
+
+ alc.ptr[it_position] = std::move( t );
+ ++alc.num_elements_used;
+ }
+ }
+
+ void push_back( const Type &t )
+ {
+ if( alc.num_elements_used == capacity() )
+ vector_ReAllocate( vector_GetNextCapacity() );
+
+ alc.construct( &alc.ptr[alc.num_elements_used], t );
+ ++alc.num_elements_used;
+ }
+
+ void push_back( Type &&t )
+ {
+ if( alc.num_elements_used == capacity() )
+ vector_ReAllocate( vector_GetNextCapacity() );
+
+ alc.construct( &alc.ptr[alc.num_elements_used], std::forward<Type>( t ) );
+ ++alc.num_elements_used;
+ }
+
+ template<class... Args>
+ Type &emplace_back( Args&&... args )
+ {
+ if( alc.num_elements_used == capacity() )
+ vector_ReAllocate( vector_GetNextCapacity() );
+
+ alc.construct( &alc.ptr[alc.num_elements_used], std::forward<Args>( args )... );
+ ++alc.num_elements_used;
+
+ return alc.ptr[alc.num_elements_used - 1];
+ }
+};
+
+// specialization for pointer types
+template<typename Type, typename Allocator>
+class MVKSmallVectorImpl<Type*, Allocator>
+{
+
+ Allocator alc;
+
+public:
+ class iterator : public std::iterator<std::random_access_iterator_tag, Type*>
+ {
+ MVKSmallVectorImpl *vector;
+ size_t index;
+
+ public:
+ typedef typename std::iterator_traits<iterator>::difference_type diff_type;
+
+ iterator() : vector{ nullptr }, index{ 0 } { }
+ iterator( const size_t _index, MVKSmallVectorImpl &_vector ) : vector{ &_vector }, index{ _index } { }
+
+ iterator &operator=( const iterator &it )
+ {
+ vector = it.vector;
+ index = it.index;
+ return *this;
+ }
+
+ Type *&operator*() { return vector->alc[index]; }
+
+ bool operator==( const iterator &it ) const { return vector == it.vector && index == it.index; }
+ bool operator!=( const iterator &it ) const { return vector != it.vector || index != it.index; }
+
+ iterator& operator++() { ++index; return *this; }
+ iterator operator++( int ) { auto t = *this; ++index; return t; }
+ iterator& operator--() { --index; return *this; }
+ iterator operator--( int ) { auto t = *this; --index; return t; }
+
+ iterator operator+ (const diff_type n) { return iterator( index + n, *vector ); }
+ iterator& operator+= (const diff_type n) { index += n; return *this; }
+ iterator operator- (const diff_type n) { return iterator( index - n, *vector ); }
+ iterator& operator-= (const diff_type n) { index -= n; return *this; }
+
+ diff_type operator- (const iterator& it) { return index - it.index; }
+
+ bool operator< (const iterator& it) { return index < it.index; }
+ bool operator<= (const iterator& it) { return index <= it.index; }
+ bool operator> (const iterator& it) { return index > it.index; }
+ bool operator>= (const iterator& it) { return index >= it.index; }
+
+ const Type &operator[]( const diff_type i ) const { return vector->alc.ptr[index + i]; }
+ Type &operator[]( const diff_type i ) { return vector->alc.ptr[index + i]; }
+
+ bool is_valid() const { return index < vector->alc.size(); }
+ size_t get_position() const { return index; }
+ };
+
+private:
+ // this is the growth strategy -> adjust to your needs
+ size_t vector_GetNextCapacity() const
+ {
+ constexpr auto ELEMENTS_FOR_64_BYTES = 64 / sizeof( Type* );
+ constexpr auto MINIMUM_CAPACITY = ELEMENTS_FOR_64_BYTES > 4 ? ELEMENTS_FOR_64_BYTES : 4;
+ const auto current_capacity = capacity();
+ return MINIMUM_CAPACITY + ( 3 * current_capacity ) / 2;
+ }
+
+ void vector_Allocate( const size_t s )
+ {
+ const auto new_reserved_size = s > size() ? s : size();
+
+ alc.allocate( new_reserved_size );
+ }
+
+ void vector_ReAllocate( const size_t s )
+ {
+ alc.re_allocate( s );
+ }
+
+public:
+ MVKSmallVectorImpl()
+ {
+ }
+
+ MVKSmallVectorImpl( const size_t n, const Type *t )
+ {
+ if ( n > 0 )
+ {
+ alc.allocate( n );
+
+ for ( size_t i = 0; i < n; ++i )
+ {
+ alc.ptr[i] = t;
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ MVKSmallVectorImpl( const MVKSmallVectorImpl &a )
+ {
+ const size_t n = a.size();
+
+ if ( n > 0 )
+ {
+ alc.allocate( n );
+
+ for ( size_t i = 0; i < n; ++i )
+ {
+ alc.ptr[i] = a.alc.ptr[i];
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ MVKSmallVectorImpl( MVKSmallVectorImpl &&a ) : alc{ std::move( a.alc ) }
+ {
+ }
+
+ MVKSmallVectorImpl( std::initializer_list<Type*> vector )
+ {
+ if ( vector.size() > capacity() )
+ {
+ vector_Allocate( vector.size() );
+ }
+
+ // std::initializer_list does not yet support std::move, we use it anyway but it has no effect
+ for ( auto element : vector )
+ {
+ alc.ptr[alc.num_elements_used] = element;
+ ++alc.num_elements_used;
+ }
+ }
+
+ ~MVKSmallVectorImpl()
+ {
+ }
+
+ template<typename U>
+ MVKSmallVectorImpl& operator=( const U &a )
+ {
+ static_assert( std::is_base_of<MVKSmallVectorImpl<U>, U>::value, "argument is not of type MVKSmallVectorImpl" );
+
+ if ( this != reinterpret_cast< const MVKSmallVectorImpl<Type>* >( &a ) )
+ {
+ const auto n = a.size();
+
+ if ( alc.num_elements_used == n )
+ {
+ for ( size_t i = 0; i < n; ++i )
+ {
+ alc.ptr[i] = a.alc.ptr[i];
+ }
+ }
+ else
+ {
+ if ( n > capacity() )
+ {
+ vector_ReAllocate( n );
+ }
+
+ for ( size_t i = 0; i < n; ++i )
+ {
+ alc.ptr[i] = a[i];
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ return *this;
+ }
+
+ MVKSmallVectorImpl& operator=( MVKSmallVectorImpl &&a )
+ {
+ alc.swap( a.alc );
+ return *this;
+ }
+
+ bool operator==( const MVKSmallVectorImpl &a ) const
+ {
+ if ( alc.num_elements_used != a.alc.num_elements_used )
+ return false;
+ for ( size_t i = 0; i < alc.num_elements_used; ++i )
+ {
+ if ( alc[i] != a.alc[i] )
+ return false;
+ }
+ return true;
+ }
+
+ bool operator!=( const MVKSmallVectorImpl &a ) const
+ {
+ if ( alc.num_elements_used != a.alc.num_elements_used )
+ return true;
+ for ( size_t i = 0; i < alc.num_elements_used; ++i )
+ {
+ if ( alc.ptr[i] != a.alc[i] )
+ return true;
+ }
+ return false;
+ }
+
+ void swap( MVKSmallVectorImpl &a )
+ {
+ alc.swap( a.alc );
+ }
+
+ iterator begin() { return iterator( 0, *this ); }
+ iterator end() { return iterator( alc.num_elements_used, *this ); }
+
+ const MVKArrayRef<Type*> contents() const { return MVKArrayRef<Type*>(data(), size()); }
+ MVKArrayRef<Type*> contents() { return MVKArrayRef<Type*>(data(), size()); }
+
+ const Type * const at( const size_t i ) const { return alc[i]; }
+ Type * &at( const size_t i ) { return alc[i]; }
+ const Type * const operator[]( const size_t i ) const { return alc[i]; }
+ Type * &operator[]( const size_t i ) { return alc[i]; }
+ const Type * const front() const { return alc[0]; }
+ Type * &front() { return alc[0]; }
+ const Type * const back() const { return alc[alc.num_elements_used - 1]; }
+ Type * &back() { return alc[alc.num_elements_used - 1]; }
+ const Type * const *data() const { return alc.ptr; }
+ Type * *data() { return alc.ptr; }
+
+ size_t size() const { return alc.num_elements_used; }
+ bool empty() const { return alc.num_elements_used == 0; }
+ size_t capacity() const { return alc.get_capacity(); }
+
+ void pop_back()
+ {
+ if ( alc.num_elements_used > 0 )
+ {
+ --alc.num_elements_used;
+ }
+ }
+
+ void clear()
+ {
+ alc.num_elements_used = 0;
+ }
+
+ void reset()
+ {
+ alc.deallocate();
+ }
+
+ void reserve( const size_t new_size )
+ {
+ if ( new_size > capacity() )
+ {
+ vector_ReAllocate( new_size );
+ }
+ }
+
+ void assign( const size_t new_size, const Type *t )
+ {
+ if ( new_size <= capacity() )
+ {
+ clear();
+ }
+ else
+ {
+ vector_Allocate( new_size );
+ }
+
+ for ( size_t i = 0; i < new_size; ++i )
+ {
+ alc.ptr[i] = const_cast< Type* >( t );
+ }
+
+ alc.num_elements_used = new_size;
+ }
+
+ void resize( const size_t new_size, const Type *t = nullptr )
+ {
+ if ( new_size == alc.num_elements_used )
+ {
+ return;
+ }
+
+ if ( new_size == 0 )
+ {
+ clear();
+ return;
+ }
+
+ if ( new_size > alc.num_elements_used )
+ {
+ if ( new_size > capacity() )
+ {
+ vector_ReAllocate( new_size );
+ }
+
+ while ( alc.num_elements_used < new_size )
+ {
+ alc.ptr[alc.num_elements_used] = const_cast< Type* >( t );
+ ++alc.num_elements_used;
+ }
+ }
+ else
+ {
+ alc.num_elements_used = new_size;
+ }
+ }
+
+ // trims the capacity of the MVKSmallVectorImpl to the number of used elements
+ void shrink_to_fit()
+ {
+ alc.shrink_to_fit();
+ }
+
+ void erase( const iterator it )
+ {
+ if ( it.is_valid() )
+ {
+ --alc.num_elements_used;
+
+ for ( size_t i = it.get_position(); i < alc.num_elements_used; ++i )
+ {
+ alc.ptr[i] = alc.ptr[i + 1];
+ }
+ }
+ }
+
+ void erase( const iterator first, const iterator last )
+ {
+ if( first.is_valid() )
+ {
+ size_t last_pos = last.is_valid() ? last.get_position() : size();
+ size_t n = last_pos - first.get_position();
+ alc.num_elements_used -= n;
+
+ for( size_t i = first.get_position(), e = last_pos; i < alc.num_elements_used && e < alc.num_elements_used + n; ++i, ++e )
+ {
+ alc.ptr[i] = alc.ptr[e];
+ }
+ }
+ }
+
+ // adds t before position it and automatically resizes vector if necessary
+ void insert( const iterator it, const Type *t )
+ {
+ if ( !it.is_valid() || alc.num_elements_used == 0 )
+ {
+ push_back( t );
+ }
+ else
+ {
+ if ( alc.num_elements_used == capacity() )
+ vector_ReAllocate( vector_GetNextCapacity() );
+
+ // move the remaining elements
+ const size_t it_position = it.get_position();
+ for ( size_t i = alc.num_elements_used; i > it_position; --i )
+ {
+ alc.ptr[i] = alc.ptr[i - 1];
+ }
+
+ alc.ptr[it_position] = const_cast< Type* >( t );
+ ++alc.num_elements_used;
+ }
+ }
+
+ void push_back( const Type *t )
+ {
+ if ( alc.num_elements_used == capacity() )
+ vector_ReAllocate( vector_GetNextCapacity() );
+
+ alc.ptr[alc.num_elements_used] = const_cast< Type* >( t );
+ ++alc.num_elements_used;
+ }
+};
+
+template<typename Type, size_t N = 0>
+using MVKSmallVector = MVKSmallVectorImpl<Type, mvk_smallvector_allocator<Type, N>>;
+
+#endif
+
+
diff --git a/MoltenVK/MoltenVK/Utility/MVKSmallVectorAllocator.h b/MoltenVK/MoltenVK/Utility/MVKSmallVectorAllocator.h
new file mode 100755
index 0000000..5bab836
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKSmallVectorAllocator.h
@@ -0,0 +1,380 @@
+/*
+ * MVKSmallVectorAllocator.h
+ *
+ * Copyright (c) 2012-2020 Dr. Torsten Hans (hans@ipacs.de)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <new>
+#include <type_traits>
+
+
+namespace mvk_smallvector_memory_allocator
+{
+ inline char *alloc( const size_t num_bytes )
+ {
+ return new char[num_bytes];
+ }
+
+ inline void free( void *ptr )
+ {
+ delete[] (char*)ptr;
+ }
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//
+// mvk_smallvector_allocator -> malloc based MVKSmallVector allocator with preallocated storage
+//
+//////////////////////////////////////////////////////////////////////////////////////////
+template <typename T, int M>
+class mvk_smallvector_allocator final
+{
+public:
+ typedef T value_type;
+ T *ptr;
+ size_t num_elements_used;
+
+private:
+
+ // Once dynamic allocation is in use, the preallocated content memory space will
+ // be re-purposed to hold the capacity count. If the content type is small, ensure
+ // preallocated memory is large enough to hold the capacity count, and increase
+ // the number of preallocated elements accordintly, to make use of this memory.
+ // In addition, increase the number of pre-allocated elements to fill any space created
+ // by the alignment of this structure, to maximize the use of the preallocated memory.
+ static constexpr size_t CAP_CNT_SIZE = sizeof( size_t );
+ static constexpr size_t ALIGN_CNT = CAP_CNT_SIZE / sizeof( T );
+ static constexpr size_t ALIGN_MASK = (ALIGN_CNT > 0) ? (ALIGN_CNT - 1) : 0;
+
+ static constexpr size_t MIN_CNT = M > ALIGN_CNT ? M : ALIGN_CNT;
+ static constexpr size_t N = (MIN_CNT + ALIGN_MASK) & ~ALIGN_MASK;
+
+ static constexpr size_t MIN_STACK_SIZE = ( N * sizeof( T ) );
+ static constexpr size_t STACK_SIZE = MIN_STACK_SIZE > CAP_CNT_SIZE ? MIN_STACK_SIZE : CAP_CNT_SIZE;
+ alignas( alignof( T ) ) unsigned char elements_stack[ STACK_SIZE ];
+
+ void set_num_elements_reserved( const size_t num_elements_reserved )
+ {
+ *reinterpret_cast<size_t*>( &elements_stack[0] ) = num_elements_reserved;
+ }
+
+public:
+ const T &operator[]( const size_t i ) const { return ptr[i]; }
+ T &operator[]( const size_t i ) { return ptr[i]; }
+
+ size_t size() const { return num_elements_used; }
+
+ //
+ // faster element construction and destruction using type traits
+ //
+ template<class S, class... Args> typename std::enable_if< !std::is_trivially_constructible<S, Args...>::value >::type
+ construct( S *_ptr, Args&&... _args )
+ {
+ new ( _ptr ) S( std::forward<Args>( _args )... );
+ }
+
+ template<class S, class... Args> typename std::enable_if< std::is_trivially_constructible<S, Args...>::value >::type
+ construct( S *_ptr, Args&&... _args )
+ {
+ *_ptr = S( std::forward<Args>( _args )... );
+ }
+
+ template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type
+ destruct( S *_ptr )
+ {
+ _ptr->~S();
+ }
+
+ template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type
+ destruct( S *_ptr )
+ {
+ }
+
+ template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type
+ destruct_all()
+ {
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ ptr[i].~S();
+ }
+
+ num_elements_used = 0;
+ }
+
+ template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type
+ destruct_all()
+ {
+ num_elements_used = 0;
+ }
+
+ template<class S> typename std::enable_if< !std::is_trivially_destructible<S>::value >::type
+ swap_stack( mvk_smallvector_allocator &a )
+ {
+ T stack_copy[N];
+
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ construct( &stack_copy[i], std::move( S::ptr[i] ) );
+ destruct( &ptr[i] );
+ }
+
+ for( size_t i = 0; i < a.num_elements_used; ++i )
+ {
+ construct( &ptr[i], std::move( a.ptr[i] ) );
+ destruct( &ptr[i] );
+ }
+
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ construct( &a.ptr[i], std::move( stack_copy[i] ) );
+ destruct( &stack_copy[i] );
+ }
+ }
+
+ template<class S> typename std::enable_if< std::is_trivially_destructible<S>::value >::type
+ swap_stack( mvk_smallvector_allocator &a )
+ {
+ for( int i = 0; i < STACK_SIZE; ++i )
+ {
+ const auto v = elements_stack[i];
+ elements_stack[i] = a.elements_stack[i];
+ a.elements_stack[i] = v;
+ }
+ }
+
+public:
+ mvk_smallvector_allocator() : ptr(reinterpret_cast<T*>( &elements_stack[0] )), num_elements_used(0)
+ {
+ }
+
+ mvk_smallvector_allocator( mvk_smallvector_allocator &&a )
+ {
+ // is a heap based -> steal ptr from a
+ if( !a.get_data_on_stack() )
+ {
+ ptr = a.ptr;
+ set_num_elements_reserved( a.get_capacity() );
+
+ a.ptr = a.get_default_ptr();
+ }
+ else
+ {
+ ptr = get_default_ptr();
+ for( size_t i = 0; i < a.num_elements_used; ++i )
+ {
+ construct( &ptr[i], std::move( a.ptr[i] ) );
+ destruct( &a.ptr[i] );
+ }
+ }
+
+ num_elements_used = a.num_elements_used;
+ a.num_elements_used = 0;
+ }
+
+ ~mvk_smallvector_allocator()
+ {
+ deallocate();
+ }
+
+ size_t get_capacity() const
+ {
+ return get_data_on_stack() ? N : *reinterpret_cast<const size_t*>( &elements_stack[0] );
+ }
+
+ constexpr T *get_default_ptr() const
+ {
+ return reinterpret_cast< T* >( const_cast< unsigned char * >( &elements_stack[0] ) );
+ }
+
+ bool get_data_on_stack() const
+ {
+ return ptr == get_default_ptr();
+ }
+
+ void swap( mvk_smallvector_allocator &a )
+ {
+ // both allocators on heap -> easy case
+ if( !get_data_on_stack() && !a.get_data_on_stack() )
+ {
+ auto copy_ptr = ptr;
+ auto copy_num_elements_reserved = get_capacity();
+ ptr = a.ptr;
+ set_num_elements_reserved( a.get_capacity() );
+ a.ptr = copy_ptr;
+ a.set_num_elements_reserved( copy_num_elements_reserved );
+ }
+ // both allocators on stack -> just switch the stack contents
+ else if( get_data_on_stack() && a.get_data_on_stack() )
+ {
+ swap_stack<T>( a );
+ }
+ else if( get_data_on_stack() && !a.get_data_on_stack() )
+ {
+ auto copy_ptr = a.ptr;
+ auto copy_num_elements_reserved = a.get_capacity();
+
+ a.ptr = a.get_default_ptr();
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ construct( &a.ptr[i], std::move( ptr[i] ) );
+ destruct( &ptr[i] );
+ }
+
+ ptr = copy_ptr;
+ set_num_elements_reserved( copy_num_elements_reserved );
+ }
+ else if( !get_data_on_stack() && a.get_data_on_stack() )
+ {
+ auto copy_ptr = ptr;
+ auto copy_num_elements_reserved = get_capacity();
+
+ ptr = get_default_ptr();
+ for( size_t i = 0; i < a.num_elements_used; ++i )
+ {
+ construct( &ptr[i], std::move( a.ptr[i] ) );
+ destruct( &a.ptr[i] );
+ }
+
+ a.ptr = copy_ptr;
+ a.set_num_elements_reserved( copy_num_elements_reserved );
+ }
+
+ auto copy_num_elements_used = num_elements_used;
+ num_elements_used = a.num_elements_used;
+ a.num_elements_used = copy_num_elements_used;
+ }
+
+ //
+ // allocates rounded up to the defined alignment the number of bytes / if the system cannot allocate the specified amount of memory then a null block is returned
+ //
+ void allocate( const size_t num_elements_to_reserve )
+ {
+ deallocate();
+
+ // check if enough memory on stack space is left
+ if( num_elements_to_reserve <= N )
+ {
+ return;
+ }
+
+ ptr = reinterpret_cast< T* >( mvk_smallvector_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );
+ num_elements_used = 0;
+ set_num_elements_reserved( num_elements_to_reserve );
+ }
+
+ //template<class S> typename std::enable_if< !std::is_trivially_copyable<S>::value >::type
+ void _re_allocate( const size_t num_elements_to_reserve )
+ {
+ auto *new_ptr = reinterpret_cast< T* >( mvk_smallvector_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );
+
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ construct( &new_ptr[i], std::move( ptr[i] ) );
+ destruct( &ptr[i] );
+ }
+
+ if( ptr != get_default_ptr() )
+ {
+ mvk_smallvector_memory_allocator::free( ptr );
+ }
+
+ ptr = new_ptr;
+ set_num_elements_reserved( num_elements_to_reserve );
+ }
+
+ //template<class S> typename std::enable_if< std::is_trivially_copyable<S>::value >::type
+ // _re_allocate( const size_t num_elements_to_reserve )
+ //{
+ // const bool data_is_on_stack = get_data_on_stack();
+ //
+ // auto *new_ptr = reinterpret_cast< S* >( mvk_smallvector_memory_allocator::tm_memrealloc( data_is_on_stack ? nullptr : ptr, num_elements_to_reserve * sizeof( S ) ) );
+ // if( data_is_on_stack )
+ // {
+ // for( int i = 0; i < N; ++i )
+ // {
+ // new_ptr[i] = ptr[i];
+ // }
+ // }
+ //
+ // ptr = new_ptr;
+ // set_num_elements_reserved( num_elements_to_reserve );
+ //}
+
+ void re_allocate( const size_t num_elements_to_reserve )
+ {
+ //TM_ASSERT( num_elements_to_reserve > get_capacity() );
+
+ if( num_elements_to_reserve > N )
+ {
+ _re_allocate( num_elements_to_reserve );
+ }
+ }
+
+ void shrink_to_fit()
+ {
+ // nothing to do if data is on stack already
+ if( get_data_on_stack() )
+ return;
+
+ // move elements to stack space
+ if( num_elements_used <= N )
+ {
+ //const auto num_elements_reserved = get_capacity();
+
+ auto *stack_ptr = get_default_ptr();
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ construct( &stack_ptr[i], std::move( ptr[i] ) );
+ destruct( &ptr[i] );
+ }
+
+ mvk_smallvector_memory_allocator::free( ptr );
+
+ ptr = stack_ptr;
+ }
+ else
+ {
+ auto *new_ptr = reinterpret_cast< T* >( mvk_smallvector_memory_allocator::alloc( num_elements_used * sizeof( T ) ) );
+
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ construct( &new_ptr[i], std::move( ptr[i] ) );
+ destruct( &ptr[i] );
+ }
+
+ mvk_smallvector_memory_allocator::free( ptr );
+
+ ptr = new_ptr;
+ set_num_elements_reserved( num_elements_used );
+ }
+ }
+
+ void deallocate()
+ {
+ destruct_all<T>();
+
+ if( !get_data_on_stack() )
+ {
+ mvk_smallvector_memory_allocator::free( ptr );
+ }
+
+ ptr = get_default_ptr();
+ num_elements_used = 0;
+ }
+};
+
diff --git a/MoltenVK/MoltenVK/Utility/MVKVector.h b/MoltenVK/MoltenVK/Utility/MVKVector.h
index c11137a..60a4871 100755
--- a/MoltenVK/MoltenVK/Utility/MVKVector.h
+++ b/MoltenVK/MoltenVK/Utility/MVKVector.h
@@ -62,6 +62,7 @@
// use MVKVector.
//
#include "MVKVectorAllocator.h"
+#include "MVKFoundation.h"
#include <type_traits>
#include <initializer_list>
#include <utility>
@@ -106,6 +107,9 @@
iterator begin() const { return iterator( 0, *this ); }
iterator end() const { return iterator( alc_ptr->size(), *this ); }
+ const MVKArrayRef<Type> contents() const { return MVKArrayRef<Type>(data(), size()); }
+ MVKArrayRef<Type> contents() { return MVKArrayRef<Type>(data(), size()); }
+
virtual const Type &operator[]( const size_t i ) const = 0;
virtual Type &operator[]( const size_t i ) = 0;
virtual const Type &at( const size_t i ) const = 0;
@@ -171,6 +175,9 @@
iterator begin() const { return iterator( 0, *this ); }
iterator end() const { return iterator( alc_ptr->size(), *this ); }
+ const MVKArrayRef<Type*> contents() const { return MVKArrayRef<Type*>(data(), size()); }
+ MVKArrayRef<Type*> contents() { return MVKArrayRef<Type*>(data(), size()); }
+
virtual const Type * const operator[]( const size_t i ) const = 0;
virtual Type * &operator[]( const size_t i ) = 0;
virtual const Type * const at( const size_t i ) const = 0;
diff --git a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
index edad56c..38623c0 100755
--- a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
+++ b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
@@ -242,7 +242,7 @@
//size_t num_elements_reserved; // uhh, num_elements_reserved is mapped onto the stack elements, let the fun begin
alignas( alignof( T ) ) unsigned char elements_stack[N * sizeof( T )];
- static_assert( N * sizeof( T ) >= sizeof( size_t ), "Bummer, nasty optimization doesn't work" );
+ static_assert( N * sizeof( T ) >= sizeof( size_t ), "Initial static allocation must be at least 8 bytes. Increase the count of pre-allocated elements." );
void set_num_elements_reserved( const size_t num_elements_reserved )
{
diff --git a/MoltenVKPackaging.xcodeproj/project.pbxproj b/MoltenVKPackaging.xcodeproj/project.pbxproj
index a6599f1..c9cf30d 100644
--- a/MoltenVKPackaging.xcodeproj/project.pbxproj
+++ b/MoltenVKPackaging.xcodeproj/project.pbxproj
@@ -267,7 +267,7 @@
A90B2B1D1A9B6170008EE819 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1140;
+ LastUpgradeCheck = 1150;
TargetAttributes = {
A9FEADBC1F3517480010240E = {
DevelopmentTeam = VU3TCKU48B;
diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
index f1086b5..88e120b 100644
--- a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
+++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MVKShaderConverterTool Package.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
index c68daf5..fb519fc 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050Debug\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
index 5d5ea44..c8303b7 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050iOS only\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme" "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
index 011bb1f..296fbcd 100644
--- "a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
+++ "b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package \050macOS only\051.xcscheme"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
index 0e1d409..02b62e2 100644
--- a/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
+++ b/MoltenVKPackaging.xcodeproj/xcshareddata/xcschemes/MoltenVK Package.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "NO"
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.cpp b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.cpp
deleted file mode 100644
index 213b3ad..0000000
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * SPIRVReflection.cpp
- *
- * Copyright (c) 2019-2020 Chip Davis for Codeweavers
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SPIRVReflection.h"
-#include <SPIRV-Cross/spirv_parser.hpp>
-#include <SPIRV-Cross/spirv_reflect.hpp>
-
-namespace mvk {
-
-static const char missingPatchInputErr[] = "Neither tessellation shader specifies a patch input mode (Triangles, Quads, or Isolines).";
-static const char missingWindingErr[] = "Neither tessellation shader specifies a winding order mode (VertexOrderCw or VertexOrderCcw).";
-static const char missingPartitionErr[] = "Neither tessellation shader specifies a partition mode (SpacingEqual, SpacingFractionalOdd, or SpacingFractionalEven).";
-static const char missingOutputVerticesErr[] = "Neither tessellation shader specifies the number of output control points.";
-
-/** Given a tessellation control shader and a tessellation evaluation shader, both in SPIR-V format, returns tessellation reflection data. */
-bool getTessReflectionData(const std::vector<uint32_t>& tesc, const std::string& tescEntryName, const std::vector<uint32_t>& tese, const std::string& teseEntryName, SPIRVTessReflectionData& reflectData, std::string& errorLog) {
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- try {
-#endif
- SPIRV_CROSS_NAMESPACE::CompilerReflection tescReflect(tesc);
- SPIRV_CROSS_NAMESPACE::CompilerReflection teseReflect(tese);
-
- if (!tescEntryName.empty()) {
- tescReflect.set_entry_point(tescEntryName, spv::ExecutionModelTessellationControl);
- }
- if (!teseEntryName.empty()) {
- teseReflect.set_entry_point(teseEntryName, spv::ExecutionModelTessellationEvaluation);
- }
-
- tescReflect.compile();
- teseReflect.compile();
-
- const SPIRV_CROSS_NAMESPACE::Bitset& tescModes = tescReflect.get_execution_mode_bitset();
- const SPIRV_CROSS_NAMESPACE::Bitset& teseModes = teseReflect.get_execution_mode_bitset();
-
- // Extract the parameters from the shaders.
- if (tescModes.get(spv::ExecutionModeTriangles)) {
- reflectData.patchKind = spv::ExecutionModeTriangles;
- } else if (tescModes.get(spv::ExecutionModeQuads)) {
- reflectData.patchKind = spv::ExecutionModeQuads;
- } else if (tescModes.get(spv::ExecutionModeIsolines)) {
- reflectData.patchKind = spv::ExecutionModeIsolines;
- } else if (teseModes.get(spv::ExecutionModeTriangles)) {
- reflectData.patchKind = spv::ExecutionModeTriangles;
- } else if (teseModes.get(spv::ExecutionModeQuads)) {
- reflectData.patchKind = spv::ExecutionModeQuads;
- } else if (teseModes.get(spv::ExecutionModeIsolines)) {
- reflectData.patchKind = spv::ExecutionModeIsolines;
- } else {
- errorLog = missingPatchInputErr;
- return false;
- }
-
- if (tescModes.get(spv::ExecutionModeVertexOrderCw)) {
- reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
- } else if (tescModes.get(spv::ExecutionModeVertexOrderCcw)) {
- reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
- } else if (teseModes.get(spv::ExecutionModeVertexOrderCw)) {
- reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
- } else if (teseModes.get(spv::ExecutionModeVertexOrderCcw)) {
- reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
- } else {
- errorLog = missingWindingErr;
- return false;
- }
-
- reflectData.pointMode = tescModes.get(spv::ExecutionModePointMode) || teseModes.get(spv::ExecutionModePointMode);
-
- if (tescModes.get(spv::ExecutionModeSpacingEqual)) {
- reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
- } else if (tescModes.get(spv::ExecutionModeSpacingFractionalEven)) {
- reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
- } else if (tescModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
- reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
- } else if (teseModes.get(spv::ExecutionModeSpacingEqual)) {
- reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
- } else if (teseModes.get(spv::ExecutionModeSpacingFractionalEven)) {
- reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
- } else if (teseModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
- reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
- } else {
- errorLog = missingPartitionErr;
- return false;
- }
-
- if (tescModes.get(spv::ExecutionModeOutputVertices)) {
- reflectData.numControlPoints = tescReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
- } else if (teseModes.get(spv::ExecutionModeOutputVertices)) {
- reflectData.numControlPoints = teseReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
- } else {
- errorLog = missingOutputVerticesErr;
- return false;
- }
-
- return true;
-
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- } catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
- errorLog = ex.what();
- return false;
- }
-#endif
-}
-
-/** Given a shader in SPIR-V format, returns output reflection data. */
-bool getShaderOutputs(const std::vector<uint32_t>& spirv, spv::ExecutionModel model, const std::string& entryName, std::vector<SPIRVShaderOutput>& outputs, std::string& errorLog) {
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- try {
-#endif
- SPIRV_CROSS_NAMESPACE::Parser parser(spirv);
- parser.parse();
- SPIRV_CROSS_NAMESPACE::CompilerReflection reflect(parser.get_parsed_ir());
- if (!entryName.empty()) {
- reflect.set_entry_point(entryName, model);
- }
- reflect.compile();
- reflect.update_active_builtins();
-
- outputs.clear();
-
- auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
- parser.get_parsed_ir().for_each_typed_id<SPIRV_CROSS_NAMESPACE::SPIRVariable>([&reflect, &outputs, model, addSat](uint32_t varID, const SPIRV_CROSS_NAMESPACE::SPIRVariable& var) {
- if (var.storage != spv::StorageClassOutput) { return; }
-
- bool isUsed = true;
- const auto* type = &reflect.get_type(reflect.get_type_from_variable(varID).parent_type);
- bool patch = reflect.has_decoration(varID, spv::DecorationPatch);
- auto biType = spv::BuiltInMax;
- if (reflect.has_decoration(varID, spv::DecorationBuiltIn)) {
- biType = (spv::BuiltIn)reflect.get_decoration(varID, spv::DecorationBuiltIn);
- isUsed = reflect.has_active_builtin(biType, var.storage);
- }
- uint32_t loc = -1;
- if (reflect.has_decoration(varID, spv::DecorationLocation)) {
- loc = reflect.get_decoration(varID, spv::DecorationLocation);
- }
- if (model == spv::ExecutionModelTessellationControl && !patch)
- type = &reflect.get_type(type->parent_type);
-
- if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct) {
- for (uint32_t i = 0; i < type->member_types.size(); i++) {
- // Each member may have a location decoration. If not, each member
- // gets an incrementing location.
- uint32_t memberLoc = addSat(loc, i);
- if (reflect.has_member_decoration(type->self, i, spv::DecorationLocation)) {
- memberLoc = reflect.get_member_decoration(type->self, i, spv::DecorationLocation);
- }
- patch = reflect.has_member_decoration(type->self, i, spv::DecorationPatch);
- if (reflect.has_member_decoration(type->self, i, spv::DecorationBuiltIn)) {
- biType = (spv::BuiltIn)reflect.get_member_decoration(type->self, i, spv::DecorationBuiltIn);
- isUsed = reflect.has_active_builtin(biType, var.storage);
- }
- const SPIRV_CROSS_NAMESPACE::SPIRType& memberType = reflect.get_type(type->member_types[i]);
- if (memberType.columns > 1) {
- for (uint32_t i = 0; i < memberType.columns; i++) {
- outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
- }
- } else if (!memberType.array.empty()) {
- for (uint32_t i = 0; i < memberType.array[0]; i++) {
- outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
- }
- } else {
- outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, biType, patch, isUsed});
- }
- }
- } else if (type->columns > 1) {
- for (uint32_t i = 0; i < type->columns; i++) {
- outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
- }
- } else if (!type->array.empty()) {
- for (uint32_t i = 0; i < type->array[0]; i++) {
- outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
- }
- } else {
- outputs.push_back({type->basetype, type->vecsize, loc, biType, patch, isUsed});
- }
- });
- // Sort outputs by ascending location.
- std::stable_sort(outputs.begin(), outputs.end(), [](const SPIRVShaderOutput& a, const SPIRVShaderOutput& b) {
- return a.location < b.location;
- });
- // Assign locations to outputs that don't have one.
- uint32_t loc = -1;
- for (SPIRVShaderOutput& out : outputs) {
- if (out.location == uint32_t(-1)) { out.location = loc + 1; }
- loc = out.location;
- }
- return true;
-#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
- } catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
- errorLog = ex.what();
- return false;
- }
-#endif
-}
-
-}
diff --git a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h
index 30d4dbf..b17fe79 100644
--- a/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h
+++ b/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/SPIRVReflection.h
@@ -21,6 +21,8 @@
#include <SPIRV-Cross/spirv.hpp>
#include <SPIRV-Cross/spirv_common.hpp>
+#include <SPIRV-Cross/spirv_parser.hpp>
+#include <SPIRV-Cross/spirv_reflect.hpp>
#include <string>
#include <vector>
@@ -75,10 +77,191 @@
#pragma mark Functions
/** Given a tessellation control shader and a tessellation evaluation shader, both in SPIR-V format, returns tessellation reflection data. */
- bool getTessReflectionData(const std::vector<uint32_t>& tesc, const std::string& tescEntryName, const std::vector<uint32_t>& tese, const std::string& teseEntryName, SPIRVTessReflectionData& reflectData, std::string& errorLog);
+ template<typename Vs>
+ static inline bool getTessReflectionData(const Vs& tesc, const std::string& tescEntryName,
+ const Vs& tese, const std::string& teseEntryName,
+ SPIRVTessReflectionData& reflectData, std::string& errorLog) {
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+ try {
+#endif
+ SPIRV_CROSS_NAMESPACE::CompilerReflection tescReflect(tesc);
+ SPIRV_CROSS_NAMESPACE::CompilerReflection teseReflect(tese);
+
+ if (!tescEntryName.empty()) {
+ tescReflect.set_entry_point(tescEntryName, spv::ExecutionModelTessellationControl);
+ }
+ if (!teseEntryName.empty()) {
+ teseReflect.set_entry_point(teseEntryName, spv::ExecutionModelTessellationEvaluation);
+ }
+
+ tescReflect.compile();
+ teseReflect.compile();
+
+ const SPIRV_CROSS_NAMESPACE::Bitset& tescModes = tescReflect.get_execution_mode_bitset();
+ const SPIRV_CROSS_NAMESPACE::Bitset& teseModes = teseReflect.get_execution_mode_bitset();
+
+ // Extract the parameters from the shaders.
+ if (tescModes.get(spv::ExecutionModeTriangles)) {
+ reflectData.patchKind = spv::ExecutionModeTriangles;
+ } else if (tescModes.get(spv::ExecutionModeQuads)) {
+ reflectData.patchKind = spv::ExecutionModeQuads;
+ } else if (tescModes.get(spv::ExecutionModeIsolines)) {
+ reflectData.patchKind = spv::ExecutionModeIsolines;
+ } else if (teseModes.get(spv::ExecutionModeTriangles)) {
+ reflectData.patchKind = spv::ExecutionModeTriangles;
+ } else if (teseModes.get(spv::ExecutionModeQuads)) {
+ reflectData.patchKind = spv::ExecutionModeQuads;
+ } else if (teseModes.get(spv::ExecutionModeIsolines)) {
+ reflectData.patchKind = spv::ExecutionModeIsolines;
+ } else {
+ errorLog = "Neither tessellation shader specifies a patch input mode (Triangles, Quads, or Isolines).";
+ return false;
+ }
+
+ if (tescModes.get(spv::ExecutionModeVertexOrderCw)) {
+ reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
+ } else if (tescModes.get(spv::ExecutionModeVertexOrderCcw)) {
+ reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
+ } else if (teseModes.get(spv::ExecutionModeVertexOrderCw)) {
+ reflectData.windingOrder = spv::ExecutionModeVertexOrderCw;
+ } else if (teseModes.get(spv::ExecutionModeVertexOrderCcw)) {
+ reflectData.windingOrder = spv::ExecutionModeVertexOrderCcw;
+ } else {
+ errorLog = "Neither tessellation shader specifies a winding order mode (VertexOrderCw or VertexOrderCcw).";
+ return false;
+ }
+
+ reflectData.pointMode = tescModes.get(spv::ExecutionModePointMode) || teseModes.get(spv::ExecutionModePointMode);
+
+ if (tescModes.get(spv::ExecutionModeSpacingEqual)) {
+ reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
+ } else if (tescModes.get(spv::ExecutionModeSpacingFractionalEven)) {
+ reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
+ } else if (tescModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
+ reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
+ } else if (teseModes.get(spv::ExecutionModeSpacingEqual)) {
+ reflectData.partitionMode = spv::ExecutionModeSpacingEqual;
+ } else if (teseModes.get(spv::ExecutionModeSpacingFractionalEven)) {
+ reflectData.partitionMode = spv::ExecutionModeSpacingFractionalEven;
+ } else if (teseModes.get(spv::ExecutionModeSpacingFractionalOdd)) {
+ reflectData.partitionMode = spv::ExecutionModeSpacingFractionalOdd;
+ } else {
+ errorLog = "Neither tessellation shader specifies a partition mode (SpacingEqual, SpacingFractionalOdd, or SpacingFractionalEven).";
+ return false;
+ }
+
+ if (tescModes.get(spv::ExecutionModeOutputVertices)) {
+ reflectData.numControlPoints = tescReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
+ } else if (teseModes.get(spv::ExecutionModeOutputVertices)) {
+ reflectData.numControlPoints = teseReflect.get_execution_mode_argument(spv::ExecutionModeOutputVertices);
+ } else {
+ errorLog = "Neither tessellation shader specifies the number of output control points.";
+ return false;
+ }
+
+ return true;
+
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+ } catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
+ errorLog = ex.what();
+ return false;
+ }
+#endif
+ }
/** Given a shader in SPIR-V format, returns output reflection data. */
- bool getShaderOutputs(const std::vector<uint32_t>& spirv, spv::ExecutionModel model, const std::string& entryName, std::vector<SPIRVShaderOutput>& outputs, std::string& errorLog);
+ template<typename Vs, typename Vo>
+ static inline bool getShaderOutputs(const Vs& spirv, spv::ExecutionModel model, const std::string& entryName,
+ Vo& outputs, std::string& errorLog) {
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+ try {
+#endif
+ SPIRV_CROSS_NAMESPACE::Parser parser(spirv);
+ parser.parse();
+ SPIRV_CROSS_NAMESPACE::CompilerReflection reflect(parser.get_parsed_ir());
+ if (!entryName.empty()) {
+ reflect.set_entry_point(entryName, model);
+ }
+ reflect.compile();
+ reflect.update_active_builtins();
+
+ outputs.clear();
+
+ auto addSat = [](uint32_t a, uint32_t b) { return a == uint32_t(-1) ? a : a + b; };
+ parser.get_parsed_ir().for_each_typed_id<SPIRV_CROSS_NAMESPACE::SPIRVariable>([&reflect, &outputs, model, addSat](uint32_t varID, const SPIRV_CROSS_NAMESPACE::SPIRVariable& var) {
+ if (var.storage != spv::StorageClassOutput) { return; }
+
+ bool isUsed = true;
+ const auto* type = &reflect.get_type(reflect.get_type_from_variable(varID).parent_type);
+ bool patch = reflect.has_decoration(varID, spv::DecorationPatch);
+ auto biType = spv::BuiltInMax;
+ if (reflect.has_decoration(varID, spv::DecorationBuiltIn)) {
+ biType = (spv::BuiltIn)reflect.get_decoration(varID, spv::DecorationBuiltIn);
+ isUsed = reflect.has_active_builtin(biType, var.storage);
+ }
+ uint32_t loc = -1;
+ if (reflect.has_decoration(varID, spv::DecorationLocation)) {
+ loc = reflect.get_decoration(varID, spv::DecorationLocation);
+ }
+ if (model == spv::ExecutionModelTessellationControl && !patch)
+ type = &reflect.get_type(type->parent_type);
+
+ if (type->basetype == SPIRV_CROSS_NAMESPACE::SPIRType::Struct) {
+ for (uint32_t idx = 0; idx < type->member_types.size(); idx++) {
+ // Each member may have a location decoration. If not, each member
+ // gets an incrementing location.
+ uint32_t memberLoc = addSat(loc, idx);
+ if (reflect.has_member_decoration(type->self, idx, spv::DecorationLocation)) {
+ memberLoc = reflect.get_member_decoration(type->self, idx, spv::DecorationLocation);
+ }
+ patch = reflect.has_member_decoration(type->self, idx, spv::DecorationPatch);
+ if (reflect.has_member_decoration(type->self, idx, spv::DecorationBuiltIn)) {
+ biType = (spv::BuiltIn)reflect.get_member_decoration(type->self, idx, spv::DecorationBuiltIn);
+ isUsed = reflect.has_active_builtin(biType, var.storage);
+ }
+ const SPIRV_CROSS_NAMESPACE::SPIRType& memberType = reflect.get_type(type->member_types[idx]);
+ if (memberType.columns > 1) {
+ for (uint32_t i = 0; i < memberType.columns; i++) {
+ outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
+ }
+ } else if (!memberType.array.empty()) {
+ for (uint32_t i = 0; i < memberType.array[0]; i++) {
+ outputs.push_back({memberType.basetype, memberType.vecsize, addSat(memberLoc, i), biType, patch, isUsed});
+ }
+ } else {
+ outputs.push_back({memberType.basetype, memberType.vecsize, memberLoc, biType, patch, isUsed});
+ }
+ }
+ } else if (type->columns > 1) {
+ for (uint32_t i = 0; i < type->columns; i++) {
+ outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
+ }
+ } else if (!type->array.empty()) {
+ for (uint32_t i = 0; i < type->array[0]; i++) {
+ outputs.push_back({type->basetype, type->vecsize, addSat(loc, i), biType, patch, isUsed});
+ }
+ } else {
+ outputs.push_back({type->basetype, type->vecsize, loc, biType, patch, isUsed});
+ }
+ });
+ // Sort outputs by ascending location.
+ std::stable_sort(outputs.begin(), outputs.end(), [](const SPIRVShaderOutput& a, const SPIRVShaderOutput& b) {
+ return a.location < b.location;
+ });
+ // Assign locations to outputs that don't have one.
+ uint32_t loc = -1;
+ for (SPIRVShaderOutput& out : outputs) {
+ if (out.location == uint32_t(-1)) { out.location = loc + 1; }
+ loc = out.location;
+ }
+ return true;
+#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS
+ } catch (SPIRV_CROSS_NAMESPACE::CompilerError& ex) {
+ errorLog = ex.what();
+ return false;
+ }
+#endif
+ }
}
#endif
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
index 62fb66e..4de848f 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/project.pbxproj
@@ -7,8 +7,6 @@
objects = {
/* Begin PBXBuildFile section */
- 450A4F5F220CB180007203D7 /* SPIRVReflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */; };
- 450A4F60220CB180007203D7 /* SPIRVReflection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */; };
450A4F61220CB180007203D7 /* SPIRVReflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 450A4F5E220CB180007203D7 /* SPIRVReflection.h */; };
450A4F62220CB180007203D7 /* SPIRVReflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 450A4F5E220CB180007203D7 /* SPIRVReflection.h */; };
A909408A1C58013E0094110D /* SPIRVToMSLConverter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A9093F5A1C58013E0094110D /* SPIRVToMSLConverter.cpp */; };
@@ -81,7 +79,6 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
- 450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SPIRVReflection.cpp; sourceTree = "<group>"; };
450A4F5E220CB180007203D7 /* SPIRVReflection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPIRVReflection.h; sourceTree = "<group>"; };
A9093F5A1C58013E0094110D /* SPIRVToMSLConverter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SPIRVToMSLConverter.cpp; sourceTree = "<group>"; };
A9093F5B1C58013E0094110D /* SPIRVToMSLConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPIRVToMSLConverter.h; sourceTree = "<group>"; };
@@ -175,7 +172,6 @@
A925B70A1C7754B2006E7ECD /* FileSupport.mm */,
A928C9171D0488DC00071B88 /* SPIRVConversion.h */,
A928C9181D0488DC00071B88 /* SPIRVConversion.mm */,
- 450A4F5D220CB180007203D7 /* SPIRVReflection.cpp */,
450A4F5E220CB180007203D7 /* SPIRVReflection.h */,
A9093F5A1C58013E0094110D /* SPIRVToMSLConverter.cpp */,
A9093F5B1C58013E0094110D /* SPIRVToMSLConverter.h */,
@@ -415,7 +411,7 @@
A9F55D25198BE6A7004EC31B /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1140;
+ LastUpgradeCheck = 1150;
ORGANIZATIONNAME = "The Brenwill Workshop Ltd.";
TargetAttributes = {
A9092A8C1A81717B00051823 = {
@@ -648,7 +644,6 @@
A909408A1C58013E0094110D /* SPIRVToMSLConverter.cpp in Sources */,
A9C70F66221B321700FBA31A /* SPIRVSupport.cpp in Sources */,
A928C91B1D0488DC00071B88 /* SPIRVConversion.mm in Sources */,
- 450A4F5F220CB180007203D7 /* SPIRVReflection.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -660,7 +655,6 @@
A909408B1C58013E0094110D /* SPIRVToMSLConverter.cpp in Sources */,
A9C70F67221B321700FBA31A /* SPIRVSupport.cpp in Sources */,
A928C91C1D0488DC00071B88 /* SPIRVConversion.mm in Sources */,
- 450A4F60220CB180007203D7 /* SPIRVReflection.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
index 9c5e88e..4a06e22 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
index 555a788..a4a66d6 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKGLSLToSPIRVConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
index a3d1947..8c280b7 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-iOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
index 445228e..10e1218 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKSPIRVToMSLConverter-macOS.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
diff --git a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
index 9b5bad7..4fcf339 100644
--- a/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
+++ b/MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj/xcshareddata/xcschemes/MoltenVKShaderConverter.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- LastUpgradeVersion = "1140"
+ LastUpgradeVersion = "1150"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"