Randomly fill virtual pages, check if sparse residency for 2D images is supported

This commit is contained in:
saschawillems 2016-09-17 19:08:27 +02:00
parent 9ce827b3f3
commit 18b7a52ece
5 changed files with 113 additions and 28 deletions

View file

@ -1,29 +1,37 @@
#version 450 #version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
// Required for the sparse* commands used in this shader
#extension GL_ARB_sparse_texture2 : enable #extension GL_ARB_sparse_texture2 : enable
#extension GL_ARB_sparse_texture_clamp : enable
layout (binding = 1) uniform sampler2D samplerColor; layout (binding = 1) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUV; layout (location = 0) in vec2 inUV;
layout (location = 1) in float inLodBias; layout (location = 1) in float inLodBias;
layout (location = 2) in vec3 inNormal;
layout (location = 3) in vec3 inViewVec;
layout (location = 4) in vec3 inLightVec;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
void main() void main()
{ {
vec4 color = vec4(0.0);
// Get residency code for current texel // Get residency code for current texel
int residencyCode = sparseTextureARB(samplerColor, inUV, outFragColor, inLodBias); int residencyCode = sparseTextureARB(samplerColor, inUV, color, inLodBias);
//#define MIN_LOD
#ifdef MIN_LOD
// Fetch sparse until we get a valid texel
// todo: does not work in SPIR-V with current drivers (will be fixed in a new release)
float minLod = 1.0;
while (!sparseTexelsResidentARB(residencyCode))
{
residencyCode = sparseTextureClampARB(samplerColor, inUV, minLod, color);
minLod += 1.0f;
}
#endif
// Check if texel is resident // Check if texel is resident
bool texelResident = sparseTexelsResidentARB(residencyCode); bool texelResident = sparseTexelsResidentARB(residencyCode);
vec4 color; float lodClamp = 1.0f;
if (texelResident) if (texelResident)
{ {
color = texture(samplerColor, inUV, inLodBias); color = texture(samplerColor, inUV, inLodBias);

View file

@ -17,9 +17,9 @@ layout (binding = 0) uniform UBO
layout (location = 0) out vec2 outUV; layout (location = 0) out vec2 outUV;
layout (location = 1) out float outLodBias; layout (location = 1) out float outLodBias;
layout (location = 2) out vec3 outNormal; //layout (location = 2) out vec3 outNormal;
layout (location = 3) out vec3 outViewVec; //layout (location = 3) out vec3 outViewVec;
layout (location = 4) out vec3 outLightVec; //layout (location = 4) out vec3 outLightVec;
out gl_PerVertex out gl_PerVertex
{ {
@ -34,11 +34,12 @@ void main()
vec3 worldPos = vec3(ubo.model * vec4(inPos, 1.0)); vec3 worldPos = vec3(ubo.model * vec4(inPos, 1.0));
gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0); gl_Position = ubo.projection * ubo.model * vec4(inPos.xyz, 1.0);
/*
vec4 pos = ubo.model * vec4(inPos, 1.0); vec4 pos = ubo.model * vec4(inPos, 1.0);
outNormal = mat3(inverse(transpose(ubo.model))) * inNormal; outNormal = mat3(inverse(transpose(ubo.model))) * inNormal;
vec3 lightPos = vec3(0.0); vec3 lightPos = vec3(0.0);
vec3 lPos = mat3(ubo.model) * lightPos.xyz; vec3 lPos = mat3(ubo.model) * lightPos.xyz;
outLightVec = lPos - pos.xyz; outLightVec = lPos - pos.xyz;
outViewVec = ubo.viewPos.xyz - pos.xyz; outViewVec = ubo.viewPos.xyz - pos.xyz;
*/
} }

View file

@ -196,6 +196,10 @@ public:
uint32_t layerCount; uint32_t layerCount;
} texture; } texture;
struct {
vkTools::VulkanTexture source;
} textures;
struct { struct {
VkPipelineVertexInputStateCreateInfo inputState; VkPipelineVertexInputStateCreateInfo inputState;
std::vector<VkVertexInputBindingDescription> bindingDescriptions; std::vector<VkVertexInputBindingDescription> bindingDescriptions;
@ -231,17 +235,22 @@ public:
{ {
VkPhysicalDeviceFeatures enabledFeatures = {}; VkPhysicalDeviceFeatures enabledFeatures = {};
enabledFeatures.shaderResourceResidency = VK_TRUE; enabledFeatures.shaderResourceResidency = VK_TRUE;
enabledFeatures.shaderResourceMinLod = VK_TRUE;
return enabledFeatures; return enabledFeatures;
} }
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION, getEnabledFeatures) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION, getEnabledFeatures)
{ {
zoom = -2.5f; zoom = -1.3f;
rotation = { 0.0f, 15.0f, 0.0f }; rotation = { 76.25f, 0.0f, 0.0f };
title = "Vulkan Example - Sparse textures residency"; title = "Vulkan Example - Sparse texture residency";
enableTextOverlay = true; enableTextOverlay = true;
std::cout.imbue(std::locale("")); std::cout.imbue(std::locale(""));
//todo: check if GPU supports sparse binding feature // Check if the GPU supports sparse residency for 2D images
if (!vulkanDevice->features.sparseResidencyImage2D)
{
vkTools::exitFatal("Device does not support sparse residency for 2D images!", "Feature not supported");
}
} }
~VulkanExample() ~VulkanExample()
@ -277,7 +286,7 @@ public:
texture.device = vulkanDevice->logicalDevice; texture.device = vulkanDevice->logicalDevice;
texture.width = width; texture.width = width;
texture.height = height; texture.height = height;
texture.mipLevels = floor(log2(std::max(width, height))) + 1; //todo texture.mipLevels = floor(log2(std::max(width, height))) + 1;
texture.layerCount = layerCount; texture.layerCount = layerCount;
texture.format = format; texture.format = format;
@ -450,7 +459,7 @@ public:
if ((x % 2 == 1) || (y % 2 == 1)) if ((x % 2 == 1) || (y % 2 == 1))
{ {
// Allocate memory for this virtual page // Allocate memory for this virtual page
newPage->allocate(device, memoryTypeIndex); //newPage->allocate(device, memoryTypeIndex);
} }
index++; index++;
@ -629,6 +638,11 @@ public:
VulkanExampleBase::submitFrame(); VulkanExampleBase::submitFrame();
} }
void loadAssets()
{
textureLoader->loadTextureArray(getAssetPath() + "textures/terrain_texturearray_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.source, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
}
void generateQuad() void generateQuad()
{ {
// Setup vertices for a single uv-mapped quad made from two triangles // Setup vertices for a single uv-mapped quad made from two triangles
@ -892,10 +906,11 @@ public:
void prepare() void prepare()
{ {
VulkanExampleBase::prepare(); VulkanExampleBase::prepare();
loadAssets();
generateQuad(); generateQuad();
setupVertexDescriptions(); setupVertexDescriptions();
prepareUniformBuffers(); prepareUniformBuffers();
prepareSparseTexture(8192, 8192, 1, VK_FORMAT_R8G8B8A8_UNORM); prepareSparseTexture(4096, 4096, 1, VK_FORMAT_R8G8B8A8_UNORM);
setupDescriptorSetLayout(); setupDescriptorSetLayout();
preparePipelines(); preparePipelines();
setupDescriptorPool(); setupDescriptorPool();
@ -953,17 +968,75 @@ public:
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
std::default_random_engine rndEngine(std::random_device{}()); std::default_random_engine rndEngine(std::random_device{}());
std::uniform_real_distribution<float> rndDist(0.0f, 1.0f); std::uniform_real_distribution<float> rndDist(0.0f, 1.0f);
// Fill random parts of the texture blitting from a source to the virtual texture
std::vector<VkImageBlit> imageBlits;
for (auto& page : texture.pages) for (auto& page : texture.pages)
{ {
if (rndDist(rndEngine) < 0.5f) if ((rndDist(rndEngine) < 0.5f) && (page.imageMemoryBind.memory == VK_NULL_HANDLE))
{ {
// Allocate page memory
page.allocate(device, memoryTypeIndex); page.allocate(device, memoryTypeIndex);
// Current mip level scaling
uint32_t scale = texture.width / (texture.width >> page.mipLevel);
for (uint32_t x = 0; x < scale; x++)
{
for (uint32_t y = 0; y < scale; y++)
{
// Image blit
VkImageBlit blit{};
// Source
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.baseArrayLayer = 1;
blit.srcSubresource.layerCount = 1;
blit.srcSubresource.mipLevel = 0;
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { static_cast<int32_t>(textures.source.width), static_cast<int32_t>(textures.source.height), 1 };
// Dest
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;
blit.dstSubresource.mipLevel = page.mipLevel;
blit.dstOffsets[0].x = static_cast<int32_t>(page.offset.x + x * 128 / scale);
blit.dstOffsets[0].y = static_cast<int32_t>(page.offset.y + y * 128 / scale);
blit.dstOffsets[0].z = 0;
blit.dstOffsets[1].x = static_cast<int32_t>(blit.dstOffsets[0].x + page.extent.width / scale);
blit.dstOffsets[1].y = static_cast<int32_t>(blit.dstOffsets[0].y + page.extent.height / scale);
blit.dstOffsets[1].z = 1;
imageBlits.push_back(blit);
} }
} }
}
}
// Update sparse queue binding
texture.updateSparseBindInfo(); texture.updateSparseBindInfo();
vkQueueBindSparse(queue, 1, &texture.bindSparseInfo, VK_NULL_HANDLE); vkQueueBindSparse(queue, 1, &texture.bindSparseInfo, VK_NULL_HANDLE);
//todo: use sparse bind semaphore //todo: use sparse bind semaphore
vkQueueWaitIdle(queue); vkQueueWaitIdle(queue);
// Issue blit commands
if (imageBlits.size() > 0)
{
VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
vkCmdBlitImage(
copyCmd,
textures.source.image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
texture.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
static_cast<uint32_t>(imageBlits.size()),
imageBlits.data(),
VK_FILTER_LINEAR
);
vulkanDevice->flushCommandBuffer(copyCmd, queue);
}
vkQueueWaitIdle(queue);
} }
virtual void keyPressed(uint32_t keyCode) virtual void keyPressed(uint32_t keyCode)
@ -989,12 +1062,15 @@ public:
virtual void getOverlayText(VulkanTextOverlay *textOverlay) virtual void getOverlayText(VulkanTextOverlay *textOverlay)
{ {
uint32_t respages = 0;
std::for_each(texture.pages.begin(), texture.pages.end(), [&respages](VirtualTexturePage page) { respages += (page.imageMemoryBind.memory != VK_NULL_HANDLE) ? 1 :0; });
std::stringstream ss; std::stringstream ss;
ss << std::setprecision(2) << std::fixed << uboVS.lodBias; ss << std::setprecision(2) << std::fixed << uboVS.lodBias;
#if defined(__ANDROID__) #if defined(__ANDROID__)
textOverlay->addText("LOD bias: " + ss.str() + " (Buttons L1/R1 to change)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); // textOverlay->addText("LOD bias: " + ss.str() + " (Buttons L1/R1 to change)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
#else #else
textOverlay->addText("LOD bias: " + ss.str() + " (numpad +/- to change)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft); //textOverlay->addText("LOD bias: " + ss.str() + " (numpad +/- to change)", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
textOverlay->addText("Resident pages: " + std::to_string(respages), 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
#endif #endif
} }
}; };