Skip to content

Commit

Permalink
Add FenceBank
Browse files Browse the repository at this point in the history
  • Loading branch information
knokko committed Nov 14, 2023
1 parent ae6d05c commit f3ef1fb
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public void destroyInitialObjects() {
checkDestroyed();

if (swapchains != null) swapchains.destroy();
sync.fenceBank.destroy();
vmaDestroyAllocator(vmaAllocator);
vkDestroyDevice(vkDevice, null);
if (windowSurface != null) windowSurface.destroy(vkInstance);
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/github/knokko/boiler/sync/BoilerSync.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
public class BoilerSync {

private final BoilerInstance instance;
public final FenceBank fenceBank;

public BoilerSync(BoilerInstance instance) {
this.instance = instance;
this.fenceBank = new FenceBank(instance);
}

public long[] createFences(boolean startSignaled, int amount, String name) {
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/com/github/knokko/boiler/sync/FenceBank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.github.knokko.boiler.sync;

import com.github.knokko.boiler.instance.BoilerInstance;

import java.util.concurrent.ConcurrentSkipListSet;

import static com.github.knokko.boiler.exceptions.VulkanFailureException.assertVkSuccess;
import static org.lwjgl.vulkan.VK10.vkDestroyFence;
import static org.lwjgl.vulkan.VK10.vkResetFences;

public class FenceBank {

private final BoilerInstance instance;
private final ConcurrentSkipListSet<Long> unusedFences = new ConcurrentSkipListSet<>();
private final ConcurrentSkipListSet<Long> borrowedFences = new ConcurrentSkipListSet<>();

FenceBank(BoilerInstance instance) {
this.instance = instance;
}

public long borrowFence() {
Long fence = unusedFences.pollFirst();
if (fence == null) {
fence = instance.sync.createFences(false, 1, "Borrowed")[0];
}
borrowedFences.add(fence);
return fence;
}

public void returnFence(long fence, boolean mightNeedReset) {
if (!borrowedFences.remove(fence)) {
throw new IllegalArgumentException("This fence wasn't borrowed");
}
if (mightNeedReset) {
assertVkSuccess(vkResetFences(instance.vkDevice(), fence), "ResetFences", "Bank return");
}
unusedFences.add(fence);
}

public void destroy() {
if (!borrowedFences.isEmpty()) {
throw new IllegalStateException("Not all borrowed fences have been returned");
}
for (long fence : unusedFences) {
vkDestroyFence(instance.vkDevice(), fence, null);
}
unusedFences.clear();
}
}
62 changes: 62 additions & 0 deletions src/test/java/com/github/knokko/boiler/sync/TestFenceBank.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.github.knokko.boiler.sync;

import com.github.knokko.boiler.builder.BoilerBuilder;
import com.github.knokko.boiler.builder.instance.ValidationFeatures;
import com.github.knokko.boiler.commands.CommandRecorder;
import com.github.knokko.boiler.instance.BoilerInstance;
import org.junit.jupiter.api.Test;

import static com.github.knokko.boiler.exceptions.VulkanFailureException.assertVkSuccess;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.vulkan.VK10.*;

public class TestFenceBank {

private void signalFence(BoilerInstance instance, long fence) {
var commandPool = instance.commands.createPool(
0, instance.queueFamilies().graphics().index(), "SignalFence"
);
var commandBuffer = instance.commands.createPrimaryBuffers(commandPool, 1, "Signal")[0];
try (var stack = stackPush()) {
var commands = CommandRecorder.begin(commandBuffer, instance, stack, "Signal");
commands.end();

instance.queueFamilies().graphics().queues().get(0).submit(
commandBuffer, "Signal", new WaitSemaphore[0], fence
);
assertVkSuccess(vkWaitForFences(
instance.vkDevice(), stack.longs(fence), true, 100_000_000L
), "WaitForFences", "Signal");
}

vkDestroyCommandPool(instance.vkDevice(), commandPool, null);
}

@Test
public void complexFenceBankTest() {
var instance = new BoilerBuilder(VK_API_VERSION_1_0, "TestFenceBank", 1)
.validation(new ValidationFeatures(false, false, false, true, true))
.build();

var fence1 = instance.sync.fenceBank.borrowFence();
assertEquals(VK_NOT_READY, vkGetFenceStatus(instance.vkDevice(), fence1));
signalFence(instance, fence1);
assertEquals(VK_SUCCESS, vkGetFenceStatus(instance.vkDevice(), fence1));

var fence2 = instance.sync.fenceBank.borrowFence();
assertEquals(VK_NOT_READY, vkGetFenceStatus(instance.vkDevice(), fence2));

instance.sync.fenceBank.returnFence(fence1, true);
assertEquals(fence1, instance.sync.fenceBank.borrowFence());
assertEquals(VK_NOT_READY, vkGetFenceStatus(instance.vkDevice(), fence1));

instance.sync.fenceBank.returnFence(fence2, false);
assertEquals(fence2, instance.sync.fenceBank.borrowFence());
assertEquals(VK_NOT_READY, vkGetFenceStatus(instance.vkDevice(), fence2));

instance.sync.fenceBank.returnFence(fence1, true);
instance.sync.fenceBank.returnFence(fence2, false);
instance.destroyInitialObjects();
}
}

0 comments on commit f3ef1fb

Please sign in to comment.