mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-25 22:46:26 +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
a9ee85ff76
commit
e7339dc7ef
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.QuadConverter;
|
||||
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.model.Models;
|
||||
import com.jozufozu.flywheel.event.EntityWorldHandler;
|
||||
|
@ -80,7 +80,7 @@ public class Flywheel {
|
|||
forgeEventBus.addListener(FlwCommands::registerClientCommands);
|
||||
|
||||
forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onRendererReload);
|
||||
forgeEventBus.addListener(InstancedArraysCompiler::invalidateAll);
|
||||
forgeEventBus.addListener(PipelineCompiler::invalidateAll);
|
||||
forgeEventBus.addListener(Models::onReload);
|
||||
forgeEventBus.addListener(MeshPool::reset);
|
||||
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.core.ComponentRegistry;
|
||||
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.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
@ -69,8 +69,8 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||
for (ContextShader contextShader : ComponentRegistry.contextShaders) {
|
||||
var ctx = new InstancedArraysCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader);
|
||||
InstancedArraysCompiler.INSTANCE.getProgram(ctx);
|
||||
var ctx = new PipelineCompiler.Context(vertexType, material, structType.getInstanceShader(), contextShader, Components.INSTANCED_ARRAYS);
|
||||
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.GlShader;
|
||||
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.Memoizer;
|
||||
import com.jozufozu.flywheel.core.compile.ProgramAssembler;
|
||||
|
@ -23,14 +24,18 @@ public class ComputeCullerCompiler extends Memoizer<FileResolution, GlProgram> {
|
|||
@Override
|
||||
protected GlProgram _create(FileResolution file) {
|
||||
|
||||
var finalSource = new StringBuilder();
|
||||
CompilationContext context = new CompilationContext();
|
||||
|
||||
var header = CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE);
|
||||
String source = file.getFile()
|
||||
.generateFinalSource(context);
|
||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE));
|
||||
finalSource.append(file.getFile()
|
||||
.generateFinalSource(context));
|
||||
|
||||
finalSource.append(Components.Pipeline.INDIRECT_CULL.getFile()
|
||||
.generateFinalSource(context));
|
||||
|
||||
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)
|
||||
.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.core.RenderContext;
|
||||
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.uniform.UniformBuffer;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
|
@ -91,20 +91,6 @@ public class IndirectEngine implements Engine {
|
|||
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() {
|
||||
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.StructType;
|
||||
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.Materials;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
|
@ -21,7 +22,7 @@ import com.jozufozu.flywheel.core.vertex.Formats;
|
|||
|
||||
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;
|
||||
|
||||
final StorageBufferWriter<T> storageBufferWriter;
|
||||
|
@ -73,18 +74,20 @@ public class IndirectList<T extends InstancedPart> {
|
|||
meshPool = new IndirectMeshPool(Formats.BLOCK, 1024);
|
||||
|
||||
// FIXME: Resizable buffers
|
||||
maxObjectCount = 1024L;
|
||||
maxObjectCount = 64 * 64 * 64;
|
||||
maxBatchCount = 64;
|
||||
|
||||
objectStride = storageBufferWriter.getAlignment();
|
||||
glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
||||
glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
||||
glNamedBufferStorage(batchBuffer, 4 * maxObjectCount, GL_DYNAMIC_STORAGE_BIT);
|
||||
int persistentBits = GL_MAP_PERSISTENT_BIT | GL_MAP_WRITE_BIT;
|
||||
glNamedBufferStorage(objectBuffer, objectStride * maxObjectCount, persistentBits);
|
||||
glNamedBufferStorage(targetBuffer, 4 * maxObjectCount, 0);
|
||||
glNamedBufferStorage(batchBuffer, 4 * maxObjectCount, persistentBits);
|
||||
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);
|
||||
batchIDClientStorage = MemoryUtil.nmemAlloc(4 * maxObjectCount);
|
||||
int mapBits = persistentBits | GL_MAP_FLUSH_EXPLICIT_BIT;
|
||||
objectClientStorage = nglMapNamedBufferRange(objectBuffer, 0, objectStride * maxObjectCount, mapBits);
|
||||
batchIDClientStorage = nglMapNamedBufferRange(batchBuffer, 0, 4 * maxObjectCount, mapBits);
|
||||
|
||||
vertexArray = glCreateVertexArrays();
|
||||
|
||||
|
@ -92,8 +95,8 @@ public class IndirectList<T extends InstancedPart> {
|
|||
.quads2Tris(2048).buffer.handle();
|
||||
setupVertexArray();
|
||||
|
||||
compute = ComputeCullerCompiler.INSTANCE.get(Components.Files.CULL_INSTANCES);
|
||||
draw = IndirectDrawCompiler.INSTANCE.get(new IndirectDrawCompiler.Program(Components.Files.DRAW_INDIRECT_VERTEX, Components.Files.DRAW_INDIRECT_FRAGMENT));
|
||||
compute = ComputeCullerCompiler.INSTANCE.get(Components.Files.ORIENTED_INDIRECT);
|
||||
draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(Formats.BLOCK, Materials.BELL, Components.Files.ORIENTED_INDIRECT, Components.WORLD, Components.INDIRECT));
|
||||
}
|
||||
|
||||
private void setupVertexArray() {
|
||||
|
@ -184,8 +187,8 @@ public class IndirectList<T extends InstancedPart> {
|
|||
batchID++;
|
||||
}
|
||||
|
||||
nglNamedBufferSubData(objectBuffer, 0, objectPtr - objectClientStorage, objectClientStorage);
|
||||
nglNamedBufferSubData(batchBuffer, 0, batchIDPtr - batchIDClientStorage, batchIDClientStorage);
|
||||
glFlushMappedNamedBufferRange(objectBuffer, 0, objectPtr - objectClientStorage);
|
||||
glFlushMappedNamedBufferRange(batchBuffer, 0, batchIDPtr - batchIDClientStorage);
|
||||
}
|
||||
|
||||
private void uploadIndirectCommands() {
|
||||
|
@ -229,7 +232,7 @@ public class IndirectList<T extends InstancedPart> {
|
|||
MemoryUtil.memPutInt(ptr + 12, mesh.getBaseVertex()); // baseVertex
|
||||
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.instancing.Engine;
|
||||
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.core.Components;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
@ -136,9 +138,9 @@ public class InstancingEngine implements Engine {
|
|||
.getInstanceShader();
|
||||
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();
|
||||
UniformBuffer.getInstance().sync();
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import java.util.function.BiConsumer;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
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.source.FileResolution;
|
||||
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 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() {
|
||||
Files.init();
|
||||
Formats.init();
|
||||
|
@ -34,6 +39,18 @@ public class Components {
|
|||
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 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 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_INDIRECT = instanceVertex(ResourceUtil.subPath(Names.TRANSFORMED, "_indirect.glsl"));
|
||||
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 SHADED_VERTEX = materialVertex(ResourceUtil.subPath(Names.SHADED, ".vert"));
|
||||
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 CRUMBLING_VERTEX = contextVertex(ResourceUtil.subPath(Names.CRUMBLING, ".vert"));
|
||||
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) {
|
||||
return FileResolution.get(rl);
|
||||
|
@ -69,8 +85,7 @@ public class Components {
|
|||
}
|
||||
|
||||
private static FileResolution instanceVertex(ResourceLocation location) {
|
||||
return FileResolution.get(location)
|
||||
.validateWith(Checks.INSTANCE_VERTEX);
|
||||
return FileResolution.get(location); // .validateWith(Checks.INSTANCE_VERTEX);
|
||||
}
|
||||
|
||||
private static FileResolution materialVertex(ResourceLocation location) {
|
||||
|
@ -100,12 +115,16 @@ public class Components {
|
|||
|
||||
public static class Checks {
|
||||
|
||||
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);
|
||||
public static final BiConsumer<ErrorReporter, SourceFile> LAYOUT_VERTEX = SourceChecks.checkFunctionArity("flw_layoutVertex", 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_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_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 {
|
||||
|
|
|
@ -162,4 +162,25 @@ public class FileResolution {
|
|||
public String toString() {
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
return generateFinalSource(context, Collections.emptyList());
|
||||
}
|
||||
|
||||
public String generateFinalSource(CompilationContext context, List<Pair<Span, String>> replacements) {
|
||||
List<Pair<Span, String>> replacements = Collections.emptyList();
|
||||
var out = new StringBuilder();
|
||||
for (Import include : flattenedImports) {
|
||||
SourceFile file = include.getFile();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#use "flywheel:api/vertex.glsl"
|
||||
#use "flywheel:util/quaternion.glsl"
|
||||
|
||||
layout(location = 0) in ivec2 oriented_light;
|
||||
layout(location = 1) in vec4 oriented_color;
|
||||
layout(location = 2) in vec3 oriented_pos;
|
||||
layout(location = 3) in vec3 oriented_pivot;
|
||||
layout(location = 4) in vec4 oriented_rotation;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 0) in ivec2 oriented_light;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 1) in vec4 oriented_color;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 2) in vec3 oriented_pos;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 3) in vec3 oriented_pivot;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 4) in vec4 oriented_rotation;
|
||||
|
||||
void flw_instanceVertex() {
|
||||
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:util/quaternion.glsl"
|
||||
#define FLW_INSTANCE_STRUCT Instance
|
||||
|
||||
#define FLW_INSTANCE_STRUCT Instance
|
||||
struct Instance {
|
||||
vec4 rotation;
|
||||
vec3 pos;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#use "flywheel:api/vertex.glsl"
|
||||
|
||||
layout(location = 0) in ivec2 transformed_light;
|
||||
layout(location = 1) in vec4 transformed_color;
|
||||
layout(location = 2) in mat4 transformed_pose;
|
||||
layout(location = 6) in mat3 transformed_normal;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 0) in ivec2 transformed_light;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 1) in vec4 transformed_color;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 2) in mat4 transformed_pose;
|
||||
layout(location = FLW_INSTANCE_BASE_INDEX + 6) in mat3 transformed_normal;
|
||||
|
||||
void flw_instanceVertex() {
|
||||
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 = 3) in ivec2 _flw_v_light;
|
||||
layout(location = 4) in vec3 _flw_v_normal;
|
||||
#define FLW_INSTANCE_BASE_INDEX 5
|
||||
|
||||
void flw_layoutVertex() {
|
||||
flw_vertexPos = vec4(_flw_v_pos, 1.0);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
layout(location = 0) in vec3 _flw_v_pos;
|
||||
layout(location = 1) in vec2 _flw_v_texCoord;
|
||||
layout(location = 2) in vec3 _flw_v_normal;
|
||||
#define FLW_INSTANCE_BASE_INDEX 3
|
||||
|
||||
void flw_layoutVertex() {
|
||||
flw_vertexPos = vec4(_flw_v_pos, 1.0);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#use "flywheel:api/fragment.glsl"
|
||||
#use "flywheel:context/world.frag"
|
||||
#use "flywheel:material/default.frag"
|
||||
|
||||
void main() {
|
||||
flw_initFragment();
|
|
@ -1,9 +1,8 @@
|
|||
#define FLW_SUBGROUP_SIZE 32
|
||||
layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
||||
#use "flywheel:api/cull.glsl"
|
||||
#use "flywheel:util/quaternion.glsl"
|
||||
#use "flywheel:uniform/frustum.glsl"
|
||||
#use "flywheel:instance/oriented_indirect.glsl"
|
||||
#use "flywheel:util/types.glsl"
|
||||
|
||||
struct MeshDrawCommand {
|
||||
uint indexCount;
|
||||
|
@ -12,7 +11,7 @@ struct MeshDrawCommand {
|
|||
uint vertexOffset;
|
||||
uint baseInstance;
|
||||
|
||||
vec4 boundingSphere;
|
||||
BoundingSphere boundingSphere;
|
||||
};
|
||||
|
||||
// populated by instancers
|
||||
|
@ -54,10 +53,11 @@ bool testSphere(vec3 center, float radius) {
|
|||
}
|
||||
|
||||
bool isVisible() {
|
||||
vec4 sphere = drawCommands[flw_batchID].boundingSphere;
|
||||
BoundingSphere sphere = drawCommands[flw_batchID].boundingSphere;
|
||||
|
||||
vec3 center = sphere.xyz;
|
||||
float radius = sphere.r;
|
||||
vec3 center;
|
||||
float radius;
|
||||
unpackBoundingSphere(sphere, center, radius);
|
||||
flw_transformBoundingSphere(objects[flw_objectID], center, radius);
|
||||
|
||||
return testSphere(center, radius);
|
|
@ -1,10 +1,5 @@
|
|||
#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 {
|
||||
FLW_INSTANCE_STRUCT objects[];
|
||||
};
|
||||
|
@ -16,7 +11,8 @@ layout(std430, binding = 1) restrict readonly buffer TargetBuffer {
|
|||
void main() {
|
||||
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
||||
flw_layoutVertex();
|
||||
Instance i = objects[instanceIndex];
|
||||
FLW_INSTANCE_STRUCT i = objects[instanceIndex];
|
||||
flw_instanceVertex(i);
|
||||
flw_materialVertex();
|
||||
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