Apply directly to the buffer

- Add DSA abstraction to GlBuffer
- Move backing impls to their respective classes
- Remove versioned package, move impls to appropriate package
- Make fallback methods take no arguments
- Do VAO check/bind in GlStateTracker
- GlVertexArray actually checks the tracked info when binding attributes
- Add separate enable* and setup* methods in VertexArray
- Add support for DSA VAO with ARB instanced arrays incase there are
  some particularly cursed drivers out there
- Misc. cleanup
This commit is contained in:
Jozufozu 2023-05-01 23:43:01 -07:00
parent 12419fd50b
commit cda7eca655
13 changed files with 227 additions and 139 deletions

View file

@ -7,7 +7,7 @@ import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.batching.BatchingEngine; import com.jozufozu.flywheel.backend.engine.batching.BatchingEngine;
import com.jozufozu.flywheel.backend.engine.indirect.IndirectEngine; import com.jozufozu.flywheel.backend.engine.indirect.IndirectEngine;
import com.jozufozu.flywheel.backend.engine.instancing.InstancingEngine; import com.jozufozu.flywheel.backend.engine.instancing.InstancingEngine;
import com.jozufozu.flywheel.gl.versioned.GlCompat; import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.lib.backend.SimpleBackend; import com.jozufozu.flywheel.lib.backend.SimpleBackend;
import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.util.ShadersModHandler; import com.jozufozu.flywheel.lib.util.ShadersModHandler;

View file

@ -10,9 +10,9 @@ import org.jetbrains.annotations.NotNull;
import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.GlShader;
import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.gl.versioned.GlCompat;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GLSLVersion;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceFile;

View file

@ -41,7 +41,7 @@ public class GPUInstancer<I extends Instance> extends AbstractInstancer<I> {
} }
vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW); vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
vbo.setGrowthMargin(instanceStride * 16); vbo.growthMargin(instanceStride * 16);
} }
public void update() { public void update() {

View file

@ -39,7 +39,7 @@ public class InstancedMeshPool {
this.vertexType = vertexType; this.vertexType = vertexType;
int stride = vertexType.getLayout().getStride(); int stride = vertexType.getLayout().getStride();
vbo = new GlBuffer(); vbo = new GlBuffer();
vbo.setGrowthMargin(stride * 32); vbo.growthMargin(stride * 32);
} }
public VertexType getVertexType() { public VertexType getVertexType() {

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.gl.versioned; package com.jozufozu.flywheel.gl;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -8,6 +8,8 @@ import org.lwjgl.opengl.GL20C;
import org.lwjgl.opengl.GLCapabilities; import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import com.jozufozu.flywheel.gl.array.GlVertexArray;
import net.minecraft.Util; import net.minecraft.Util;
/** /**
@ -17,17 +19,9 @@ import net.minecraft.Util;
* system. * system.
*/ */
public class GlCompat { public class GlCompat {
private static final GLCapabilities caps; public static final GLCapabilities CAPABILITIES = GL.createCapabilities();
public static final VertexArray vertexArray; private static final boolean amd = _decideIfWeAreAMDWindows();
public static final boolean amd; private static final boolean supportsIndirect = _decideIfWeSupportIndirect();
public static final boolean supportsIndirect;
static {
caps = GL.createCapabilities();
vertexArray = VertexArray.DSA.INSTANCE.fallback(caps);
supportsIndirect = _decideIfWeSupportIndirect();
amd = _decideIfWeAreAMDWindows();
}
private GlCompat() { private GlCompat() {
} }
@ -37,7 +31,7 @@ public class GlCompat {
} }
public static boolean supportsInstancing() { public static boolean supportsInstancing() {
return caps.OpenGL33 || caps.GL_ARB_instanced_arrays; return GlVertexArray.IMPL != null;
} }
public static boolean supportsIndirect() { public static boolean supportsIndirect() {
@ -45,12 +39,7 @@ public class GlCompat {
} }
private static boolean _decideIfWeSupportIndirect() { private static boolean _decideIfWeSupportIndirect() {
return caps.OpenGL46 || ( return CAPABILITIES.OpenGL46 || (CAPABILITIES.GL_ARB_compute_shader && CAPABILITIES.GL_ARB_shader_draw_parameters && CAPABILITIES.GL_ARB_base_instance && CAPABILITIES.GL_ARB_multi_draw_indirect && CAPABILITIES.GL_ARB_direct_state_access);
caps.GL_ARB_compute_shader &&
caps.GL_ARB_shader_draw_parameters &&
caps.GL_ARB_base_instance &&
caps.GL_ARB_multi_draw_indirect &&
caps.GL_ARB_direct_state_access);
} }
/** /**

View file

@ -39,6 +39,12 @@ public class GlStateTracker {
return new State(BUFFERS.clone(), vao, program); return new State(BUFFERS.clone(), vao, program);
} }
public static void bindVao(int vao) {
if (vao != GlStateTracker.vao) {
GlStateManager._glBindVertexArray(vao);
}
}
public record State(int[] buffers, int vao, int program) implements AutoCloseable { public record State(int[] buffers, int vao, int program) implements AutoCloseable {
public void restore() { public void restore() {
if (vao != GlStateTracker.vao) { if (vao != GlStateTracker.vao) {

View file

@ -1,18 +1,14 @@
package com.jozufozu.flywheel.gl.array; package com.jozufozu.flywheel.gl.array;
import java.util.List;
import org.lwjgl.opengl.GL32; import org.lwjgl.opengl.GL32;
import com.jozufozu.flywheel.api.layout.BufferLayout; import com.jozufozu.flywheel.api.layout.BufferLayout;
import com.jozufozu.flywheel.gl.GlObject; import com.jozufozu.flywheel.gl.GlObject;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.versioned.GlCompat;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
@SuppressWarnings("MismatchedReadAndWriteOfArray")
public class GlVertexArray extends GlObject { public class GlVertexArray extends GlObject {
public static final VertexArray IMPL = new VertexArray.DSA().fallback();
private static final int MAX_ATTRIBS = GL32.glGetInteger(GL32.GL_MAX_VERTEX_ATTRIBS); private static final int MAX_ATTRIBS = GL32.glGetInteger(GL32.GL_MAX_VERTEX_ATTRIBS);
/** /**
@ -42,57 +38,61 @@ public class GlVertexArray extends GlObject {
private int elementBufferBinding = 0; private int elementBufferBinding = 0;
public GlVertexArray() { public GlVertexArray() {
setHandle(GlCompat.vertexArray.create()); setHandle(IMPL.create());
} }
public void bindForDraw() { public void bindForDraw() {
if (!isBound()) { GlStateTracker.bindVao(handle());
GlStateManager._glBindVertexArray(handle());
}
}
private boolean isBound() {
return handle() == GlStateTracker.getVertexArray();
} }
public static void unbind() { public static void unbind() {
GlStateManager._glBindVertexArray(0); GlStateManager._glBindVertexArray(0);
} }
public void bindAttributes(BufferLayout type, int vbo, int startAttrib, long startOffset) { public void bindAttributes(BufferLayout type, final int vbo, final int startAttrib, final long startOffset) {
final int vao = handle();
final int stride = type.getStride(); final int stride = type.getStride();
List<VertexAttribute> vertexAttributes = type.attributes(); int index = startAttrib;
for (int i = 0; i < vertexAttributes.size(); i++) { long offset = startOffset;
var attribute = vertexAttributes.get(i); for (var attribute : type.attributes()) {
int index = i + startAttrib; if (!enabled[index]) {
targets[index] = vbo; IMPL.enableAttrib(vao, index);
attributes[index] = attribute; enabled[index] = true;
offsets[index] = startOffset; }
strides[index] = stride;
GlCompat.vertexArray.setupAttrib(handle(), index, vbo, stride, startOffset, attribute); if (shouldSetupAttrib(index, vbo, stride, offset, attribute)) {
IMPL.setupAttrib(vao, index, vbo, stride, offset, attribute);
targets[index] = vbo;
attributes[index] = attribute;
offsets[index] = offset;
strides[index] = stride;
}
startOffset += attribute.getByteWidth(); index++;
offset += attribute.getByteWidth();
} }
} }
private boolean shouldSetupAttrib(int index, int vbo, int stride, long offset, VertexAttribute attribute) {
return targets[index] != vbo || offsets[index] != offset || strides[index] != stride || !attribute.equals(attributes[index]);
}
protected void deleteInternal(int handle) { protected void deleteInternal(int handle) {
GlStateManager._glDeleteVertexArrays(handle); GlStateManager._glDeleteVertexArrays(handle);
} }
public void setAttributeDivisor(int index, int divisor) { public void setAttributeDivisor(int index, int divisor) {
if (divisors[index] != divisor) { if (divisors[index] != divisor) {
GlCompat.vertexArray.setAttribDivisor(handle(), index, divisor); IMPL.setAttribDivisor(handle(), index, divisor);
divisors[index] = divisor; divisors[index] = divisor;
} }
} }
public void setElementBuffer(int ebo) { public void setElementBuffer(int ebo) {
if (elementBufferBinding != ebo) { if (elementBufferBinding != ebo) {
GlCompat.vertexArray.setElementBuffer(handle(), ebo); IMPL.setElementBuffer(handle(), ebo);
elementBufferBinding = ebo; elementBufferBinding = ebo;
} }
} }

View file

@ -1,23 +1,23 @@
package com.jozufozu.flywheel.gl.versioned; package com.jozufozu.flywheel.gl.array;
import org.lwjgl.opengl.ARBInstancedArrays; import org.lwjgl.opengl.ARBInstancedArrays;
import org.lwjgl.opengl.GL20C; import org.lwjgl.opengl.GL20C;
import org.lwjgl.opengl.GL30C; import org.lwjgl.opengl.GL30C;
import org.lwjgl.opengl.GL33C; import org.lwjgl.opengl.GL33C;
import org.lwjgl.opengl.GL45C; import org.lwjgl.opengl.GL45C;
import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.system.Checks; import org.lwjgl.system.Checks;
import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.array.VertexAttribute;
import com.jozufozu.flywheel.gl.buffer.GlBufferType; import com.jozufozu.flywheel.gl.buffer.GlBufferType;
import com.mojang.blaze3d.platform.GlStateManager;
public interface VertexArray { public interface VertexArray {
int create(); int create();
void setElementBuffer(int vao, int elementBuffer); void setElementBuffer(int vao, int elementBuffer);
void enableAttrib(int vao, int index);
void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute); void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute);
void setAttribDivisor(int vao, int attrib, int divisor); void setAttribDivisor(int vao, int attrib, int divisor);
@ -30,69 +30,58 @@ public interface VertexArray {
@Override @Override
public void setElementBuffer(int vao, int elementBuffer) { public void setElementBuffer(int vao, int elementBuffer) {
if (vao != GlStateTracker.getVertexArray()) { GlStateTracker.bindVao(vao);
GlStateManager._glBindVertexArray(vao);
}
GlBufferType.ELEMENT_ARRAY_BUFFER.bind(elementBuffer); GlBufferType.ELEMENT_ARRAY_BUFFER.bind(elementBuffer);
} }
@Override @Override
public void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute) { public void enableAttrib(int vao, int index) {
if (vao != GlStateTracker.getVertexArray()) { GlStateTracker.bindVao(vao);
GlStateManager._glBindVertexArray(vao);
}
GlBufferType.ARRAY_BUFFER.bind(vbo);
GL20C.glEnableVertexAttribArray(index); GL20C.glEnableVertexAttribArray(index);
attribute.setup(offset, index, stride);
} }
@Override
public void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute) {
GlStateTracker.bindVao(vao);
GlBufferType.ARRAY_BUFFER.bind(vbo);
attribute.setup(offset, index, stride);
}
} }
class InstancedArraysARB extends GL3 { class InstancedArraysARB extends GL3 {
public static InstancedArraysARB INSTANCE = new InstancedArraysARB();
@Override @Override
public void setAttribDivisor(int vao, int attrib, int divisor) { public void setAttribDivisor(int vao, int attrib, int divisor) {
if (vao != GlStateTracker.getVertexArray()) { GlStateTracker.bindVao(vao);
GlStateManager._glBindVertexArray(vao);
}
ARBInstancedArrays.glVertexAttribDivisorARB(attrib, divisor); ARBInstancedArrays.glVertexAttribDivisorARB(attrib, divisor);
} }
public VertexArray fallback(GLCapabilities caps) { public VertexArray fallback() {
return isSupported(caps) ? this : null; if (Checks.checkFunctions(GlCompat.CAPABILITIES.glVertexAttribDivisorARB)) {
} return this;
}
private boolean isSupported(GLCapabilities caps) { // null signals that we don't support instancing.
return Checks.checkFunctions(caps.glVertexAttribDivisorARB); return null;
} }
} }
class InstancedArraysCore extends GL3 { class InstancedArraysCore extends GL3 {
public static InstancedArraysCore INSTANCE = new InstancedArraysCore();
@Override @Override
public void setAttribDivisor(int vao, int attrib, int divisor) { public void setAttribDivisor(int vao, int attrib, int divisor) {
if (vao != GlStateTracker.getVertexArray()) { GlStateTracker.bindVao(vao);
GlStateManager._glBindVertexArray(vao);
}
GL33C.glVertexAttribDivisor(attrib, divisor); GL33C.glVertexAttribDivisor(attrib, divisor);
} }
public VertexArray fallback(GLCapabilities caps) { public VertexArray fallback() {
return isSupported(caps) ? this : InstancedArraysARB.INSTANCE.fallback(caps); // We know vertex arrays are supported because minecraft required GL32.
if (Checks.checkFunctions(GlCompat.CAPABILITIES.glVertexAttribDivisor)) {
return this;
}
return new InstancedArraysARB().fallback();
} }
private static boolean isSupported(GLCapabilities caps) {
// We know vertex arrays are supported because minecraft required GL32.
return Checks.checkFunctions(caps.glVertexAttribDivisor);
}
} }
class DSA implements VertexArray { class DSA implements VertexArray {
public static final DSA INSTANCE = new DSA();
@Override @Override
public int create() { public int create() {
return GL45C.glCreateVertexArrays(); return GL45C.glCreateVertexArrays();
@ -104,8 +93,12 @@ public interface VertexArray {
} }
@Override @Override
public void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute) { public void enableAttrib(int vao, int index) {
GL45C.glEnableVertexArrayAttrib(vao, index); GL45C.glEnableVertexArrayAttrib(vao, index);
}
@Override
public void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute) {
GL45C.glVertexArrayVertexBuffer(vao, index, vbo, offset, stride); GL45C.glVertexArrayVertexBuffer(vao, index, vbo, offset, stride);
attribute.setupDSA(vao, index); attribute.setupDSA(vao, index);
} }
@ -115,12 +108,26 @@ public interface VertexArray {
GL45C.glVertexArrayBindingDivisor(vao, attrib, divisor); GL45C.glVertexArrayBindingDivisor(vao, attrib, divisor);
} }
public VertexArray fallback(GLCapabilities caps) { public VertexArray fallback() {
return isSupported(caps) ? this : InstancedArraysCore.INSTANCE.fallback(caps); var c = GlCompat.CAPABILITIES;
} if (Checks.checkFunctions(c.glCreateVertexArrays, c.glVertexArrayElementBuffer, c.glEnableVertexArrayAttrib, c.glVertexArrayVertexBuffer, c.glVertexArrayAttribFormat, c.glVertexArrayAttribIFormat)) {
private static boolean isSupported(GLCapabilities caps) { if (Checks.checkFunctions(c.glVertexArrayBindingDivisor)) {
return Checks.checkFunctions(caps.glCreateVertexArrays, caps.glVertexArrayElementBuffer, caps.glEnableVertexArrayAttrib, caps.glVertexArrayVertexBuffer, caps.glVertexArrayBindingDivisor, caps.glVertexArrayAttribFormat, caps.glVertexArrayAttribIFormat); return this;
} else if (Checks.checkFunctions(c.glVertexArrayVertexAttribDivisorEXT)) {
// Seems like this may happen when a driver supports
// ARB_direct_state_access but not core instanced arrays?
return new InstancedArraysEXTDSA();
}
}
return new InstancedArraysCore().fallback();
}
}
class InstancedArraysEXTDSA extends DSA {
@Override
public void setAttribDivisor(int vao, int attrib, int divisor) {
ARBInstancedArrays.glVertexArrayVertexAttribDivisorEXT(vao, attrib, divisor);
} }
} }
} }

View file

@ -13,7 +13,6 @@ import com.jozufozu.flywheel.gl.GlNumericType;
* @param normalized Whether the data is normalized. * @param normalized Whether the data is normalized.
*/ */
public record VertexAttributeF(GlNumericType type, int size, boolean normalized) implements VertexAttribute { public record VertexAttributeF(GlNumericType type, int size, boolean normalized) implements VertexAttribute {
@Override @Override
public int getByteWidth() { public int getByteWidth() {
return size * type.getByteWidth(); return size * type.getByteWidth();

View file

@ -12,7 +12,6 @@ import com.jozufozu.flywheel.gl.GlNumericType;
* @param size The number of components in the attribute, e.g. 3 for a vec3. * @param size The number of components in the attribute, e.g. 3 for a vec3.
*/ */
public record VertexAttributeI(GlNumericType type, int size) implements VertexAttribute { public record VertexAttributeI(GlNumericType type, int size) implements VertexAttribute {
@Override @Override
public int getByteWidth() { public int getByteWidth() {
return size * type.getByteWidth(); return size * type.getByteWidth();

View file

@ -0,0 +1,89 @@
package com.jozufozu.flywheel.gl.buffer;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import org.lwjgl.opengl.GL45C;
import org.lwjgl.system.Checks;
import com.jozufozu.flywheel.gl.GlCompat;
public interface Buffer {
int create();
void data(int vbo, long size, long ptr, int glEnum);
void copyData(int src, int dst, long srcOffset, long dstOffset, long size);
long mapRange(int handle, int offset, long size, int access);
void unmap(int handle);
class DSA implements Buffer {
@Override
public int create() {
return GL45C.glCreateBuffers();
}
@Override
public void data(int vbo, long size, long ptr, int glEnum) {
GL45C.nglNamedBufferData(vbo, size, ptr, glEnum);
}
@Override
public void copyData(int src, int dst, long srcOffset, long dstOffset, long size) {
GL45C.glCopyNamedBufferSubData(src, dst, srcOffset, dstOffset, size);
}
@Override
public long mapRange(int handle, int offset, long size, int access) {
return GL45C.nglMapNamedBufferRange(handle, offset, size, access);
}
@Override
public void unmap(int handle) {
GL45C.glUnmapNamedBuffer(handle);
}
public Buffer fallback() {
var c = GlCompat.CAPABILITIES;
if (Checks.checkFunctions(c.glCreateBuffers, c.glNamedBufferData, c.glCopyNamedBufferSubData, c.glMapNamedBufferRange, c.glUnmapNamedBuffer)) {
return this;
}
return new Core();
}
}
class Core implements Buffer {
@Override
public int create() {
return GL15.glGenBuffers();
}
@Override
public void data(int vbo, long size, long ptr, int glEnum) {
GlBufferType.COPY_WRITE_BUFFER.bind(vbo);
GL15.nglBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, size, ptr, glEnum);
}
@Override
public void copyData(int src, int dst, long size, long srcOffset, long dstOffset) {
GlBufferType.COPY_READ_BUFFER.bind(src);
GlBufferType.COPY_WRITE_BUFFER.bind(dst);
GL31.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, GlBufferType.COPY_WRITE_BUFFER.glEnum, srcOffset, dstOffset, size);
}
@Override
public long mapRange(int handle, int offset, long size, int access) {
GlBufferType.COPY_READ_BUFFER.bind(handle);
return GL30.nglMapBufferRange(GlBufferType.COPY_READ_BUFFER.glEnum, 0, size, access);
}
@Override
public void unmap(int handle) {
GlBufferType.COPY_READ_BUFFER.bind(handle);
GL15.glUnmapBuffer(GlBufferType.COPY_READ_BUFFER.glEnum);
}
}
}

View file

@ -1,16 +1,16 @@
package com.jozufozu.flywheel.gl.buffer; package com.jozufozu.flywheel.gl.buffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glDeleteBuffers; import static org.lwjgl.opengl.GL15.glDeleteBuffers;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL15.nglBufferData; import org.lwjgl.system.MemoryUtil;
import static org.lwjgl.opengl.GL31.glCopyBufferSubData;
import com.jozufozu.flywheel.gl.GlObject; import com.jozufozu.flywheel.gl.GlObject;
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker; import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import com.mojang.blaze3d.platform.GlStateManager;
public class GlBuffer extends GlObject { public class GlBuffer extends GlObject {
public static final Buffer IMPL = new Buffer.DSA().fallback();
protected final GlBufferUsage usage; protected final GlBufferUsage usage;
/** /**
* The size (in bytes) of the buffer on the GPU. * The size (in bytes) of the buffer on the GPU.
@ -26,64 +26,67 @@ public class GlBuffer extends GlObject {
} }
public GlBuffer(GlBufferUsage usage) { public GlBuffer(GlBufferUsage usage) {
setHandle(glGenBuffers()); setHandle(IMPL.create());
this.usage = usage; this.usage = usage;
} }
/** /**
* @return true if the buffer was recreated. * @return true if the buffer was recreated.
*/ */
public boolean ensureCapacity(long size) { public boolean ensureCapacity(long capacity) {
if (size < 0) { if (capacity < 0) {
throw new IllegalArgumentException("Size " + size + " < 0"); throw new IllegalArgumentException("Size " + capacity + " < 0");
} }
if (size == 0) { if (capacity == 0) {
return false; return false;
} }
if (this.size == 0) { if (size == 0) {
this.size = size; alloc(capacity);
GlBufferType.COPY_WRITE_BUFFER.bind(handle());
glBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, size, usage.glEnum);
FlwMemoryTracker._allocGPUMemory(size);
return true; return true;
} }
if (size > this.size) { if (capacity > size) {
var oldSize = this.size; realloc(capacity);
this.size = size + growthMargin;
realloc(oldSize, this.size);
return true; return true;
} }
return false; return false;
} }
private void realloc(long oldSize, long newSize) { private void alloc(long capacity) {
FlwMemoryTracker._freeGPUMemory(oldSize); increaseSize(capacity);
FlwMemoryTracker._allocGPUMemory(newSize); IMPL.data(handle(), size, MemoryUtil.NULL, usage.glEnum);
var oldHandle = handle(); FlwMemoryTracker._allocGPUMemory(size);
var newHandle = glGenBuffers(); }
GlBufferType.COPY_READ_BUFFER.bind(oldHandle); private void realloc(long capacity) {
GlBufferType.COPY_WRITE_BUFFER.bind(newHandle); FlwMemoryTracker._freeGPUMemory(size);
var oldSize = size;
glBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, newSize, usage.glEnum); increaseSize(capacity);
glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, GlBufferType.COPY_WRITE_BUFFER.glEnum, 0, 0, oldSize);
int oldHandle = handle();
int newHandle = IMPL.create();
IMPL.data(newHandle, size, MemoryUtil.NULL, usage.glEnum);
IMPL.copyData(oldHandle, newHandle, 0, 0, oldSize);
glDeleteBuffers(oldHandle); glDeleteBuffers(oldHandle);
setHandle(newHandle); setHandle(newHandle);
FlwMemoryTracker._allocGPUMemory(size);
}
/**
* Increase the size of the buffer to at least the given capacity.
*/
private void increaseSize(long capacity) {
size = capacity + growthMargin;
} }
public void upload(MemoryBlock directBuffer) { public void upload(MemoryBlock directBuffer) {
FlwMemoryTracker._freeGPUMemory(size); FlwMemoryTracker._freeGPUMemory(size);
GlBufferType.COPY_WRITE_BUFFER.bind(handle()); IMPL.data(handle(), directBuffer.size(), directBuffer.ptr(), usage.glEnum);
nglBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, directBuffer.size(), directBuffer.ptr(), usage.glEnum); size = directBuffer.size();
this.size = directBuffer.size();
FlwMemoryTracker._allocGPUMemory(size); FlwMemoryTracker._allocGPUMemory(size);
} }
@ -91,16 +94,16 @@ public class GlBuffer extends GlObject {
return new MappedBuffer(handle(), size); return new MappedBuffer(handle(), size);
} }
public void setGrowthMargin(int growthMargin) { public void growthMargin(int growthMargin) {
this.growthMargin = growthMargin; this.growthMargin = growthMargin;
} }
public long getSize() { public long size() {
return size; return size;
} }
protected void deleteInternal(int handle) { protected void deleteInternal(int handle) {
glDeleteBuffers(handle); GlStateManager._glDeleteBuffers(handle);
FlwMemoryTracker._freeGPUMemory(size); FlwMemoryTracker._freeGPUMemory(size);
} }
} }

View file

@ -1,10 +1,8 @@
package com.jozufozu.flywheel.gl.buffer; package com.jozufozu.flywheel.gl.buffer;
import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT; import static org.lwjgl.opengl.GL30.GL_MAP_WRITE_BIT;
import static org.lwjgl.opengl.GL30.nglMapBufferRange;
import static org.lwjgl.system.MemoryUtil.NULL; import static org.lwjgl.system.MemoryUtil.NULL;
import org.lwjgl.opengl.GL15;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.gl.error.GlError; import com.jozufozu.flywheel.gl.error.GlError;
@ -17,8 +15,7 @@ public class MappedBuffer implements AutoCloseable {
public MappedBuffer(int glBuffer, long size) { public MappedBuffer(int glBuffer, long size) {
this.glBuffer = glBuffer; this.glBuffer = glBuffer;
GlBufferType.COPY_READ_BUFFER.bind(glBuffer); ptr = GlBuffer.IMPL.mapRange(glBuffer, 0, size, GL_MAP_WRITE_BIT);
ptr = nglMapBufferRange(GlBufferType.COPY_READ_BUFFER.glEnum, 0, size, GL_MAP_WRITE_BIT);
if (ptr == MemoryUtil.NULL) { if (ptr == MemoryUtil.NULL) {
throw new GlException(GlError.poll(), "Could not map buffer"); throw new GlException(GlError.poll(), "Could not map buffer");
@ -35,8 +32,7 @@ public class MappedBuffer implements AutoCloseable {
return; return;
} }
GlBufferType.COPY_READ_BUFFER.bind(glBuffer); GlBuffer.IMPL.unmap(glBuffer);
GL15.glUnmapBuffer(GlBufferType.COPY_READ_BUFFER.glEnum);
ptr = NULL; ptr = NULL;
} }
} }