mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Better buffer binding
- Directly call GlBuffer#bind before raw gl calls - Everything else is hidden now - GlStateTracker.State implements AutoCloseable for try-with-resources blocks - Wrap InstancedModel render calls in a GlStateTracker restore block - Improve EBO creation - Track CPU memory usage (wish java had ownership concepts) - Misc cleanups
This commit is contained in:
parent
2632cd385c
commit
1765aa74f8
52 changed files with 800 additions and 719 deletions
|
@ -43,6 +43,7 @@ minecraft {
|
|||
property 'forge.logging.markers', ''
|
||||
property 'forge.logging.console.level', 'debug'
|
||||
property 'mixin.debug.export', 'true'
|
||||
property 'flw.dumpShaderSource', 'true'
|
||||
|
||||
arg '-mixin.config=flywheel.mixins.json'
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public interface InstancedStructType<S> extends StructType<S> {
|
||||
|
@ -9,7 +10,7 @@ public interface InstancedStructType<S> extends StructType<S> {
|
|||
*
|
||||
* @param backing The buffer that the StructWriter will write to.
|
||||
*/
|
||||
StructWriter<S> getWriter(VecBuffer backing);
|
||||
StructWriter<S> getWriter(ByteBuffer backing);
|
||||
|
||||
FileResolution getInstanceShader();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
@ -17,6 +19,8 @@ import net.minecraft.world.level.LevelAccessor;
|
|||
public class Backend {
|
||||
public static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
public static boolean dumpShaderSource = Boolean.getBoolean("flw.dumpShaderSource");
|
||||
|
||||
private static BackendType backendType;
|
||||
|
||||
private static ParallelTaskEngine taskEngine;
|
||||
|
@ -105,4 +109,5 @@ public class Backend {
|
|||
private Backend() {
|
||||
throw new UnsupportedOperationException("Backend is a static class!");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import org.lwjgl.opengl.GL43;
|
||||
import org.lwjgl.opengl.GLDebugMessageCallback;
|
||||
|
||||
import com.mojang.blaze3d.platform.GlDebug;
|
||||
|
||||
public class FlywheelDebug {
|
||||
//
|
||||
// public static void setup() {
|
||||
// GLDebugMessageCallback.create()
|
||||
// GL43.glDebugMessageCallback();
|
||||
// }
|
||||
//
|
||||
// private static void printDebugLog(int p_84039_, int p_84040_, int p_84041_, int p_84042_, int p_84043_, long p_84044_, long p_84045_) {
|
||||
// String s = GLDebugMessageCallback.getMessage(p_84043_, p_84044_);
|
||||
// GlDebug.LogEntry gldebug$logentry;
|
||||
// synchronized(MESSAGE_BUFFER) {
|
||||
// gldebug$logentry = lastEntry;
|
||||
// if (gldebug$logentry != null && gldebug$logentry.isSame(p_84039_, p_84040_, p_84041_, p_84042_, s)) {
|
||||
// ++gldebug$logentry.count;
|
||||
// } else {
|
||||
// gldebug$logentry = new GlDebug.LogEntry(p_84039_, p_84040_, p_84041_, p_84042_, s);
|
||||
// MESSAGE_BUFFER.add(gldebug$logentry);
|
||||
// lastEntry = gldebug$logentry;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// LOGGER.info("OpenGL debug message: {}", (Object)gldebug$logentry);
|
||||
// }
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
public class FlywheelMemory {
|
||||
|
||||
public static final Cleaner CLEANER = Cleaner.create();
|
||||
|
||||
private static int gpuMemory = 0;
|
||||
private static int cpuMemory = 0;
|
||||
|
||||
public static void _freeCPUMemory(long size) {
|
||||
cpuMemory -= size;
|
||||
}
|
||||
|
||||
public static void _allocCPUMemory(long size) {
|
||||
cpuMemory += size;
|
||||
}
|
||||
|
||||
public static void _freeGPUMemory(long size) {
|
||||
gpuMemory -= size;
|
||||
}
|
||||
|
||||
public static void _allocGPUMemory(long size) {
|
||||
gpuMemory += size;
|
||||
}
|
||||
|
||||
public static int getGPUMemory() {
|
||||
return gpuMemory;
|
||||
}
|
||||
|
||||
public static int getCPUMemory() {
|
||||
return cpuMemory;
|
||||
}
|
||||
|
||||
public static Cleaner.Cleanable track(Object owner, ByteBuffer buffer) {
|
||||
return CLEANER.register(owner, new Tracked(buffer));
|
||||
}
|
||||
|
||||
public static class Tracked implements Runnable {
|
||||
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
public Tracked(ByteBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
_allocCPUMemory(buffer.capacity());
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_freeCPUMemory(buffer.capacity());
|
||||
MemoryUtil.memFree(buffer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.gl;
|
||||
|
||||
import com.jozufozu.flywheel.backend.RenderWork;
|
||||
|
||||
// Utility class for safely dealing with gl object handles.
|
||||
public abstract class GlObject {
|
||||
private static final int INVALID_HANDLE = Integer.MIN_VALUE;
|
||||
|
@ -40,5 +42,4 @@ public abstract class GlObject {
|
|||
}
|
||||
|
||||
protected abstract void deleteInternal(int handle);
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class GlStateTracker {
|
|||
return new State(buffers.clone(), vao, program);
|
||||
}
|
||||
|
||||
public static record State(int[] buffers, int vao, int program) {
|
||||
public record State(int[] buffers, int vao, int program) implements AutoCloseable {
|
||||
public void restore() {
|
||||
GlBufferType[] values = GlBufferType.values();
|
||||
|
||||
|
@ -58,5 +58,10 @@ public class GlStateTracker {
|
|||
GlStateManager._glUseProgram(program);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.gl;
|
|||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
|
@ -61,16 +62,19 @@ public class GlVertexArray extends GlObject {
|
|||
GlStateManager._glBindVertexArray(0);
|
||||
}
|
||||
|
||||
public void bindAttributes(int startIndex, BufferLayout type) {
|
||||
int boundBuffer = GlStateTracker.getBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
|
||||
public void bindAttributes(GlBuffer buffer, int startIndex, BufferLayout type) {
|
||||
bind();
|
||||
|
||||
int targetBuffer = buffer.handle();
|
||||
|
||||
GlBufferType.ARRAY_BUFFER.bind(targetBuffer);
|
||||
|
||||
int i = startIndex;
|
||||
int offset = 0;
|
||||
final int stride = type.getStride();
|
||||
|
||||
for (VertexAttribute attribute : type.getAttributes()) {
|
||||
targets[i] = boundBuffer;
|
||||
targets[i] = targetBuffer;
|
||||
attributes[i] = attribute;
|
||||
offsets[i] = offset;
|
||||
strides[i] = stride;
|
||||
|
|
|
@ -29,12 +29,12 @@ public abstract class GlBuffer extends GlObject {
|
|||
}
|
||||
}
|
||||
|
||||
protected final GlBufferType type;
|
||||
public final GlBufferType type;
|
||||
|
||||
/**
|
||||
* The size (in bytes) of the buffer on the GPU.
|
||||
*/
|
||||
protected long capacity;
|
||||
protected long size;
|
||||
|
||||
/**
|
||||
* How much extra room to give the buffer when we reallocate.
|
||||
|
@ -42,7 +42,7 @@ public abstract class GlBuffer extends GlObject {
|
|||
protected int growthMargin;
|
||||
|
||||
public GlBuffer(GlBufferType type) {
|
||||
_create();
|
||||
setHandle(GL20.glGenBuffers());
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
@ -50,42 +50,14 @@ public abstract class GlBuffer extends GlObject {
|
|||
this.growthMargin = growthMargin;
|
||||
}
|
||||
|
||||
public long getCapacity() {
|
||||
return capacity;
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public MappedBuffer getBuffer() {
|
||||
return getBuffer(0, capacity);
|
||||
public GlBufferType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public abstract MappedBuffer getBuffer(long offset, long length);
|
||||
|
||||
/**
|
||||
* Ensure that the buffer has at least enough room to store size bytes.
|
||||
*
|
||||
* @return true if the buffer grew.
|
||||
*/
|
||||
public boolean ensureCapacity(long size) {
|
||||
if (size > capacity) {
|
||||
capacity = size + growthMargin;
|
||||
alloc(capacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this after all draw calls using this buffer are complete.
|
||||
*/
|
||||
public void doneForThisFrame() {
|
||||
|
||||
}
|
||||
|
||||
protected abstract void alloc(long size);
|
||||
|
||||
public abstract void upload(ByteBuffer directBuffer);
|
||||
|
||||
public void bind() {
|
||||
type.bind(handle());
|
||||
}
|
||||
|
@ -94,11 +66,31 @@ public abstract class GlBuffer extends GlObject {
|
|||
type.unbind();
|
||||
}
|
||||
|
||||
protected void _create() {
|
||||
setHandle(GL20.glGenBuffers());
|
||||
public abstract void upload(ByteBuffer directBuffer);
|
||||
|
||||
public abstract MappedBuffer map();
|
||||
|
||||
/**
|
||||
* Ensure that the buffer has at least enough room to store {@code size} bytes.
|
||||
*
|
||||
* @return {@code true} if the buffer moved.
|
||||
*/
|
||||
public abstract boolean ensureCapacity(long size);
|
||||
|
||||
/**
|
||||
* Call this after all draw calls using this buffer are complete.
|
||||
*/
|
||||
public void doneForThisFrame() {
|
||||
|
||||
}
|
||||
|
||||
protected void deleteInternal(int handle) {
|
||||
GL20.glDeleteBuffers(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this buffer need not be #flush()'d for its contents to sync.
|
||||
* @return true if this buffer is persistently mapped.
|
||||
*/
|
||||
public abstract boolean isPersistent();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import org.lwjgl.opengl.GL43;
|
|||
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
public enum GlBufferType {
|
||||
ARRAY_BUFFER(GL15C.GL_ARRAY_BUFFER),
|
||||
|
@ -53,11 +54,13 @@ public enum GlBufferType {
|
|||
}
|
||||
|
||||
public void bind(int buffer) {
|
||||
GlStateManager._glBindBuffer(glEnum, buffer);
|
||||
if (getBoundBuffer() != buffer) {
|
||||
GlStateManager._glBindBuffer(glEnum, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void unbind() {
|
||||
GlStateManager._glBindBuffer(glEnum, 0);
|
||||
bind(0);
|
||||
}
|
||||
|
||||
public int getBoundBuffer() {
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
/**
|
||||
* Interface for generically dealing with mapped buffers.
|
||||
*/
|
||||
public interface Mappable {
|
||||
GlBufferType getType();
|
||||
|
||||
/**
|
||||
* Indicates that this buffer need not be #flush()'d for its contents to sync.
|
||||
* @return true if this buffer is persistently mapped.
|
||||
*/
|
||||
boolean isPersistent();
|
||||
}
|
|
@ -3,43 +3,69 @@ package com.jozufozu.flywheel.backend.gl.buffer;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
public class MappedBuffer extends VecBuffer implements AutoCloseable {
|
||||
public class MappedBuffer implements AutoCloseable {
|
||||
|
||||
protected final long offset;
|
||||
protected final long length;
|
||||
protected final Mappable owner;
|
||||
private final long offset;
|
||||
private final long length;
|
||||
private final GlBuffer owner;
|
||||
private final boolean persistent;
|
||||
private ByteBuffer internal;
|
||||
|
||||
public MappedBuffer(Mappable owner, ByteBuffer internal, long offset, long length) {
|
||||
public MappedBuffer(GlBuffer owner, ByteBuffer internal, long offset, long length) {
|
||||
this.internal = internal;
|
||||
this.owner = owner;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
persistent = owner.isPersistent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the changes in client memory available to the GPU.
|
||||
*/
|
||||
public void flush() {
|
||||
if (owner.isPersistent()) return;
|
||||
if (persistent) return;
|
||||
|
||||
if (internal == null) return;
|
||||
|
||||
owner.bind();
|
||||
GL15.glUnmapBuffer(owner.getType().glEnum);
|
||||
internal = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedBuffer position(int p) {
|
||||
if (p < offset || p >= offset + length) {
|
||||
throw new IndexOutOfBoundsException("Index " + p + " is not mapped");
|
||||
}
|
||||
super.position(p - (int) offset);
|
||||
internal.position(p - (int) offset);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
public void close() {
|
||||
flush();
|
||||
}
|
||||
|
||||
public ByteBuffer unwrap() {
|
||||
return internal;
|
||||
}
|
||||
|
||||
public long getMemAddress() {
|
||||
return MemoryUtil.memAddress(internal);
|
||||
}
|
||||
|
||||
public void clear(long clearStart, long clearLength) {
|
||||
if (clearLength <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clearStart < offset || clearStart + clearLength > offset + length) {
|
||||
throw new IndexOutOfBoundsException("Clear range [" + clearStart + "," + (clearStart + clearLength) + "] is not mapped");
|
||||
}
|
||||
|
||||
long addr = MemoryUtil.memAddress(unwrap()) + clearStart;
|
||||
|
||||
MemoryUtil.memSet(addr, 0, clearLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@ package com.jozufozu.flywheel.backend.gl.buffer;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
|
||||
public class MappedGlBuffer extends GlBuffer implements Mappable {
|
||||
public class MappedGlBuffer extends GlBuffer {
|
||||
|
||||
protected final GlBufferUsage usage;
|
||||
|
||||
|
@ -21,27 +21,67 @@ public class MappedGlBuffer extends GlBuffer implements Mappable {
|
|||
this.usage = usage;
|
||||
}
|
||||
|
||||
protected void alloc(long size) {
|
||||
GL15.glBufferData(type.glEnum, size, usage.glEnum);
|
||||
@Override
|
||||
public boolean ensureCapacity(long size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("Size " + size + " < 0");
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.size == 0) {
|
||||
this.size = size;
|
||||
bind();
|
||||
GL32.glBufferData(type.glEnum, size, usage.glEnum);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (size > this.size) {
|
||||
var oldSize = this.size;
|
||||
this.size = size + growthMargin;
|
||||
|
||||
realloc(oldSize, this.size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void realloc(long oldSize, long newSize) {
|
||||
var oldHandle = handle();
|
||||
var newHandle = GL32.glGenBuffers();
|
||||
|
||||
GlBufferType.COPY_READ_BUFFER.bind(oldHandle);
|
||||
type.bind(newHandle);
|
||||
|
||||
GL32.glBufferData(type.glEnum, newSize, usage.glEnum);
|
||||
GL32.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, type.glEnum, 0, 0, oldSize);
|
||||
|
||||
delete();
|
||||
setHandle(newHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(ByteBuffer directBuffer) {
|
||||
GL15.glBufferData(type.glEnum, directBuffer, usage.glEnum);
|
||||
bind();
|
||||
GL32.glBufferData(type.glEnum, directBuffer, usage.glEnum);
|
||||
this.size = directBuffer.capacity();
|
||||
}
|
||||
|
||||
public MappedBuffer getBuffer(long offset, long length) {
|
||||
ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, offset, length, GL30.GL_MAP_WRITE_BIT);
|
||||
@Override
|
||||
public MappedBuffer map() {
|
||||
bind();
|
||||
ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, GL30.GL_MAP_WRITE_BIT);
|
||||
|
||||
if (byteBuffer == null) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
}
|
||||
|
||||
return new MappedBuffer(this, byteBuffer, offset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlBufferType getType() {
|
||||
return type;
|
||||
return new MappedBuffer(this, byteBuffer, 0, size);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,20 +6,21 @@ import static org.lwjgl.opengl.GL44.GL_MAP_PERSISTENT_BIT;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlFence;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlError;
|
||||
import com.jozufozu.flywheel.backend.gl.error.GlException;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
|
||||
public class PersistentGlBuffer extends GlBuffer implements Mappable {
|
||||
public class PersistentGlBuffer extends GlBuffer {
|
||||
|
||||
private MappedBuffer buffer;
|
||||
@Nullable
|
||||
private MappedBuffer access;
|
||||
int flags;
|
||||
|
||||
long size;
|
||||
GlFence fence;
|
||||
private final GlFence fence;
|
||||
|
||||
public PersistentGlBuffer(GlBufferType type) {
|
||||
super(type);
|
||||
|
@ -34,47 +35,98 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void alloc(long size) {
|
||||
this.size = size;
|
||||
|
||||
if (buffer != null) {
|
||||
deleteInternal(handle());
|
||||
_create();
|
||||
|
||||
bind();
|
||||
public boolean ensureCapacity(long size) {
|
||||
if (size < 0) {
|
||||
throw new IllegalArgumentException("Size " + size + " < 0");
|
||||
}
|
||||
|
||||
fence.clear();
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GlCompat.getInstance().bufferStorage.bufferStorage(type, size, flags);
|
||||
if (this.size == 0) {
|
||||
this.size = size;
|
||||
bind();
|
||||
GlCompat.getInstance().bufferStorage.bufferStorage(type, this.size, flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, flags);
|
||||
if (size > this.size) {
|
||||
var oldSize = this.size;
|
||||
this.size = size + growthMargin;
|
||||
|
||||
fence.clear();
|
||||
|
||||
realloc(this.size, oldSize);
|
||||
|
||||
access = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(ByteBuffer directBuffer) {
|
||||
ensureCapacity(directBuffer.capacity());
|
||||
|
||||
var access = getWriteAccess();
|
||||
|
||||
ByteBuffer ourBuffer = access.unwrap();
|
||||
|
||||
ourBuffer.reset();
|
||||
|
||||
MemoryUtil.memCopy(directBuffer, ourBuffer);
|
||||
|
||||
int uploadSize = directBuffer.remaining();
|
||||
int ourSize = ourBuffer.capacity();
|
||||
|
||||
if (uploadSize < ourSize) {
|
||||
long clearFrom = access.getMemAddress() + uploadSize;
|
||||
MemoryUtil.memSet(clearFrom, 0, ourSize - uploadSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void mapToClientMemory() {
|
||||
bind();
|
||||
ByteBuffer byteBuffer = GL32.glMapBufferRange(type.glEnum, 0, size, flags);
|
||||
|
||||
if (byteBuffer == null) {
|
||||
throw new GlException(GlError.poll(), "Could not map buffer");
|
||||
}
|
||||
|
||||
buffer = new MappedBuffer(this, byteBuffer, 0, size);
|
||||
access = new MappedBuffer(this, byteBuffer, 0, size);
|
||||
}
|
||||
|
||||
private void realloc(long newSize, long oldSize) {
|
||||
int oldHandle = handle();
|
||||
int newHandle = GL32.glGenBuffers();
|
||||
|
||||
GlBufferType.COPY_READ_BUFFER.bind(oldHandle);
|
||||
type.bind(newHandle);
|
||||
|
||||
GlCompat.getInstance().bufferStorage.bufferStorage(type, newSize, flags);
|
||||
|
||||
GL32.glCopyBufferSubData(GlBufferType.COPY_READ_BUFFER.glEnum, type.glEnum, 0, 0, oldSize);
|
||||
|
||||
delete();
|
||||
setHandle(newHandle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(ByteBuffer directBuffer) {
|
||||
throw new UnsupportedOperationException("FIXME: Nothing calls #upload on a persistent buffer as of 12/10/2021.");
|
||||
public MappedBuffer map() {
|
||||
return getWriteAccess()
|
||||
.position(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedBuffer getBuffer(long offset, long length) {
|
||||
private MappedBuffer getWriteAccess() {
|
||||
if (access == null) {
|
||||
mapToClientMemory();
|
||||
} else {
|
||||
fence.waitSync(); // FIXME: Hangs too much, needs double/triple buffering
|
||||
}
|
||||
|
||||
fence.waitSync();
|
||||
|
||||
buffer.position((int) offset);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GlBufferType getType() {
|
||||
return type;
|
||||
return access;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.gl.buffer;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
public class VecBuffer {
|
||||
|
||||
protected ByteBuffer internal;
|
||||
|
||||
public VecBuffer() {
|
||||
}
|
||||
|
||||
public VecBuffer(ByteBuffer internal) {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
public static VecBuffer allocate(int bytes) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(bytes);
|
||||
buffer.order(ByteOrder.nativeOrder());
|
||||
return new VecBuffer(buffer);
|
||||
}
|
||||
|
||||
public ByteBuffer unwrap() {
|
||||
return internal;
|
||||
}
|
||||
|
||||
public VecBuffer rewind() {
|
||||
((Buffer) internal).rewind();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putFloatArray(float[] floats) {
|
||||
|
||||
internal.asFloatBuffer().put(floats);
|
||||
internal.position(internal.position() + floats.length * 4);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putByteArray(byte[] bytes) {
|
||||
internal.put(bytes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer put(FloatBuffer floats) {
|
||||
|
||||
int remainingBytes = floats.remaining() * 4;
|
||||
internal.asFloatBuffer().put(floats);
|
||||
internal.position(internal.position() + remainingBytes);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int position() {
|
||||
return internal.position();
|
||||
}
|
||||
|
||||
/**
|
||||
* Position this buffer relative to the 0-index in GPU memory.
|
||||
*
|
||||
* @return This buffer.
|
||||
*/
|
||||
public VecBuffer position(int p) {
|
||||
internal.position(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putFloat(float f) {
|
||||
internal.putFloat(f);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putInt(int i) {
|
||||
internal.putInt(i);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putShort(short s) {
|
||||
internal.putShort(s);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer put(byte b) {
|
||||
internal.put(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer put(ByteBuffer b) {
|
||||
internal.put(b);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putVec4(float x, float y, float z, float w) {
|
||||
internal.putFloat(x);
|
||||
internal.putFloat(y);
|
||||
internal.putFloat(z);
|
||||
internal.putFloat(w);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putColor(int r, int g, int b, int a) {
|
||||
internal.put((byte) r);
|
||||
internal.put((byte) g);
|
||||
internal.put((byte) b);
|
||||
internal.put((byte) a);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putColor(byte r, byte g, byte b, byte a) {
|
||||
internal.put(r);
|
||||
internal.put(g);
|
||||
internal.put(b);
|
||||
internal.put(a);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putVec3(float x, float y, float z) {
|
||||
internal.putFloat(x);
|
||||
internal.putFloat(y);
|
||||
internal.putFloat(z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putVec2(float x, float y) {
|
||||
internal.putFloat(x);
|
||||
internal.putFloat(y);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putVec3(byte x, byte y, byte z) {
|
||||
internal.put(x);
|
||||
internal.put(y);
|
||||
internal.put(z);
|
||||
return this;
|
||||
}
|
||||
|
||||
public VecBuffer putVec2(byte x, byte y) {
|
||||
internal.put(x);
|
||||
internal.put(y);
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -7,10 +7,11 @@ import java.util.stream.Collectors;
|
|||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.core.compile.ShaderCompilationException;
|
||||
import com.jozufozu.flywheel.core.shader.ShaderConstants;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -30,18 +31,10 @@ public class GlShader extends GlObject {
|
|||
GlCompat.safeShaderSource(handle, source);
|
||||
GL20.glCompileShader(handle);
|
||||
|
||||
// TODO: control this via a JVM flag or other
|
||||
dumpSource(source, type);
|
||||
|
||||
// String log = GL20.glGetShaderInfoLog(handle);
|
||||
//
|
||||
// if (!log.isEmpty()) {
|
||||
// System.out.println(log);
|
||||
//// env.printShaderInfoLog(source, log, this.name);
|
||||
// }
|
||||
|
||||
if (GL20.glGetShaderi(handle, GL20.GL_COMPILE_STATUS) != GL20.GL_TRUE) {
|
||||
throw new ShaderLoadingException("Could not compile " + getName() + ". See log for details.");
|
||||
throw new ShaderCompilationException("Could not compile " + getName(), handle);
|
||||
}
|
||||
|
||||
setHandle(handle);
|
||||
|
@ -61,6 +54,10 @@ public class GlShader extends GlObject {
|
|||
}
|
||||
|
||||
private void dumpSource(String source, ShaderType type) {
|
||||
if (!Backend.dumpShaderSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
File dir = new File(Minecraft.getInstance().gameDirectory, "flywheel_sources");
|
||||
dir.mkdirs();
|
||||
File file = new File(dir, type.getFileName(getName()));
|
||||
|
|
|
@ -38,13 +38,7 @@ public class GlCompat {
|
|||
instancedArrays = getLatest(InstancedArrays.class, caps);
|
||||
bufferStorage = getLatest(BufferStorage.class, caps);
|
||||
|
||||
if (Util.getPlatform() == Util.OS.WINDOWS) {
|
||||
String vendor = GL20C.glGetString(GL20C.GL_VENDOR);
|
||||
// vendor string I got was "ATI Technologies Inc."
|
||||
amd = vendor.contains("ATI") || vendor.contains("AMD");
|
||||
} else {
|
||||
amd = false;
|
||||
}
|
||||
amd = _isAmdWindows();
|
||||
}
|
||||
|
||||
public boolean onAMDWindows() {
|
||||
|
@ -82,7 +76,7 @@ public class GlCompat {
|
|||
|
||||
/**
|
||||
* Copied from:
|
||||
* <br> https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96
|
||||
* <br> <a href="https://github.com/grondag/canvas/commit/820bf754092ccaf8d0c169620c2ff575722d7d96">canvas</a>
|
||||
*
|
||||
* <p>Identical in function to {@link GL20C#glShaderSource(int, CharSequence)} but
|
||||
* passes a null pointer for string length to force the driver to rely on the null
|
||||
|
@ -107,5 +101,20 @@ public class GlCompat {
|
|||
stack.setPointer(stackPointer);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean _isAmdWindows() {
|
||||
if (Util.getPlatform() != Util.OS.WINDOWS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String vendor = GL20C.glGetString(GL20C.GL_VENDOR);
|
||||
|
||||
if (vendor == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vendor string I got was "ATI Technologies Inc."
|
||||
return vendor.contains("ATI") || vendor.contains("AMD");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.FlywheelMemory;
|
||||
import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
|
||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||
|
@ -14,11 +16,12 @@ import net.minecraft.client.renderer.RenderType;
|
|||
*
|
||||
* The number of vertices needs to be known ahead of time.
|
||||
*/
|
||||
public class DrawBuffer {
|
||||
public class DrawBuffer implements AutoCloseable {
|
||||
|
||||
private final RenderType parent;
|
||||
private ByteBuffer backingBuffer;
|
||||
private int expectedVertices;
|
||||
private Cleaner.Cleanable cleanable;
|
||||
|
||||
public DrawBuffer(RenderType parent) {
|
||||
this.parent = parent;
|
||||
|
@ -43,9 +46,12 @@ public class DrawBuffer {
|
|||
|
||||
if (backingBuffer == null) {
|
||||
backingBuffer = MemoryTracker.create(byteSize);
|
||||
cleanable = FlywheelMemory.track(this, backingBuffer);
|
||||
}
|
||||
if (byteSize > backingBuffer.capacity()) {
|
||||
cleanable.clean();
|
||||
backingBuffer = MemoryTracker.resize(backingBuffer, byteSize);
|
||||
cleanable = FlywheelMemory.track(this, backingBuffer);
|
||||
}
|
||||
|
||||
return new DirectVertexConsumer(backingBuffer, format, vertexCount);
|
||||
|
@ -74,4 +80,11 @@ public class DrawBuffer {
|
|||
public void reset() {
|
||||
this.expectedVertices = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (cleanable != null) {
|
||||
cleanable.clean();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend.instancing;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.config.FlwCommands;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
|
@ -123,9 +122,6 @@ public class InstancedRenderDispatcher {
|
|||
}
|
||||
|
||||
public static void getDebugString(List<String> debug) {
|
||||
debug.add("");
|
||||
debug.add("Flywheel: " + Flywheel.getVersion());
|
||||
|
||||
if (Backend.isOn()) {
|
||||
InstanceWorld instanceWorld = instanceWorlds.get(Minecraft.getInstance().level);
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.InstancedStructType;
|
||||
|
@ -56,65 +54,48 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
removeDeletedInstances();
|
||||
}
|
||||
|
||||
vbo.bind();
|
||||
|
||||
if (!realloc()) {
|
||||
|
||||
if (checkAndGrowBuffer()) {
|
||||
// The instance vbo has moved, so we need to re-bind attributes
|
||||
boundTo.clear();
|
||||
|
||||
if (anyToRemove) {
|
||||
clearBufferTail();
|
||||
}
|
||||
|
||||
if (anyToUpdate) {
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
glInstanceCount = data.size();
|
||||
}
|
||||
|
||||
if (anyToUpdate) {
|
||||
clearAndUpdateBuffer();
|
||||
}
|
||||
|
||||
glInstanceCount = data.size();
|
||||
|
||||
if (boundTo.add(vao)) {
|
||||
bindInstanceAttributes(vao);
|
||||
}
|
||||
|
||||
vbo.unbind();
|
||||
|
||||
anyToRemove = anyToUpdate = false;
|
||||
}
|
||||
|
||||
private void clearBufferTail() {
|
||||
int size = data.size();
|
||||
final int offset = size * instanceFormat.getStride();
|
||||
final long length = vbo.getCapacity() - offset;
|
||||
if (length > 0) {
|
||||
try (MappedBuffer buf = vbo.getBuffer(offset, length)) {
|
||||
MemoryUtil.memSet(MemoryUtil.memAddress(buf.unwrap()), 0, length);
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error clearing buffer tail:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBuffer() {
|
||||
private void clearAndUpdateBuffer() {
|
||||
final int size = data.size();
|
||||
final long clearStart = (long) size * instanceFormat.getStride();
|
||||
final long clearLength = vbo.getSize() - clearStart;
|
||||
|
||||
if (size <= 0) return;
|
||||
try (MappedBuffer buf = vbo.map()) {
|
||||
buf.clear(clearStart, clearLength);
|
||||
|
||||
try (MappedBuffer mapped = vbo.getBuffer()) {
|
||||
if (size > 0) {
|
||||
|
||||
final StructWriter<D> writer = instancedType.getWriter(mapped);
|
||||
final StructWriter<D> writer = instancedType.getWriter(buf.unwrap());
|
||||
|
||||
boolean sequential = true;
|
||||
for (int i = 0; i < size; i++) {
|
||||
final D element = data.get(i);
|
||||
if (element.checkDirtyAndClear()) {
|
||||
if (!sequential) {
|
||||
writer.seek(i);
|
||||
boolean sequential = true;
|
||||
for (int i = 0; i < size; i++) {
|
||||
final D element = data.get(i);
|
||||
if (element.checkDirtyAndClear()) {
|
||||
if (!sequential) {
|
||||
writer.seek(i);
|
||||
}
|
||||
writer.write(element);
|
||||
sequential = true;
|
||||
} else {
|
||||
sequential = false;
|
||||
}
|
||||
writer.write(element);
|
||||
sequential = true;
|
||||
} else {
|
||||
sequential = false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -122,33 +103,22 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean realloc() {
|
||||
/**
|
||||
* @return {@code true} if the buffer moved.
|
||||
*/
|
||||
private boolean checkAndGrowBuffer() {
|
||||
int size = this.data.size();
|
||||
int stride = instanceFormat.getStride();
|
||||
int requiredSize = size * stride;
|
||||
if (vbo.ensureCapacity(requiredSize)) {
|
||||
|
||||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
StructWriter<D> writer = instancedType.getWriter(buffer);
|
||||
for (D datum : data) {
|
||||
writer.write(datum);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error reallocating GPUInstancer:", e);
|
||||
}
|
||||
|
||||
glInstanceCount = size;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return vbo.ensureCapacity(requiredSize);
|
||||
}
|
||||
|
||||
private void bindInstanceAttributes(GlVertexArray vao) {
|
||||
vao.bindAttributes(attributeBaseIndex, instanceFormat);
|
||||
vao.bindAttributes(this.vbo, this.attributeBaseIndex, this.instanceFormat);
|
||||
|
||||
for (int i = 0; i < instanceFormat.getAttributeCount(); i++) {
|
||||
vao.setAttributeDivisor(attributeBaseIndex + i, 1);
|
||||
for (int i = 0; i < this.instanceFormat.getAttributeCount(); i++) {
|
||||
vao.setAttributeDivisor(this.attributeBaseIndex + i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Map;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
@ -44,7 +45,7 @@ public class InstancedModel<D extends InstanceData> {
|
|||
private Layer(MeshPool allocator, Material material, Mesh mesh) {
|
||||
this.material = material;
|
||||
vao = new GlVertexArray();
|
||||
bufferedMesh = allocator.alloc(mesh, vao);
|
||||
bufferedMesh = allocator.alloc(mesh);
|
||||
instancer.attributeBaseIndex = bufferedMesh.getAttributeCount();
|
||||
vao.enableArrays(bufferedMesh.getAttributeCount() + instancer.instanceFormat.getAttributeCount());
|
||||
}
|
||||
|
@ -53,16 +54,17 @@ public class InstancedModel<D extends InstanceData> {
|
|||
public void render() {
|
||||
if (invalid()) return;
|
||||
|
||||
vao.bind();
|
||||
try (var ignored = GlStateTracker.getRestoreState()) {
|
||||
|
||||
instancer.renderSetup(vao);
|
||||
instancer.renderSetup(vao);
|
||||
|
||||
if (instancer.glInstanceCount > 0) {
|
||||
bufferedMesh.drawInstances(instancer.glInstanceCount);
|
||||
if (instancer.glInstanceCount > 0) {
|
||||
bufferedMesh.drawInstances(vao, instancer.glInstanceCount);
|
||||
}
|
||||
|
||||
// persistent mapping sync point
|
||||
instancer.vbo.doneForThisFrame();
|
||||
}
|
||||
|
||||
// persistent mapping sync point
|
||||
instancer.vbo.doneForThisFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,7 +10,7 @@ public class ArrayModelRenderer {
|
|||
|
||||
public ArrayModelRenderer(BlockMesh mesh, MeshPool meshPool) {
|
||||
this.vao = new GlVertexArray();
|
||||
this.mesh = meshPool.alloc(mesh, this.vao);
|
||||
this.mesh = meshPool.alloc(mesh);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,9 +19,7 @@ public class ArrayModelRenderer {
|
|||
public void draw() {
|
||||
if (mesh.isDeleted()) return;
|
||||
|
||||
vao.bind();
|
||||
|
||||
mesh.drawCall();
|
||||
mesh.drawCall(vao);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
|
@ -42,7 +44,6 @@ public class MeshPool {
|
|||
|
||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
|
||||
vbo.bind();
|
||||
vbo.setGrowthMargin(stride * 64);
|
||||
}
|
||||
|
||||
|
@ -50,16 +51,15 @@ public class MeshPool {
|
|||
* Allocate a model in the arena.
|
||||
*
|
||||
* @param mesh The model to allocate.
|
||||
* @param vao The vertex array object to attach the model to.
|
||||
* @return A handle to the allocated model.
|
||||
*/
|
||||
public BufferedMesh alloc(Mesh mesh, GlVertexArray vao) {
|
||||
BufferedMesh bufferedModel = new BufferedMesh(vao, mesh, vertices);
|
||||
public BufferedMesh alloc(Mesh mesh) {
|
||||
BufferedMesh bufferedModel = new BufferedMesh(mesh, vertices);
|
||||
vertices += mesh.getVertexCount();
|
||||
models.add(bufferedModel);
|
||||
pendingUpload.add(bufferedModel);
|
||||
|
||||
setDirty();
|
||||
dirty = true;
|
||||
return bufferedModel;
|
||||
}
|
||||
|
||||
|
@ -67,13 +67,11 @@ public class MeshPool {
|
|||
if (dirty) {
|
||||
if (anyToRemove) processDeletions();
|
||||
|
||||
vbo.bind();
|
||||
if (realloc()) {
|
||||
uploadAll();
|
||||
} else {
|
||||
uploadPending();
|
||||
}
|
||||
vbo.unbind();
|
||||
|
||||
dirty = false;
|
||||
pendingUpload.clear();
|
||||
|
@ -110,7 +108,7 @@ public class MeshPool {
|
|||
}
|
||||
|
||||
private void uploadAll() {
|
||||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
try (MappedBuffer buffer = vbo.map()) {
|
||||
VertexWriter writer = vertexType.createWriter(buffer.unwrap());
|
||||
|
||||
int vertices = 0;
|
||||
|
@ -128,7 +126,7 @@ public class MeshPool {
|
|||
}
|
||||
|
||||
private void uploadPending() {
|
||||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
try (MappedBuffer buffer = vbo.map()) {
|
||||
VertexWriter writer = vertexType.createWriter(buffer.unwrap());
|
||||
for (BufferedMesh model : pendingUpload) {
|
||||
model.buffer(writer);
|
||||
|
@ -139,10 +137,6 @@ public class MeshPool {
|
|||
}
|
||||
}
|
||||
|
||||
private void setDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
vbo.delete();
|
||||
}
|
||||
|
@ -150,51 +144,60 @@ public class MeshPool {
|
|||
public class BufferedMesh {
|
||||
|
||||
private final ElementBuffer ebo;
|
||||
private final GlVertexArray vao;
|
||||
|
||||
private final Mesh mesh;
|
||||
private int first;
|
||||
|
||||
private boolean deleted;
|
||||
|
||||
public BufferedMesh(GlVertexArray vao, Mesh mesh, int first) {
|
||||
this.vao = vao;
|
||||
private final Set<GlVertexArray> boundTo = new HashSet<>();
|
||||
|
||||
public BufferedMesh(Mesh mesh, int first) {
|
||||
this.mesh = mesh;
|
||||
this.first = first;
|
||||
ebo = mesh.createEBO();
|
||||
this.ebo = mesh.createEBO();
|
||||
}
|
||||
|
||||
public void drawCall() {
|
||||
ebo.bind();
|
||||
GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, first);
|
||||
public void drawCall(GlVertexArray vao) {
|
||||
attachTo(vao);
|
||||
vao.bind();
|
||||
this.ebo.bind();
|
||||
GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, this.ebo.elementCount, this.ebo.eboIndexType.getGlEnum(), 0, this.first);
|
||||
}
|
||||
|
||||
public void drawInstances(int instanceCount) {
|
||||
public void drawInstances(GlVertexArray vao, int instanceCount) {
|
||||
if (mesh.getVertexCount() <= 0 || isDeleted()) return;
|
||||
|
||||
ebo.bind();
|
||||
attachTo(vao);
|
||||
|
||||
vao.bind();
|
||||
this.ebo.bind();
|
||||
|
||||
//Backend.log.info(StringUtil.args("drawElementsInstancedBaseVertex", GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first));
|
||||
|
||||
GL32.glDrawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount, first);
|
||||
GL32.glDrawElementsInstancedBaseVertex(GlPrimitive.TRIANGLES.glEnum, this.ebo.elementCount, this.ebo.eboIndexType.getGlEnum(), 0, instanceCount, this.first);
|
||||
}
|
||||
|
||||
private void attachTo(GlVertexArray vao) {
|
||||
if (this.boundTo.add(vao)) {
|
||||
vao.enableArrays(getAttributeCount());
|
||||
vao.bindAttributes(MeshPool.this.vbo, 0, MeshPool.this.vertexType.getLayout());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
return this.deleted;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
setDirty();
|
||||
anyToRemove = true;
|
||||
deleted = true;
|
||||
MeshPool.this.dirty = true;
|
||||
MeshPool.this.anyToRemove = true;
|
||||
this.deleted = true;
|
||||
}
|
||||
|
||||
private void buffer(VertexWriter writer) {
|
||||
writer.seekToVertex(first);
|
||||
writer.writeVertexList(mesh.getReader());
|
||||
|
||||
vao.enableArrays(getAttributeCount());
|
||||
vao.bindAttributes(0, vertexType.getLayout());
|
||||
writer.seekToVertex(this.first);
|
||||
writer.writeVertexList(this.mesh.getReader());
|
||||
this.boundTo.clear();
|
||||
}
|
||||
|
||||
public int getAttributeCount() {
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
package com.jozufozu.flywheel.backend.struct;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
|
||||
public abstract class BufferWriter<S> implements StructWriter<S> {
|
||||
protected final VecBuffer backingBuffer;
|
||||
protected final ByteBuffer backingBuffer;
|
||||
|
||||
protected final int stride;
|
||||
|
||||
protected BufferWriter(VecBuffer backingBuffer, StructType<S> vertexType) {
|
||||
this.backingBuffer = backingBuffer;
|
||||
protected BufferWriter(StructType<S> structType, ByteBuffer byteBuffer) {
|
||||
this.backingBuffer = byteBuffer;
|
||||
|
||||
this.stride = vertexType.getLayout().getStride();
|
||||
this.stride = structType.getLayout().getStride();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.struct;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
|
||||
/**
|
||||
* This class copied/adapted from jellysquid's
|
||||
|
@ -20,8 +21,8 @@ public abstract class UnsafeBufferWriter<S> extends BufferWriter<S> {
|
|||
*/
|
||||
protected long writePointer;
|
||||
|
||||
protected UnsafeBufferWriter(VecBuffer backingBuffer, StructType<S> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
protected UnsafeBufferWriter(StructType<S> structType, ByteBuffer byteBuffer) {
|
||||
super(structType, byteBuffer);
|
||||
|
||||
acquireWritePointer();
|
||||
}
|
||||
|
@ -38,6 +39,6 @@ public abstract class UnsafeBufferWriter<S> extends BufferWriter<S> {
|
|||
}
|
||||
|
||||
private void acquireWritePointer() {
|
||||
this.writePointer = MemoryUtil.memAddress(this.backingBuffer.unwrap(), this.backingBuffer.position());
|
||||
this.writePointer = MemoryUtil.memAddress(this.backingBuffer, this.backingBuffer.position());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull;
|
|||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
|
@ -14,9 +15,12 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraftforge.client.event.RegisterClientCommandsEvent;
|
||||
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue;
|
||||
import net.minecraftforge.fml.ModList;
|
||||
|
@ -87,6 +91,25 @@ public class FlwCommands {
|
|||
}
|
||||
));
|
||||
|
||||
commandBuilder.command.then(Commands.literal("debugCrumble")
|
||||
.then(Commands.argument("pos", BlockPosArgument.blockPos())
|
||||
.then(Commands.argument("stage", IntegerArgumentType.integer(0, 9))
|
||||
.executes(context -> {
|
||||
BlockPos pos = BlockPosArgument.getLoadedBlockPos(context, "pos");
|
||||
int value = IntegerArgumentType.getInteger(context, "stage");
|
||||
|
||||
Entity executor = context.getSource()
|
||||
.getEntity();
|
||||
|
||||
if (executor == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
executor.level.destroyBlockProgress(executor.getId(), pos, value);
|
||||
|
||||
return 1;
|
||||
}))));
|
||||
|
||||
commandBuilder.build(event.getDispatcher());
|
||||
}
|
||||
|
||||
|
|
|
@ -6,16 +6,22 @@ import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.core.layout.CommonItems;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
|
||||
public class FullscreenQuad {
|
||||
|
||||
public static final Lazy<FullscreenQuad> INSTANCE = Lazy.of(FullscreenQuad::new);
|
||||
private static final BufferLayout LAYOUT = BufferLayout.builder()
|
||||
.addItems(CommonItems.VEC4)
|
||||
.build();
|
||||
|
||||
private static final float[] vertices = {
|
||||
// pos // tex
|
||||
|
@ -29,24 +35,25 @@ public class FullscreenQuad {
|
|||
private final GlBuffer vbo;
|
||||
|
||||
private FullscreenQuad() {
|
||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
vbo.bind();
|
||||
vbo.ensureCapacity(bufferSize);
|
||||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
buffer.putFloatArray(vertices);
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Could not create fullscreen quad.", e);
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
vbo.ensureCapacity(bufferSize);
|
||||
try (MappedBuffer buffer = vbo.map()) {
|
||||
|
||||
buffer.unwrap()
|
||||
.asFloatBuffer()
|
||||
.put(vertices);
|
||||
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Could not create fullscreen quad.", e);
|
||||
}
|
||||
|
||||
vao = new GlVertexArray();
|
||||
|
||||
vao.enableArrays(1);
|
||||
|
||||
vao.bindAttributes(vbo, 0, LAYOUT);
|
||||
}
|
||||
|
||||
vao = new GlVertexArray();
|
||||
vao.bind();
|
||||
|
||||
vao.enableArrays(1);
|
||||
|
||||
glVertexAttribPointer(0, 4, GlNumericType.FLOAT.getGlEnum(), false, 4 * 4, 0);
|
||||
|
||||
GlVertexArray.unbind();
|
||||
vbo.unbind();
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
|
|
|
@ -3,17 +3,14 @@ package com.jozufozu.flywheel.core;
|
|||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
|
@ -29,14 +26,12 @@ import net.minecraftforge.fml.common.Mod;
|
|||
@Mod.EventBusSubscriber(Dist.CLIENT)
|
||||
public class QuadConverter {
|
||||
|
||||
public static final int STARTING_CAPACITY = 42; // 255 / 6 = 42
|
||||
|
||||
private static QuadConverter INSTANCE;
|
||||
|
||||
@NotNull
|
||||
public static QuadConverter getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new QuadConverter(STARTING_CAPACITY);
|
||||
INSTANCE = new QuadConverter();
|
||||
}
|
||||
|
||||
return INSTANCE;
|
||||
|
@ -47,130 +42,80 @@ public class QuadConverter {
|
|||
return INSTANCE;
|
||||
}
|
||||
|
||||
Map<GlNumericType, GlBuffer> ebos;
|
||||
int[] capacities;
|
||||
private MappedGlBuffer ebo;
|
||||
private int quadCapacity;
|
||||
|
||||
public QuadConverter(int initialCapacity) {
|
||||
this.ebos = new EnumMap<>(GlNumericType.class);
|
||||
initCapacities();
|
||||
|
||||
fillBuffer(initialCapacity);
|
||||
public QuadConverter() {
|
||||
this.ebo = new MappedGlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER);
|
||||
this.quadCapacity = 0;
|
||||
}
|
||||
|
||||
public ElementBuffer quads2Tris(int quads) {
|
||||
int indexCount = quads * 6;
|
||||
GlNumericType type = getSmallestIndexType(indexCount);
|
||||
|
||||
if (quads > getCapacity(type)) {
|
||||
fillBuffer(quads, indexCount, type);
|
||||
if (quads > quadCapacity) {
|
||||
ebo.ensureCapacity((long) indexCount * GlNumericType.UINT.getByteWidth());
|
||||
|
||||
try (MappedBuffer map = ebo.map()) {
|
||||
ByteBuffer indices = map.unwrap();
|
||||
|
||||
fillBuffer(indices, quads);
|
||||
}
|
||||
ebo.unbind();
|
||||
|
||||
this.quadCapacity = quads;
|
||||
}
|
||||
|
||||
return new ElementBuffer(getBuffer(type), indexCount, type);
|
||||
}
|
||||
|
||||
private void initCapacities() {
|
||||
this.capacities = new int[GlNumericType.values().length];
|
||||
}
|
||||
|
||||
private int getCapacity(GlNumericType type) {
|
||||
return capacities[type.ordinal()];
|
||||
}
|
||||
|
||||
private void updateCapacity(GlNumericType type, int capacity) {
|
||||
if (getCapacity(type) < capacity) {
|
||||
capacities[type.ordinal()] = capacity;
|
||||
}
|
||||
return new ElementBuffer(ebo, indexCount, GlNumericType.UINT);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
ebos.values()
|
||||
.forEach(GlBuffer::delete);
|
||||
ebos.clear();
|
||||
initCapacities();
|
||||
ebo.delete();
|
||||
this.quadCapacity = 0;
|
||||
}
|
||||
|
||||
private void fillBuffer(int quads) {
|
||||
int indexCount = quads * 6;
|
||||
private void fillBuffer(ByteBuffer indices, int quads) {
|
||||
long addr = MemoryUtil.memAddress(indices);
|
||||
int numVertices = 4 * quads;
|
||||
int baseVertex = 0;
|
||||
while (baseVertex < numVertices) {
|
||||
// writeQuadIndices(indices, baseVertex);
|
||||
writeQuadIndicesUnsafe(addr, baseVertex);
|
||||
|
||||
fillBuffer(quads, indexCount, getSmallestIndexType(indexCount));
|
||||
}
|
||||
|
||||
private void fillBuffer(int quads, int indexCount, GlNumericType type) {
|
||||
MemoryStack stack = MemoryStack.stackPush();
|
||||
int bytes = indexCount * type.getByteWidth();
|
||||
|
||||
ByteBuffer indices;
|
||||
if (bytes > stack.getSize()) {
|
||||
indices = MemoryUtil.memAlloc(bytes); // not enough space on the preallocated stack
|
||||
} else {
|
||||
stack.push();
|
||||
indices = stack.malloc(bytes);
|
||||
baseVertex += 4;
|
||||
addr += 6 * 4;
|
||||
}
|
||||
|
||||
indices.order(ByteOrder.nativeOrder());
|
||||
|
||||
fillBuffer(indices, type, quads);
|
||||
|
||||
GlBuffer buffer = getBuffer(type);
|
||||
|
||||
buffer.bind();
|
||||
buffer.upload(indices);
|
||||
buffer.unbind();
|
||||
|
||||
if (bytes > stack.getSize()) {
|
||||
MemoryUtil.memFree(indices);
|
||||
} else {
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
updateCapacity(type, quads);
|
||||
// ((Buffer) indices).flip();
|
||||
}
|
||||
|
||||
private void fillBuffer(ByteBuffer indices, GlNumericType type, int quads) {
|
||||
for (int i = 0, max = 4 * quads; i < max; i += 4) {
|
||||
// triangle a
|
||||
type.castAndBuffer(indices, i);
|
||||
type.castAndBuffer(indices, i + 1);
|
||||
type.castAndBuffer(indices, i + 2);
|
||||
// triangle b
|
||||
type.castAndBuffer(indices, i);
|
||||
type.castAndBuffer(indices, i + 2);
|
||||
type.castAndBuffer(indices, i + 3);
|
||||
}
|
||||
((Buffer) indices).flip();
|
||||
private void writeQuadIndices(ByteBuffer indices, int baseVertex) {
|
||||
// triangle a
|
||||
indices.putInt(baseVertex);
|
||||
indices.putInt(baseVertex + 1);
|
||||
indices.putInt(baseVertex + 2);
|
||||
// triangle b
|
||||
indices.putInt(baseVertex);
|
||||
indices.putInt(baseVertex + 2);
|
||||
indices.putInt(baseVertex + 3);
|
||||
}
|
||||
|
||||
private GlBuffer getBuffer(GlNumericType type) {
|
||||
return ebos.computeIfAbsent(type, $ -> new MappedGlBuffer(GlBufferType.ELEMENT_ARRAY_BUFFER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the needed number of indices, what is the smallest bit width type that can index everything? <br>
|
||||
*
|
||||
* <pre>
|
||||
* | indexCount | type |
|
||||
* |--------------|-------|
|
||||
* | [0, 255) | byte |
|
||||
* | [256, 65536) | short |
|
||||
* | [65537, ) | int |
|
||||
* </pre>
|
||||
*/
|
||||
private static GlNumericType getSmallestIndexType(int indexCount) {
|
||||
// indexCount = indexCount >>> 8;
|
||||
// if (indexCount == 0) {
|
||||
// return GlNumericType.UBYTE;
|
||||
// }
|
||||
// indexCount = indexCount >>> 8;
|
||||
// if (indexCount == 0) {
|
||||
// return GlNumericType.USHORT;
|
||||
// }
|
||||
|
||||
return GlNumericType.UINT;
|
||||
private void writeQuadIndicesUnsafe(long addr, int baseVertex) {
|
||||
// triangle a
|
||||
MemoryUtil.memPutInt(addr, baseVertex);
|
||||
MemoryUtil.memPutInt(addr + 4, baseVertex + 1);
|
||||
MemoryUtil.memPutInt(addr + 8, baseVertex + 2);
|
||||
// triangle b
|
||||
MemoryUtil.memPutInt(addr + 12, baseVertex);
|
||||
MemoryUtil.memPutInt(addr + 16, baseVertex + 2);
|
||||
MemoryUtil.memPutInt(addr + 20, baseVertex + 3);
|
||||
}
|
||||
|
||||
// make sure this gets reset first so it has a chance to repopulate
|
||||
@SubscribeEvent(priority = EventPriority.HIGHEST)
|
||||
public static void onRendererReload(ReloadRenderersEvent event) {
|
||||
if (INSTANCE != null) INSTANCE.delete();
|
||||
if (INSTANCE != null) {
|
||||
INSTANCE.delete();
|
||||
INSTANCE = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
|||
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo.FogType;
|
||||
import com.jozufozu.flywheel.core.shader.ShaderConstants;
|
||||
import com.jozufozu.flywheel.core.shader.StateSnapshot;
|
||||
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
||||
import com.jozufozu.flywheel.core.source.FileIndex;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
|
||||
|
@ -33,7 +33,7 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
|
|||
shaderConstants.writeInto(finalSource);
|
||||
finalSource.append('\n');
|
||||
|
||||
FileIndexImpl index = new FileIndexImpl();
|
||||
FileIndex index = new FileIndex();
|
||||
|
||||
// MATERIAL
|
||||
|
||||
|
@ -49,7 +49,11 @@ public class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShade
|
|||
|
||||
finalSource.append(generateFooter());
|
||||
|
||||
return new GlShader(finalSource.toString(), ShaderType.FRAGMENT, ImmutableList.of(materialShader.name, contextShaderSource.name), shaderConstants);
|
||||
try {
|
||||
return new GlShader(finalSource.toString(), ShaderType.FRAGMENT, ImmutableList.of(materialShader.name, contextShaderSource.name), shaderConstants);
|
||||
} catch (ShaderCompilationException e) {
|
||||
throw e.withErrorLog(index);
|
||||
}
|
||||
}
|
||||
|
||||
protected String generateFooter() {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.FileIndex;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
|
||||
public class ShaderCompilationException extends ShaderLoadingException {
|
||||
|
||||
private final int shaderHandle;
|
||||
|
||||
private String errors = "";
|
||||
|
||||
public ShaderCompilationException(String message, int shaderHandle) {
|
||||
super(message);
|
||||
this.shaderHandle = shaderHandle;
|
||||
}
|
||||
|
||||
public ShaderLoadingException withErrorLog(FileIndex fileIndex) {
|
||||
if (this.shaderHandle == -1)
|
||||
return this;
|
||||
|
||||
this.errors = fileIndex.parseErrors(GL20.glGetShaderInfoLog(this.shaderHandle));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return super.getMessage() + '\n' + this.errors;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
|||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.core.shader.StateSnapshot;
|
||||
import com.jozufozu.flywheel.core.source.FileIndexImpl;
|
||||
import com.jozufozu.flywheel.core.source.FileIndex;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
||||
|
@ -34,7 +34,7 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
|
|||
shaderConstants.writeInto(finalSource);
|
||||
finalSource.append('\n');
|
||||
|
||||
var index = new FileIndexImpl();
|
||||
var index = new FileIndex();
|
||||
|
||||
// LAYOUT
|
||||
|
||||
|
@ -64,7 +64,11 @@ public class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
|
|||
.orElseThrow();
|
||||
finalSource.append(generateFooter(key.vertexType, instanceStruct));
|
||||
|
||||
return new GlShader(finalSource.toString(), ShaderType.VERTEX, ImmutableList.of(layoutShader.name, instanceShader.name, materialShader.name, contextShaderSource.name), shaderConstants);
|
||||
try {
|
||||
return new GlShader(finalSource.toString(), ShaderType.VERTEX, ImmutableList.of(layoutShader.name, instanceShader.name, materialShader.name, contextShaderSource.name), shaderConstants);
|
||||
} catch (ShaderCompilationException e) {
|
||||
throw e.withErrorLog(index);
|
||||
}
|
||||
}
|
||||
|
||||
protected String generateFooter(VertexType vertexType, ShaderStruct instance) {
|
||||
|
|
|
@ -61,20 +61,19 @@ public class CrumblingRenderer {
|
|||
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageBlockEntities(levelRenderer, level);
|
||||
if (activeStages.isEmpty()) return;
|
||||
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
|
||||
Matrix4f viewProjection = poseStack.last()
|
||||
.pose()
|
||||
.copy();
|
||||
viewProjection.multiplyBackward(projectionMatrix);
|
||||
Matrix4f viewProjection = poseStack.last()
|
||||
.pose()
|
||||
.copy();
|
||||
viewProjection.multiplyBackward(projectionMatrix);
|
||||
|
||||
State state = STATE.get();
|
||||
var instanceManager = state.instanceManager;
|
||||
var engine = state.instancerManager;
|
||||
State state = STATE.get();
|
||||
var instanceManager = state.instanceManager;
|
||||
var engine = state.instancerManager;
|
||||
|
||||
renderCrumblingInner(activeStages, instanceManager, engine, level, poseStack, camera, viewProjection);
|
||||
|
||||
restoreState.restore();
|
||||
renderCrumblingInner(activeStages, instanceManager, engine, level, poseStack, camera, viewProjection);
|
||||
}
|
||||
}
|
||||
|
||||
private static void renderCrumblingInner(Int2ObjectMap<List<BlockEntity>> activeStages, InstanceManager<BlockEntity> instanceManager, CrumblingEngine engine, ClientLevel level, PoseStack stack, Camera camera, Matrix4f viewProjection) {
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.jozufozu.flywheel.core.hardcoded;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.core.vertex.Formats;
|
||||
|
@ -26,12 +28,14 @@ public class ModelPart implements Mesh {
|
|||
this.vertices = vertices;
|
||||
}
|
||||
|
||||
PosTexNormalWriterUnsafe writer = getType().createWriter(MemoryTracker.create(size()));
|
||||
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
||||
cuboid.buffer(writer);
|
||||
}
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
PosTexNormalWriterUnsafe writer = getType().createWriter(stack.malloc(size()));
|
||||
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
||||
cuboid.buffer(writer);
|
||||
}
|
||||
|
||||
reader = writer.intoReader();
|
||||
reader = writer.intoReader();
|
||||
}
|
||||
}
|
||||
|
||||
public static PartBuilder builder(String name, int sizeU, int sizeV) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Random;
|
||||
|
||||
|
@ -10,6 +11,7 @@ import com.mojang.blaze3d.vertex.BufferBuilder;
|
|||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
@ -52,24 +54,17 @@ public class ModelUtil {
|
|||
return new WorldModelBuilder(layer);
|
||||
}
|
||||
|
||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(Bufferable object) {
|
||||
public static ShadeSeparatedBufferBuilder getBufferBuilder(Bufferable bufferable) {
|
||||
ModelBlockRenderer blockRenderer = VANILLA_RENDERER.getModelRenderer();
|
||||
ThreadLocalObjects objects = THREAD_LOCAL_OBJECTS.get();
|
||||
|
||||
ShadeSeparatedBufferBuilder builder = new ShadeSeparatedBufferBuilder(512);
|
||||
objects.begin();
|
||||
|
||||
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
objects.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
objects.shadeSeparatingWrapper.prepare(builder, objects.unshadedBuilder);
|
||||
bufferable.bufferInto(blockRenderer, objects.shadeSeparatingWrapper, objects.random);
|
||||
|
||||
object.bufferInto(blockRenderer, objects.shadeSeparatingWrapper, objects.random);
|
||||
objects.end();
|
||||
|
||||
objects.shadeSeparatingWrapper.clear();
|
||||
objects.unshadedBuilder.end();
|
||||
builder.appendUnshadedVertices(objects.unshadedBuilder);
|
||||
builder.end();
|
||||
|
||||
return builder;
|
||||
return objects.separatedBufferBuilder;
|
||||
}
|
||||
|
||||
private static PoseStack createRotation(Direction facing) {
|
||||
|
@ -96,7 +91,21 @@ public class ModelUtil {
|
|||
private static class ThreadLocalObjects {
|
||||
public final Random random = new Random();
|
||||
public final ShadeSeparatingVertexConsumer shadeSeparatingWrapper = new ShadeSeparatingVertexConsumer();
|
||||
public final ShadeSeparatedBufferBuilder separatedBufferBuilder = new ShadeSeparatedBufferBuilder(512);
|
||||
public final BufferBuilder unshadedBuilder = new BufferBuilder(512);
|
||||
|
||||
private void begin() {
|
||||
this.separatedBufferBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
this.unshadedBuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.BLOCK);
|
||||
this.shadeSeparatingWrapper.prepare(this.separatedBufferBuilder, this.unshadedBuilder);
|
||||
}
|
||||
|
||||
private void end() {
|
||||
this.shadeSeparatingWrapper.clear();
|
||||
this.unshadedBuilder.end();
|
||||
this.separatedBufferBuilder.appendUnshadedVertices(this.unshadedBuilder);
|
||||
this.separatedBufferBuilder.end();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +1,68 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
public interface FileIndex {
|
||||
public class FileIndex {
|
||||
public final List<SourceFile> files = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns an arbitrary file ID for use this compilation context, or generates one if missing.
|
||||
*
|
||||
* @param sourceFile The file to retrieve the ID for.
|
||||
* @return A file ID unique to the given sourceFile.
|
||||
*/
|
||||
int getFileID(SourceFile sourceFile);
|
||||
public int getFileID(SourceFile sourceFile) {
|
||||
int i = files.indexOf(sourceFile);
|
||||
if (i != -1) {
|
||||
return i;
|
||||
}
|
||||
|
||||
boolean exists(SourceFile sourceFile);
|
||||
int size = files.size();
|
||||
files.add(sourceFile);
|
||||
return size;
|
||||
}
|
||||
|
||||
SourceFile getFile(int fileID);
|
||||
public boolean exists(SourceFile sourceFile) {
|
||||
return files.contains(sourceFile);
|
||||
}
|
||||
|
||||
default Span getLineSpan(int fileId, int lineNo) {
|
||||
public SourceFile getFile(int fileId) {
|
||||
return files.get(fileId);
|
||||
}
|
||||
|
||||
public String parseErrors(String log) {
|
||||
List<String> lines = log.lines()
|
||||
.toList();
|
||||
|
||||
StringBuilder errors = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
ErrorBuilder builder = parseCompilerError(line);
|
||||
|
||||
if (builder != null) {
|
||||
errors.append(builder.build());
|
||||
} else {
|
||||
errors.append(line).append('\n');
|
||||
}
|
||||
}
|
||||
return errors.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ErrorBuilder parseCompilerError(String line) {
|
||||
try {
|
||||
return ErrorBuilder.fromLogLine(this, line);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Span getLineSpan(int fileId, int lineNo) {
|
||||
return getFile(fileId).getLineSpanNoWhitespace(lineNo);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FileIndexImpl implements FileIndex {
|
||||
public final List<SourceFile> files = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Returns an arbitrary file ID for use this compilation context, or generates one if missing.
|
||||
* @param sourceFile The file to retrieve the ID for.
|
||||
* @return A file ID unique to the given sourceFile.
|
||||
*/
|
||||
@Override
|
||||
public int getFileID(SourceFile sourceFile) {
|
||||
int i = files.indexOf(sourceFile);
|
||||
if (i != -1) {
|
||||
return i;
|
||||
}
|
||||
|
||||
int size = files.size();
|
||||
files.add(sourceFile);
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(SourceFile sourceFile) {
|
||||
return files.contains(sourceFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceFile getFile(int fileId) {
|
||||
return files.get(fileId);
|
||||
}
|
||||
|
||||
public void printShaderInfoLog(String source, String log, ResourceLocation name) {
|
||||
List<String> lines = log.lines()
|
||||
.toList();
|
||||
|
||||
boolean needsSourceDump = false;
|
||||
|
||||
StringBuilder errors = new StringBuilder();
|
||||
for (String line : lines) {
|
||||
ErrorBuilder builder = parseCompilerError(line);
|
||||
|
||||
if (builder != null) {
|
||||
errors.append(builder.build());
|
||||
} else {
|
||||
errors.append(line).append('\n');
|
||||
needsSourceDump = true;
|
||||
}
|
||||
}
|
||||
Backend.LOGGER.error("Errors compiling '" + name + "': \n" + errors);
|
||||
if (needsSourceDump) {
|
||||
// TODO: generated code gets its own "file"
|
||||
ErrorReporter.printLines(source);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ErrorBuilder parseCompilerError(String line) {
|
||||
try {
|
||||
return ErrorBuilder.fromLogLine(this, line);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
package com.jozufozu.flywheel.core.structs;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.backend.struct.UnsafeBufferWriter;
|
||||
|
||||
public abstract class BasicWriterUnsafe<D extends BasicData> extends UnsafeBufferWriter<D> {
|
||||
|
||||
public BasicWriterUnsafe(VecBuffer backingBuffer, StructType<D> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
public BasicWriterUnsafe(StructType<D> structType, ByteBuffer byteBuffer) {
|
||||
super(structType, byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package com.jozufozu.flywheel.core.structs.model;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.BatchedStructType;
|
||||
import com.jozufozu.flywheel.api.struct.InstancedStructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.core.layout.CommonItems;
|
||||
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
||||
|
@ -28,8 +29,8 @@ public class ModelType implements InstancedStructType<ModelData>, BatchedStructT
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructWriter<ModelData> getWriter(VecBuffer backing) {
|
||||
return new ModelWriterUnsafe(backing, this);
|
||||
public StructWriter<ModelData> getWriter(ByteBuffer backing) {
|
||||
return new ModelWriterUnsafe(this, backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package com.jozufozu.flywheel.core.structs.model;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.core.structs.BasicWriterUnsafe;
|
||||
import com.jozufozu.flywheel.util.MatrixWrite;
|
||||
|
||||
public class ModelWriterUnsafe extends BasicWriterUnsafe<ModelData> {
|
||||
|
||||
public ModelWriterUnsafe(VecBuffer backingBuffer, StructType<ModelData> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
public ModelWriterUnsafe(StructType<ModelData> structType, ByteBuffer byteBuffer) {
|
||||
super(structType, byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package com.jozufozu.flywheel.core.structs.oriented;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.BatchedStructType;
|
||||
import com.jozufozu.flywheel.api.struct.InstancedStructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.core.layout.CommonItems;
|
||||
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
||||
|
@ -29,8 +30,8 @@ public class OrientedType implements InstancedStructType<OrientedData>, BatchedS
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructWriter<OrientedData> getWriter(VecBuffer backing) {
|
||||
return new OrientedWriterUnsafe(backing, this);
|
||||
public StructWriter<OrientedData> getWriter(ByteBuffer backing) {
|
||||
return new OrientedWriterUnsafe(this, backing);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
package com.jozufozu.flywheel.core.structs.oriented;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.core.structs.BasicWriterUnsafe;
|
||||
|
||||
public class OrientedWriterUnsafe extends BasicWriterUnsafe<OrientedData> {
|
||||
public OrientedWriterUnsafe(VecBuffer backingBuffer, StructType<OrientedData> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
public OrientedWriterUnsafe(StructType<OrientedData> structType, ByteBuffer byteBuffer) {
|
||||
super(structType, byteBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,35 +1,24 @@
|
|||
package com.jozufozu.flywheel.core.vertex;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
|
||||
public class BlockVertexListUnsafe implements VertexList {
|
||||
|
||||
private final ByteBuffer buffer;
|
||||
private final int vertexCount;
|
||||
private final long base;
|
||||
public class BlockVertexListUnsafe extends TrackedVertexList {
|
||||
|
||||
public BlockVertexListUnsafe(ByteBuffer buffer, int vertexCount) {
|
||||
this.buffer = buffer;
|
||||
this.base = MemoryUtil.memAddress(buffer);
|
||||
this.vertexCount = vertexCount;
|
||||
super(buffer, vertexCount);
|
||||
}
|
||||
|
||||
private long ptr(long index) {
|
||||
return base + index * 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return vertexCount == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getX(int index) {
|
||||
return MemoryUtil.memGetFloat(ptr(index));
|
||||
|
@ -95,11 +84,6 @@ public class BlockVertexListUnsafe implements VertexList {
|
|||
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 30));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getVertexType() {
|
||||
return Formats.BLOCK;
|
||||
|
|
|
@ -1,23 +1,20 @@
|
|||
package com.jozufozu.flywheel.core.vertex;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.FlywheelMemory;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||
|
||||
public class PosTexNormalVertexListUnsafe implements VertexList {
|
||||
|
||||
private final ByteBuffer buffer;
|
||||
private final int vertexCount;
|
||||
private final long base;
|
||||
public class PosTexNormalVertexListUnsafe extends TrackedVertexList {
|
||||
|
||||
public PosTexNormalVertexListUnsafe(ByteBuffer buffer, int vertexCount) {
|
||||
this.buffer = buffer;
|
||||
this.vertexCount = vertexCount;
|
||||
this.base = MemoryUtil.memAddress(buffer);
|
||||
super(buffer, vertexCount);
|
||||
}
|
||||
|
||||
private long ptr(long idx) {
|
||||
|
@ -89,11 +86,6 @@ public class PosTexNormalVertexListUnsafe implements VertexList {
|
|||
return RenderMath.f(MemoryUtil.memGetByte(ptr(index) + 22));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getVertexType() {
|
||||
return Formats.POS_TEX_NORMAL;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package com.jozufozu.flywheel.core.vertex;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.backend.FlywheelMemory;
|
||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||
|
||||
public abstract class TrackedVertexList implements VertexList, AutoCloseable {
|
||||
|
||||
protected final ByteBuffer contents;
|
||||
protected final long base;
|
||||
protected final int vertexCount;
|
||||
private final Cleaner.Cleanable cleanable;
|
||||
|
||||
protected TrackedVertexList(ByteBuffer copyFrom, int vertexCount) {
|
||||
this.contents = MemoryTracker.create(copyFrom.capacity());
|
||||
this.contents.order(copyFrom.order());
|
||||
this.contents.put(copyFrom);
|
||||
((Buffer) this.contents).flip();
|
||||
|
||||
this.cleanable = FlywheelMemory.track(this, this.contents);
|
||||
|
||||
this.base = MemoryUtil.memAddress(this.contents);
|
||||
this.vertexCount = vertexCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
cleanable.clean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
package com.jozufozu.flywheel.event;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.FlywheelMemory;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.light.LightUpdater;
|
||||
import com.jozufozu.flywheel.util.WorldAttached;
|
||||
|
@ -21,7 +25,15 @@ public class ForgeEvents {
|
|||
|
||||
if (Minecraft.getInstance().options.renderDebug) {
|
||||
|
||||
InstancedRenderDispatcher.getDebugString(event.getRight());
|
||||
ArrayList<String> debug = event.getRight();
|
||||
debug.add("");
|
||||
debug.add("Flywheel: " + Flywheel.getVersion());
|
||||
|
||||
InstancedRenderDispatcher.getDebugString(debug);
|
||||
|
||||
debug.add("Memory used:");
|
||||
debug.add("GPU: " + FlywheelMemory.getGPUMemory());
|
||||
debug.add("CPU: " + FlywheelMemory.getCPUMemory());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ public class FrustumMixin {
|
|||
@Inject(method = "prepare", at = @At("TAIL"))
|
||||
private void onPrepare(double x, double y, double z, CallbackInfo ci) {
|
||||
if (OptifineHandler.isShadowPass()) {
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(Minecraft.getInstance().level, LastActiveCamera.getActiveCamera(), (Frustum) (Object) this));
|
||||
restoreState.restore();
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(Minecraft.getInstance().level, LastActiveCamera.getActiveCamera(), (Frustum) (Object) this));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,20 +46,19 @@ public class LevelRendererMixin {
|
|||
Vec3 position = pCamera.getPosition();
|
||||
RenderContext.CURRENT = new RenderContext(level, pPoseStack, RenderLayerEvent.createViewProjection(pPoseStack), renderBuffers, position.x, position.y, position.z);
|
||||
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(level, pCamera, null));
|
||||
restoreState.restore();
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(level, pCamera, null));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "renderChunkLayer")
|
||||
private void renderChunkLayer(RenderType pRenderType, PoseStack pPoseStack, double pCamX, double pCamY, double pCamZ, Matrix4f pProjectionMatrix, CallbackInfo ci) {
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
|
||||
// TODO: Is this necessary?
|
||||
InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, pRenderType);
|
||||
MinecraftForge.EVENT_BUS.post(new RenderLayerEvent(RenderContext.CURRENT, pRenderType));
|
||||
|
||||
restoreState.restore();
|
||||
// TODO: Is this necessary?
|
||||
InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, pRenderType);
|
||||
MinecraftForge.EVENT_BUS.post(new RenderLayerEvent(RenderContext.CURRENT, pRenderType));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "renderLevel")
|
||||
|
|
|
@ -19,22 +19,20 @@ public class MultiBufferSourceMixin {
|
|||
@Inject(method = "endBatch(Lnet/minecraft/client/renderer/RenderType;)V", at = @At("TAIL"))
|
||||
private void renderLayer(RenderType renderType, CallbackInfo ci) {
|
||||
if (RenderContext.CURRENT != null && Backend.isGameActive() && Backend.isOn()) {
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
|
||||
InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, renderType);
|
||||
InstancedRenderDispatcher.renderSpecificType(RenderContext.CURRENT, renderType);
|
||||
|
||||
restoreState.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "endBatch()V", at = @At("TAIL"))
|
||||
private void endBatch(CallbackInfo ci) {
|
||||
if (RenderContext.CURRENT != null && Backend.isGameActive() && Backend.isOn()) {
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
|
||||
InstancedRenderDispatcher.renderAllRemaining(RenderContext.CURRENT);
|
||||
|
||||
restoreState.restore();
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
InstancedRenderDispatcher.renderAllRemaining(RenderContext.CURRENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package com.jozufozu.flywheel.mixin.matrix;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.util.MatrixWrite;
|
||||
import com.mojang.math.Matrix3f;
|
||||
|
||||
|
@ -35,7 +36,7 @@ public abstract class Matrix3fMixin implements MatrixWrite {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void flywheel$write(VecBuffer buffer) {
|
||||
public void flywheel$write(ByteBuffer buffer) {
|
||||
buffer.putFloat(m00);
|
||||
buffer.putFloat(m10);
|
||||
buffer.putFloat(m20);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package com.jozufozu.flywheel.mixin.matrix;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.util.MatrixWrite;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
|
@ -49,7 +50,7 @@ public abstract class Matrix4fMixin implements MatrixWrite {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void flywheel$write(VecBuffer buf) {
|
||||
public void flywheel$write(ByteBuffer buf) {
|
||||
buf.putFloat(m00);
|
||||
buf.putFloat(m10);
|
||||
buf.putFloat(m20);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* @see com.jozufozu.flywheel.mixin.matrix.Matrix3fMixin
|
||||
|
@ -13,5 +13,5 @@ public interface MatrixWrite {
|
|||
*/
|
||||
void flywheel$writeUnsafe(long ptr);
|
||||
|
||||
void flywheel$write(VecBuffer buf);
|
||||
void flywheel$write(ByteBuffer buf);
|
||||
}
|
||||
|
|
|
@ -12,9 +12,10 @@ vec2 flattenedPos(vec3 pos, vec3 normal) {
|
|||
pos -= floor(pos) + vec3(0.5);
|
||||
|
||||
float sinYRot = -normal.x;
|
||||
float sqLength = normal.x * normal.x + normal.z * normal.z;
|
||||
vec2 XZ = normal.xz;
|
||||
float sqLength = dot(XZ, XZ);
|
||||
if (sqLength > 0) {
|
||||
sinYRot /= sqrt(sqLength);
|
||||
sinYRot *= inversesqrt(sqLength);
|
||||
sinYRot = clamp(sinYRot, -1, 1);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue