Skip to content

Commit dbfc563

Browse files
committed
Improve descriptor set and descriptor pool memory management
There's still a lot of stuff to be done, though
1 parent afff3c8 commit dbfc563

2 files changed

Lines changed: 96 additions & 60 deletions

File tree

src/main/java/git/artdeell/artvk/Vk11DescriptorPool.java

Lines changed: 91 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import net.fabricmc.api.EnvType;
55
import net.fabricmc.api.Environment;
66
import org.lwjgl.system.MemoryStack;
7+
import org.lwjgl.system.MemoryUtil;
78
import org.lwjgl.vulkan.VK10;
89
import org.lwjgl.vulkan.VkDescriptorPoolCreateInfo;
910
import org.lwjgl.vulkan.VkDescriptorPoolSize;
@@ -13,15 +14,19 @@
1314
@Environment(EnvType.CLIENT)
1415
public class Vk11DescriptorPool implements Destroyable {
1516
public static final int SETS_PER_FRAME = 1512;
16-
private static final int TOTAL_SETS = Vk11CommandEncoder.MAX_SUBMITS_IN_FLIGHT * SETS_PER_FRAME;
17+
public static final int SET_PREALLOCATE_COUNT = 504;
18+
public static final int RECLAIM_THRESHOLD = 504;
1719

1820
private final Vk11Device device;
19-
private final long pool;
20-
private final long[] sets = new long[TOTAL_SETS];
21-
private final int[] frameSetIndex = new int[Vk11CommandEncoder.MAX_SUBMITS_IN_FLIGHT];
21+
private final PoolObject[] pools = new PoolObject[Vk11CommandEncoder.MAX_SUBMITS_IN_FLIGHT];
22+
private final LongBuffer bindGroupLayouts;
23+
private long currentSet;
2224

2325
public Vk11DescriptorPool(final Vk11Device device, final Vk11CommandEncoder encoder, final Vk11BindGroupLayout layout) {
2426
this.device = device;
27+
long bindGroupLayout = layout.handle();
28+
bindGroupLayouts = MemoryUtil.memAllocLong(SET_PREALLOCATE_COUNT);
29+
for(int i = 0; i < SET_PREALLOCATE_COUNT; i++) bindGroupLayouts.put(i, bindGroupLayout);
2530

2631
int uniformBufferCount = 0;
2732
int sampledImageCount = 0;
@@ -44,62 +49,36 @@ public Vk11DescriptorPool(final Vk11Device device, final Vk11CommandEncoder enco
4449
Buffer poolSizes = VkDescriptorPoolSize.calloc(poolSizeCount, stack);
4550
int idx = 0;
4651
if (uniformBufferCount > 0) {
47-
poolSizes.get(idx).type(VK10.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER).descriptorCount(uniformBufferCount * TOTAL_SETS);
48-
idx++;
52+
poolSizes.get(idx++).type(VK10.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER).descriptorCount(uniformBufferCount * SETS_PER_FRAME);
4953
}
5054
if (sampledImageCount > 0) {
51-
poolSizes.get(idx).type(VK10.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER).descriptorCount(sampledImageCount * TOTAL_SETS);
52-
idx++;
55+
poolSizes.get(idx++).type(VK10.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER).descriptorCount(sampledImageCount * SETS_PER_FRAME);
5356
}
5457
if (texelBufferCount > 0) {
55-
poolSizes.get(idx).type(VK10.VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER).descriptorCount(texelBufferCount * TOTAL_SETS);
58+
poolSizes.get(idx++).type(VK10.VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER).descriptorCount(texelBufferCount * SETS_PER_FRAME);
5659
}
5760

58-
VkDescriptorPoolCreateInfo poolInfo = VkDescriptorPoolCreateInfo.calloc(stack)
59-
.sType$Default()
60-
.maxSets(TOTAL_SETS)
61-
.pPoolSizes(poolSizes);
62-
LongBuffer poolPtr = stack.callocLong(1);
63-
Vk11Utils.crashIfFailure(VK10.vkCreateDescriptorPool(device.vkDevice(), poolInfo, null, poolPtr), "Failed to create descriptor pool");
64-
this.pool = poolPtr.get(0);
65-
66-
LongBuffer setLayouts = stack.longs(layout.handle());
67-
LongBuffer setPtr = stack.callocLong(1);
68-
VkDescriptorSetAllocateInfo allocInfo = VkDescriptorSetAllocateInfo.calloc(stack)
69-
.sType$Default()
70-
.descriptorPool(this.pool)
71-
.pSetLayouts(setLayouts);
72-
for (int i = 0; i < TOTAL_SETS; i++) {
73-
Vk11Utils.crashIfFailure(VK10.vkAllocateDescriptorSets(device.vkDevice(), allocInfo, setPtr), "Failed to allocate descriptor set");
74-
this.sets[i] = setPtr.get(0);
75-
}
61+
for(int i = 0; i < pools.length; i++) {
62+
pools[i] = new PoolObject(stack, poolSizes);
63+
}
64+
7665
}
7766
encoder.registerDescriptorPool(this);
7867
}
7968

8069
public boolean isCapacityLow(int frameIndex) {
81-
int offset = this.frameSetIndex[frameIndex];
82-
if(offset >= SETS_PER_FRAME / 2) {
83-
System.out.println(toString()+" over capacity threshold: "+SETS_PER_FRAME +" used: "+offset);
84-
return true;
85-
}
86-
return false;
70+
return pools[frameIndex].isOverCapacityThreshold();
8771
}
8872

89-
public int allocateSet(final int frameIndex) {
90-
int base = frameIndex * SETS_PER_FRAME;
91-
int offset = this.frameSetIndex[frameIndex]++;
92-
if (offset >= SETS_PER_FRAME) {
93-
throw new IllegalStateException("Descriptor set limit exceeded for frame " + frameIndex + " (max " + SETS_PER_FRAME + " per frame)");
94-
}
95-
return base + offset;
73+
public void allocateSet(final int frameIndex) {
74+
currentSet = pools[frameIndex].takeSet();
9675
}
9776

9877
public void resetFrame(final int frameIndex) {
99-
this.frameSetIndex[frameIndex] = 0;
78+
pools[frameIndex].reset();
10079
}
10180

102-
public void updateUniformBuffer(final Vk11Device device, final int setIndex, final int binding, final long buffer, final long offset, final long range) {
81+
public void updateUniformBuffer(final Vk11Device device, final int binding, final long buffer, final long offset, final long range) {
10382
try (MemoryStack stack = MemoryStack.stackPush()) {
10483
org.lwjgl.vulkan.VkDescriptorBufferInfo.Buffer bufferInfo = org.lwjgl.vulkan.VkDescriptorBufferInfo.calloc(1, stack);
10584
bufferInfo.buffer(buffer);
@@ -109,7 +88,7 @@ public void updateUniformBuffer(final Vk11Device device, final int setIndex, fin
10988
org.lwjgl.vulkan.VkWriteDescriptorSet.Buffer write = org.lwjgl.vulkan.VkWriteDescriptorSet.calloc(1, stack);
11089
write.get(0)
11190
.sType$Default()
112-
.dstSet(this.sets[setIndex])
91+
.dstSet(currentSet)
11392
.dstBinding(binding)
11493
.dstArrayElement(0)
11594
.descriptorType(VK10.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
@@ -120,7 +99,7 @@ public void updateUniformBuffer(final Vk11Device device, final int setIndex, fin
12099
}
121100
}
122101

123-
public void updateSampledImage(final Vk11Device device, final int setIndex, final int binding, final long imageView, final long sampler) {
102+
public void updateSampledImage(final Vk11Device device, final int binding, final long imageView, final long sampler) {
124103
try (MemoryStack stack = MemoryStack.stackPush()) {
125104
org.lwjgl.vulkan.VkDescriptorImageInfo.Buffer imageInfo = org.lwjgl.vulkan.VkDescriptorImageInfo.calloc(1, stack);
126105
imageInfo.sampler(sampler);
@@ -130,7 +109,7 @@ public void updateSampledImage(final Vk11Device device, final int setIndex, fina
130109
org.lwjgl.vulkan.VkWriteDescriptorSet.Buffer write = org.lwjgl.vulkan.VkWriteDescriptorSet.calloc(1, stack);
131110
write.get(0)
132111
.sType$Default()
133-
.dstSet(this.sets[setIndex])
112+
.dstSet(currentSet)
134113
.dstBinding(binding)
135114
.dstArrayElement(0)
136115
.descriptorType(VK10.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
@@ -141,14 +120,14 @@ public void updateSampledImage(final Vk11Device device, final int setIndex, fina
141120
}
142121
}
143122

144-
public void updateTexelBuffer(final Vk11Device device, final int setIndex, final int binding, final long bufferView) {
123+
public void updateTexelBuffer(final Vk11Device device, final int binding, final long bufferView) {
145124
try (MemoryStack stack = MemoryStack.stackPush()) {
146125
LongBuffer bvPtr = stack.longs(bufferView);
147126

148127
org.lwjgl.vulkan.VkWriteDescriptorSet.Buffer write = org.lwjgl.vulkan.VkWriteDescriptorSet.calloc(1, stack);
149128
write.get(0)
150129
.sType$Default()
151-
.dstSet(this.sets[setIndex])
130+
.dstSet(currentSet)
152131
.dstBinding(binding)
153132
.dstArrayElement(0)
154133
.descriptorType(VK10.VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER)
@@ -159,18 +138,75 @@ public void updateTexelBuffer(final Vk11Device device, final int setIndex, final
159138
}
160139
}
161140

162-
public void bind(final org.lwjgl.vulkan.VkCommandBuffer commandBuffer, final long pipelineLayout, final int setIndex) {
141+
public void bind(final org.lwjgl.vulkan.VkCommandBuffer commandBuffer, final long pipelineLayout) {
163142
try (MemoryStack stack = MemoryStack.stackPush()) {
164-
VK10.vkCmdBindDescriptorSets(commandBuffer, VK10.VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, stack.longs(this.sets[setIndex]), null);
143+
VK10.vkCmdBindDescriptorSets(commandBuffer, VK10.VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, stack.longs(currentSet), null);
165144
}
166145
}
167-
168-
public long descriptorSet(final int setIndex) {
169-
return this.sets[setIndex];
170-
}
171-
172146
@Override
173147
public void destroy() {
174-
VK10.vkDestroyDescriptorPool(device.vkDevice(), pool, null);
148+
for(PoolObject pool : pools) pool.destroy();
175149
}
150+
151+
private class PoolObject {
152+
protected final long pool;
153+
protected final LongBuffer sets;
154+
private int numAllocated;
155+
private int numUsed;
156+
157+
public PoolObject(MemoryStack stack, Buffer poolSizes) {
158+
VkDescriptorPoolCreateInfo poolInfo = VkDescriptorPoolCreateInfo.calloc(stack)
159+
.sType$Default()
160+
.maxSets(SETS_PER_FRAME)
161+
.pPoolSizes(poolSizes);
162+
LongBuffer poolPtr = stack.callocLong(1);
163+
Vk11Utils.crashIfFailure(VK10.vkCreateDescriptorPool(device.vkDevice(), poolInfo, null, poolPtr), "Failed to create descriptor pool");
164+
pool = poolPtr.get(0);
165+
sets = MemoryUtil.memCallocLong(SETS_PER_FRAME);
166+
numAllocated = 0;
167+
numUsed = 0;
168+
preallocateMore(SET_PREALLOCATE_COUNT);
169+
}
170+
171+
public void preallocateMore(int count) {
172+
assert count <= SET_PREALLOCATE_COUNT;
173+
LongBuffer layoutsSlice = MemoryUtil.memSlice(bindGroupLayouts, 0, count);
174+
LongBuffer outSetsSlice = MemoryUtil.memSlice(sets, numAllocated, count);
175+
try(MemoryStack stack = MemoryStack.stackPush()) {
176+
VkDescriptorSetAllocateInfo allocInfo = VkDescriptorSetAllocateInfo.calloc(stack)
177+
.sType$Default()
178+
.descriptorPool(pool)
179+
.pSetLayouts(layoutsSlice);
180+
assert allocInfo.descriptorSetCount() == count;
181+
Vk11Utils.crashIfFailure(VK10.vkAllocateDescriptorSets(device.vkDevice(), allocInfo, outSetsSlice), "Failed to allocate descriptor set");
182+
}
183+
numAllocated += count;
184+
}
185+
186+
public boolean isOverCapacityThreshold() {
187+
return numUsed >= RECLAIM_THRESHOLD;
188+
}
189+
190+
public void reset() {
191+
if(numUsed > RECLAIM_THRESHOLD) {
192+
193+
Vk11Utils.crashIfFailure(VK10.vkResetDescriptorPool(device.vkDevice(), pool, 0), "Failed to reclaim descriptor pool");
194+
numAllocated = 0;
195+
preallocateMore(SET_PREALLOCATE_COUNT);
196+
}
197+
numUsed = 0;
198+
}
199+
200+
public long takeSet() {
201+
int nextIdx = numUsed++;
202+
if(nextIdx >= numAllocated) {
203+
preallocateMore(SET_PREALLOCATE_COUNT);
204+
}
205+
return sets.get(nextIdx);
206+
}
207+
208+
public void destroy() {
209+
VK10.vkDestroyDescriptorPool(device.vkDevice(), pool, null);
210+
}
211+
}
176212
}

src/main/java/git/artdeell/artvk/Vk11RenderPass.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ private void pushDescriptors() {
334334
assert pipeline != null;
335335
Vk11BindGroupLayout layout = pipeline.layout();
336336
Vk11DescriptorPool pool = pipeline.descriptorPool();
337-
int setIndex = pool.allocateSet(frameIndex);
338337

338+
pool.allocateSet(frameIndex);
339339
try (MemoryStack stack = MemoryStack.stackPush()) {
340340
for (int i = 0; i < layout.entries().size(); i++) {
341341
Vk11BindGroupLayout.Entry entry = layout.entries().get(i);
@@ -345,14 +345,14 @@ private void pushDescriptors() {
345345
if (buffer == null) {
346346
throw new IllegalStateException("Missing uniform " + entry.name() + " (should be " + entry.type() + ")");
347347
}
348-
pool.updateUniformBuffer(device, setIndex, i, ((Vk11GpuBuffer)buffer.buffer()).vkBuffer(), buffer.offset(), buffer.length());
348+
pool.updateUniformBuffer(device, i, ((Vk11GpuBuffer)buffer.buffer()).vkBuffer(), buffer.offset(), buffer.length());
349349
}
350350
case SAMPLED_IMAGE -> {
351351
Vk11RenderPass.TextureViewAndSampler value = textures.get(entry.name());
352352
if (value == null) {
353353
throw new IllegalStateException("Missing sampler " + entry.name());
354354
}
355-
pool.updateSampledImage(device, setIndex, i, value.view.vkImageView(), value.sampler.vkSampler());
355+
pool.updateSampledImage(device, i, value.view.vkImageView(), value.sampler.vkSampler());
356356
}
357357
case TEXEL_BUFFER -> {
358358
GpuBufferSlice value = uniforms.get(entry.name());
@@ -374,12 +374,12 @@ private void pushDescriptors() {
374374
long bufferViewHandle = bufferViewPtr.get(0);
375375
encoder.queueForDestroy(() -> VK10.vkDestroyBufferView(device.vkDevice(), bufferViewHandle, null));
376376
}
377-
pool.updateTexelBuffer(device, setIndex, i, bufferViewPtr.get(0));
377+
pool.updateTexelBuffer(device, i, bufferViewPtr.get(0));
378378
}
379379
}
380380
}
381381

382-
pool.bind(commandBuffer(), pipeline.pipelineLayout(), setIndex);
382+
pool.bind(commandBuffer(), pipeline.pipelineLayout());
383383
}
384384

385385
anyDescriptorDirty = false;

0 commit comments

Comments
 (0)