mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-26 06:57:02 +01:00
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:
parent
12419fd50b
commit
cda7eca655
13 changed files with 227 additions and 139 deletions
|
@ -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.indirect.IndirectEngine;
|
||||
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.context.Contexts;
|
||||
import com.jozufozu.flywheel.lib.util.ShadersModHandler;
|
||||
|
|
|
@ -10,9 +10,9 @@ import org.jetbrains.annotations.NotNull;
|
|||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.gl.GlCompat;
|
||||
import com.jozufozu.flywheel.gl.shader.GlShader;
|
||||
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.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
|
|
|
@ -41,7 +41,7 @@ public class GPUInstancer<I extends Instance> extends AbstractInstancer<I> {
|
|||
}
|
||||
|
||||
vbo = new GlBuffer(GlBufferUsage.DYNAMIC_DRAW);
|
||||
vbo.setGrowthMargin(instanceStride * 16);
|
||||
vbo.growthMargin(instanceStride * 16);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
|
|
|
@ -39,7 +39,7 @@ public class InstancedMeshPool {
|
|||
this.vertexType = vertexType;
|
||||
int stride = vertexType.getLayout().getStride();
|
||||
vbo = new GlBuffer();
|
||||
vbo.setGrowthMargin(stride * 32);
|
||||
vbo.growthMargin(stride * 32);
|
||||
}
|
||||
|
||||
public VertexType getVertexType() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.gl.versioned;
|
||||
package com.jozufozu.flywheel.gl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
@ -8,6 +8,8 @@ import org.lwjgl.opengl.GL20C;
|
|||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import com.jozufozu.flywheel.gl.array.GlVertexArray;
|
||||
|
||||
import net.minecraft.Util;
|
||||
|
||||
/**
|
||||
|
@ -17,17 +19,9 @@ import net.minecraft.Util;
|
|||
* system.
|
||||
*/
|
||||
public class GlCompat {
|
||||
private static final GLCapabilities caps;
|
||||
public static final VertexArray vertexArray;
|
||||
public static final boolean amd;
|
||||
public static final boolean supportsIndirect;
|
||||
|
||||
static {
|
||||
caps = GL.createCapabilities();
|
||||
vertexArray = VertexArray.DSA.INSTANCE.fallback(caps);
|
||||
supportsIndirect = _decideIfWeSupportIndirect();
|
||||
amd = _decideIfWeAreAMDWindows();
|
||||
}
|
||||
public static final GLCapabilities CAPABILITIES = GL.createCapabilities();
|
||||
private static final boolean amd = _decideIfWeAreAMDWindows();
|
||||
private static final boolean supportsIndirect = _decideIfWeSupportIndirect();
|
||||
|
||||
private GlCompat() {
|
||||
}
|
||||
|
@ -37,7 +31,7 @@ public class GlCompat {
|
|||
}
|
||||
|
||||
public static boolean supportsInstancing() {
|
||||
return caps.OpenGL33 || caps.GL_ARB_instanced_arrays;
|
||||
return GlVertexArray.IMPL != null;
|
||||
}
|
||||
|
||||
public static boolean supportsIndirect() {
|
||||
|
@ -45,12 +39,7 @@ public class GlCompat {
|
|||
}
|
||||
|
||||
private static boolean _decideIfWeSupportIndirect() {
|
||||
return caps.OpenGL46 || (
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
|
@ -39,6 +39,12 @@ public class GlStateTracker {
|
|||
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 void restore() {
|
||||
if (vao != GlStateTracker.vao) {
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
package com.jozufozu.flywheel.gl.array;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.jozufozu.flywheel.api.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.gl.GlObject;
|
||||
import com.jozufozu.flywheel.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.gl.versioned.GlCompat;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
@SuppressWarnings("MismatchedReadAndWriteOfArray")
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -42,57 +38,61 @@ public class GlVertexArray extends GlObject {
|
|||
|
||||
private int elementBufferBinding = 0;
|
||||
|
||||
|
||||
public GlVertexArray() {
|
||||
setHandle(GlCompat.vertexArray.create());
|
||||
setHandle(IMPL.create());
|
||||
}
|
||||
|
||||
public void bindForDraw() {
|
||||
if (!isBound()) {
|
||||
GlStateManager._glBindVertexArray(handle());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBound() {
|
||||
return handle() == GlStateTracker.getVertexArray();
|
||||
GlStateTracker.bindVao(handle());
|
||||
}
|
||||
|
||||
public static void unbind() {
|
||||
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();
|
||||
|
||||
List<VertexAttribute> vertexAttributes = type.attributes();
|
||||
for (int i = 0; i < vertexAttributes.size(); i++) {
|
||||
var attribute = vertexAttributes.get(i);
|
||||
int index = i + startAttrib;
|
||||
targets[index] = vbo;
|
||||
attributes[index] = attribute;
|
||||
offsets[index] = startOffset;
|
||||
strides[index] = stride;
|
||||
int index = startAttrib;
|
||||
long offset = startOffset;
|
||||
for (var attribute : type.attributes()) {
|
||||
if (!enabled[index]) {
|
||||
IMPL.enableAttrib(vao, index);
|
||||
enabled[index] = true;
|
||||
}
|
||||
|
||||
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) {
|
||||
GlStateManager._glDeleteVertexArrays(handle);
|
||||
}
|
||||
|
||||
public void setAttributeDivisor(int index, int divisor) {
|
||||
if (divisors[index] != divisor) {
|
||||
GlCompat.vertexArray.setAttribDivisor(handle(), index, divisor);
|
||||
IMPL.setAttribDivisor(handle(), index, divisor);
|
||||
divisors[index] = divisor;
|
||||
}
|
||||
}
|
||||
|
||||
public void setElementBuffer(int ebo) {
|
||||
if (elementBufferBinding != ebo) {
|
||||
GlCompat.vertexArray.setElementBuffer(handle(), ebo);
|
||||
IMPL.setElementBuffer(handle(), ebo);
|
||||
elementBufferBinding = ebo;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.GL20C;
|
||||
import org.lwjgl.opengl.GL30C;
|
||||
import org.lwjgl.opengl.GL33C;
|
||||
import org.lwjgl.opengl.GL45C;
|
||||
import org.lwjgl.opengl.GLCapabilities;
|
||||
import org.lwjgl.system.Checks;
|
||||
|
||||
import com.jozufozu.flywheel.gl.GlCompat;
|
||||
import com.jozufozu.flywheel.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.gl.array.VertexAttribute;
|
||||
import com.jozufozu.flywheel.gl.buffer.GlBufferType;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
public interface VertexArray {
|
||||
int create();
|
||||
|
||||
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 setAttribDivisor(int vao, int attrib, int divisor);
|
||||
|
@ -30,69 +30,58 @@ public interface VertexArray {
|
|||
|
||||
@Override
|
||||
public void setElementBuffer(int vao, int elementBuffer) {
|
||||
if (vao != GlStateTracker.getVertexArray()) {
|
||||
GlStateManager._glBindVertexArray(vao);
|
||||
}
|
||||
GlStateTracker.bindVao(vao);
|
||||
GlBufferType.ELEMENT_ARRAY_BUFFER.bind(elementBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute) {
|
||||
if (vao != GlStateTracker.getVertexArray()) {
|
||||
GlStateManager._glBindVertexArray(vao);
|
||||
}
|
||||
GlBufferType.ARRAY_BUFFER.bind(vbo);
|
||||
|
||||
public void enableAttrib(int vao, int index) {
|
||||
GlStateTracker.bindVao(vao);
|
||||
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 {
|
||||
public static InstancedArraysARB INSTANCE = new InstancedArraysARB();
|
||||
|
||||
@Override
|
||||
public void setAttribDivisor(int vao, int attrib, int divisor) {
|
||||
if (vao != GlStateTracker.getVertexArray()) {
|
||||
GlStateManager._glBindVertexArray(vao);
|
||||
}
|
||||
GlStateTracker.bindVao(vao);
|
||||
ARBInstancedArrays.glVertexAttribDivisorARB(attrib, divisor);
|
||||
}
|
||||
|
||||
public VertexArray fallback(GLCapabilities caps) {
|
||||
return isSupported(caps) ? this : null;
|
||||
}
|
||||
|
||||
private boolean isSupported(GLCapabilities caps) {
|
||||
return Checks.checkFunctions(caps.glVertexAttribDivisorARB);
|
||||
public VertexArray fallback() {
|
||||
if (Checks.checkFunctions(GlCompat.CAPABILITIES.glVertexAttribDivisorARB)) {
|
||||
return this;
|
||||
}
|
||||
// null signals that we don't support instancing.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class InstancedArraysCore extends GL3 {
|
||||
public static InstancedArraysCore INSTANCE = new InstancedArraysCore();
|
||||
|
||||
@Override
|
||||
public void setAttribDivisor(int vao, int attrib, int divisor) {
|
||||
if (vao != GlStateTracker.getVertexArray()) {
|
||||
GlStateManager._glBindVertexArray(vao);
|
||||
}
|
||||
GlStateTracker.bindVao(vao);
|
||||
GL33C.glVertexAttribDivisor(attrib, divisor);
|
||||
}
|
||||
|
||||
public VertexArray fallback(GLCapabilities caps) {
|
||||
return isSupported(caps) ? this : InstancedArraysARB.INSTANCE.fallback(caps);
|
||||
public VertexArray fallback() {
|
||||
// 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 {
|
||||
public static final DSA INSTANCE = new DSA();
|
||||
|
||||
@Override
|
||||
public int create() {
|
||||
return GL45C.glCreateVertexArrays();
|
||||
|
@ -104,8 +93,12 @@ public interface VertexArray {
|
|||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupAttrib(int vao, int index, int vbo, int stride, long offset, VertexAttribute attribute) {
|
||||
GL45C.glVertexArrayVertexBuffer(vao, index, vbo, offset, stride);
|
||||
attribute.setupDSA(vao, index);
|
||||
}
|
||||
|
@ -115,12 +108,26 @@ public interface VertexArray {
|
|||
GL45C.glVertexArrayBindingDivisor(vao, attrib, divisor);
|
||||
}
|
||||
|
||||
public VertexArray fallback(GLCapabilities caps) {
|
||||
return isSupported(caps) ? this : InstancedArraysCore.INSTANCE.fallback(caps);
|
||||
}
|
||||
public VertexArray fallback() {
|
||||
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) {
|
||||
return Checks.checkFunctions(caps.glCreateVertexArrays, caps.glVertexArrayElementBuffer, caps.glEnableVertexArrayAttrib, caps.glVertexArrayVertexBuffer, caps.glVertexArrayBindingDivisor, caps.glVertexArrayAttribFormat, caps.glVertexArrayAttribIFormat);
|
||||
if (Checks.checkFunctions(c.glVertexArrayBindingDivisor)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ import com.jozufozu.flywheel.gl.GlNumericType;
|
|||
* @param normalized Whether the data is normalized.
|
||||
*/
|
||||
public record VertexAttributeF(GlNumericType type, int size, boolean normalized) implements VertexAttribute {
|
||||
|
||||
@Override
|
||||
public int getByteWidth() {
|
||||
return size * type.getByteWidth();
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
public record VertexAttributeI(GlNumericType type, int size) implements VertexAttribute {
|
||||
|
||||
@Override
|
||||
public int getByteWidth() {
|
||||
return size * type.getByteWidth();
|
||||
|
|
89
src/main/java/com/jozufozu/flywheel/gl/buffer/Buffer.java
Normal file
89
src/main/java/com/jozufozu/flywheel/gl/buffer/Buffer.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +1,16 @@
|
|||
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.glGenBuffers;
|
||||
import static org.lwjgl.opengl.GL15.nglBufferData;
|
||||
import static org.lwjgl.opengl.GL31.glCopyBufferSubData;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.gl.GlObject;
|
||||
import com.jozufozu.flywheel.lib.memory.FlwMemoryTracker;
|
||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
public class GlBuffer extends GlObject {
|
||||
public static final Buffer IMPL = new Buffer.DSA().fallback();
|
||||
protected final GlBufferUsage usage;
|
||||
/**
|
||||
* The size (in bytes) of the buffer on the GPU.
|
||||
|
@ -26,64 +26,67 @@ public class GlBuffer extends GlObject {
|
|||
}
|
||||
|
||||
public GlBuffer(GlBufferUsage usage) {
|
||||
setHandle(glGenBuffers());
|
||||
setHandle(IMPL.create());
|
||||
this.usage = usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the buffer was recreated.
|
||||
*/
|
||||
public boolean ensureCapacity(long size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("Size " + size + " < 0");
|
||||
public boolean ensureCapacity(long capacity) {
|
||||
if (capacity < 0) {
|
||||
throw new IllegalArgumentException("Size " + capacity + " < 0");
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
if (capacity == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.size == 0) {
|
||||
this.size = size;
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(handle());
|
||||
glBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, size, usage.glEnum);
|
||||
FlwMemoryTracker._allocGPUMemory(size);
|
||||
|
||||
if (size == 0) {
|
||||
alloc(capacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (size > this.size) {
|
||||
var oldSize = this.size;
|
||||
this.size = size + growthMargin;
|
||||
|
||||
realloc(oldSize, this.size);
|
||||
|
||||
if (capacity > size) {
|
||||
realloc(capacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void realloc(long oldSize, long newSize) {
|
||||
FlwMemoryTracker._freeGPUMemory(oldSize);
|
||||
FlwMemoryTracker._allocGPUMemory(newSize);
|
||||
var oldHandle = handle();
|
||||
var newHandle = glGenBuffers();
|
||||
private void alloc(long capacity) {
|
||||
increaseSize(capacity);
|
||||
IMPL.data(handle(), size, MemoryUtil.NULL, usage.glEnum);
|
||||
FlwMemoryTracker._allocGPUMemory(size);
|
||||
}
|
||||
|
||||
GlBufferType.COPY_READ_BUFFER.bind(oldHandle);
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(newHandle);
|
||||
|
||||
glBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, newSize, usage.glEnum);
|
||||
glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, GlBufferType.COPY_WRITE_BUFFER.glEnum, 0, 0, oldSize);
|
||||
private void realloc(long capacity) {
|
||||
FlwMemoryTracker._freeGPUMemory(size);
|
||||
var oldSize = size;
|
||||
increaseSize(capacity);
|
||||
|
||||
int oldHandle = handle();
|
||||
int newHandle = IMPL.create();
|
||||
IMPL.data(newHandle, size, MemoryUtil.NULL, usage.glEnum);
|
||||
IMPL.copyData(oldHandle, newHandle, 0, 0, oldSize);
|
||||
glDeleteBuffers(oldHandle);
|
||||
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) {
|
||||
FlwMemoryTracker._freeGPUMemory(size);
|
||||
GlBufferType.COPY_WRITE_BUFFER.bind(handle());
|
||||
nglBufferData(GlBufferType.COPY_WRITE_BUFFER.glEnum, directBuffer.size(), directBuffer.ptr(), usage.glEnum);
|
||||
this.size = directBuffer.size();
|
||||
IMPL.data(handle(), directBuffer.size(), directBuffer.ptr(), usage.glEnum);
|
||||
size = directBuffer.size();
|
||||
FlwMemoryTracker._allocGPUMemory(size);
|
||||
}
|
||||
|
||||
|
@ -91,16 +94,16 @@ public class GlBuffer extends GlObject {
|
|||
return new MappedBuffer(handle(), size);
|
||||
}
|
||||
|
||||
public void setGrowthMargin(int growthMargin) {
|
||||
public void growthMargin(int growthMargin) {
|
||||
this.growthMargin = growthMargin;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
public long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
protected void deleteInternal(int handle) {
|
||||
glDeleteBuffers(handle);
|
||||
GlStateManager._glDeleteBuffers(handle);
|
||||
FlwMemoryTracker._freeGPUMemory(size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package com.jozufozu.flywheel.gl.buffer;
|
||||
|
||||
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 org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.gl.error.GlError;
|
||||
|
@ -17,8 +15,7 @@ public class MappedBuffer implements AutoCloseable {
|
|||
public MappedBuffer(int glBuffer, long size) {
|
||||
this.glBuffer = glBuffer;
|
||||
|
||||
GlBufferType.COPY_READ_BUFFER.bind(glBuffer);
|
||||
ptr = nglMapBufferRange(GlBufferType.COPY_READ_BUFFER.glEnum, 0, size, GL_MAP_WRITE_BIT);
|
||||
ptr = GlBuffer.IMPL.mapRange(glBuffer, 0, size, GL_MAP_WRITE_BIT);
|
||||
|
||||
if (ptr == MemoryUtil.NULL) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
|
@ -35,8 +32,7 @@ public class MappedBuffer implements AutoCloseable {
|
|||
return;
|
||||
}
|
||||
|
||||
GlBufferType.COPY_READ_BUFFER.bind(glBuffer);
|
||||
GL15.glUnmapBuffer(GlBufferType.COPY_READ_BUFFER.glEnum);
|
||||
GlBuffer.IMPL.unmap(glBuffer);
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue