mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-23 03:17:53 +01:00
Merge remote-tracking branch 'upstream/1.20/dev' into feat/multi-loader-1.21
This commit is contained in:
commit
db9e1b753a
13 changed files with 72 additions and 48 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -23,7 +23,7 @@ jobs:
|
||||||
restore-keys: "${{ runner.os }}-gradle-"
|
restore-keys: "${{ runner.os }}-gradle-"
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v3
|
uses: gradle/actions/setup-gradle@v4.2.0
|
||||||
with:
|
with:
|
||||||
gradle-home-cache-cleanup: true
|
gradle-home-cache-cleanup: true
|
||||||
cache-read-only: ${{ !endsWith(github.ref_name, '/dev') }}
|
cache-read-only: ${{ !endsWith(github.ref_name, '/dev') }}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.engine_room.flywheel.backend.engine;
|
package dev.engine_room.flywheel.backend.engine;
|
||||||
|
|
||||||
import java.util.BitSet;
|
import java.util.BitSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
@ -34,6 +35,7 @@ import net.minecraft.core.Vec3i;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.level.chunk.DataLayer;
|
import net.minecraft.world.level.chunk.DataLayer;
|
||||||
|
import net.minecraft.world.level.lighting.LayerLightEventListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A managed arena of light sections for uploading to the GPU.
|
* A managed arena of light sections for uploading to the GPU.
|
||||||
|
@ -57,8 +59,8 @@ public class LightStorage implements Effect {
|
||||||
private static final int DEFAULT_ARENA_CAPACITY_SECTIONS = 64;
|
private static final int DEFAULT_ARENA_CAPACITY_SECTIONS = 64;
|
||||||
private static final int INVALID_SECTION = -1;
|
private static final int INVALID_SECTION = -1;
|
||||||
|
|
||||||
private static final ConstantDataLayer EMPTY_BLOCK_DATA = new ConstantDataLayer(0);
|
private static final ConstantDataLayer ALWAYS_0 = new ConstantDataLayer(0);
|
||||||
private static final ConstantDataLayer EMPTY_SKY_DATA = new ConstantDataLayer(15);
|
private static final ConstantDataLayer ALWAYS_15 = new ConstantDataLayer(15);
|
||||||
|
|
||||||
private final LevelAccessor level;
|
private final LevelAccessor level;
|
||||||
private final LightLut lut;
|
private final LightLut lut;
|
||||||
|
@ -268,29 +270,51 @@ public class LightStorage implements Effect {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataLayer getSkyData(long section) {
|
private DataLayer getSkyData(long section) {
|
||||||
var sky = level.getLightEngine()
|
var layerListener = level.getLightEngine()
|
||||||
.getLayerListener(LightLayer.SKY);
|
.getLayerListener(LightLayer.SKY);
|
||||||
var skyStorage = (SkyLightSectionStorageExtension) ((LightEngineAccessor<?, ?>) sky).flywheel$storage();
|
|
||||||
|
|
||||||
var out = skyStorage.flywheel$skyDataLayer(section);
|
if (layerListener == LayerLightEventListener.DummyLightLayerEventListener.INSTANCE) {
|
||||||
|
// The dummy listener always returns 0.
|
||||||
if (out == null) {
|
// In vanilla this happens in the nether and end,
|
||||||
return EMPTY_SKY_DATA;
|
// and the light texture is simply updated
|
||||||
|
// to be invariant on sky light.
|
||||||
|
return ALWAYS_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
if (layerListener instanceof LightEngineAccessor<?, ?> accessor) {
|
||||||
|
// Sky storage has a fancy way to get the sky light at a given block position, but the logic is not
|
||||||
|
// implemented in vanilla for fetching data layers directly. We need to re-implement it here. The simplest
|
||||||
|
// way to do it was to expose the same logic via an extension method. Re-implementing it external to the
|
||||||
|
// SkyLightSectionStorage class would require many more accessors.
|
||||||
|
if (accessor.flywheel$storage() instanceof SkyLightSectionStorageExtension skyStorage) {
|
||||||
|
var out = skyStorage.flywheel$skyDataLayer(section);
|
||||||
|
|
||||||
|
// Null section here means there are no blocks above us to darken this section.
|
||||||
|
return Objects.requireNonNullElse(out, ALWAYS_15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: We're likely in some exotic dimension that needs special handling.
|
||||||
|
return ALWAYS_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataLayer getBlockData(long section) {
|
private DataLayer getBlockData(long section) {
|
||||||
var out = ((LightEngineAccessor<?, ?>) level.getLightEngine()
|
var layerListener = level.getLightEngine()
|
||||||
.getLayerListener(LightLayer.BLOCK)).flywheel$storage()
|
.getLayerListener(LightLayer.BLOCK);
|
||||||
.getDataLayerData(section);
|
|
||||||
|
|
||||||
if (out == null) {
|
if (layerListener == LayerLightEventListener.DummyLightLayerEventListener.INSTANCE) {
|
||||||
return EMPTY_BLOCK_DATA;
|
return ALWAYS_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
if (layerListener instanceof LightEngineAccessor<?, ?> accessor) {
|
||||||
|
var out = accessor.flywheel$storage()
|
||||||
|
.getDataLayerData(section);
|
||||||
|
|
||||||
|
return Objects.requireNonNullElse(out, ALWAYS_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: We're likely in some exotic dimension that needs special handling.
|
||||||
|
return ALWAYS_0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectXStrip(long ptr, long section, SectionEdge y, SectionEdge z) {
|
private void collectXStrip(long ptr, long section, SectionEdge y, SectionEdge z) {
|
||||||
|
|
|
@ -109,11 +109,9 @@ public class IndirectBuffers {
|
||||||
GlBufferType.DRAW_INDIRECT_BUFFER.bind(draw.handle());
|
GlBufferType.DRAW_INDIRECT_BUFFER.bind(draw.handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind all buffers except the draw command buffer.
|
|
||||||
*/
|
|
||||||
public void bindForCrumbling() {
|
public void bindForCrumbling() {
|
||||||
multiBind(1, 4);
|
// All we need is the instance buffer. Crumbling uses its own draw buffer.
|
||||||
|
multiBind(BufferBindings.INSTANCE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void multiBind(int base, int count) {
|
private void multiBind(int base, int count) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package dev.engine_room.flywheel.backend.engine.indirect;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
|
||||||
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
|
import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT;
|
||||||
import static org.lwjgl.opengl.GL30.glUniform1ui;
|
|
||||||
import static org.lwjgl.opengl.GL42.GL_COMMAND_BARRIER_BIT;
|
import static org.lwjgl.opengl.GL42.GL_COMMAND_BARRIER_BIT;
|
||||||
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
|
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
|
||||||
import static org.lwjgl.opengl.GL43.glDispatchCompute;
|
import static org.lwjgl.opengl.GL43.glDispatchCompute;
|
||||||
|
@ -199,7 +198,6 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
drawBarrier();
|
drawBarrier();
|
||||||
|
|
||||||
GlProgram lastProgram = null;
|
GlProgram lastProgram = null;
|
||||||
int baseDrawUniformLoc = -1;
|
|
||||||
|
|
||||||
for (var multiDraw : multiDraws.get(visualType)) {
|
for (var multiDraw : multiDraws.get(visualType)) {
|
||||||
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material);
|
var drawProgram = programs.getIndirectProgram(instanceType, multiDraw.embedded ? ContextShader.EMBEDDED : ContextShader.DEFAULT, multiDraw.material);
|
||||||
|
@ -208,19 +206,16 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
|
|
||||||
// Don't need to do this unless the program changes.
|
// Don't need to do this unless the program changes.
|
||||||
drawProgram.bind();
|
drawProgram.bind();
|
||||||
baseDrawUniformLoc = drawProgram.getUniformLocation("_flw_baseDraw");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glUniform1ui(baseDrawUniformLoc, multiDraw.start);
|
|
||||||
|
|
||||||
MaterialRenderState.setup(multiDraw.material);
|
MaterialRenderState.setup(multiDraw.material);
|
||||||
|
|
||||||
multiDraw.submit();
|
multiDraw.submit(drawProgram);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindWithContextShader(ContextShader override, Material material) {
|
public void bindForCrumbling(Material material) {
|
||||||
var program = programs.getIndirectProgram(instanceType, override, material);
|
var program = programs.getIndirectProgram(instanceType, ContextShader.CRUMBLING, material);
|
||||||
|
|
||||||
program.bind();
|
program.bind();
|
||||||
|
|
||||||
|
@ -228,8 +223,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
|
|
||||||
drawBarrier();
|
drawBarrier();
|
||||||
|
|
||||||
var flwBaseDraw = program.getUniformLocation("_flw_baseDraw");
|
program.setUInt("_flw_baseDraw", 0);
|
||||||
glUniform1ui(flwBaseDraw, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void drawBarrier() {
|
private void drawBarrier() {
|
||||||
|
@ -290,8 +284,8 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private record MultiDraw(Material material, boolean embedded, int start, int end) {
|
private record MultiDraw(Material material, boolean embedded, int start, int end) {
|
||||||
private void submit() {
|
private void submit(GlProgram drawProgram) {
|
||||||
GlCompat.safeMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, this.start * IndirectBuffers.DRAW_COMMAND_STRIDE, this.end - this.start, (int) IndirectBuffers.DRAW_COMMAND_STRIDE);
|
GlCompat.safeMultiDrawElementsIndirect(drawProgram, GL_TRIANGLES, GL_UNSIGNED_INT, this.start, this.end, IndirectBuffers.DRAW_COMMAND_STRIDE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import dev.engine_room.flywheel.api.instance.Instance;
|
||||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||||
import dev.engine_room.flywheel.api.visualization.VisualType;
|
import dev.engine_room.flywheel.api.visualization.VisualType;
|
||||||
import dev.engine_room.flywheel.backend.Samplers;
|
import dev.engine_room.flywheel.backend.Samplers;
|
||||||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
|
||||||
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
import dev.engine_room.flywheel.backend.compile.IndirectPrograms;
|
||||||
import dev.engine_room.flywheel.backend.engine.AbstractInstancer;
|
import dev.engine_room.flywheel.backend.engine.AbstractInstancer;
|
||||||
import dev.engine_room.flywheel.backend.engine.CommonCrumbling;
|
import dev.engine_room.flywheel.backend.engine.CommonCrumbling;
|
||||||
|
@ -235,7 +234,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
||||||
// Transform the material to be suited for crumbling.
|
// Transform the material to be suited for crumbling.
|
||||||
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, draw.material());
|
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, draw.material());
|
||||||
|
|
||||||
cullingGroup.bindWithContextShader(ContextShader.CRUMBLING, crumblingMaterial);
|
cullingGroup.bindForCrumbling(crumblingMaterial);
|
||||||
|
|
||||||
MaterialRenderState.setup(crumblingMaterial);
|
MaterialRenderState.setup(crumblingMaterial);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,9 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
private final Vector4fc boundingSphere;
|
private final Vector4fc boundingSphere;
|
||||||
|
|
||||||
private final AtomicReference<InstancePage<I>[]> pages = new AtomicReference<>(pageArray(0));
|
private final AtomicReference<InstancePage<I>[]> pages = new AtomicReference<>(pageArray(0));
|
||||||
|
|
||||||
|
private final AtomicInteger instanceCount = new AtomicInteger(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The set of pages whose count changed and thus need their descriptor re-uploaded.
|
* The set of pages whose count changed and thus need their descriptor re-uploaded.
|
||||||
*/
|
*/
|
||||||
|
@ -145,6 +148,8 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
// We just filled the 17th instance, so we are no longer mergeable.
|
// We just filled the 17th instance, so we are no longer mergeable.
|
||||||
parent.mergeablePages.clear(pageNo);
|
parent.mergeablePages.clear(pageNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parent.instanceCount.incrementAndGet();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,6 +208,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
}
|
}
|
||||||
// Set full page last so that other threads don't race to set the other bitsets.
|
// Set full page last so that other threads don't race to set the other bitsets.
|
||||||
parent.fullPages.clear(pageNo);
|
parent.fullPages.clear(pageNo);
|
||||||
|
parent.instanceCount.decrementAndGet();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,9 +544,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||||
}
|
}
|
||||||
|
|
||||||
public int instanceCount() {
|
public int instanceCount() {
|
||||||
// Not exactly accurate but it's an upper bound.
|
return instanceCount.get();
|
||||||
// TODO: maybe this could be tracked with an AtomicInteger?
|
|
||||||
return pages.get().length << ObjectStorage.LOG_2_PAGE_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,7 @@ import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.backend.FlwBackend;
|
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||||
import dev.engine_room.flywheel.backend.compile.core.Compilation;
|
import dev.engine_room.flywheel.backend.compile.core.Compilation;
|
||||||
|
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||||
import dev.engine_room.flywheel.backend.glsl.GlslVersion;
|
import dev.engine_room.flywheel.backend.glsl.GlslVersion;
|
||||||
import dev.engine_room.flywheel.lib.math.MoreMath;
|
import dev.engine_room.flywheel.lib.math.MoreMath;
|
||||||
|
|
||||||
|
@ -78,15 +79,20 @@ public final class GlCompat {
|
||||||
* but uses consecutive DI instead of MDI if MDI is known to not work well with the current driver.
|
* but uses consecutive DI instead of MDI if MDI is known to not work well with the current driver.
|
||||||
* Unlike the original function, stride cannot be equal to 0.
|
* Unlike the original function, stride cannot be equal to 0.
|
||||||
*/
|
*/
|
||||||
public static void safeMultiDrawElementsIndirect(int mode, int type, long indirect, int drawcount, int stride) {
|
public static void safeMultiDrawElementsIndirect(GlProgram drawProgram, int mode, int type, int start, int end, long stride) {
|
||||||
|
var count = end - start;
|
||||||
|
long indirect = start * stride;
|
||||||
|
|
||||||
if (GlCompat.DRIVER == Driver.INTEL) {
|
if (GlCompat.DRIVER == Driver.INTEL) {
|
||||||
// Intel renders garbage with MDI, but consecutive DI works fine.
|
// Intel renders garbage with MDI, but consecutive DI works "fine".
|
||||||
for (int i = 0; i < drawcount; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
|
drawProgram.setUInt("_flw_baseDraw", start + i);
|
||||||
GL40.glDrawElementsIndirect(mode, type, indirect);
|
GL40.glDrawElementsIndirect(mode, type, indirect);
|
||||||
indirect += stride;
|
indirect += stride;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GL43.glMultiDrawElementsIndirect(mode, type, indirect, drawcount, stride);
|
drawProgram.setUInt("_flw_baseDraw", start);
|
||||||
|
GL43.glMultiDrawElementsIndirect(mode, type, indirect, count, (int) stride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.engine_room.flywheel.lib.vertex;
|
package dev.engine_room.flywheel.lib.vertex;
|
||||||
|
|
||||||
import dev.engine_room.flywheel.api.vertex.MutableVertexList;
|
import dev.engine_room.flywheel.api.vertex.MutableVertexList;
|
||||||
import net.minecraft.client.renderer.LightTexture;
|
|
||||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||||
|
|
||||||
public interface DefaultVertexList extends MutableVertexList {
|
public interface DefaultVertexList extends MutableVertexList {
|
||||||
|
@ -57,7 +56,7 @@ public interface DefaultVertexList extends MutableVertexList {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default int light(int index) {
|
default int light(int index) {
|
||||||
return LightTexture.FULL_BRIGHT;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,5 +6,5 @@ void flw_instanceVertex(in FlwInstance i) {
|
||||||
flw_vertexColor *= i.color;
|
flw_vertexColor *= i.color;
|
||||||
flw_vertexOverlay = i.overlay;
|
flw_vertexOverlay = i.overlay;
|
||||||
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
||||||
flw_vertexLight = vec2(i.light) / 256.0;
|
flw_vertexLight = max(vec2(i.light) / 256.0, flw_vertexLight);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ void flw_instanceVertex(in FlwInstance i) {
|
||||||
flw_vertexColor *= i.color;
|
flw_vertexColor *= i.color;
|
||||||
flw_vertexOverlay = i.overlay;
|
flw_vertexOverlay = i.overlay;
|
||||||
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
||||||
flw_vertexLight = vec2(i.light) / 256.0;
|
flw_vertexLight = max(vec2(i.light) / 256.0, flw_vertexLight);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,5 @@ void flw_instanceVertex(in FlwInstance i) {
|
||||||
flw_vertexColor *= i.color;
|
flw_vertexColor *= i.color;
|
||||||
flw_vertexOverlay = i.overlay;
|
flw_vertexOverlay = i.overlay;
|
||||||
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
// Some drivers have a bug where uint over float division is invalid, so use an explicit cast.
|
||||||
flw_vertexLight = vec2(i.light) / 256.0;
|
flw_vertexLight = max(vec2(i.light) / 256.0, flw_vertexLight);
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ final class BakedModelBufferer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ThreadLocalObjects {
|
private static class ThreadLocalObjects {
|
||||||
public final FabricOriginBlockAndTintGetter level = new FabricOriginBlockAndTintGetter(p -> 0, p -> 15);
|
public final FabricOriginBlockAndTintGetter level = new FabricOriginBlockAndTintGetter(p -> 0, p -> 0);
|
||||||
public final PoseStack identityPoseStack = new PoseStack();
|
public final PoseStack identityPoseStack = new PoseStack();
|
||||||
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ final class BakedModelBufferer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class ThreadLocalObjects {
|
private static class ThreadLocalObjects {
|
||||||
public final OriginBlockAndTintGetter level = new OriginBlockAndTintGetter(p -> 0, p -> 15);
|
public final OriginBlockAndTintGetter level = new OriginBlockAndTintGetter(p -> 0, p -> 0);
|
||||||
public final PoseStack identityPoseStack = new PoseStack();
|
public final PoseStack identityPoseStack = new PoseStack();
|
||||||
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
public final RandomSource random = RandomSource.createNewThreadLocalInstance();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue