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
#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_texture_clamp : enable
layout (binding = 1) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUV;
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;
void main()
{
vec4 color = vec4(0.0);
// 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
bool texelResident = sparseTexelsResidentARB(residencyCode);
vec4 color;
float lodClamp = 1.0f;
if (texelResident)
{
color = texture(samplerColor, inUV, inLodBias);

View file

@ -17,13 +17,13 @@ layout (binding = 0) uniform UBO
layout (location = 0) out vec2 outUV;
layout (location = 1) out float outLodBias;
layout (location = 2) out vec3 outNormal;
layout (location = 3) out vec3 outViewVec;
layout (location = 4) out vec3 outLightVec;
//layout (location = 2) out vec3 outNormal;
//layout (location = 3) out vec3 outViewVec;
//layout (location = 4) out vec3 outLightVec;
out gl_PerVertex
{
vec4 gl_Position;
vec4 gl_Position;
};
void main()
@ -34,11 +34,12 @@ void main()
vec3 worldPos = vec3(ubo.model * vec4(inPos, 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;
vec3 lightPos = vec3(0.0);
vec3 lPos = mat3(ubo.model) * lightPos.xyz;
outLightVec = lPos - pos.xyz;
outViewVec = ubo.viewPos.xyz - pos.xyz;
outLightVec = lPos - pos.xyz;
outViewVec = ubo.viewPos.xyz - pos.xyz;
*/
}

View file

@ -196,6 +196,10 @@ public:
uint32_t layerCount;
} texture;
struct {
vkTools::VulkanTexture source;
} textures;
struct {
VkPipelineVertexInputStateCreateInfo inputState;
std::vector<VkVertexInputBindingDescription> bindingDescriptions;
@ -230,18 +234,23 @@ public:
static VkPhysicalDeviceFeatures getEnabledFeatures()
{
VkPhysicalDeviceFeatures enabledFeatures = {};
enabledFeatures.shaderResourceResidency = VK_TRUE;
enabledFeatures.shaderResourceResidency = VK_TRUE;
enabledFeatures.shaderResourceMinLod = VK_TRUE;
return enabledFeatures;
}
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION, getEnabledFeatures)
{
zoom = -2.5f;
rotation = { 0.0f, 15.0f, 0.0f };
title = "Vulkan Example - Sparse textures residency";
zoom = -1.3f;
rotation = { 76.25f, 0.0f, 0.0f };
title = "Vulkan Example - Sparse texture residency";
enableTextOverlay = true;
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()
@ -277,7 +286,7 @@ public:
texture.device = vulkanDevice->logicalDevice;
texture.width = width;
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.format = format;
@ -450,7 +459,7 @@ public:
if ((x % 2 == 1) || (y % 2 == 1))
{
// Allocate memory for this virtual page
newPage->allocate(device, memoryTypeIndex);
//newPage->allocate(device, memoryTypeIndex);
}
index++;
@ -629,6 +638,11 @@ public:
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()
{
// Setup vertices for a single uv-mapped quad made from two triangles
@ -892,10 +906,11 @@ public:
void prepare()
{
VulkanExampleBase::prepare();
loadAssets();
generateQuad();
setupVertexDescriptions();
prepareUniformBuffers();
prepareSparseTexture(8192, 8192, 1, VK_FORMAT_R8G8B8A8_UNORM);
prepareSparseTexture(4096, 4096, 1, VK_FORMAT_R8G8B8A8_UNORM);
setupDescriptorSetLayout();
preparePipelines();
setupDescriptorPool();
@ -953,17 +968,75 @@ public:
vkDeviceWaitIdle(device);
std::default_random_engine rndEngine(std::random_device{}());
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)
{
if (rndDist(rndEngine) < 0.5f)
if ((rndDist(rndEngine) < 0.5f) && (page.imageMemoryBind.memory == VK_NULL_HANDLE))
{
// Allocate page memory
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();
vkQueueBindSparse(queue, 1, &texture.bindSparseInfo, VK_NULL_HANDLE);
//todo: use sparse bind semaphore
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)
@ -989,12 +1062,15 @@ public:
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;
ss << std::setprecision(2) << std::fixed << uboVS.lodBias;
#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
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
}
};