Add PBOs and PBO support for default rendering

This commit is contained in:
johni0702
2015-07-16 16:19:20 +02:00
parent 787942aef2
commit 6a5b6fdac5
5 changed files with 270 additions and 6 deletions

View File

@@ -0,0 +1,160 @@
package eu.crushedpixel.replaymod.opengl;
import eu.crushedpixel.replaymod.utils.Api;
import eu.crushedpixel.replaymod.utils.Objects;
import lombok.RequiredArgsConstructor;
import net.minecraft.client.Minecraft;
import org.apache.logging.log4j.LogManager;
import org.lwjgl.opengl.ARBBufferObject;
import org.lwjgl.opengl.GLContext;
import java.nio.ByteBuffer;
import static org.lwjgl.opengl.ARBPixelBufferObject.*;
import static org.lwjgl.opengl.GL15.*;
import static org.lwjgl.opengl.GL21.GL_PIXEL_PACK_BUFFER;
@Api
public class PixelBufferObject {
@RequiredArgsConstructor
public enum Usage {
COPY(GL_STREAM_COPY_ARB, GL_STREAM_COPY),
DRAW(GL_STREAM_DRAW_ARB, GL_STREAM_DRAW),
READ(GL_STREAM_READ_ARB, GL_STREAM_READ);
private final int arb, gl15;
}
public static final boolean SUPPORTED = GLContext.getCapabilities().GL_ARB_pixel_buffer_object || GLContext.getCapabilities().OpenGL15;
private static final boolean arb = !GLContext.getCapabilities().OpenGL15;
private static ThreadLocal<Integer> bound = new ThreadLocal<Integer>();
private static ThreadLocal<Integer> mapped = new ThreadLocal<Integer>();
private final long size;
private long handle;
public PixelBufferObject(long size, Usage usage) {
if (!SUPPORTED) {
throw new UnsupportedOperationException("PBOs not supported.");
}
this.size = size;
this.handle = arb ? ARBBufferObject.glGenBuffersARB() : glGenBuffers();
bind();
if (arb) {
ARBBufferObject.glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, size, usage.arb);
} else {
glBufferData(GL_PIXEL_PACK_BUFFER, size, usage.gl15);
}
}
@Api
private int getHandle() {
if (handle == -1) {
throw new IllegalStateException("PBO not allocated.");
}
return (int) handle;
}
@Api
public void bind() {
if (arb) {
ARBBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, getHandle());
} else {
glBindBuffer(GL_PIXEL_PACK_BUFFER, getHandle());
}
bound.set(getHandle());
}
@Api
public void unbind() {
checkBound();
if (arb) {
ARBBufferObject.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
} else {
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
bound.set(0);
}
private void checkBound() {
if (!Objects.equals(getHandle(), bound.get())) {
throw new IllegalStateException("Buffer not bound.");
}
}
@Api
public ByteBuffer mapReadOnly() {
checkBound();
mapped.set(getHandle());
if (arb) {
return ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB, size, null);
} else {
return glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY, size, null);
}
}
@Api
public ByteBuffer mapWriteOnly() {
checkBound();
mapped.set(getHandle());
if (arb) {
return ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_WRITE_ONLY_ARB, size, null);
} else {
return glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_WRITE_ONLY, size, null);
}
}
@Api
public ByteBuffer mapReadWrite() {
checkBound();
mapped.set(getHandle());
if (arb) {
return ARBBufferObject.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_WRITE_ARB, size, null);
} else {
return glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE, size, null);
}
}
@Api
public void unmap() {
checkBound();
if (!Objects.equals(mapped.get(), getHandle())) {
throw new IllegalStateException("Buffer not mapped.");
}
if (arb) {
ARBBufferObject.glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
} else {
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
}
@Api
public void delete() {
if (handle != -1) {
if (arb) {
ARBBufferObject.glDeleteBuffersARB(getHandle());
} else {
glDeleteBuffers(getHandle());
}
handle = -1;
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
if (handle != -1) {
LogManager.getLogger().warn("PBO garbage collected before deleted!");
Minecraft.getMinecraft().addScheduledTask(new Runnable() {
@Override
public void run() {
delete();
}
});
}
}
}