Skip to content

Commit

Permalink
actually do feedback readback
Browse files Browse the repository at this point in the history
  • Loading branch information
RogueLogix committed Mar 13, 2024
1 parent 50921d6 commit 6972e38
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import net.roguelogix.quartz.internal.QuartzInternalEvent;
import net.roguelogix.quartz.internal.common.B3DStateHelper;
import net.roguelogix.quartz.internal.gl33.batching.GL33DrawBatch;
import net.roguelogix.quartz.internal.gl46.GL46FeedbackDrawing;
import net.roguelogix.quartz.internal.util.PointerWrapper;
import net.roguelogix.quartz.internal.util.VertexFormatOutput;
import org.joml.Matrix4f;
Expand Down Expand Up @@ -263,12 +262,29 @@ public static void collectAllFeedback(boolean shadowsEnabled) {
}
B3DStateHelper.bindVertexArray(0);

if(QuartzCore.TESTING_ALLOWED && QuartzCore.isTestingRunning()){
if (QuartzCore.TESTING_ALLOWED && QuartzCore.isTestingRunning()) {
long totalSize = 0;
for (FeedbackBuffer value : renderTypeFeedbackBuffers.values()) {
totalSize += value.size;
}
var ptr = PointerWrapper.alloc(totalSize);
long currentOffset = 0;
var buffers = new Object2ObjectOpenHashMap<RenderType, Pair<PointerWrapper, Integer>>();
for (RenderType renderType : inUseRenderTypes) {
buffers.put(renderType, new Pair<>(null, 0));
final var feedbackBuffer = renderTypeFeedbackBuffers.get(renderType);
final var drawBuffer = renderTypeDrawBuffer.getInt(renderType);
final var drawnVertices = renderTypeDrawnVertices.getInt(renderType);

final var bufferPtr = ptr.slice(currentOffset, feedbackBuffer.size);
currentOffset += bufferPtr.size();
B3DStateHelper.bindArrayBuffer(drawBuffer);
nglGetBufferSubData(GL_ARRAY_BUFFER, 0, feedbackBuffer.size, bufferPtr.pointer());

buffers.put(renderType, new Pair<>(bufferPtr, drawnVertices));
}
B3DStateHelper.bindArrayBuffer(0);
Quartz.EVENT_BUS.post(new QuartzInternalEvent.FeedbackCollected(inUseRenderTypes, buffers));
ptr.free();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private record FeedbackBuffer(int buffer, int size) {
private FeedbackBuffer(int size) {
this(glCreateBuffers(), roundUpPo2(size));
// no flags, only used on the server side, unless testing
glNamedBufferStorage(buffer, this.size, QuartzCore.TESTING_ALLOWED ? GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT : 0);
glNamedBufferStorage(buffer, this.size, QuartzCore.TESTING_ALLOWED ? GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT: 0);
}

void delete() {
Expand Down Expand Up @@ -137,7 +137,14 @@ public static void startup() {

public static void shutdown() {
glDeleteVertexArrays(feedbackVAO);
renderTypeFeedbackBuffers.values().forEach(FeedbackBuffer::delete);
renderTypeFeedbackBuffers.forEach((renderType, feedbackBuffer) -> {
if (QuartzCore.TESTING_ALLOWED) {
PointerWrapper.removeReadableLocation(new PointerWrapper(renderTypeFeedbackBufferMappings.getLong(renderType), feedbackBuffer.size));
glUnmapNamedBuffer(feedbackBuffer.buffer);
}
feedbackBuffer.delete();
});
renderTypeFeedbackBufferMappings.clear();
rebuildCallbackHandle.delete();
rebuildCallbackHandle = null;
}
Expand Down Expand Up @@ -241,10 +248,27 @@ public static void collectAllFeedback(boolean shadowsEnabled) {

requiredVertices *= outputFormat.vertexSize();

var buffer = renderTypeFeedbackBuffers.computeIfAbsent(renderType, e -> new FeedbackBuffer(requiredVertices));
var buffer = renderTypeFeedbackBuffers.computeIfAbsent(renderType, e -> {
var feedbackBuffer = new FeedbackBuffer(requiredVertices);
if (QuartzCore.TESTING_ALLOWED) {
final long mappedPtr = nglMapNamedBufferRange(feedbackBuffer.buffer, 0, feedbackBuffer.size, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
PointerWrapper.addReadableLocation(new PointerWrapper(mappedPtr, feedbackBuffer.size));
renderTypeFeedbackBufferMappings.put(renderType, mappedPtr);
}
return feedbackBuffer;
});
if (buffer.size < requiredVertices) {
buffer.delete();
if (QuartzCore.TESTING_ALLOWED) {
PointerWrapper.removeReadableLocation(new PointerWrapper(renderTypeFeedbackBufferMappings.getLong(renderType), buffer.size));
glUnmapBuffer(buffer.buffer);
}
buffer = new FeedbackBuffer(requiredVertices);
if (QuartzCore.TESTING_ALLOWED) {
final long mappedPtr = nglMapNamedBufferRange(buffer.buffer, 0, buffer.size, GL_MAP_READ_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
PointerWrapper.addReadableLocation(new PointerWrapper(mappedPtr, buffer.size));
renderTypeFeedbackBufferMappings.put(renderType, mappedPtr);
}
renderTypeFeedbackBuffers.put(renderType, buffer);
}

Expand Down Expand Up @@ -279,11 +303,17 @@ public static void collectAllFeedback(boolean shadowsEnabled) {
}
prevousFrameSyncs[frameInFlight] = frameSync;

if(QuartzCore.TESTING_ALLOWED && QuartzCore.isTestingRunning()){
if (QuartzCore.TESTING_ALLOWED && QuartzCore.isTestingRunning()) {
var buffers = new Object2ObjectOpenHashMap<RenderType, Pair<PointerWrapper, Integer>>();
for (RenderType renderType : inUseRenderTypes) {
buffers.put(renderType, new Pair<>(null, 0));
final var feedbackBuffer = renderTypeFeedbackBuffers.get(renderType);
final var feedbackBufferMapping = renderTypeFeedbackBufferMappings.getLong(renderType);
final var drawnVertices = renderTypeDrawnVertices.getInt(renderType);
final var ptr = new PointerWrapper(feedbackBufferMapping, feedbackBuffer.size);

buffers.put(renderType, new Pair<>(ptr, drawnVertices));
}
glFinish();
Quartz.EVENT_BUS.post(new QuartzInternalEvent.FeedbackCollected(inUseRenderTypes, buffers));
}
}
Expand Down
102 changes: 71 additions & 31 deletions src/main/java/net/roguelogix/quartz/internal/util/PointerWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,57 @@ public static void logLeakedMemory() {
}
}

private static final ObjectArraySet<PointerWrapper> validReadLocations = new ObjectArraySet<>();
private static final ObjectArraySet<PointerWrapper> validWriteLocations = new ObjectArraySet<>();

public static void addAccessibleLocation(PointerWrapper wrapper) {
if (!DEBUG) {
return;
}

addReadableLocation(wrapper);
addWritableLocation(wrapper);
}

public static void removeAccessibleLocation(PointerWrapper wrapper) {
if (!DEBUG) {
return;
}
removeReadableLocation(wrapper);
removeWritableLocation(wrapper);
}

public static void addReadableLocation(PointerWrapper wrapper) {
if (!DEBUG) {
return;
}

synchronized (validReadLocations) {
validReadLocations.add(wrapper);
}
}

public static void removeReadableLocation(PointerWrapper wrapper) {
if (!DEBUG) {
return;
}
synchronized (validReadLocations) {
validReadLocations.remove(wrapper);
}
}


public static void addWritableLocation(PointerWrapper wrapper) {
if (!DEBUG) {
return;
}

synchronized (validWriteLocations) {
validWriteLocations.add(wrapper);
}
}

public static void removeAccessibleLocation(PointerWrapper wrapper) {
public static void removeWritableLocation(PointerWrapper wrapper) {
if (!DEBUG) {
return;
}
Expand All @@ -132,11 +171,12 @@ public static void removeAccessibleLocation(PointerWrapper wrapper) {
}
}

public static void verifyCanAccessLocation(long ptr, long size) {
public static void verifyCanAccessLocation(long ptr, long size, boolean read) {
if (!DEBUG) {
return;
}
for (final var value : validWriteLocations) {
final var validLocations = read ? validReadLocations : validWriteLocations;
for (final var value : validLocations) {
// doesnt start in this range
if (value.pointer > ptr || value.pointer + value.size <= ptr) {
continue;
Expand All @@ -147,7 +187,7 @@ public static void verifyCanAccessLocation(long ptr, long size) {
// starts in a known range, and doesnt attempt to access past the end, its valid
return;
}
throw new NullPointerException("Unable to find a valid write location for attempted write");
throw new NullPointerException("Unable to find a valid location for attempted access " + (read ? "(reading)" : "(writing)"));
}

public void set(byte data) {
Expand Down Expand Up @@ -182,8 +222,8 @@ public static void copy(PointerWrapper src, long srcOffset, PointerWrapper dst,
if (dstEndIndex > dst.size) {
throw new IllegalArgumentException("Attempt to copy pointer would read past end of destination. dest size: " + dst.size + ", dest offset: " + dstOffset + ", copy size: " + size);
}
verifyCanAccessLocation(srcPtr, size);
verifyCanAccessLocation(dstPtr, size);
verifyCanAccessLocation(srcPtr, size, true);
verifyCanAccessLocation(dstPtr, size, false);
}
boolean overlaps = srcOffset == dstOffset;
overlaps |= srcPtr < dstPtr && dstPtr < srcPtr + size;
Expand Down Expand Up @@ -223,11 +263,11 @@ public void copyTo(PointerWrapper dst) {
copyTo(0, dst, 0, Math.min(size, dst.size));
}

private void checkRange(long offset, long writeSize) {
checkRange(offset, writeSize, writeSize);
private void checkRange(long offset, long writeSize, boolean read) {
checkRange(offset, writeSize, writeSize, read);
}

private void checkRange(long offset, long writeSize, long alignment) {
private void checkRange(long offset, long writeSize, long alignment, boolean read) {
if (this.pointer == 0) {
throw new IllegalStateException("Attempt to use NULLPTR");
}
Expand All @@ -242,42 +282,42 @@ private void checkRange(long offset, long writeSize, long alignment) {
if ((dstPtr % alignment) != 0) {
throw new IllegalArgumentException("Attempt to access unaligned address");
}
verifyCanAccessLocation(dstPtr, writeSize);
verifyCanAccessLocation(dstPtr, writeSize, read);
}
}

public void putByte(long offset, byte val) {
checkRange(offset, 1);
checkRange(offset, 1, false);
MemoryUtil.memPutByte(pointer + offset, val);
}

public void putShort(long offset, short val) {
checkRange(offset, 2);
checkRange(offset, 2, false);
MemoryUtil.memPutShort(pointer + offset, val);
}

public void putInt(long offset, int val) {
checkRange(offset, 4);
checkRange(offset, 4, false);
MemoryUtil.memPutInt(pointer + offset, val);
}

public void putLong(long offset, long val) {
checkRange(offset, 8);
checkRange(offset, 8, false);
MemoryUtil.memPutLong(pointer + offset, val);
}

public void putFloat(long offset, float val) {
checkRange(offset, 4);
checkRange(offset, 4, false);
MemoryUtil.memPutFloat(pointer + offset, val);
}

public void putDouble(long offset, double val) {
checkRange(offset, 8);
checkRange(offset, 8, false);
MemoryUtil.memPutDouble(pointer + offset, val);
}

public void putVector3i(long offset, Vector3ic vector) {
checkRange(offset, 12, 16);
checkRange(offset, 12, 16, false);
final var dstPtr = pointer + offset;
if (JOML_UNSAFE_AVAILABLE) {
vector.getToAddress(pointer + offset);
Expand All @@ -289,7 +329,7 @@ public void putVector3i(long offset, Vector3ic vector) {
}

public void putVector3f(long offset, Vector3fc vector) {
checkRange(offset, 12, 16);
checkRange(offset, 12, 16, false);
final var dstPtr = pointer + offset;
if(JOML_UNSAFE_AVAILABLE){
vector.getToAddress(pointer + offset);
Expand All @@ -301,7 +341,7 @@ public void putVector3f(long offset, Vector3fc vector) {
}

public void putVector4i(long offset, Vector4ic vector) {
checkRange(offset, 16);
checkRange(offset, 16, false);
final var dstPtr = pointer + offset;
if (JOML_UNSAFE_AVAILABLE) {
vector.getToAddress(pointer + offset);
Expand All @@ -314,7 +354,7 @@ public void putVector4i(long offset, Vector4ic vector) {
}

public void putVector4f(long offset, Vector4fc vector) {
checkRange(offset, 16);
checkRange(offset, 16, false);
final var dstPtr = pointer + offset;
if (JOML_UNSAFE_AVAILABLE) {
vector.getToAddress(pointer + offset);
Expand All @@ -327,7 +367,7 @@ public void putVector4f(long offset, Vector4fc vector) {
}

public void putMatrix4f(long offset, Matrix4fc matrix) {
checkRange(offset, 64, 16);
checkRange(offset, 64, 16, false);
final var dstPtr = pointer + offset;
if (JOML_UNSAFE_AVAILABLE) {
matrix.getToAddress(dstPtr);
Expand All @@ -352,7 +392,7 @@ public void putMatrix4f(long offset, Matrix4fc matrix) {
}

public void putMatrix3x4f(long offset, Matrix4fc matrix) {
checkRange(offset, 48, 16);
checkRange(offset, 48, 16, false);
// TODO: check new JOML for getToAddress3x4, or an open issue for it
final var dstPtr = pointer + offset;
MemoryUtil.memPutFloat(dstPtr, matrix.m00());
Expand Down Expand Up @@ -406,47 +446,47 @@ public void putMatrix4fIdx(long index, Matrix4fc matrix4f) {
}

public byte getByte(long offset) {
checkRange(offset, 1);
checkRange(offset, 1, true);
return MemoryUtil.memGetByte(pointer + offset);
}

public short getShort(long offset) {
checkRange(offset, 2);
checkRange(offset, 2, true);
return MemoryUtil.memGetShort(pointer + offset);
}

public int getInt(long offset) {
checkRange(offset, 4);
checkRange(offset, 4, true);
return MemoryUtil.memGetInt(pointer + offset);
}

public long getLong(long offset) {
checkRange(offset, 8);
checkRange(offset, 8, true);
return MemoryUtil.memGetLong(pointer + offset);
}

public float getFloat(long offset) {
checkRange(offset, 4);
checkRange(offset, 4, true);
return MemoryUtil.memGetFloat(pointer + offset);
}

public double getDouble(long offset) {
checkRange(offset, 8);
checkRange(offset, 8, true);
return MemoryUtil.memGetDouble(pointer + offset);
}

public void getMatrix4f(long offset, Matrix4f matrix) {
checkRange(offset, 64, 16);
checkRange(offset, 64, 16, true);
matrix.setFromAddress(pointer + offset);
}

public void getMatrix3x4f(long offset, Matrix4f matrix) {
checkRange(offset, 64, 16);
checkRange(offset, 64, 16, true);
matrix.setFromAddress(pointer + offset);
}

public void getVector3i(long offset, Vector3i vector) {
checkRange(offset, 12, 16);
checkRange(offset, 12, 16, true);
vector.setFromAddress(pointer + offset);
}

Expand Down

0 comments on commit 6972e38

Please sign in to comment.