mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-25 11:25:34 +01:00
Indirectly lit
- "Functional" arena based lighting for indirect - Strip out most of the reference counting stuffs for embeddings - Naively re-buffer all tracked light sections every frame
This commit is contained in:
parent
e10852fe7a
commit
51224d618f
26 changed files with 134 additions and 110 deletions
|
@ -8,5 +8,4 @@ public class Samplers {
|
|||
public static final GlTextureUnit LIGHT = GlTextureUnit.T2;
|
||||
public static final GlTextureUnit CRUMBLING = GlTextureUnit.T3;
|
||||
public static final GlTextureUnit INSTANCE_BUFFER = GlTextureUnit.T4;
|
||||
public static final GlTextureUnit EMBEDDED_LIGHT = GlTextureUnit.T5;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ public enum ContextShader {
|
|||
DEFAULT(null, $ -> {
|
||||
}),
|
||||
CRUMBLING("_FLW_CRUMBLING", program -> program.setSamplerBinding("_flw_crumblingTex", Samplers.CRUMBLING)),
|
||||
EMBEDDED("_FLW_EMBEDDED", program -> program.setSamplerBinding("_flw_lightVolume", Samplers.EMBEDDED_LIGHT));
|
||||
EMBEDDED("_FLW_EMBEDDED", $ -> {});
|
||||
|
||||
@Nullable
|
||||
private final String define;
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.ArrayList;
|
|||
import dev.engine_room.flywheel.api.Flywheel;
|
||||
import dev.engine_room.flywheel.api.instance.InstanceType;
|
||||
import dev.engine_room.flywheel.api.layout.Layout;
|
||||
import dev.engine_room.flywheel.backend.engine.indirect.IndirectBuffers;
|
||||
import dev.engine_room.flywheel.backend.engine.indirect.BufferBindings;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.FnSignature;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import dev.engine_room.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
|
@ -43,7 +43,7 @@ public class SsboInstanceComponent extends InstanceAssemblerComponent {
|
|||
|
||||
fnBody.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
|
||||
|
||||
builder._addRaw("layout(std430, binding = " + IndirectBuffers.INSTANCE_INDEX + ") restrict readonly buffer InstanceBuffer {\n"
|
||||
builder._addRaw("layout(std430, binding = " + BufferBindings.INSTANCE_BUFFER_BINDING + ") restrict readonly buffer InstanceBuffer {\n"
|
||||
+ " uint _flw_instances[];\n"
|
||||
+ "};");
|
||||
builder.blankLine();
|
||||
|
|
|
@ -25,8 +25,6 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
|||
protected AbstractInstancer(InstanceType<I> type, Environment environment) {
|
||||
this.type = type;
|
||||
this.environment = environment;
|
||||
|
||||
environment.acquire();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -177,9 +175,7 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
|||
deleted.clear();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
environment.release();
|
||||
}
|
||||
public abstract void delete();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
|
|
@ -16,6 +16,7 @@ import dev.engine_room.flywheel.api.instance.Instancer;
|
|||
import dev.engine_room.flywheel.api.model.Model;
|
||||
import dev.engine_room.flywheel.backend.FlwBackend;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.Environment;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
|
||||
import dev.engine_room.flywheel.lib.util.Pair;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
@ -45,7 +46,7 @@ public abstract class DrawManager<N extends AbstractInstancer<?>> {
|
|||
initializationQueue.clear();
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
public void flush(LightStorage lightStorage) {
|
||||
// Thread safety: flush is called from the render thread after all visual updates have been made,
|
||||
// so there are no:tm: threads we could be racing with.
|
||||
for (var instancer : initializationQueue) {
|
||||
|
|
|
@ -31,7 +31,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
public class EngineImpl implements Engine {
|
||||
private final int sqrMaxOriginDistance;
|
||||
private final DrawManager<? extends AbstractInstancer<?>> drawManager;
|
||||
private final EnvironmentStorage environmentStorage = new EnvironmentStorage();
|
||||
private final EnvironmentStorage environmentStorage;
|
||||
private final LightStorage lightStorage;
|
||||
private final Flag flushFlag = new NamedFlag("flushed");
|
||||
|
||||
|
@ -40,12 +40,13 @@ public class EngineImpl implements Engine {
|
|||
public EngineImpl(LevelAccessor level, DrawManager<? extends AbstractInstancer<?>> drawManager, int maxOriginDistance) {
|
||||
this.drawManager = drawManager;
|
||||
sqrMaxOriginDistance = maxOriginDistance * maxOriginDistance;
|
||||
lightStorage = new LightStorage(level);
|
||||
environmentStorage = new EnvironmentStorage();
|
||||
lightStorage = new LightStorage(level, environmentStorage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plan<RenderContext> createFramePlan() {
|
||||
return SyncedPlan.of(this::flush);
|
||||
return lightStorage.createFramePlan().then(SyncedPlan.of(this::flush));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,7 +97,6 @@ public class EngineImpl implements Engine {
|
|||
@Override
|
||||
public void delete() {
|
||||
drawManager.delete();
|
||||
environmentStorage.delete();
|
||||
lightStorage.delete();
|
||||
}
|
||||
|
||||
|
@ -107,8 +107,8 @@ public class EngineImpl implements Engine {
|
|||
private void flush(RenderContext ctx) {
|
||||
try (var state = GlStateTracker.getRestoreState()) {
|
||||
Uniforms.update(ctx);
|
||||
drawManager.flush();
|
||||
environmentStorage.flush();
|
||||
drawManager.flush(lightStorage);
|
||||
}
|
||||
|
||||
flushFlag.raise();
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package dev.engine_room.flywheel.backend.engine;
|
||||
|
||||
import dev.engine_room.flywheel.backend.engine.embed.AbstractEmbeddedEnvironment;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceLinkedOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceSet;
|
||||
import it.unimi.dsi.fastutil.objects.ReferenceSets;
|
||||
|
@ -13,10 +15,13 @@ public class EnvironmentStorage {
|
|||
}
|
||||
|
||||
public void flush() {
|
||||
environments.removeIf(AbstractEmbeddedEnvironment::isDeleted);
|
||||
environments.forEach(AbstractEmbeddedEnvironment::flush);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
environments.clear();
|
||||
public LongSet allLightSections() {
|
||||
var out = new LongOpenHashSet();
|
||||
environments.forEach(e -> e.addLightSections(out));
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,10 +15,10 @@ import dev.engine_room.flywheel.api.visualization.VisualEmbedding;
|
|||
import dev.engine_room.flywheel.backend.compile.ContextShader;
|
||||
import dev.engine_room.flywheel.backend.engine.EngineImpl;
|
||||
import dev.engine_room.flywheel.backend.gl.shader.GlProgram;
|
||||
import dev.engine_room.flywheel.backend.util.AtomicReferenceCounted;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
||||
public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted implements Environment, VisualEmbedding {
|
||||
public abstract class AbstractEmbeddedEnvironment implements Environment, VisualEmbedding {
|
||||
protected final Matrix4f pose = new Matrix4f();
|
||||
protected final Matrix3f normal = new Matrix3f();
|
||||
private final Matrix4f poseComposed = new Matrix4f();
|
||||
|
@ -27,6 +27,8 @@ public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted
|
|||
protected final EngineImpl engine;
|
||||
private final RenderStage renderStage;
|
||||
|
||||
private boolean deleted = false;
|
||||
|
||||
public AbstractEmbeddedEnvironment(EngineImpl engine, RenderStage renderStage) {
|
||||
this.engine = engine;
|
||||
this.renderStage = renderStage;
|
||||
|
@ -38,9 +40,6 @@ public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted
|
|||
return engine.instancer(AbstractEmbeddedEnvironment.this, type, model, renderStage);
|
||||
}
|
||||
};
|
||||
|
||||
// Acquire the reference owned by the visual that created this.
|
||||
acquire();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,15 +93,20 @@ public abstract class AbstractEmbeddedEnvironment extends AtomicReferenceCounted
|
|||
return out;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void addLightSections(LongSet out) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by visuals
|
||||
*/
|
||||
@Override
|
||||
public void delete() {
|
||||
// Release the reference owned by the visual that created this.
|
||||
// Note that visuals don't explicitly call acquire, instead the
|
||||
// storage acquired a reference when this was constructed.
|
||||
release();
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
public abstract void setupLight(GlProgram program);
|
||||
|
|
|
@ -47,4 +47,8 @@ public class Arena {
|
|||
public void delete() {
|
||||
memoryBlock.free();
|
||||
}
|
||||
|
||||
public int capacity() {
|
||||
return top;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,4 @@ public interface Environment {
|
|||
void setupDraw(GlProgram drawProgram);
|
||||
|
||||
void setupCull(GlProgram cullProgram);
|
||||
|
||||
void acquire();
|
||||
|
||||
void release();
|
||||
}
|
||||
|
|
|
@ -23,14 +23,4 @@ public class GlobalEnvironment implements Environment {
|
|||
public void setupCull(GlProgram cullProgram) {
|
||||
cullProgram.setBool(EmbeddingUniforms.USE_MODEL_MATRIX, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acquire() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,11 @@ import java.util.BitSet;
|
|||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import dev.engine_room.flywheel.api.event.RenderContext;
|
||||
import dev.engine_room.flywheel.api.task.Plan;
|
||||
import dev.engine_room.flywheel.backend.engine.EnvironmentStorage;
|
||||
import dev.engine_room.flywheel.backend.engine.indirect.StagingBuffer;
|
||||
import dev.engine_room.flywheel.lib.task.SimplePlan;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
|
@ -29,11 +33,12 @@ import net.minecraft.world.level.LightLayer;
|
|||
* <p>Thus, each section occupies 5832 bytes.
|
||||
*/
|
||||
public class LightStorage {
|
||||
private final long SECTION_SIZE_BYTES = 9 * 9 * 9 * 8;
|
||||
private final int DEFAULT_ARENA_CAPACITY_SECTIONS = 64;
|
||||
private final int INVALID_SECTION = -1;
|
||||
public static final long SECTION_SIZE_BYTES = 9 * 9 * 9 * 8;
|
||||
private static final int DEFAULT_ARENA_CAPACITY_SECTIONS = 64;
|
||||
private static final int INVALID_SECTION = -1;
|
||||
|
||||
private final LevelAccessor level;
|
||||
private final EnvironmentStorage environmentStorage;
|
||||
|
||||
private final Arena arena;
|
||||
private final Long2IntMap section2ArenaIndex = new Long2IntOpenHashMap();
|
||||
|
@ -44,12 +49,24 @@ public class LightStorage {
|
|||
private final BitSet changed = new BitSet();
|
||||
private boolean newSections = false;
|
||||
|
||||
public LightStorage(LevelAccessor level) {
|
||||
public LightStorage(LevelAccessor level, EnvironmentStorage environmentStorage) {
|
||||
this.level = level;
|
||||
this.environmentStorage = environmentStorage;
|
||||
|
||||
arena = new Arena(SECTION_SIZE_BYTES, DEFAULT_ARENA_CAPACITY_SECTIONS);
|
||||
}
|
||||
|
||||
public Plan<RenderContext> createFramePlan() {
|
||||
return SimplePlan.of(() -> {
|
||||
var longs = environmentStorage.allLightSections();
|
||||
longs.forEach(this::addSection);
|
||||
});
|
||||
}
|
||||
|
||||
public int capacity() {
|
||||
return arena.capacity();
|
||||
}
|
||||
|
||||
public void addSection(long section) {
|
||||
var lightEngine = level.getLightEngine();
|
||||
|
||||
|
@ -187,6 +204,7 @@ public class LightStorage {
|
|||
for (int i = changed.nextSetBit(0); i >= 0; i = changed.nextSetBit(i + 1)) {
|
||||
staging.enqueueCopy(arena.indexToPointer(i), SECTION_SIZE_BYTES, dstVbo, i * SECTION_SIZE_BYTES);
|
||||
}
|
||||
changed.clear();
|
||||
}
|
||||
|
||||
public IntArrayList createLut() {
|
||||
|
|
|
@ -14,7 +14,6 @@ public class NestedEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
|
|||
public NestedEmbeddedEnvironment(AbstractEmbeddedEnvironment parent, EngineImpl engine, RenderStage renderStage) {
|
||||
super(engine, renderStage);
|
||||
this.parent = parent;
|
||||
parent.acquire();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -33,9 +32,4 @@ public class NestedEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
|
|||
pose.mul(this.pose);
|
||||
normal.mul(this.normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void _delete() {
|
||||
parent.release();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,19 +16,17 @@ public class TopLevelEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
|
|||
super(engine, renderStage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
super.flush();
|
||||
|
||||
lightSections.forEach(engine.lightStorage()::addSection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lightChunks(LongSet chunks) {
|
||||
lightSections.clear();
|
||||
lightSections.addAll(chunks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addLightSections(LongSet out) {
|
||||
out.addAll(lightSections);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupLight(GlProgram program) {
|
||||
program.setBool(EmbeddingUniforms.USE_LIGHT_VOLUME, !lightSections.isEmpty());
|
||||
|
@ -39,9 +37,4 @@ public class TopLevelEmbeddedEnvironment extends AbstractEmbeddedEnvironment {
|
|||
pose.set(this.pose);
|
||||
normal.set(this.normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _delete() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package dev.engine_room.flywheel.backend.engine.indirect;
|
||||
|
||||
public class BufferBindings {
|
||||
public static final int INSTANCE_BUFFER_BINDING = 0;
|
||||
public static final int TARGET_BUFFER_BINDING = 1;
|
||||
public static final int MODEL_INDEX_BUFFER_BINDING = 2;
|
||||
public static final int MODEL_BUFFER_BINDING = 3;
|
||||
public static final int DRAW_BUFFER_BINDING = 4;
|
||||
public static final int EMBEDDING_LUT_BINDING = 5;
|
||||
public static final int EMBEDDING_LIGHT_BINDING = 6;
|
||||
|
||||
private BufferBindings() {
|
||||
}
|
||||
}
|
|
@ -22,13 +22,6 @@ public class IndirectBuffers {
|
|||
public static final long DRAW_COMMAND_STRIDE = 40;
|
||||
public static final long DRAW_COMMAND_OFFSET = 0;
|
||||
|
||||
public static final int INSTANCE_INDEX = 0;
|
||||
public static final int TARGET_INDEX = 1;
|
||||
public static final int MODEL_INDEX_INDEX = 2;
|
||||
public static final int MODEL_INDEX = 3;
|
||||
public static final int DRAW_INDEX = 4;
|
||||
|
||||
|
||||
// Offsets to the 3 segments
|
||||
private static final long HANDLE_OFFSET = 0;
|
||||
private static final long OFFSET_OFFSET = BUFFER_COUNT * INT_SIZE;
|
||||
|
@ -117,7 +110,7 @@ public class IndirectBuffers {
|
|||
|
||||
private void multiBind() {
|
||||
final long ptr = multiBindBlock.ptr();
|
||||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, IndirectBuffers.BUFFER_COUNT, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE_BUFFER_BINDING, IndirectBuffers.BUFFER_COUNT, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +118,7 @@ public class IndirectBuffers {
|
|||
*/
|
||||
public void bindForCrumbling() {
|
||||
final long ptr = multiBindBlock.ptr();
|
||||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, 4, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.INSTANCE_BUFFER_BINDING, 4, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
|
@ -23,6 +23,7 @@ import dev.engine_room.flywheel.backend.engine.InstancerKey;
|
|||
import dev.engine_room.flywheel.backend.engine.MaterialRenderState;
|
||||
import dev.engine_room.flywheel.backend.engine.MeshPool;
|
||||
import dev.engine_room.flywheel.backend.engine.TextureBinder;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
|
||||
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
|
||||
import dev.engine_room.flywheel.backend.gl.array.GlVertexArray;
|
||||
|
@ -40,6 +41,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||
private final Map<GroupKey<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
|
||||
private final GlBuffer crumblingDrawBuffer = new GlBuffer();
|
||||
|
||||
private final LightBuffers lightBuffers;
|
||||
|
||||
public IndirectDrawManager(IndirectPrograms programs) {
|
||||
this.programs = programs;
|
||||
programs.acquire();
|
||||
|
@ -50,6 +53,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||
vertexArray = GlVertexArray.create();
|
||||
|
||||
meshPool.bind(vertexArray);
|
||||
lightBuffers = new LightBuffers();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,6 +87,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||
TextureBinder.bindLightAndOverlay();
|
||||
|
||||
vertexArray.bindForDraw();
|
||||
lightBuffers.bind();
|
||||
Uniforms.bindAll();
|
||||
|
||||
for (var group : cullingGroups.values()) {
|
||||
|
@ -95,8 +100,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
super.flush();
|
||||
public void flush(LightStorage lightStorage) {
|
||||
super.flush(lightStorage);
|
||||
|
||||
for (var group : cullingGroups.values()) {
|
||||
group.flushInstancers();
|
||||
|
@ -108,6 +113,8 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||
|
||||
stagingBuffer.reclaim();
|
||||
|
||||
lightBuffers.flush(stagingBuffer, lightStorage);
|
||||
|
||||
for (var group : cullingGroups.values()) {
|
||||
group.upload(stagingBuffer);
|
||||
}
|
||||
|
@ -159,7 +166,7 @@ public class IndirectDrawManager extends DrawManager<IndirectInstancer<?>> {
|
|||
var block = MemoryBlock.malloc(IndirectBuffers.DRAW_COMMAND_STRIDE);
|
||||
|
||||
GlBufferType.DRAW_INDIRECT_BUFFER.bind(crumblingDrawBuffer.handle());
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, IndirectBuffers.DRAW_INDEX, crumblingDrawBuffer.handle(), 0, IndirectBuffers.DRAW_COMMAND_STRIDE);
|
||||
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BufferBindings.DRAW_BUFFER_BINDING, crumblingDrawBuffer.handle(), 0, IndirectBuffers.DRAW_COMMAND_STRIDE);
|
||||
|
||||
for (var groupEntry : byType.entrySet()) {
|
||||
var byProgress = groupEntry.getValue();
|
||||
|
|
|
@ -125,8 +125,6 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
|
||||
@Override
|
||||
public void delete() {
|
||||
super.delete();
|
||||
|
||||
for (IndirectDraw draw : draws()) {
|
||||
draw.delete();
|
||||
}
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
package dev.engine_room.flywheel.backend.engine.indirect;
|
||||
|
||||
import org.lwjgl.opengl.GL46;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
|
||||
|
||||
public class LightBuffers {
|
||||
private final ResizableStorageBuffer lightArena = new ResizableStorageBuffer();
|
||||
private final ResizableStorageArray lightArena = new ResizableStorageArray(LightStorage.SECTION_SIZE_BYTES);
|
||||
private final ResizableStorageArray lut = new ResizableStorageArray(4);
|
||||
|
||||
public LightBuffers() {
|
||||
}
|
||||
|
||||
public void flush(StagingBuffer staging, LightStorage light) {
|
||||
var capacity = light.capacity();
|
||||
|
||||
if (capacity == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
lightArena.ensureCapacity(capacity);
|
||||
light.uploadChangedSections(staging, lightArena.handle());
|
||||
|
||||
if (light.hasNewSections()) {
|
||||
|
@ -26,4 +34,13 @@ public class LightBuffers {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
if (lightArena.capacity() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.EMBEDDING_LUT_BINDING, lut.handle(), 0, lut.byteCapacity());
|
||||
GL46.glBindBufferRange(GL46.GL_SHADER_STORAGE_BUFFER, BufferBindings.EMBEDDING_LIGHT_BINDING, lightArena.handle(), 0, lightArena.byteCapacity());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import dev.engine_room.flywheel.backend.engine.MaterialEncoder;
|
|||
import dev.engine_room.flywheel.backend.engine.MaterialRenderState;
|
||||
import dev.engine_room.flywheel.backend.engine.MeshPool;
|
||||
import dev.engine_room.flywheel.backend.engine.TextureBinder;
|
||||
import dev.engine_room.flywheel.backend.engine.embed.LightStorage;
|
||||
import dev.engine_room.flywheel.backend.engine.uniform.Uniforms;
|
||||
import dev.engine_room.flywheel.backend.gl.GlStateTracker;
|
||||
import dev.engine_room.flywheel.backend.gl.TextureBuffer;
|
||||
|
@ -55,8 +56,8 @@ public class InstancedDrawManager extends DrawManager<InstancedInstancer<?>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
super.flush();
|
||||
public void flush(LightStorage lightStorage) {
|
||||
super.flush(lightStorage);
|
||||
|
||||
var instancers = this.instancers.values();
|
||||
instancers.removeIf(instancer -> {
|
||||
|
|
|
@ -116,8 +116,6 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
}
|
||||
|
||||
public void delete() {
|
||||
super.delete();
|
||||
|
||||
if (vbo == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,14 +13,6 @@ uniform sampler2D _flw_crumblingTex;
|
|||
in vec2 _flw_crumblingTexCoord;
|
||||
#endif
|
||||
|
||||
#ifdef _FLW_EMBEDDED
|
||||
uniform sampler3D _flw_lightVolume;
|
||||
|
||||
uniform bool _flw_useLightVolume;
|
||||
|
||||
in vec3 _flw_lightVolumeCoord;
|
||||
#endif
|
||||
|
||||
flat in uint _flw_instanceID;
|
||||
|
||||
out vec4 _flw_outputColor;
|
||||
|
@ -43,12 +35,6 @@ void _flw_main() {
|
|||
flw_fragOverlay = flw_vertexOverlay;
|
||||
flw_fragLight = flw_vertexLight;
|
||||
|
||||
#ifdef _FLW_EMBEDDED
|
||||
if (_flw_useLightVolume) {
|
||||
flw_fragLight = max(flw_fragLight, texture(_flw_lightVolume, _flw_lightVolumeCoord).rg);
|
||||
}
|
||||
#endif
|
||||
|
||||
flw_materialFragment();
|
||||
|
||||
#ifdef _FLW_CRUMBLING
|
||||
|
@ -98,11 +84,6 @@ void _flw_main() {
|
|||
case 6u:
|
||||
color = vec4(vec3(diffuseFactor), 1.);
|
||||
break;
|
||||
#ifdef _FLW_EMBEDDED
|
||||
case 7u:
|
||||
color = vec4(_flw_lightVolumeCoord, 1.);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
_flw_outputColor = flw_fogFilter(color);
|
||||
|
|
|
@ -70,7 +70,7 @@ vec2 getCrumblingTexCoord() {
|
|||
uniform mat4 _flw_modelMatrix;
|
||||
uniform mat3 _flw_normalMatrix;
|
||||
|
||||
bool _flw_embeddedLight(vec3 worldPos, vec3 normal, out vec2 lightCoord);
|
||||
bool _flw_embeddedLight(vec3 worldPos, out vec2 lightCoord);
|
||||
#endif
|
||||
|
||||
flat out uint _flw_instanceID;
|
||||
|
@ -89,7 +89,7 @@ void _flw_main(in FlwInstance instance, in uint stableInstanceID) {
|
|||
flw_vertexNormal = _flw_normalMatrix * flw_vertexNormal;
|
||||
|
||||
vec2 embeddedLight;
|
||||
if (_flw_embeddedLight(flw_vertexPos, flw_vertexNormal, embeddedLight)) {
|
||||
if (_flw_embeddedLight(flw_vertexPos.xyz, embeddedLight)) {
|
||||
flw_vertexLight = max(flw_vertexLight, embeddedLight);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3,3 +3,5 @@
|
|||
#define _FLW_MODEL_INDEX_BUFFER_BINDING 2
|
||||
#define _FLW_MODEL_BUFFER_BINDING 3
|
||||
#define _FLW_DRAW_BUFFER_BINDING 4
|
||||
#define _FLW_EMBEDDING_LUT_BINDING 5
|
||||
#define _FLW_EMBEDDING_LIGHT_BINDING 6
|
||||
|
|
|
@ -13,24 +13,33 @@ layout(std430, binding = _FLW_DRAW_BUFFER_BINDING) restrict readonly buffer Draw
|
|||
|
||||
#ifdef _FLW_EMBEDDED
|
||||
|
||||
layout(std430, binding = 8) restrict readonly buffer EmbeddingLut {
|
||||
layout(std430, binding = _FLW_EMBEDDING_LUT_BINDING) restrict readonly buffer EmbeddingLut {
|
||||
uint _flw_embeddingLut[];
|
||||
};
|
||||
|
||||
const uint _FLW_LIGHT_SECTION_SIZE_BYTES = 18 * 18 * 18;
|
||||
const uint _FLW_LIGHT_SECTION_SIZE_INTS = _FLW_LIGHT_SECTION_SIZE_BYTES / 4;
|
||||
|
||||
layout(std430, binding = 9) restrict readonly buffer LightSections {
|
||||
layout(std430, binding = _FLW_EMBEDDING_LIGHT_BINDING) restrict readonly buffer LightSections {
|
||||
uint _flw_lightSections[];
|
||||
};
|
||||
|
||||
/// Find the index for the next step in the LUT.
|
||||
/// @param base The base index in the LUT, should point to the start of a coordinate span.
|
||||
/// @param coord The coordinate to look for.
|
||||
/// @param next Output. The index of the next step in the LUT.
|
||||
/// @return true if the coordinate is not in the span.
|
||||
bool _flw_nextLut(uint base, int coord, out uint next) {
|
||||
// The base coordinate.
|
||||
int start = int(_flw_embeddingLut[base]);
|
||||
// The width of the coordinate span.
|
||||
uint size = _flw_embeddingLut[base + 1];
|
||||
|
||||
// Index of the coordinate in the span.
|
||||
int i = coord - start;
|
||||
|
||||
if (i < 0 || i >= size) {
|
||||
// We missed.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -52,25 +61,29 @@ bool _flw_chunkCoordToSectionIndex(ivec3 sectionPos, out uint index) {
|
|||
return _flw_nextLut(z, sectionPos.z, index);
|
||||
}
|
||||
|
||||
vec2 _flw_lightAt(uint sectionOffset, ivec3 blockInSectionPos) {
|
||||
vec2 _flw_lightAt(uint sectionOffset, uvec3 blockInSectionPos) {
|
||||
uint byteOffset = blockInSectionPos.x + blockInSectionPos.z * 18u + blockInSectionPos.y * 18u * 18u;
|
||||
|
||||
uint uintOffset = byteOffset >> 2u;
|
||||
uint bitOffset = (byteOffset & 3u) << 3;
|
||||
|
||||
uint packed = _flw_lightSections[sectionOffset + uintOffset];
|
||||
uint block = (packed >> bitOffset) & 0xFu;
|
||||
uint sky = (packed >> (bitOffset + 4u)) & 0xFu;
|
||||
uint raw = _flw_lightSections[sectionOffset + uintOffset];
|
||||
uint block = (raw >> bitOffset) & 0xFu;
|
||||
uint sky = (raw >> (bitOffset + 4u)) & 0xFu;
|
||||
|
||||
return vec2(block, sky);
|
||||
}
|
||||
|
||||
bool _flw_embeddedLight(vec3 worldPos, vec3 normal, out vec2 lightCoord) {
|
||||
bool _flw_embeddedLight(vec3 worldPos, out vec2 lightCoord) {
|
||||
ivec3 blockPos = ivec3(floor(worldPos));
|
||||
|
||||
ivec3 sectionPos = blockPos >> 4;
|
||||
uvec3 blockInSectionPos = (blockPos & 0xF) + 1;
|
||||
|
||||
uint lightSectionIndex;
|
||||
if (_flw_chunkCoordToSectionIndex(sectionPos, lightSectionIndex)) {
|
||||
// TODO: useful debug mode for this.
|
||||
// flw_vertexOverlay = ivec2(0, 3);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ uniform uvec4 _flw_packedMaterial;
|
|||
uniform int _flw_baseInstance = 0;
|
||||
|
||||
#ifdef _FLW_EMBEDDED
|
||||
bool _flw_embeddedLight(vec3 worldPos, vec3 normal, out vec2 lightCoord) {
|
||||
bool _flw_embeddedLight(vec3 worldPos, out vec2 lightCoord) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue