micro opt + gpu timer
This commit is contained in:
@@ -26,6 +26,7 @@ import me.cortex.voxy.client.core.rendering.section.geometry.IGeometryData;
|
|||||||
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
||||||
import me.cortex.voxy.client.core.rendering.util.PrintfDebugUtil;
|
import me.cortex.voxy.client.core.rendering.util.PrintfDebugUtil;
|
||||||
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
import me.cortex.voxy.client.core.rendering.util.UploadStream;
|
||||||
|
import me.cortex.voxy.client.core.util.GPUTiming;
|
||||||
import me.cortex.voxy.client.core.util.IrisUtil;
|
import me.cortex.voxy.client.core.util.IrisUtil;
|
||||||
import me.cortex.voxy.common.Logger;
|
import me.cortex.voxy.common.Logger;
|
||||||
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
import me.cortex.voxy.common.thread.ServiceThreadPool;
|
||||||
@@ -206,6 +207,7 @@ public class VoxyRenderSystem {
|
|||||||
|
|
||||||
long startTime = System.nanoTime();
|
long startTime = System.nanoTime();
|
||||||
TimingStatistics.all.start();
|
TimingStatistics.all.start();
|
||||||
|
GPUTiming.INSTANCE.marker();//Start marker
|
||||||
TimingStatistics.main.start();
|
TimingStatistics.main.start();
|
||||||
|
|
||||||
//TODO: optimize
|
//TODO: optimize
|
||||||
@@ -260,8 +262,11 @@ public class VoxyRenderSystem {
|
|||||||
//Done here as is allows less gl state resetup
|
//Done here as is allows less gl state resetup
|
||||||
this.modelService.tick(Math.max(3_000_000-(System.nanoTime()-startTime), 500_000));
|
this.modelService.tick(Math.max(3_000_000-(System.nanoTime()-startTime), 500_000));
|
||||||
}
|
}
|
||||||
|
GPUTiming.INSTANCE.marker();
|
||||||
TimingStatistics.postDynamic.stop();
|
TimingStatistics.postDynamic.stop();
|
||||||
|
|
||||||
|
GPUTiming.INSTANCE.tick();
|
||||||
|
|
||||||
glBindFramebuffer(GlConst.GL_FRAMEBUFFER, oldFB);
|
glBindFramebuffer(GlConst.GL_FRAMEBUFFER, oldFB);
|
||||||
glViewport(dims[0], dims[1], dims[2], dims[3]);
|
glViewport(dims[0], dims[1], dims[2], dims[3]);
|
||||||
|
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ public class RenderGenerationService {
|
|||||||
private final AtomicInteger holdingSectionCount = new AtomicInteger();//Used to limit section holding
|
private final AtomicInteger holdingSectionCount = new AtomicInteger();//Used to limit section holding
|
||||||
|
|
||||||
private final AtomicInteger taskQueueCount = new AtomicInteger();
|
private final AtomicInteger taskQueueCount = new AtomicInteger();
|
||||||
private final PriorityBlockingQueue<BuildTask> taskQueue = new PriorityBlockingQueue<>(320000, (a,b)-> Long.compareUnsigned(a.priority, b.priority));
|
private final PriorityBlockingQueue<BuildTask> taskQueue = new PriorityBlockingQueue<>(5000, (a,b)-> Long.compareUnsigned(a.priority, b.priority));
|
||||||
private final StampedLock taskMapLock = new StampedLock();
|
private final StampedLock taskMapLock = new StampedLock();
|
||||||
private final Long2ObjectOpenHashMap<BuildTask> taskMap = new Long2ObjectOpenHashMap<>(320000);
|
private final Long2ObjectOpenHashMap<BuildTask> taskMap = new Long2ObjectOpenHashMap<>(5000);
|
||||||
|
|
||||||
private final WorldEngine world;
|
private final WorldEngine world;
|
||||||
private final ModelBakerySubsystem modelBakery;
|
private final ModelBakerySubsystem modelBakery;
|
||||||
|
|||||||
165
src/main/java/me/cortex/voxy/client/core/util/GPUTiming.java
Normal file
165
src/main/java/me/cortex/voxy/client/core/util/GPUTiming.java
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
package me.cortex.voxy.client.core.util;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import me.cortex.voxy.client.core.gl.GlBuffer;
|
||||||
|
import me.cortex.voxy.client.core.rendering.util.DownloadStream;
|
||||||
|
import me.cortex.voxy.common.util.MemoryBuffer;
|
||||||
|
import me.cortex.voxy.common.util.Pair;
|
||||||
|
import me.cortex.voxy.common.util.TrackedObject;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.ARBTimerQuery.GL_TIMESTAMP;
|
||||||
|
import static org.lwjgl.opengl.ARBTimerQuery.glQueryCounter;
|
||||||
|
import static org.lwjgl.opengl.GL11.glFinish;
|
||||||
|
import static org.lwjgl.opengl.GL11.glFlush;
|
||||||
|
import static org.lwjgl.opengl.GL15.glDeleteQueries;
|
||||||
|
import static org.lwjgl.opengl.GL15.glGenQueries;
|
||||||
|
import static org.lwjgl.opengl.GL15C.*;
|
||||||
|
import static org.lwjgl.opengl.GL33.glGetQueryObjecti64;
|
||||||
|
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
|
||||||
|
import static org.lwjgl.opengl.GL44.GL_QUERY_RESULT_NO_WAIT;
|
||||||
|
import static org.lwjgl.opengl.GL45.glGetQueryBufferObjectui64v;
|
||||||
|
|
||||||
|
public class GPUTiming {
|
||||||
|
public static GPUTiming INSTANCE = new GPUTiming();
|
||||||
|
|
||||||
|
private final GlTimestampQuerySet timingSet = new GlTimestampQuerySet();
|
||||||
|
|
||||||
|
public void marker() {
|
||||||
|
this.timingSet.capture(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
this.timingSet.download((meta,data)->{
|
||||||
|
long current = data[0];
|
||||||
|
for (int i = 1; i < meta.length; i++) {
|
||||||
|
long next = data[i];
|
||||||
|
long delta = next - current;
|
||||||
|
//System.out.println(delta);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.timingSet.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void free() {
|
||||||
|
this.timingSet.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TimingDataConsumer {
|
||||||
|
void accept(int[] metadata, long[] timings);
|
||||||
|
}
|
||||||
|
private static final class GlTimestampQuerySet extends TrackedObject {
|
||||||
|
private record InflightRequest(int[] queries, int[] meta, TimingDataConsumer callback) {
|
||||||
|
private boolean callbackIfReady(IntArrayFIFOQueue queryPool) {
|
||||||
|
boolean ready = glGetQueryObjecti(this.queries[this.queries.length-1], GL_QUERY_RESULT_AVAILABLE) == GL_TRUE;
|
||||||
|
if (!ready) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
long[] results = new long[this.queries.length];
|
||||||
|
for (int i = 0; i < this.queries.length; i++) {
|
||||||
|
results[i] = glGetQueryObjecti64(this.queries[i], GL_QUERY_RESULT);
|
||||||
|
queryPool.enqueue(this.queries[i]);
|
||||||
|
}
|
||||||
|
this.callback.accept(this.meta, results);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private final IntArrayFIFOQueue POOL = new IntArrayFIFOQueue();
|
||||||
|
private final ObjectArrayFIFOQueue<InflightRequest> INFLIGHT = new ObjectArrayFIFOQueue();
|
||||||
|
|
||||||
|
private final int[] queries = new int[64];
|
||||||
|
private final int[] metadata = new int[64];
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
|
||||||
|
public void capture(int metadata) {
|
||||||
|
if (this.index > this.metadata.length) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
int slot = this.index++;
|
||||||
|
this.metadata[slot] = metadata;
|
||||||
|
int query = this.getQuery();
|
||||||
|
glQueryCounter(query, GL_TIMESTAMP);
|
||||||
|
this.queries[slot] = query;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void download(TimingDataConsumer consumer) {
|
||||||
|
var queries = Arrays.copyOf(this.queries, this.index);
|
||||||
|
var metadata = Arrays.copyOf(this.metadata, this.index);
|
||||||
|
this.index = 0;
|
||||||
|
this.INFLIGHT.enqueue(new InflightRequest(queries, metadata, consumer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
while (!INFLIGHT.isEmpty()) {
|
||||||
|
if (INFLIGHT.first().callbackIfReady(POOL)) {
|
||||||
|
INFLIGHT.dequeue();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getQuery() {
|
||||||
|
if (POOL.isEmpty()) {
|
||||||
|
return glGenQueries();
|
||||||
|
} else {
|
||||||
|
return POOL.dequeueInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void free() {
|
||||||
|
super.free0();
|
||||||
|
while (!POOL.isEmpty()) {
|
||||||
|
glDeleteQueries(POOL.dequeueInt());
|
||||||
|
}
|
||||||
|
while (!INFLIGHT.isEmpty()) {
|
||||||
|
glDeleteQueries(INFLIGHT.dequeue().queries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
private static final class GlTimestampQuerySet extends TrackedObject {
|
||||||
|
private final int query = glGenQueries();
|
||||||
|
public final GlBuffer store;
|
||||||
|
public final int[] metadata;
|
||||||
|
public int index;
|
||||||
|
public GlTimestampQuerySet(int maxCount) {
|
||||||
|
this.store = new GlBuffer(maxCount*8L);
|
||||||
|
this.metadata = new int[maxCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void capture(int metadata) {
|
||||||
|
if (this.index>this.metadata.length) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
int slot = this.index++;
|
||||||
|
this.metadata[slot] = metadata;
|
||||||
|
glQueryCounter(this.query, GL_TIMESTAMP);//This should be gpu side, so should be fast
|
||||||
|
glFinish();
|
||||||
|
glGetQueryBufferObjectui64v(this.query, this.store.id, GL_QUERY_RESULT_NO_WAIT, slot*8L);
|
||||||
|
glMemoryBarrier(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void download(TimingDataConsumer consumer) {
|
||||||
|
var meta = Arrays.copyOf(this.metadata, this.index);
|
||||||
|
this.index = 0;
|
||||||
|
//DownloadStream.INSTANCE.download(this.store, buffer->consumer.accept(meta, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void free() {
|
||||||
|
super.free0();
|
||||||
|
glDeleteQueries(this.query);
|
||||||
|
this.store.free();
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user