Fix texturesparseresidency memory and image layout bugs
This commit is contained in:
parent
93328016e9
commit
1f6d425933
2 changed files with 45 additions and 18 deletions
|
|
@ -29,11 +29,11 @@ bool VirtualTexturePage::resident()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate Vulkan memory for the virtual page
|
// Allocate Vulkan memory for the virtual page
|
||||||
void VirtualTexturePage::allocate(VkDevice device, uint32_t memoryTypeIndex)
|
bool VirtualTexturePage::allocate(VkDevice device, uint32_t memoryTypeIndex)
|
||||||
{
|
{
|
||||||
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
imageMemoryBind = {};
|
imageMemoryBind = {};
|
||||||
|
|
@ -52,16 +52,20 @@ void VirtualTexturePage::allocate(VkDevice device, uint32_t memoryTypeIndex)
|
||||||
imageMemoryBind.subresource = subResource;
|
imageMemoryBind.subresource = subResource;
|
||||||
imageMemoryBind.extent = extent;
|
imageMemoryBind.extent = extent;
|
||||||
imageMemoryBind.offset = offset;
|
imageMemoryBind.offset = offset;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release Vulkan memory allocated for this page
|
// Release Vulkan memory allocated for this page
|
||||||
void VirtualTexturePage::release(VkDevice device)
|
bool VirtualTexturePage::release(VkDevice device)
|
||||||
{
|
{
|
||||||
|
del= false;
|
||||||
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
vkFreeMemory(device, imageMemoryBind.memory, nullptr);
|
vkFreeMemory(device, imageMemoryBind.memory, nullptr);
|
||||||
imageMemoryBind.memory = VK_NULL_HANDLE;
|
imageMemoryBind.memory = VK_NULL_HANDLE;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -81,19 +85,24 @@ VirtualTexturePage* VirtualTexture::addPage(VkOffset3D offset, VkExtent3D extent
|
||||||
newPage.imageMemoryBind = {};
|
newPage.imageMemoryBind = {};
|
||||||
newPage.imageMemoryBind.offset = offset;
|
newPage.imageMemoryBind.offset = offset;
|
||||||
newPage.imageMemoryBind.extent = extent;
|
newPage.imageMemoryBind.extent = extent;
|
||||||
|
newPage.del = false;
|
||||||
pages.push_back(newPage);
|
pages.push_back(newPage);
|
||||||
return &pages.back();
|
return &pages.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call before sparse binding to update memory bind list etc.
|
// Call before sparse binding to update memory bind list etc.
|
||||||
void VirtualTexture::updateSparseBindInfo()
|
void VirtualTexture::updateSparseBindInfo(std::vector<VirtualTexturePage> &bindingChangedPages, bool del)
|
||||||
{
|
{
|
||||||
// Update list of memory-backed sparse image memory binds
|
// Update list of memory-backed sparse image memory binds
|
||||||
//sparseImageMemoryBinds.resize(pages.size());
|
//sparseImageMemoryBinds.resize(pages.size());
|
||||||
sparseImageMemoryBinds.clear();
|
sparseImageMemoryBinds.clear();
|
||||||
for (auto page : pages)
|
for (auto page : bindingChangedPages)
|
||||||
{
|
{
|
||||||
sparseImageMemoryBinds.push_back(page.imageMemoryBind);
|
sparseImageMemoryBinds.push_back(page.imageMemoryBind);
|
||||||
|
if (del)
|
||||||
|
{
|
||||||
|
sparseImageMemoryBinds[sparseImageMemoryBinds.size() - 1].memory = VK_NULL_HANDLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Update sparse bind info
|
// Update sparse bind info
|
||||||
bindSparseInfo = vks::initializers::bindSparseInfo();
|
bindSparseInfo = vks::initializers::bindSparseInfo();
|
||||||
|
|
@ -186,6 +195,7 @@ void VulkanExample::prepareSparseTexture(uint32_t width, uint32_t height, uint32
|
||||||
texture.layerCount = layerCount;
|
texture.layerCount = layerCount;
|
||||||
texture.format = format;
|
texture.format = format;
|
||||||
|
|
||||||
|
texture.subRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, texture.mipLevels, 0, 1 };
|
||||||
// Get device properties for the requested texture format
|
// Get device properties for the requested texture format
|
||||||
VkFormatProperties formatProperties;
|
VkFormatProperties formatProperties;
|
||||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
|
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
|
||||||
|
|
@ -235,7 +245,7 @@ void VulkanExample::prepareSparseTexture(uint32_t width, uint32_t height, uint32
|
||||||
VK_CHECK_RESULT(vkCreateImage(device, &sparseImageCreateInfo, nullptr, &texture.image));
|
VK_CHECK_RESULT(vkCreateImage(device, &sparseImageCreateInfo, nullptr, &texture.image));
|
||||||
|
|
||||||
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, texture.subRange);
|
||||||
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
||||||
|
|
||||||
// Get memory requirements
|
// Get memory requirements
|
||||||
|
|
@ -420,7 +430,7 @@ void VulkanExample::prepareSparseTexture(uint32_t width, uint32_t height, uint32
|
||||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &bindSparseSemaphore));
|
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &bindSparseSemaphore));
|
||||||
|
|
||||||
// Prepare bind sparse info for reuse in queue submission
|
// Prepare bind sparse info for reuse in queue submission
|
||||||
texture.updateSparseBindInfo();
|
texture.updateSparseBindInfo(texture.pages);
|
||||||
|
|
||||||
// Bind to queue
|
// Bind to queue
|
||||||
// todo: in draw?
|
// todo: in draw?
|
||||||
|
|
@ -732,7 +742,7 @@ void VulkanExample::uploadContent(VirtualTexturePage page, VkImage image)
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
VkBufferImageCopy region{};
|
VkBufferImageCopy region{};
|
||||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.imageSubresource.layerCount = 1;
|
region.imageSubresource.layerCount = 1;
|
||||||
|
|
@ -740,7 +750,7 @@ void VulkanExample::uploadContent(VirtualTexturePage page, VkImage image)
|
||||||
region.imageOffset = page.offset;
|
region.imageOffset = page.offset;
|
||||||
region.imageExtent = page.extent;
|
region.imageExtent = page.extent;
|
||||||
vkCmdCopyBufferToImage(copyCmd, imageBuffer.buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyBufferToImage(copyCmd, imageBuffer.buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||||
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
||||||
|
|
||||||
imageBuffer.destroy();
|
imageBuffer.destroy();
|
||||||
|
|
@ -754,16 +764,20 @@ void VulkanExample::fillRandomPages()
|
||||||
std::uniform_real_distribution<float> rndDist(0.0f, 1.0f);
|
std::uniform_real_distribution<float> rndDist(0.0f, 1.0f);
|
||||||
|
|
||||||
std::vector<VirtualTexturePage> updatedPages;
|
std::vector<VirtualTexturePage> updatedPages;
|
||||||
|
std::vector<VirtualTexturePage> bindingChangedPages;
|
||||||
for (auto& page : texture.pages) {
|
for (auto& page : texture.pages) {
|
||||||
if (rndDist(rndEngine) < 0.5f) {
|
if (rndDist(rndEngine) < 0.5f) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
page.allocate(device, texture.memoryTypeIndex);
|
if (page.allocate(device, texture.memoryTypeIndex))
|
||||||
|
{
|
||||||
|
bindingChangedPages.push_back(page);
|
||||||
|
}
|
||||||
updatedPages.push_back(page);
|
updatedPages.push_back(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update sparse queue binding
|
// Update sparse queue binding
|
||||||
texture.updateSparseBindInfo();
|
texture.updateSparseBindInfo(bindingChangedPages);
|
||||||
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(VK_FLAGS_NONE);
|
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(VK_FLAGS_NONE);
|
||||||
VkFence fence;
|
VkFence fence;
|
||||||
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
|
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
|
||||||
|
|
@ -849,7 +863,7 @@ void VulkanExample::fillMipTail()
|
||||||
}
|
}
|
||||||
|
|
||||||
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||||
vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
|
||||||
VkBufferImageCopy region{};
|
VkBufferImageCopy region{};
|
||||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
region.imageSubresource.layerCount = 1;
|
region.imageSubresource.layerCount = 1;
|
||||||
|
|
@ -857,7 +871,7 @@ void VulkanExample::fillMipTail()
|
||||||
region.imageOffset = {};
|
region.imageOffset = {};
|
||||||
region.imageExtent = { width, height, depth };
|
region.imageExtent = { width, height, depth };
|
||||||
vkCmdCopyBufferToImage(copyCmd, imageBuffer.buffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
vkCmdCopyBufferToImage(copyCmd, imageBuffer.buffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||||
vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
vks::tools::setImageLayout(copyCmd, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, texture.subRange, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
||||||
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
||||||
|
|
||||||
imageBuffer.destroy();
|
imageBuffer.destroy();
|
||||||
|
|
@ -872,21 +886,32 @@ void VulkanExample::flushRandomPages()
|
||||||
std::uniform_real_distribution<float> rndDist(0.0f, 1.0f);
|
std::uniform_real_distribution<float> rndDist(0.0f, 1.0f);
|
||||||
|
|
||||||
std::vector<VirtualTexturePage> updatedPages;
|
std::vector<VirtualTexturePage> updatedPages;
|
||||||
|
std::vector<VirtualTexturePage> bindingChangedPages;
|
||||||
for (auto& page : texture.pages)
|
for (auto& page : texture.pages)
|
||||||
{
|
{
|
||||||
if (rndDist(rndEngine) < 0.5f) {
|
if (rndDist(rndEngine) < 0.5f) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
page.release(device);
|
if (page.imageMemoryBind.memory != VK_NULL_HANDLE){
|
||||||
|
page.del = true;
|
||||||
|
bindingChangedPages.push_back(page);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update sparse queue binding
|
// Update sparse queue binding
|
||||||
texture.updateSparseBindInfo();
|
texture.updateSparseBindInfo(bindingChangedPages, true);
|
||||||
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(VK_FLAGS_NONE);
|
VkFenceCreateInfo fenceInfo = vks::initializers::fenceCreateInfo(VK_FLAGS_NONE);
|
||||||
VkFence fence;
|
VkFence fence;
|
||||||
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
|
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
|
||||||
vkQueueBindSparse(queue, 1, &texture.bindSparseInfo, fence);
|
vkQueueBindSparse(queue, 1, &texture.bindSparseInfo, fence);
|
||||||
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
|
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
|
||||||
|
for (auto& page : texture.pages)
|
||||||
|
{
|
||||||
|
if (page.del)
|
||||||
|
{
|
||||||
|
page.release(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay)
|
void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay)
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,12 @@ struct VirtualTexturePage
|
||||||
uint32_t mipLevel; // Mip level that this page belongs to
|
uint32_t mipLevel; // Mip level that this page belongs to
|
||||||
uint32_t layer; // Array layer that this page belongs to
|
uint32_t layer; // Array layer that this page belongs to
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
bool del;
|
||||||
|
|
||||||
VirtualTexturePage();
|
VirtualTexturePage();
|
||||||
bool resident();
|
bool resident();
|
||||||
void allocate(VkDevice device, uint32_t memoryTypeIndex);
|
bool allocate(VkDevice device, uint32_t memoryTypeIndex);
|
||||||
void release(VkDevice device);
|
bool release(VkDevice device);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Virtual texture object containing all pages
|
// Virtual texture object containing all pages
|
||||||
|
|
@ -55,7 +56,7 @@ struct VirtualTexture
|
||||||
} mipTailInfo;
|
} mipTailInfo;
|
||||||
|
|
||||||
VirtualTexturePage *addPage(VkOffset3D offset, VkExtent3D extent, const VkDeviceSize size, const uint32_t mipLevel, uint32_t layer);
|
VirtualTexturePage *addPage(VkOffset3D offset, VkExtent3D extent, const VkDeviceSize size, const uint32_t mipLevel, uint32_t layer);
|
||||||
void updateSparseBindInfo();
|
void updateSparseBindInfo(std::vector<VirtualTexturePage> &bindingChangedPages, bool del = false);
|
||||||
// @todo: replace with dtor?
|
// @todo: replace with dtor?
|
||||||
void destroy();
|
void destroy();
|
||||||
};
|
};
|
||||||
|
|
@ -73,6 +74,7 @@ public:
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
uint32_t mipLevels;
|
uint32_t mipLevels;
|
||||||
uint32_t layerCount;
|
uint32_t layerCount;
|
||||||
|
VkImageSubresourceRange subRange;
|
||||||
} texture;
|
} texture;
|
||||||
|
|
||||||
vkglTF::Model plane;
|
vkglTF::Model plane;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue