Disable depth and/or stencil testing if corresponding attachment is missing.

MVKDepthStencilCommandEncoderState track whether depth and
stencil attachements exist, and modify testing accordingly.
Add MVKMTLDepthStencilDescriptorData::disable() function.
MoltenVK_Runtime_UserGuide.md remove VkEvent as known limitation.
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index e735323..8fc20af 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -512,8 +512,6 @@
   In order to use Vulkan layers such as the validation layers, use the Vulkan loader and layers from the
   [LunarG Vulkan SDK](https://vulkan.lunarg.com).
 
-- `VkEvents` are not supported.
-
 - Application-controlled memory allocations using `VkAllocationCallbacks` are ignored.
 
 - Pipeline statistics query pool using `VK_QUERY_TYPE_PIPELINE_STATISTICS` is not supported.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 6440f77..b47e4ac 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -23,6 +23,7 @@
 - Add support for `VkEvent`, using either native `MTLEvent` or emulation when `MTLEvent` not available.
 - `vkInvalidateMappedMemoryRanges()` synchronizes managed device memory to CPU.
 - Revert to supporting host-coherent memory for linear images on macOS.
+- Disable depth and/or stencil testing if corresponding attachment is missing.
 - Ensure Vulkan loader magic number is set every time before returning any dispatchable Vulkan handle.
 - Fix crash when `VkDeviceCreateInfo` specifies queue families out of numerical order.
 - Fix crash in `vkDestroyPipelineLayout()`.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 9af8197..7fd30e8 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -62,7 +62,7 @@
      * will be encoded to Metal, otherwise it is marked as clean, so the contents will NOT
      * be encoded. Default state can be left unencoded on a new Metal encoder.
      */
-    void beginMetalRenderPass() { if (_isModified) { markDirty(); } }
+	virtual void beginMetalRenderPass() { if (_isModified) { markDirty(); } }
 
     /**
      * If the content of this instance is dirty, marks this instance as no longer dirty
@@ -237,6 +237,8 @@
      */
     void setStencilWriteMask(VkStencilFaceFlags faceMask, uint32_t stencilWriteMask);
 
+	void beginMetalRenderPass() override;
+
     /** Constructs this instance for the specified command encoder. */
     MVKDepthStencilCommandEncoderState(MVKCommandEncoder* cmdEncoder)
         : MVKCommandEncoderState(cmdEncoder) {}
@@ -248,7 +250,9 @@
                          const VkStencilOpState& vkStencil,
                          bool enabled);
 
-    MVKMTLDepthStencilDescriptorData _depthStencilData;
+    MVKMTLDepthStencilDescriptorData _depthStencilData = kMVKMTLDepthStencilDescriptorDataDefault;
+	bool _hasDepthAttachment = false;
+	bool _hasStencilAttachment = false;
 };
 
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index 641832e..4d44d4c 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -312,26 +312,43 @@
     markDirty();
 }
 
+void MVKDepthStencilCommandEncoderState::beginMetalRenderPass() {
+	MVKRenderSubpass* mvkSubpass = _cmdEncoder->getSubpass();
+	MTLPixelFormat mtlDSFormat = _cmdEncoder->getMTLPixelFormatFromVkFormat(mvkSubpass->getDepthStencilFormat());
+
+	bool prevHasDepthAttachment = _hasDepthAttachment;
+	_hasDepthAttachment = mvkMTLPixelFormatIsDepthFormat(mtlDSFormat);
+	if (_hasDepthAttachment != prevHasDepthAttachment) { markDirty(); }
+
+	bool prevHasStencilAttachment = _hasStencilAttachment;
+	_hasStencilAttachment = mvkMTLPixelFormatIsStencilFormat(mtlDSFormat);
+	if (_hasStencilAttachment != prevHasStencilAttachment) { markDirty(); }
+}
+
 void MVKDepthStencilCommandEncoderState::encodeImpl(uint32_t stage) {
-    if (stage != kMVKGraphicsStageRasterization && stage != kMVKGraphicsStageVertex) { return; }
-    MVKRenderSubpass *subpass = _cmdEncoder->getSubpass();
-    id<MTLDepthStencilState> mtlDSS = nil;
-    if (stage != kMVKGraphicsStageVertex && subpass->getDepthStencilFormat() != VK_FORMAT_UNDEFINED) {
-        mtlDSS = _cmdEncoder->getCommandEncodingPool()->getMTLDepthStencilState(_depthStencilData);
-    } else {
-        // If there is no depth attachment but the depth/stencil state contains a non-always depth
-        // test, Metal Validation will give the following error:
-        // "validateDepthStencilState:3657: failed assertion `MTLDepthStencilDescriptor sets
-        //  depth test but MTLRenderPassDescriptor has a nil depthAttachment texture'"
-        // Check the subpass to see if there is a depth/stencil attachment, and if not use
-        // a depth/stencil state with depth test always, depth write disabled, and no stencil state.
-        mtlDSS = _cmdEncoder->getCommandEncodingPool()->getMTLDepthStencilState(false, false);
-    }
-    [_cmdEncoder->_mtlRenderEncoder setDepthStencilState: mtlDSS];
+	auto cmdEncPool = _cmdEncoder->getCommandEncodingPool();
+	switch (stage) {
+		case kMVKGraphicsStageRasterization: {
+			// If renderpass does not have a depth or a stencil attachment, disable corresponding test
+			MVKMTLDepthStencilDescriptorData adjustedDSData = _depthStencilData;
+			adjustedDSData.disable(!_hasDepthAttachment, !_hasStencilAttachment);
+			[_cmdEncoder->_mtlRenderEncoder setDepthStencilState: cmdEncPool->getMTLDepthStencilState(adjustedDSData)];
+			break;
+		}
+		case kMVKGraphicsStageVertex: {
+			// Vertex stage of tessellation pipeline requires depth/stencil testing be disabled
+			[_cmdEncoder->_mtlRenderEncoder setDepthStencilState: cmdEncPool->getMTLDepthStencilState(false, false)];
+			break;
+		}
+		default:		// Do nothing on other stages
+			break;
+	}
 }
 
 void MVKDepthStencilCommandEncoderState::resetImpl() {
     _depthStencilData = kMVKMTLDepthStencilDescriptorDataDefault;
+	_hasDepthAttachment = false;
+	_hasStencilAttachment = false;
 }
 
 
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
index a14e2de..46e0fb5 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandResourceFactory.h
@@ -207,18 +207,24 @@
 		return mvkHash((uint64_t*)this, sizeof(*this) / sizeof(uint64_t));
 	}
 
-    MVKMTLDepthStencilDescriptorData_t() {
+	/** Disable depth and/or stencil testing. */
+	void disable(bool disableDepth, bool disableStencil) {
+		if (disableDepth) {
+			depthCompareFunction = MTLCompareFunctionAlways;
+			depthWriteEnabled = false;
+		}
+		if (disableStencil) {
+			frontFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
+			backFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
+		}
+	}
 
-        // Start with all zeros to ensure memory comparisons will work,
-        // even if the structure contains alignment gaps.
-        memset(this, 0, sizeof(*this));
-
-        depthCompareFunction = MTLCompareFunctionAlways;
-        depthWriteEnabled = false;
-
-        frontFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
-        backFaceStencilData = kMVKMTLStencilDescriptorDataDefault;
-    }
+	MVKMTLDepthStencilDescriptorData_t() {
+		// Start with all zeros to ensure memory comparisons will work,
+		// even if the structure contains alignment gaps.
+		memset(this, 0, sizeof(*this));
+		disable(true, true);
+	}
 
 } __attribute__((aligned(sizeof(uint64_t)))) MVKMTLDepthStencilDescriptorData;
 
@@ -345,10 +351,7 @@
 	id<MTLRenderPipelineState> newCmdClearMTLRenderPipelineState(MVKRPSKeyClearAtt& attKey,
 																 MVKVulkanAPIDeviceObject* owner);
 
-	/**
-	 * Returns a new MTLDepthStencilState dedicated to rendering to several 
-	 * attachments to support clearing regions of those attachments.
-	 */
+	/** Returns a new MTLDepthStencilState that always writes to the depth and/or stencil attachments. */
 	id<MTLDepthStencilState> newMTLDepthStencilState(bool useDepth, bool useStencil);
 
     /**