Allow queue processing to be optionally handled on the submitting (render) thread.

Add MVKDeviceConfiguration::synchronousQueueSubmits configuration setting.
Update to latest SPRIV-Cross version to fix atomic_compare issue.
Update MoltenVK version to 1.0.8.
diff --git a/ExternalRevisions/SPIRV-Cross_repo_revision b/ExternalRevisions/SPIRV-Cross_repo_revision
index e8c521d..72c98fa 100644
--- a/ExternalRevisions/SPIRV-Cross_repo_revision
+++ b/ExternalRevisions/SPIRV-Cross_repo_revision
@@ -1 +1 @@
-c74dc4578a1cd2138f98ec22b63d3b39b2de7456
+f929c361c55b931f9eaa5c5396ee33585cf23796
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index 140f1e0..aa5a207 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -48,7 +48,7 @@
  */
 #define MVK_VERSION_MAJOR   1
 #define MVK_VERSION_MINOR   0
-#define MVK_VERSION_PATCH   7
+#define MVK_VERSION_PATCH   8
 
 #define MVK_MAKE_VERSION(major, minor, patch)    (((major) * 10000) + ((minor) * 100) + (patch))
 #define MVK_VERSION     MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH)
@@ -67,7 +67,8 @@
 typedef struct {
     VkBool32 debugMode;                     /**< If enabled, several debugging capabilities will be enabled. Shader code will be logged during Runtime Shader Conversion. Adjusts settings that might trigger Metal validation but are otherwise acceptable to Metal runtime. Improves support for Xcode GPU Frame Capture. Default value is true in the presence of the DEBUG build setting, and false otherwise. */
     VkBool32 shaderConversionFlipVertexY;   /**< If enabled, MSL vertex shader code created during Runtime Shader Conversion will flip the Y-axis of each vertex, as Vulkan coordinate system is inverse of OpenGL. Default is true. */
-    VkBool32 supportLargeQueryPools;        /**< Metal allows only 8192 occlusion queries per MTLBuffer. If enabled, MoltenVK allocates a MTLBuffer for each query pool, allowing each query pool to support 8192 queries, which may slow performance or cause unexpected behaviour if the query pool is not established prior to a Metal renderpass, or if the query pool is changed within a Metal renderpass. If disabled, one MTLBuffer will be shared by all query pools, which improves performance, but limits the total device queries to 8192. Default is true. */
+	VkBool32 synchronousQueueSubmits;       /**< If enabled, queue command submissions (vkQueueSubmit() & vkQueuePresentKHR()) will be processed on the thread that called the submission function. If disabled, processing will be dispatched to a GCD dispatch_queue whose priority is determined by VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). This setting affects how much command processing should be performed on the rendering thread, or offloaded to a secondary thread. Default value is false, and command processing will be handled on a prioritizable queue thread. */
+    VkBool32 supportLargeQueryPools;        /**< Metal allows only 8192 occlusion queries per MTLBuffer. If enabled, MoltenVK allocates a MTLBuffer for each query pool, allowing each query pool to support 8192 queries, which may slow performance or cause unexpected behaviour if the query pool is not established prior to a Metal renderpass, or if the query pool is changed within a Metal renderpass. If disabled, one MTLBuffer will be shared by all query pools, which improves performance, but limits the total device queries to 8192. Default value is true. */
 	VkBool32 presentWithCommandBuffer;      /**< If enabled, each surface presentation is scheduled using a command buffer. Enabling this may improve rendering frame synchronization, but may result in reduced frame rates. Default value is false if the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting is defined when MoltenVK is compiled, and true otherwise. By default the MVK_PRESENT_WITHOUT_COMMAND_BUFFER build setting is not defined and the value of this setting is true. */
     VkBool32 displayWatermark;              /**< If enabled, a MoltenVK logo watermark will be rendered on top of the scene. This can be enabled for publicity during demos. Default value is true if the MVK_DISPLAY_WATERMARK build setting is defined when MoltenVK is compiled, and false otherwise. By default the MVK_DISPLAY_WATERMARK build setting is not defined. */
     VkBool32 performanceTracking;           /**< If enabled, per-frame performance statistics are tracked, optionally logged, and can be retrieved via the vkGetSwapchainPerformanceMVK() function, and various performance statistics are tracked, logged, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. Default value is true in the presence of the DEBUG build setting, and false otherwise. */
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index d6f652b..4362999 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -1444,6 +1444,7 @@
     // Init const config. Use a pointer to bypass the const qualifier.
     MVKDeviceConfiguration* pCfg = (MVKDeviceConfiguration*)&_mvkConfig;
     pCfg->debugMode = MVK_DEBUG;
+	pCfg->synchronousQueueSubmits = false;
     pCfg->supportLargeQueryPools = true;
     pCfg->shaderConversionFlipVertexY = true;
 	pCfg->presentWithCommandBuffer = MVK_PRESENT_WITH_COMMAND_BUFFER_BOOL;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
index 090760e..04437e6 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm
@@ -60,14 +60,18 @@
 
 #pragma mark Queue submissions
 
-/**
- * Submits the specified submission object to the execution queue, wrapping each submission
- * in a dedicated autorelease pool. Relying on the dispatch queue to find time to drain the
- * autorelease pool can result in significant memory creep under heavy workloads.
- */
+// Executes the submmission, either immediately, or by dispatching to an execution queue.
+// Submissions to the execution queue are wrapped in a dedicated autorelease pool.
+// Relying on the dispatch queue to find time to drain the autorelease pool can
+// result in significant memory creep under heavy workloads.
 void MVKQueue::submit(MVKQueueSubmission* qSubmit) {
 	if ( !qSubmit ) { return; }     // Ignore nils
-	dispatch_async(_execQueue, ^{ @autoreleasepool { qSubmit->execute(); } } );
+
+	if (_execQueue) {
+		dispatch_async(_execQueue, ^{ @autoreleasepool { qSubmit->execute(); } } );
+	} else {
+		qSubmit->execute();
+	}
 }
 
 VkResult MVKQueue::submit(uint32_t submitCount, const VkSubmitInfo* pSubmits,
@@ -196,21 +200,25 @@
 	_nextMTLCmdBuffID = 1;
 }
 
-/** Creates and initializes the execution dispatch queue. */
+// Unless synchronous submission processing was configured,
+// creates and initializes the prioritized execution dispatch queue.
 void MVKQueue::initExecQueue() {
+	if (_device->_mvkConfig.synchronousQueueSubmits) {
+		_execQueue = nullptr;
+	} else {
+		// Create a name for the dispatch queue
+		const char* dqNameFmt = "MoltenVKDispatchQueue-%d-%d-%.1f";
+		char dqName[strlen(dqNameFmt) + 32];
+		sprintf(dqName, dqNameFmt, _queueFamily->getIndex(), _index, _priority);
 
-	// Create a name for the dispatch queue
-	const char* dqNameFmt = "MoltenVKDispatchQueue-%d-%d-%.1f";
-	char dqName[strlen(dqNameFmt) + 32];
-	sprintf(dqName, dqNameFmt, _queueFamily->getIndex(), _index, _priority);
+		// Determine the dispatch queue priority
+		dispatch_qos_class_t dqQOS = MVK_DISPATCH_QUEUE_QOS_CLASS;
+		int dqPriority = (1.0 - _priority) * QOS_MIN_RELATIVE_PRIORITY;
+		dispatch_queue_attr_t dqAttr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, dqQOS, dqPriority);
 
-	// Determine the dispatch queue priority
-	dispatch_qos_class_t dqQOS = MVK_DISPATCH_QUEUE_QOS_CLASS;
-	int dqPriority = (1.0 - _priority) * QOS_MIN_RELATIVE_PRIORITY;
-	dispatch_queue_attr_t dqAttr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, dqQOS, dqPriority);
-
-	// Create the dispatch queue
-	_execQueue = dispatch_queue_create(dqName, dqAttr);		// retained
+		// Create the dispatch queue
+		_execQueue = dispatch_queue_create(dqName, dqAttr);		// retained
+	}
 }
 
 /** Creates and initializes the Metal queue. */
@@ -234,9 +242,9 @@
 	destroyExecQueue();
 }
 
-/** Destroys the execution dispatch queue. */
+// Destroys the execution dispatch queue.
 void MVKQueue::destroyExecQueue() {
-	dispatch_release(_execQueue);
+	if (_execQueue) { dispatch_release(_execQueue); }
 }