Fill mip tail
This commit is contained in:
parent
62070aa9f4
commit
b67bfa6f88
1 changed files with 115 additions and 14 deletions
|
|
@ -59,7 +59,6 @@ struct VirtualTexturePage
|
||||||
{
|
{
|
||||||
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
||||||
{
|
{
|
||||||
//std::cout << "Page " << index << " already allocated" << std::endl;
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -104,6 +103,7 @@ struct VirtualTexture
|
||||||
VkSparseImageMemoryBindInfo imageMemoryBindInfo; // Sparse image memory bind info
|
VkSparseImageMemoryBindInfo imageMemoryBindInfo; // Sparse image memory bind info
|
||||||
VkSparseImageOpaqueMemoryBindInfo opaqueMemoryBindInfo; // Sparse image opaque memory bind info (mip tail)
|
VkSparseImageOpaqueMemoryBindInfo opaqueMemoryBindInfo; // Sparse image opaque memory bind info (mip tail)
|
||||||
uint32_t mipTailStart; // First mip level in mip tail
|
uint32_t mipTailStart; // First mip level in mip tail
|
||||||
|
VkSparseImageMemoryRequirements sparseImageMemoryRequirements; // @todo: Comment
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
@ -145,15 +145,12 @@ struct VirtualTexture
|
||||||
bindSparseInfo.imageBindCount = (imageMemoryBindInfo.bindCount > 0) ? 1 : 0;
|
bindSparseInfo.imageBindCount = (imageMemoryBindInfo.bindCount > 0) ? 1 : 0;
|
||||||
bindSparseInfo.pImageBinds = &imageMemoryBindInfo;
|
bindSparseInfo.pImageBinds = &imageMemoryBindInfo;
|
||||||
|
|
||||||
// Opaque image memory binds (mip tail)
|
// Opaque image memory binds for the mip tail
|
||||||
// @todo
|
|
||||||
/*
|
|
||||||
opaqueMemoryBindInfo.image = image;
|
opaqueMemoryBindInfo.image = image;
|
||||||
opaqueMemoryBindInfo.bindCount = static_cast<uint32_t>(opaqueMemoryBinds.size());
|
opaqueMemoryBindInfo.bindCount = static_cast<uint32_t>(opaqueMemoryBinds.size());
|
||||||
opaqueMemoryBindInfo.pBinds = opaqueMemoryBinds.data();
|
opaqueMemoryBindInfo.pBinds = opaqueMemoryBinds.data();
|
||||||
bindSparseInfo.imageOpaqueBindCount = (opaqueMemoryBindInfo.bindCount > 0) ? 1 : 0;
|
bindSparseInfo.imageOpaqueBindCount = (opaqueMemoryBindInfo.bindCount > 0) ? 1 : 0;
|
||||||
bindSparseInfo.pImageOpaqueBinds = &opaqueMemoryBindInfo;
|
bindSparseInfo.pImageOpaqueBinds = &opaqueMemoryBindInfo;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release all Vulkan resources
|
// Release all Vulkan resources
|
||||||
|
|
@ -171,7 +168,6 @@ struct VirtualTexture
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t memoryTypeIndex;
|
uint32_t memoryTypeIndex;
|
||||||
int32_t lastFilledMip = 0;
|
|
||||||
|
|
||||||
class VulkanExample : public VulkanExampleBase
|
class VulkanExample : public VulkanExampleBase
|
||||||
{
|
{
|
||||||
|
|
@ -263,7 +259,6 @@ public:
|
||||||
texture.width = width;
|
texture.width = width;
|
||||||
texture.height = height;
|
texture.height = height;
|
||||||
texture.mipLevels = floor(log2(std::max(width, height))) + 1;
|
texture.mipLevels = floor(log2(std::max(width, height))) + 1;
|
||||||
texture.mipLevels = 1;
|
|
||||||
texture.layerCount = layerCount;
|
texture.layerCount = layerCount;
|
||||||
texture.format = format;
|
texture.format = format;
|
||||||
|
|
||||||
|
|
@ -361,8 +356,6 @@ public:
|
||||||
texture.mipTailStart = reqs.imageMipTailFirstLod;
|
texture.mipTailStart = reqs.imageMipTailFirstLod;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastFilledMip = texture.mipTailStart - 1;
|
|
||||||
|
|
||||||
// Get sparse image requirements for the color aspect
|
// Get sparse image requirements for the color aspect
|
||||||
VkSparseImageMemoryRequirements sparseMemoryReq;
|
VkSparseImageMemoryRequirements sparseMemoryReq;
|
||||||
bool colorAspectFound = false;
|
bool colorAspectFound = false;
|
||||||
|
|
@ -390,9 +383,13 @@ public:
|
||||||
uint32_t sparseBindsCount = static_cast<uint32_t>(sparseImageMemoryReqs.size / sparseImageMemoryReqs.alignment);
|
uint32_t sparseBindsCount = static_cast<uint32_t>(sparseImageMemoryReqs.size / sparseImageMemoryReqs.alignment);
|
||||||
std::vector<VkSparseMemoryBind> sparseMemoryBinds(sparseBindsCount);
|
std::vector<VkSparseMemoryBind> sparseMemoryBinds(sparseBindsCount);
|
||||||
|
|
||||||
|
texture.sparseImageMemoryRequirements = sparseMemoryReq;
|
||||||
|
|
||||||
// Check if the format has a single mip tail for all layers or one mip tail for each layer
|
// Check if the format has a single mip tail for all layers or one mip tail for each layer
|
||||||
// The mip tail contains all mip levels > sparseMemoryReq.imageMipTailFirstLod
|
// The mip tail contains all mip levels > sparseMemoryReq.imageMipTailFirstLod
|
||||||
bool singleMipTail = sparseMemoryReq.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT;
|
bool singleMipTail = sparseMemoryReq.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT;
|
||||||
|
// @todo: Comment
|
||||||
|
bool alingedMipSize = sparseMemoryReq.formatProperties.flags & VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT;
|
||||||
|
|
||||||
// Sparse bindings for each mip level of all layers outside of the mip tail
|
// Sparse bindings for each mip level of all layers outside of the mip tail
|
||||||
for (uint32_t layer = 0; layer < texture.layerCount; layer++)
|
for (uint32_t layer = 0; layer < texture.layerCount; layer++)
|
||||||
|
|
@ -814,7 +811,19 @@ public:
|
||||||
rndVal[1] = (uint8_t)rndDist(rndEngine);
|
rndVal[1] = (uint8_t)rndDist(rndEngine);
|
||||||
rndVal[2] = (uint8_t)rndDist(rndEngine);
|
rndVal[2] = (uint8_t)rndDist(rndEngine);
|
||||||
}
|
}
|
||||||
rndVal[3] = 0;
|
rndVal[3] = 255;
|
||||||
|
|
||||||
|
switch (page.mipLevel) {
|
||||||
|
case 0:
|
||||||
|
rndVal[0] = rndVal[1] = rndVal[2] = 255;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rndVal[0] = rndVal[1] = rndVal[2] = 200;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rndVal[0] = rndVal[1] = rndVal[2] = 150;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t y = 0; y < page.extent.height; y++)
|
for (uint32_t y = 0; y < page.extent.height; y++)
|
||||||
{
|
{
|
||||||
|
|
@ -849,8 +858,7 @@ public:
|
||||||
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;
|
||||||
for (auto& page : texture.pages)
|
for (auto& page : texture.pages) {
|
||||||
{
|
|
||||||
if (rndDist(rndEngine) < 0.5f) {
|
if (rndDist(rndEngine) < 0.5f) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -871,6 +879,96 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fillMipTail()
|
||||||
|
{
|
||||||
|
//@todo: WIP
|
||||||
|
VkDeviceSize imageMipTailSize = texture.sparseImageMemoryRequirements.imageMipTailSize;
|
||||||
|
VkDeviceSize imageMipTailOffset = texture.sparseImageMemoryRequirements.imageMipTailOffset;
|
||||||
|
// Stride between memory bindings for each mip level if not single mip tail (VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT not set)
|
||||||
|
VkDeviceSize imageMipTailStride = texture.sparseImageMemoryRequirements.imageMipTailStride;
|
||||||
|
|
||||||
|
VkSparseImageMemoryBind mipTailimageMemoryBind{};
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocInfo = vks::initializers::memoryAllocateInfo();
|
||||||
|
allocInfo.allocationSize = imageMipTailSize;
|
||||||
|
allocInfo.memoryTypeIndex = memoryTypeIndex;
|
||||||
|
VK_CHECK_RESULT(vkAllocateMemory(device, &allocInfo, nullptr, &mipTailimageMemoryBind.memory));
|
||||||
|
|
||||||
|
uint32_t mipLevel = texture.sparseImageMemoryRequirements.imageMipTailFirstLod;
|
||||||
|
uint32_t width = std::max(texture.width >> texture.sparseImageMemoryRequirements.imageMipTailFirstLod, 1u);
|
||||||
|
uint32_t height = std::max(texture.height >> texture.sparseImageMemoryRequirements.imageMipTailFirstLod, 1u);
|
||||||
|
uint32_t depth = 1;
|
||||||
|
|
||||||
|
for (uint32_t i = texture.mipTailStart; i < texture.mipLevels; i++) {
|
||||||
|
|
||||||
|
const uint32_t width = std::max(texture.width >> i, 1u);
|
||||||
|
const uint32_t height = std::max(texture.height >> i, 1u);
|
||||||
|
const uint32_t depth = 1;
|
||||||
|
|
||||||
|
// Generate some random image data and upload as a buffer
|
||||||
|
const size_t bufferSize = 4 * width * height;
|
||||||
|
|
||||||
|
vks::Buffer imageBuffer;
|
||||||
|
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||||
|
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
|
||||||
|
&imageBuffer,
|
||||||
|
bufferSize));
|
||||||
|
imageBuffer.map();
|
||||||
|
|
||||||
|
// Fill buffer with random colors
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 rndEngine(rd());
|
||||||
|
std::uniform_int_distribution<uint32_t> rndDist(0, 255);
|
||||||
|
uint8_t* data = (uint8_t*)imageBuffer.mapped;
|
||||||
|
uint8_t rndVal[4];
|
||||||
|
ZeroMemory(&rndVal, sizeof(uint32_t));
|
||||||
|
while (rndVal[0] + rndVal[1] + rndVal[2] < 10) {
|
||||||
|
rndVal[0] = (uint8_t)rndDist(rndEngine);
|
||||||
|
rndVal[1] = (uint8_t)rndDist(rndEngine);
|
||||||
|
rndVal[2] = (uint8_t)rndDist(rndEngine);
|
||||||
|
}
|
||||||
|
rndVal[3] = 255;
|
||||||
|
|
||||||
|
switch (mipLevel) {
|
||||||
|
case 0:
|
||||||
|
rndVal[0] = rndVal[1] = rndVal[2] = 255;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
rndVal[0] = rndVal[1] = rndVal[2] = 200;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
rndVal[0] = rndVal[1] = rndVal[2] = 150;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
for (uint32_t x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
for (uint32_t c = 0; c < 4; c++, ++data)
|
||||||
|
{
|
||||||
|
*data = rndVal[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
VkBufferImageCopy region{};
|
||||||
|
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
|
region.imageSubresource.layerCount = 1;
|
||||||
|
region.imageSubresource.mipLevel = i;
|
||||||
|
region.imageOffset = {};
|
||||||
|
region.imageExtent = { width, height, depth };
|
||||||
|
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);
|
||||||
|
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
||||||
|
|
||||||
|
imageBuffer.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void flushRandomPages()
|
void flushRandomPages()
|
||||||
{
|
{
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(device);
|
||||||
|
|
@ -899,21 +997,24 @@ public:
|
||||||
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay)
|
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay)
|
||||||
{
|
{
|
||||||
if (overlay->header("Settings")) {
|
if (overlay->header("Settings")) {
|
||||||
if (overlay->sliderFloat("LOD bias", &uboVS.lodBias, 0.0f, (float)texture.mipLevels)) {
|
if (overlay->sliderFloat("LOD bias", &uboVS.lodBias, -(float)texture.mipLevels, (float)texture.mipLevels)) {
|
||||||
updateUniformBuffers();
|
updateUniformBuffers();
|
||||||
}
|
}
|
||||||
overlay->text("Last filled mip level: %d", lastFilledMip);
|
|
||||||
if (overlay->button("Fill random pages")) {
|
if (overlay->button("Fill random pages")) {
|
||||||
fillRandomPages();
|
fillRandomPages();
|
||||||
}
|
}
|
||||||
if (overlay->button("Flush random pages")) {
|
if (overlay->button("Flush random pages")) {
|
||||||
flushRandomPages();
|
flushRandomPages();
|
||||||
}
|
}
|
||||||
|
if (overlay->button("Fill mip tail")) {
|
||||||
|
fillMipTail();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (overlay->header("Statistics")) {
|
if (overlay->header("Statistics")) {
|
||||||
uint32_t respages = 0;
|
uint32_t respages = 0;
|
||||||
std::for_each(texture.pages.begin(), texture.pages.end(), [&respages](VirtualTexturePage page) { respages += (page.resident()) ? 1 : 0; });
|
std::for_each(texture.pages.begin(), texture.pages.end(), [&respages](VirtualTexturePage page) { respages += (page.resident()) ? 1 : 0; });
|
||||||
overlay->text("Resident pages: %d of %d", respages, static_cast<uint32_t>(texture.pages.size()));
|
overlay->text("Resident pages: %d of %d", respages, static_cast<uint32_t>(texture.pages.size()));
|
||||||
|
overlay->text("Mip tail starts at: %d", texture.mipTailStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue