Added optimized support for VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT when MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS is used
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
index 7a38e67..9ad5e61 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.h
@@ -166,7 +166,9 @@
 	bool canPrefill();
 	void prefill();
 	void clearPrefilledMTLCommandBuffer();
-	void releaseCommands();
+    void releaseCommands(MVKCommand* command);
+	void releaseRecordedCommands();
+    void flushImmediateCmdEncoder();
 
 	MVKCommand* _head = nullptr;
 	MVKCommand* _tail = nullptr;
@@ -175,6 +177,8 @@
 	std::atomic_flag _isExecutingNonConcurrently;
 	VkCommandBufferInheritanceInfo _secondaryInheritanceInfo;
 	id<MTLCommandBuffer> _prefilledMTLCmdBuffer = nil;
+    MVKCommandEncodingContext* _immediateCmdEncodingContext = nullptr;
+    MVKCommandEncoder* _immediateCmdEncoder = nullptr;
 	bool _isSecondary;
 	bool _doesContinueRenderPass;
 	bool _canAcceptCommands;
@@ -274,6 +278,10 @@
 
 	/** Encode commands from the command buffer onto the Metal command buffer. */
 	void encode(id<MTLCommandBuffer> mtlCmdBuff, MVKCommandEncodingContext* pEncodingContext);
+    
+    void beginEncoding(id<MTLCommandBuffer> mtlCmdBuff, MVKCommandEncodingContext* pEncodingContext);
+    void encodeCommands(MVKCommand* command);
+    void endEncoding();
 
 	/** Encode commands from the specified secondary command buffer onto the Metal command buffer. */
 	void encodeSecondary(MVKCommandBuffer* secondaryCmdBuffer);
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
index ac7124b..574cb98 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm
@@ -50,24 +50,51 @@
 	const VkCommandBufferInheritanceInfo* pInheritInfo = (_isSecondary ? pBeginInfo->pInheritanceInfo : NULL);
 	bool hasInheritInfo = mvkSetOrClear(&_secondaryInheritanceInfo, pInheritInfo);
 	_doesContinueRenderPass = mvkAreAllFlagsEnabled(usage, VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT) && hasInheritInfo;
-
-	return getConfigurationResult();
+    
+    if(canPrefill()) {
+        @autoreleasepool {
+            uint32_t qIdx = 0;
+            _prefilledMTLCmdBuffer = _commandPool->newMTLCommandBuffer(qIdx);    // retain
+            
+            _immediateCmdEncodingContext = new MVKCommandEncodingContext;
+            
+            _immediateCmdEncoder = new MVKCommandEncoder(this);
+            _immediateCmdEncoder->beginEncoding(_prefilledMTLCmdBuffer, _immediateCmdEncodingContext);
+        }
+    }
+    
+    return getConfigurationResult();
 }
 
-void MVKCommandBuffer::releaseCommands() {
-	MVKCommand* cmd = _head;
-	while (cmd) {
-		MVKCommand* nextCmd = cmd->_next;	// Establish next before returning current to pool.
-		(cmd->getTypePool(getCommandPool()))->returnObject(cmd);
-		cmd = nextCmd;
-	}
+void MVKCommandBuffer::releaseCommands(MVKCommand* command) {
+    while(command) {
+        MVKCommand* nextCommand = command->_next; // Establish next before returning current to pool.
+        (command->getTypePool(getCommandPool()))->returnObject(command);
+        command = nextCommand;
+    }
+}
+
+void MVKCommandBuffer::releaseRecordedCommands() {
+    releaseCommands(_head);
 	_head = nullptr;
 	_tail = nullptr;
 }
 
+void MVKCommandBuffer::flushImmediateCmdEncoder() {
+    if(_immediateCmdEncoder) {
+        _immediateCmdEncoder->endEncoding();
+        delete _immediateCmdEncoder;
+        _immediateCmdEncoder = nullptr;
+        
+        delete _immediateCmdEncodingContext;
+        _immediateCmdEncodingContext = nullptr;
+    }
+}
+
 VkResult MVKCommandBuffer::reset(VkCommandBufferResetFlags flags) {
+    flushImmediateCmdEncoder();
 	clearPrefilledMTLCommandBuffer();
-	releaseCommands();
+	releaseRecordedCommands();
 	_doesContinueRenderPass = false;
 	_canAcceptCommands = false;
 	_isReusable = false;
@@ -89,15 +116,26 @@
 
 VkResult MVKCommandBuffer::end() {
 	_canAcceptCommands = false;
-	prefill();
+    
+    flushImmediateCmdEncoder();
+    
 	return getConfigurationResult();
 }
 
 void MVKCommandBuffer::addCommand(MVKCommand* command) {
-	if ( !_canAcceptCommands ) {
-		setConfigurationResult(reportError(VK_NOT_READY, "Command buffer cannot accept commands before vkBeginCommandBuffer() is called."));
-		return;
-	}
+    if ( !_canAcceptCommands ) {
+        setConfigurationResult(reportError(VK_NOT_READY, "Command buffer cannot accept commands before vkBeginCommandBuffer() is called."));
+        return;
+    }
+    
+    if(_immediateCmdEncoder) {
+        _immediateCmdEncoder->encodeCommands(command);
+        
+        if( !_isReusable ) {
+            releaseCommands(command);
+            return;
+        }
+    }
 
     if (_tail) { _tail->_next = command; }
     command->_next = nullptr;
@@ -141,27 +179,6 @@
 	return true;
 }
 
-// If we can, prefill a MTLCommandBuffer with the commands in this command buffer.
-// Wrap in autorelease pool to capture autoreleased Metal encoding activity.
-void MVKCommandBuffer::prefill() {
-	@autoreleasepool {
-		clearPrefilledMTLCommandBuffer();
-
-		if ( !canPrefill() ) { return; }
-
-		uint32_t qIdx = 0;
-		_prefilledMTLCmdBuffer = _commandPool->newMTLCommandBuffer(qIdx);	// retain
-
-		MVKCommandEncodingContext encodingContext;
-		MVKCommandEncoder encoder(this);
-		encoder.encode(_prefilledMTLCmdBuffer, &encodingContext);
-
-		// Once encoded onto Metal, if this command buffer is not reusable, we don't need the
-		// MVKCommand instances anymore, so release them in order to reduce memory pressure.
-		if ( !_isReusable ) { releaseCommands(); }
-	}
-}
-
 bool MVKCommandBuffer::canPrefill() {
 	bool wantPrefill = _device->shouldPrefillMTLCommandBuffers();
 	return wantPrefill && !(_isSecondary || _supportsConcurrentExecution);
@@ -251,33 +268,44 @@
 
 void MVKCommandEncoder::encode(id<MTLCommandBuffer> mtlCmdBuff,
 							   MVKCommandEncodingContext* pEncodingContext) {
-	_framebuffer = nullptr;
-	_renderPass = nullptr;
-	_subpassContents = VK_SUBPASS_CONTENTS_INLINE;
-	_renderSubpassIndex = 0;
-	_multiviewPassIndex = 0;
-	_canUseLayeredRendering = false;
+    beginEncoding(mtlCmdBuff, pEncodingContext);
+    encodeCommands(_cmdBuffer->_head);
+    endEncoding();
+}
 
-	_pEncodingContext = pEncodingContext;
-	_mtlCmdBuffer = mtlCmdBuff;		// not retained
+void MVKCommandEncoder::beginEncoding(id<MTLCommandBuffer> mtlCmdBuff, MVKCommandEncodingContext* pEncodingContext) {
+    _framebuffer = nullptr;
+    _renderPass = nullptr;
+    _subpassContents = VK_SUBPASS_CONTENTS_INLINE;
+    _renderSubpassIndex = 0;
+    _multiviewPassIndex = 0;
+    _canUseLayeredRendering = false;
 
-	setLabelIfNotNil(_mtlCmdBuffer, _cmdBuffer->_debugName);
+    _pEncodingContext = pEncodingContext;
+    _mtlCmdBuffer = mtlCmdBuff;        // not retained
 
-	MVKCommand* cmd = _cmdBuffer->_head;
-	while (cmd) {
-		uint32_t prevMVPassIdx = _multiviewPassIndex;
-		cmd->encode(this);
-		if (_multiviewPassIndex > prevMVPassIdx) {
-			// This means we're in a multiview render pass, and we moved on to the
-			// next view group. Re-encode all commands in the subpass again for this group.
-			cmd = _lastMultiviewPassCmd->_next;
-		} else {
-			cmd = cmd->_next;
-		}
-	}
+    setLabelIfNotNil(_mtlCmdBuffer, _cmdBuffer->_debugName);
+}
 
-	endCurrentMetalEncoding();
-	finishQueries();
+void MVKCommandEncoder::encodeCommands(MVKCommand* command) {
+    while(command) {
+        uint32_t prevMVPassIdx = _multiviewPassIndex;
+        command->encode(this);
+        
+        if(_multiviewPassIndex > prevMVPassIdx) {
+            // This means we're in a multiview render pass, and we moved on to the
+            // next view group. Re-encode all commands in the subpass again for this group.
+            
+            command = _lastMultiviewPassCmd->_next;
+        } else {
+            command = command->_next;
+        }
+    }
+}
+
+void MVKCommandEncoder::endEncoding() {
+    endCurrentMetalEncoding();
+    finishQueries();
 }
 
 void MVKCommandEncoder::encodeSecondary(MVKCommandBuffer* secondaryCmdBuffer) {