Split into header and implementation
This commit is contained in:
parent
77322190ea
commit
3b117fd2dc
2 changed files with 932 additions and 872 deletions
|
|
@ -10,53 +10,27 @@
|
|||
* Note : This sample is work-in-progress and works basically, but it's not yet finished
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
#include "texturesparseresidency.h"
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
/*
|
||||
Virtual texture page
|
||||
Contains all functions and objects for a single page of a virtual texture
|
||||
*/
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "vulkanexamplebase.h"
|
||||
#include "VulkanDevice.hpp"
|
||||
#include "VulkanBuffer.hpp"
|
||||
#include "VulkanModel.hpp"
|
||||
|
||||
#define ENABLE_VALIDATION false
|
||||
|
||||
// Virtual texture page as a part of the partially resident texture
|
||||
// Contains memory bindings, offsets and status information
|
||||
struct VirtualTexturePage
|
||||
VirtualTexturePage::VirtualTexturePage()
|
||||
{
|
||||
VkOffset3D offset;
|
||||
VkExtent3D extent;
|
||||
VkSparseImageMemoryBind imageMemoryBind; // Sparse image memory bind for this page
|
||||
VkDeviceSize size; // Page (memory) size in bytes
|
||||
uint32_t mipLevel; // Mip level that this page belongs to
|
||||
uint32_t layer; // Array layer that this page belongs to
|
||||
uint32_t index;
|
||||
// Pages are initially not backed up by memory (non-resident)
|
||||
imageMemoryBind.memory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
VirtualTexturePage()
|
||||
{
|
||||
imageMemoryBind.memory = VK_NULL_HANDLE; // Page initially not backed up by memory
|
||||
}
|
||||
|
||||
bool resident()
|
||||
{
|
||||
bool VirtualTexturePage::resident()
|
||||
{
|
||||
return (imageMemoryBind.memory != VK_NULL_HANDLE);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate Vulkan memory for the virtual page
|
||||
void allocate(VkDevice device, uint32_t memoryTypeIndex)
|
||||
{
|
||||
// Allocate Vulkan memory for the virtual page
|
||||
void VirtualTexturePage::allocate(VkDevice device, uint32_t memoryTypeIndex)
|
||||
{
|
||||
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
||||
{
|
||||
return;
|
||||
|
|
@ -78,42 +52,26 @@ struct VirtualTexturePage
|
|||
imageMemoryBind.subresource = subResource;
|
||||
imageMemoryBind.extent = extent;
|
||||
imageMemoryBind.offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Release Vulkan memory allocated for this page
|
||||
void release(VkDevice device)
|
||||
{
|
||||
// Release Vulkan memory allocated for this page
|
||||
void VirtualTexturePage::release(VkDevice device)
|
||||
{
|
||||
if (imageMemoryBind.memory != VK_NULL_HANDLE)
|
||||
{
|
||||
vkFreeMemory(device, imageMemoryBind.memory, nullptr);
|
||||
imageMemoryBind.memory = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Virtual texture object containing all pages
|
||||
struct VirtualTexture
|
||||
/*
|
||||
Virtual texture
|
||||
Contains the virtual pages and memory binding information for a whole virtual texture
|
||||
*/
|
||||
|
||||
VirtualTexturePage* VirtualTexture::addPage(VkOffset3D offset, VkExtent3D extent, const VkDeviceSize size, const uint32_t mipLevel, uint32_t layer)
|
||||
{
|
||||
VkDevice device;
|
||||
VkImage image; // Texture image handle
|
||||
VkBindSparseInfo bindSparseInfo; // Sparse queue binding information
|
||||
std::vector<VirtualTexturePage> pages; // Contains all virtual pages of the texture
|
||||
std::vector<VkSparseImageMemoryBind> sparseImageMemoryBinds; // Sparse image memory bindings of all memory-backed virtual tables
|
||||
std::vector<VkSparseMemoryBind> opaqueMemoryBinds; // Sparse ópaque memory bindings for the mip tail (if present)
|
||||
VkSparseImageMemoryBindInfo imageMemoryBindInfo; // Sparse image memory bind info
|
||||
VkSparseImageOpaqueMemoryBindInfo opaqueMemoryBindInfo; // Sparse image opaque memory bind info (mip tail)
|
||||
uint32_t mipTailStart; // First mip level in mip tail
|
||||
VkSparseImageMemoryRequirements sparseImageMemoryRequirements; // @todo: Comment
|
||||
|
||||
// @todo: comment
|
||||
struct MipTailInfo {
|
||||
bool singleMipTail;
|
||||
bool alingedMipSize;
|
||||
} mipTailInfo;
|
||||
|
||||
VirtualTexturePage* addPage(VkOffset3D offset, VkExtent3D extent, const VkDeviceSize size, const uint32_t mipLevel, uint32_t layer)
|
||||
{
|
||||
VirtualTexturePage newPage;
|
||||
VirtualTexturePage newPage{};
|
||||
newPage.offset = offset;
|
||||
newPage.extent = extent;
|
||||
newPage.size = size;
|
||||
|
|
@ -125,11 +83,11 @@ struct VirtualTexture
|
|||
newPage.imageMemoryBind.extent = extent;
|
||||
pages.push_back(newPage);
|
||||
return &pages.back();
|
||||
}
|
||||
}
|
||||
|
||||
// Call before sparse binding to update memory bind list etc.
|
||||
void updateSparseBindInfo()
|
||||
{
|
||||
// Call before sparse binding to update memory bind list etc.
|
||||
void VirtualTexture::updateSparseBindInfo()
|
||||
{
|
||||
// Update list of memory-backed sparse image memory binds
|
||||
//sparseImageMemoryBinds.resize(pages.size());
|
||||
sparseImageMemoryBinds.clear();
|
||||
|
|
@ -157,11 +115,11 @@ struct VirtualTexture
|
|||
opaqueMemoryBindInfo.pBinds = opaqueMemoryBinds.data();
|
||||
bindSparseInfo.imageOpaqueBindCount = (opaqueMemoryBindInfo.bindCount > 0) ? 1 : 0;
|
||||
bindSparseInfo.pImageOpaqueBinds = &opaqueMemoryBindInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// Release all Vulkan resources
|
||||
void destroy()
|
||||
{
|
||||
// Release all Vulkan resources
|
||||
void VirtualTexture::destroy()
|
||||
{
|
||||
for (auto page : pages)
|
||||
{
|
||||
page.release(device);
|
||||
|
|
@ -170,51 +128,13 @@ struct VirtualTexture
|
|||
{
|
||||
vkFreeMemory(device, bind.memory, nullptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
uint32_t memoryTypeIndex;
|
||||
|
||||
class VulkanExample : public VulkanExampleBase
|
||||
/*
|
||||
Vulkan Example class
|
||||
*/
|
||||
VulkanExample::VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||
{
|
||||
public:
|
||||
//todo: comments
|
||||
struct SparseTexture : VirtualTexture {
|
||||
VkSampler sampler;
|
||||
VkImageLayout imageLayout;
|
||||
VkImageView view;
|
||||
VkDescriptorImageInfo descriptor;
|
||||
VkFormat format;
|
||||
uint32_t width, height;
|
||||
uint32_t mipLevels;
|
||||
uint32_t layerCount;
|
||||
} texture;
|
||||
|
||||
vks::VertexLayout vertexLayout = vks::VertexLayout({
|
||||
vks::VERTEX_COMPONENT_POSITION,
|
||||
vks::VERTEX_COMPONENT_NORMAL,
|
||||
vks::VERTEX_COMPONENT_UV,
|
||||
});
|
||||
vks::Model plane;
|
||||
|
||||
struct UboVS {
|
||||
glm::mat4 projection;
|
||||
glm::mat4 model;
|
||||
glm::vec4 viewPos;
|
||||
float lodBias = 0.0f;
|
||||
} uboVS;
|
||||
vks::Buffer uniformBufferVS;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkDescriptorSet descriptorSet;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
|
||||
//todo: comment
|
||||
VkSemaphore bindSparseSemaphore = VK_NULL_HANDLE;
|
||||
|
||||
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
|
||||
{
|
||||
title = "Sparse texture residency";
|
||||
std::cout.imbue(std::locale(""));
|
||||
camera.type = Camera::CameraType::lookat;
|
||||
|
|
@ -222,10 +142,10 @@ public:
|
|||
camera.setRotation(glm::vec3(0.0f, 180.0f, 0.0f));
|
||||
camera.setPerspective(60.0f, (float)width / (float)height, 0.1f, 256.0f);
|
||||
settings.overlay = true;
|
||||
}
|
||||
}
|
||||
|
||||
~VulkanExample()
|
||||
{
|
||||
VulkanExample::~VulkanExample()
|
||||
{
|
||||
// Clean up used Vulkan resources
|
||||
// Note : Inherited destructor cleans up resources stored in base class
|
||||
destroyTextureImage(texture);
|
||||
|
|
@ -235,10 +155,10 @@ public:
|
|||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||
plane.destroy();
|
||||
uniformBufferVS.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void getEnabledFeatures()
|
||||
{
|
||||
void VulkanExample::getEnabledFeatures()
|
||||
{
|
||||
if (deviceFeatures.sparseBinding && deviceFeatures.sparseResidencyImage2D) {
|
||||
enabledFeatures.shaderResourceResidency = VK_TRUE;
|
||||
enabledFeatures.shaderResourceMinLod = VK_TRUE;
|
||||
|
|
@ -248,19 +168,19 @@ public:
|
|||
else {
|
||||
std::cout << "Sparse binding not supported" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::uvec3 alignedDivision(const VkExtent3D& extent, const VkExtent3D& granularity)
|
||||
{
|
||||
glm::uvec3 VulkanExample::alignedDivision(const VkExtent3D& extent, const VkExtent3D& granularity)
|
||||
{
|
||||
glm::uvec3 res;
|
||||
res.x = extent.width / granularity.width + ((extent.width % granularity.width) ? 1u : 0u);
|
||||
res.y = extent.height / granularity.height + ((extent.height % granularity.height) ? 1u : 0u);
|
||||
res.z = extent.depth / granularity.depth + ((extent.depth % granularity.depth) ? 1u : 0u);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
void prepareSparseTexture(uint32_t width, uint32_t height, uint32_t layerCount, VkFormat format)
|
||||
{
|
||||
void VulkanExample::prepareSparseTexture(uint32_t width, uint32_t height, uint32_t layerCount, VkFormat format)
|
||||
{
|
||||
texture.device = vulkanDevice->logicalDevice;
|
||||
texture.width = width;
|
||||
texture.height = height;
|
||||
|
|
@ -380,10 +300,10 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
// todo:
|
||||
// @todo: proper comment
|
||||
// Calculate number of required sparse memory bindings by alignment
|
||||
assert((sparseImageMemoryReqs.size % sparseImageMemoryReqs.alignment) == 0);
|
||||
memoryTypeIndex = vulkanDevice->getMemoryType(sparseImageMemoryReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
texture.memoryTypeIndex = vulkanDevice->getMemoryType(sparseImageMemoryReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
// Get sparse bindings
|
||||
uint32_t sparseBindsCount = static_cast<uint32_t>(sparseImageMemoryReqs.size / sparseImageMemoryReqs.alignment);
|
||||
|
|
@ -458,7 +378,7 @@ public:
|
|||
// Allocate memory for the mip tail
|
||||
VkMemoryAllocateInfo allocInfo = vks::initializers::memoryAllocateInfo();
|
||||
allocInfo.allocationSize = sparseMemoryReq.imageMipTailSize;
|
||||
allocInfo.memoryTypeIndex = memoryTypeIndex;
|
||||
allocInfo.memoryTypeIndex = texture.memoryTypeIndex;
|
||||
|
||||
VkDeviceMemory deviceMemory;
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device, &allocInfo, nullptr, &deviceMemory));
|
||||
|
|
@ -483,7 +403,7 @@ public:
|
|||
// Allocate memory for the mip tail
|
||||
VkMemoryAllocateInfo allocInfo = vks::initializers::memoryAllocateInfo();
|
||||
allocInfo.allocationSize = sparseMemoryReq.imageMipTailSize;
|
||||
allocInfo.memoryTypeIndex = memoryTypeIndex;
|
||||
allocInfo.memoryTypeIndex = texture.memoryTypeIndex;
|
||||
|
||||
VkDeviceMemory deviceMemory;
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device, &allocInfo, nullptr, &deviceMemory));
|
||||
|
|
@ -514,7 +434,7 @@ public:
|
|||
VkSamplerCreateInfo sampler = vks::initializers::samplerCreateInfo();
|
||||
sampler.magFilter = VK_FILTER_LINEAR;
|
||||
sampler.minFilter = VK_FILTER_LINEAR;
|
||||
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
||||
sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampler.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
|
|
@ -524,7 +444,7 @@ public:
|
|||
sampler.maxLod = static_cast<float>(texture.mipLevels);
|
||||
sampler.maxAnisotropy = vulkanDevice->features.samplerAnisotropy ? vulkanDevice->properties.limits.maxSamplerAnisotropy : 1.0f;
|
||||
sampler.anisotropyEnable = false;
|
||||
sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
|
||||
sampler.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
|
||||
VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &texture.sampler));
|
||||
|
||||
// Create image view
|
||||
|
|
@ -545,19 +465,19 @@ public:
|
|||
texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
texture.descriptor.imageView = texture.view;
|
||||
texture.descriptor.sampler = texture.sampler;
|
||||
}
|
||||
}
|
||||
|
||||
// Free all Vulkan resources used a texture object
|
||||
void destroyTextureImage(SparseTexture texture)
|
||||
{
|
||||
// Free all Vulkan resources used a texture object
|
||||
void VulkanExample::destroyTextureImage(SparseTexture texture)
|
||||
{
|
||||
vkDestroyImageView(device, texture.view, nullptr);
|
||||
vkDestroyImage(device, texture.image, nullptr);
|
||||
vkDestroySampler(device, texture.sampler, nullptr);
|
||||
texture.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void buildCommandBuffers()
|
||||
{
|
||||
void VulkanExample::buildCommandBuffers()
|
||||
{
|
||||
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
|
||||
|
||||
VkClearValue clearValues[2];
|
||||
|
|
@ -601,24 +521,24 @@ public:
|
|||
|
||||
VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
void VulkanExample::draw()
|
||||
{
|
||||
VulkanExampleBase::prepareFrame();
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &drawCmdBuffers[currentBuffer];
|
||||
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE));
|
||||
VulkanExampleBase::submitFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void loadAssets()
|
||||
{
|
||||
void VulkanExample::loadAssets()
|
||||
{
|
||||
plane.loadFromFile(getAssetPath() + "models/plane_z.obj", vertexLayout, 1.0f, vulkanDevice, queue);
|
||||
}
|
||||
}
|
||||
|
||||
void setupDescriptorPool()
|
||||
{
|
||||
void VulkanExample::setupDescriptorPool()
|
||||
{
|
||||
// Example uses one ubo and one image sampler
|
||||
std::vector<VkDescriptorPoolSize> poolSizes =
|
||||
{
|
||||
|
|
@ -633,10 +553,10 @@ public:
|
|||
2);
|
||||
|
||||
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
|
||||
}
|
||||
}
|
||||
|
||||
void setupDescriptorSetLayout()
|
||||
{
|
||||
void VulkanExample::setupDescriptorSetLayout()
|
||||
{
|
||||
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings =
|
||||
{
|
||||
// Binding 0 : Vertex shader uniform buffer
|
||||
|
|
@ -664,10 +584,10 @@ public:
|
|||
1);
|
||||
|
||||
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
}
|
||||
}
|
||||
|
||||
void setupDescriptorSet()
|
||||
{
|
||||
void VulkanExample::setupDescriptorSet()
|
||||
{
|
||||
VkDescriptorSetAllocateInfo allocInfo =
|
||||
vks::initializers::descriptorSetAllocateInfo(
|
||||
descriptorPool,
|
||||
|
|
@ -693,10 +613,10 @@ public:
|
|||
};
|
||||
|
||||
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void preparePipelines()
|
||||
{
|
||||
void VulkanExample::preparePipelines()
|
||||
{
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0, VK_FALSE);
|
||||
VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo(VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0);
|
||||
VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState(0xf, VK_FALSE);
|
||||
|
|
@ -738,11 +658,11 @@ public:
|
|||
shaderStages[0] = loadShader(getShadersPath() + "texturesparseresidency/sparseresidency.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
|
||||
shaderStages[1] = loadShader(getShadersPath() + "texturesparseresidency/sparseresidency.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare and initialize uniform buffer containing shader uniforms
|
||||
void prepareUniformBuffers()
|
||||
{
|
||||
// Prepare and initialize uniform buffer containing shader uniforms
|
||||
void VulkanExample::prepareUniformBuffers()
|
||||
{
|
||||
// Vertex shader uniform buffer block
|
||||
VK_CHECK_RESULT(vulkanDevice->createBuffer(
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
|
|
@ -752,10 +672,10 @@ public:
|
|||
&uboVS));
|
||||
|
||||
updateUniformBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
void updateUniformBuffers()
|
||||
{
|
||||
void VulkanExample::updateUniformBuffers()
|
||||
{
|
||||
uboVS.projection = camera.matrices.perspective;
|
||||
uboVS.model = camera.matrices.view;
|
||||
uboVS.viewPos = camera.viewPos;
|
||||
|
|
@ -763,10 +683,10 @@ public:
|
|||
VK_CHECK_RESULT(uniformBufferVS.map());
|
||||
memcpy(uniformBufferVS.mapped, &uboVS, sizeof(uboVS));
|
||||
uniformBufferVS.unmap();
|
||||
}
|
||||
}
|
||||
|
||||
void prepare()
|
||||
{
|
||||
void VulkanExample::prepare()
|
||||
{
|
||||
VulkanExampleBase::prepare();
|
||||
// Check if the GPU supports sparse residency for 2D images
|
||||
if (!vulkanDevice->features.sparseResidencyImage2D) {
|
||||
|
|
@ -782,20 +702,20 @@ public:
|
|||
setupDescriptorSet();
|
||||
buildCommandBuffers();
|
||||
prepared = true;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void render()
|
||||
{
|
||||
void VulkanExample::render()
|
||||
{
|
||||
if (!prepared)
|
||||
return;
|
||||
draw();
|
||||
if (camera.updated) {
|
||||
updateUniformBuffers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uploadContent(VirtualTexturePage page, VkImage image)
|
||||
{
|
||||
void VulkanExample::uploadContent(VirtualTexturePage page, VkImage image)
|
||||
{
|
||||
// Generate some random image data and upload as a buffer
|
||||
const size_t bufferSize = 4 * page.extent.width * page.extent.height;
|
||||
|
||||
|
|
@ -844,10 +764,10 @@ public:
|
|||
vulkanDevice->flushCommandBuffer(copyCmd, queue);
|
||||
|
||||
imageBuffer.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void fillRandomPages()
|
||||
{
|
||||
void VulkanExample::fillRandomPages()
|
||||
{
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
std::default_random_engine rndEngine(std::random_device{}());
|
||||
|
|
@ -858,7 +778,7 @@ public:
|
|||
if (rndDist(rndEngine) < 0.5f) {
|
||||
continue;
|
||||
}
|
||||
page.allocate(device, memoryTypeIndex);
|
||||
page.allocate(device, texture.memoryTypeIndex);
|
||||
updatedPages.push_back(page);
|
||||
}
|
||||
|
||||
|
|
@ -873,10 +793,10 @@ public:
|
|||
for (auto &page: updatedPages) {
|
||||
uploadContent(page, texture.image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fillMipTail()
|
||||
{
|
||||
void VulkanExample::fillMipTail()
|
||||
{
|
||||
//@todo: WIP
|
||||
VkDeviceSize imageMipTailSize = texture.sparseImageMemoryRequirements.imageMipTailSize;
|
||||
VkDeviceSize imageMipTailOffset = texture.sparseImageMemoryRequirements.imageMipTailOffset;
|
||||
|
|
@ -887,7 +807,7 @@ public:
|
|||
|
||||
VkMemoryAllocateInfo allocInfo = vks::initializers::memoryAllocateInfo();
|
||||
allocInfo.allocationSize = imageMipTailSize;
|
||||
allocInfo.memoryTypeIndex = memoryTypeIndex;
|
||||
allocInfo.memoryTypeIndex = texture.memoryTypeIndex;
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device, &allocInfo, nullptr, &mipTailimageMemoryBind.memory));
|
||||
|
||||
uint32_t mipLevel = texture.sparseImageMemoryRequirements.imageMipTailFirstLod;
|
||||
|
|
@ -962,10 +882,10 @@ public:
|
|||
|
||||
imageBuffer.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flushRandomPages()
|
||||
{
|
||||
void VulkanExample::flushRandomPages()
|
||||
{
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
std::default_random_engine rndEngine(std::random_device{}());
|
||||
|
|
@ -987,10 +907,10 @@ public:
|
|||
VK_CHECK_RESULT(vkCreateFence(device, &fenceInfo, nullptr, &fence));
|
||||
vkQueueBindSparse(queue, 1, &texture.bindSparseInfo, fence);
|
||||
vkWaitForFences(device, 1, &fence, VK_TRUE, UINT64_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay)
|
||||
{
|
||||
void VulkanExample::OnUpdateUIOverlay(vks::UIOverlay* overlay)
|
||||
{
|
||||
if (overlay->header("Settings")) {
|
||||
if (overlay->sliderFloat("LOD bias", &uboVS.lodBias, -(float)texture.mipLevels, (float)texture.mipLevels)) {
|
||||
updateUniformBuffers();
|
||||
|
|
@ -1012,7 +932,6 @@ public:
|
|||
overlay->text("Mip tail starts at: %d", texture.mipTailStart);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
VULKAN_EXAMPLE_MAIN()
|
||||
|
|
|
|||
141
examples/texturesparseresidency/texturesparseresidency.h
Normal file
141
examples/texturesparseresidency/texturesparseresidency.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Vulkan Example - Sparse texture residency example
|
||||
*
|
||||
* Copyright (C) 2016-2020 by Sascha Willems - www.saschawillems.de
|
||||
*
|
||||
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note : This sample is work-in-progress and works basically, but it's not yet finished
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include "vulkanexamplebase.h"
|
||||
#include "VulkanDevice.hpp"
|
||||
#include "VulkanBuffer.hpp"
|
||||
#include "VulkanModel.hpp"
|
||||
|
||||
#define ENABLE_VALIDATION false
|
||||
|
||||
// Virtual texture page as a part of the partially resident texture
|
||||
// Contains memory bindings, offsets and status information
|
||||
struct VirtualTexturePage
|
||||
{
|
||||
VkOffset3D offset;
|
||||
VkExtent3D extent;
|
||||
VkSparseImageMemoryBind imageMemoryBind; // Sparse image memory bind for this page
|
||||
VkDeviceSize size; // Page (memory) size in bytes
|
||||
uint32_t mipLevel; // Mip level that this page belongs to
|
||||
uint32_t layer; // Array layer that this page belongs to
|
||||
uint32_t index;
|
||||
|
||||
VirtualTexturePage();
|
||||
bool resident();
|
||||
void allocate(VkDevice device, uint32_t memoryTypeIndex);
|
||||
void release(VkDevice device);
|
||||
};
|
||||
|
||||
// Virtual texture object containing all pages
|
||||
struct VirtualTexture
|
||||
{
|
||||
VkDevice device;
|
||||
VkImage image; // Texture image handle
|
||||
VkBindSparseInfo bindSparseInfo; // Sparse queue binding information
|
||||
std::vector<VirtualTexturePage> pages; // Contains all virtual pages of the texture
|
||||
std::vector<VkSparseImageMemoryBind> sparseImageMemoryBinds; // Sparse image memory bindings of all memory-backed virtual tables
|
||||
std::vector<VkSparseMemoryBind> opaqueMemoryBinds; // Sparse ópaque memory bindings for the mip tail (if present)
|
||||
VkSparseImageMemoryBindInfo imageMemoryBindInfo; // Sparse image memory bind info
|
||||
VkSparseImageOpaqueMemoryBindInfo opaqueMemoryBindInfo; // Sparse image opaque memory bind info (mip tail)
|
||||
uint32_t mipTailStart; // First mip level in mip tail
|
||||
VkSparseImageMemoryRequirements sparseImageMemoryRequirements; // @todo: Comment
|
||||
uint32_t memoryTypeIndex; // @todo: Comment
|
||||
|
||||
// @todo: comment
|
||||
struct MipTailInfo {
|
||||
bool singleMipTail;
|
||||
bool alingedMipSize;
|
||||
} mipTailInfo;
|
||||
|
||||
VirtualTexturePage *addPage(VkOffset3D offset, VkExtent3D extent, const VkDeviceSize size, const uint32_t mipLevel, uint32_t layer);
|
||||
void updateSparseBindInfo();
|
||||
// @todo: replace with dtor?
|
||||
void destroy();
|
||||
};
|
||||
|
||||
class VulkanExample : public VulkanExampleBase
|
||||
{
|
||||
public:
|
||||
//todo: comments
|
||||
struct SparseTexture : VirtualTexture {
|
||||
VkSampler sampler;
|
||||
VkImageLayout imageLayout;
|
||||
VkImageView view;
|
||||
VkDescriptorImageInfo descriptor;
|
||||
VkFormat format;
|
||||
uint32_t width, height;
|
||||
uint32_t mipLevels;
|
||||
uint32_t layerCount;
|
||||
} texture;
|
||||
|
||||
vks::VertexLayout vertexLayout = vks::VertexLayout({
|
||||
vks::VERTEX_COMPONENT_POSITION,
|
||||
vks::VERTEX_COMPONENT_NORMAL,
|
||||
vks::VERTEX_COMPONENT_UV,
|
||||
});
|
||||
vks::Model plane;
|
||||
|
||||
struct UboVS {
|
||||
glm::mat4 projection;
|
||||
glm::mat4 model;
|
||||
glm::vec4 viewPos;
|
||||
float lodBias = 0.0f;
|
||||
} uboVS;
|
||||
vks::Buffer uniformBufferVS;
|
||||
|
||||
VkPipeline pipeline;
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkDescriptorSet descriptorSet;
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
|
||||
//todo: comment
|
||||
VkSemaphore bindSparseSemaphore = VK_NULL_HANDLE;
|
||||
|
||||
VulkanExample();
|
||||
~VulkanExample();
|
||||
virtual void getEnabledFeatures();
|
||||
glm::uvec3 alignedDivision(const VkExtent3D& extent, const VkExtent3D& granularity);
|
||||
void prepareSparseTexture(uint32_t width, uint32_t height, uint32_t layerCount, VkFormat format);
|
||||
// @todo: move to dtor of texture
|
||||
void destroyTextureImage(SparseTexture texture);
|
||||
void buildCommandBuffers();
|
||||
void draw();
|
||||
void loadAssets();
|
||||
void setupDescriptorPool();
|
||||
void setupDescriptorSetLayout();
|
||||
void setupDescriptorSet();
|
||||
void preparePipelines();
|
||||
void prepareUniformBuffers();
|
||||
void updateUniformBuffers();
|
||||
void prepare();
|
||||
virtual void render();
|
||||
void uploadContent(VirtualTexturePage page, VkImage image);
|
||||
void fillRandomPages();
|
||||
void fillMipTail();
|
||||
void flushRandomPages();
|
||||
virtual void OnUpdateUIOverlay(vks::UIOverlay* overlay);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue