Advertise the VK_EXT_shader_stencil_export extension.

This is supported by Mac GPU Family 2 starting on macOS 10.14, and Apple
GPU Family 5 starting on iOS 12.

Supporting this is a bit tricky. Because only some devices support this
extension, we now have to keep track of supported device extensions per
device.
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index 1b36bfb..a0d5107 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -240,7 +240,7 @@
 - `VK_KHR_maintenance3`
 - `VK_KHR_push_descriptor`
 - `VK_KHR_relaxed_block_layout`
-- `VK_KHR_sampler_mirror_clamp_to_edge`
+- `VK_KHR_sampler_mirror_clamp_to_edge` *(macOS)*
 - `VK_KHR_shader_draw_parameters`
 - `VK_KHR_shader_float16_int8`
 - `VK_KHR_storage_buffer_storage_class`
@@ -254,6 +254,7 @@
 - `VK_EXT_host_query_reset`
 - `VK_EXT_memory_budget`
 - `VK_EXT_metal_surface`
+- `VK_EXT_shader_stencil_export` *(requires Mac GPU family 2 or iOS GPU family 5)*
 - `VK_EXT_shader_viewport_index_layer`
 - `VK_EXT_vertex_attribute_divisor`
 - `VK_EXTX_portability_subset`
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index cf0f232..7365f17 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -537,6 +537,7 @@
 	VkBool32 events;							/**< If true, Metal synchronization events are supported. */
 	VkBool32 memoryBarriers;					/**< If true, full memory barriers within Metal render passes are supported. */
 	VkBool32 multisampleLayeredRendering;       /**< If true, layered rendering to multiple multi-sampled cube or texture array layers is supported. */
+	VkBool32 stencilFeedback;					/**< If true, fragment shaders that write to [[stencil]] outputs are supported. */
 } MVKPhysicalDeviceMetalFeatures;
 
 /**
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index e170075..233d360 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -88,6 +88,9 @@
 	/** Returns a pointer to the Vulkan instance. */
 	MVKInstance* getInstance() override { return _mvkInstance; }
 
+	/** Populates the specified array with the supported extensions of this device. */
+	VkResult getExtensionProperties(const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties);
+
 	/** Populates the specified structure with the features of this device. */
 	void getFeatures(VkPhysicalDeviceFeatures* features);
 
@@ -318,6 +321,8 @@
 	void initFeatures();
 	void initProperties();
 	void initMemoryProperties();
+	void initExtensions();
+	MVKExtensionList* getSupportedExtensions(const char* pLayerName = nullptr);
 	std::vector<MVKQueueFamily*>& getQueueFamilies();
 	void initPipelineCacheUUID();
 	MTLFeatureSet getHighestMTLFeatureSet();
@@ -327,6 +332,7 @@
 
 	id<MTLDevice> _mtlDevice;
 	MVKInstance* _mvkInstance;
+	MVKExtensionList _supportedExtensions;
 	VkPhysicalDeviceFeatures _features;
 	MVKPhysicalDeviceMetalFeatures _metalFeatures;
 	VkPhysicalDeviceProperties _properties;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index e697ab8..30c2a4a 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -56,6 +56,11 @@
 #pragma mark -
 #pragma mark MVKPhysicalDevice
 
+VkResult MVKPhysicalDevice::getExtensionProperties(const char* pLayerName, uint32_t* pCount, VkExtensionProperties* pProperties) {
+	MVKExtensionList* extensions = getSupportedExtensions(pLayerName);
+	return extensions->getProperties(pCount, pProperties);
+}
+
 void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures* features) {
     if (features) { *features = _features; }
 }
@@ -676,7 +681,7 @@
 
 #pragma mark Construction
 
-MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) {
+MVKPhysicalDevice::MVKPhysicalDevice(MVKInstance* mvkInstance, id<MTLDevice> mtlDevice) : _supportedExtensions(this, true) {
 	_mvkInstance = mvkInstance;
 	_mtlDevice = [mtlDevice retain];
 
@@ -684,6 +689,7 @@
 	initFeatures();             // Call second.
 	initProperties();           // Call third.
 	initMemoryProperties();
+	initExtensions();
 	logGPUInfo();
 }
 
@@ -751,6 +757,7 @@
 
 	if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_iOS_GPUFamily5_v1] ) {
 		_metalFeatures.layeredRendering = true;
+		_metalFeatures.stencilFeedback = true;
 	}
 
 #endif
@@ -793,6 +800,7 @@
 
 	if ( [_mtlDevice supportsFeatureSet: MTLFeatureSet_macOS_GPUFamily2_v1] ) {
 		_metalFeatures.multisampleLayeredRendering = _metalFeatures.layeredRendering;
+		_metalFeatures.stencilFeedback = true;
 	}
 
 #endif
@@ -1499,6 +1507,18 @@
 #endif
 }
 
+void MVKPhysicalDevice::initExtensions() {
+	if (!_metalFeatures.stencilFeedback) {
+		_supportedExtensions.vk_EXT_shader_stencil_export.enabled = false;
+	}
+}
+
+// Return all extensions supported by this physical device.
+MVKExtensionList* MVKPhysicalDevice::getSupportedExtensions(const char* pLayerName) {
+	if (!pLayerName || strcmp(pLayerName, "MoltenVK") == 0) { return &_supportedExtensions; }
+	return getInstance()->getLayerManager()->getLayerNamed(pLayerName)->getSupportedExtensions();
+}
+
 void MVKPhysicalDevice::logGPUInfo() {
 	string devTypeStr;
 	switch (_properties.deviceType) {
@@ -2280,7 +2300,7 @@
 	MVKExtensionList* pWritableExtns = (MVKExtensionList*)&_enabledExtensions;
 	setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount,
 												  pCreateInfo->ppEnabledExtensionNames,
-												  getInstance()->getDriverLayer()->getSupportedExtensions()));
+												  getPhysicalDevice()->getSupportedExtensions()));
 }
 
 // Create the command queues
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
index c066bd6..2d9e0e1 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def
@@ -58,6 +58,7 @@
 MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET)
 MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET)
 MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE)
+MVK_EXTENSION(EXT_shader_stencil_export, EXT_SHADER_STENCIL_EXPORT)
 MVK_EXTENSION(EXT_shader_viewport_index_layer, EXT_SHADER_VIEWPORT_INDEX_LAYER)
 MVK_EXTENSION(EXT_vertex_attribute_divisor, EXT_VERTEX_ATTRIBUTE_DIVISOR)
 MVK_EXTENSION(EXTX_portability_subset, EXTX_PORTABILITY_SUBSET)
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.h b/MoltenVK/MoltenVK/Layers/MVKExtensions.h
index e93fa50..f42aa0f 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.h
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.h
@@ -85,6 +85,20 @@
 	 */
 	std::string enabledNamesString(const char* separator = " ", bool prefixFirstWithSeparator = false) const;
 
+	/**
+	 * If pProperties is null, the value of pCount is updated with the number of extensions
+	 * enabled in this list.
+	 *
+	 * If pProperties is not null, then pCount extension properties are copied into the array.
+	 * If the number of available extensions is less than pCount, the value of pCount is updated
+	 * to indicate the number of extension properties actually returned in the array.
+	 *
+	 * Returns VK_SUCCESS if successful. Returns VK_INCOMPLETE if the number of extensions
+	 * enabled in this list is larger than the specified pCount. Returns other values
+	 * if an error occurs.
+	 */
+	VkResult getProperties(uint32_t* pCount, VkExtensionProperties* pProperties);
+
 	MVKExtensionList(MVKVulkanAPIObject* apiObject, bool enableForPlatform = false);
 
 protected:
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
index 8ca031a..e1580dc 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
@@ -50,6 +50,9 @@
 	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
 		return mvkOSVersion() >= 10.13;
 	}
+	if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
+		return mvkOSVersion() >= 10.14;
+	}
 	if (pProperties == &kVkExtProps_MVK_IOS_SURFACE) { return false; }
 	if (pProperties == &kVkExtProps_IMG_FORMAT_PVRTC) { return false; }
 #endif
@@ -58,6 +61,9 @@
 	if (pProperties == &kVkExtProps_EXT_MEMORY_BUDGET) {
 		return mvkOSVersion() >= 11.0;
 	}
+	if (pProperties == &kVkExtProps_EXT_SHADER_STENCIL_EXPORT) {
+		return mvkOSVersion() >= 12.0;
+	}
 	if (pProperties == &kVkExtProps_MVK_MACOS_SURFACE) { return false; }
 #endif
 
@@ -157,3 +163,31 @@
 	}
 	return logMsg;
 }
+
+VkResult MVKExtensionList::getProperties(uint32_t* pCount, VkExtensionProperties* pProperties) {
+
+	uint32_t enabledCnt = 0;
+
+	// Iterate extensions and handle those that are enabled. Count them,
+	// and if they are to be returned, and there is room, do so.
+	uint32_t extnCnt = getCount();
+	MVKExtension* extnAry = &extensionArray;
+	for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
+		if (extnAry[extnIdx].enabled) {
+			if (pProperties) {
+				if (enabledCnt < *pCount) {
+					pProperties[enabledCnt] = *(extnAry[extnIdx].pProperties);
+				} else {
+					return VK_INCOMPLETE;
+				}
+			}
+			enabledCnt++;
+		}
+	}
+
+	// Return the count of enabled extensions. This will either be a
+	// count of all enabled extensions, or a count of those returned.
+	*pCount = enabledCnt;
+	return VK_SUCCESS;
+}
+
diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
index bbc5a79..0fb19e6 100644
--- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
@@ -32,29 +32,7 @@
 
 VkResult MVKLayer::getExtensionProperties(uint32_t* pCount, VkExtensionProperties* pProperties) {
 
-	uint32_t enabledCnt = 0;
-
-	// Iterate extensions and handle those that are enabled. Count them,
-	// and if they are to be returned, and there is room, do so.
-	uint32_t extnCnt = _supportedExtensions.getCount();
-	MVKExtension* extnAry = &_supportedExtensions.extensionArray;
-	for (uint32_t extnIdx = 0; extnIdx < extnCnt; extnIdx++) {
-		if (extnAry[extnIdx].enabled) {
-			if (pProperties) {
-				if (enabledCnt < *pCount) {
-					pProperties[enabledCnt] = *(extnAry[extnIdx].pProperties);
-				} else {
-					return VK_INCOMPLETE;
-				}
-			}
-			enabledCnt++;
-		}
-	}
-
-	// Return the count of enabled extensions. This will either be a
-	// count of all enabled extensions, or a count of those returned.
-	*pCount = enabledCnt;
-	return VK_SUCCESS;
+	return _supportedExtensions.getProperties(pCount, pProperties);
 }
 
 
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index f4875b2..8a287a5 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -282,7 +282,7 @@
 
 	MVKTraceVulkanCallStart();
 	MVKPhysicalDevice* mvkPD = MVKPhysicalDevice::getMVKPhysicalDevice(physicalDevice);
-	VkResult rslt = mvkPD->getInstance()->getLayerManager()->getLayerNamed(pLayerName)->getExtensionProperties(pCount, pProperties);
+	VkResult rslt = mvkPD->getExtensionProperties(pLayerName, pCount, pProperties);
 	MVKTraceVulkanCallEnd();
 	return rslt;
 }