Add class mixins for reference counting and configuration results.

Separate reference counting from MVKVulkanAPIObject into a new
MVKReferenceCountingMixin class, so reference counting can
potentially be used in other areas of the class hierarchy.
Replace MVKConfigurableObject with MVKConfigurableMixin for the same reason.
Remove some inline definitions as unnecessary in the files being revised here.
This commit is contained in:
Bill Hollings 2021-05-04 15:26:28 -04:00
parent 1e7ff59944
commit 91c5f58f7a
4 changed files with 92 additions and 60 deletions

View File

@ -45,10 +45,10 @@ public:
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 @@ public:
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 @@ public:
* 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 @@ protected:
#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:

View File

@ -20,8 +20,6 @@
#include "MVKBaseObject.h"
#include <vulkan/vk_icd.h>
#include <string>
#include <atomic>
#import <Foundation/NSString.h>
@ -34,13 +32,11 @@ class MVKInstance;
/**
* 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 @@ public:
/** 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 @@ public:
/** 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 @@ public:
*
* 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;
}

View File

@ -62,13 +62,11 @@ MVKVulkanAPIObject* MVKVulkanAPIObject::getMVKVulkanAPIObject(VkObjectType objTy
}
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;
}

View File

@ -20,6 +20,7 @@
#include "mvk_vulkan.h"
#include <string>
#include <atomic>
class MVKVulkanAPIObject;
@ -99,29 +100,94 @@ public:
#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;