Merge pull request #819 from billhollings/master

Fix issue where preallocated descriptor count was not reset during vkResetDescriptorPool().
diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md
index cba451e..92f3d0b 100644
--- a/Docs/MoltenVK_Runtime_UserGuide.md
+++ b/Docs/MoltenVK_Runtime_UserGuide.md
@@ -352,17 +352,21 @@
 - Application runtime environment variables.
 - Build settings at **MoltenVK** build time.
 
-To change the **MoltenVK** configuration settings at runtime using a programmatic API, use the 
-`vkGetMoltenVKConfigurationMVK()` and `vkSetMoltenVKConfigurationMVK()` functions to retrieve, 
-modify, and set a copy of the `MVKConfiguration` structure.
+To change some of the **MoltenVK** configuration settings at runtime using a programmatic API, 
+use the `vkGetMoltenVKConfigurationMVK()` and `vkSetMoltenVKConfigurationMVK()` functions to 
+retrieve, modify, and set a copy of the `MVKConfiguration` structure.
 
-The initial value of each of the configuration settings can established at runtime 
+The initial value of each of the configuration settings can be established at runtime 
 by a corresponding environment variable, or if the environment variable is not set, 
 by a corresponding build setting at the time **MoltenVK** is compiled. The environment 
 variable and build setting for each configuration parameter share the same name.
 
-See the description of the `MVKConfiguration` structure parameters in the `vk_mvk_moltenvk.h` 
-file for more info about configuring and optimizing **MoltenVK** at build time or runtime.
+There are also a number of additional runtime environment variables that are not included in the
+`MVKConfiguration` structure, but that also control **MoltenVK** behaviour.
+
+See the description of the environment variables and the `MVKConfiguration` structure parameters 
+in the `vk_mvk_moltenvk.h` file for more info about configuring and optimizing **MoltenVK** 
+at runtime or build time.
 
 
 <a name="shaders"></a>
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 0fc1581..aa01001 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -17,15 +17,19 @@
 MoltenVK 1.0.40
 ---------------
 
-Released TBD
+Released 2020/01/21
 
+- Refactor descriptor management to reduce memory footprint and fix caching leak.
+- Add `MVK_CONFIG_PREALLOCATE_DESCRIPTORS` environment variable to support preallocated 
+  descriptor pooling within a `VkDescriptorPool` via the `VkDescriptorPoolSize` values.
 - Fix crash when app does not use queue family zero.
 - Fix buffer offset in `vkCmdPushDescriptorSet()` for non-dedicated buffer memory.
 - Fix Metal validation error on push constant sizing differences between C and MSL structs.
 - Track performance of `CAMetalLayer nextDrawable` call.
 - Document recommendation to use 3 swapchain images, particularly with full-screen rendering.
+- Update `MoltenVK_Runtime_UserGuide.md` to better explain runtime environment variables.
 - Update `VK_MVK_MOLTENVK_SPEC_VERSION` to `24`.
-- Update copyright to 2020.
+- Update copyright notices to year 2020.
 
 
 
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index e203c43..078c134 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -144,6 +144,15 @@
  *    on native 1D textures, including not being renderable, clearable, or permitting mipmaps.
  *    Using a Metal 2D texture allows Vulkan 1D textures to support this additional functionality.
  *    This setting is enabled by default, and MoltenVK will use a Metal 2D texture for each Vulkan 1D image.
+ *
+ * 7. The MVK_CONFIG_PREALLOCATE_DESCRIPTORS runtime environment variable or MoltenVK compile-time
+ *    build setting controls whether MoltenVK should preallocate memory in each VkDescriptorPool
+ *    according to the values of the VkDescriptorPoolSize parameters. Doing so may improve
+ *    descriptor set allocation performance at a cost of preallocated application memory.
+ *    If this environment variable is disabled, the descriptors required for a descriptor set will
+ *    be dynamically allocated in application memory when the descriptor set itself is allocated.
+ *    This setting is disabled by default, and MoltenVK will dynamically allocate descriptors
+ *    when the containing descriptor set is allocated.
  */
 typedef struct {
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
index 212fc63..51756a3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.h
@@ -162,6 +162,7 @@
 	VkResult allocateDescriptor(MVKDescriptor** pMVKDesc);
 	bool findDescriptor(uint32_t endIndex, MVKDescriptor** pMVKDesc);
 	void freeDescriptor(MVKDescriptor* mvkDesc);
+	void reset();
 
 	std::vector<DescriptorClass> _descriptors;
 	std::vector<bool> _availability;
@@ -188,6 +189,7 @@
 
 	VkResult allocateDescriptor(VkDescriptorType descriptorType, MVKDescriptor** pMVKDesc);
 	void freeDescriptor(MVKDescriptor* mvkDesc);
+	void reset();
 
 	MVKDescriptorTypePreallocation<MVKUniformBufferDescriptor> _uniformBufferDescriptors;
 	MVKDescriptorTypePreallocation<MVKStorageBufferDescriptor> _storageBufferDescriptors;
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
index cfecbfd..8e220bb 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm
@@ -355,6 +355,11 @@
 }
 
 template<typename DescriptorClass>
+void MVKDescriptorTypePreallocation<DescriptorClass>::reset() {
+	_nextAvailableIndex = 0;
+}
+
+template<typename DescriptorClass>
 MVKDescriptorTypePreallocation<DescriptorClass>::MVKDescriptorTypePreallocation(const VkDescriptorPoolCreateInfo* pCreateInfo,
 																				VkDescriptorType descriptorType) {
 	// There may be more than  one poolSizeCount instance for the desired VkDescriptorType.
@@ -466,6 +471,21 @@
 	}
 }
 
+void MVKPreallocatedDescriptors::reset() {
+	_uniformBufferDescriptors.reset();
+	_storageBufferDescriptors.reset();
+	_uniformBufferDynamicDescriptors.reset();
+	_storageBufferDynamicDescriptors.reset();
+	_inlineUniformBlockDescriptors.reset();
+	_sampledImageDescriptors.reset();
+	_storageImageDescriptors.reset();
+	_inputAttachmentDescriptors.reset();
+	_samplerDescriptors.reset();
+	_combinedImageSamplerDescriptors.reset();
+	_uniformTexelBufferDescriptors.reset();
+	_storageTexelBufferDescriptors.reset();
+}
+
 MVKPreallocatedDescriptors::MVKPreallocatedDescriptors(const VkDescriptorPoolCreateInfo* pCreateInfo) :
 	_uniformBufferDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER),
 	_storageBufferDescriptors(pCreateInfo, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER),
@@ -521,6 +541,7 @@
 VkResult MVKDescriptorPool::reset(VkDescriptorPoolResetFlags flags) {
 	for (auto& mvkDS : _allocatedSets) { freeDescriptorSet(mvkDS); }
 	_allocatedSets.clear();
+	if (_preallocatedDescriptors) { _preallocatedDescriptors->reset(); }
 	return VK_SUCCESS;
 }