Skip to content

Instantly share code, notes, and snippets.

@mlfarrell
Created December 10, 2018 01:37
Show Gist options
  • Save mlfarrell/1e7f771673619cc2c83773577bde5fc6 to your computer and use it in GitHub Desktop.
Save mlfarrell/1e7f771673619cc2c83773577bde5fc6 to your computer and use it in GitHub Desktop.
Vulkan async resource handles
struct VulkanAsyncResourceHandle
{
union
{
VkFence fence;
VkBuffer buffer;
VkImage image;
VkSampler sampler;
VkCommandBuffer commandBuffer;
};
union
{
VkImageView imageView;
VkCommandPool commandPool;
};
VulkanMemoryManager::Suballocation alloc;
VkDevice device;
enum Type
{
FENCE, BUFFER, IMAGE, SAMPLER, COMMAND_BUFFER
};
VulkanAsyncResourceHandle(VulkanAsyncResourceMonitor *monitor, Type type, VkDevice device);
static VulkanAsyncResourceHandle *newBuffer(VulkanAsyncResourceMonitor *monitor, VkDevice device, VkBuffer buffer, VulkanMemoryManager::Suballocation alloc);
static VulkanAsyncResourceHandle *newImage(VulkanAsyncResourceMonitor *monitor, VkDevice device, VkImage image, VkImageView imageView, VulkanMemoryManager::Suballocation alloc);
static VulkanAsyncResourceHandle *newSampler(VulkanAsyncResourceMonitor *monitor, VkDevice device, VkSampler sampler);
static VulkanAsyncResourceHandle *newCommandBuffer(VulkanAsyncResourceMonitor *monitor, VkDevice device, VkCommandBuffer commandBuffer, VkCommandPool pool);
static VulkanAsyncResourceHandle *newFence(VulkanAsyncResourceMonitor *monitor, VkDevice device, VkFence fence);
void retain();
bool release();
void dealloc();
VulkanAsyncResourceMonitor *monitor;
Type type;
std::atomic_int refCount;
};
void VulkanAsyncResourceHandle::dealloc()
{
switch(type)
{
case FENCE:
vkDestroyFence(device, fence, nullptr);
break;
case BUFFER:
vkDestroyBuffer(device, buffer, nullptr);
break;
case IMAGE:
vkDestroyImage(device, image, nullptr);
if(imageView)
vkDestroyImageView(device, imageView, nullptr);
break;
case SAMPLER:
vkDestroySampler(device, sampler, nullptr);
break;
case COMMAND_BUFFER:
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); //you may need to schedule this out to the alloc'ing thread
break;
}
if(alloc)
{
monitor->memoryManager->free(alloc);
}
}
////////////// Usage examples ////////////////////////////////////////////////////////////////////////////////
//Creating resource handles///////////////////////////////////////////////////////////////////////////////////////
auto fenceHandle = VulkanAsyncResourceHandle::newFence(resourceMonitor, device, transferFence);
auto cmdBufHandle = VulkanAsyncResourceHandle::newCommandBuffer(resourceMonitor, device, currentTransferCommandBuffer.first, transferCommandPool);
VulkanAsyncResourceCollection transferResources(resourceMonitor, fenceHandle, {
cmdBufHandle, fenceHandle
});
resourceMonitor->append(move(transferResources), true);
fenceHandle->release();
cmdBufHandle->release();
///////////
imageHandle = VulkanAsyncResourceHandle::newImage(instance->getResourceMonitor(), device, image, imageView, imageAllocation);
auto resourceMonitor = instance->getResourceMonitor();
auto fenceHandle = VulkanAsyncResourceHandle::newFence(resourceMonitor, device, transferFence);
auto cmdBufHandle = VulkanAsyncResourceHandle::newCommandBuffer(resourceMonitor, device, commandBuffer, commandPool);
VulkanAsyncResourceCollection transferResources(resourceMonitor, fenceHandle, {
stagingBufferHandle, imageHandle,
cmdBufHandle, fenceHandle
});
resourceMonitor->append(move(transferResources));
fenceHandle->release();
cmdBufHandle->release();
//Polling for and releasing resource handles (done in resource monitoring bg thread)////////////////////////////////////
bool VulkanAsyncResourceCollection::check(VkDevice device)
{
VkResult status = VK_SUCCESS;
if(!frame)
{
if(!fence)
{
return false;
}
status = vkGetFenceStatus(device, fence->fence);
}
else
{
status = (monitor->completedFrame.load() > frameId) ? VK_SUCCESS : VK_NOT_READY;
}
if(status == VK_SUCCESS)
{
for(auto &handle : handles) if(handle)
{
if(handle->release())
{
delete handle;
handle = nullptr;
}
}
if(!frame)
{
if(fence->release())
{
delete fence;
fence = nullptr;
}
}
return true;
}
else if(status == VK_ERROR_DEVICE_LOST)
{
throw std::runtime_error("VulkanAsyncResourceFence::checkFence encountered VK_ERROR_DEVICE_LOST");
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment