Merge branch '1.18/dev' into 1.18/shader-sanity

# Conflicts:
#	src/main/java/com/jozufozu/flywheel/backend/instancing/instancing/InstancingEngine.java
This commit is contained in:
Jozufozu 2022-01-09 22:35:42 -08:00
commit 12cab85f69
14 changed files with 248 additions and 135 deletions

View file

@ -1,3 +1,13 @@
0.5.1:
Fixes
- Fix crash on resource reload with backend off
- Fix artifacts while using Optifine shaders
- Fix crash when trying to access biomes in a VirtualRenderWorld
Technical/API
- Refactor instance renderer registration to separate client and server logic (thanks Pepper!)
- VirtualRenderWorlds now have a "biomeOffset" field which gets added when looking up biomes
- Added GlStateTracker which hooks into GlStateManager to track changes in buffer, vertex array, and program bindings
0.5.0a:
Fixes
- Address crash experienced by some users while rendering any tile.

View file

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

View file

@ -4,7 +4,6 @@ import org.lwjgl.opengl.GL20;
import com.jozufozu.flywheel.core.layout.BufferLayout;
import com.jozufozu.flywheel.core.layout.LayoutItem;
import com.jozufozu.flywheel.mixin.BufferUploaderAccessor;
import com.mojang.blaze3d.platform.GlStateManager;
public class GlVertexArray extends GlObject {
@ -14,20 +13,14 @@ public class GlVertexArray extends GlObject {
public static void bind(int vao) {
GlStateManager._glBindVertexArray(vao);
BufferUploaderAccessor.flywheel$setLastVAO(vao);
}
public void bind() {
bind(handle());
}
public static int getBoundVertexArray() {
return BufferUploaderAccessor.flywheel$getLastVAO();
}
public static void unbind() {
GlStateManager._glBindVertexArray(0);
BufferUploaderAccessor.flywheel$setLastVAO(0);
}
public void enableArrays(int count) {

View file

@ -8,7 +8,7 @@ import org.lwjgl.opengl.GL40;
import org.lwjgl.opengl.GL42;
import org.lwjgl.opengl.GL43;
import com.jozufozu.flywheel.mixin.BufferUploaderAccessor;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.mojang.blaze3d.platform.GlStateManager;
public enum GlBufferType {
@ -33,29 +33,34 @@ public enum GlBufferType {
this.glEnum = glEnum;
}
public void bind(int buffer) {
GlStateManager._glBindBuffer(glEnum, buffer);
public static GlBufferType fromTarget(int pTarget) {
return switch (pTarget) {
case GL15C.GL_ARRAY_BUFFER -> ARRAY_BUFFER;
case GL15C.GL_ELEMENT_ARRAY_BUFFER -> ELEMENT_ARRAY_BUFFER;
case GL21.GL_PIXEL_PACK_BUFFER -> PIXEL_PACK_BUFFER;
case GL21.GL_PIXEL_UNPACK_BUFFER -> PIXEL_UNPACK_BUFFER;
case GL30.GL_TRANSFORM_FEEDBACK_BUFFER -> TRANSFORM_FEEDBACK_BUFFER;
case GL31.GL_UNIFORM_BUFFER -> UNIFORM_BUFFER;
case GL31.GL_TEXTURE_BUFFER -> TEXTURE_BUFFER;
case GL31.GL_COPY_READ_BUFFER -> COPY_READ_BUFFER;
case GL31.GL_COPY_WRITE_BUFFER -> COPY_WRITE_BUFFER;
case GL40.GL_DRAW_INDIRECT_BUFFER -> DRAW_INDIRECT_BUFFER;
case GL42.GL_ATOMIC_COUNTER_BUFFER -> ATOMIC_COUNTER_BUFFER;
case GL43.GL_DISPATCH_INDIRECT_BUFFER -> DISPATCH_INDIRECT_BUFFER;
case GL43.GL_SHADER_STORAGE_BUFFER -> SHADER_STORAGE_BUFFER;
default -> throw new IllegalArgumentException("Unknown target: " + pTarget);
};
}
switch (this.glEnum) {
case GL15C.GL_ELEMENT_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$setLastEBO(buffer);
case GL15C.GL_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$setLastVBO(buffer);
}
public void bind(int buffer) {
GlStateManager._glBindBuffer(glEnum, buffer);
}
public void unbind() {
GlStateManager._glBindBuffer(glEnum, 0);
switch (this.glEnum) {
case GL15C.GL_ELEMENT_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$setLastEBO(0);
case GL15C.GL_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$setLastVBO(0);
}
}
public int getBoundBuffer() {
return switch (this.glEnum) {
case GL15C.GL_ELEMENT_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$getLastEBO();
case GL15C.GL_ARRAY_BUFFER -> BufferUploaderAccessor.flywheel$getLastVBO();
default -> -1;
};
return GlStateTracker.getBuffer(this);
}
}

View file

@ -13,7 +13,6 @@ import org.lwjgl.system.MemoryStack;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlObject;
import com.jozufozu.flywheel.mixin.ShaderInstanceAccessor;
import com.mojang.blaze3d.shaders.ProgramManager;
import com.mojang.math.Matrix4f;
@ -31,14 +30,11 @@ public abstract class GlProgram extends GlObject {
}
public void bind() {
int handle = handle();
ProgramManager.glUseProgram(handle);
ShaderInstanceAccessor.flywheel$setLastProgramId(handle);
ProgramManager.glUseProgram(handle());
}
public void unbind() {
public static void unbind() {
ProgramManager.glUseProgram(0);
ShaderInstanceAccessor.flywheel$setLastProgramId(0);
}
/**

View file

@ -3,6 +3,7 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;
import javax.annotation.Nullable;
@ -23,6 +24,7 @@ import net.minecraft.client.Camera;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
public class InstancingEngine<P extends WorldProgram> implements Engine {
@ -73,10 +75,6 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
*/
@Override
public void render(TaskEngine taskEngine, RenderLayerEvent event) {
int ebo = GlBufferType.ELEMENT_ARRAY_BUFFER.getBoundBuffer();
int vbo = GlBufferType.ARRAY_BUFFER.getBoundBuffer();
int vao = GlVertexArray.getBoundVertexArray();
double camX;
double camY;
double camZ;
@ -96,10 +94,6 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
}
getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ, event.getLayer()));
GlBufferType.ELEMENT_ARRAY_BUFFER.bind(ebo);
GlBufferType.ARRAY_BUFFER.bind(vbo);
GlVertexArray.bind(vao);
}
private Stream<InstancedMaterialGroup<P>> getGroupsToRender(@Nullable RenderLayer layer) {

View file

@ -29,7 +29,7 @@ public class WorldProgram extends GlProgram {
super.bind();
registerSamplers();
super.unbind();
unbind();
}
protected void registerSamplers() {

View file

@ -17,6 +17,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.SectionPos;
import net.minecraft.core.Vec3i;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundSource;
import net.minecraft.tags.TagContainer;
@ -25,6 +26,7 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -54,21 +56,39 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld {
protected final int height;
protected final int minBuildHeight;
protected final Vec3i biomeOffset;
public VirtualRenderWorld(Level level) {
this(level, level.getHeight(), level.getMinBuildHeight());
this(level, Vec3i.ZERO, level.getHeight(), level.getMinBuildHeight());
}
public VirtualRenderWorld(Level level, int height, int minBuildHeight) {
public VirtualRenderWorld(Level level, Vec3i biomeOffset) {
this(level, biomeOffset, level.getHeight(), level.getMinBuildHeight());
}
public VirtualRenderWorld(Level level, Vec3i biomeOffset, int height, int minBuildHeight) {
super((WritableLevelData) level.getLevelData(), level.dimension(), level.dimensionType(), level::getProfiler,
true, false, 0);
this.biomeOffset = biomeOffset;
this.level = level;
this.height = height;
this.minBuildHeight = minBuildHeight;
this.height = nextMultipleOf16(height);
this.minBuildHeight = nextMultipleOf16(minBuildHeight);
this.chunkSource = new VirtualChunkSource(this);
this.lighter = new LevelLightEngine(chunkSource, true, false);
}
/**
* We need to ensure that height and minBuildHeight are multiples of 16.
* Adapted from: https://math.stackexchange.com/questions/291468
*/
public static int nextMultipleOf16(int a) {
if (a < 0) {
return -(((Math.abs(a) - 1) | 15) + 1);
} else {
return ((a - 1) | 15) + 1;
}
}
/**
* Run this after you're done using setBlock().
*/
@ -165,6 +185,27 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld {
return getBlockState(scratch.set(x, y, z));
}
// BIOME OFFSET
@Override
public Biome getBiome(BlockPos pPos) {
return super.getBiome(pPos.offset(biomeOffset));
}
@Override
public Biome getUncachedNoiseBiome(int pX, int pY, int pZ) {
// Control flow should never reach this method,
// so we add biomeOffset in case some other mod calls this directly.
return level.getUncachedNoiseBiome(pX + biomeOffset.getX(), pY + biomeOffset.getY(), pZ + biomeOffset.getZ());
}
@Override
public Biome getNoiseBiome(int pX, int pY, int pZ) {
// Control flow should never reach this method,
// so we add biomeOffset in case some other mod calls this directly.
return level.getNoiseBiome(pX + biomeOffset.getX(), pY + biomeOffset.getY(), pZ + biomeOffset.getZ());
}
// RENDERING CONSTANTS
@Override
@ -179,6 +220,11 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld {
// THIN WRAPPERS AHEAD
@Override
public BiomeManager getBiomeManager() {
return level.getBiomeManager();
}
@Override
public RegistryAccess registryAccess() {
return level.registryAccess();
@ -214,11 +260,6 @@ public class VirtualRenderWorld extends Level implements FlywheelWorld {
return level.getScoreboard();
}
@Override
public Biome getUncachedNoiseBiome(int p_225604_1_, int p_225604_2_, int p_225604_3_) {
return level.getUncachedNoiseBiome(p_225604_1_, p_225604_2_, p_225604_3_);
}
// UNIMPORTANT CONSTANTS
@Override

View file

@ -1,39 +0,0 @@
package com.jozufozu.flywheel.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import com.mojang.blaze3d.vertex.BufferUploader;
@Mixin(BufferUploader.class)
public interface BufferUploaderAccessor {
@Accessor("lastVertexArrayObject")
static void flywheel$setLastVAO(int id) {
throw new AssertionError();
}
@Accessor("lastVertexBufferObject")
static void flywheel$setLastVBO(int id) {
throw new AssertionError();
}
@Accessor("lastIndexBufferObject")
static void flywheel$setLastEBO(int id) {
throw new AssertionError();
}
@Accessor("lastIndexBufferObject")
static int flywheel$getLastEBO() {
throw new AssertionError();
}
@Accessor("lastVertexBufferObject")
static int flywheel$getLastVBO() {
throw new AssertionError();
}
@Accessor("lastVertexArrayObject")
static int flywheel$getLastVAO() {
throw new AssertionError();
}
}

View file

@ -0,0 +1,29 @@
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,29 @@
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 com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.mojang.blaze3d.platform.GlStateManager;
@Mixin(GlStateManager.class)
public class GlStateManagerMixin {
@Inject(method = "_glBindBuffer", at = @At("TAIL"))
private static void onBindBuffer(int pTarget, int pBuffer, CallbackInfo ci) {
GlStateTracker._setBuffer(GlBufferType.fromTarget(pTarget), pBuffer);
}
@Inject(method = "_glBindVertexArray", at = @At("TAIL"))
private static void onBindVertexArray(int pArray, CallbackInfo ci) {
GlStateTracker._setVertexArray(pArray);
}
@Inject(method = "_glUseProgram", at = @At("TAIL"))
private static void onUseProgram(int pProgram, CallbackInfo ci) {
GlStateTracker._setProgram(pProgram);
}
}

View file

@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
import com.jozufozu.flywheel.event.BeginFrameEvent;
@ -57,7 +58,11 @@ public class LevelRendererMixin {
RenderBuffers renderBuffers = this.renderBuffers;
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
MinecraftForge.EVENT_BUS.post(new RenderLayerEvent(level, type, stack, renderBuffers, camX, camY, camZ));
restoreState.restore();
}
@Inject(at = @At("TAIL"), method = "allChanged")
@ -76,7 +81,9 @@ public class LevelRendererMixin {
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

View file

@ -1,14 +0,0 @@
package com.jozufozu.flywheel.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import net.minecraft.client.renderer.ShaderInstance;
@Mixin(ShaderInstance.class)
public interface ShaderInstanceAccessor {
@Accessor("lastProgramId")
static void flywheel$setLastProgramId(int id) {
throw new AssertionError();
}
}

View file

@ -1,37 +1,37 @@
{
"required": true,
"minVersion": "0.8",
"package": "com.jozufozu.flywheel.mixin",
"compatibilityLevel": "JAVA_17",
"refmap": "flywheel.refmap.json",
"client": [
"BlockEntityTypeMixin",
"BufferBuilderMixin",
"BufferUploaderAccessor",
"CameraMixin",
"CancelEntityRenderMixin",
"ChunkRebuildHooksMixin",
"EntityTypeMixin",
"FixFabulousDepthMixin",
"FrustumMixin",
"InstanceAddMixin",
"InstanceRemoveMixin",
"LevelRendererAccessor",
"LevelRendererMixin",
"PausedPartialTickAccessor",
"RenderTexturesMixin",
"RenderTypeMixin",
"ShaderCloseMixin",
"ShaderInstanceAccessor",
"atlas.AtlasDataMixin",
"atlas.SheetDataAccessor",
"light.LightUpdateMixin",
"light.NetworkLightUpdateMixin",
"matrix.Matrix3fMixin",
"matrix.Matrix4fMixin",
"matrix.PoseStackMixin"
],
"injectors": {
"defaultRequire": 1
"required": true,
"minVersion": "0.8",
"package": "com.jozufozu.flywheel.mixin",
"compatibilityLevel": "JAVA_17",
"refmap": "flywheel.refmap.json",
"client": [
"BlockEntityTypeMixin",
"BufferBuilderMixin",
"BufferUploaderMixin",
"CameraMixin",
"CancelEntityRenderMixin",
"ChunkRebuildHooksMixin",
"EntityTypeMixin",
"FixFabulousDepthMixin",
"FrustumMixin",
"GlStateManagerMixin",
"InstanceAddMixin",
"InstanceRemoveMixin",
"LevelRendererAccessor",
"LevelRendererMixin",
"PausedPartialTickAccessor",
"RenderTexturesMixin",
"RenderTypeMixin",
"ShaderCloseMixin",
"atlas.AtlasDataMixin",
"atlas.SheetDataAccessor",
"light.LightUpdateMixin",
"light.NetworkLightUpdateMixin",
"matrix.Matrix3fMixin",
"matrix.Matrix4fMixin",
"matrix.PoseStackMixin"
],
"injectors": {
"defaultRequire": 1
}
}