Skip to content

Commit

Permalink
wip: shared buffer builder
Browse files Browse the repository at this point in the history
  • Loading branch information
knokko committed Oct 22, 2024
1 parent 5428ee5 commit 3b91137
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@
* host-visible memory, and must be mapped at <i>hostAddress</i> during its lifetime.
*/
public record MappedVkbBuffer(long vkBuffer, long vmaAllocation, long size, long hostAddress) implements VkbBuffer {

// TODO Document and test
MappedVkbBufferRange fullMappedRange() {
return new MappedVkbBufferRange(this, 0L, size);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.github.knokko.boiler.buffers;

import java.nio.*;

import static org.lwjgl.system.MemoryUtil.*;

public record MappedVkbBufferRange(MappedVkbBuffer buffer, long offset, long size) {

long hostAddress() {
return buffer.hostAddress() + offset;
}

int intSize() {
if (size > Integer.MAX_VALUE) throw new UnsupportedOperationException("Size (" + size + ") is too large");
return (int) size;
}

VkbBufferRange range() {
return new VkbBufferRange(buffer, offset, size);
}

ByteBuffer byteBuffer() {
return memByteBuffer(hostAddress(), intSize());
}

ShortBuffer shortBuffer() {
return memShortBuffer(hostAddress(), intSize() / Short.BYTES);
}

IntBuffer intBuffer() {
return memIntBuffer(hostAddress(), intSize() / Integer.BYTES);
}

FloatBuffer floatBuffer() {
return memFloatBuffer(hostAddress(), intSize() / Float.BYTES);
}

LongBuffer longBuffer() {
return memLongBuffer(hostAddress(), intSize() / Long.BYTES);
}

DoubleBuffer doubleBuffer() {
return memDoubleBuffer(hostAddress(), intSize() / Double.BYTES);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.github.knokko.boiler.buffers;

import com.github.knokko.boiler.BoilerInstance;

import java.util.function.Supplier;

import static com.github.knokko.boiler.utilities.BoilerMath.nextMultipleOf;

public abstract class SharedBufferBuilder<B extends VkbBuffer, R> {

protected final BoilerInstance instance;
private long totalSize = 0L;
private B buffer;

public SharedBufferBuilder(BoilerInstance instance) {
this.instance = instance;
}

public Supplier<R> add(long size, long alignment) {
if (alignment > 0L) totalSize = nextMultipleOf(totalSize, alignment);
long offset = totalSize;
totalSize += size;

return () -> {
if (buffer == null) throw new IllegalStateException("Buffer hasn't been built yet");
return createRange(buffer, offset, size);
};
}

public B build(int usage, String name) {
this.buffer = buildBuffer(totalSize, usage, name);
return this.buffer;
}

protected abstract B buildBuffer(long size, int usage, String name);

protected abstract R createRange(B buffer, long offset, long size);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.github.knokko.boiler.buffers;

import com.github.knokko.boiler.BoilerInstance;

public class SharedDeviceBufferBuilder extends SharedBufferBuilder<DeviceVkbBuffer, VkbBufferRange> {

public SharedDeviceBufferBuilder(BoilerInstance instance) {
super(instance);
}

@Override
protected DeviceVkbBuffer buildBuffer(long size, int usage, String name) {
return instance.buffers.create(size, usage, name);
}

@Override
protected VkbBufferRange createRange(DeviceVkbBuffer buffer, long offset, long size) {
return new VkbBufferRange(buffer, offset, size);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.github.knokko.boiler.buffers;

import com.github.knokko.boiler.BoilerInstance;

public class SharedMappedBufferBuilder extends SharedBufferBuilder<MappedVkbBuffer, MappedVkbBufferRange> {
public SharedMappedBufferBuilder(BoilerInstance instance) {
super(instance);
}

@Override
protected MappedVkbBuffer buildBuffer(long size, int usage, String name) {
return instance.buffers.createMapped(size, usage, name);
}

@Override
protected MappedVkbBufferRange createRange(MappedVkbBuffer buffer, long offset, long size) {
return new MappedVkbBufferRange(buffer, offset, size);
}
}
11 changes: 11 additions & 0 deletions src/main/java/com/github/knokko/boiler/utilities/BoilerMath.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.github.knokko.boiler.utilities;

public class BoilerMath {

public static long nextMultipleOf(long value, long alignment) { // TODO Document this
long quotient = value / alignment;
long reverted = quotient * alignment;
if (reverted < value) reverted += alignment;
return reverted;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package com.github.knokko.boiler.buffers;

import com.github.knokko.boiler.BoilerInstance;
import com.github.knokko.boiler.builders.BoilerBuilder;
import com.github.knokko.boiler.commands.CommandRecorder;
import com.github.knokko.boiler.synchronization.ResourceUsage;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.lwjgl.system.MemoryStack.stackPush;
import static org.lwjgl.vulkan.VK10.*;

public class TestSharedBufferBuilder {

private static BoilerInstance instance;

@BeforeAll
public static void setUp() {
instance = new BoilerBuilder(
VK_API_VERSION_1_0, "TestSharedBufferBuilder", 1
).validation().forbidValidationErrors().build();
}

@Test
public void testAlignment() {
var builder = new SharedDeviceBufferBuilder(instance);
var getRange0 = builder.add(1, 1234);
var getRange1 = builder.add(100, 13);
var getRange2 = builder.add(50, 57);
var buffer = builder.build(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, "AlignmentBuffer");

var range0 = getRange0.get();
var range1 = getRange1.get();
var range2 = getRange2.get();

assertEquals(1, range0.size());
assertEquals(0, range0.offset());
assertEquals(100, range1.size());
assertEquals(13, range1.offset());
assertEquals(50, range2.size());
assertEquals(114, range2.offset());
assertEquals(164, buffer.size());

buffer.destroy(instance);
}
// TODO Docs
@Test
public void testBufferCopyShuffle() {
var sourceBuilder = new SharedMappedBufferBuilder(instance);
var getSource0 = sourceBuilder.add(7, 4);
var getSource1 = sourceBuilder.add(8, 8);
var getSource2 = sourceBuilder.add(1, 1);
var sourceBuffer = sourceBuilder.build(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, "SharedSource");
getSource0.get().intBuffer().put(1234);
getSource1.get().doubleBuffer().put(1.25);
getSource2.get().byteBuffer().put((byte) 123);

var middleBuilder = new SharedDeviceBufferBuilder(instance);
var getMiddle2 = middleBuilder.add(1, 1);
var getMiddle0 = middleBuilder.add(7, 4);
var getMiddle1 = middleBuilder.add(8, 8);
var middleBuffer = middleBuilder.build(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, "SharedMiddle"
);

var destBuilder = new SharedMappedBufferBuilder(instance);
var getDest1 = destBuilder.add(8, 8);
var getDest2 = destBuilder.add(1, 1);
var getDest0 = destBuilder.add(7, 4);
var destBuffer = destBuilder.build(VK_BUFFER_USAGE_TRANSFER_DST_BIT, "SharedDestination");

var commandPool = instance.commands.createPool(
0, instance.queueFamilies().transfer().index(), "SharedCommandPool"
);
var commandBuffer = instance.commands.createPrimaryBuffers(commandPool, 1, "SharedCommandBuffer")[0];
try (var stack = stackPush()) {
var recorder = CommandRecorder.begin(commandBuffer, instance, stack, "SharedShuffle");
recorder.copyBuffer(getSource0.get().range(), middleBuffer.vkBuffer(), getMiddle0.get().offset());
recorder.copyBuffer(getSource1.get().range(), middleBuffer.vkBuffer(), getMiddle1.get().offset());
recorder.copyBuffer(getSource2.get().range(), middleBuffer.vkBuffer(), getMiddle2.get().offset());

recorder.bufferBarrier(getMiddle0.get(), ResourceUsage.TRANSFER_DEST, ResourceUsage.TRANSFER_SOURCE);
recorder.bufferBarrier(getMiddle1.get(), ResourceUsage.TRANSFER_DEST, ResourceUsage.TRANSFER_SOURCE);
recorder.bufferBarrier(getMiddle2.get(), ResourceUsage.TRANSFER_DEST, ResourceUsage.TRANSFER_SOURCE);

recorder.copyBuffer(getMiddle0.get(), destBuffer.vkBuffer(), getDest0.get().offset());
recorder.copyBuffer(getMiddle1.get(), destBuffer.vkBuffer(), getDest1.get().offset());
recorder.copyBuffer(getMiddle2.get(), destBuffer.vkBuffer(), getDest2.get().offset());

recorder.end();

var fence = instance.sync.fenceBank.borrowFence(false, "ShuffleFence");
instance.queueFamilies().transfer().first().submit(commandBuffer, "Shuffle", null, fence);
fence.awaitSignal();
instance.sync.fenceBank.returnFence(fence);
}

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

assertEquals(1234, getDest0.get().intBuffer().get());
assertEquals(1.25, getDest1.get().doubleBuffer().get());
assertEquals(123, getDest2.get().byteBuffer().get());

sourceBuffer.destroy(instance);
middleBuffer.destroy(instance);
destBuffer.destroy(instance);
}

@Test
public void testMappedBufferBuilder() {
var builder = new SharedMappedBufferBuilder(instance);
var getRange0 = builder.add(3, 0);
var getRange1 = builder.add(8, 4);

var buffer = builder.build(VK_BUFFER_USAGE_TRANSFER_DST_BIT, "TestMappedBuffer");
var range0 = getRange0.get();
var range1 = getRange1.get();

assertEquals(0, range0.offset());
assertEquals(3, range0.size());
assertEquals(4, range1.offset());
assertEquals(8, range1.size());
assertEquals(12, buffer.size());

range0.byteBuffer().put(2, (byte) 3);
range1.intBuffer().put(12345);

assertEquals(3, buffer.fullMappedRange().byteBuffer().get(2));
assertEquals(12345, buffer.fullMappedRange().intBuffer().get(1));

buffer.destroy(instance);
}

@AfterAll
public static void cleanUp() {
instance.destroyInitialObjects();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.github.knokko.boiler.utilities;

import org.junit.jupiter.api.Test;

import static com.github.knokko.boiler.utilities.BoilerMath.nextMultipleOf;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class TestBoilerMath {

@Test
public void testNextMultipleOf() {
assertEquals(10, nextMultipleOf(10, 1));
assertEquals(10, nextMultipleOf(10, 2));
assertEquals(10, nextMultipleOf(10, 5));
assertEquals(10, nextMultipleOf(10, 10));
assertEquals(12, nextMultipleOf(10, 3));
assertEquals(12, nextMultipleOf(10, 4));
}
}

0 comments on commit 3b91137

Please sign in to comment.