Merge pull request #376 from aerofly/master
MVKVector and small bug fix
diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
index d7ee478..d25f6cd 100644
--- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
+++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj
@@ -9,6 +9,10 @@
/* Begin PBXBuildFile section */
45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
45003E74214AD4E600E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; };
+ 83A4AD2A21BD75570006C935 /* MVKVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2521BD75570006C935 /* MVKVector.h */; };
+ 83A4AD2B21BD75570006C935 /* MVKVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2521BD75570006C935 /* MVKVector.h */; };
+ 83A4AD2C21BD75570006C935 /* MVKVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */; };
+ 83A4AD2D21BD75570006C935 /* MVKVectorAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */; };
A9096E5E1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
A9096E5F1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; };
A909F65F213B190700FCD6BE /* MVKExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A909F65A213B190600FCD6BE /* MVKExtensions.h */; };
@@ -261,6 +265,8 @@
/* Begin PBXFileReference section */
45003E6F214AD4C900E989CB /* MVKExtensions.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKExtensions.def; sourceTree = "<group>"; };
+ 83A4AD2521BD75570006C935 /* MVKVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKVector.h; sourceTree = "<group>"; };
+ 83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKVectorAllocator.h; sourceTree = "<group>"; };
A9096E5C1F81E16300DFBEA6 /* MVKCmdDispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVKCmdDispatch.h; sourceTree = "<group>"; };
A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKCmdDispatch.mm; sourceTree = "<group>"; };
A909F65A213B190600FCD6BE /* MVKExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKExtensions.h; sourceTree = "<group>"; };
@@ -491,6 +497,8 @@
A98149401FB6A3F7005F00B4 /* Utility */ = {
isa = PBXGroup;
children = (
+ 83A4AD2521BD75570006C935 /* MVKVector.h */,
+ 83A4AD2921BD75570006C935 /* MVKVectorAllocator.h */,
A98149411FB6A3F7005F00B4 /* MVKBaseObject.cpp */,
A98149421FB6A3F7005F00B4 /* MVKBaseObject.h */,
A98149431FB6A3F7005F00B4 /* MVKEnvironment.h */,
@@ -607,10 +615,12 @@
A9F042A61FB4CF83009FCCB8 /* MVKLogging.h in Headers */,
A94FB8001C7DFB4800632CA3 /* MVKQueue.h in Headers */,
A94FB7EC1C7DFB4800632CA3 /* MVKFramebuffer.h in Headers */,
+ 83A4AD2C21BD75570006C935 /* MVKVectorAllocator.h in Headers */,
A98149611FB6A3F7005F00B4 /* MVKWatermarkShaderSource.h in Headers */,
A9E53DE32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
A94FB8181C7DFB4800632CA3 /* MVKSync.h in Headers */,
A94FB7E41C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+ 83A4AD2A21BD75570006C935 /* MVKVector.h in Headers */,
A94FB7D41C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
A94FB80C1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
A94FB7C01C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */,
@@ -668,10 +678,12 @@
A9F042A71FB4CF83009FCCB8 /* MVKLogging.h in Headers */,
A94FB8011C7DFB4800632CA3 /* MVKQueue.h in Headers */,
A94FB7ED1C7DFB4800632CA3 /* MVKFramebuffer.h in Headers */,
+ 83A4AD2D21BD75570006C935 /* MVKVectorAllocator.h in Headers */,
A98149621FB6A3F7005F00B4 /* MVKWatermarkShaderSource.h in Headers */,
A9E53DE42100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h in Headers */,
A94FB8191C7DFB4800632CA3 /* MVKSync.h in Headers */,
A94FB7E51C7DFB4800632CA3 /* MVKDevice.h in Headers */,
+ 83A4AD2B21BD75570006C935 /* MVKVector.h in Headers */,
A94FB7D51C7DFB4800632CA3 /* MVKCommandPool.h in Headers */,
A94FB80D1C7DFB4800632CA3 /* MVKShaderModule.h in Headers */,
A94FB7C11C7DFB4800632CA3 /* MVKCmdQueries.h in Headers */,
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
index 91bd8b6..7e585cd 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
@@ -20,7 +20,7 @@
#include "MVKCommand.h"
#include "MVKMTLResourceBindings.h"
-#include <vector>
+#include "MVKVector.h"
#import <Metal/Metal.h>
@@ -44,7 +44,7 @@
MVKCmdBindVertexBuffers(MVKCommandTypePool<MVKCmdBindVertexBuffers>* pool);
protected:
- std::vector<MVKMTLBufferBinding> _bindings;
+ MVKVector<MVKMTLBufferBinding> _bindings;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
index a6002f7..5689133 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
@@ -19,6 +19,7 @@
#pragma once
#include "MVKCommand.h"
+#include "MVKVector.h"
#include <vector>
class MVKCommandBuffer;
@@ -101,8 +102,8 @@
private:
VkPipelineBindPoint _pipelineBindPoint;
MVKPipelineLayout* _pipelineLayout;
- std::vector<MVKDescriptorSet*> _descriptorSets;
- std::vector<uint32_t> _dynamicOffsets;
+ MVKVector<MVKDescriptorSet*> _descriptorSets;
+ MVKVector<uint32_t> _dynamicOffsets;
uint32_t _firstSet;
};
@@ -128,7 +129,7 @@
MVKPipelineLayout* _pipelineLayout;
VkShaderStageFlags _stageFlags;
uint32_t _offset;
- std::vector<char> _pushConstants;
+ MVKVector<char> _pushConstants;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
index 57d1ac8..01f141c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdPipeline.mm
@@ -160,7 +160,7 @@
_offset = offset;
_pushConstants.resize(size);
- copy_n((char*)pValues, size, _pushConstants.begin());
+ std::copy_n((char*)pValues, size, _pushConstants.begin());
}
void MVKCmdPushConstants::encode(MVKCommandEncoder* cmdEncoder) {
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
index db87024..9562d6b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdRenderPass.h
@@ -19,6 +19,7 @@
#pragma once
#include "MVKCommand.h"
+#include "MVKVector.h"
#include <vector>
#import <Metal/Metal.h>
@@ -47,7 +48,7 @@
VkSubpassContents _contents;
MVKRenderPass* _renderPass;
MVKFramebuffer* _framebuffer;
- std::vector<VkClearValue> _clearValues;
+ MVKVector<VkClearValue> _clearValues;
};
@@ -114,7 +115,7 @@
private:
uint32_t _firstViewport;
- std::vector<MTLViewport> _mtlViewports;
+ MVKVector<MTLViewport> _mtlViewports;
};
@@ -133,7 +134,7 @@
private:
uint32_t _firstScissor;
- std::vector<MTLScissorRect> _mtlScissors;
+ MVKVector<MTLScissorRect> _mtlScissors;
};
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index 7560d4c..d970f0e 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -23,6 +23,7 @@
#include "MVKCommandEncoderState.h"
#include "MVKMTLBufferAllocation.h"
#include "MVKCmdPipeline.h"
+#include "MVKVector.h"
#include <vector>
#include <unordered_map>
@@ -239,7 +240,7 @@
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
- std::vector<VkClearValue>* clearValues);
+ MVKVector<VkClearValue>* clearValues);
/** Begins the next render subpass. */
void beginNextSubpass(VkSubpassContents renderpassContents);
@@ -402,7 +403,7 @@
uint32_t _renderSubpassIndex;
VkRect2D _renderArea;
MVKActivatedQueries* _pActivatedQueries;
- std::vector<VkClearValue> _clearValues;
+ MVKVector<VkClearValue> _clearValues;
id<MTLComputeCommandEncoder> _mtlComputeEncoder;
MVKCommandUse _mtlComputeEncoderUse;
id<MTLBlitCommandEncoder> _mtlBlitEncoder;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index 35ebe11..d36819b 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -219,7 +219,7 @@
MVKRenderPass* renderPass,
MVKFramebuffer* framebuffer,
VkRect2D& renderArea,
- vector<VkClearValue>* clearValues) {
+ MVKVector<VkClearValue>* clearValues) {
_renderPass = renderPass;
_framebuffer = framebuffer;
_renderArea = renderArea;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 4981e65..a87a7e0 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -18,9 +18,9 @@
#pragma once
-#include "MVKMTLResourceBindings.h"
+#include "MVKMTLResourceBindings.h"
#include "MVKCommandResourceFactory.h"
-#include <vector>
+#include "MVKVector.h"
class MVKCommandEncoder;
class MVKOcclusionQueryPool;
@@ -135,7 +135,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(std::vector<MTLViewport> mtlViewports,
+ void setViewports(const MVKVector<MTLViewport> &mtlViewports,
uint32_t firstViewport,
bool isSettingDynamically);
@@ -147,7 +147,7 @@
void encodeImpl() override;
void resetImpl() override;
- std::vector<MTLViewport> _mtlViewports;
+ MVKVector<MTLViewport> _mtlViewports;
};
@@ -164,7 +164,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(std::vector<MTLScissorRect> mtlScissors,
+ void setScissors(const MVKVector<MTLScissorRect> &mtlScissors,
uint32_t firstScissor,
bool isSettingDynamically);
@@ -176,7 +176,7 @@
void encodeImpl() override;
void resetImpl() override;
- std::vector<MTLScissorRect> _mtlScissors;
+ MVKVector<MTLScissorRect> _mtlScissors;
};
@@ -189,7 +189,7 @@
public:
/** Sets the specified push constants. */
- void setPushConstants(uint32_t offset, std::vector<char>& pushConstants);
+ void setPushConstants(uint32_t offset, MVKVector<char>& pushConstants);
/** Sets the index of the Metal buffer used to hold the push constants. */
void setMTLBufferIndex(uint32_t mtlBufferIndex);
@@ -203,7 +203,7 @@
void encodeImpl() override;
void resetImpl() override;
- std::vector<char> _pushConstants;
+ MVKVector<char> _pushConstants;
VkShaderStageFlagBits _shaderStage;
uint32_t _mtlBufferIndex = 0;
};
@@ -348,15 +348,15 @@
// Template function that marks both the vector and all binding elements in the vector as dirty.
template<class T>
- void markDirty(std::vector<T>& bindings, bool& bindingsDirtyFlag) {
+ void markDirty(T& bindings, bool& bindingsDirtyFlag) {
for (auto& b : bindings) { b.isDirty = true; }
bindingsDirtyFlag = true;
}
// 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>
- void bind(const T& b, std::vector<T>& bindings, bool& bindingsDirtyFlag) {
+ template<class T, class U>
+ void bind(const T& b, U& bindings, bool& bindingsDirtyFlag) {
if ( !b.mtlResource ) { return; }
@@ -365,7 +365,7 @@
bindingsDirtyFlag = true;
db.isDirty = true;
- for (auto iter = bindings.begin(), end = bindings.end(); iter != end; iter++) {
+ for (auto iter = bindings.begin(), end = bindings.end(); iter != end; ++iter) {
if( iter->index == db.index ) {
*iter = db;
return;
@@ -377,7 +377,7 @@
// 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(std::vector<T>& bindings,
+ void encodeBinding(MVKVector<T>& bindings,
bool& bindingsDirtyFlag,
std::function<void(MVKCommandEncoder* cmdEncoder, T& b)> mtlOperation) {
if (bindingsDirtyFlag) {
@@ -451,12 +451,12 @@
void resetImpl() override;
void markDirty() override;
- std::vector<MVKMTLBufferBinding> _vertexBufferBindings;
- std::vector<MVKMTLBufferBinding> _fragmentBufferBindings;
- std::vector<MVKMTLTextureBinding> _vertexTextureBindings;
- std::vector<MVKMTLTextureBinding> _fragmentTextureBindings;
- std::vector<MVKMTLSamplerStateBinding> _vertexSamplerStateBindings;
- std::vector<MVKMTLSamplerStateBinding> _fragmentSamplerStateBindings;
+ MVKVector<MVKMTLBufferBinding> _vertexBufferBindings;
+ MVKVector<MVKMTLBufferBinding> _fragmentBufferBindings;
+ MVKVector<MVKMTLTextureBinding> _vertexTextureBindings;
+ MVKVector<MVKMTLTextureBinding> _fragmentTextureBindings;
+ MVKVector<MVKMTLSamplerStateBinding> _vertexSamplerStateBindings;
+ MVKVector<MVKMTLSamplerStateBinding> _fragmentSamplerStateBindings;
MVKMTLBufferBinding _vertexAuxBufferBinding;
MVKMTLBufferBinding _fragmentAuxBufferBinding;
@@ -499,9 +499,9 @@
void resetImpl() override;
void markDirty() override;
- std::vector<MVKMTLBufferBinding> _bufferBindings;
- std::vector<MVKMTLTextureBinding> _textureBindings;
- std::vector<MVKMTLSamplerStateBinding> _samplerStateBindings;
+ MVKVector<MVKMTLBufferBinding> _bufferBindings;
+ MVKVector<MVKMTLTextureBinding> _textureBindings;
+ MVKVector<MVKMTLSamplerStateBinding> _samplerStateBindings;
MVKMTLBufferBinding _auxBufferBinding;
bool _areBufferBindingsDirty = false;
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index b1ed8f3..f50843f 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -50,7 +50,7 @@
#pragma mark -
#pragma mark MVKViewportCommandEncoderState
-void MVKViewportCommandEncoderState::setViewports(vector<MTLViewport> mtlViewports,
+void MVKViewportCommandEncoderState::setViewports(const MVKVector<MTLViewport> &mtlViewports,
uint32_t firstViewport,
bool isSettingDynamically) {
@@ -91,7 +91,7 @@
#pragma mark -
#pragma mark MVKScissorCommandEncoderState
-void MVKScissorCommandEncoderState::setScissors(vector<MTLScissorRect> mtlScissors,
+void MVKScissorCommandEncoderState::setScissors(const MVKVector<MTLScissorRect> &mtlScissors,
uint32_t firstScissor,
bool isSettingDynamically) {
@@ -113,7 +113,7 @@
void MVKScissorCommandEncoderState::encodeImpl() {
MVKAssert(!_mtlScissors.empty(), "Must specify at least one scissor rect");
- std::vector<MTLScissorRect> clippedScissors(_mtlScissors);
+ auto clippedScissors(_mtlScissors);
std::for_each(clippedScissors.begin(), clippedScissors.end(), [this](MTLScissorRect& scissor) {
scissor = _cmdEncoder->clipToRenderArea(scissor);
});
@@ -136,7 +136,7 @@
#pragma mark -
#pragma mark MVKPushConstantsCommandEncoderState
-void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, vector<char>& pushConstants) {
+void MVKPushConstantsCommandEncoderState:: setPushConstants(uint32_t offset, MVKVector<char>& pushConstants) {
uint32_t pcCnt = (uint32_t)pushConstants.size();
mvkEnsureSize(_pushConstants, offset + pcCnt);
copy(pushConstants.begin(), pushConstants.end(), _pushConstants.begin() + offset);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 865fb00..47ce94a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -20,6 +20,7 @@
#include "MVKDevice.h"
#include "MVKImage.h"
+#include "MVKVector.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include <unordered_set>
#include <unordered_map>
@@ -80,7 +81,7 @@
void bind(MVKCommandEncoder* cmdEncoder,
MVKDescriptorBinding& descBinding,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- std::vector<uint32_t>& dynamicOffsets,
+ MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex);
/** Encodes this binding layout and the specified descriptor binding on the specified command encoder immediately. */
@@ -131,7 +132,7 @@
void bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
MVKDescriptorSet* descSet,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- std::vector<uint32_t>& dynamicOffsets,
+ MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex);
@@ -165,7 +166,7 @@
friend class MVKPipelineLayout;
friend class MVKDescriptorSet;
- std::vector<MVKDescriptorSetLayoutBinding> _bindings;
+ MVKVector<MVKDescriptorSetLayoutBinding> _bindings;
std::unordered_map<uint32_t, uint32_t> _bindingToIndex;
MVKShaderResourceBinding _mtlResourceCounts;
bool _isPushDescriptorLayout : 1;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index d9bd60e..0cd71f3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -80,7 +80,7 @@
void MVKDescriptorSetLayoutBinding::bind(MVKCommandEncoder* cmdEncoder,
MVKDescriptorBinding& descBinding,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- vector<uint32_t>& dynamicOffsets,
+ MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
MVKMTLBufferBinding bb;
MVKMTLTextureBinding tb;
@@ -494,7 +494,7 @@
void MVKDescriptorSetLayout::bindDescriptorSet(MVKCommandEncoder* cmdEncoder,
MVKDescriptorSet* descSet,
MVKShaderResourceBinding& dslMTLRezIdxOffsets,
- vector<uint32_t>& dynamicOffsets,
+ MVKVector<uint32_t>& dynamicOffsets,
uint32_t* pDynamicOffsetIndex) {
if (_isPushDescriptorLayout) return;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 3e3f246..4761825 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -22,6 +22,7 @@
#include "MVKDescriptorSet.h"
#include "MVKShaderModule.h"
#include "MVKSync.h"
+#include "MVKVector.h"
#include <MoltenVKSPIRVToMSLConverter/SPIRVToMSLConverter.h>
#include <unordered_set>
#include <vector>
@@ -53,9 +54,9 @@
/** Binds descriptor sets to a command encoder. */
void bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
- std::vector<MVKDescriptorSet*>& descriptorSets,
+ MVKVector<MVKDescriptorSet*>& descriptorSets,
uint32_t firstSet,
- std::vector<uint32_t>& dynamicOffsets);
+ MVKVector<uint32_t>& dynamicOffsets);
/** Populates the specified shader converter context. */
void populateShaderConverterContext(SPIRVToMSLConverterContext& context);
@@ -157,8 +158,8 @@
VkPipelineRasterizationStateCreateInfo _rasterInfo;
VkPipelineDepthStencilStateCreateInfo _depthStencilInfo;
- std::vector<MTLViewport> _mtlViewports;
- std::vector<MTLScissorRect> _mtlScissors;
+ MVKVector<MTLViewport> _mtlViewports;
+ MVKVector<MTLScissorRect> _mtlScissors;
id<MTLRenderPipelineState> _mtlPipelineState;
MTLCullMode _mtlCullMode;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 271f5a5..74c496b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -36,9 +36,9 @@
#pragma mark MVKPipelineLayout
void MVKPipelineLayout::bindDescriptorSets(MVKCommandEncoder* cmdEncoder,
- vector<MVKDescriptorSet*>& descriptorSets,
+ MVKVector<MVKDescriptorSet*>& descriptorSets,
uint32_t firstSet,
- vector<uint32_t>& dynamicOffsets) {
+ MVKVector<uint32_t>& dynamicOffsets) {
uint32_t pDynamicOffsetIndex = 0;
uint32_t dsCnt = (uint32_t)descriptorSets.size();
@@ -342,7 +342,11 @@
}
}
- // Fragment shader - only add if rasterization is enabled
+ // bug fix by aerofly -> if no fragment shader is used and _needsFragmentAuxBuffer was true newBufferWithLength was trying to allocate zero bytes
+ // please verify this fix
+ _needsFragmentAuxBuffer = false;
+
+ // Fragment shader - only add if rasterization is enabled
for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
const VkPipelineShaderStageCreateInfo* pSS = &pCreateInfo->pStages[i];
if (mvkAreFlagsEnabled(pSS->stage, VK_SHADER_STAGE_FRAGMENT_BIT) && !shaderContext.options.isRasterizationDisabled) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
index c27d7d2..d3e6a2f 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
@@ -22,6 +22,7 @@
#include "MVKCommandBuffer.h"
#include "MVKImage.h"
#include "MVKSync.h"
+#include "MVKVector.h"
#include <vector>
#include <mutex>
@@ -169,7 +170,7 @@
MVKQueueSubmission* _prev;
MVKQueueSubmission* _next;
VkResult _submissionResult;
- std::vector<MVKSemaphore*> _waitSemaphores;
+ MVKVector<MVKSemaphore*> _waitSemaphores;
bool _isAwaitingSemaphores;
};
@@ -204,8 +205,8 @@
void commitActiveMTLCommandBuffer(bool signalCompletion = false);
void finish();
- std::vector<MVKCommandBuffer*> _cmdBuffers;
- std::vector<MVKSemaphore*> _signalSemaphores;
+ MVKVector<MVKCommandBuffer*> _cmdBuffers;
+ MVKVector<MVKSemaphore*> _signalSemaphores;
MVKFence* _fence;
MVKCommandUse _cmdBuffUse;
id<MTLCommandBuffer> _activeMTLCommandBuffer;
@@ -227,6 +228,6 @@
const VkPresentInfoKHR* pPresentInfo);
protected:
- std::vector<MVKSwapchainImage*> _surfaceImages;
+ MVKVector<MVKSwapchainImage*> _surfaceImages;
};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
index 7449550..34cbea6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.h
@@ -19,6 +19,7 @@
#pragma once
#include "MVKDevice.h"
+#include "MVKVector.h"
#include <vector>
#import <Metal/Metal.h>
@@ -56,7 +57,7 @@
*/
void populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
MVKFramebuffer* framebuffer,
- std::vector<VkClearValue>& clearValues,
+ MVKVector<VkClearValue>& clearValues,
bool isRenderingEntireAttachment);
/**
@@ -64,7 +65,7 @@
* when the render area is smaller than the full framebuffer size.
*/
void populateClearAttachments(std::vector<VkClearAttachment>& clearAtts,
- std::vector<VkClearValue>& clearValues);
+ MVKVector<VkClearValue>& clearValues);
/** Constructs an instance for the specified parent renderpass. */
MVKRenderSubpass(MVKRenderPass* renderPass, const VkSubpassDescription* pCreateInfo);
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
index 0a63201..b695ba5 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKRenderPass.mm
@@ -67,7 +67,7 @@
void MVKRenderSubpass::populateMTLRenderPassDescriptor(MTLRenderPassDescriptor* mtlRPDesc,
MVKFramebuffer* framebuffer,
- vector<VkClearValue>& clearValues,
+ MVKVector<VkClearValue>& clearValues,
bool isRenderingEntireAttachment) {
// Populate the Metal color attachments
uint32_t caCnt = getColorAttachmentCount();
@@ -157,7 +157,7 @@
}
void MVKRenderSubpass::populateClearAttachments(vector<VkClearAttachment>& clearAtts,
- vector<VkClearValue>& clearValues) {
+ MVKVector<VkClearValue>& clearValues) {
VkClearAttachment cAtt;
uint32_t attIdx;
diff --git a/MoltenVK/MoltenVK/Utility/MVKVector.h b/MoltenVK/MoltenVK/Utility/MVKVector.h
new file mode 100755
index 0000000..df0b8a9
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKVector.h
@@ -0,0 +1,528 @@
+/*
+ * MVKVectorAllocator.h
+ *
+ * Copyright (c) 2012-2018 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 MVKVector should use std::vector
+//
+#if 0
+
+template<typename T>
+using MVKVector = std::vector<T>;
+
+#else
+
+//
+// a simple std::vector like container with a configurable extra stack space
+// this class supports just the necessary members to be compatible with MoltenVK
+// if C++17 is used, code can be simplified further
+// by default MVKVector used 8 elements from the stack before getting memory from heap
+//
+#include "MVKVectorAllocator.h"
+#include <type_traits>
+#include <initializer_list>
+#include <utility>
+
+template<class Type, class Allocator = mvk_vector_allocator_with_stack<Type, 8>> class MVKVector
+{
+ Allocator alc;
+
+public:
+ class iterator
+ {
+ const MVKVector *vector;
+ size_t index;
+
+ public:
+ iterator() = delete;
+ iterator( const size_t _index, const MVKVector &_vector ) : vector{ &_vector }, index{ _index } { }
+
+ iterator &operator=( const iterator &it )
+ {
+ vector = it.vector;
+ index = it.index;
+ return *this;
+ }
+
+ Type *operator->() const
+ {
+ return &vector->alc.ptr[index];
+ }
+
+ Type &operator*() const
+ {
+ return vector->alc.ptr[index];
+ }
+
+ operator Type*() const
+ {
+ 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; }
+
+ bool is_valid() const { return index < vector->alc.num_elements_used; }
+ size_t get_position() const { return index; }
+ };
+
+ class reverse_iterator
+ {
+ const MVKVector *vector;
+ size_t index;
+
+ public:
+ reverse_iterator() = delete;
+ reverse_iterator( const size_t _index, const MVKVector &_vector ) : vector{ &_vector }, index{ _index } { }
+ reverse_iterator &operator=( const reverse_iterator & ) = delete;
+
+ Type *operator->() const
+ {
+ return &vector->alc.ptr[index];
+ }
+
+ Type &operator*() const
+ {
+ return vector->alc.ptr[index];
+ }
+
+ operator Type*() const
+ {
+ return &vector->alc.ptr[index];
+ }
+
+ bool operator==( const reverse_iterator &it ) const
+ {
+ return vector == it.vector && index == it.index;
+ }
+
+ bool operator!=( const reverse_iterator &it ) const
+ {
+ return vector != it.vector || index != it.index;
+ }
+
+ reverse_iterator& operator++() { --index; return *this; }
+
+ bool is_valid() const { return index < vector->alc.num_elements_used; }
+ size_t get_position() const { return index; }
+ };
+
+private:
+ 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();
+ //if( current_capacity < 256 )
+ // return MINIMUM_CAPACITY + 2 * current_capacity;
+ return MINIMUM_CAPACITY + ( 3 * current_capacity ) / 2;
+ }
+
+ void vector_Allocate( const size_t s )
+ {
+ const auto new_reserved_size = tm_max( s, alc.num_elements_used );
+
+ alc.allocate( new_reserved_size );
+ }
+
+ void vector_ReAllocate( const size_t s )
+ {
+ alc.re_allocate( s );
+ }
+
+public:
+ MVKVector()
+ {
+ }
+
+ MVKVector( 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;
+ }
+ }
+
+ MVKVector( const MVKVector &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;
+ }
+ }
+
+ MVKVector( MVKVector &&a ) : alc{ std::move( a.alc ) }
+ {
+ }
+
+ MVKVector( 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;
+ }
+ }
+
+ ~MVKVector()
+ {
+ }
+
+ MVKVector& operator=( const MVKVector &a )
+ {
+ if( this != &a )
+ {
+ const auto n = a.alc.num_elements_used;
+
+ 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.alc.ptr[i] );
+ }
+
+ alc.num_elements_used = n;
+ }
+ }
+
+ return *this;
+ }
+
+ MVKVector& operator=( MVKVector &&a )
+ {
+ alc.swap( a.alc );
+ return *this;
+ }
+
+ bool operator==( const MVKVector &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.ptr[i] != a.alc.ptr[i] )
+ return false;
+ }
+ return true;
+ }
+
+ bool operator!=( const MVKVector &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.ptr[i] )
+ return true;
+ }
+ return false;
+ }
+
+ void swap( MVKVector &a )
+ {
+ alc.swap( a.alc );
+ }
+
+ void clear()
+ {
+ alc.template destruct_all<Type>();
+ }
+
+ void reset()
+ {
+ alc.deallocate();
+ }
+
+ iterator begin() const { return iterator( 0, *this ); }
+ iterator end() const { return iterator( alc.num_elements_used, *this ); }
+ reverse_iterator rbegin() const { return reverse_iterator( alc.num_elements_used - 1, *this ); }
+ reverse_iterator rend() const { return reverse_iterator( size_t( -1 ), *this ); }
+ size_t size() const { return alc.num_elements_used; }
+ bool empty() const { return alc.num_elements_used == 0; }
+
+ Type &at( const size_t i ) const
+ {
+ return alc.ptr[i];
+ }
+
+ const Type &operator[]( const size_t i ) const
+ {
+ return alc.ptr[i];
+ }
+
+ Type &operator[]( const size_t i )
+ {
+ return alc.ptr[i];
+ }
+
+ const Type *data() const
+ {
+ return alc.ptr;
+ }
+
+ Type *data()
+ {
+ return alc.ptr;
+ }
+
+ size_t capacity() const
+ {
+ return alc.get_capacity();
+ }
+
+ const Type &front() const
+ {
+ return alc.ptr[0];
+ }
+
+ Type &front()
+ {
+ return alc.ptr[0];
+ }
+
+ const Type &back() const
+ {
+ return alc.ptr[alc.num_elements_used - 1];
+ }
+
+ Type &back()
+ {
+ return alc.ptr[alc.num_elements_used - 1];
+ }
+
+ void pop_back()
+ {
+ if( alc.num_elements_used > 0 )
+ {
+ --alc.num_elements_used;
+ alc.destruct( &alc.ptr[alc.num_elements_used] );
+ }
+ }
+
+ 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.GetIndex(); 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] );
+ }
+ }
+
+ // 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];
+ }
+};
+
+#endif
+
diff --git a/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
new file mode 100755
index 0000000..442e0ac
--- /dev/null
+++ b/MoltenVK/MoltenVK/Utility/MVKVectorAllocator.h
@@ -0,0 +1,526 @@
+/*
+ * MVKVectorAllocator.h
+ *
+ * Copyright (c) 2012-2018 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_memory_allocator
+{
+ inline char *alloc( const size_t num_bytes )
+ {
+ return new char[num_bytes];
+ }
+
+ inline void free( void *ptr )
+ {
+ delete[] (char*)ptr;
+ }
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//
+// mvk_vector_allocator_default -> malloc based allocator for MVKVector
+//
+//////////////////////////////////////////////////////////////////////////////////////////
+template <typename T>
+class mvk_vector_allocator_default final
+{
+public:
+ T *ptr;
+ size_t num_elements_used;
+
+private:
+ size_t num_elements_reserved;
+
+public:
+ template<class S, class... Args> typename std::enable_if< !std::is_trivially_constructible<S>::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>::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;
+ }
+
+public:
+ constexpr mvk_vector_allocator_default() : ptr{ nullptr }, num_elements_used{ 0 }, num_elements_reserved{ 0 }
+ {
+ }
+
+ mvk_vector_allocator_default( mvk_vector_allocator_default &&a ) : ptr{ a.ptr }, num_elements_used{ a.num_elements_used }, num_elements_reserved{ a.num_elements_reserved }
+ {
+ a.ptr = nullptr;
+ a.num_elements_used = 0;
+ a.num_elements_reserved = 0;
+ }
+
+ ~mvk_vector_allocator_default()
+ {
+ deallocate();
+ }
+
+ size_t get_capacity() const
+ {
+ return num_elements_reserved;
+ }
+
+ void swap( mvk_vector_allocator_default &a )
+ {
+ const auto copy_ptr = a.ptr;
+ const auto copy_num_elements_used = a.num_elements_used;
+ const auto copy_num_elements_reserved = a.num_elements_reserved;
+
+ a.ptr = ptr;
+ a.num_elements_used = num_elements_used;
+ a.num_elements_reserved = num_elements_reserved;
+
+ ptr = copy_ptr;
+ num_elements_used = copy_num_elements_used;
+ num_elements_reserved = copy_num_elements_reserved;
+ }
+
+ void allocate( const size_t num_elements_to_reserve )
+ {
+ deallocate();
+
+ ptr = reinterpret_cast< T* >( mvk_memory_allocator::alloc( num_elements_to_reserve * sizeof( T ) ) );
+ num_elements_used = 0;
+ num_elements_reserved = num_elements_to_reserve;
+ }
+
+ void re_allocate( const size_t num_elements_to_reserve )
+ {
+ //if constexpr( std::is_trivially_copyable<T>::value )
+ //{
+ // ptr = reinterpret_cast< T* >( mvk_memory_allocator::tm_memrealloc( ptr, num_elements_to_reserve * sizeof( T ) );
+ //}
+ //else
+ {
+ auto *new_ptr = reinterpret_cast< T* >( mvk_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 != nullptr )
+ {
+ mvk_memory_allocator::free( ptr );
+ }
+
+ ptr = new_ptr;
+ }
+
+ num_elements_reserved = num_elements_to_reserve;
+ }
+
+ void shrink_to_fit()
+ {
+ if( num_elements_used == 0 )
+ {
+ deallocate();
+ }
+ else
+ {
+ auto *new_ptr = reinterpret_cast< T* >( mvk_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_memory_allocator::free( ptr );
+
+ ptr = new_ptr;
+ num_elements_reserved = num_elements_used;
+ }
+ }
+
+ void deallocate()
+ {
+ destruct_all<T>();
+
+ mvk_memory_allocator::free( ptr );
+
+ ptr = nullptr;
+ num_elements_reserved = 0;
+ }
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//
+// mvk_vector_allocator_with_stack -> malloc based MVKVector allocator with stack storage
+//
+//////////////////////////////////////////////////////////////////////////////////////////
+template <typename T, int N>
+class mvk_vector_allocator_with_stack
+{
+public:
+ T *ptr;
+ size_t num_elements_used;
+
+private:
+ //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" );
+
+ void set_num_elements_reserved( const size_t num_elements_reserved )
+ {
+ *reinterpret_cast< size_t* >( &elements_stack[0] ) = num_elements_reserved;
+ }
+
+
+public:
+ //
+ // 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_vector_allocator_with_stack &a )
+ {
+ T stack_copy[N];
+
+ for( size_t i = 0; i < num_elements_used; ++i )
+ {
+ construct( &stack_copy[i], std::move( 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_vector_allocator_with_stack &a )
+ {
+ constexpr int STACK_SIZE = N * sizeof( T );
+ 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_vector_allocator_with_stack() : ptr{ reinterpret_cast< T* >( &elements_stack[0] ) }, num_elements_used{ 0 }
+ {
+ }
+
+ mvk_vector_allocator_with_stack( mvk_vector_allocator_with_stack &&a ) : num_elements_used{ a.num_elements_used }
+ {
+ // 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] );
+ }
+ }
+
+ a.num_elements_used = 0;
+ }
+
+ ~mvk_vector_allocator_with_stack()
+ {
+ 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_vector_allocator_with_stack &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_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_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_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_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_memory_allocator::free( ptr );
+
+ ptr = stack_ptr;
+ }
+ else
+ {
+ auto *new_ptr = reinterpret_cast< T* >( mvk_memory_allocator::alloc( ptr, 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_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_memory_allocator::free( ptr );
+ }
+
+ ptr = get_default_ptr();
+ num_elements_used = 0;
+ }
+};
+
+