mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-02 08:14:57 +01:00
Condensing culling
- Adapt compilers to work with arbitrary instance types - Use single compiler for all draw shaders - Temp solution for instanced array attributes - Introduce pipeline shaders
This commit is contained in:
parent
03f6125c68
commit
c94a0934e3
24 changed files with 299 additions and 392 deletions
|
@ -16,7 +16,7 @@ import com.jozufozu.flywheel.core.DebugRender;
|
||||||
import com.jozufozu.flywheel.core.PartialModel;
|
import com.jozufozu.flywheel.core.PartialModel;
|
||||||
import com.jozufozu.flywheel.core.QuadConverter;
|
import com.jozufozu.flywheel.core.QuadConverter;
|
||||||
import com.jozufozu.flywheel.core.StitchedSprite;
|
import com.jozufozu.flywheel.core.StitchedSprite;
|
||||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysCompiler;
|
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||||
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
||||||
import com.jozufozu.flywheel.core.model.Models;
|
import com.jozufozu.flywheel.core.model.Models;
|
||||||
import com.jozufozu.flywheel.event.EntityWorldHandler;
|
import com.jozufozu.flywheel.event.EntityWorldHandler;
|
||||||
|
@ -80,7 +80,7 @@ public class Flywheel {
|
||||||
forgeEventBus.addListener(FlwCommands::registerClientCommands);
|
forgeEventBus.addListener(FlwCommands::registerClientCommands);
|
||||||
|
|
||||||
forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onRendererReload);
|
forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onRendererReload);
|
||||||
forgeEventBus.addListener(InstancedArraysCompiler::invalidateAll);
|
forgeEventBus.addListener(PipelineCompiler::invalidateAll);
|
||||||
forgeEventBus.addListener(Models::onReload);
|
forgeEventBus.addListener(Models::onReload);
|
||||||
forgeEventBus.addListener(MeshPool::reset);
|
forgeEventBus.addListener(MeshPool::reset);
|
||||||
forgeEventBus.addListener(CrumblingRenderer::onReloadRenderers);
|
forgeEventBus.addListener(CrumblingRenderer::onReloadRenderers);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.jozufozu.flywheel.api.pipeline;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||||
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
|
|
||||||
|
public record PipelineShader(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment) {
|
||||||
|
|
||||||
|
}
|
|
@ -6,10 +6,10 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysCompiler;
|
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||||
|
import com.jozufozu.flywheel.core.Components;
|
||||||
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
|
||||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||||
import com.jozufozu.flywheel.util.StringUtil;
|
import com.jozufozu.flywheel.util.StringUtil;
|
||||||
|
@ -69,8 +69,8 @@ public class Loader implements ResourceManagerReloadListener {
|
||||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||||
for (ContextShader contextShader : ComponentRegistry.contextShaders) {
|
for (ContextShader contextShader : ComponentRegistry.contextShaders) {
|
||||||
var ctx = new InstancedArraysCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader);
|
var ctx = new PipelineCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader, Components.INSTANCED_ARRAYS);
|
||||||
InstancedArraysCompiler.INSTANCE.getProgram(ctx);
|
PipelineCompiler.INSTANCE.getProgram(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
package com.jozufozu.flywheel.backend.instancing;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||||
|
import com.jozufozu.flywheel.api.material.Material;
|
||||||
|
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||||
|
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
import com.jozufozu.flywheel.core.compile.*;
|
||||||
|
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||||
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
|
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||||
|
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A caching compiler.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is responsible for compiling programs on the fly. An instance of this class will keep a cache of
|
||||||
|
* compiled programs, and will only compile a program if it is not already in the cache.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class PipelineCompiler extends Memoizer<PipelineCompiler.Context, GlProgram> {
|
||||||
|
|
||||||
|
public static final PipelineCompiler INSTANCE = new PipelineCompiler();
|
||||||
|
|
||||||
|
private final ShaderCompiler shaderCompiler;
|
||||||
|
|
||||||
|
private PipelineCompiler() {
|
||||||
|
this.shaderCompiler = new ShaderCompiler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec.
|
||||||
|
*
|
||||||
|
* @param ctx The context of compilation.
|
||||||
|
* @return A compiled GlProgram.
|
||||||
|
*/
|
||||||
|
public GlProgram getProgram(PipelineCompiler.Context ctx) {
|
||||||
|
return super.get(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invalidate() {
|
||||||
|
super.invalidate();
|
||||||
|
shaderCompiler.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GlProgram _create(PipelineCompiler.Context ctx) {
|
||||||
|
|
||||||
|
var glslVersion = ctx.pipelineShader()
|
||||||
|
.glslVersion();
|
||||||
|
|
||||||
|
var vertex = new ShaderCompiler.Context(glslVersion, ShaderType.VERTEX, ctx.getVertexComponents());
|
||||||
|
var fragment = new ShaderCompiler.Context(glslVersion, ShaderType.FRAGMENT, ctx.getFragmentComponents());
|
||||||
|
|
||||||
|
return new ProgramAssembler(ctx.instanceShader.getFileLoc())
|
||||||
|
.attachShader(shaderCompiler.get(vertex))
|
||||||
|
.attachShader(shaderCompiler.get(fragment))
|
||||||
|
.link()
|
||||||
|
.build(ctx.contextShader.factory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void _destroy(GlProgram value) {
|
||||||
|
value.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
||||||
|
INSTANCE.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the entire context of a program's usage.
|
||||||
|
*
|
||||||
|
* @param vertexType The vertexType the program should be adapted for.
|
||||||
|
* @param material The material shader to use.
|
||||||
|
* @param instanceShader The instance shader to use.
|
||||||
|
* @param contextShader The context shader to use.
|
||||||
|
*/
|
||||||
|
public record Context(VertexType vertexType, Material material, FileResolution instanceShader,
|
||||||
|
ContextShader contextShader, PipelineShader pipelineShader) {
|
||||||
|
|
||||||
|
ImmutableList<SourceFile> getVertexComponents() {
|
||||||
|
return ImmutableList.of(vertexType.getLayoutShader().getFile(), instanceShader.getFile(), material.getVertexShader().getFile(),
|
||||||
|
contextShader.getVertexShader(), pipelineShader.vertex().getFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImmutableList<SourceFile> getFragmentComponents() {
|
||||||
|
return ImmutableList.of(material.getFragmentShader().getFile(), contextShader.getFragmentShader(),
|
||||||
|
pipelineShader.fragment().getFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles compilation and deletion of vertex shaders.
|
||||||
|
*/
|
||||||
|
public static class ShaderCompiler extends Memoizer<ShaderCompiler.Context, GlShader> {
|
||||||
|
|
||||||
|
public ShaderCompiler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GlShader _create(Context key) {
|
||||||
|
StringBuilder finalSource = new StringBuilder();
|
||||||
|
|
||||||
|
finalSource.append(key.generateHeader());
|
||||||
|
finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n");
|
||||||
|
finalSource.append("#extension GL_ARB_conservative_depth : enable\n");
|
||||||
|
finalSource.append("#extension GL_ARB_enhanced_layouts : enable\n");
|
||||||
|
|
||||||
|
var ctx = new CompilationContext();
|
||||||
|
|
||||||
|
var names = ImmutableList.<ResourceLocation>builder();
|
||||||
|
for (var file : key.components) {
|
||||||
|
finalSource.append(file.generateFinalSource(ctx));
|
||||||
|
names.add(file.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new GlShader(finalSource.toString(), key.shaderType, names.build());
|
||||||
|
} catch (ShaderCompilationException e) {
|
||||||
|
throw e.withErrorLog(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void _destroy(GlShader value) {
|
||||||
|
value.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param glslVersion The GLSL version to use.
|
||||||
|
* @param components A list of shader components to stitch together, in order.
|
||||||
|
*/
|
||||||
|
public record Context(GLSLVersion glslVersion, ShaderType shaderType, List<SourceFile> components) {
|
||||||
|
|
||||||
|
public String generateHeader() {
|
||||||
|
return CompileUtil.generateHeader(glslVersion, shaderType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
|
import com.jozufozu.flywheel.core.Components;
|
||||||
import com.jozufozu.flywheel.core.compile.CompileUtil;
|
import com.jozufozu.flywheel.core.compile.CompileUtil;
|
||||||
import com.jozufozu.flywheel.core.compile.Memoizer;
|
import com.jozufozu.flywheel.core.compile.Memoizer;
|
||||||
import com.jozufozu.flywheel.core.compile.ProgramAssembler;
|
import com.jozufozu.flywheel.core.compile.ProgramAssembler;
|
||||||
|
@ -23,14 +24,18 @@ public class ComputeCullerCompiler extends Memoizer<FileResolution, GlProgram> {
|
||||||
@Override
|
@Override
|
||||||
protected GlProgram _create(FileResolution file) {
|
protected GlProgram _create(FileResolution file) {
|
||||||
|
|
||||||
|
var finalSource = new StringBuilder();
|
||||||
CompilationContext context = new CompilationContext();
|
CompilationContext context = new CompilationContext();
|
||||||
|
|
||||||
var header = CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE);
|
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE));
|
||||||
String source = file.getFile()
|
finalSource.append(file.getFile()
|
||||||
.generateFinalSource(context);
|
.generateFinalSource(context));
|
||||||
|
|
||||||
|
finalSource.append(Components.Pipeline.INDIRECT_CULL.getFile()
|
||||||
|
.generateFinalSource(context));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var shader = new GlShader(header + source, ShaderType.COMPUTE, ImmutableList.of(file.getFileLoc()));
|
var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(file.getFileLoc()));
|
||||||
|
|
||||||
return new ProgramAssembler(file.getFileLoc()).attachShader(shader)
|
return new ProgramAssembler(file.getFileLoc()).attachShader(shader)
|
||||||
.link()
|
.link()
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.instancing.indirect;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
|
||||||
import com.jozufozu.flywheel.core.WorldProgram;
|
|
||||||
import com.jozufozu.flywheel.core.compile.CompileUtil;
|
|
||||||
import com.jozufozu.flywheel.core.compile.Memoizer;
|
|
||||||
import com.jozufozu.flywheel.core.compile.ProgramAssembler;
|
|
||||||
import com.jozufozu.flywheel.core.compile.ShaderCompilationException;
|
|
||||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
|
||||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
|
||||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
|
||||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
|
||||||
|
|
||||||
public class IndirectDrawCompiler extends Memoizer<IndirectDrawCompiler.Program, GlProgram> {
|
|
||||||
public static final IndirectDrawCompiler INSTANCE = new IndirectDrawCompiler();
|
|
||||||
|
|
||||||
private IndirectDrawCompiler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GlProgram _create(IndirectDrawCompiler.Program program) {
|
|
||||||
|
|
||||||
GlShader vertexShader = compile(program.vertex.getFile(), ShaderType.VERTEX);
|
|
||||||
GlShader fragmentShader = compile(program.fragment.getFile(), ShaderType.FRAGMENT);
|
|
||||||
|
|
||||||
return new ProgramAssembler(program.vertex.getFileLoc())
|
|
||||||
.attachShader(vertexShader)
|
|
||||||
.attachShader(fragmentShader)
|
|
||||||
.link()
|
|
||||||
.build(WorldProgram::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static GlShader compile(SourceFile file, ShaderType type) {
|
|
||||||
var context = new CompilationContext();
|
|
||||||
try {
|
|
||||||
var header = CompileUtil.generateHeader(GLSLVersion.V460, type);
|
|
||||||
var source = file.generateFinalSource(context);
|
|
||||||
|
|
||||||
return new GlShader(header + source, type, ImmutableList.of(file.name));
|
|
||||||
} catch (ShaderCompilationException e) {
|
|
||||||
throw e.withErrorLog(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void _destroy(GlProgram value) {
|
|
||||||
value.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
|
||||||
INSTANCE.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public record Program(FileResolution vertex, FileResolution fragment) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,7 +19,7 @@ import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysCompiler;
|
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
||||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||||
|
@ -91,20 +91,6 @@ public class IndirectEngine implements Engine {
|
||||||
RenderSystem.enableCull();
|
RenderSystem.enableCull();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setup(ShaderState desc) {
|
|
||||||
|
|
||||||
VertexType vertexType = desc.vertex();
|
|
||||||
FileResolution instanceShader = desc.instance()
|
|
||||||
.getInstanceShader();
|
|
||||||
Material material = desc.material();
|
|
||||||
|
|
||||||
var ctx = new InstancedArraysCompiler.Context(vertexType, material, instanceShader, context);
|
|
||||||
|
|
||||||
InstancedArraysCompiler.INSTANCE.getProgram(ctx)
|
|
||||||
.bind();
|
|
||||||
UniformBuffer.getInstance().sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearAll() {
|
public void clearAll() {
|
||||||
factories.values().forEach(IndirectFactory::clear);
|
factories.values().forEach(IndirectFactory::clear);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import com.jozufozu.flywheel.api.instancer.InstancedPart;
|
||||||
import com.jozufozu.flywheel.api.struct.StorageBufferWriter;
|
import com.jozufozu.flywheel.api.struct.StorageBufferWriter;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||||
import com.jozufozu.flywheel.core.Components;
|
import com.jozufozu.flywheel.core.Components;
|
||||||
import com.jozufozu.flywheel.core.Materials;
|
import com.jozufozu.flywheel.core.Materials;
|
||||||
import com.jozufozu.flywheel.core.QuadConverter;
|
import com.jozufozu.flywheel.core.QuadConverter;
|
||||||
|
@ -21,7 +22,7 @@ import com.jozufozu.flywheel.core.vertex.Formats;
|
||||||
|
|
||||||
public class IndirectList<T extends InstancedPart> {
|
public class IndirectList<T extends InstancedPart> {
|
||||||
|
|
||||||
private static final long DRAW_COMMAND_STRIDE = 48;
|
private static final long DRAW_COMMAND_STRIDE = 36;
|
||||||
private static final long DRAW_COMMAND_OFFSET = 0;
|
private static final long DRAW_COMMAND_OFFSET = 0;
|
||||||
|
|
||||||
final StorageBufferWriter<T> storageBufferWriter;
|
final StorageBufferWriter<T> storageBufferWriter;
|
||||||
|
@ -73,18 +74,20 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
meshPool = new IndirectMeshPool(Formats.BLOCK, 1024);
|
meshPool = new IndirectMeshPool(Formats.BLOCK, 1024);
|
||||||
|
|
||||||
// FIXME: Resizable buffers
|
// FIXME: Resizable buffers
|
||||||
maxObjectCount = 1024L;
|
maxObjectCount = 64 * 64 * 64;
|
||||||
maxBatchCount = 64;
|
maxBatchCount = 64;
|
||||||
|
|
||||||
objectStride = storageBufferWriter.getAlignment();
|
objectStride = storageBufferWriter.getAlignment();
|
||||||
glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
int persistentBits = GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT;
|
||||||
glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, persistentBits);
|
||||||
glNamedBufferStorage(batchBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, 0);
|
||||||
|
glNamedBufferStorage(batchBuffer, 4 * maxObjectCount, persistentBits);
|
||||||
glNamedBufferStorage(drawBuffer, DRAW_COMMAND_STRIDE * maxBatchCount, GL_DYNAMIC_STORAGE_BIT);
|
glNamedBufferStorage(drawBuffer, DRAW_COMMAND_STRIDE * maxBatchCount, GL_DYNAMIC_STORAGE_BIT);
|
||||||
glNamedBufferStorage(debugBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
glNamedBufferStorage(debugBuffer, 4 * maxObjectCount, 0);
|
||||||
|
|
||||||
objectClientStorage = MemoryUtil.nmemAlloc(objectStride * maxObjectCount);
|
int mapBits = persistentBits | GL_MAP_FLUSH_EXPLICIT_BIT;
|
||||||
batchIDClientStorage = MemoryUtil.nmemAlloc(4 * maxObjectCount);
|
objectClientStorage = nglMapNamedBufferRange(objectBuffer, 0, objectStride * maxObjectCount, mapBits);
|
||||||
|
batchIDClientStorage = nglMapNamedBufferRange(batchBuffer, 0, 4 * maxObjectCount, mapBits);
|
||||||
|
|
||||||
vertexArray = glCreateVertexArrays();
|
vertexArray = glCreateVertexArrays();
|
||||||
|
|
||||||
|
@ -92,8 +95,8 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
.quads2Tris(2048).buffer.handle();
|
.quads2Tris(2048).buffer.handle();
|
||||||
setupVertexArray();
|
setupVertexArray();
|
||||||
|
|
||||||
compute = ComputeCullerCompiler.INSTANCE.get(Components.Files.CULL_INSTANCES);
|
compute = ComputeCullerCompiler.INSTANCE.get(Components.Files.ORIENTED_INDIRECT);
|
||||||
draw = IndirectDrawCompiler.INSTANCE.get(new IndirectDrawCompiler.Program(Components.Files.DRAW_INDIRECT_VERTEX, Components.Files.DRAW_INDIRECT_FRAGMENT));
|
draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(Formats.BLOCK, Materials.BELL, Components.Files.ORIENTED_INDIRECT, Components.WORLD, Components.INDIRECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupVertexArray() {
|
private void setupVertexArray() {
|
||||||
|
@ -184,8 +187,8 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
batchID++;
|
batchID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
nglNamedBufferSubData(objectBuffer, 0, objectPtr - objectClientStorage, objectClientStorage);
|
glFlushMappedNamedBufferRange(objectBuffer, 0, objectPtr - objectClientStorage);
|
||||||
nglNamedBufferSubData(batchBuffer, 0, batchIDPtr - batchIDClientStorage, batchIDClientStorage);
|
glFlushMappedNamedBufferRange(batchBuffer, 0, batchIDPtr - batchIDClientStorage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadIndirectCommands() {
|
private void uploadIndirectCommands() {
|
||||||
|
@ -229,7 +232,7 @@ public class IndirectList<T extends InstancedPart> {
|
||||||
MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex
|
MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex
|
||||||
MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance
|
MemoryUtil.memPutInt(ptr + 16, baseInstance); // baseInstance
|
||||||
|
|
||||||
boundingSphere.getToAddress(ptr + 32); // boundingSphere
|
boundingSphere.getToAddress(ptr + 20); // boundingSphere
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,252 +0,0 @@
|
||||||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
|
||||||
import com.jozufozu.flywheel.api.material.Material;
|
|
||||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
|
||||||
import com.jozufozu.flywheel.core.compile.*;
|
|
||||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
|
||||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
|
||||||
import com.jozufozu.flywheel.core.source.parse.ShaderField;
|
|
||||||
import com.jozufozu.flywheel.core.source.span.Span;
|
|
||||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
|
||||||
import com.jozufozu.flywheel.util.Pair;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A caching compiler.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This class is responsible for compiling programs on the fly. An instance of this class will keep a cache of
|
|
||||||
* compiled programs, and will only compile a program if it is not already in the cache.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* A ProgramCompiler is also responsible for deleting programs and shaders on renderer reload.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public class InstancedArraysCompiler extends Memoizer<InstancedArraysCompiler.Context, GlProgram> {
|
|
||||||
|
|
||||||
public static final InstancedArraysCompiler INSTANCE = new InstancedArraysCompiler();
|
|
||||||
|
|
||||||
private final VertexCompiler vertexCompiler;
|
|
||||||
private final FragmentCompiler fragmentCompiler;
|
|
||||||
|
|
||||||
private InstancedArraysCompiler() {
|
|
||||||
this.vertexCompiler = new VertexCompiler();
|
|
||||||
this.fragmentCompiler = new FragmentCompiler();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get or compile a spec to the given vertex type, accounting for all game state conditions specified by the spec.
|
|
||||||
*
|
|
||||||
* @param ctx The context of compilation.
|
|
||||||
* @return A compiled GlProgram.
|
|
||||||
*/
|
|
||||||
public GlProgram getProgram(InstancedArraysCompiler.Context ctx) {
|
|
||||||
return super.get(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void invalidate() {
|
|
||||||
super.invalidate();
|
|
||||||
vertexCompiler.invalidate();
|
|
||||||
fragmentCompiler.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GlProgram _create(InstancedArraysCompiler.Context ctx) {
|
|
||||||
// TODO: try-catch here to prevent crashing if shaders failed to compile
|
|
||||||
Material material = ctx.material;
|
|
||||||
FileResolution instanceShader = ctx.instanceShader();
|
|
||||||
ContextShader contextShader = ctx.contextShader;
|
|
||||||
|
|
||||||
var vertex = new VertexCompiler.Context(ctx.vertexType(), instanceShader.getFile(), material.getVertexShader().getFile(),
|
|
||||||
contextShader.getVertexShader());
|
|
||||||
|
|
||||||
var fragment = new FragmentCompiler.Context(material.getFragmentShader().getFile(), contextShader.getFragmentShader());
|
|
||||||
|
|
||||||
return new ProgramAssembler(instanceShader.getFileLoc())
|
|
||||||
.attachShader(vertexCompiler.get(vertex))
|
|
||||||
.attachShader(fragmentCompiler.get(fragment))
|
|
||||||
.link()
|
|
||||||
.build(contextShader.factory());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void _destroy(GlProgram value) {
|
|
||||||
value.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
|
||||||
INSTANCE.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the entire context of a program's usage.
|
|
||||||
*
|
|
||||||
* @param vertexType The vertexType the program should be adapted for.
|
|
||||||
* @param material The material shader to use.
|
|
||||||
* @param instanceShader The instance shader to use.
|
|
||||||
* @param contextShader The context shader to use.
|
|
||||||
*/
|
|
||||||
public record Context(VertexType vertexType, Material material, FileResolution instanceShader,
|
|
||||||
ContextShader contextShader) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles compilation and deletion of vertex shaders.
|
|
||||||
*/
|
|
||||||
public static class VertexCompiler extends Memoizer<VertexCompiler.Context, GlShader> {
|
|
||||||
|
|
||||||
public VertexCompiler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GlShader _create(Context key) {
|
|
||||||
StringBuilder finalSource = new StringBuilder();
|
|
||||||
|
|
||||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.VERTEX));
|
|
||||||
finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n");
|
|
||||||
|
|
||||||
var index = new CompilationContext();
|
|
||||||
|
|
||||||
// LAYOUT
|
|
||||||
|
|
||||||
var layoutShader = key.vertexType.getLayoutShader().getFile();
|
|
||||||
finalSource.append(layoutShader.generateFinalSource(index));
|
|
||||||
|
|
||||||
// INSTANCE
|
|
||||||
|
|
||||||
int attributeBaseIndex = key.vertexType.getLayout()
|
|
||||||
.getAttributeCount();
|
|
||||||
|
|
||||||
var instanceShader = key.instanceShader;
|
|
||||||
var replacements = new ArrayList<Pair<Span, String>>();
|
|
||||||
for (ShaderField field : instanceShader.fields.values()) {
|
|
||||||
if (field.decoration != ShaderField.Decoration.IN) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int location = Integer.parseInt(field.location.get());
|
|
||||||
int newLocation = location + attributeBaseIndex;
|
|
||||||
replacements.add(Pair.of(field.location, Integer.toString(newLocation)));
|
|
||||||
}
|
|
||||||
finalSource.append(instanceShader.generateFinalSource(index, replacements));
|
|
||||||
|
|
||||||
// MATERIAL
|
|
||||||
|
|
||||||
var materialShader = key.materialShader;
|
|
||||||
finalSource.append(materialShader.generateFinalSource(index));
|
|
||||||
|
|
||||||
// CONTEXT
|
|
||||||
|
|
||||||
var contextShaderSource = key.contextShader;
|
|
||||||
finalSource.append(contextShaderSource.generateFinalSource(index));
|
|
||||||
|
|
||||||
// MAIN
|
|
||||||
|
|
||||||
finalSource.append("""
|
|
||||||
void main() {
|
|
||||||
flw_layoutVertex();
|
|
||||||
|
|
||||||
flw_instanceVertex();
|
|
||||||
|
|
||||||
flw_materialVertex();
|
|
||||||
|
|
||||||
flw_contextVertex();
|
|
||||||
}
|
|
||||||
""");
|
|
||||||
|
|
||||||
try {
|
|
||||||
return new GlShader(finalSource.toString(), ShaderType.VERTEX, ImmutableList.of(layoutShader.name, instanceShader.name, materialShader.name, contextShaderSource.name));
|
|
||||||
} catch (ShaderCompilationException e) {
|
|
||||||
throw e.withErrorLog(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void _destroy(GlShader value) {
|
|
||||||
value.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param vertexType The vertex type to use.
|
|
||||||
* @param instanceShader The instance shader source.
|
|
||||||
* @param materialShader The vertex material shader source.
|
|
||||||
* @param contextShader The context shader source.
|
|
||||||
*/
|
|
||||||
public record Context(VertexType vertexType, SourceFile instanceShader, SourceFile materialShader, SourceFile contextShader) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles compilation and deletion of fragment shaders.
|
|
||||||
*/
|
|
||||||
public static class FragmentCompiler extends Memoizer<FragmentCompiler.Context, GlShader> {
|
|
||||||
|
|
||||||
public FragmentCompiler() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GlShader _create(Context key) {
|
|
||||||
StringBuilder finalSource = new StringBuilder();
|
|
||||||
|
|
||||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V420, ShaderType.FRAGMENT));
|
|
||||||
finalSource.append("#extension GL_ARB_conservative_depth : enable\n");
|
|
||||||
|
|
||||||
var ctx = new CompilationContext();
|
|
||||||
|
|
||||||
// MATERIAL
|
|
||||||
|
|
||||||
SourceFile materialShader = key.materialShader;
|
|
||||||
finalSource.append(materialShader.generateFinalSource(ctx));
|
|
||||||
|
|
||||||
// CONTEXT
|
|
||||||
|
|
||||||
SourceFile contextShaderSource = key.contextShader;
|
|
||||||
finalSource.append(contextShaderSource.generateFinalSource(ctx));
|
|
||||||
|
|
||||||
// MAIN
|
|
||||||
|
|
||||||
finalSource.append(generateFooter());
|
|
||||||
|
|
||||||
try {
|
|
||||||
return new GlShader(finalSource.toString(), ShaderType.FRAGMENT, ImmutableList.of(materialShader.name, contextShaderSource.name));
|
|
||||||
} catch (ShaderCompilationException e) {
|
|
||||||
throw e.withErrorLog(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String generateFooter() {
|
|
||||||
return """
|
|
||||||
void main() {
|
|
||||||
flw_initFragment();
|
|
||||||
|
|
||||||
flw_materialFragment();
|
|
||||||
|
|
||||||
flw_contextFragment();
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void _destroy(GlShader value) {
|
|
||||||
value.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents the conditions under which a shader is compiled.
|
|
||||||
*
|
|
||||||
* @param materialShader The fragment material shader source.
|
|
||||||
*/
|
|
||||||
public record Context(SourceFile materialShader, SourceFile contextShader) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,7 +17,9 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||||
|
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||||
|
import com.jozufozu.flywheel.core.Components;
|
||||||
import com.jozufozu.flywheel.core.RenderContext;
|
import com.jozufozu.flywheel.core.RenderContext;
|
||||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
|
@ -136,9 +138,9 @@ public class InstancingEngine implements Engine {
|
||||||
.getInstanceShader();
|
.getInstanceShader();
|
||||||
Material material = desc.material();
|
Material material = desc.material();
|
||||||
|
|
||||||
var ctx = new InstancedArraysCompiler.Context(vertexType, material, instanceShader, context);
|
var ctx = new PipelineCompiler.Context(vertexType, material, instanceShader, context, Components.INSTANCED_ARRAYS);
|
||||||
|
|
||||||
InstancedArraysCompiler.INSTANCE.getProgram(ctx)
|
PipelineCompiler.INSTANCE.getProgram(ctx)
|
||||||
.bind();
|
.bind();
|
||||||
UniformBuffer.getInstance().sync();
|
UniformBuffer.getInstance().sync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||||
|
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||||
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
||||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||||
import com.jozufozu.flywheel.core.source.SourceChecks;
|
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||||
|
@ -27,6 +29,9 @@ public class Components {
|
||||||
public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT));
|
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 ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT));
|
||||||
|
|
||||||
|
public static final PipelineShader INSTANCED_ARRAYS = new PipelineShader(GLSLVersion.V420, Pipeline.INSTANCED_ARRAYS_DRAW, Pipeline.DRAW_FRAGMENT);
|
||||||
|
public static final PipelineShader INDIRECT = new PipelineShader(GLSLVersion.V460, Pipeline.INDIRECT_DRAW, Pipeline.DRAW_FRAGMENT);
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
Files.init();
|
Files.init();
|
||||||
Formats.init();
|
Formats.init();
|
||||||
|
@ -34,6 +39,18 @@ public class Components {
|
||||||
Materials.init();
|
Materials.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Pipeline {
|
||||||
|
public static final FileResolution DRAW_FRAGMENT = pipeline("pipeline/draw.frag");
|
||||||
|
public static final FileResolution INSTANCED_ARRAYS_DRAW = pipeline("pipeline/instanced_arrays_draw.vert");
|
||||||
|
public static final FileResolution INDIRECT_DRAW = pipeline("pipeline/indirect_draw.vert");
|
||||||
|
public static final FileResolution INDIRECT_CULL = pipeline("pipeline/indirect_cull.glsl");
|
||||||
|
|
||||||
|
private static FileResolution pipeline(String name) {
|
||||||
|
return FileResolution.get(Flywheel.rl(name))
|
||||||
|
.validateWith(Checks.PIPELINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Files {
|
public static class Files {
|
||||||
|
|
||||||
public static final FileResolution VIEW_UNIFORMS = uniform(Flywheel.rl("uniform/view.glsl"));
|
public static final FileResolution VIEW_UNIFORMS = uniform(Flywheel.rl("uniform/view.glsl"));
|
||||||
|
@ -42,7 +59,9 @@ public class Components {
|
||||||
public static final FileResolution BLOCK_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.BLOCK, ".vert"));
|
public static final FileResolution BLOCK_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.BLOCK, ".vert"));
|
||||||
public static final FileResolution POS_TEX_NORMAL_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"));
|
public static final FileResolution POS_TEX_NORMAL_LAYOUT = layoutVertex(ResourceUtil.subPath(Names.POS_TEX_NORMAL, ".vert"));
|
||||||
public static final FileResolution TRANSFORMED = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, ".vert"));
|
public static final FileResolution TRANSFORMED = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, ".vert"));
|
||||||
|
public static final FileResolution TRANSFORMED_INDIRECT = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, "_indirect.glsl"));
|
||||||
public static final FileResolution ORIENTED = instanceVertex(ResourceUtil.subPath(Names.ORIENTED, ".vert"));
|
public static final FileResolution ORIENTED = instanceVertex(ResourceUtil.subPath(Names.ORIENTED, ".vert"));
|
||||||
|
public static final FileResolution ORIENTED_INDIRECT = instanceVertex(ResourceUtil.subPath(Names.ORIENTED, "_indirect.glsl"));
|
||||||
public static final FileResolution DEFAULT_VERTEX = materialVertex(ResourceUtil.subPath(Names.DEFAULT, ".vert"));
|
public static final FileResolution DEFAULT_VERTEX = materialVertex(ResourceUtil.subPath(Names.DEFAULT, ".vert"));
|
||||||
public static final FileResolution SHADED_VERTEX = materialVertex(ResourceUtil.subPath(Names.SHADED, ".vert"));
|
public static final FileResolution SHADED_VERTEX = materialVertex(ResourceUtil.subPath(Names.SHADED, ".vert"));
|
||||||
public static final FileResolution DEFAULT_FRAGMENT = materialFragment(ResourceUtil.subPath(Names.DEFAULT, ".frag"));
|
public static final FileResolution DEFAULT_FRAGMENT = materialFragment(ResourceUtil.subPath(Names.DEFAULT, ".frag"));
|
||||||
|
@ -51,9 +70,6 @@ public class Components {
|
||||||
public static final FileResolution WORLD_FRAGMENT = contextFragment(ResourceUtil.subPath(Names.WORLD, ".frag"));
|
public static final FileResolution WORLD_FRAGMENT = contextFragment(ResourceUtil.subPath(Names.WORLD, ".frag"));
|
||||||
public static final FileResolution CRUMBLING_VERTEX = contextVertex(ResourceUtil.subPath(Names.CRUMBLING, ".vert"));
|
public static final FileResolution CRUMBLING_VERTEX = contextVertex(ResourceUtil.subPath(Names.CRUMBLING, ".vert"));
|
||||||
public static final FileResolution CRUMBLING_FRAGMENT = contextFragment(ResourceUtil.subPath(Names.CRUMBLING, ".frag"));
|
public static final FileResolution CRUMBLING_FRAGMENT = contextFragment(ResourceUtil.subPath(Names.CRUMBLING, ".frag"));
|
||||||
public static final FileResolution CULL_INSTANCES = compute(Flywheel.rl("compute/cull_instances.glsl"));
|
|
||||||
public static final FileResolution DRAW_INDIRECT_VERTEX = FileResolution.get(ResourceUtil.subPath(Names.DRAW_INDIRECT, ".vert"));
|
|
||||||
public static final FileResolution DRAW_INDIRECT_FRAGMENT = FileResolution.get(ResourceUtil.subPath(Names.DRAW_INDIRECT, ".frag"));
|
|
||||||
|
|
||||||
private static FileResolution compute(ResourceLocation rl) {
|
private static FileResolution compute(ResourceLocation rl) {
|
||||||
return FileResolution.get(rl);
|
return FileResolution.get(rl);
|
||||||
|
@ -69,8 +85,7 @@ public class Components {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FileResolution instanceVertex(ResourceLocation location) {
|
private static FileResolution instanceVertex(ResourceLocation location) {
|
||||||
return FileResolution.get(location)
|
return FileResolution.get(location); // .validateWith(Checks.INSTANCE_VERTEX);
|
||||||
.validateWith(Checks.INSTANCE_VERTEX);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FileResolution materialVertex(ResourceLocation location) {
|
private static FileResolution materialVertex(ResourceLocation location) {
|
||||||
|
@ -100,12 +115,16 @@ public class Components {
|
||||||
|
|
||||||
public static class Checks {
|
public static class Checks {
|
||||||
|
|
||||||
public static final BiConsumer<ErrorReporter, SourceFile> LAYOUT_VERTEX = SourceChecks.checkFunctionArity("flw_layoutVertex", 0);
|
public static final BiConsumer<ErrorReporter, SourceFile> LAYOUT_VERTEX = SourceChecks.checkFunctionArity("flw_layoutVertex", 0)
|
||||||
public static final BiConsumer<ErrorReporter, SourceFile> INSTANCE_VERTEX = SourceChecks.checkFunctionArity("flw_instanceVertex", 0);
|
.andThen(SourceChecks.checkDefine("FLW_INSTANCE_BASE_INDEX"));
|
||||||
|
public static final BiConsumer<ErrorReporter, SourceFile> INSTANCE_VERTEX = SourceChecks.checkFunctionParameterTypeExists("flw_instanceVertex", 1, 0)
|
||||||
|
.andThen(SourceChecks.checkDefine("FLW_INSTANCE_STRUCT"));
|
||||||
public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_VERTEX = SourceChecks.checkFunctionArity("flw_materialVertex", 0);
|
public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_VERTEX = SourceChecks.checkFunctionArity("flw_materialVertex", 0);
|
||||||
public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_FRAGMENT = SourceChecks.checkFunctionArity("flw_materialFragment", 0);
|
public static final BiConsumer<ErrorReporter, SourceFile> MATERIAL_FRAGMENT = SourceChecks.checkFunctionArity("flw_materialFragment", 0);
|
||||||
public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_VERTEX = SourceChecks.checkFunctionArity("flw_contextVertex", 0);
|
public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_VERTEX = SourceChecks.checkFunctionArity("flw_contextVertex", 0);
|
||||||
public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_FRAGMENT = SourceChecks.checkFunctionArity("flw_contextFragment", 0).andThen(SourceChecks.checkFunctionArity("flw_initFragment", 0));
|
public static final BiConsumer<ErrorReporter, SourceFile> CONTEXT_FRAGMENT = SourceChecks.checkFunctionArity("flw_contextFragment", 0).andThen(SourceChecks.checkFunctionArity("flw_initFragment", 0));
|
||||||
|
|
||||||
|
public static final BiConsumer<ErrorReporter, SourceFile> PIPELINE = SourceChecks.checkFunctionArity("main", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Names {
|
public static class Names {
|
||||||
|
|
|
@ -162,4 +162,25 @@ public class FileResolution {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "FileResolution[" + fileLoc + "]";
|
return "FileResolution[" + fileLoc + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileResolution that = (FileResolution) o;
|
||||||
|
|
||||||
|
return fileLoc.equals(that.fileLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
// FileResolutions are interned and therefore can be hashed based on object identity.
|
||||||
|
// Overriding this to make it explicit.
|
||||||
|
return System.identityHashCode(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,4 +54,12 @@ public class SourceChecks {
|
||||||
|
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BiConsumer<? super ErrorReporter, ? super SourceFile> checkDefine(String define) {
|
||||||
|
return (errorReporter, file) -> {
|
||||||
|
// if (!file.hasDefine(define)) {
|
||||||
|
// errorReporter.generateMissingDefine(file, define, "\"" + define + "\" define not defined");
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,10 +185,7 @@ public class SourceFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateFinalSource(CompilationContext context) {
|
public String generateFinalSource(CompilationContext context) {
|
||||||
return generateFinalSource(context, Collections.emptyList());
|
List<Pair<Span, String>> replacements = Collections.emptyList();
|
||||||
}
|
|
||||||
|
|
||||||
public String generateFinalSource(CompilationContext context, List<Pair<Span, String>> replacements) {
|
|
||||||
var out = new StringBuilder();
|
var out = new StringBuilder();
|
||||||
for (Import include : flattenedImports) {
|
for (Import include : flattenedImports) {
|
||||||
SourceFile file = include.getFile();
|
SourceFile file = include.getFile();
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#use "flywheel:api/vertex.glsl"
|
#use "flywheel:api/vertex.glsl"
|
||||||
#use "flywheel:util/quaternion.glsl"
|
#use "flywheel:util/quaternion.glsl"
|
||||||
|
|
||||||
layout(location = 0) in ivec2 oriented_light;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 0) in ivec2 oriented_light;
|
||||||
layout(location = 1) in vec4 oriented_color;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 1) in vec4 oriented_color;
|
||||||
layout(location = 2) in vec3 oriented_pos;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 2) in vec3 oriented_pos;
|
||||||
layout(location = 3) in vec3 oriented_pivot;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 3) in vec3 oriented_pivot;
|
||||||
layout(location = 4) in vec4 oriented_rotation;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 4) in vec4 oriented_rotation;
|
||||||
|
|
||||||
void flw_instanceVertex() {
|
void flw_instanceVertex() {
|
||||||
flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - oriented_pivot, oriented_rotation) + oriented_pivot + oriented_pos, 1.0);
|
flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - oriented_pivot, oriented_rotation) + oriented_pivot + oriented_pos, 1.0);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#use "flywheel:api/vertex.glsl"
|
#use "flywheel:api/vertex.glsl"
|
||||||
#use "flywheel:util/quaternion.glsl"
|
#use "flywheel:util/quaternion.glsl"
|
||||||
#define FLW_INSTANCE_STRUCT Instance
|
|
||||||
|
|
||||||
|
#define FLW_INSTANCE_STRUCT Instance
|
||||||
struct Instance {
|
struct Instance {
|
||||||
vec4 rotation;
|
vec4 rotation;
|
||||||
vec3 pos;
|
vec3 pos;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#use "flywheel:api/vertex.glsl"
|
#use "flywheel:api/vertex.glsl"
|
||||||
|
|
||||||
layout(location = 0) in ivec2 transformed_light;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 0) in ivec2 transformed_light;
|
||||||
layout(location = 1) in vec4 transformed_color;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 1) in vec4 transformed_color;
|
||||||
layout(location = 2) in mat4 transformed_pose;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 2) in mat4 transformed_pose;
|
||||||
layout(location = 6) in mat3 transformed_normal;
|
layout(location = FLW_INSTANCE_BASE_INDEX + 6) in mat3 transformed_normal;
|
||||||
|
|
||||||
void flw_instanceVertex() {
|
void flw_instanceVertex() {
|
||||||
flw_vertexPos = transformed_pose * flw_vertexPos;
|
flw_vertexPos = transformed_pose * flw_vertexPos;
|
||||||
|
|
|
@ -5,6 +5,7 @@ layout(location = 1) in vec4 _flw_v_color;
|
||||||
layout(location = 2) in vec2 _flw_v_texCoord;
|
layout(location = 2) in vec2 _flw_v_texCoord;
|
||||||
layout(location = 3) in ivec2 _flw_v_light;
|
layout(location = 3) in ivec2 _flw_v_light;
|
||||||
layout(location = 4) in vec3 _flw_v_normal;
|
layout(location = 4) in vec3 _flw_v_normal;
|
||||||
|
#define FLW_INSTANCE_BASE_INDEX 5
|
||||||
|
|
||||||
void flw_layoutVertex() {
|
void flw_layoutVertex() {
|
||||||
flw_vertexPos = vec4(_flw_v_pos, 1.0);
|
flw_vertexPos = vec4(_flw_v_pos, 1.0);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
layout(location = 0) in vec3 _flw_v_pos;
|
layout(location = 0) in vec3 _flw_v_pos;
|
||||||
layout(location = 1) in vec2 _flw_v_texCoord;
|
layout(location = 1) in vec2 _flw_v_texCoord;
|
||||||
layout(location = 2) in vec3 _flw_v_normal;
|
layout(location = 2) in vec3 _flw_v_normal;
|
||||||
|
#define FLW_INSTANCE_BASE_INDEX 3
|
||||||
|
|
||||||
void flw_layoutVertex() {
|
void flw_layoutVertex() {
|
||||||
flw_vertexPos = vec4(_flw_v_pos, 1.0);
|
flw_vertexPos = vec4(_flw_v_pos, 1.0);
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#use "flywheel:api/fragment.glsl"
|
#use "flywheel:api/fragment.glsl"
|
||||||
#use "flywheel:context/world.frag"
|
|
||||||
#use "flywheel:material/default.frag"
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
flw_initFragment();
|
flw_initFragment();
|
|
@ -1,9 +1,8 @@
|
||||||
#define FLW_SUBGROUP_SIZE 32
|
#define FLW_SUBGROUP_SIZE 32
|
||||||
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
||||||
#use "flywheel:api/cull.glsl"
|
#use "flywheel:api/cull.glsl"
|
||||||
#use "flywheel:util/quaternion.glsl"
|
|
||||||
#use "flywheel:uniform/frustum.glsl"
|
#use "flywheel:uniform/frustum.glsl"
|
||||||
#use "flywheel:instance/oriented_indirect.glsl"
|
#use "flywheel:util/types.glsl"
|
||||||
|
|
||||||
struct MeshDrawCommand {
|
struct MeshDrawCommand {
|
||||||
uint indexCount;
|
uint indexCount;
|
||||||
|
@ -12,7 +11,7 @@ struct MeshDrawCommand {
|
||||||
uint vertexOffset;
|
uint vertexOffset;
|
||||||
uint baseInstance;
|
uint baseInstance;
|
||||||
|
|
||||||
vec4 boundingSphere;
|
BoundingSphere boundingSphere;
|
||||||
};
|
};
|
||||||
|
|
||||||
// populated by instancers
|
// populated by instancers
|
||||||
|
@ -54,10 +53,11 @@ bool testSphere(vec3 center, float radius) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isVisible() {
|
bool isVisible() {
|
||||||
vec4 sphere = drawCommands[flw_batchID].boundingSphere;
|
BoundingSphere sphere = drawCommands[flw_batchID].boundingSphere;
|
||||||
|
|
||||||
vec3 center = sphere.xyz;
|
vec3 center;
|
||||||
float radius = sphere.r;
|
float radius;
|
||||||
|
unpackBoundingSphere(sphere, center, radius);
|
||||||
flw_transformBoundingSphere(objects[flw_objectID], center, radius);
|
flw_transformBoundingSphere(objects[flw_objectID], center, radius);
|
||||||
|
|
||||||
return testSphere(center, radius);
|
return testSphere(center, radius);
|
|
@ -1,10 +1,5 @@
|
||||||
#use "flywheel:api/vertex.glsl"
|
#use "flywheel:api/vertex.glsl"
|
||||||
#use "flywheel:layout/block.vert"
|
|
||||||
#use "flywheel:context/world.vert"
|
|
||||||
#use "flywheel:util/quaternion.glsl"
|
|
||||||
#use "flywheel:instance/oriented_indirect.glsl"
|
|
||||||
|
|
||||||
// populated by instancers
|
|
||||||
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
layout(std430, binding = 0) restrict readonly buffer ObjectBuffer {
|
||||||
FLW_INSTANCE_STRUCT objects[];
|
FLW_INSTANCE_STRUCT objects[];
|
||||||
};
|
};
|
||||||
|
@ -16,7 +11,8 @@ layout(std430, binding = 1) restrict readonly buffer TargetBuffer {
|
||||||
void main() {
|
void main() {
|
||||||
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
||||||
flw_layoutVertex();
|
flw_layoutVertex();
|
||||||
Instance i = objects[instanceIndex];
|
FLW_INSTANCE_STRUCT i = objects[instanceIndex];
|
||||||
flw_instanceVertex(i);
|
flw_instanceVertex(i);
|
||||||
|
flw_materialVertex();
|
||||||
flw_contextVertex();
|
flw_contextVertex();
|
||||||
}
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#use "flywheel:api/vertex.glsl"
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
flw_layoutVertex();
|
||||||
|
flw_instanceVertex();
|
||||||
|
flw_materialVertex();
|
||||||
|
flw_contextVertex();
|
||||||
|
}
|
17
src/main/resources/assets/flywheel/flywheel/util/types.glsl
Normal file
17
src/main/resources/assets/flywheel/flywheel/util/types.glsl
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
struct Vec3F {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 4-aligned instead of a 16-aligned vec4
|
||||||
|
struct BoundingSphere {
|
||||||
|
Vec3F center;
|
||||||
|
float radius;
|
||||||
|
};
|
||||||
|
|
||||||
|
void unpackBoundingSphere(in BoundingSphere sphere, out vec3 center, out float radius) {
|
||||||
|
center = vec3(sphere.center.x, sphere.center.y, sphere.center.z);
|
||||||
|
radius = sphere.radius;
|
||||||
|
}
|
Loading…
Reference in a new issue