Merge pull request #714 from billhollings/master

 Fix crash in vkDestroyPipelineLayout()
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index c3fe0f6..fd3c8e8 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -24,10 +24,15 @@
 - Revert to supporting host-coherent memory for linear images on macOS.
 - 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()`.
+- `vkCmdClearImage()` set error if attempt made to clear 1D image.
+- Remove error logging on `VK_TIMEOUT` of `VkSemaphore` and `VkFence`.
 - Consolidate the various linkable objects into a `MVKLinkableMixin` template base class.
 - Use `MVKVector` whenever possible in MoltenVK, especially within render loop.
 - No longer prefer dedicated allocations for buffer memory, including buffer-backed images.
 - Handle the `compositeAlpha` member of `VkSwapchainCreateInfoKHR`.
+- `VkPhysicalDevicePortabilitySubsetFeaturesEXTX::events` set to `true`.
+
 
 
 MoltenVK 1.0.36
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
index 40c1fa1..103befb 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
@@ -1055,6 +1055,9 @@
     }
 
 	// Validate
+	if (_image->getImageType() == VK_IMAGE_TYPE_1D) {
+		setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClearImage(): 1D images cannot be cleared on this device."));
+	}
 	if ( !_image->getSupportsAllFormatFeatures(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ) {
 		setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdClearImage(): Format %s cannot be cleared on this device.", mvkVkFormatName(_image->getVkFormat())));
 	}
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 2f73064..e900a61 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -128,7 +128,7 @@
                     auto* portabilityFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesEXTX*)next;
                     portabilityFeatures->triangleFans = false;
                     portabilityFeatures->separateStencilMaskRef = true;
-                    portabilityFeatures->events = _metalFeatures.events;
+                    portabilityFeatures->events = true;
                     portabilityFeatures->standardImageViews = _mvkInstance->getMoltenVKConfiguration()->fullImageViewSwizzle;
                     portabilityFeatures->samplerMipLodBias = false;
                     break;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 30d48c2..020af29 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -102,10 +102,12 @@
 	/** Constructs an instance for the specified device. */
 	MVKPipelineLayout(MVKDevice* device, const VkPipelineLayoutCreateInfo* pCreateInfo);
 
+	~MVKPipelineLayout() override;
+
 protected:
 	void propogateDebugName() override {}
 
-	MVKVectorInline<MVKDescriptorSetLayout, 8> _descriptorSetLayouts;
+	MVKVectorInline<MVKDescriptorSetLayout*, 8> _descriptorSetLayouts;
 	MVKVectorInline<MVKShaderResourceBinding, 8> _dslMTLResourceIndexOffsets;
 	MVKVectorInline<VkPushConstantRange, 8> _pushConstants;
 	MVKShaderResourceBinding _pushConstantsMTLResourceIndexes;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 265d922..1d1ae2d 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -47,11 +47,11 @@
 	for (uint32_t dsIdx = 0; dsIdx < dsCnt; dsIdx++) {
 		MVKDescriptorSet* descSet = descriptorSets[dsIdx];
 		uint32_t dslIdx = firstSet + dsIdx;
-		auto& dsl = _descriptorSetLayouts[dslIdx];
-		dsl.bindDescriptorSet(cmdEncoder, descSet,
-							  _dslMTLResourceIndexOffsets[dslIdx],
-							  dynamicOffsets, &pDynamicOffsetIndex);
-		setConfigurationResult(dsl.getConfigurationResult());
+		MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[dslIdx];
+		dsl->bindDescriptorSet(cmdEncoder, descSet,
+							   _dslMTLResourceIndexOffsets[dslIdx],
+							   dynamicOffsets, &pDynamicOffsetIndex);
+		setConfigurationResult(dsl->getConfigurationResult());
 	}
 }
 
@@ -60,9 +60,9 @@
                                           MVKVector<VkWriteDescriptorSet>& descriptorWrites,
                                           uint32_t set) {
 	clearConfigurationResult();
-	auto& dsl = _descriptorSetLayouts[set];
-	dsl.pushDescriptorSet(cmdEncoder, descriptorWrites, _dslMTLResourceIndexOffsets[set]);
-	setConfigurationResult(dsl.getConfigurationResult());
+	MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[set];
+	dsl->pushDescriptorSet(cmdEncoder, descriptorWrites, _dslMTLResourceIndexOffsets[set]);
+	setConfigurationResult(dsl->getConfigurationResult());
 }
 
 // A null cmdEncoder can be passed to perform a validation pass
@@ -71,9 +71,9 @@
                                           uint32_t set,
                                           const void* pData) {
 	clearConfigurationResult();
-	auto& dsl = _descriptorSetLayouts[set];
-	dsl.pushDescriptorSet(cmdEncoder, descUpdateTemplate, pData, _dslMTLResourceIndexOffsets[set]);
-	setConfigurationResult(dsl.getConfigurationResult());
+	MVKDescriptorSetLayout* dsl = _descriptorSetLayouts[set];
+	dsl->pushDescriptorSet(cmdEncoder, descUpdateTemplate, pData, _dslMTLResourceIndexOffsets[set]);
+	setConfigurationResult(dsl->getConfigurationResult());
 }
 
 void MVKPipelineLayout::populateShaderConverterContext(SPIRVToMSLConversionConfiguration& context) {
@@ -82,9 +82,9 @@
     // Add resource bindings defined in the descriptor set layouts
 	uint32_t dslCnt = (uint32_t)_descriptorSetLayouts.size();
 	for (uint32_t dslIdx = 0; dslIdx < dslCnt; dslIdx++) {
-        _descriptorSetLayouts[dslIdx].populateShaderConverterContext(context,
-                                                                     _dslMTLResourceIndexOffsets[dslIdx],
-                                                                     dslIdx);
+		_descriptorSetLayouts[dslIdx]->populateShaderConverterContext(context,
+																	  _dslMTLResourceIndexOffsets[dslIdx],
+																	  dslIdx);
 	}
 
 	// Add any resource bindings used by push-constants
@@ -113,16 +113,16 @@
     // with each DSL as it is added. The final accumulation of resource index offsets
     // becomes the resource index offsets that will be used for push contants.
 
-    // According to the Vulkan spec, VkDescriptorSetLayout is intended to be consumed when
-    // passed to any Vulkan function, and may be safely destroyed by app immediately after.
-    // In order for this pipeline layout to retain the content of a VkDescriptorSetLayout,
-    // this pipeline holds onto copies of the MVKDescriptorSetLayout instances, so that the
-    // originals created by the app can be safely destroyed.
+    // According to the Vulkan spec, VkDescriptorSetLayout is intended to be consumed when passed
+	// to any Vulkan function, and may be safely destroyed by app immediately after. In order for
+	// this pipeline layout to retain the VkDescriptorSetLayout, the MVKDescriptorSetLayout
+	// instance is retained, so that it will live on here after it has been destroyed by the API.
 
 	_descriptorSetLayouts.reserve(pCreateInfo->setLayoutCount);
 	for (uint32_t i = 0; i < pCreateInfo->setLayoutCount; i++) {
 		MVKDescriptorSetLayout* pDescSetLayout = (MVKDescriptorSetLayout*)pCreateInfo->pSetLayouts[i];
-		_descriptorSetLayouts.push_back(*pDescSetLayout);
+		pDescSetLayout->retain();
+		_descriptorSetLayouts.push_back(pDescSetLayout);
 		_dslMTLResourceIndexOffsets.push_back(_pushConstantsMTLResourceIndexes);
 		_pushConstantsMTLResourceIndexes += pDescSetLayout->_mtlResourceCounts;
 	}
@@ -150,6 +150,10 @@
 	}
 }
 
+MVKPipelineLayout::~MVKPipelineLayout() {
+	for (auto dsl : _descriptorSetLayouts) { dsl->release(); }
+}
+
 
 #pragma mark -
 #pragma mark MVKPipeline
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
index 9fb29be..60d4532 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm
@@ -80,15 +80,9 @@
 #pragma mark -
 #pragma mark MVKSemaphore
 
-bool MVKSemaphore::wait(uint64_t timeout) {
-	bool isDone = _blocker.wait(timeout, true);
-	if ( !isDone && timeout > 0 ) { reportError(VK_TIMEOUT, "Vulkan semaphore timeout after %llu nanoseconds.", timeout); }
-	return isDone;
-}
+bool MVKSemaphore::wait(uint64_t timeout) { return _blocker.wait(timeout, true); }
 
-void MVKSemaphore::signal() {
-    _blocker.release();
-}
+void MVKSemaphore::signal() { _blocker.release(); }
 
 void MVKSemaphore::encodeWait(id<MTLCommandBuffer> cmdBuff) {
     [cmdBuff encodeWaitForEvent: _mtlEvent value: _mtlEventValue];
@@ -254,12 +248,7 @@
 		((MVKFence*)pFences[i])->addSitter(&fenceSitter);
 	}
 
-	if ( !fenceSitter.wait(timeout) ) {
-		rslt = VK_TIMEOUT;
-		if (timeout > 0) {
-			device->reportError(rslt, "Vulkan fence timeout after %llu nanoseconds.", timeout);
-		}
-	}
+	if ( !fenceSitter.wait(timeout) ) { rslt = VK_TIMEOUT; }
 
 	for (uint32_t i = 0; i < fenceCount; i++) {
 		((MVKFence*)pFences[i])->removeSitter(&fenceSitter);