Add workaround for apps that use one semaphore for all swapchain images.

Support deferred secondary signaling of semaphore & fence acquired while image is free.
Add MVKBaseObject::destroy() function to support customization of object destruction.
Support deferred destruction of MVKSemaphore & MVKFence instances.
This commit is contained in:
Bill Hollings 2018-04-14 20:12:33 -04:00
parent 4c746bb288
commit 793f3fdaf3
9 changed files with 163 additions and 85 deletions

View File

@ -1037,7 +1037,8 @@ MVKBuffer* MVKDevice::createBuffer(const VkBufferCreateInfo* pCreateInfo,
void MVKDevice::destroyBuffer(MVKBuffer* mvkBuff,
const VkAllocationCallbacks* pAllocator) {
delete removeResource(mvkBuff);
removeResource(mvkBuff);
mvkBuff->destroy();
}
MVKBufferView* MVKDevice::createBufferView(const VkBufferViewCreateInfo* pCreateInfo,
@ -1047,7 +1048,7 @@ MVKBufferView* MVKDevice::createBufferView(const VkBufferViewCreateInfo* pCreate
void MVKDevice::destroyBufferView(MVKBufferView* mvkBuffView,
const VkAllocationCallbacks* pAllocator) {
delete mvkBuffView;
mvkBuffView->destroy();
}
MVKImage* MVKDevice::createImage(const VkImageCreateInfo* pCreateInfo,
@ -1057,7 +1058,8 @@ MVKImage* MVKDevice::createImage(const VkImageCreateInfo* pCreateInfo,
void MVKDevice::destroyImage(MVKImage* mvkImg,
const VkAllocationCallbacks* pAllocator) {
delete removeResource(mvkImg);
removeResource(mvkImg);
mvkImg->destroy();
}
MVKImageView* MVKDevice::createImageView(const VkImageViewCreateInfo* pCreateInfo,
@ -1067,7 +1069,7 @@ MVKImageView* MVKDevice::createImageView(const VkImageViewCreateInfo* pCreateInf
void MVKDevice::destroyImageView(MVKImageView* mvkImgView,
const VkAllocationCallbacks* pAllocator) {
delete mvkImgView;
mvkImgView->destroy();
}
MVKSwapchain* MVKDevice::createSwapchain(const VkSwapchainCreateInfoKHR* pCreateInfo,
@ -1077,7 +1079,7 @@ MVKSwapchain* MVKDevice::createSwapchain(const VkSwapchainCreateInfoKHR* pCreate
void MVKDevice::destroySwapchain(MVKSwapchain* mvkSwpChn,
const VkAllocationCallbacks* pAllocator) {
delete mvkSwpChn;
mvkSwpChn->destroy();
}
MVKSwapchainImage* MVKDevice::createSwapchainImage(const VkImageCreateInfo* pCreateInfo,
@ -1088,7 +1090,8 @@ MVKSwapchainImage* MVKDevice::createSwapchainImage(const VkImageCreateInfo* pCre
void MVKDevice::destroySwapchainImage(MVKSwapchainImage* mvkImg,
const VkAllocationCallbacks* pAllocator) {
delete removeResource(mvkImg);
removeResource(mvkImg);
mvkImg->destroy();
}
MVKFence* MVKDevice::createFence(const VkFenceCreateInfo* pCreateInfo,
@ -1098,7 +1101,7 @@ MVKFence* MVKDevice::createFence(const VkFenceCreateInfo* pCreateInfo,
void MVKDevice::destroyFence(MVKFence* mvkFence,
const VkAllocationCallbacks* pAllocator) {
delete mvkFence;
mvkFence->destroy();
}
MVKSemaphore* MVKDevice::createSemaphore(const VkSemaphoreCreateInfo* pCreateInfo,
@ -1108,7 +1111,7 @@ MVKSemaphore* MVKDevice::createSemaphore(const VkSemaphoreCreateInfo* pCreateInf
void MVKDevice::destroySemaphore(MVKSemaphore* mvkSem4,
const VkAllocationCallbacks* pAllocator) {
delete mvkSem4;
mvkSem4->destroy();
}
MVKQueryPool* MVKDevice::createQueryPool(const VkQueryPoolCreateInfo* pCreateInfo,
@ -1127,7 +1130,7 @@ MVKQueryPool* MVKDevice::createQueryPool(const VkQueryPoolCreateInfo* pCreateInf
void MVKDevice::destroyQueryPool(MVKQueryPool* mvkQP,
const VkAllocationCallbacks* pAllocator) {
delete mvkQP;
mvkQP->destroy();
}
MVKShaderModule* MVKDevice::createShaderModule(const VkShaderModuleCreateInfo* pCreateInfo,
@ -1137,7 +1140,7 @@ MVKShaderModule* MVKDevice::createShaderModule(const VkShaderModuleCreateInfo* p
void MVKDevice::destroyShaderModule(MVKShaderModule* mvkShdrMod,
const VkAllocationCallbacks* pAllocator) {
delete mvkShdrMod;
mvkShdrMod->destroy();
}
MVKPipelineCache* MVKDevice::createPipelineCache(const VkPipelineCacheCreateInfo* pCreateInfo,
@ -1147,7 +1150,7 @@ MVKPipelineCache* MVKDevice::createPipelineCache(const VkPipelineCacheCreateInfo
void MVKDevice::destroyPipelineCache(MVKPipelineCache* mvkPLC,
const VkAllocationCallbacks* pAllocator) {
delete mvkPLC;
mvkPLC->destroy();
}
MVKPipelineLayout* MVKDevice::createPipelineLayout(const VkPipelineLayoutCreateInfo* pCreateInfo,
@ -1157,7 +1160,7 @@ MVKPipelineLayout* MVKDevice::createPipelineLayout(const VkPipelineLayoutCreateI
void MVKDevice::destroyPipelineLayout(MVKPipelineLayout* mvkPLL,
const VkAllocationCallbacks* pAllocator) {
delete mvkPLL;
mvkPLL->destroy();
}
template<typename PipelineType, typename PipelineInfoType>
@ -1193,7 +1196,7 @@ VkResult MVKDevice::createPipelines(VkPipelineCache pipelineCache,
} else {
rslt = plRslt;
pPipelines[plIdx] = VK_NULL_HANDLE;
delete mvkPL;
mvkPL->destroy();
}
}
@ -1218,7 +1221,7 @@ template VkResult MVKDevice::createPipelines<MVKComputePipeline, VkComputePipeli
void MVKDevice::destroyPipeline(MVKPipeline* mvkPL,
const VkAllocationCallbacks* pAllocator) {
delete mvkPL;
mvkPL->destroy();
}
MVKSampler* MVKDevice::createSampler(const VkSamplerCreateInfo* pCreateInfo,
@ -1228,7 +1231,7 @@ MVKSampler* MVKDevice::createSampler(const VkSamplerCreateInfo* pCreateInfo,
void MVKDevice::destroySampler(MVKSampler* mvkSamp,
const VkAllocationCallbacks* pAllocator) {
delete mvkSamp;
mvkSamp->destroy();
}
MVKDescriptorSetLayout* MVKDevice::createDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
@ -1238,7 +1241,7 @@ MVKDescriptorSetLayout* MVKDevice::createDescriptorSetLayout(const VkDescriptorS
void MVKDevice::destroyDescriptorSetLayout(MVKDescriptorSetLayout* mvkDSL,
const VkAllocationCallbacks* pAllocator) {
delete mvkDSL;
mvkDSL->destroy();
}
MVKDescriptorPool* MVKDevice::createDescriptorPool(const VkDescriptorPoolCreateInfo* pCreateInfo,
@ -1248,7 +1251,7 @@ MVKDescriptorPool* MVKDevice::createDescriptorPool(const VkDescriptorPoolCreateI
void MVKDevice::destroyDescriptorPool(MVKDescriptorPool* mvkDP,
const VkAllocationCallbacks* pAllocator) {
delete mvkDP;
mvkDP->destroy();
}
MVKFramebuffer* MVKDevice::createFramebuffer(const VkFramebufferCreateInfo* pCreateInfo,
@ -1258,7 +1261,7 @@ MVKFramebuffer* MVKDevice::createFramebuffer(const VkFramebufferCreateInfo* pCre
void MVKDevice::destroyFramebuffer(MVKFramebuffer* mvkFB,
const VkAllocationCallbacks* pAllocator) {
delete mvkFB;
mvkFB->destroy();
}
MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo* pCreateInfo,
@ -1268,7 +1271,7 @@ MVKRenderPass* MVKDevice::createRenderPass(const VkRenderPassCreateInfo* pCreate
void MVKDevice::destroyRenderPass(MVKRenderPass* mvkRP,
const VkAllocationCallbacks* pAllocator) {
delete mvkRP;
mvkRP->destroy();
}
MVKCommandPool* MVKDevice::createCommandPool(const VkCommandPoolCreateInfo* pCreateInfo,
@ -1278,7 +1281,7 @@ MVKCommandPool* MVKDevice::createCommandPool(const VkCommandPoolCreateInfo* pCre
void MVKDevice::destroyCommandPool(MVKCommandPool* mvkCmdPool,
const VkAllocationCallbacks* pAllocator) {
delete mvkCmdPool;
mvkCmdPool->destroy();
}
MVKDeviceMemory* MVKDevice::allocateMemory(const VkMemoryAllocateInfo* pAllocateInfo,
@ -1288,7 +1291,7 @@ MVKDeviceMemory* MVKDevice::allocateMemory(const VkMemoryAllocateInfo* pAllocate
void MVKDevice::freeMemory(MVKDeviceMemory* mvkDevMem,
const VkAllocationCallbacks* pAllocator) {
delete mvkDevMem;
mvkDevMem->destroy();
}
/** Adds the specified resource for tracking, and returns the added resource. */
@ -1407,7 +1410,6 @@ uint32_t MVKDevice::expandVisibilityResultMTLBuffer(uint32_t queryCount) {
#pragma mark Construction
MVKDevice::MVKDevice(MVKPhysicalDevice* physicalDevice, const VkDeviceCreateInfo* pCreateInfo) : _mvkConfig() {
// MVKLogDebug("Creating MVKDevice. Elapsed time: %.6f ms.", mvkGetElapsedMilliseconds());
initPerformanceTracking();
@ -1485,7 +1487,7 @@ void MVKDevice::initPerformanceTracking() {
MVKDevice::~MVKDevice() {
mvkDestroyContainerContents(_queueFamilies);
[_globalVisibilityResultMTLBuffer release];
delete _commandResourceFactory;
_commandResourceFactory->destroy();
}

View File

@ -310,6 +310,9 @@ protected:
#pragma mark -
#pragma mark MVKSwapchainImage
/** Tracks a semaphore and fence for later signaling. */
typedef std::pair<MVKSemaphore*, MVKFence*> MVKSwapchainSignaler;
/** Indicates the relative availability of each image in the swapchain. */
typedef struct MVKSwapchainImageAvailability_t {
uint64_t acquisitionID; /**< When this image was last made available, relative to the other images in the swapchain. Smaller value is earlier. */
@ -327,14 +330,6 @@ public:
/** Returns the index of this image within the encompassing swapchain. */
inline uint32_t getSwapchainIndex() { return _swapchainIndex; }
/**
* Makes this image available for acquisition by the app.
*
* If any semaphores are waiting to be signaled when this image becomes available, the
* earliest semaphore is signaled, and this image remains unavailable for other uses.
*/
void makeAvailable();
/**
* Registers a semaphore and/or fence that will be signaled when this image becomes available.
* This function accepts both a semaphore and a fence, and either none, one, or both may be provided.
@ -373,14 +368,18 @@ protected:
id<CAMetalDrawable> getCAMetalDrawable();
void resetCAMetalDrawable();
void resetMetalSurface();
void signal(std::pair<MVKSemaphore*, MVKFence*> tracker);
void signal(MVKSwapchainSignaler& signaler);
void markAsTracked(MVKSwapchainSignaler& signaler);
void unmarkAsTracked(MVKSwapchainSignaler& signaler);
void makeAvailable();
void renderWatermark(id<MTLCommandBuffer> mtlCmdBuff);
MVKSwapchain* _swapchain;
uint32_t _swapchainIndex;
id<CAMetalDrawable> _mtlDrawable;
std::mutex _availabilityLock;
std::list<std::pair<MVKSemaphore*, MVKFence*>> _availabilityTrackers;
std::list<MVKSwapchainSignaler> _availabilitySignalers;
MVKSwapchainSignaler _preSignaled;
MVKSwapchainImageAvailability _availability;
};

View File

@ -203,9 +203,6 @@ VkResult MVKImage::pullFromDevice(VkDeviceSize offset, VkDeviceSize size) {
}
void* MVKImage::map(VkDeviceSize offset, VkDeviceSize size) {
// MVKLogDebug("Comparing map to image %p with memory offset %d and size %d.", this, _deviceMemoryOffset, _byteCount);
// if (doesContain(offset, size)) { MVKLogDebug("Mapping %d bytes to single image %p.", size, this); }
return (doesContain(offset, size)
? _deviceMemory->allocateMappedMemory(offset, size)
: VK_NULL_HANDLE);
@ -773,54 +770,77 @@ bool MVKSwapchainImageAvailability_t::operator< (const MVKSwapchainImageAvailabi
return acquisitionID < rhs.acquisitionID;
}
// Makes this image available for acquisition by the app.
// If any semaphores are waiting to be signaled when this image becomes available, the
// earliest semaphore is signaled, and this image remains unavailable for other uses.
void MVKSwapchainImage::makeAvailable() {
lock_guard<mutex> lock(_availabilityLock);
// Mark when this event happened, relative to that of other images
_availability.acquisitionID = _swapchain->getNextAcquisitionID();
// If there are no availability trackers waiting, mark this image as available.
// Otherwise, mark this image as unavailable, and extract and signal the first semaphore and fence.
if ( _availabilityTrackers.empty() ) {
_availability.isAvailable = true;
// Mark this image as available if no semaphores or fences are waiting to be signaled.
_availability.isAvailable = _availabilitySignalers.empty();
MVKSwapchainSignaler signaler;
if (_availability.isAvailable) {
// If this image is now available, signal the semaphore and fence that were associated
// with the last time this image was acquired while available. This is a workaround for
// when an app uses a single semaphore or fence for more than one swapchain image.
// Becuase the semaphore or fence will be signaled by more than one image, it will
// get out of sync, and the final use of the image would not be signaled as a result.
signaler = _preSignaled;
} else {
_availability.isAvailable = false;
auto tracker = _availabilityTrackers.front();
_availabilityTrackers.pop_front();
signal(tracker);
// If this image is not yet available, extract and signal the first semaphore and fence.
signaler = _availabilitySignalers.front();
_availabilitySignalers.pop_front();
}
// MVKLogDebug("Finished presentation of MVKSwapchainImage %p. Elapsed time: %.6f ms.", this, mvkGetElapsedMilliseconds());
// Signal the semaphore and fence, and let them know they are no longer being tracked.
signal(signaler);
unmarkAsTracked(signaler);
// MVKLogDebug("Signaling%s swapchain image %p semaphore %p from present, with %lu remaining semaphores.", (_availability.isAvailable ? " pre-signaled" : ""), this, signaler.first, _availabilitySignalers.size());
}
void MVKSwapchainImage::signalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) {
lock_guard<mutex> lock(_availabilityLock);
// MVKLogDebug("Requesting signal when MVKSwapchain image %p is free to semaphore %p and fence %p.", this, semaphore, fence);
auto tracker = make_pair(semaphore, fence);
auto signaler = make_pair(semaphore, fence);
if (_availability.isAvailable) {
_availability.isAvailable = false;
signal(tracker);
signal(signaler);
_preSignaled = signaler;
} else {
_availabilityTrackers.push_back(tracker);
_availabilitySignalers.push_back(signaler);
}
markAsTracked(signaler);
// MVKLogDebug("%s swapchain image %p semaphore %p in acquire with %lu other semaphores.", (_availability.isAvailable ? "Signaling" : "Tracking"), this, semaphore, _availabilitySignalers.size());
}
/** Signal either or both of the semaphore and fence in the specified tracker pair. */
void MVKSwapchainImage::signal(pair<MVKSemaphore*, MVKFence*> tracker) {
void MVKSwapchainImage::signal(MVKSwapchainSignaler& signaler) {
if (signaler.first) { signaler.first->signal(); }
if (signaler.second) { signaler.second->signal(); }
}
MVKSemaphore* semaphore = tracker.first;
if (semaphore) { semaphore->signal(); }
// Tell the semaphore and fence that they are being tracked for future signaling.
void MVKSwapchainImage::markAsTracked(MVKSwapchainSignaler& signaler) {
if (signaler.first) { signaler.first->wasAddedToSignaler(); }
if (signaler.second) { signaler.second->wasAddedToSignaler(); }
}
MVKFence* fence = tracker.second;
if (fence) { fence->signal(); }
// MVKLogDebug("MVKSwapchainImage %p signalling semaphore %p and fence %p.", this, semaphore, fence);
// Tell the semaphore and fence that they are no longer being tracked for future signaling.
void MVKSwapchainImage::unmarkAsTracked(MVKSwapchainSignaler& signaler) {
if (signaler.first) { signaler.first->wasRemovedFromSignaler(); }
if (signaler.second) { signaler.second->wasRemovedFromSignaler(); }
}
const MVKSwapchainImageAvailability* MVKSwapchainImage::getAvailability() {
lock_guard<mutex> lock(_availabilityLock);
_availability.waitCount = (uint32_t)_availabilityTrackers.size();
_availability.waitCount = (uint32_t)_availabilitySignalers.size();
return &_availability;
}
@ -833,12 +853,7 @@ const MVKSwapchainImageAvailability* MVKSwapchainImage::getAvailability() {
* This implementation retrieves a MTLTexture from the CAMetalDrawable.
*/
id<MTLTexture> MVKSwapchainImage::newMTLTexture() {
// return [[getCAMetalDrawable() texture] retain];
id<CAMetalDrawable> mtlDrwbl = getCAMetalDrawable();
id<MTLTexture> mtlTex = [[mtlDrwbl texture] retain];
// MVKLogDebug("Retrieved MTLTexture %p from CAMetalDrawable %p in MVKSwapchain image: %p. Elapsed time: %.6f ms.",
// mtlTex, mtlDrwbl, this, mvkGetElapsedMilliseconds());
return mtlTex;
return [[getCAMetalDrawable() texture] retain];
}
id<CAMetalDrawable> MVKSwapchainImage::getCAMetalDrawable() {
@ -847,15 +862,12 @@ id<CAMetalDrawable> MVKSwapchainImage::getCAMetalDrawable() {
_mtlDrawable = [_swapchain->getNextCAMetalDrawable() retain]; // retained
}
MVKAssert(_mtlDrawable, "Could not aquire an available CAMetalDrawable from the CAMetalLayer in MVKSwapchain image: %p.", this);
// MVKLogDebug("Retrieved CAMetalDrawable %p with retain count %d in MVKSwapchain image: %p. Elapsed time: %.6f ms.",
// _mtlDrawable, _mtlDrawable.retainCount, this, mvkGetElapsedMilliseconds());
}
return _mtlDrawable;
}
void MVKSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff) {
// MVKLogDebug("Presenting CAMetalDrawable: %s with retain count %d in MVKSwapchain image: %p. Elapsed time: %.6f ms.",
// _mtlDrawable.description.UTF8String, _mtlDrawable.retainCount, this, mvkGetElapsedMilliseconds());
// MVKLogDebug("Presenting swapchain image %p from present.", this);
id<CAMetalDrawable> mtlDrawable = getCAMetalDrawable();
_swapchain->willPresentSurface(getMTLTexture(), mtlCmdBuff);
@ -876,16 +888,12 @@ void MVKSwapchainImage::presentCAMetalDrawable(id<MTLCommandBuffer> mtlCmdBuff)
/** Removes and releases the Metal drawable object, so that it can be lazily created by getCAMetalDrawable(). */
void MVKSwapchainImage::resetCAMetalDrawable() {
// MVKLogDebug("Releasing MTLDrawable: %s with retain count %d in MVKSwapchain image: %p.",
// _mtlDrawable.description.UTF8String, _mtlDrawable.retainCount, this);
[_mtlDrawable release];
_mtlDrawable = nil;
}
/** Resets the MTLTexture and CAMetalDrawable underlying this image. */
void MVKSwapchainImage::resetMetalSurface() {
// MVKLogDebug("Resetting MTLTexture: %p and CAMetalDrawable %p in MVKSwapchain image: %p. Elapsed time: %.6f ms.",
// _mtlTexture, _mtlDrawable, this, mvkGetElapsedMilliseconds());
resetMTLTexture(); // Release texture first so drawable will be last to release it
resetCAMetalDrawable();
}
@ -900,10 +908,9 @@ MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device,
_swapchainIndex = _swapchain->getImageCount();
_availability.acquisitionID = _swapchain->getNextAcquisitionID();
_availability.isAvailable = true;
_preSignaled = make_pair(nullptr, nullptr);
_mtlDrawable = nil;
_canSupportMTLTextureView = false; // Override...swapchains never support Metal image view.
// MVKLogDebug("Created MVKSwapchain image %p.", this);
}
MVKSwapchainImage::~MVKSwapchainImage() {

View File

@ -269,8 +269,12 @@ void MVKQueueSubmission::recordResult(VkResult vkResult) {
#pragma mark -
#pragma mark MVKQueueCommandBufferSubmission
std::atomic<uint32_t> _subCount;
void MVKQueueCommandBufferSubmission::execute() {
// MVKLogDebug("Executing submission %p.", this);
// Execute each command buffer, or if no command buffers, but a fence or semaphores,
// create an empty MTLCommandBuffer to trigger the semaphores and fence.
if ( !_cmdBuffers.empty() ) {
@ -325,6 +329,8 @@ NSString* MVKQueueCommandBufferSubmission::getMTLCommandBufferName() {
void MVKQueueCommandBufferSubmission::finish() {
// MVKLogDebug("Finishing submission %p. Submission count %u.", this, _subCount--);
// Signal each of the signal semaphores.
for (auto& ss : _signalSemaphores) { ss->signal(); }
@ -364,6 +370,8 @@ MVKQueueCommandBufferSubmission::MVKQueueCommandBufferSubmission(MVKDevice* devi
_fence = (MVKFence*)fence;
_cmdBuffUse= cmdBuffUse;
_activeMTLCommandBuffer = nil;
// MVKLogDebug("Creating submission %p. Submission count %u.", this, ++_subCount);
}

View File

@ -73,12 +73,9 @@ VkResult MVKSwapchain::acquireNextImageKHR(uint64_t timeout,
minWaitIndex = mvkSCImg->getSwapchainIndex();
}
}
// MVKLogDebug("Selected MVKSwapchainImage %p, index: %d to trigger semaphore %p and fence %p", _surfaceImages[minWaitIndex], minWaitIndex, semaphore, fence);
*pImageIndex = minWaitIndex; // Return the index of the image with the shortest wait
_surfaceImages[minWaitIndex]->signalWhenAvailable((MVKSemaphore*)semaphore, (MVKFence*)fence);
return getHasSurfaceSizeChanged() ? VK_SUBOPTIMAL_KHR : VK_SUCCESS;
}

View File

@ -96,11 +96,45 @@ private:
};
#pragma mark -
#pragma mark MVKSignalable
/** Abstract class for Vulkan semaphores and fences. */
class MVKSignalable : public MVKBaseDeviceObject {
public:
/* Called when this object has been added to a tracker for later signaling. */
void wasAddedToSignaler();
/**
* Called when this object has been removed from a tracker for later signaling.
* If this object was destroyed while this signal was pending, it will now be deleted.
*/
void wasRemovedFromSignaler();
/** If this object is waiting to be signaled, deletion will be deferred until then. */
void destroy() override;
#pragma mark Construction
MVKSignalable(MVKDevice* device) : MVKBaseDeviceObject(device) {}
protected:
void maybeDestroy();
std::mutex _signalerLock;
uint32_t _signalerCount = 0;
bool _isDestroyed = false;
};
#pragma mark -
#pragma mark MVKSemaphore
/** Represents a Vulkan semaphore. */
class MVKSemaphore : public MVKBaseDeviceObject {
class MVKSemaphore : public MVKSignalable {
public:
@ -121,7 +155,7 @@ public:
#pragma mark Construction
MVKSemaphore(MVKDevice* device, const VkSemaphoreCreateInfo* pCreateInfo)
: MVKBaseDeviceObject(device), _blocker(false, 1) {}
: MVKSignalable(device), _blocker(false, 1) {}
protected:
MVKSemaphoreImpl _blocker;
@ -132,7 +166,7 @@ protected:
#pragma mark MVKFence
/** Represents a Vulkan fence. */
class MVKFence : public MVKBaseDeviceObject {
class MVKFence : public MVKSignalable {
public:
@ -165,7 +199,7 @@ public:
#pragma mark Construction
MVKFence(MVKDevice* device, const VkFenceCreateInfo* pCreateInfo) : MVKBaseDeviceObject(device),
MVKFence(MVKDevice* device, const VkFenceCreateInfo* pCreateInfo) : MVKSignalable(device),
_isSignaled(mvkAreFlagsEnabled(pCreateInfo->flags, VK_FENCE_CREATE_SIGNALED_BIT)) {}
~MVKFence() override;

View File

@ -31,7 +31,7 @@ void MVKSemaphoreImpl::release() {
// Either decrement the reservation counter, or clear it altogether
if (_shouldWaitAll) {
_reservationCount--;
if (_reservationCount > 0) { _reservationCount--; }
} else {
_reservationCount = 0;
}
@ -65,6 +65,36 @@ bool MVKSemaphoreImpl::wait(uint64_t timeout, bool reserveAgain) {
}
#pragma mark -
#pragma mark MVKSignalable
void MVKSignalable::wasAddedToSignaler() {
lock_guard<mutex> lock(_signalerLock);
_signalerCount++;
}
void MVKSignalable::wasRemovedFromSignaler() {
lock_guard<mutex> lock(_signalerLock);
if (_signalerCount > 0) { _signalerCount--; }
maybeDestroy();
}
void MVKSignalable::destroy() {
lock_guard<mutex> lock(_signalerLock);
_isDestroyed = true;
maybeDestroy();
}
void MVKSignalable::maybeDestroy() {
if (_isDestroyed && _signalerCount == 0) {
MVKBaseDeviceObject::destroy();
}
}
#pragma mark -
#pragma mark MVKSemaphore

View File

@ -37,6 +37,9 @@ public:
/** Returns the name of the class of which this object is an instance. */
std::string className();
/** Destroys this object. Default behaviour simply deletes it. Subclasses may override to delay deletion. */
virtual void destroy() { delete this; }
virtual ~MVKBaseObject() {}
};

View File

@ -60,8 +60,7 @@ MVK_PUBLIC_SYMBOL void vkDestroyInstance(
VkInstance instance,
const VkAllocationCallbacks* pAllocator) {
MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance);
delete mvkInst;
MVKInstance::getMVKInstance(instance)->destroy();
}
MVK_PUBLIC_SYMBOL VkResult vkEnumeratePhysicalDevices(
@ -168,8 +167,7 @@ MVK_PUBLIC_SYMBOL void vkDestroyDevice(
VkDevice device,
const VkAllocationCallbacks* pAllocator) {
MVKDevice* mvkDev = MVKDevice::getMVKDevice(device);
delete mvkDev;
MVKDevice::getMVKDevice(device)->destroy();
}
MVK_PUBLIC_SYMBOL VkResult vkEnumerateInstanceExtensionProperties(