Randomly fill virtual pages, check if sparse residency for 2D images is supported
This commit is contained in:
parent
9ce827b3f3
commit
18b7a52ece
5 changed files with 113 additions and 28 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -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;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -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
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue