44import net .fabricmc .api .EnvType ;
55import net .fabricmc .api .Environment ;
66import org .lwjgl .system .MemoryStack ;
7+ import org .lwjgl .system .MemoryUtil ;
78import org .lwjgl .vulkan .VK10 ;
89import org .lwjgl .vulkan .VkDescriptorPoolCreateInfo ;
910import org .lwjgl .vulkan .VkDescriptorPoolSize ;
1314@ Environment (EnvType .CLIENT )
1415public 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}
0 commit comments