Merge pull request #1352 from billhollings/shader-config

Improvements to SPIRVToMSLConversionConfiguration
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
index 512c17a..68c5353 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.h
@@ -45,10 +45,10 @@
 	MVKVulkanAPIObject* getVulkanAPIObject() override { return _physicalDevice->getVulkanAPIObject(); }
 
 	/** Returns the index of this queue family. */
-	inline uint32_t getIndex() { return _queueFamilyIndex; }
+	uint32_t getIndex() { return _queueFamilyIndex; }
 
 	/** Populates the specified properties structure. */
-	inline void getProperties(VkQueueFamilyProperties* queueProperties) {
+	void getProperties(VkQueueFamilyProperties* queueProperties) {
 		if (queueProperties) { *queueProperties = _properties; }
 	}
 
@@ -98,13 +98,13 @@
 	VkResult waitIdle();
 
 	/** Return the name of this queue. */
-	inline const std::string& getName() { return _name; }
+	const std::string& getName() { return _name; }
 
 
 #pragma mark Metal
 
 	/** Returns the Metal queue underlying this queue. */
-	inline id<MTLCommandQueue> getMTLCommandQueue() { return _mtlQueue; }
+	id<MTLCommandQueue> getMTLCommandQueue() { return _mtlQueue; }
 
 	/** Returns a Metal command buffer from the Metal queue. */
 	id<MTLCommandBuffer> getMTLCommandBuffer(bool retainRefs = false);
@@ -120,13 +120,13 @@
      * Returns a reference to this object suitable for use as a Vulkan API handle.
      * This is the compliment of the getMVKQueue() method.
      */
-    inline VkQueue getVkQueue() { return (VkQueue)getVkHandle(); }
+    VkQueue getVkQueue() { return (VkQueue)getVkHandle(); }
 
     /**
      * Retrieves the MVKQueue instance referenced by the VkQueue handle.
      * This is the compliment of the getVkQueue() method.
      */
-    static inline MVKQueue* getMVKQueue(VkQueue vkQueue) {
+    static MVKQueue* getMVKQueue(VkQueue vkQueue) {
         return (MVKQueue*)getDispatchableObject(vkQueue);
     }
 
@@ -158,7 +158,7 @@
 #pragma mark MVKQueueSubmission
 
 /** This is an abstract class for an operation that can be submitted to an MVKQueue. */
-class MVKQueueSubmission : public MVKConfigurableObject {
+class MVKQueueSubmission : public MVKBaseObject, public MVKConfigurableMixin {
 
 public:
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h
index cbb0219..837b13b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.h
@@ -20,8 +20,6 @@
 
 #include "MVKBaseObject.h"
 #include <vulkan/vk_icd.h>
-#include <string>
-#include <atomic>
 
 #import <Foundation/NSString.h>
 
@@ -34,13 +32,11 @@
 /**
  * Abstract class that represents an opaque Vulkan API handle object.
  *
- * API objects can sometimes be destroyed by the client before the GPU is done with them.
- * To support this, an object of this type will automatically be deleted iff it has been
- * destroyed by the client, and all references have been released. An object of this type
- * is therefore allowed to live past its destruction by the client, until it is no longer
- * referenced by other objects.
+ * Vulkan API objects can sometimes be destroyed by the client before the GPU is done with them.
+ * To support this, this class inherits from MVKReferenceCountingMixin to allow an instance to
+ * live past its destruction by the client, until it is no longer referenced by other objects.
  */
-class MVKVulkanAPIObject : public MVKConfigurableObject {
+class MVKVulkanAPIObject : public MVKReferenceCountingMixin<MVKBaseObject>, public MVKConfigurableMixin {
 
 public:
 
@@ -59,29 +55,8 @@
 	/** Returns the Vulkan instance. */
 	virtual MVKInstance* getInstance() = 0;
 
-	/**
-	 * Called when this instance has been retained as a reference by another object,
-	 * indicating that this instance will not be deleted until that reference is released.
-	 */
-	inline void retain() { _refCount++; }
-
-	/**
-	 * Called when this instance has been released as a reference from another object.
-	 * Once all references have been released, this object is free to be deleted.
-	 * If the destroy() function has already been called on this instance by the time
-	 * this function is called, this instance will be deleted.
-	 */
-	inline void release() { if (--_refCount == 0) { MVKConfigurableObject::destroy(); } }
-
-	/**
-	 * Marks this instance as destroyed. If all previous references to this instance
-	 * have been released, this instance will be deleted, otherwise deletion of this
-	 * instance will automatically be deferred until all references have been released.
-	 */
-	void destroy() override { release(); }
-
 	/** Gets the debug object name of this instance. */
-	inline NSString* getDebugName() { return _debugName; }
+	NSString* getDebugName() { return _debugName; }
 
 	/** Sets the debug object name of this instance. */
 	VkResult setDebugName(const char* pObjectName);
@@ -92,21 +67,14 @@
 	/** Returns the MVKVulkanAPIObject instance referenced by the object of the given type. */
 	static MVKVulkanAPIObject* getMVKVulkanAPIObject(VkObjectType objType, uint64_t objectHandle);
 
-	/** Construct an empty instance. Declared here to support copy constructor. */
-	MVKVulkanAPIObject() : _refCount(1) {}
-
-	/** Default copy constructor disallowed due to mutex. Copy starts with fresh reference counts. */
+	MVKVulkanAPIObject() {}
 	MVKVulkanAPIObject(const MVKVulkanAPIObject& other);
-
-	/** Default copy assignment disallowed due to mutex. Copy starts with fresh reference counts. */
 	MVKVulkanAPIObject& operator=(const MVKVulkanAPIObject& other);
-
 	~MVKVulkanAPIObject() override;
 
 protected:
 	virtual void propagateDebugName() = 0;
 
-	std::atomic<uint32_t> _refCount;
 	NSString* _debugName = nil;
 };
 
@@ -143,7 +111,7 @@
 	 *
      * This is the compliment of the getVkHandle() function.
      */
-    static inline MVKDispatchableVulkanAPIObject* getDispatchableObject(void* vkHandle) {
+    static MVKDispatchableVulkanAPIObject* getDispatchableObject(void* vkHandle) {
 		return vkHandle ? ((MVKDispatchableObjectICDRef*)vkHandle)->mvkObject : nullptr;
     }
 
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
index 5df32e1..64556b3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKVulkanAPIObject.mm
@@ -62,13 +62,11 @@
 }
 
 MVKVulkanAPIObject::MVKVulkanAPIObject(const MVKVulkanAPIObject& other) {
-	_refCount = 1;
 	_debugName = [other._debugName retain];
 }
 
 MVKVulkanAPIObject& MVKVulkanAPIObject::operator=(const MVKVulkanAPIObject& other) {
 	[_debugName release];
-	_refCount = 1;
 	_debugName = [other._debugName retain];
 	return *this;
 }
diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h
index 44c6592..68012f3 100644
--- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h
+++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h
@@ -20,6 +20,7 @@
 
 #include "mvk_vulkan.h"
 #include <string>
+#include <atomic>
 
 class MVKVulkanAPIObject;
 
@@ -99,29 +100,94 @@
 
 
 #pragma mark -
-#pragma mark MVKConfigurableObject
+#pragma mark MVKReferenceCountingMixin
 
-/** 
- * Abstract class that represents an object whose configuration can be validated and tracked
- * as a queriable result. This is the base class of opaque Vulkan API objects, and commands.
+/**
+ * This templated mixin adds the ability for an object to track references
+ * to itself and defer destruction while existing references are alive.
+ *
+ * The BaseClass template parameter should derive from MVKBaseObject.
+ * or must otherwise declare a virtual destroy() function.
+ *
+ * To add this mixin to a class, subclass from this mixin template class, and
+ * set the template BaseClass to the nominal parent class of the class this is
+ * being added to. For example, if MySubClass nominally inherits from MyBaseClass,
+ * this mixin can be added to MySubClass by declaring MySubClass as follows:
+ *
+ *   class MySubClass : public MVKReferenceCountingMixin<MyBaseClass>
+ *
+ * As noted, in this example, MyBaseClass should derive from MVKBaseObject,
+ * or must otherwise declare a virtual destroy() function
  */
-class MVKConfigurableObject : public MVKBaseObject {
+template <class BaseClass>
+class MVKReferenceCountingMixin : public BaseClass {
+
+public:
+
+	/**
+	 * Called when this instance has been retained as a reference by another object,
+	 * indicating that this instance will not be deleted until that reference is released.
+	 */
+	void retain() { _refCount++; }
+
+	/**
+	 * Called when this instance has been released as a reference from another object.
+	 * Once all references have been released, this object is free to be deleted.
+	 * If the destroy() function has already been called on this instance by the time
+	 * this function is called, this instance will be deleted.
+	 */
+	void release() { if (--_refCount == 0) { BaseClass::destroy(); } }
+
+	/**
+	 * Marks this instance as destroyed. If all previous references to this instance
+	 * have been released, this instance will be deleted, otherwise deletion of this
+	 * instance will automatically be deferred until all references have been released.
+	 */
+	void destroy() override { release(); }
+
+	MVKReferenceCountingMixin() : _refCount(1) {}
+
+	/** Copy starts with fresh reference counts. */
+	MVKReferenceCountingMixin(const MVKReferenceCountingMixin& other) {
+		_refCount = 1;
+	}
+
+	/** Copy starts with fresh reference counts. */
+	MVKReferenceCountingMixin& operator=(const MVKReferenceCountingMixin& other) {
+		_refCount = 1;
+		return *this;
+	}
+
+protected:
+	std::atomic<uint32_t> _refCount;
+
+};
+
+
+#pragma mark -
+#pragma mark MVKConfigurableMixin
+
+/**
+ * Mixin that can be added to a class whose instances are configured from Vulkan configuration
+ * info, and the result of which can be validated and tracked as a queriable Vulkan VkResult.
+ */
+class MVKConfigurableMixin {
 
 public:
 
 	/** Returns a indication of the success of the configuration of this instance. */
-	inline VkResult getConfigurationResult() { return _configurationResult; }
+	VkResult getConfigurationResult() { return _configurationResult; }
 
 	/** If the existing configuration result is VK_SUCCESS, it is set to the specified value. */
-    inline void setConfigurationResult(VkResult vkResult) {
-        if (_configurationResult == VK_SUCCESS) { _configurationResult = vkResult; }
-    }
+	void setConfigurationResult(VkResult vkResult) {
+		if (_configurationResult == VK_SUCCESS) { _configurationResult = vkResult; }
+	}
 
 	/** Returns whether the configuration was successful. */
-	inline bool wasConfigurationSuccessful() { return _configurationResult == VK_SUCCESS; }
+	bool wasConfigurationSuccessful() { return _configurationResult == VK_SUCCESS; }
 
-    /** Resets the indication of the success of the configuration of this instance back to VK_SUCCESS. */
-    inline void clearConfigurationResult() { _configurationResult = VK_SUCCESS; }
+	/** Resets the indication of the success of the configuration of this instance back to VK_SUCCESS. */
+	void clearConfigurationResult() { _configurationResult = VK_SUCCESS; }
 
 protected:
 	VkResult _configurationResult = VK_SUCCESS;