From e112e3115067bcd9b643e3ece8ae55776d0b98d9 Mon Sep 17 00:00:00 2001 From: Cheng Cao Date: Sun, 1 Oct 2023 00:40:01 -0700 Subject: [PATCH] Reflection based safe descriptor set updates & set-typed pools --- .../me/cortex/vulkanite/client/Vulkanite.java | 26 +++ .../client/rendering/VulkanPipeline.java | 186 +++++++----------- .../me/cortex/vulkanite/lib/cmd/VCmdBuff.java | 19 +- .../descriptors/DescriptorUpdateBuilder.java | 33 ++++ .../lib/descriptors/VDescriptorSet.java | 21 ++ .../lib/descriptors/VDescriptorSetLayout.java | 2 + .../lib/descriptors/VTypedDescriptorPool.java | 87 ++++++++ .../cortex/vulkanite/lib/memory/VBuffer.java | 15 +- .../shader/reflection/ShaderReflection.java | 5 + 9 files changed, 265 insertions(+), 129 deletions(-) create mode 100644 src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java create mode 100644 src/main/java/me/cortex/vulkanite/lib/descriptors/VTypedDescriptorPool.java diff --git a/src/main/java/me/cortex/vulkanite/client/Vulkanite.java b/src/main/java/me/cortex/vulkanite/client/Vulkanite.java index 86cf6b0..31f2fe2 100644 --- a/src/main/java/me/cortex/vulkanite/client/Vulkanite.java +++ b/src/main/java/me/cortex/vulkanite/client/Vulkanite.java @@ -5,12 +5,16 @@ import me.cortex.vulkanite.client.rendering.VulkanPipeline; import me.cortex.vulkanite.lib.base.VContext; import me.cortex.vulkanite.lib.base.initalizer.VInitializer; +import me.cortex.vulkanite.lib.descriptors.VDescriptorPool; +import me.cortex.vulkanite.lib.descriptors.VDescriptorSetLayout; +import me.cortex.vulkanite.lib.descriptors.VTypedDescriptorPool; import me.jellysquid.mods.sodium.client.render.chunk.RenderSection; import me.jellysquid.mods.sodium.client.render.chunk.compile.ChunkBuildOutput; import net.minecraft.util.Util; import org.lwjgl.vulkan.*; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import static org.lwjgl.vulkan.EXTDebugUtils.VK_EXT_DEBUG_UTILS_EXTENSION_NAME; @@ -50,6 +54,7 @@ public class Vulkanite { private final ArbitarySyncPointCallback fencedCallback = new ArbitarySyncPointCallback(); private final AccelerationManager accelerationManager; + private final HashMap descriptorPools = new HashMap<>(); public Vulkanite() { ctx = createVulkanContext(); @@ -70,6 +75,24 @@ public void upload(List results) { accelerationManager.chunkBuilds(results); } + public VTypedDescriptorPool getPoolByLayout(VDescriptorSetLayout layout) { + synchronized (descriptorPools) { + if (!descriptorPools.containsKey(layout)) { + descriptorPools.put(layout, new VTypedDescriptorPool(ctx, layout, 0)); + } + return descriptorPools.get(layout); + } + } + + public void removePoolByLayout(VDescriptorSetLayout layout) { + synchronized (descriptorPools) { + if (descriptorPools.containsKey(layout)) { + descriptorPools.get(layout).free(); + descriptorPools.remove(layout); + } + } + } + public void sectionRemove(RenderSection section) { accelerationManager.sectionRemove(section); } @@ -92,6 +115,9 @@ public void addSyncedCallback(Runnable callback) { } public void destroy() { + for (var pool : descriptorPools.values()) { + pool.free(); + } accelerationManager.cleanup(); } diff --git a/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java b/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java index 3460ed7..e58708d 100644 --- a/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java +++ b/src/main/java/me/cortex/vulkanite/client/rendering/VulkanPipeline.java @@ -62,13 +62,6 @@ public class VulkanPipeline { private record RtPipeline(VRaytracePipeline pipeline, int commonSet, int geomSet, int customTexSet, int ssboSet) {} private RtPipeline[] raytracePipelines; - private VDescriptorSetLayout commonLayout; - private VDescriptorSetLayout customtexLayout; - private VDescriptorSetLayout storageBufferLayout; - - private VDescriptorPool commonDescriptorPool; - private VDescriptorPool customtexDescriptorPool; - private VDescriptorPool storageBufferDescriptorPool; private final VSampler sampler; private final VSampler ctexSampler; @@ -170,40 +163,6 @@ public VulkanPipeline(VContext ctx, AccelerationManager accelerationManager, Ray .maxAnisotropy(1.0f)); try { - commonLayout = new DescriptorSetLayoutBuilder() - .binding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL)// camera data - .binding(1, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, VK_SHADER_STAGE_ALL)// funni acceleration buffer - .binding(3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_ALL)//block texture - .binding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_ALL)//block texture normal - .binding(5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_ALL)//block texture specular - // Reordered these so output texture is last... this means you can dynamically add more output textures without messing other ids - .binding(6, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, maxIrisRenderTargets, VK_SHADER_STAGE_ALL)// output texture - .build(ctx); - - DescriptorSetLayoutBuilder ctexLayoutBuilder = new DescriptorSetLayoutBuilder(); - for (int i = 0; i < customTextureViews.length; i++) { - ctexLayoutBuilder.binding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_ALL); - } - - customtexLayout = ctexLayoutBuilder.build(ctx); - - DescriptorSetLayoutBuilder ssboLayoutBuilder = new DescriptorSetLayoutBuilder(); - for (int id : ssboIds) { - ssboLayoutBuilder.binding(id, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_ALL); - } - - storageBufferLayout = ssboLayoutBuilder.build(ctx); - - //TODO: use frameahead count instead of just... 10 - commonDescriptorPool = new VDescriptorPool(ctx, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 10, commonLayout.types); - commonDescriptorPool.allocateSets(commonLayout); - - customtexDescriptorPool = new VDescriptorPool(ctx, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 10, customtexLayout.types); - customtexDescriptorPool.allocateSets(customtexLayout); - - storageBufferDescriptorPool = new VDescriptorPool(ctx, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 10, storageBufferLayout.types); - storageBufferDescriptorPool.allocateSets(storageBufferLayout); - var commonSetExpected = new ShaderReflection.Set(new ShaderReflection.Binding[]{ new ShaderReflection.Binding("", 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, false), new ShaderReflection.Binding("", 1, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 0, false), @@ -329,46 +288,13 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag uboBuffer.unmap(); uboBuffer.flush(); - long commonSet = commonDescriptorPool.get(fidx); - long ctexSet = customtexDescriptorPool.get(fidx); - long ssboSet = storageBufferDescriptorPool.get(fidx); - - var updater = new DescriptorUpdateBuilder(ctx, 7) - .set(commonSet) - .uniform(0, uboBuffer) - .acceleration(1, tlas) - .imageSampler(3, blockAtlasView.getView(), sampler) - .imageSampler(4, - blockAtlasNormalView.getView() != null ? blockAtlasNormalView.getView() - : placeholderNormalsView, - sampler) - .imageSampler(5, - blockAtlasSpecularView.getView() != null ? blockAtlasSpecularView.getView() - : placeholderSpecularView, - sampler); - List outImgViewList = new ArrayList<>(outImgs.size()); - for (int i = 0; i < outImgs.size(); i++) { - int index = i; - outImgViewList.add(irisRenderTargetViews[i].getView(() -> outImgs.get(index))); - } - updater.imageStore(6, 0, outImgViewList); - updater.apply(); - - updater = new DescriptorUpdateBuilder(ctx, customTextureViews.length) - .set(ctexSet); - - for (int i = 0; i < customTextureViews.length; i++) { - updater.imageSampler(i, customTextureViews[i].getView(), ctexSampler); - } - updater.apply(); - - updater = new DescriptorUpdateBuilder(ctx, ssbos.length) - .set(ssboSet); - - for (ShaderStorageBuffer ssbo : ssbos) { - updater.buffer(ssbo.getIndex(), ((IVGBuffer) ssbo).getBuffer()); + // Call getView() on shared image view trackers to ensure they are created + blockAtlasView.getView(); + blockAtlasNormalView.getView(); + blockAtlasSpecularView.getView(); + for (var v : customTextureViews) { + v.getView(); } - updater.apply(); //TODO: dont use a single use pool for commands like this... var cmd = singleUsePool.createCommandBuffer(); @@ -392,23 +318,69 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag } } - for (var pipeline : raytracePipelines) { - pipeline.pipeline.bind(cmd); - var sets = new TreeMap(); - if (pipeline.commonSet != -1) { - sets.put(pipeline.commonSet, commonSet); + for (var record : raytracePipelines) { + var pipeline = record.pipeline; + pipeline.bind(cmd); + var layouts = pipeline.reflection.getLayouts(); // Should be cached already + var sets = new long[layouts.size()]; + if (record.commonSet != -1) { + var commonSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.commonSet)).allocateSet(); + + var updater = new DescriptorUpdateBuilder(ctx, pipeline.reflection.getSet(record.commonSet)) + .set(commonSet.set) + .uniform(0, uboBuffer) + .acceleration(1, tlas) + .imageSampler(3, blockAtlasView.getView(), sampler) + .imageSampler(4, + blockAtlasNormalView.getView() != null ? blockAtlasNormalView.getView() + : placeholderNormalsView, + sampler) + .imageSampler(5, + blockAtlasSpecularView.getView() != null ? blockAtlasSpecularView.getView() + : placeholderSpecularView, + sampler); + List outImgViewList = new ArrayList<>(outImgs.size()); + for (int i = 0; i < outImgs.size(); i++) { + int index = i; + outImgViewList.add(irisRenderTargetViews[i].getView(() -> outImgs.get(index))); + } + updater.imageStore(6, 0, outImgViewList); + updater.apply(); + + sets[record.commonSet] = commonSet.set; + cmd.addTransientResource(commonSet); } - if (pipeline.geomSet != -1) { - sets.put(pipeline.geomSet, accelerationManager.getGeometrySet()); + if (record.geomSet != -1) { + sets[record.geomSet] = accelerationManager.getGeometrySet(); } - if (pipeline.customTexSet != -1) { - sets.put(pipeline.customTexSet, ctexSet); + if (record.customTexSet != -1) { + var ctexSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.customTexSet)).allocateSet(); + + var updater = new DescriptorUpdateBuilder(ctx, pipeline.reflection.getSet(record.customTexSet)) + .set(ctexSet.set); + for (int i = 0; i < customTextureViews.length; i++) { + updater.imageSampler(i, customTextureViews[i].getView(), ctexSampler); + } + updater.apply(); + + sets[record.customTexSet] = ctexSet.set; + cmd.addTransientResource(ctexSet); } - if (pipeline.ssboSet != -1) { - sets.put(pipeline.ssboSet, ssboSet); + if (record.ssboSet != -1) { + var ssboSet = Vulkanite.INSTANCE.getPoolByLayout(layouts.get(record.ssboSet)).allocateSet(); + + var updater = new DescriptorUpdateBuilder(ctx, pipeline.reflection.getSet(record.ssboSet)) + .set(ssboSet.set); + for (ShaderStorageBuffer ssbo : ssbos) { + updater.buffer(ssbo.getIndex(), ((IVGBuffer) ssbo).getBuffer()); + } + updater.apply(); + + sets[record.ssboSet] = ssboSet.set; + cmd.addTransientResource(ssboSet); } - pipeline.pipeline.bindDSet(cmd, sets.values().stream().mapToLong(a->a).toArray()); - pipeline.pipeline.trace(cmd, outImgs.get(0).width, outImgs.get(0).height, 1); + pipeline.bindDSet(cmd, sets); + pipeline.trace(cmd, outImgs.get(0).width, outImgs.get(0).height, 1); // Barrier on the output images for (var img : outImgs) { @@ -459,23 +431,10 @@ public void renderPostShadows(List outImgs, Camera camera, ShaderStorag } public void destory() { - for (var pass : raytracePipelines) { - if (pass != null) { - pass.pipeline.free(); - } - } - if (commonLayout != null) - commonLayout.free(); - if (customtexLayout != null) - customtexLayout.free(); - if (storageBufferLayout != null) - storageBufferLayout.free(); - if (commonDescriptorPool != null) - commonDescriptorPool.free(); - if (customtexDescriptorPool != null) - customtexDescriptorPool.free(); - if (storageBufferDescriptorPool != null) - storageBufferDescriptorPool.free(); + vkDeviceWaitIdle(ctx.device); + + // Check pending fences first + // Then destroy the cmd pool (which destroys linked transient resources) ctx.sync.checkFences(); if (singleUsePool != null) { singleUsePool.doReleases(); @@ -484,6 +443,13 @@ public void destory() { if (previousSemaphore != null) { previousSemaphore.free(); } + // Finally destroy the pipelines + // (Which destroys the descriptor set layouts & releases the VTypedDescriptorPool) + for (var pass : raytracePipelines) { + if (pass != null) { + pass.pipeline.free(); + } + } for (SharedImageViewTracker customTexView : customTextureViews) { if (customTexView != null) diff --git a/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java b/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java index 599e3af..bf61272 100644 --- a/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java +++ b/src/main/java/me/cortex/vulkanite/lib/cmd/VCmdBuff.java @@ -25,6 +25,8 @@ import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR; import static org.lwjgl.vulkan.KHRAccelerationStructure.VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.LinkedList; //TODO: Track with TrackedResourceObject but need to be careful due to how the freeing works @@ -32,12 +34,12 @@ public class VCmdBuff extends TrackedResourceObject implements Pointer { private final VCommandPool pool; public final VkCommandBuffer buffer; - private LinkedList transientBuffers; + private HashSet transientResources; VCmdBuff(VCommandPool pool, VkCommandBuffer buff) { this.pool = pool; this.buffer = buff; - this.transientBuffers = new LinkedList<>(); + this.transientResources = new HashSet<>(); } //Enqueues the pool to be freed by the owning thread @@ -69,7 +71,7 @@ public void encodeDataUpload(MemoryManager manager, long src, VBuffer dest, long vkCmdCopyBuffer(buffer, staging.buffer(), dest.buffer(), copy); } - transientBuffers.add(staging); + transientResources.add(staging); } public void encodeImageUpload(MemoryManager manager, long src, VImage dest, long srcSize, int destLayout) { @@ -89,7 +91,7 @@ public void encodeImageUpload(MemoryManager manager, long src, VImage dest, long vkCmdCopyBufferToImage(buffer, staging.buffer(), dest.image(), destLayout, copy); } - transientBuffers.add(staging); + transientResources.add(staging); } public void encodeMemoryBarrier() { @@ -102,6 +104,10 @@ public void encodeMemoryBarrier() { } } + public void addTransientResource(TrackedResourceObject resource) { + transientResources.add(resource); + } + public static int dstStageToAccess(int dstStage) { switch (dstStage) { case VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT: @@ -200,8 +206,7 @@ public void free() { void freeInternal() { free0(); vkFreeCommandBuffers(pool.device, pool.pool, buffer); - while (!transientBuffers.isEmpty()) { - transientBuffers.removeFirst().free(); - } + transientResources.forEach(TrackedResourceObject::free); + transientResources.clear(); } } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java index 1272190..9811c51 100644 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/DescriptorUpdateBuilder.java @@ -5,6 +5,7 @@ import me.cortex.vulkanite.lib.memory.VBuffer; import me.cortex.vulkanite.lib.other.VImageView; import me.cortex.vulkanite.lib.other.VSampler; +import me.cortex.vulkanite.lib.shader.reflection.ShaderReflection; import org.lwjgl.system.MemoryStack; import org.lwjgl.vulkan.VkDescriptorBufferInfo; import org.lwjgl.vulkan.VkDescriptorImageInfo; @@ -21,6 +22,8 @@ public class DescriptorUpdateBuilder { private final MemoryStack stack; private final VkWriteDescriptorSet.Buffer updates; private final VImageView placeholderImageView; + private ShaderReflection.Set refSet = null; + public DescriptorUpdateBuilder(VContext ctx, int maxUpdates) { this(ctx, maxUpdates, null); } @@ -32,6 +35,15 @@ public DescriptorUpdateBuilder(VContext ctx, int maxUpdates, VImageView placehol this.placeholderImageView = placeholderImageView; } + public DescriptorUpdateBuilder(VContext ctx, ShaderReflection.Set refSet) { + this(ctx, refSet, null); + } + + public DescriptorUpdateBuilder(VContext ctx, ShaderReflection.Set refSet, VImageView placeholderImageView) { + this(ctx, refSet.bindings().size(), placeholderImageView); + this.refSet = refSet; + } + private long viewOrPlaceholder(VImageView v) { if (v == null && placeholderImageView == null) return 0; return v == null ? placeholderImageView.view : v.view; @@ -47,6 +59,9 @@ public DescriptorUpdateBuilder buffer(int binding, VBuffer buffer) { return buffer(binding, buffer, 0, VK_WHOLE_SIZE); } public DescriptorUpdateBuilder buffer(int binding, VBuffer buffer, long offset, long range) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } updates.get() .sType$Default() .dstBinding(binding) @@ -63,6 +78,9 @@ public DescriptorUpdateBuilder buffer(int binding, VBuffer buffer, long offset, } public DescriptorUpdateBuilder buffer(int binding, int dstArrayElement, List buffers) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } var bufInfo = VkDescriptorBufferInfo.calloc(buffers.size(), stack); for (int i = 0; i < buffers.size(); i++) { bufInfo.get(i) @@ -87,6 +105,9 @@ public DescriptorUpdateBuilder uniform(int binding, VBuffer buffer) { return uniform(binding, buffer, 0, VK_WHOLE_SIZE); } public DescriptorUpdateBuilder uniform(int binding, VBuffer buffer, long offset, long range) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } updates.get() .sType$Default() .dstBinding(binding) @@ -102,6 +123,9 @@ public DescriptorUpdateBuilder uniform(int binding, VBuffer buffer, long offset, } public DescriptorUpdateBuilder acceleration(int binding, VAccelerationStructure... structures) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } var buff = stack.mallocLong(structures.length); for (var structure : structures) { buff.put(structure.structure); @@ -120,6 +144,9 @@ public DescriptorUpdateBuilder acceleration(int binding, VAccelerationStructure. } public DescriptorUpdateBuilder imageStore(int binding, int dstArrayElement, List views) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } var imgInfo = VkDescriptorImageInfo.calloc(views.size(), stack); for (int i = 0; i < views.size(); i++) { imgInfo.get(i) @@ -139,6 +166,9 @@ public DescriptorUpdateBuilder imageStore(int binding, VImageView view) { return imageStore(binding, VK_IMAGE_LAYOUT_GENERAL, view); } public DescriptorUpdateBuilder imageStore(int binding, int layout, VImageView view) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } updates.get() .sType$Default() .dstBinding(binding) @@ -157,6 +187,9 @@ public DescriptorUpdateBuilder imageSampler(int binding, VImageView view, VSampl } public DescriptorUpdateBuilder imageSampler(int binding, int layout, VImageView view, VSampler sampler) { + if (refSet != null && refSet.getBindingAt(binding) == null) { + return this; + } updates.get() .sType$Default() .dstBinding(binding) diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java new file mode 100644 index 0000000..825afc7 --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSet.java @@ -0,0 +1,21 @@ +package me.cortex.vulkanite.lib.descriptors; + +import me.cortex.vulkanite.lib.base.TrackedResourceObject; + +public class VDescriptorSet extends TrackedResourceObject { + private final VTypedDescriptorPool pool; + public final long poolHandle; + public final long set; + + VDescriptorSet(VTypedDescriptorPool pool, long poolHandle, long set) { + this.pool = pool; + this.poolHandle = poolHandle; + this.set = set; + } + + @Override + public void free() { + free0(); + pool.freeSet(this); + } +} diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java index ea8c170..5ff63cd 100644 --- a/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/VDescriptorSetLayout.java @@ -1,5 +1,6 @@ package me.cortex.vulkanite.lib.descriptors; +import me.cortex.vulkanite.client.Vulkanite; import me.cortex.vulkanite.lib.base.TrackedResourceObject; import me.cortex.vulkanite.lib.base.VContext; import org.lwjgl.system.Pointer; @@ -32,6 +33,7 @@ public long address() { @Override public void free() { + Vulkanite.INSTANCE.removePoolByLayout(this); free0(); vkDestroyDescriptorSetLayout(ctx.device, layout, null); } diff --git a/src/main/java/me/cortex/vulkanite/lib/descriptors/VTypedDescriptorPool.java b/src/main/java/me/cortex/vulkanite/lib/descriptors/VTypedDescriptorPool.java new file mode 100644 index 0000000..c7113b4 --- /dev/null +++ b/src/main/java/me/cortex/vulkanite/lib/descriptors/VTypedDescriptorPool.java @@ -0,0 +1,87 @@ +package me.cortex.vulkanite.lib.descriptors; + +import me.cortex.vulkanite.lib.base.TrackedResourceObject; +import me.cortex.vulkanite.lib.base.VContext; +import org.lwjgl.vulkan.VkDescriptorPoolCreateInfo; +import org.lwjgl.vulkan.VkDescriptorPoolSize; +import org.lwjgl.vulkan.VkDescriptorSetAllocateInfo; + +import java.nio.LongBuffer; +import java.util.ArrayList; + +import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; +import static org.lwjgl.system.MemoryStack.stackPush; +import static org.lwjgl.vulkan.VK10.*; + +public class VTypedDescriptorPool extends TrackedResourceObject { + private final VContext ctx; + private final ArrayList pools = new ArrayList<>(); + private final ArrayList poolFreeSizes = new ArrayList<>(); + private final VDescriptorSetLayout layout; + private final int flags; + + private static final int nSetsPerPool = 16; + + public VTypedDescriptorPool(VContext ctx, VDescriptorSetLayout layout, int flags) { + this.ctx = ctx; + this.layout = layout; + this.flags = flags; + } + + private void createNewPool() { + try (var stack = stackPush()) { + var sizes = VkDescriptorPoolSize.calloc(layout.types.length, stack); + for (int i = 0; i < layout.types.length; i++) { + sizes.get(i).type(layout.types[i]).descriptorCount(nSetsPerPool); + } + LongBuffer pPool = stack.mallocLong(1); + _CHECK_(vkCreateDescriptorPool(ctx.device, VkDescriptorPoolCreateInfo.calloc(stack) + .sType$Default() + .flags(flags | VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT) + .maxSets(nSetsPerPool) + .pPoolSizes(sizes), null, pPool)); + pools.add(pPool.get(0)); + poolFreeSizes.add(nSetsPerPool); + } + } + + public VDescriptorSet allocateSet() { + if (poolFreeSizes.isEmpty() || poolFreeSizes.get(pools.size() - 1) == 0) { + createNewPool(); + } + long pool = pools.get(pools.size() - 1); + long set; + poolFreeSizes.set(pools.size() - 1, poolFreeSizes.get(pools.size() - 1) - 1); + try (var stack = stackPush()) { + var pSet = stack.mallocLong(1); + _CHECK_(vkAllocateDescriptorSets(ctx.device, VkDescriptorSetAllocateInfo.calloc(stack) + .sType$Default() + .descriptorPool(pool) + .pSetLayouts(stack.mallocLong(1).put(0, layout.layout)), pSet)); + set = pSet.get(0); + } + return new VDescriptorSet(this, pool, set); + } + + public void freeSet(VDescriptorSet set) { + int index = pools.indexOf(set.poolHandle); + try (var stack = stackPush()) { + var pDescriptorSets = stack.mallocLong(1).put(0, set.set); + _CHECK_(vkFreeDescriptorSets(ctx.device, set.poolHandle, pDescriptorSets)); + } + poolFreeSizes.set(index, poolFreeSizes.get(index) + 1); + if (poolFreeSizes.get(index) == nSetsPerPool) { + vkDestroyDescriptorPool(ctx.device, set.poolHandle, null); + pools.remove(index); + poolFreeSizes.remove(index); + } + } + + @Override + public void free() { + free0(); + for (long pool : pools) { + vkDestroyDescriptorPool(ctx.device, pool, null); + } + } +} diff --git a/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java b/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java index 95fcd39..17753d0 100644 --- a/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java +++ b/src/main/java/me/cortex/vulkanite/lib/memory/VBuffer.java @@ -1,20 +1,10 @@ package me.cortex.vulkanite.lib.memory; -import org.lwjgl.system.MemoryStack; -import org.lwjgl.vulkan.VkBufferDeviceAddressInfo; -import org.lwjgl.vulkan.VkDevice; -import org.lwjgl.vulkan.VkDeviceOrHostAddressKHR; -import org.lwjgl.vulkan.VkMappedMemoryRange; +import me.cortex.vulkanite.lib.base.TrackedResourceObject; -import java.lang.ref.Cleaner; - -import static me.cortex.vulkanite.lib.other.VUtil._CHECK_; -import static org.lwjgl.system.MemoryStack.stackPush; -import static org.lwjgl.vulkan.KHRBufferDeviceAddress.vkGetBufferDeviceAddressKHR; import static org.lwjgl.vulkan.VK10.VK_WHOLE_SIZE; -import static org.lwjgl.vulkan.VK10.vkFlushMappedMemoryRanges; -public class VBuffer { +public class VBuffer extends TrackedResourceObject { private VmaAllocator.BufferAllocation allocation; VBuffer(VmaAllocator.BufferAllocation allocation) { @@ -26,6 +16,7 @@ public long buffer() { } public void free() { + free0(); allocation.free(); allocation = null; } diff --git a/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java b/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java index 03868ba..20612ae 100644 --- a/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java +++ b/src/main/java/me/cortex/vulkanite/lib/shader/reflection/ShaderReflection.java @@ -220,6 +220,7 @@ public List buildSetLayouts(VContext context, int runtimeS | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT); } else { builder.binding(binding.binding, binding.descriptorType, binding.arraySize, VK_SHADER_STAGE_ALL); + builder.setBindingFlags(binding.binding, VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT); } } else { builder.binding(binding.binding, binding.descriptorType, VK_SHADER_STAGE_ALL); @@ -230,6 +231,10 @@ public List buildSetLayouts(VContext context, int runtimeS return layouts; } + public final List getLayouts() { + return layouts; + } + public void freeLayouts() { for (var l : layouts) { l.free();