mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Indirectly materialized
- Pass material IDs through the indirect draw buffer - Turns out buffers can be bound to both storage and draw indirect - Use indexOf in ComponentRegistry to determine IDs - Remove World/Crumbling Program and move sampler binding to ContextShader setup
This commit is contained in:
parent
d197fe0a4f
commit
80001f0037
15 changed files with 76 additions and 128 deletions
|
@ -4,7 +4,7 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
|||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public interface Context {
|
||||
void setup(GlProgram program);
|
||||
void onProgramLink(GlProgram program);
|
||||
|
||||
FileResolution vertexShader();
|
||||
|
||||
|
|
|
@ -3,11 +3,14 @@ package com.jozufozu.flywheel.api.context;
|
|||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader,
|
||||
FileResolution fragmentShader) implements Context {
|
||||
public record ContextShader(FileResolution vertexShader, FileResolution fragmentShader) implements Context {
|
||||
@Override
|
||||
public void setup(GlProgram program) {
|
||||
|
||||
public void onProgramLink(GlProgram program) {
|
||||
program.bind();
|
||||
program.setSamplerBinding("flw_diffuseTex", 0);
|
||||
program.setSamplerBinding("flw_overlayTex", 1);
|
||||
program.setSamplerBinding("flw_lightTex", 2);
|
||||
GlProgram.unbind();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,8 +2,6 @@ package com.jozufozu.flywheel.backend.gl.shader;
|
|||
|
||||
import static org.lwjgl.opengl.GL20.*;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
||||
|
@ -15,7 +13,6 @@ public class GlProgram extends GlObject {
|
|||
setHandle(handle);
|
||||
}
|
||||
|
||||
// TODO: Programs bind the uniform buffers they need, no more GlProgram inheritance
|
||||
public void bind() {
|
||||
// TODO: bind textures?
|
||||
UniformBuffer.getInstance()
|
||||
|
@ -48,17 +45,13 @@ public class GlProgram extends GlObject {
|
|||
*
|
||||
* @param name The name of the sampler uniform.
|
||||
* @param binding The index of the texture unit.
|
||||
* @return The sampler uniform's index.
|
||||
* @throws NullPointerException If no uniform exists with the given name.
|
||||
*/
|
||||
public int setSamplerBinding(String name, int binding) {
|
||||
public void setSamplerBinding(String name, int binding) {
|
||||
int samplerUniform = getUniformLocation(name);
|
||||
|
||||
if (samplerUniform >= 0) {
|
||||
glUniform1i(samplerUniform, binding);
|
||||
}
|
||||
|
||||
return samplerUniform;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,11 +59,4 @@ public class GlProgram extends GlObject {
|
|||
glDeleteProgram(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory interface to create a {@link GlProgram}.
|
||||
*/
|
||||
public interface Factory {
|
||||
|
||||
@NotNull GlProgram create(int handle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ public class FlwCompiler {
|
|||
|
||||
var glProgram = link(vertex.handle(), fragment.handle());
|
||||
ctx.contextShader()
|
||||
.setup(glProgram);
|
||||
.onProgramLink(glProgram);
|
||||
pipelinePrograms.put(ctx, glProgram);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.indirect;
|
||||
|
||||
import static org.lwjgl.opengl.GL45.glCreateBuffers;
|
||||
import static org.lwjgl.opengl.GL46.GL_DRAW_INDIRECT_BUFFER;
|
||||
import static org.lwjgl.opengl.GL46.GL_DYNAMIC_STORAGE_BIT;
|
||||
import static org.lwjgl.opengl.GL46.GL_MAP_FLUSH_EXPLICIT_BIT;
|
||||
import static org.lwjgl.opengl.GL46.GL_MAP_PERSISTENT_BIT;
|
||||
import static org.lwjgl.opengl.GL46.GL_MAP_WRITE_BIT;
|
||||
import static org.lwjgl.opengl.GL46.GL_SHADER_STORAGE_BUFFER;
|
||||
import static org.lwjgl.opengl.GL46.glBindBuffer;
|
||||
import static org.lwjgl.opengl.GL46.glCopyNamedBufferSubData;
|
||||
import static org.lwjgl.opengl.GL46.glDeleteBuffers;
|
||||
import static org.lwjgl.opengl.GL46.glFlushMappedNamedBufferRange;
|
||||
import static org.lwjgl.opengl.GL46.glNamedBufferStorage;
|
||||
import static org.lwjgl.opengl.GL46.nglBindBuffersRange;
|
||||
import static org.lwjgl.opengl.GL46.nglCreateBuffers;
|
||||
import static org.lwjgl.opengl.GL46.nglDeleteBuffers;
|
||||
import static org.lwjgl.opengl.GL46.nglMapNamedBufferRange;
|
||||
import static org.lwjgl.opengl.GL46.nglNamedBufferSubData;
|
||||
import static org.lwjgl.opengl.GL46.*;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
import org.lwjgl.system.Pointer;
|
||||
|
@ -30,7 +15,7 @@ public class IndirectBuffers {
|
|||
public static final long PTR_SIZE = Pointer.POINTER_SIZE;
|
||||
|
||||
// DRAW COMMAND
|
||||
public static final long DRAW_COMMAND_STRIDE = 36;
|
||||
public static final long DRAW_COMMAND_STRIDE = 44;
|
||||
public static final long DRAW_COMMAND_OFFSET = 0;
|
||||
|
||||
// BITS
|
||||
|
@ -180,15 +165,16 @@ public class IndirectBuffers {
|
|||
FlwMemoryTracker._freeGPUMemory(maxDrawCount * DRAW_COMMAND_STRIDE);
|
||||
}
|
||||
|
||||
public void bindAll() {
|
||||
bindN(BUFFER_COUNT);
|
||||
public void bindForCompute() {
|
||||
multiBind(BUFFER_COUNT);
|
||||
}
|
||||
|
||||
public void bindObjectAndTarget() {
|
||||
bindN(2);
|
||||
public void bindForDraw() {
|
||||
multiBind(BUFFER_COUNT);
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, draw);
|
||||
}
|
||||
|
||||
private void bindN(int bufferCount) {
|
||||
private void multiBind(int bufferCount) {
|
||||
if (bufferCount > BUFFER_COUNT) {
|
||||
throw new IllegalArgumentException("Can't bind more than " + BUFFER_COUNT + " buffers");
|
||||
}
|
||||
|
@ -197,10 +183,6 @@ public class IndirectBuffers {
|
|||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, bufferCount, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
}
|
||||
|
||||
void bindIndirectBuffer() {
|
||||
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, draw);
|
||||
}
|
||||
|
||||
void flushBatchIDs(long length) {
|
||||
glFlushMappedNamedBufferRange(batch, 0, length);
|
||||
}
|
||||
|
|
|
@ -3,18 +3,11 @@ package com.jozufozu.flywheel.backend.instancing.indirect;
|
|||
import static org.lwjgl.opengl.GL42.GL_COMMAND_BARRIER_BIT;
|
||||
import static org.lwjgl.opengl.GL42.glMemoryBarrier;
|
||||
import static org.lwjgl.opengl.GL43.GL_SHADER_STORAGE_BARRIER_BIT;
|
||||
import static org.lwjgl.opengl.GL46.glBindVertexArray;
|
||||
import static org.lwjgl.opengl.GL46.glCreateVertexArrays;
|
||||
import static org.lwjgl.opengl.GL46.glDeleteVertexArrays;
|
||||
import static org.lwjgl.opengl.GL46.glDispatchCompute;
|
||||
import static org.lwjgl.opengl.GL46.glEnableVertexArrayAttrib;
|
||||
import static org.lwjgl.opengl.GL46.glVertexArrayElementBuffer;
|
||||
import static org.lwjgl.opengl.GL46.glVertexArrayVertexBuffer;
|
||||
import static org.lwjgl.opengl.GL46.*;
|
||||
|
||||
import com.jozufozu.flywheel.api.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler;
|
||||
|
@ -26,7 +19,6 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
|
||||
private static final int BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT;
|
||||
|
||||
final StructWriter<T> storageBufferWriter;
|
||||
final GlProgram compute;
|
||||
final GlProgram draw;
|
||||
private final VertexType vertexType;
|
||||
|
@ -47,7 +39,6 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
|
||||
IndirectCullingGroup(StructType<T> structType, VertexType vertexType) {
|
||||
this.vertexType = vertexType;
|
||||
storageBufferWriter = structType.getWriter();
|
||||
|
||||
objectStride = structType.getLayout()
|
||||
.getStride();
|
||||
|
@ -116,7 +107,7 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
uploadIndirectCommands();
|
||||
|
||||
compute.bind();
|
||||
buffers.bindAll();
|
||||
buffers.bindForCompute();
|
||||
|
||||
var groupCount = (instanceCountThisFrame + 31) >> 5; // ceil(instanceCount / 32)
|
||||
glDispatchCompute(groupCount, 1, 1);
|
||||
|
@ -130,8 +121,7 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
|
||||
draw.bind();
|
||||
glBindVertexArray(vertexArray);
|
||||
buffers.bindObjectAndTarget();
|
||||
buffers.bindIndirectBuffer();
|
||||
buffers.bindForDraw();
|
||||
|
||||
memoryBarrier();
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.lwjgl.system.MemoryUtil;
|
|||
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
|
||||
public final class IndirectDraw<T extends InstancedPart> {
|
||||
final IndirectInstancer<T> instancer;
|
||||
|
@ -11,12 +12,18 @@ public final class IndirectDraw<T extends InstancedPart> {
|
|||
final Material material;
|
||||
int baseInstance = -1;
|
||||
|
||||
final int vertexMaterialID;
|
||||
final int fragmentMaterialID;
|
||||
|
||||
boolean needsFullWrite = true;
|
||||
|
||||
IndirectDraw(IndirectInstancer<T> instancer, Material material, IndirectMeshPool.BufferedMesh mesh) {
|
||||
this.instancer = instancer;
|
||||
this.material = material;
|
||||
this.mesh = mesh;
|
||||
|
||||
this.vertexMaterialID = ComponentRegistry.materials.getVertexID(material);
|
||||
this.fragmentMaterialID = ComponentRegistry.materials.getFragmentID(material);
|
||||
}
|
||||
|
||||
public void prepare(int baseInstance) {
|
||||
|
@ -48,5 +55,8 @@ public final class IndirectDraw<T extends InstancedPart> {
|
|||
MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance
|
||||
|
||||
boundingSphere.getToAddress(ptr + 20); // boundingSphere
|
||||
MemoryUtil.memPutInt(ptr + 36, vertexMaterialID); // vertexMaterialID
|
||||
MemoryUtil.memPutInt(ptr + 40, fragmentMaterialID); // fragmentMaterialID
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.List;
|
|||
import com.jozufozu.flywheel.api.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
|
||||
public class IndirectDrawSet<T extends InstancedPart> {
|
||||
|
||||
|
@ -37,6 +38,7 @@ public class IndirectDrawSet<T extends InstancedPart> {
|
|||
continue;
|
||||
}
|
||||
material.setup();
|
||||
Textures.bindActiveTextures();
|
||||
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, i * stride, 1, stride);
|
||||
material.clear();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -18,8 +11,6 @@ import com.jozufozu.flywheel.api.uniform.UniformProvider;
|
|||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class ComponentRegistry {
|
||||
|
@ -93,8 +84,8 @@ public class ComponentRegistry {
|
|||
public <T extends Material> T add(T material) {
|
||||
materials.add(material);
|
||||
|
||||
vertexSources.register(material, material.getVertexShader());
|
||||
fragmentSources.register(material, material.getFragmentShader());
|
||||
vertexSources.register(material.getVertexShader());
|
||||
fragmentSources.register(material.getFragmentShader());
|
||||
|
||||
return material;
|
||||
}
|
||||
|
@ -113,15 +104,21 @@ public class ComponentRegistry {
|
|||
return fragmentSources.sourceView;
|
||||
}
|
||||
|
||||
public int getVertexID(Material material) {
|
||||
return vertexSources.orderedSources.indexOf(material.getVertexShader());
|
||||
}
|
||||
|
||||
public int getFragmentID(Material material) {
|
||||
return fragmentSources.orderedSources.indexOf(material.getFragmentShader());
|
||||
}
|
||||
|
||||
private static class MaterialSources {
|
||||
private final Set<FileResolution> registered = new HashSet<>();
|
||||
private final List<FileResolution> orderedSources = new ArrayList<>();
|
||||
private final Reference2IntMap<Material> material2ID = new Reference2IntOpenHashMap<>();
|
||||
private final List<FileResolution> sourceView = Collections.unmodifiableList(orderedSources);
|
||||
|
||||
public void register(Material material, FileResolution vertexShader) {
|
||||
public void register(FileResolution vertexShader) {
|
||||
if (registered.add(vertexShader)) {
|
||||
material2ID.put(material, orderedSources.size());
|
||||
orderedSources.add(vertexShader);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.util.function.BiConsumer;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
|
@ -19,9 +18,9 @@ import net.minecraft.resources.ResourceLocation;
|
|||
public class Components {
|
||||
|
||||
|
||||
public static final FlwUniformProvider UNIFORM_PROVIDER = ComponentRegistry.register(new FlwUniformProvider());
|
||||
public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT));
|
||||
public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT));
|
||||
public static final FlwUniformProvider UNIFORM_PROVIDER = ComponentRegistry.register(new FlwUniformProvider());
|
||||
public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(Files.WORLD_VERTEX, Files.WORLD_FRAGMENT));
|
||||
public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT));
|
||||
|
||||
public static void init() {
|
||||
Files.init();
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
public class WorldProgram extends GlProgram {
|
||||
|
||||
// TODO: sampler registry?
|
||||
protected int diffuseTex;
|
||||
protected int overlayTex;
|
||||
protected int lightTex;
|
||||
|
||||
public WorldProgram(int handle) {
|
||||
super(handle);
|
||||
|
||||
bind();
|
||||
registerSamplers();
|
||||
unbind();
|
||||
}
|
||||
|
||||
protected void registerSamplers() {
|
||||
diffuseTex = setSamplerBinding("flw_diffuseTex", 0);
|
||||
overlayTex = setSamplerBinding("flw_overlayTex", 1);
|
||||
lightTex = setSamplerBinding("flw_lightTex", 2);
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.crumbling;
|
||||
|
||||
import com.jozufozu.flywheel.core.WorldProgram;
|
||||
|
||||
public class CrumblingProgram extends WorldProgram {
|
||||
public CrumblingProgram(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerSamplers() {
|
||||
diffuseTex = setSamplerBinding("flw_diffuseTex", 0);
|
||||
}
|
||||
}
|
|
@ -2,16 +2,7 @@
|
|||
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
||||
#use "flywheel:api/cull.glsl"
|
||||
#use "flywheel:util/types.glsl"
|
||||
|
||||
struct MeshDrawCommand {
|
||||
uint indexCount;
|
||||
uint instanceCount;
|
||||
uint firstIndex;
|
||||
uint vertexOffset;
|
||||
uint baseInstance;
|
||||
|
||||
BoundingSphere boundingSphere;
|
||||
};
|
||||
#use "flywheel:pipeline/indirect_draw_command.glsl"
|
||||
|
||||
// populated by instancers
|
||||
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#use "flywheel:api/vertex.glsl"
|
||||
#use "flywheel:pipeline/indirect_draw_command.glsl"
|
||||
|
||||
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
||||
FlwPackedInstance objects[];
|
||||
|
@ -8,9 +9,22 @@ layout(std430, binding = 1) restrict readonly buffer TargetBuffer {
|
|||
uint objectIDs[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 2) restrict readonly buffer BatchBuffer {
|
||||
uint batchIDs[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 3) restrict readonly buffer DrawCommands {
|
||||
MeshDrawCommand drawCommands[];
|
||||
};
|
||||
|
||||
void main() {
|
||||
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
||||
uint batchID = batchIDs[instanceIndex];
|
||||
FlwInstance i = flw_unpackInstance(objects[instanceIndex]);
|
||||
|
||||
flw_materialVertexID = drawCommands[batchID].vertexMaterialID;
|
||||
flw_materialFragmentID = drawCommands[batchID].fragmentMaterialID;
|
||||
|
||||
flw_layoutVertex();
|
||||
flw_instanceVertex(i);
|
||||
flw_materialVertex();
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#use "flywheel:util/types.glsl"
|
||||
|
||||
struct MeshDrawCommand {
|
||||
uint indexCount;
|
||||
uint instanceCount;
|
||||
uint firstIndex;
|
||||
uint vertexOffset;
|
||||
uint baseInstance;
|
||||
|
||||
BoundingSphere boundingSphere;
|
||||
uint vertexMaterialID;
|
||||
uint fragmentMaterialID;
|
||||
};
|
Loading…
Reference in a new issue