Merge remote-tracking branch 'origin/1.18/dev' into 1.18/fabric/dev

Conflicts:
	build.gradle
	gradle.properties
	src/main/java/com/jozufozu/flywheel/core/QuadConverter.java
	src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingRenderer.java
	src/main/java/com/jozufozu/flywheel/core/vertex/BlockVertexList.java
	src/main/java/com/jozufozu/flywheel/event/ForgeEvents.java
	src/main/java/com/jozufozu/flywheel/mixin/ChunkRebuildHooksMixin.java
	src/main/java/com/jozufozu/flywheel/mixin/InstanceAddMixin.java
	src/main/java/com/jozufozu/flywheel/mixin/LevelRendererMixin.java
This commit is contained in:
PepperCode1 2022-11-10 18:05:46 -08:00
commit 7c757fee80
38 changed files with 318 additions and 341 deletions

View file

@ -13,6 +13,17 @@ insert_final_newline = true
[*.json] [*.json]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2
max_line_length = 500
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = true
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false
[*.java] [*.java]
indent_style = tab indent_style = tab

View file

@ -59,6 +59,10 @@ body:
label: Mod Version label: Mod Version
description: The version of the mod you were using when the bug occured description: The version of the mod you were using when the bug occured
options: options:
- "0.6.8"
- "0.6.7"
- "0.6.6"
- "0.6.5"
- "0.6.4" - "0.6.4"
- "0.6.3" - "0.6.3"
- "0.6.2" - "0.6.2"
@ -77,6 +81,8 @@ body:
label: Minecraft Version label: Minecraft Version
description: The version of Minecraft you were using when the bug occured description: The version of Minecraft you were using when the bug occured
options: options:
- "1.19.2"
- "1.18.2"
- "1.18.1" - "1.18.1"
- "1.17.1" - "1.17.1"
validations: validations:

View file

@ -71,6 +71,14 @@ dependencies {
modCompileOnly 'io.vram:frex-fabric-mc118:6.0.263' modCompileOnly 'io.vram:frex-fabric-mc118:6.0.263'
} }
loom {
runs {
client {
property('flw.loadRenderDoc', 'true')
}
}
}
processResources { processResources {
inputs.property 'version', project.version inputs.property 'version', project.version

View file

@ -2,7 +2,7 @@ org.gradle.jvmargs = -Xmx3G
org.gradle.daemon = false org.gradle.daemon = false
# mod version info # mod version info
mod_version = 0.6.4 mod_version = 0.6.8
artifact_minecraft_version = 1.18.2 artifact_minecraft_version = 1.18.2
minecraft_version = 1.18.2 minecraft_version = 1.18.2
@ -12,7 +12,7 @@ fabric_version = 0.56.1+1.18.2
# build dependency versions # build dependency versions
loom_version = 0.12-SNAPSHOT loom_version = 0.12-SNAPSHOT
cursegradle_version = 1.4.0 cursegradle_version = 1.4.0
parchment_version = 2022.07.10 parchment_version = 2022.11.06
# curseforge info # curseforge info
projectId = 486392 projectId = 486392

View file

@ -7,13 +7,12 @@ import com.mojang.blaze3d.platform.GlStateManager;
* Tracks bound buffers/vbos because GlStateManager doesn't do that for us. * Tracks bound buffers/vbos because GlStateManager doesn't do that for us.
*/ */
public class GlStateTracker { public class GlStateTracker {
private static final int[] BUFFERS = new int[GlBufferType.values().length];
private static final int[] buffers = new int[GlBufferType.values().length];
private static int vao; private static int vao;
private static int program; private static int program;
public static int getBuffer(GlBufferType type) { public static int getBuffer(GlBufferType type) {
return buffers[type.ordinal()]; return BUFFERS[type.ordinal()];
} }
public static int getVertexArray() { public static int getVertexArray() {
@ -24,36 +23,36 @@ public class GlStateTracker {
return program; return program;
} }
public static void _setBuffer(GlBufferType type, int buffer) { public static void _setBuffer(GlBufferType type, int id) {
buffers[type.ordinal()] = buffer; BUFFERS[type.ordinal()] = id;
}
public static void _setProgram(int id) {
program = id;
} }
public static void _setVertexArray(int id) { public static void _setVertexArray(int id) {
vao = id; vao = id;
} }
public static State getRestoreState() { public static void _setProgram(int id) {
return new State(buffers.clone(), vao, program); program = id;
} }
public static record State(int[] buffers, int vao, int program) { public static State getRestoreState() {
return new State(BUFFERS.clone(), vao, program);
}
public record State(int[] buffers, int vao, int program) {
public void restore() { public void restore() {
if (vao != GlStateTracker.vao) {
GlStateManager._glBindVertexArray(vao);
}
GlBufferType[] values = GlBufferType.values(); GlBufferType[] values = GlBufferType.values();
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
if (buffers[i] != GlStateTracker.buffers[i]) { if (buffers[i] != GlStateTracker.BUFFERS[i] && values[i] != GlBufferType.ELEMENT_ARRAY_BUFFER) {
GlStateManager._glBindBuffer(values[i].glEnum, buffers[i]); GlStateManager._glBindBuffer(values[i].glEnum, buffers[i]);
} }
} }
if (vao != GlStateTracker.vao) {
GlStateManager._glBindVertexArray(vao);
}
if (program != GlStateTracker.program) { if (program != GlStateTracker.program) {
GlStateManager._glUseProgram(program); GlStateManager._glUseProgram(program);
} }

View file

@ -39,7 +39,7 @@ public class MappedBuffer extends VecBuffer implements AutoCloseable {
} }
@Override @Override
public void close() throws Exception { public void close() {
flush(); flush();
} }
} }

View file

@ -2,6 +2,8 @@ package com.jozufozu.flywheel.backend.instancing;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.jetbrains.annotations.ApiStatus;
import com.jozufozu.flywheel.backend.model.BufferBuilderExtension; import com.jozufozu.flywheel.backend.model.BufferBuilderExtension;
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer; import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
import com.mojang.blaze3d.platform.MemoryTracker; import com.mojang.blaze3d.platform.MemoryTracker;
@ -20,6 +22,7 @@ public class DrawBuffer {
private ByteBuffer backingBuffer; private ByteBuffer backingBuffer;
private int expectedVertices; private int expectedVertices;
@ApiStatus.Internal
public DrawBuffer(RenderType parent) { public DrawBuffer(RenderType parent) {
this.parent = parent; this.parent = parent;
} }
@ -39,7 +42,10 @@ public class DrawBuffer {
VertexFormat format = parent.format(); VertexFormat format = parent.format();
int byteSize = format.getVertexSize() * vertexCount; // Add one extra vertex to uphold the vanilla assumption that BufferBuilders have at least
// enough buffer space for one more vertex. Rubidium checks for this extra space when popNextBuffer
// is called and reallocates the buffer if there is not space for one more vertex.
int byteSize = format.getVertexSize() * (vertexCount + 1);
if (backingBuffer == null) { if (backingBuffer == null) {
backingBuffer = MemoryTracker.create(byteSize); backingBuffer = MemoryTracker.create(byteSize);

View file

@ -1,6 +1,7 @@
package com.jozufozu.flywheel.backend.instancing; package com.jozufozu.flywheel.backend.instancing;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -359,4 +360,14 @@ public abstract class InstanceManager<T> implements InstancingEngine.OriginShift
LightUpdater.get(value.world).removeListener(value); LightUpdater.get(value.world).removeListener(value);
} }
} }
public void queueAddAll(Collection<? extends T> objects) {
if (!Backend.isOn() || objects.isEmpty()) {
return;
}
synchronized (queuedAdditions) {
queuedAdditions.addAll(objects);
}
}
} }

View file

@ -6,9 +6,7 @@ import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
public class EntityInstanceManager extends InstanceManager<Entity> { public class EntityInstanceManager extends InstanceManager<Entity> {
@ -29,18 +27,13 @@ public class EntityInstanceManager extends InstanceManager<Entity> {
@Override @Override
protected boolean canCreateInstance(Entity entity) { protected boolean canCreateInstance(Entity entity) {
if (!entity.isAlive()) return false; if (!entity.isAlive()) {
return false;
}
Level world = entity.level; Level world = entity.level;
if (Backend.isFlywheelWorld(world)) { return Backend.isFlywheelWorld(world);
BlockPos pos = entity.blockPosition();
BlockGetter existingChunk = world.getChunkForCollisions(pos.getX() >> 4, pos.getZ() >> 4);
return existingChunk != null;
}
return false;
} }
} }

View file

@ -45,6 +45,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
public void render() { public void render() {
if (invalid()) return; if (invalid()) return;
// XXX VAO is bound and not reset or restored
vao.bind(); vao.bind();
renderSetup(); renderSetup();
@ -69,11 +70,13 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
vao = new GlVertexArray(); vao = new GlVertexArray();
model = modelAllocator.alloc(modelData, arenaModel -> { model = modelAllocator.alloc(modelData, arenaModel -> {
// XXX VAO is bound and not reset or restored
vao.bind(); vao.bind();
arenaModel.setupState(vao); arenaModel.setupState(vao);
}); });
// XXX VAO is bound and not reset or restored
vao.bind(); vao.bind();
vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount()); vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
@ -108,6 +111,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
removeDeletedInstances(); removeDeletedInstances();
} }
// XXX ARRAY_BUFFER is bound and reset
instanceVBO.bind(); instanceVBO.bind();
if (!realloc()) { if (!realloc()) {

View file

@ -68,15 +68,23 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
return vertexCount; return vertexCount;
} }
// XXX Overriden in CrumblingGroup
// XXX Runs inside of restore state
public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
type.setupRenderState(); type.setupRenderState();
Textures.bindActiveTextures(); Textures.bindActiveTextures(); // XXX Changes active unit and bound textures
renderAll(viewProjection, camX, camY, camZ, layer); renderAll(viewProjection, camX, camY, camZ, layer); // XXX May change ARRAY_BUFFER binding (reset or not reset), VAO binding (not reset), shader binding (not reset), call Model.createEBO
type.clearRenderState(); type.clearRenderState();
// XXX Should texture bindings be reset or restored?
// XXX Should the active unit be reset or restored?
// XXX Should the VAO binding be reset or restored?
// XXX Should the ARRAY_BUFFER binding be reset or restored?
// XXX Should the shader binding be reset or restored?
} }
// XXX Internal GL state changes are inconsistent; sometimes bindings are reset to 0, sometimes not
protected void renderAll(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { protected void renderAll(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
initializeInstancers(); initializeInstancers(); // XXX May change ARRAY_BUFFER binding (reset or not reset), VAO binding (not reset), call Model.createEBO
vertexCount = 0; vertexCount = 0;
instanceCount = 0; instanceCount = 0;
@ -88,6 +96,7 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
P program = owner.context.getProgram(ProgramContext.create(entry.getKey() P program = owner.context.getProgram(ProgramContext.create(entry.getKey()
.getProgramSpec(), Formats.POS_TEX_NORMAL, layer)); .getProgramSpec(), Formats.POS_TEX_NORMAL, layer));
// XXX Shader is bound and not reset or restored
program.bind(); program.bind();
program.uploadViewProjection(viewProjection); program.uploadViewProjection(viewProjection);
program.uploadCameraPos(camX, camY, camZ); program.uploadCameraPos(camX, camY, camZ);
@ -95,7 +104,7 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
setup(program); setup(program);
for (GPUInstancer<?> instancer : material.getAllInstancers()) { for (GPUInstancer<?> instancer : material.getAllInstancers()) {
instancer.render(); instancer.render(); // XXX May change VAO binding (not reset), ARRAY_BUFFER binding (reset)
vertexCount += instancer.getVertexCount(); vertexCount += instancer.getVertexCount();
instanceCount += instancer.getInstanceCount(); instanceCount += instancer.getInstanceCount();
} }
@ -103,19 +112,19 @@ public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialG
} }
private void initializeInstancers() { private void initializeInstancers() {
ModelAllocator allocator = getModelAllocator(); ModelAllocator allocator = getModelAllocator(); // XXX May change ARRAY_BUFFER binding (not reset)
// initialize all uninitialized instancers... // initialize all uninitialized instancers...
for (InstancedMaterial<?> material : materials.values()) { for (InstancedMaterial<?> material : materials.values()) {
for (GPUInstancer<?> instancer : material.uninitialized) { for (GPUInstancer<?> instancer : material.uninitialized) {
instancer.init(allocator); instancer.init(allocator); // XXX May change VAO binding (not reset), ARRAY_BUFFER binding (not reset), call Model.createEBO
} }
material.uninitialized.clear(); material.uninitialized.clear();
} }
if (allocator instanceof ModelPool pool) { if (allocator instanceof ModelPool pool) {
// ...and then flush the model arena in case anything was marked for upload // ...and then flush the model arena in case anything was marked for upload
pool.flush(); pool.flush(); // XXX May change ARRAY_BUFFER binding (reset)
} }
} }

View file

@ -10,6 +10,7 @@ import javax.annotation.Nullable;
import com.jozufozu.flywheel.api.MaterialGroup; import com.jozufozu.flywheel.api.MaterialGroup;
import com.jozufozu.flywheel.backend.RenderLayer; import com.jozufozu.flywheel.backend.RenderLayer;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.instancing.Engine; import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.TaskEngine; import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.core.compile.ProgramCompiler; import com.jozufozu.flywheel.core.compile.ProgramCompiler;
@ -74,6 +75,9 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
*/ */
@Override @Override
public void render(TaskEngine taskEngine, RenderLayerEvent event) { public void render(TaskEngine taskEngine, RenderLayerEvent event) {
// XXX Restore state
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
double camX; double camX;
double camY; double camY;
double camZ; double camZ;
@ -93,6 +97,8 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
} }
getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ, event.getLayer())); getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ, event.getLayer()));
restoreState.restore();
} }
private Stream<InstancedMaterialGroup<P>> getGroupsToRender(@Nullable RenderLayer layer) { private Stream<InstancedMaterialGroup<P>> getGroupsToRender(@Nullable RenderLayer layer) {

View file

@ -1,25 +1,29 @@
package com.jozufozu.flywheel.backend.model; package com.jozufozu.flywheel.backend.model;
import com.jozufozu.flywheel.backend.gl.GlNumericType; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer; import com.mojang.blaze3d.vertex.VertexFormat;
public class ElementBuffer { public class ElementBuffer {
private final GlBuffer buffer; protected final int elementCount;
public final int elementCount; protected final VertexFormat.IndexType eboIndexType;
public final GlNumericType eboIndexType; private final int glBuffer;
public ElementBuffer(GlBuffer backing, int elementCount, GlNumericType indexType) { public ElementBuffer(int backing, int elementCount, VertexFormat.IndexType indexType) {
this.buffer = backing;
this.eboIndexType = indexType;
this.elementCount = elementCount; this.elementCount = elementCount;
this.eboIndexType = indexType;
this.glBuffer = backing;
} }
public void bind() { public void bind() {
buffer.bind(); GlBufferType.ELEMENT_ARRAY_BUFFER.bind(glBuffer);
} }
public void unbind() { public int getElementCount() {
buffer.unbind(); return elementCount;
}
public VertexFormat.IndexType getEboIndexType() {
return eboIndexType;
} }
} }

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.backend.model; package com.jozufozu.flywheel.backend.model;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.core.model.Model;
public enum FallbackAllocator implements ModelAllocator { public enum FallbackAllocator implements ModelAllocator {
@ -7,7 +8,7 @@ public enum FallbackAllocator implements ModelAllocator {
@Override @Override
public BufferedModel alloc(Model model, Callback allocationCallback) { public BufferedModel alloc(Model model, Callback allocationCallback) {
IndexedModel out = new IndexedModel(model); IndexedModel out = new IndexedModel(model, Formats.POS_TEX_NORMAL);
allocationCallback.onAlloc(out); allocationCallback.onAlloc(out);
return out; return out;
} }

View file

@ -20,6 +20,7 @@ import com.jozufozu.flywheel.core.model.Model;
*/ */
public class IndexedModel implements BufferedModel { public class IndexedModel implements BufferedModel {
protected final VertexType type;
protected final Model model; protected final Model model;
protected final GlPrimitive primitiveMode; protected final GlPrimitive primitiveMode;
protected ElementBuffer ebo; protected ElementBuffer ebo;
@ -27,6 +28,11 @@ public class IndexedModel implements BufferedModel {
protected boolean deleted; protected boolean deleted;
public IndexedModel(Model model) { public IndexedModel(Model model) {
this(model, model.getType());
}
public IndexedModel(Model model, VertexType type) {
this.type = type;
this.model = model; this.model = model;
this.primitiveMode = GlPrimitive.TRIANGLES; this.primitiveMode = GlPrimitive.TRIANGLES;
@ -38,7 +44,8 @@ public class IndexedModel implements BufferedModel {
// mirror it in system memory, so we can write to it, and upload our model. // mirror it in system memory, so we can write to it, and upload our model.
try (MappedBuffer buffer = vbo.getBuffer()) { try (MappedBuffer buffer = vbo.getBuffer()) {
model.writeInto(buffer.unwrap()); type.createWriter(buffer.unwrap())
.writeVertexList(model.getReader());
} catch (Exception e) { } catch (Exception e) {
Flywheel.LOGGER.error(String.format("Error uploading model '%s':", model.name()), e); Flywheel.LOGGER.error(String.format("Error uploading model '%s':", model.name()), e);
} }
@ -52,15 +59,16 @@ public class IndexedModel implements BufferedModel {
* The VBO/VAO should be bound externally. * The VBO/VAO should be bound externally.
*/ */
public void setupState(GlVertexArray vao) { public void setupState(GlVertexArray vao) {
// XXX ARRAY_BUFFER is bound and not reset or restored
vbo.bind(); vbo.bind();
vao.enableArrays(getAttributeCount()); vao.enableArrays(getAttributeCount());
vao.bindAttributes(0, getType().getLayout()); vao.bindAttributes(0, getType().getLayout());
ebo.bind();
} }
@Override @Override
public void drawCall() { public void drawCall() {
ebo.bind(); GL20.glDrawElements(primitiveMode.glEnum, ebo.getElementCount(), ebo.getEboIndexType().asGLType, 0);
GL20.glDrawElements(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0);
} }
/** /**
@ -70,9 +78,7 @@ public class IndexedModel implements BufferedModel {
public void drawInstances(int instanceCount) { public void drawInstances(int instanceCount) {
if (!valid()) return; if (!valid()) return;
ebo.bind(); GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.getElementCount(), ebo.getEboIndexType().asGLType, 0, instanceCount);
GL31.glDrawElementsInstanced(primitiveMode.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, instanceCount);
} }
public boolean isDeleted() { public boolean isDeleted() {
@ -81,7 +87,7 @@ public class IndexedModel implements BufferedModel {
@Override @Override
public VertexType getType() { public VertexType getType() {
return model.getType(); return type;
} }
public int getVertexCount() { public int getVertexCount() {

View file

@ -42,6 +42,7 @@ public class ModelPool implements ModelAllocator {
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER); vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
// XXX ARRAY_BUFFER is bound and not reset or restored
vbo.bind(); vbo.bind();
vbo.setGrowthMargin(stride * 64); vbo.setGrowthMargin(stride * 64);
} }
@ -68,6 +69,7 @@ public class ModelPool implements ModelAllocator {
if (dirty) { if (dirty) {
if (anyToRemove) processDeletions(); if (anyToRemove) processDeletions();
// XXX ARRAY_BUFFER is bound and reset
vbo.bind(); vbo.bind();
if (realloc()) { if (realloc()) {
uploadAll(); uploadAll();
@ -182,25 +184,25 @@ public class ModelPool implements ModelAllocator {
@Override @Override
public void setupState(GlVertexArray vao) { public void setupState(GlVertexArray vao) {
// XXX ARRAY_BUFFER is bound and not reset or restored
vbo.bind(); vbo.bind();
vao.enableArrays(getAttributeCount()); vao.enableArrays(getAttributeCount());
vao.bindAttributes(0, vertexType.getLayout()); vao.bindAttributes(0, vertexType.getLayout());
ebo.bind();
} }
@Override @Override
public void drawCall() { public void drawCall() {
GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.elementCount, ebo.eboIndexType.getGlEnum(), 0, first); GL32.glDrawElementsBaseVertex(GlPrimitive.TRIANGLES.glEnum, ebo.getElementCount(), ebo.getEboIndexType().asGLType, 0, first);
} }
@Override @Override
public void drawInstances(int instanceCount) { public void drawInstances(int instanceCount) {
if (!valid()) return; if (!valid()) return;
ebo.bind();
//Backend.log.info(StringUtil.args("drawElementsInstancedBaseVertex", GlPrimitive.TRIANGLES, ebo.elementCount, ebo.eboIndexType, 0, instanceCount, first)); //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, ebo.getElementCount(), ebo.getEboIndexType().asGLType, 0, instanceCount, first);
} }
@Override @Override

View file

@ -58,6 +58,7 @@ public class VBOModel implements BufferedModel {
* The VBO/VAO should be bound externally. * The VBO/VAO should be bound externally.
*/ */
public void setupState(GlVertexArray vao) { public void setupState(GlVertexArray vao) {
// XXX ARRAY_BUFFER is bound and not reset or restored
vbo.bind(); vbo.bind();
vao.enableArrays(getAttributeCount()); vao.enableArrays(getAttributeCount());
vao.bindAttributes(0, getLayout()); vao.bindAttributes(0, getLayout());

View file

@ -35,7 +35,7 @@ public class FlwConfig {
protected final Map<String, Option<?>> optionMapView = Collections.unmodifiableMap(optionMap); protected final Map<String, Option<?>> optionMapView = Collections.unmodifiableMap(optionMap);
/** Select the backend to use. */ /** Select the backend to use. */
public final EnumOption<BackendType> backend = addOption(new EnumOption<>("engine", BackendType.INSTANCING)); public final EnumOption<BackendType> backend = addOption(new EnumOption<>("backend", BackendType.INSTANCING));
/** Enable or disable a debug overlay that colors pixels by their normal. */ /** Enable or disable a debug overlay that colors pixels by their normal. */
public final BooleanOption debugNormals = addOption(new BooleanOption("debugNormals", false)); public final BooleanOption debugNormals = addOption(new BooleanOption("debugNormals", false));
/** Enable or disable instance update limiting with distance. */ /** Enable or disable instance update limiting with distance. */

View file

@ -20,12 +20,12 @@ import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
* A helper class for loading and accessing json models. * A helper class for loading and accessing json models.
* <br> * <br>
* Creating a PartialModel will make the associated modelLocation automatically load. * Creating a PartialModel will make the associated modelLocation automatically load.
* PartialModels must be initialized during {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent FMLClientSetupEvent}. * PartialModels must be initialized the mod class constructor.
* <br> * <br>
* Once {@link ModelBakeEvent} finishes, all PartialModels (with valid modelLocations) * Once {@link ModelBakeEvent} finishes, all PartialModels (with valid modelLocations)
* will have their bakedModel fields populated. * will have their bakedModel fields populated.
* <br> * <br>
* Attempting to create a PartialModel after ModelRegistryEvent will cause an error. * Attempting to create a PartialModel after {@link ModelRegistryEvent} will cause an error.
*/ */
public class PartialModel { public class PartialModel {

View file

@ -1,37 +1,32 @@
package com.jozufozu.flywheel.core; package com.jozufozu.flywheel.core;
import java.nio.Buffer; import org.jetbrains.annotations.NotNull;
import java.nio.ByteBuffer; import org.jetbrains.annotations.Nullable;
import java.nio.ByteOrder; import org.lwjgl.opengl.GL32;
import java.util.EnumMap; import org.lwjgl.opengl.GL32C;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.backend.gl.GlNumericType; 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.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer; import com.jozufozu.flywheel.backend.gl.buffer.GlBufferUsage;
import com.jozufozu.flywheel.backend.model.ElementBuffer; import com.jozufozu.flywheel.backend.model.ElementBuffer;
import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.mojang.blaze3d.vertex.VertexFormat;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
/** /**
* A class to manage EBOs that index quads as triangles. * A class to manage EBOs that index quads as triangles.
*/ */
public class QuadConverter { public class QuadConverter {
public static final int STARTING_CAPACITY = 42; // 255 / 6 = 42
private static QuadConverter INSTANCE; private static QuadConverter INSTANCE;
@Nonnull @NotNull
public static QuadConverter getInstance() { public static QuadConverter getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
INSTANCE = new QuadConverter(STARTING_CAPACITY); INSTANCE = new QuadConverter();
} }
return INSTANCE; return INSTANCE;
@ -42,129 +37,79 @@ public class QuadConverter {
return INSTANCE; return INSTANCE;
} }
Map<GlNumericType, GlBuffer> ebos; private final Int2ReferenceMap<ElementBuffer> cache = new Int2ReferenceArrayMap<>();
int[] capacities; private final int ebo;
private int quadCapacity;
public QuadConverter(int initialCapacity) { public QuadConverter() {
this.ebos = new EnumMap<>(GlNumericType.class); this.ebo = GL32.glGenBuffers();
initCapacities(); this.quadCapacity = 0;
fillBuffer(initialCapacity);
} }
public ElementBuffer quads2Tris(int quads) { public ElementBuffer quads2Tris(int quads) {
int indexCount = quads * 6; if (quads > quadCapacity) {
GlNumericType type = getSmallestIndexType(indexCount); grow(quads * 2);
if (quads > getCapacity(type)) {
fillBuffer(quads, indexCount, type);
} }
return new ElementBuffer(getBuffer(type), indexCount, type); return cache.computeIfAbsent(quads, this::createElementBuffer);
} }
private void initCapacities() { @NotNull
this.capacities = new int[GlNumericType.values().length]; private ElementBuffer createElementBuffer(int quads) {
return new ElementBuffer(ebo, quads * 6, VertexFormat.IndexType.INT);
} }
private int getCapacity(GlNumericType type) { private void grow(int quads) {
return capacities[type.ordinal()]; int byteSize = quads * 6 * GlNumericType.UINT.getByteWidth();
} final long ptr = MemoryUtil.nmemAlloc(byteSize);
private void updateCapacity(GlNumericType type, int capacity) { fillBuffer(ptr, quads);
if (getCapacity(type) < capacity) {
capacities[type.ordinal()] = capacity; // XXX ARRAY_BUFFER is bound and reset
} final var bufferType = GlBufferType.ARRAY_BUFFER;
final int oldBuffer = bufferType.getBoundBuffer();
bufferType.bind(ebo);
GL32C.nglBufferData(bufferType.glEnum, byteSize, ptr, GlBufferUsage.STATIC_DRAW.glEnum);
bufferType.bind(oldBuffer);
MemoryUtil.nmemFree(ptr);
this.quadCapacity = quads;
} }
public void delete() { public void delete() {
ebos.values() GL32.glDeleteBuffers(ebo);
.forEach(GlBuffer::delete); this.cache.clear();
ebos.clear(); this.quadCapacity = 0;
initCapacities();
} }
private void fillBuffer(int quads) { private void fillBuffer(long ptr, int quads) {
int indexCount = quads * 6; int numVertices = 4 * quads;
int baseVertex = 0;
while (baseVertex < numVertices) {
writeQuadIndicesUnsafe(ptr, baseVertex);
fillBuffer(quads, indexCount, getSmallestIndexType(indexCount)); baseVertex += 4;
ptr += 6 * 4;
}
} }
private void fillBuffer(int quads, int indexCount, GlNumericType type) { private void writeQuadIndicesUnsafe(long ptr, int baseVertex) {
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);
}
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);
}
private void fillBuffer(ByteBuffer indices, GlNumericType type, int quads) {
for (int i = 0, max = 4 * quads; i < max; i += 4) {
// triangle a // triangle a
type.castAndBuffer(indices, i); MemoryUtil.memPutInt(ptr, baseVertex);
type.castAndBuffer(indices, i + 1); MemoryUtil.memPutInt(ptr + 4, baseVertex + 1);
type.castAndBuffer(indices, i + 2); MemoryUtil.memPutInt(ptr + 8, baseVertex + 2);
// triangle b // triangle b
type.castAndBuffer(indices, i); MemoryUtil.memPutInt(ptr + 12, baseVertex);
type.castAndBuffer(indices, i + 2); MemoryUtil.memPutInt(ptr + 16, baseVertex + 2);
type.castAndBuffer(indices, i + 3); MemoryUtil.memPutInt(ptr + 20, baseVertex + 3);
}
((Buffer) indices).flip();
} }
private GlBuffer getBuffer(GlNumericType type) { // make sure this gets reset first, so it has a chance to repopulate
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;
}
// make sure this gets reset first so it has a chance to repopulate
public static void onRendererReload(ReloadRenderersEvent event) { public static void onRendererReload(ReloadRenderersEvent event) {
if (INSTANCE != null) INSTANCE.delete(); if (INSTANCE != null) {
INSTANCE.delete();
INSTANCE = null;
}
} }
} }

View file

@ -18,6 +18,7 @@ public class CrumblingGroup<P extends CrumblingProgram> extends InstancedMateria
super(owner, type); super(owner, type);
} }
// XXX See notes of overriden method
@Override @Override
public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) { public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
type.setupRenderState(); type.setupRenderState();

View file

@ -5,6 +5,7 @@ import java.util.List;
import java.util.SortedSet; import java.util.SortedSet;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
import com.jozufozu.flywheel.backend.instancing.InstanceManager; import com.jozufozu.flywheel.backend.instancing.InstanceManager;
import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine; import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
@ -16,6 +17,7 @@ import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
import com.jozufozu.flywheel.util.Lazy; import com.jozufozu.flywheel.util.Lazy;
import com.jozufozu.flywheel.util.Pair; import com.jozufozu.flywheel.util.Pair;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@ -30,6 +32,7 @@ import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.BlockDestructionProgress; import net.minecraft.server.level.BlockDestructionProgress;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.Vec3;
/** /**
* Responsible for rendering the block breaking overlay for instanced block entities. * Responsible for rendering the block breaking overlay for instanced block entities.
@ -48,13 +51,21 @@ public class CrumblingRenderer {
INVALIDATOR = state.second(); INVALIDATOR = state.second();
} }
public static void renderBreaking(RenderLayerEvent event) { public static void render(ClientLevel level, Camera camera, PoseStack stack) {
if (!Backend.canUseInstancing(event.getWorld())) return; if (!Backend.canUseInstancing(level)) return;
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageBlockEntities(event.getWorld());
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageBlockEntities(level);
if (activeStages.isEmpty()) return; if (activeStages.isEmpty()) return;
Vec3 cameraPos = camera.getPosition();
// XXX Restore state
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
CrumblingRenderer.renderBreaking(activeStages, new RenderLayerEvent(level, null, stack, null, cameraPos.x, cameraPos.y, cameraPos.z));
restoreState.restore();
}
private static void renderBreaking(Int2ObjectMap<List<BlockEntity>> activeStages, RenderLayerEvent event) {
State state = STATE.get(); State state = STATE.get();
InstanceManager<BlockEntity> instanceManager = state.instanceManager; InstanceManager<BlockEntity> instanceManager = state.instanceManager;
InstancingEngine<CrumblingProgram> materials = state.materialManager; InstancingEngine<CrumblingProgram> materials = state.materialManager;
@ -71,6 +82,7 @@ public class CrumblingRenderer {
instanceManager.beginFrame(SerialTaskEngine.INSTANCE, info); instanceManager.beginFrame(SerialTaskEngine.INSTANCE, info);
// XXX Each call applies another restore state even though we are already inside of a restore state
materials.render(SerialTaskEngine.INSTANCE, event); materials.render(SerialTaskEngine.INSTANCE, event);
instanceManager.invalidate(); instanceManager.invalidate();
@ -78,6 +90,9 @@ public class CrumblingRenderer {
} }
// XXX Inconsistent GL state cleanup
// If texture binding and active unit need to be restored, store them in variables before GL state is changed
// instead of guessing that unit 0 and crumbling tex 0 are correct
GlTextureUnit.T0.makeActive(); GlTextureUnit.T0.makeActive();
AbstractTexture breaking = textureManager.getTexture(ModelBakery.BREAKING_LOCATIONS.get(0)); AbstractTexture breaking = textureManager.getTexture(ModelBakery.BREAKING_LOCATIONS.get(0));
if (breaking != null) RenderSystem.bindTexture(breaking.getId()); if (breaking != null) RenderSystem.bindTexture(breaking.getId());

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.core.hardcoded;
import java.util.List; import java.util.List;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.Formats; import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.model.Model; import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe; import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe;
@ -51,4 +52,20 @@ public class ModelPart implements Model {
public VertexList getReader() { public VertexList getReader() {
return reader; return reader;
} }
@Override
public VertexType getType() {
return Formats.POS_TEX_NORMAL;
}
@Override
public void delete() {
if (reader instanceof AutoCloseable closeable) {
try {
closeable.close();
} catch (Exception e) {
//
}
}
}
} }

View file

@ -1,6 +1,7 @@
package com.jozufozu.flywheel.core.model; package com.jozufozu.flywheel.core.model;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.Formats; import com.jozufozu.flywheel.core.Formats;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@ -12,10 +13,8 @@ import net.minecraft.world.level.block.state.BlockState;
* A model of a single block. * A model of a single block.
*/ */
public class BlockModel implements Model { public class BlockModel implements Model {
private static final PoseStack IDENTITY = new PoseStack();
private final VertexList reader; private final VertexList reader;
private final String name; private final String name;
public BlockModel(BlockState state) { public BlockModel(BlockState state) {
@ -25,12 +24,21 @@ public class BlockModel implements Model {
} }
public BlockModel(BakedModel model, BlockState referenceState) { public BlockModel(BakedModel model, BlockState referenceState) {
this(model, referenceState, IDENTITY); this(new BakedModelBuilder(model).withReferenceState(referenceState), referenceState.toString());
} }
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) { public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
reader = Formats.BLOCK.createReader(ModelUtil.getBufferBuilder(model, referenceState, ms)); this(new BakedModelBuilder(model).withReferenceState(referenceState)
name = referenceState.toString(); .withPoseStack(ms), referenceState.toString());
}
public BlockModel(Bufferable bufferable, String name) {
this(bufferable.build(), name);
}
public BlockModel(ShadeSeparatedBufferBuilder bufferBuilder, String name) {
this.name = name;
reader = Formats.BLOCK.createReader(bufferBuilder);
} }
@Override @Override
@ -47,4 +55,20 @@ public class BlockModel implements Model {
public VertexList getReader() { public VertexList getReader() {
return reader; return reader;
} }
@Override
public VertexType getType() {
return Formats.BLOCK;
}
@Override
public void delete() {
if (reader instanceof AutoCloseable closeable) {
try {
closeable.close();
} catch (Exception e) {
//
}
}
}
} }

View file

@ -5,7 +5,6 @@ import java.nio.ByteBuffer;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType; import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.backend.model.ElementBuffer; import com.jozufozu.flywheel.backend.model.ElementBuffer;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.QuadConverter; import com.jozufozu.flywheel.core.QuadConverter;
/** /**
@ -42,10 +41,9 @@ public interface Model {
*/ */
int vertexCount(); int vertexCount();
default VertexType getType() { VertexType getType();
return Formats.POS_TEX_NORMAL;
}
// XXX Since this is public API (technically) we cannot make assumptions about what GL state this method can use or modify unless a contract is established.
/** /**
* Create an element buffer object that indexes the vertices of this model. * Create an element buffer object that indexes the vertices of this model.
* *
@ -61,6 +59,8 @@ public interface Model {
.quads2Tris(vertexCount() / 4); .quads2Tris(vertexCount() / 4);
} }
void delete();
/** /**
* The size in bytes that this model's data takes up. * The size in bytes that this model's data takes up.
*/ */

View file

@ -1,37 +0,0 @@
package com.jozufozu.flywheel.core.model;
import com.jozufozu.flywheel.api.vertex.VertexList;
import com.jozufozu.flywheel.api.vertex.VertexType;
import com.jozufozu.flywheel.core.Formats;
import com.mojang.blaze3d.vertex.BufferBuilder;
public class WorldModel implements Model {
private final VertexList reader;
private final String name;
public WorldModel(BufferBuilder bufferBuilder, String name) {
this.reader = Formats.BLOCK.createReader(bufferBuilder);
this.name = name;
}
@Override
public String name() {
return name;
}
@Override
public VertexType getType() {
return Formats.BLOCK;
}
@Override
public int vertexCount() {
return reader.getVertexCount();
}
@Override
public VertexList getReader() {
return reader;
}
}

View file

@ -86,7 +86,7 @@ public final class WorldModelBuilder implements Bufferable {
return this; return this;
} }
public WorldModel intoMesh(String name) { public BlockModel intoMesh(String name) {
return new WorldModel(ModelUtil.getBufferBuilder(this), name); return new BlockModel(ModelUtil.getBufferBuilder(this), name);
} }
} }

View file

@ -7,7 +7,6 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.vertex.VertexList; import com.jozufozu.flywheel.api.vertex.VertexList;
import com.mojang.blaze3d.platform.MemoryTracker; import com.mojang.blaze3d.platform.MemoryTracker;
import com.mojang.blaze3d.vertex.BufferBuilder;
public abstract class AbstractVertexList implements VertexList, AutoCloseable { public abstract class AbstractVertexList implements VertexList, AutoCloseable {
@ -22,15 +21,6 @@ public abstract class AbstractVertexList implements VertexList, AutoCloseable {
init(copyFrom); init(copyFrom);
} }
public AbstractVertexList(BufferBuilder builder) {
var pair = builder.popNextBuffer();
ByteBuffer copyFrom = pair.getSecond();
this.contents = MemoryTracker.create(copyFrom.capacity());
this.vertexCount = pair.getFirst().vertexCount();
this.base = MemoryUtil.memAddress(this.contents);
init(copyFrom);
}
private void init(ByteBuffer copyFrom) { private void init(ByteBuffer copyFrom) {
this.contents.order(copyFrom.order()); this.contents.order(copyFrom.order());
this.contents.put(copyFrom); this.contents.put(copyFrom);

View file

@ -1,19 +1,17 @@
package com.jozufozu.flywheel.core.vertex; package com.jozufozu.flywheel.core.vertex;
import java.nio.ByteBuffer;
import com.jozufozu.flywheel.api.vertex.ShadedVertexList; import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
import com.jozufozu.flywheel.fabric.helper.BufferBuilderHelper;
import com.jozufozu.flywheel.util.RenderMath; import com.jozufozu.flywheel.util.RenderMath;
import com.mojang.blaze3d.vertex.BufferBuilder;
public class BlockVertexList extends AbstractVertexList { public class BlockVertexList extends AbstractVertexList {
private final int stride; private final int stride;
public BlockVertexList(BufferBuilder builder) { public BlockVertexList(ByteBuffer copyFrom, int vertexCount, int stride) {
super(builder); super(copyFrom, vertexCount);
this.stride = BufferBuilderHelper.getVertexFormat(builder) this.stride = stride;
.getVertexSize();
} }
@Override @Override
@ -94,9 +92,9 @@ public class BlockVertexList extends AbstractVertexList {
private final int unshadedStartVertex; private final int unshadedStartVertex;
public Shaded(ShadeSeparatedBufferBuilder builder) { public Shaded(ByteBuffer copyFrom, int vertexCount, int stride, int unshadedStartVertex) {
super(builder); super(copyFrom, vertexCount, stride);
unshadedStartVertex = builder.getUnshadedStartVertex(); this.unshadedStartVertex = unshadedStartVertex;
} }
@Override @Override

View file

@ -13,7 +13,6 @@ import net.minecraft.client.multiplayer.ClientLevel;
public class ForgeEvents { public class ForgeEvents {
public static void addToDebugScreen(List<String> right) { public static void addToDebugScreen(List<String> right) {
InstancedRenderDispatcher.getDebugString(right); InstancedRenderDispatcher.getDebugString(right);
} }

View file

@ -1,29 +0,0 @@
package com.jozufozu.flywheel.mixin;
import javax.annotation.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.mojang.blaze3d.vertex.BufferUploader;
import com.mojang.blaze3d.vertex.VertexFormat;
@Mixin(BufferUploader.class)
public class BufferUploaderMixin {
@Shadow
@Nullable
private static VertexFormat lastFormat;
@Inject(method = "reset", at = @At("HEAD"))
private static void stopBufferUploaderFromClearingBufferStateIfNothingIsBound(CallbackInfo ci) {
// Trust our tracker over BufferUploader's.
if (GlStateTracker.getVertexArray() == 0) {
lastFormat = null;
}
}
}

View file

@ -0,0 +1,28 @@
package com.jozufozu.flywheel.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import net.minecraft.client.main.Main;
@Mixin(value = Main.class, remap = false)
public class ClientMainMixin {
@Inject(method = "main", at = @At("HEAD"))
private static void injectRenderDoc(CallbackInfo ci) {
// Only try to load RenderDoc if a system property is set.
if (System.getProperty("flw.loadRenderDoc") == null) {
return;
}
try {
System.loadLibrary("renderdoc");
} catch (Throwable ignored) {
// Oh well, we tried.
// On Windows, RenderDoc installs to "C:\Program Files\RenderDoc\"
System.err.println("Is RenderDoc in your PATH?");
}
}
}

View file

@ -3,21 +3,17 @@ package com.jozufozu.flywheel.mixin;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Group;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer; import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.ReloadRenderersEvent; import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent; import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.fabric.event.FlywheelEvents; import com.jozufozu.flywheel.fabric.event.FlywheelEvents;
import com.mojang.blaze3d.vertex.BufferUploader;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix4f; import com.mojang.math.Matrix4f;
@ -31,7 +27,6 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
@Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after sodium @Mixin(value = LevelRenderer.class, priority = 1001) // Higher priority to go after sodium
public class LevelRendererMixin { public class LevelRendererMixin {
@ -48,41 +43,9 @@ public class LevelRendererMixin {
FlywheelEvents.BEGIN_FRAME.invoker().handleEvent(new BeginFrameEvent(level, camera, frustum)); FlywheelEvents.BEGIN_FRAME.invoker().handleEvent(new BeginFrameEvent(level, camera, frustum));
} }
@Unique
private boolean flywheel$LayerRendered;
/**
* This only gets injected if renderChunkLayer is not Overwritten
*/
@Group(name = "flywheel$renderLayer", min = 1, max = 2)
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ShaderInstance;clear()V"), method = "renderChunkLayer")
private void renderLayer(RenderType type, PoseStack stack, double camX, double camY, double camZ, Matrix4f p_172999_, CallbackInfo ci) {
flywheel$renderLayer(type, stack, camX, camY, camZ);
flywheel$LayerRendered = true;
}
/**
* This always gets injected.
*/
@Group(name = "flywheel$renderLayer")
@Inject(at = @At("TAIL"), method = "renderChunkLayer") @Inject(at = @At("TAIL"), method = "renderChunkLayer")
private void renderLayerSodium(RenderType type, PoseStack stack, double camX, double camY, double camZ, Matrix4f p_172999_, CallbackInfo ci) { private void renderLayer(RenderType type, PoseStack stack, double camX, double camY, double camZ, Matrix4f projection, CallbackInfo ci) {
if (!flywheel$LayerRendered) {
flywheel$renderLayer(type, stack, camX, camY, camZ);
}
flywheel$LayerRendered = false;
BufferUploader.reset();
}
@Unique
private void flywheel$renderLayer(RenderType type, PoseStack stack, double camX, double camY, double camZ) {
RenderBuffers renderBuffers = this.renderBuffers;
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
FlywheelEvents.RENDER_LAYER.invoker().handleEvent(new RenderLayerEvent(level, type, stack, renderBuffers, camX, camY, camZ)); FlywheelEvents.RENDER_LAYER.invoker().handleEvent(new RenderLayerEvent(level, type, stack, renderBuffers, camX, camY, camZ));
restoreState.restore();
} }
@Inject(at = @At("TAIL"), method = "allChanged") @Inject(at = @At("TAIL"), method = "allChanged")
@ -92,17 +55,10 @@ public class LevelRendererMixin {
FlywheelEvents.RELOAD_RENDERERS.invoker().handleEvent(new ReloadRenderersEvent(level)); FlywheelEvents.RELOAD_RENDERERS.invoker().handleEvent(new ReloadRenderersEvent(level));
} }
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;checkPoseStack(Lcom/mojang/blaze3d/vertex/PoseStack;)V", ordinal = 2 // after the game renders the breaking overlay normally @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/LevelRenderer;checkPoseStack(Lcom/mojang/blaze3d/vertex/PoseStack;)V", ordinal = 2 // after the game renders the breaking overlay normally
), method = "renderLevel") ), method = "renderLevel")
private void renderBlockBreaking(PoseStack stack, float p_228426_2_, long p_228426_3_, boolean p_228426_5_, Camera info, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f p_228426_9_, CallbackInfo ci) { private void renderBlockBreaking(PoseStack stack, float p_228426_2_, long p_228426_3_, boolean p_228426_5_, Camera camera, GameRenderer gameRenderer, LightTexture lightTexture, Matrix4f p_228426_9_, CallbackInfo ci) {
if (!Backend.isOn()) return; CrumblingRenderer.render(level, camera, stack);
Vec3 cameraPos = info.getPosition();
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
CrumblingRenderer.renderBreaking(new RenderLayerEvent(level, null, stack, null, cameraPos.x, cameraPos.y, cameraPos.z));
restoreState.restore();
} }
// Instancing // Instancing

View file

@ -14,11 +14,14 @@ import net.minecraft.client.renderer.RenderType;
public class RenderTypeMixin implements RenderTypeExtension { public class RenderTypeMixin implements RenderTypeExtension {
@Unique @Unique
private final DrawBuffer flywheel$drawBuffer = new DrawBuffer((RenderType) (Object) this); private DrawBuffer flywheel$drawBuffer;
@Override @Override
@Nonnull @Nonnull
public DrawBuffer flywheel$getDrawBuffer() { public DrawBuffer flywheel$getDrawBuffer() {
if (flywheel$drawBuffer == null) {
flywheel$drawBuffer = new DrawBuffer((RenderType) (Object) this);
}
return flywheel$drawBuffer; return flywheel$drawBuffer;
} }
} }

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.mixin; package com.jozufozu.flywheel.mixin.instancemanage;
import java.util.Set; import java.util.Set;

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.mixin; package com.jozufozu.flywheel.mixin.instancemanage;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.mixin; package com.jozufozu.flywheel.mixin.instancemanage;
import javax.annotation.Nullable; import javax.annotation.Nullable;

View file

@ -7,16 +7,13 @@
"BlockEntityRenderDispatcherAccessor", "BlockEntityRenderDispatcherAccessor",
"BlockEntityTypeMixin", "BlockEntityTypeMixin",
"BufferBuilderMixin", "BufferBuilderMixin",
"BufferUploaderMixin",
"CameraMixin", "CameraMixin",
"ClientLevelMixin", "ClientLevelMixin",
"ChunkRebuildHooksMixin", "ClientMainMixin",
"EntityTypeMixin", "EntityTypeMixin",
"FixFabulousDepthMixin", "FixFabulousDepthMixin",
"FrustumMixin", "FrustumMixin",
"GlStateManagerMixin", "GlStateManagerMixin",
"InstanceAddMixin",
"InstanceRemoveMixin",
"LevelRendererAccessor", "LevelRendererAccessor",
"LevelRendererMixin", "LevelRendererMixin",
"PausedPartialTickAccessor", "PausedPartialTickAccessor",
@ -24,6 +21,9 @@
"RenderTypeMixin", "RenderTypeMixin",
"atlas.AtlasDataMixin", "atlas.AtlasDataMixin",
"atlas.SheetDataAccessor", "atlas.SheetDataAccessor",
"instancemanage.ChunkRebuildHooksMixin",
"instancemanage.InstanceAddMixin",
"instancemanage.InstanceRemoveMixin",
"light.LightUpdateMixin", "light.LightUpdateMixin",
"light.NetworkLightUpdateMixin", "light.NetworkLightUpdateMixin",
"matrix.Matrix3fMixin", "matrix.Matrix3fMixin",