Skip to content

Commit

Permalink
MVKCommandBuffer: Optimize management of command storage.
Browse files Browse the repository at this point in the history
The main motivation behind this commit is to reduce the time needed to free or
reset a command buffer. With the current scheme, we need to loop over all
recorded commands and return them to their pools. This can take a significant
amount of time in games, of the order of a millisecond.

With this change, instead of pooling individual commands by their type, we
instead keep chunks of memory in each command buffer, from which we bump
allocate memory for the commands to be recorded. MVKCommandVector is introduced
to use the same memory pool for dynamic arrays of data associated with the
commands.

Pointers to commands that actually have non-trivial destructors (i.e. they keep
references to other objects) are stored separately, so that we can call their
destructors when reseting the command buffer. All the memory simply gets
discarded by setting the current chunk's index and offset to zero.

As a side note, specific applications might opt to not retain pipeline layouts
in bind/push descriptor commands (introduced by
30113fc) if it's known not to be needed, to
further reduce time spent resetting command buffers.
  • Loading branch information
js6i committed Sep 16, 2022
1 parent 250e1f9 commit daf1323
Show file tree
Hide file tree
Showing 21 changed files with 346 additions and 866 deletions.
2 changes: 0 additions & 2 deletions MoltenVK/MoltenVK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,6 @@
A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKOSExtensions.mm; sourceTree = "<group>"; };
A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKOSExtensions.h; sourceTree = "<group>"; };
A9B8EE0A1A98D796009C5A02 /* libMoltenVK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVK.a; sourceTree = BUILT_PRODUCTS_DIR; };
A9C83DCD24533E22003E5261 /* MVKCommandTypePools.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKCommandTypePools.def; sourceTree = "<group>"; };
A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MoltenVKShaderConverter.xcodeproj; path = ../MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj; sourceTree = "<group>"; };
A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKMTLBufferAllocation.h; sourceTree = "<group>"; };
A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKMTLBufferAllocation.mm; sourceTree = "<group>"; };
Expand Down Expand Up @@ -605,7 +604,6 @@
A94FB77B1C7DFB4800632CA3 /* MVKCommandPool.mm */,
A95870F61C90D29F009EB096 /* MVKCommandResourceFactory.h */,
A95870F71C90D29F009EB096 /* MVKCommandResourceFactory.mm */,
A9C83DCD24533E22003E5261 /* MVKCommandTypePools.def */,
A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */,
A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */,
A9E4B7881E1D8AF10046A4CE /* MVKMTLResourceBindings.h */,
Expand Down
12 changes: 0 additions & 12 deletions MoltenVK/MoltenVK/Commands/MVKCmdDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ class MVKCmdDebugMarkerBegin : public MVKCmdDebugMarker {

public:
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

};


Expand All @@ -64,10 +60,6 @@ class MVKCmdDebugMarkerEnd : public MVKCommand {
VkResult setContent(MVKCommandBuffer* cmdBuff);

void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

};


Expand All @@ -79,10 +71,6 @@ class MVKCmdDebugMarkerInsert : public MVKCmdDebugMarker {

public:
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

};


Expand Down
2 changes: 1 addition & 1 deletion MoltenVK/MoltenVK/Commands/MVKCmdDebug.mm
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
const float color[4]) {
[_markerName release];
_markerName = [[NSString alloc] initWithUTF8String: pMarkerName]; // retained

cmdBuff->destroyList.push_back(this);
return VK_SUCCESS;
}

Expand Down
6 changes: 1 addition & 5 deletions MoltenVK/MoltenVK/Commands/MVKCmdDispatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ class MVKCmdDispatch : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

uint32_t _baseGroupX;
uint32_t _baseGroupX;
uint32_t _baseGroupY;
uint32_t _baseGroupZ;
uint32_t _groupCountX;
Expand All @@ -60,8 +58,6 @@ class MVKCmdDispatchIndirect : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

id<MTLBuffer> _mtlIndirectBuffer;
VkDeviceSize _mtlIndirectBufferOffset;
};
Expand Down
21 changes: 1 addition & 20 deletions MoltenVK/MoltenVK/Commands/MVKCmdDraw.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@

/**
* Vulkan command to bind buffers containing vertex content.
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
class MVKCmdBindVertexBuffers : public MVKCommand {

public:
Expand All @@ -45,16 +43,9 @@ class MVKCmdBindVertexBuffers : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

MVKSmallVector<MVKMTLBufferBinding, N> _bindings;
MVKCommandVector<MVKMTLBufferBinding> _bindings;
};

// Concrete template class implementations.
typedef MVKCmdBindVertexBuffers<1> MVKCmdBindVertexBuffers1;
typedef MVKCmdBindVertexBuffers<2> MVKCmdBindVertexBuffers2;
typedef MVKCmdBindVertexBuffers<8> MVKCmdBindVertexBuffersMulti;


#pragma mark -
#pragma mark MVKCmdBindIndexBuffer
Expand All @@ -71,8 +62,6 @@ class MVKCmdBindIndexBuffer : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

MVKIndexMTLBufferBinding _binding;
};

Expand All @@ -93,8 +82,6 @@ class MVKCmdDraw : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

uint32_t _firstVertex;
uint32_t _vertexCount;
uint32_t _firstInstance;
Expand All @@ -119,8 +106,6 @@ class MVKCmdDrawIndexed : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

uint32_t _firstIndex;
uint32_t _indexCount;
int32_t _vertexOffset;
Expand All @@ -145,8 +130,6 @@ class MVKCmdDrawIndirect : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

id<MTLBuffer> _mtlIndirectBuffer;
VkDeviceSize _mtlIndirectBufferOffset;
uint32_t _mtlIndirectBufferStride;
Expand All @@ -170,8 +153,6 @@ class MVKCmdDrawIndexedIndirect : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

id<MTLBuffer> _mtlIndirectBuffer;
VkDeviceSize _mtlIndirectBufferOffset;
uint32_t _mtlIndirectBufferStride;
Expand Down
11 changes: 3 additions & 8 deletions MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@
#pragma mark -
#pragma mark MVKCmdBindVertexBuffers

template <size_t N>
VkResult MVKCmdBindVertexBuffers<N>::setContent(MVKCommandBuffer* cmdBuff,
VkResult MVKCmdBindVertexBuffers::setContent(MVKCommandBuffer* cmdBuff,
uint32_t startBinding,
uint32_t bindingCount,
const VkBuffer* pBuffers,
const VkDeviceSize* pOffsets) {

MVKDevice* mvkDvc = cmdBuff->getDevice();
_bindings.alc.cmdBuffer = cmdBuff;
_bindings.clear(); // Clear for reuse
_bindings.reserve(bindingCount);
MVKMTLBufferBinding b;
Expand All @@ -50,15 +50,10 @@
return VK_SUCCESS;
}

template <size_t N>
void MVKCmdBindVertexBuffers<N>::encode(MVKCommandEncoder* cmdEncoder) {
void MVKCmdBindVertexBuffers::encode(MVKCommandEncoder* cmdEncoder) {
for (auto& b : _bindings) { cmdEncoder->_graphicsResourcesState.bindBuffer(kMVKShaderStageVertex, b); }
}

template class MVKCmdBindVertexBuffers<1>;
template class MVKCmdBindVertexBuffers<2>;
template class MVKCmdBindVertexBuffers<8>;


#pragma mark -
#pragma mark MVKCmdBindIndexBuffer
Expand Down
76 changes: 7 additions & 69 deletions MoltenVK/MoltenVK/Commands/MVKCmdPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ class MVKDescriptorUpdateTemplate;

/**
* Vulkan command to add a pipeline barrier.
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
class MVKCmdPipelineBarrier : public MVKCommand {

public:
Expand All @@ -55,20 +53,14 @@ class MVKCmdPipelineBarrier : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
bool coversTextures();

MVKSmallVector<MVKPipelineBarrier, N> _barriers;
MVKCommandVector<MVKPipelineBarrier> _barriers;
VkPipelineStageFlags _srcStageMask;
VkPipelineStageFlags _dstStageMask;
VkDependencyFlags _dependencyFlags;
};

// Concrete template class implementations.
typedef MVKCmdPipelineBarrier<1> MVKCmdPipelineBarrier1;
typedef MVKCmdPipelineBarrier<4> MVKCmdPipelineBarrier4;
typedef MVKCmdPipelineBarrier<32> MVKCmdPipelineBarrierMulti;


#pragma mark -
#pragma mark MVKCmdBindPipeline
Expand Down Expand Up @@ -97,10 +89,6 @@ class MVKCmdBindGraphicsPipeline : public MVKCmdBindPipeline {
void encode(MVKCommandEncoder* cmdEncoder) override;

bool isTessellationPipeline() override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

};


Expand All @@ -112,10 +100,6 @@ class MVKCmdBindComputePipeline : public MVKCmdBindPipeline {

public:
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

};


Expand All @@ -124,9 +108,7 @@ class MVKCmdBindComputePipeline : public MVKCmdBindPipeline {

/**
* Vulkan command to bind descriptor sets without dynamic offsets.
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
class MVKCmdBindDescriptorSetsStatic : public MVKCommand {

public:
Expand All @@ -142,30 +124,22 @@ class MVKCmdBindDescriptorSetsStatic : public MVKCommand {
~MVKCmdBindDescriptorSetsStatic() override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
void encode(MVKCommandEncoder* cmdEncoder, MVKArrayRef<uint32_t> dynamicOffsets);

MVKSmallVector<MVKDescriptorSet*, N> _descriptorSets;
MVKCommandVector<MVKDescriptorSet*> _descriptorSets;
MVKPipelineLayout* _pipelineLayout = nullptr;
VkPipelineBindPoint _pipelineBindPoint;
uint32_t _firstSet;
};

// Concrete template class implementations.
typedef MVKCmdBindDescriptorSetsStatic<1> MVKCmdBindDescriptorSetsStatic1;
typedef MVKCmdBindDescriptorSetsStatic<4> MVKCmdBindDescriptorSetsStatic4;
typedef MVKCmdBindDescriptorSetsStatic<8> MVKCmdBindDescriptorSetsStaticMulti;


#pragma mark -
#pragma mark MVKCmdBindDescriptorSetsDynamic

/**
* Vulkan command to bind descriptor sets with dynamic offsets.
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
class MVKCmdBindDescriptorSetsDynamic : public MVKCmdBindDescriptorSetsStatic<N> {
class MVKCmdBindDescriptorSetsDynamic : public MVKCmdBindDescriptorSetsStatic {

public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
Expand All @@ -180,24 +154,16 @@ class MVKCmdBindDescriptorSetsDynamic : public MVKCmdBindDescriptorSetsStatic<N>
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

MVKSmallVector<uint32_t, N> _dynamicOffsets;
MVKCommandVector<uint32_t> _dynamicOffsets;
};

// Concrete template class implementations.
typedef MVKCmdBindDescriptorSetsDynamic<4> MVKCmdBindDescriptorSetsDynamic4;
typedef MVKCmdBindDescriptorSetsDynamic<8> MVKCmdBindDescriptorSetsDynamicMulti;


#pragma mark -
#pragma mark MVKCmdPushConstants

/**
* Vulkan command to bind push constants.
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
class MVKCmdPushConstants : public MVKCommand {

public:
Expand All @@ -211,19 +177,11 @@ class MVKCmdPushConstants : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

MVKSmallVector<char, N> _pushConstants;
MVKCommandVector<char> _pushConstants;
VkShaderStageFlags _stageFlags;
uint32_t _offset;
};

// Concrete template class implementations.
typedef MVKCmdPushConstants<64> MVKCmdPushConstants64;
typedef MVKCmdPushConstants<128> MVKCmdPushConstants128;
typedef MVKCmdPushConstants<512> MVKCmdPushConstantsMulti;


#pragma mark -
#pragma mark MVKCmdPushDescriptorSet

Expand All @@ -243,10 +201,9 @@ class MVKCmdPushDescriptorSet : public MVKCommand {
~MVKCmdPushDescriptorSet() override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;
void clearDescriptorWrites();

MVKSmallVector<VkWriteDescriptorSet, 1> _descriptorWrites;
MVKCommandVector<VkWriteDescriptorSet> _descriptorWrites;
MVKPipelineLayout* _pipelineLayout = nullptr;
VkPipelineBindPoint _pipelineBindPoint;
uint32_t _set;
Expand All @@ -271,8 +228,6 @@ class MVKCmdPushDescriptorSetWithTemplate : public MVKCommand {
~MVKCmdPushDescriptorSetWithTemplate() override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

MVKDescriptorUpdateTemplate* _descUpdateTemplate;
MVKPipelineLayout* _pipelineLayout = nullptr;
void* _pData = nullptr;
Expand Down Expand Up @@ -305,10 +260,6 @@ class MVKCmdSetEvent : public MVKCmdSetResetEvent {

public:
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

};


Expand All @@ -320,10 +271,6 @@ class MVKCmdResetEvent : public MVKCmdSetResetEvent {

public:
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

};


Expand All @@ -333,9 +280,7 @@ class MVKCmdResetEvent : public MVKCmdSetResetEvent {
/** Vulkan command to wait for an event to be signaled. */
/**
* Vulkan command to wait for an event to be signaled.
* Template class to balance vector pre-allocations between very common low counts and fewer larger counts.
*/
template <size_t N>
class MVKCmdWaitEvents : public MVKCommand {

public:
Expand All @@ -354,12 +299,5 @@ class MVKCmdWaitEvents : public MVKCommand {
void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

MVKSmallVector<MVKEvent*, N> _mvkEvents;

MVKCommandVector<MVKEvent*> _mvkEvents;
};

// Concrete template class implementations.
typedef MVKCmdWaitEvents<1> MVKCmdWaitEvents1;
typedef MVKCmdWaitEvents<8> MVKCmdWaitEventsMulti;
Loading

0 comments on commit daf1323

Please sign in to comment.