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

Conflicts:
	src/main/java/com/jozufozu/flywheel/FlywheelClient.java
	src/main/java/com/jozufozu/flywheel/event/EntityWorldHandler.java
This commit is contained in:
PepperCode1 2021-12-31 12:57:19 -08:00
commit 44f3358f3e
21 changed files with 113 additions and 67 deletions

View file

@ -1,3 +1,8 @@
0.5.0a:
Fixes
- Address crash experienced by some users while rendering any tile.
- Fix crash caused by loading a world with flywheel backend off.
0.5.0: 0.5.0:
New New
- Added parallel batching backend, effectively a CPU instancer. - Added parallel batching backend, effectively a CPU instancer.

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.5.0 mod_version = 0.5.0a
mc_update_version = 1.18 mc_update_version = 1.18
minecraft_version = 1.18.1 minecraft_version = 1.18.1
loader_version = 0.12.12 loader_version = 0.12.12

View file

@ -27,7 +27,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
public class Backend { public class Backend {
public static final Logger log = LogManager.getLogger(Backend.class); public static final Logger LOGGER = LogManager.getLogger(Backend.class);
protected static final Backend INSTANCE = new Backend(); protected static final Backend INSTANCE = new Backend();
public static Backend getInstance() { public static Backend getInstance() {
@ -39,8 +39,6 @@ public class Backend {
public GLCapabilities capabilities; public GLCapabilities capabilities;
public GlCompat compat; public GlCompat compat;
private boolean enabled;
public final Loader loader; public final Loader loader;
private final List<ShaderContext<?>> contexts = new ArrayList<>(); private final List<ShaderContext<?>> contexts = new ArrayList<>();
private final Map<ResourceLocation, StructType<?>> materialRegistry = new HashMap<>(); private final Map<ResourceLocation, StructType<?>> materialRegistry = new HashMap<>();
@ -93,7 +91,7 @@ public class Backend {
} }
materialRegistry.put(name, spec); materialRegistry.put(name, spec);
log.debug("registered material '" + name + "' with instance size " + spec.getLayout().getStride()); LOGGER.debug("registered material '" + name + "' with instance size " + spec.getLayout().getStride());
return spec; return spec;
} }
@ -104,20 +102,12 @@ public class Backend {
public void refresh() { public void refresh() {
OptifineHandler.refresh(); OptifineHandler.refresh();
boolean usingShaders = OptifineHandler.usingShaders();
capabilities = GL.createCapabilities(); capabilities = GL.createCapabilities();
compat = new GlCompat(capabilities); compat = new GlCompat(capabilities);
engine = FlwConfig.get() engine = chooseEngine(compat);
.getEngine();
enabled = switch (engine) {
case OFF -> false;
case BATCHING -> true;
case INSTANCING -> !usingShaders && compat.instancedArraysSupported();
};
} }
public Collection<StructType<?>> allMaterials() { public Collection<StructType<?>> allMaterials() {
@ -133,7 +123,7 @@ public class Backend {
} }
public static boolean isOn() { public static boolean isOn() {
return getInstance().enabled; return getInstance().engine != FlwEngine.OFF;
} }
public static boolean canUseInstancing(@Nullable Level world) { public static boolean canUseInstancing(@Nullable Level world) {
@ -174,4 +164,18 @@ public class Backend {
public static void init() { public static void init() {
} }
private static FlwEngine chooseEngine(GlCompat compat) {
FlwEngine preferredChoice = FlwConfig.get()
.getEngine();
boolean usingShaders = OptifineHandler.usingShaders();
boolean canUseEngine = switch (preferredChoice) {
case OFF -> true;
case BATCHING -> !usingShaders;
case INSTANCING -> !usingShaders && compat.instancedArraysSupported();
};
return canUseEngine ? preferredChoice : FlwEngine.OFF;
}
} }

View file

@ -82,10 +82,10 @@ public class Loader {
throw new ShaderLoadingException("Could not load all shaders, see log for details"); throw new ShaderLoadingException("Could not load all shaders, see log for details");
} }
Backend.log.info("Loaded all shader programs."); Backend.LOGGER.info("Loaded all shader programs.");
ClientLevel world = Minecraft.getInstance().level; ClientLevel world = Minecraft.getInstance().level;
if (Backend.isFlywheelWorld(world)) { if (Backend.canUseInstancing(world)) {
// TODO: looks like it might be good to have another event here // TODO: looks like it might be good to have another event here
InstancedRenderDispatcher.resetInstanceWorld(world); InstancedRenderDispatcher.resetInstanceWorld(world);
CrumblingRenderer.reset(); CrumblingRenderer.reset();
@ -115,7 +115,7 @@ public class Loader {
backend.register(spec); backend.register(spec);
} catch (Exception e) { } catch (Exception e) {
Backend.log.error(e); Backend.LOGGER.error(e);
} }
} }
} }

View file

@ -44,9 +44,9 @@ public class OptifineHandler {
optifine = Package.getPackage(OPTIFINE_ROOT_PACKAGE); optifine = Package.getPackage(OPTIFINE_ROOT_PACKAGE);
if (optifine == null) { if (optifine == null) {
Backend.log.info("Optifine not detected."); Backend.LOGGER.info("Optifine not detected.");
} else { } else {
Backend.log.info("Optifine detected."); Backend.LOGGER.info("Optifine detected.");
refresh(); refresh();
} }
@ -79,7 +79,7 @@ public class OptifineHandler {
return false; return false;
}); });
} catch (IOException e) { } catch (IOException e) {
Backend.log.info("No shader config found."); Backend.LOGGER.info("No shader config found.");
} }
return shadersOff; return shadersOff;
} }

View file

@ -12,7 +12,6 @@ import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.gl.GlFence; import com.jozufozu.flywheel.backend.gl.GlFence;
import com.jozufozu.flywheel.backend.gl.error.GlError; import com.jozufozu.flywheel.backend.gl.error.GlError;
import com.jozufozu.flywheel.backend.gl.error.GlException; import com.jozufozu.flywheel.backend.gl.error.GlException;
import com.jozufozu.flywheel.util.StringUtil;
public class PersistentGlBuffer extends GlBuffer implements Mappable { public class PersistentGlBuffer extends GlBuffer implements Mappable {
@ -49,13 +48,6 @@ public class PersistentGlBuffer extends GlBuffer implements Mappable {
Backend.getInstance().compat.bufferStorage.bufferStorage(type, size, flags); Backend.getInstance().compat.bufferStorage.bufferStorage(type, size, flags);
GlError error = GlError.poll();
if (error != null) {
// If this error is being thrown but everything seems fine,
// GlError.poll() might be returning an error from something earlier.
throw new GlException(error, StringUtil.args("bufferStorage", type, size, flags));
}
ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, flags); ByteBuffer byteBuffer = GL30.glMapBufferRange(type.glEnum, 0, size, flags);
if (byteBuffer == null) { if (byteBuffer == null) {

View file

@ -5,8 +5,6 @@ import java.util.function.Supplier;
import org.lwjgl.opengl.GL20; import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30; import org.lwjgl.opengl.GL30;
import com.jozufozu.flywheel.Flywheel;
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;
@ -41,10 +39,10 @@ public enum GlError {
} }
public static void pollAndThrow(Supplier<String> context) { public static void pollAndThrow(Supplier<String> context) {
// TODO: build flag? to enable or disable this function // This was a bad idea.
GlError err = GlError.poll(); // GlError err = GlError.poll();
if (err != null) { // if (err != null) {
Flywheel.LOGGER.error("{}: {}", err.name(), context.get()); // Flywheel.LOGGER.error("{}: {}", err.name(), context.get());
} // }
} }
} }

View file

@ -49,7 +49,7 @@ public abstract class GlProgram extends GlObject {
int index = glGetUniformLocation(this.handle(), uniform); int index = glGetUniformLocation(this.handle(), uniform);
if (index < 0) { if (index < 0) {
Backend.log.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name); Backend.LOGGER.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name);
} }
return index; return index;

View file

@ -24,8 +24,8 @@ public class GlShader extends GlObject {
String log = GL20.glGetShaderInfoLog(handle); String log = GL20.glGetShaderInfoLog(handle);
if (!log.isEmpty()) { if (!log.isEmpty()) {
Backend.log.error("Shader compilation log for " + name + ": " + log); Backend.LOGGER.error("Shader compilation log for " + name + ": " + log);
Backend.log.error(source); Backend.LOGGER.error(source);
} }
//Backend.log.debug(shader.printSource()); //Backend.log.debug(shader.printSource());

View file

@ -22,8 +22,11 @@ public class InstancedRenderDispatcher {
* @param te The tile whose instance you want to update. * @param te The tile whose instance you want to update.
*/ */
public static void enqueueUpdate(BlockEntity te) { public static void enqueueUpdate(BlockEntity te) {
if (te.hasLevel() && te.getLevel() instanceof ClientLevel) if (Backend.isOn() && te.hasLevel() && te.getLevel() instanceof ClientLevel) {
getTiles(te.getLevel()).queueUpdate(te); instanceWorlds.get(te.getLevel())
.getTileEntityInstanceManager()
.queueUpdate(te);
}
} }
/** /**
@ -31,17 +34,29 @@ public class InstancedRenderDispatcher {
* @param entity The entity whose instance you want to update. * @param entity The entity whose instance you want to update.
*/ */
public static void enqueueUpdate(Entity entity) { public static void enqueueUpdate(Entity entity) {
getEntities(entity.level).queueUpdate(entity); if (Backend.isOn()) {
instanceWorlds.get(entity.level)
.getEntityInstanceManager()
.queueUpdate(entity);
}
} }
public static InstanceManager<BlockEntity> getTiles(LevelAccessor world) { public static InstanceManager<BlockEntity> getTiles(LevelAccessor world) {
return instanceWorlds.get(world) if (Backend.isOn()) {
.getTileEntityInstanceManager(); return instanceWorlds.get(world)
.getTileEntityInstanceManager();
} else {
throw new NullPointerException("Backend is off, cannot retrieve instance world.");
}
} }
public static InstanceManager<Entity> getEntities(LevelAccessor world) { public static InstanceManager<Entity> getEntities(LevelAccessor world) {
return instanceWorlds.get(world) if (Backend.isOn()) {
.getEntityInstanceManager(); return instanceWorlds.get(world)
.getEntityInstanceManager();
} else {
throw new NullPointerException("Backend is off, cannot retrieve instance world.");
}
} }
public static void tick(Minecraft mc) { public static void tick(Minecraft mc) {
@ -52,11 +67,14 @@ public class InstancedRenderDispatcher {
ClientLevel world = mc.level; ClientLevel world = mc.level;
AnimationTickHolder.tick(); AnimationTickHolder.tick();
instanceWorlds.get(world).tick(); if (Backend.isOn()) {
instanceWorlds.get(world)
.tick();
}
} }
public static void onBeginFrame(BeginFrameEvent event) { public static void onBeginFrame(BeginFrameEvent event) {
if (Backend.isGameActive()) { if (Backend.isGameActive() && Backend.isOn()) {
instanceWorlds.get(event.getWorld()) instanceWorlds.get(event.getWorld())
.beginFrame(event); .beginFrame(event);
} }

View file

@ -50,7 +50,7 @@ public class ProtoProgram {
String log = glGetProgramInfoLog(this.program); String log = glGetProgramInfoLog(this.program);
if (!log.isEmpty()) { if (!log.isEmpty()) {
Backend.log.debug("Program link log for " + parent.name + ": " + log); Backend.LOGGER.debug("Program link log for " + parent.name + ": " + log);
} }
int result = glGetProgrami(this.program, GL_LINK_STATUS); int result = glGetProgrami(this.program, GL_LINK_STATUS);

View file

@ -73,7 +73,7 @@ public class FileResolution {
builder.pointAtFile(span.getSourceFile()) builder.pointAtFile(span.getSourceFile())
.pointAt(span, 2); .pointAt(span, 2);
} }
Backend.log.error(builder.build()); Backend.LOGGER.error(builder.build());
} }
} }

View file

@ -18,7 +18,7 @@ public class ErrorReporter {
.pointAt(span, 2) .pointAt(span, 2)
.build(); .build();
Backend.log.error(error); Backend.LOGGER.error(error);
} }
public static void generateFileError(SourceFile file, String message) { public static void generateFileError(SourceFile file, String message) {
@ -27,7 +27,7 @@ public class ErrorReporter {
.pointAtFile(file) .pointAtFile(file)
.build(); .build();
Backend.log.error(error); Backend.LOGGER.error(error);
} }
public static void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg) { public static void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg) {
@ -45,7 +45,7 @@ public class ErrorReporter {
.pointAt(vertexName, 2) .pointAt(vertexName, 2)
.hintIncludeFor(span.orElse(null), hint); .hintIncludeFor(span.orElse(null), hint);
Backend.log.error(error.build()); Backend.LOGGER.error(error.build());
} }
public static void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) { public static void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) {
@ -62,6 +62,6 @@ public class ErrorReporter {
.pointAtFile(file) .pointAtFile(file)
.hintIncludeFor(span.orElse(null), hint); .hintIncludeFor(span.orElse(null), hint);
Backend.log.error(error.build()); Backend.LOGGER.error(error.build());
} }
} }

View file

@ -34,7 +34,7 @@ public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
@Override @Override
public void load() { public void load() {
Backend.log.info("Loading context '{}'", name); Backend.LOGGER.info("Loading context '{}'", name);
specStream.get() specStream.get()
.map(backend::getSpec) .map(backend::getSpec)
@ -46,10 +46,10 @@ public class WorldContext<P extends WorldProgram> implements ShaderContext<P> {
try { try {
programs.put(spec.name, pipeline.compile(spec)); programs.put(spec.name, pipeline.compile(spec));
Backend.log.debug("Loaded program {}", spec.name); Backend.LOGGER.debug("Loaded program {}", spec.name);
} catch (Exception e) { } catch (Exception e) {
Backend.log.error("Error loading program {}", spec.name); Backend.LOGGER.error("Error loading program {}", spec.name);
Backend.log.error("", e); Backend.LOGGER.error("", e);
backend.loader.notifyError(); backend.loader.notifyError();
} }
} }

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.event; package com.jozufozu.flywheel.event;
import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
@ -8,12 +9,12 @@ import net.minecraft.world.entity.Entity;
public class EntityWorldHandler { public class EntityWorldHandler {
public static void onEntityJoinWorld(Entity entity, ClientLevel level) { public static void onEntityJoinWorld(Entity entity, ClientLevel level) {
InstancedRenderDispatcher.getEntities(level) if (Backend.isOn()) InstancedRenderDispatcher.getEntities(level)
.queueAdd(entity); .queueAdd(entity);
} }
public static void onEntityLeaveWorld(Entity entity, ClientLevel level) { public static void onEntityLeaveWorld(Entity entity, ClientLevel level) {
InstancedRenderDispatcher.getEntities(level) if (Backend.isOn()) InstancedRenderDispatcher.getEntities(level)
.remove(entity); .remove(entity);
} }
} }

View file

@ -0,0 +1,19 @@
package com.jozufozu.flywheel.fabric.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.Backend;
import net.minecraft.SystemReport;
@Mixin(value = SystemReport.class, priority = 1100)
public class SystemReportMixin {
@Inject(method = "<init>()V", at = @At("TAIL"))
private void onTailInit(CallbackInfo ci) {
SystemReport self = (SystemReport) (Object) this;
self.setDetail("Flywheel Backend", () -> Backend.getInstance().getBackendDescriptor());
}
}

View file

@ -20,7 +20,7 @@ public class ChunkRebuildHooksMixin {
@Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true) @Inject(method = "handleBlockEntity", at = @At("HEAD"), cancellable = true)
private <E extends BlockEntity> void addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set<BlockEntity> set, E be, CallbackInfo ci) { private <E extends BlockEntity> void addAndFilterBEs(ChunkRenderDispatcher.CompiledChunk compiledChunk, Set<BlockEntity> set, E be, CallbackInfo ci) {
if (Backend.isOn() && Backend.isFlywheelWorld(be.getLevel())) { if (Backend.canUseInstancing(be.getLevel())) {
InstancedRenderRegistry registry = InstancedRenderRegistry.getInstance(); InstancedRenderRegistry registry = InstancedRenderRegistry.getInstance();
if (registry.canInstance(be.getType())) if (registry.canInstance(be.getType()))

View file

@ -7,6 +7,7 @@ import org.spongepowered.asm.mixin.injection.At;
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.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -23,7 +24,9 @@ public class InstanceAddMixin {
@Inject(method = "setBlockEntity", @Inject(method = "setBlockEntity",
at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")) at = @At(value = "INVOKE_ASSIGN", target = "Ljava/util/Map;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"))
private void tileAdded(BlockEntity be, CallbackInfo ci) { private void tileAdded(BlockEntity be, CallbackInfo ci) {
if (level.isClientSide) InstancedRenderDispatcher.getTiles(this.level) if (level.isClientSide && Backend.isOn()) {
.add(be); InstancedRenderDispatcher.getTiles(this.level)
.add(be);
}
} }
} }

View file

@ -8,6 +8,7 @@ import org.spongepowered.asm.mixin.injection.At;
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.instancing.InstancedRenderDispatcher; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
@ -23,8 +24,10 @@ public class InstanceRemoveMixin {
@Inject(at = @At("TAIL"), method = "setRemoved") @Inject(at = @At("TAIL"), method = "setRemoved")
private void removeInstance(CallbackInfo ci) { private void removeInstance(CallbackInfo ci) {
if (level instanceof ClientLevel) InstancedRenderDispatcher.getTiles(this.level) if (level instanceof ClientLevel && Backend.isOn()) {
.remove((BlockEntity) (Object) this); InstancedRenderDispatcher.getTiles(this.level)
.remove((BlockEntity) (Object) this);
}
} }
// /** // /**

View file

@ -83,7 +83,9 @@ public class RenderHooksMixin {
*/ */
@Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V") @Inject(at = @At("TAIL"), method = "setBlockDirty(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;)V")
private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) { private void checkUpdate(BlockPos pos, BlockState lastState, BlockState newState, CallbackInfo ci) {
InstancedRenderDispatcher.getTiles(level) if (Backend.isOn()) {
.update(level.getBlockEntity(pos)); InstancedRenderDispatcher.getTiles(level)
.update(level.getBlockEntity(pos));
}
} }
} }

View file

@ -8,6 +8,7 @@
"DebugScreenOverlayMixin", "DebugScreenOverlayMixin",
"Matrix4fMixin", "Matrix4fMixin",
"MinecraftMixin", "MinecraftMixin",
"SystemReportMixin",
"TextureAtlasMixin", "TextureAtlasMixin",
"VertexFormatAccessor" "VertexFormatAccessor"
], ],