From 18b7a52ece7389721a9320a9526163e93ebdfd1c Mon Sep 17 00:00:00 2001 From: saschawillems Date: Sat, 17 Sep 2016 19:08:27 +0200 Subject: [PATCH] Randomly fill virtual pages, check if sparse residency for 2D images is supported --- .../sparseresidency.frag | 26 +++-- .../sparseresidency.frag.spv | Bin 1676 -> 1556 bytes .../sparseresidency.vert | 17 +-- .../sparseresidency.vert.spv | Bin 3552 -> 1908 bytes .../texturesparseresidency.cpp | 98 ++++++++++++++++-- 5 files changed, 113 insertions(+), 28 deletions(-) diff --git a/data/shaders/texturesparseresidency/sparseresidency.frag b/data/shaders/texturesparseresidency/sparseresidency.frag index a415a0d1..63660bfd 100644 --- a/data/shaders/texturesparseresidency/sparseresidency.frag +++ b/data/shaders/texturesparseresidency/sparseresidency.frag @@ -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); diff --git a/data/shaders/texturesparseresidency/sparseresidency.frag.spv b/data/shaders/texturesparseresidency/sparseresidency.frag.spv index 477433919c753272f16b46cd304924df4fd0896d..f6fae7bc240d4c930f562ed5ab50e83a55f75321 100644 GIT binary patch literal 1556 zcmZvcSx*!}6oqS;g;A76HW9@ha0f?4K#W^p66a+S1-HjZXS!o1X{IOLO(JjpHvg1M zV&eJAD$@@ZxpV8BbL-ZvTh&x2HYSa!=&xy>n!jVtOb8o;zbijw8WwkZ?|SXLh}t{5 z4~d*MRh-pkw7#Y}b`lOp@Jq54*(2GkV$rmjW>sZ2=9@ODiRt$G2gir~d>m$Z+%MuU z#c39Aqc#7p^#@6KGB$NZl=lOlQ{F+Eq?vqObx+G@aXyUV(cr9;MzP~B$>&Ov#97CM z+kDhK9DVpGCtSDn4@bQ;Ivj?%ZYD`8N*}pat~nYT9Yxr^cC!NdhGRib(j9OY^RN#FKONo7s!^i zo_he(zd*lDc{prS811}_u_YFMN(NW9Ma5na7s#lETo>huhhNc+%*c}uy*xZ#Rc*5p zh-3Yn3xa#*F#Tar`+_|AI3w|k^5lXi9!$UB&@a0=YtX^;4}DFT`=nNCUQpKS@~jIS z=kX1P$>V!;OLJqszVbbKAOu(L5xMwa_*&S58o=Bc9B0~=CogzUuZpvAHw?HRV(Rj& z<*s<=J{SGwoqHT;-YQ}0<}ISXR5sRfmoJoy9?#3@FPI)K%jh4Nny$#~cU+mYy}ByQ z8sg|7`jM(5|1}vpyx$8BogVW>(HZE}4aZ*Sd;@ULD>Zu$8;&EEGl7|N9{S8W?&r1) z{kt^&XEA^;0dXZlA}u>Zm_Gdtna8I0O_+XRWAH2TBc|-|LH%8QElHbewXJoO zqh%?zaueQ0~^&4MwPUY+z9g|ouwcpZ{*lrqA zQnZ+3Nwp2>{@5l#(}s=H{itb$;V;N1ey7{E@qW~fVnMf`x`Ob-Q4g10jnPT^GWJ^q zUCGrQg!QPo7x+ru?VXc9w8{I^u61`@6IOP%Es_M%Om|bhkzHDnlKutZt0?aHZ7s!= zTt9>GD6n6TY$N07ukH+5$EhO^R4sKZ$@p@-s5LVNQ_q5o56sMpnE8QoJ-L9H8+zsn z<~4xH0ZgAKr9!vpCf(aJtw>p1RmPcBVcr4;KO^n1YUbKw8byS^U{wffR3}y zXCk;K8Kwt(v%+KYoJU^h$K^Q-9zB?zz@eX%M^8QIr{t*>9zB?z!4aR4XD@q*gXtmM zf-rA@I@v#^EUwD4kDk$k9N)+=x>dzF@2CAI#K{$oyNFk1 za8LUN-7FR}4lQ+n(K4qc8Qf3BuFLcNQ4D@rwko4Htl2}Yw`9dyZwnV|T@j|%kLnQh z+>x;d9W@ar7kWtSx6bEo?%}>X##<=H(2xUX@&nHP*Q%5^u#s`@hh1y#VaD`~{_CgH lY2?nh2N{Pp*VQtPy>GJox3p$Idg8oKa%3*V{_3_J*+0(-e}Di0 diff --git a/data/shaders/texturesparseresidency/sparseresidency.vert b/data/shaders/texturesparseresidency/sparseresidency.vert index 51ace177..2ef3a344 100644 --- a/data/shaders/texturesparseresidency/sparseresidency.vert +++ b/data/shaders/texturesparseresidency/sparseresidency.vert @@ -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; + */ } diff --git a/data/shaders/texturesparseresidency/sparseresidency.vert.spv b/data/shaders/texturesparseresidency/sparseresidency.vert.spv index ce9b686dcedd40b91ec4effb2fe2c4514d140da4..f6a965713882bacab828f5566e9c67ff8cdd58a1 100644 GIT binary patch delta 101 zcmaDL{e_R0nMs+Qfq@YSIT-9G@|rSoPjpsgwA)yk$tb|eV8_6~keTO~UzD4e!@#gP uib;!+6C@@F#7vv_GGAxpwPs*pPylj4!i`#S%*Z literal 3552 zcmZ9OX?Ijb5QZ-ai6|%{vbbRucQ7CVqR5iCBx)oHOWd7Ik}(WSX5!2Q2&hE;1L{xm zSNX+re4aa9u}O0(UGLjf)wT4ULx11sBSo=;f4hp`ir(5+^nr_FcQIJ*lhaqH$2#5R zu~Vl{Xz@hRUm9w&7v$QBtXAty^+%E2h$q9yapV)^JEV(jApQL7WB;2VJMoyDu8d!q zsB~&;)poU8t8{Kumuu}xYw>1nsoQzjhNF6OrP8Q2SJta5waTfJC)TP>nh=g{x8+Kpu$SmtQY>dhW8K$JJZD~-x* ztvz3BcWZaGGdFpcXRS`XOwRcB+ogVyeT~r8>I|s$a;v>sHD@_zQg3ciCAR?AsIT1U zW;rd&ZQ+4(j`mHn`Px$H=Un0DDPO9XO#MFs?-JX8vAq-fMgmWP?W=15nc{EY(UN_b z_f;Q?5$Vq*${XaySDP@ z681Zh^ZYUP9Y~yu&0Ws($JwKxW=q~NwXZI}pFQA)i;Hh*Txrlu? z`q<;k?4Ct@bDKe2k-P88+>epDwpB!%5bccXdoxbpjf5lbdtm!y-uIJko@aRL^3K_1 zjDKMKCXHqP{k@BKWsUwm1@?Sl8(vKKJpS74L41oBi0+#ek8^{wKZN*Rd=uK+gTsit z_P$ZE_RiXGNPFLa_Rjr9L|$xN|@rm)G)c;_|+|2dBUGp67i#2ljq# z%-QegJaQbdF6$O+7d2f%-(J%=oP6Xzfu8680a(rz`G1Hmm*@Xc;`-QQ?jNJ;uf6Aa z{*z$u*2Y}@9(r8wjeZK=p6h3D^4HRvoko}2!wYpDpCjfpf_OFuKgd3dcor-8If&qU zwe;+-WW4o+{nf;4>k9rFdfc7Ixt{TPocYAdxgyRN=*E%H<9wO%p3PE~-{@DRu76RO zbMRlIo2z-5L-60Ad$;!(Q{LatZxLhZr%k+t@6rA3^jr153ZkvNGxK*?PJMyBio{!6 zLf<~WWjOh$w}vhkEBGHEg3tS~lJR*zZzNt@SH!8K8%I8mb2H=fIJXin=ZZKDbmPe9 zaaJ?lv*>dZ-P)|foP%$no2z-5L-1?p-t9fcjJf=XZY=$@iMh1V7m%1s2VGlvXR*jG z7xwGua$~jBNc^3H(Vs+}& diff --git a/texturesparseresidency/texturesparseresidency.cpp b/texturesparseresidency/texturesparseresidency.cpp index 9eff45c4..3d456a1e 100644 --- a/texturesparseresidency/texturesparseresidency.cpp +++ b/texturesparseresidency/texturesparseresidency.cpp @@ -196,6 +196,10 @@ public: uint32_t layerCount; } texture; + struct { + vkTools::VulkanTexture source; + } textures; + struct { VkPipelineVertexInputStateCreateInfo inputState; std::vector 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 rndDist(0.0f, 1.0f); + // Fill random parts of the texture blitting from a source to the virtual texture + std::vector 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(textures.source.width), static_cast(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(page.offset.x + x * 128 / scale); + blit.dstOffsets[0].y = static_cast(page.offset.y + y * 128 / scale); + blit.dstOffsets[0].z = 0; + blit.dstOffsets[1].x = static_cast(blit.dstOffsets[0].x + page.extent.width / scale); + blit.dstOffsets[1].y = static_cast(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(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 } };