mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-27 05:17:56 +01:00
The uintification
- Store packed instances in a uint[] in indirect - Split the object buffer into an instance buffer and a model index buffer - Rename StructInstanceComponent to SsboInstanceComponent - Expand abstraction in InstanceAssemblerComponent to allow both types of instance assemblers to reuse per-element unpacking generation - Separate FlwInstance struct generation into separate component, InstanceStructComponent - Also inline LayoutInterpreter into this class - Move necessary internal definitions for components from api_impl to common components_header shaders - Use the same api_impl shader between pipelines
This commit is contained in:
parent
84515316a7
commit
277597d6bf
32 changed files with 532 additions and 771 deletions
|
@ -18,12 +18,16 @@ import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
|||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
||||
|
||||
public final class FlwPrograms {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger(Flywheel.ID + "/shaders");
|
||||
|
||||
private static final ResourceLocation COMPONENTS_HEADER_VERT = Flywheel.rl("internal/components_header.vert");
|
||||
private static final ResourceLocation COMPONENTS_HEADER_FRAG = Flywheel.rl("internal/components_header.frag");
|
||||
|
||||
private FlwPrograms() {
|
||||
}
|
||||
|
||||
|
@ -34,21 +38,24 @@ public final class FlwPrograms {
|
|||
|
||||
var sources = new ShaderSources(resourceManager);
|
||||
var stats = new CompilerStats("ubershaders");
|
||||
var loadChecker = new SourceLoader(sources, stats);
|
||||
var loader = new SourceLoader(sources, stats);
|
||||
|
||||
var vertexMaterialComponent = createVertexMaterialComponent(loadChecker);
|
||||
var fragmentMaterialComponent = createFragmentMaterialComponent(loadChecker);
|
||||
var fogComponent = createFogComponent(loadChecker);
|
||||
var cutoutComponent = createCutoutComponent(loadChecker);
|
||||
var vertexComponentsHeader = loader.find(COMPONENTS_HEADER_VERT);
|
||||
var fragmentComponentsHeader = loader.find(COMPONENTS_HEADER_FRAG);
|
||||
|
||||
if (stats.errored() || vertexMaterialComponent == null || fragmentMaterialComponent == null || fogComponent == null || cutoutComponent == null) {
|
||||
var vertexMaterialComponent = createVertexMaterialComponent(loader);
|
||||
var fragmentMaterialComponent = createFragmentMaterialComponent(loader);
|
||||
var fogComponent = createFogComponent(loader);
|
||||
var cutoutComponent = createCutoutComponent(loader);
|
||||
|
||||
if (stats.errored() || vertexComponentsHeader == null || fragmentComponentsHeader == null || vertexMaterialComponent == null || fragmentMaterialComponent == null || fogComponent == null || cutoutComponent == null) {
|
||||
// Probably means the shader sources are missing.
|
||||
stats.emitErrorLog();
|
||||
return;
|
||||
}
|
||||
|
||||
List<SourceComponent> vertexComponents = List.of(vertexMaterialComponent);
|
||||
List<SourceComponent> fragmentComponents = List.of(fragmentMaterialComponent, fogComponent, cutoutComponent);
|
||||
List<SourceComponent> vertexComponents = List.of(vertexComponentsHeader, vertexMaterialComponent);
|
||||
List<SourceComponent> fragmentComponents = List.of(fragmentComponentsHeader, fragmentMaterialComponent, fogComponent, cutoutComponent);
|
||||
|
||||
var pipelineKeys = createPipelineKeys();
|
||||
InstancingPrograms.reload(sources, pipelineKeys, vertexComponents, fragmentComponents);
|
||||
|
@ -66,27 +73,27 @@ public final class FlwPrograms {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loadChecker) {
|
||||
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("material_vertex"))
|
||||
.materialSources(ShaderIndices.materialVertex()
|
||||
.all())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("_flw_uberMaterialVertexIndex"))
|
||||
.build(loadChecker);
|
||||
.build(loader);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loadChecker) {
|
||||
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("material_fragment"))
|
||||
.materialSources(ShaderIndices.materialFragment()
|
||||
.all())
|
||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||
.switchOn(GlslExpr.variable("_flw_uberMaterialFragmentIndex"))
|
||||
.build(loadChecker);
|
||||
.build(loader);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createFogComponent(SourceLoader loadChecker) {
|
||||
private static UberShaderComponent createFogComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("fog"))
|
||||
.materialSources(ShaderIndices.fog()
|
||||
.all())
|
||||
|
@ -96,11 +103,11 @@ public final class FlwPrograms {
|
|||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("_flw_uberFogIndex"))
|
||||
.build(loadChecker);
|
||||
.build(loader);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UberShaderComponent createCutoutComponent(SourceLoader loadChecker) {
|
||||
private static UberShaderComponent createCutoutComponent(SourceLoader loader) {
|
||||
return UberShaderComponent.builder(Flywheel.rl("cutout"))
|
||||
.materialSources(ShaderIndices.cutout()
|
||||
.all())
|
||||
|
@ -110,7 +117,7 @@ public final class FlwPrograms {
|
|||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.boolLiteral(false))
|
||||
.switchOn(GlslExpr.variable("_flw_uberCutoutIndex"))
|
||||
.build(loadChecker);
|
||||
.build(loader);
|
||||
}
|
||||
|
||||
public static class ResourceReloadListener implements ResourceManagerReloadListener {
|
||||
|
|
|
@ -8,7 +8,8 @@ import org.jetbrains.annotations.Nullable;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.backend.compile.component.StructInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.InstanceStructComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.SsboInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
|
||||
import com.jozufozu.flywheel.backend.compile.core.Compile;
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
|
@ -24,7 +25,7 @@ import com.jozufozu.flywheel.lib.util.ResourceUtil;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class IndirectPrograms extends AtomicReferenceCounted {
|
||||
private static final ResourceLocation CULL_SHADER_HEADER = Flywheel.rl("internal/indirect/cull_header.glsl");
|
||||
private static final ResourceLocation CULL_SHADER_API_IMPL = Flywheel.rl("internal/indirect/cull_api_impl.glsl");
|
||||
private static final ResourceLocation CULL_SHADER_MAIN = Flywheel.rl("internal/indirect/cull.glsl");
|
||||
private static final ResourceLocation APPLY_SHADER_MAIN = Flywheel.rl("internal/indirect/apply.glsl");
|
||||
private static final ResourceLocation SCATTER_SHADER_MAIN = Flywheel.rl("internal/indirect/scatter.glsl");
|
||||
|
@ -78,9 +79,10 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
|||
.link(CULL.shader(GlslVersion.V460, ShaderType.COMPUTE)
|
||||
.nameMapper(instanceType -> "culling/" + ResourceUtil.toDebugFileNameNoExtension(instanceType.cullShader()))
|
||||
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
||||
.withResource(CULL_SHADER_HEADER)
|
||||
.withComponent(StructInstanceComponent::create)
|
||||
.withResource(CULL_SHADER_API_IMPL)
|
||||
.withComponent(InstanceStructComponent::new)
|
||||
.withResource(InstanceType::cullShader)
|
||||
.withComponent(SsboInstanceComponent::new)
|
||||
.withResource(CULL_SHADER_MAIN))
|
||||
.postLink((key, program) -> {
|
||||
program.setUniformBlockBinding("_FlwFrameUniforms", Uniforms.FRAME_INDEX);
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.glsl.GlslVersion;
|
||||
|
@ -13,20 +14,16 @@ import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, ResourceLocation fragmentMain,
|
||||
ResourceLocation vertexApiImpl, ResourceLocation fragmentApiImpl, InstanceAssembler assembler,
|
||||
String compilerMarker, Consumer<GlProgram> onLink) {
|
||||
InstanceAssembler assembler, String compilerMarker, Consumer<GlProgram> onLink) {
|
||||
|
||||
@FunctionalInterface
|
||||
public interface InstanceAssembler {
|
||||
/**
|
||||
* Generate the source component necessary to convert a packed {@link InstanceType} into its shader representation.
|
||||
* Generate the source component necessary to convert a packed {@link Instance} into its shader representation.
|
||||
*
|
||||
* @return A source component defining functions that unpack a representation of the given instance type.
|
||||
*/
|
||||
SourceComponent assemble(InstanceAssemblerContext context);
|
||||
}
|
||||
|
||||
public record InstanceAssemblerContext(int baseAttribute, InstanceType<?> instanceType) {
|
||||
SourceComponent assemble(InstanceType<?> instanceType);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
@ -41,10 +38,6 @@ public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, Res
|
|||
@Nullable
|
||||
private ResourceLocation fragmentMain;
|
||||
@Nullable
|
||||
private ResourceLocation vertexApiImpl;
|
||||
@Nullable
|
||||
private ResourceLocation fragmentApiImpl;
|
||||
@Nullable
|
||||
private InstanceAssembler assembler;
|
||||
@Nullable
|
||||
private String compilerMarker;
|
||||
|
@ -66,16 +59,6 @@ public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, Res
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder vertexApiImpl(ResourceLocation shader) {
|
||||
this.vertexApiImpl = shader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fragmentApiImpl(ResourceLocation shader) {
|
||||
this.fragmentApiImpl = shader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder assembler(InstanceAssembler assembler) {
|
||||
this.assembler = assembler;
|
||||
return this;
|
||||
|
@ -95,12 +78,10 @@ public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, Res
|
|||
Objects.requireNonNull(glslVersion);
|
||||
Objects.requireNonNull(vertexMain);
|
||||
Objects.requireNonNull(fragmentMain);
|
||||
Objects.requireNonNull(vertexApiImpl);
|
||||
Objects.requireNonNull(fragmentApiImpl);
|
||||
Objects.requireNonNull(assembler);
|
||||
Objects.requireNonNull(compilerMarker);
|
||||
Objects.requireNonNull(onLink);
|
||||
return new Pipeline(glslVersion, vertexMain, fragmentMain, vertexApiImpl, fragmentApiImpl, assembler, compilerMarker, onLink);
|
||||
return new Pipeline(glslVersion, vertexMain, fragmentMain, assembler, compilerMarker, onLink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ package com.jozufozu.flywheel.backend.compile;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.InternalVertex;
|
||||
import com.jozufozu.flywheel.backend.Samplers;
|
||||
import com.jozufozu.flywheel.backend.compile.component.InstanceStructComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
|
||||
import com.jozufozu.flywheel.backend.compile.core.Compile;
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
|
@ -13,9 +15,14 @@ import com.jozufozu.flywheel.backend.glsl.ShaderSources;
|
|||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.lib.util.ResourceUtil;
|
||||
|
||||
public class PipelineCompiler {
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class PipelineCompiler {
|
||||
private static final Compile<PipelineProgramKey> PIPELINE = new Compile<>();
|
||||
|
||||
private static final ResourceLocation API_IMPL_VERT = Flywheel.rl("internal/api_impl.vert");
|
||||
private static final ResourceLocation API_IMPL_FRAG = Flywheel.rl("internal/api_impl.frag");
|
||||
|
||||
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
|
||||
return PIPELINE.program()
|
||||
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.VERTEX)
|
||||
|
@ -29,13 +36,14 @@ public class PipelineCompiler {
|
|||
})
|
||||
.onCompile((key, comp) -> key.contextShader()
|
||||
.onCompile(comp))
|
||||
.withResource(pipeline.vertexApiImpl())
|
||||
.withResource(InternalVertex.LAYOUT_SHADER)
|
||||
.withComponent(key -> pipeline.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(InternalVertex.ATTRIBUTE_COUNT, key.instanceType())))
|
||||
.withComponents(vertexComponents)
|
||||
.withResource(API_IMPL_VERT)
|
||||
.withComponent(key -> new InstanceStructComponent(key.instanceType()))
|
||||
.withResource(key -> key.instanceType()
|
||||
.vertexShader())
|
||||
.withComponents(vertexComponents)
|
||||
.withResource(InternalVertex.LAYOUT_SHADER)
|
||||
.withComponent(key -> pipeline.assembler()
|
||||
.assemble(key.instanceType()))
|
||||
.withResource(pipeline.vertexMain()))
|
||||
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
||||
.nameMapper(key -> {
|
||||
|
@ -46,16 +54,16 @@ public class PipelineCompiler {
|
|||
.enableExtension("GL_ARB_conservative_depth")
|
||||
.onCompile((key, comp) -> key.contextShader()
|
||||
.onCompile(comp))
|
||||
.withResource(pipeline.fragmentApiImpl())
|
||||
.withResource(API_IMPL_FRAG)
|
||||
.withComponents(fragmentComponents)
|
||||
.withResource(pipeline.fragmentMain()))
|
||||
.preLink((key, program) -> {
|
||||
program.bindAttribLocation("_flw_a_pos", 0);
|
||||
program.bindAttribLocation("_flw_a_color", 1);
|
||||
program.bindAttribLocation("_flw_a_texCoord", 2);
|
||||
program.bindAttribLocation("_flw_a_overlay", 3);
|
||||
program.bindAttribLocation("_flw_a_light", 4);
|
||||
program.bindAttribLocation("_flw_a_normal", 5);
|
||||
program.bindAttribLocation("_flw_aPos", 0);
|
||||
program.bindAttribLocation("_flw_aColor", 1);
|
||||
program.bindAttribLocation("_flw_aTexCoord", 2);
|
||||
program.bindAttribLocation("_flw_aOverlay", 3);
|
||||
program.bindAttribLocation("_flw_aLight", 4);
|
||||
program.bindAttribLocation("_flw_aNormal", 5);
|
||||
})
|
||||
.postLink((key, program) -> {
|
||||
program.setUniformBlockBinding("_FlwFrameUniforms", Uniforms.FRAME_INDEX);
|
||||
|
|
|
@ -3,7 +3,7 @@ package com.jozufozu.flywheel.backend.compile;
|
|||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Samplers;
|
||||
import com.jozufozu.flywheel.backend.compile.component.BufferTextureInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.StructInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.SsboInstanceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.GlslVersion;
|
||||
|
||||
public final class Pipelines {
|
||||
|
@ -12,20 +12,20 @@ public final class Pipelines {
|
|||
.glslVersion(GlslVersion.V330)
|
||||
.vertexMain(Flywheel.rl("internal/instancing/main.vert"))
|
||||
.fragmentMain(Flywheel.rl("internal/instancing/main.frag"))
|
||||
.vertexApiImpl(Flywheel.rl("internal/instancing/api_impl.vert"))
|
||||
.fragmentApiImpl(Flywheel.rl("internal/instancing/api_impl.frag"))
|
||||
.assembler(BufferTextureInstanceComponent::create)
|
||||
.assembler(BufferTextureInstanceComponent::new)
|
||||
.onLink(program -> program.setSamplerBinding("_flw_instances", Samplers.INSTANCE_BUFFER))
|
||||
.build();
|
||||
|
||||
public static final Pipeline INDIRECT = Pipeline.builder()
|
||||
.compilerMarker("indirect")
|
||||
.glslVersion(GlslVersion.V460)
|
||||
.vertexMain(Flywheel.rl("internal/indirect/main.vert"))
|
||||
.fragmentMain(Flywheel.rl("internal/indirect/main.frag"))
|
||||
.vertexApiImpl(Flywheel.rl("internal/indirect/api_impl.vert"))
|
||||
.fragmentApiImpl(Flywheel.rl("internal/indirect/api_impl.frag"))
|
||||
.assembler(StructInstanceComponent::create)
|
||||
.assembler(SsboInstanceComponent::new)
|
||||
.onLink($ -> {
|
||||
})
|
||||
.build();
|
||||
|
||||
private Pipelines() {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
import com.jozufozu.flywheel.api.layout.MatrixElementType;
|
||||
import com.jozufozu.flywheel.api.layout.ScalarElementType;
|
||||
import com.jozufozu.flywheel.api.layout.UnsignedIntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.ValueRepr;
|
||||
import com.jozufozu.flywheel.api.layout.VectorElementType;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
|
@ -24,66 +13,12 @@ import com.jozufozu.flywheel.backend.glsl.generate.GlslStmt;
|
|||
import com.jozufozu.flywheel.lib.math.MoreMath;
|
||||
|
||||
public class BufferTextureInstanceComponent extends InstanceAssemblerComponent {
|
||||
private static final String UNPACK_ARG = "index";
|
||||
|
||||
private static final String[] SWIZZLE_SELECTORS = { "x", "y", "z", "w" };
|
||||
|
||||
// Each function receives a uint expression as the input.
|
||||
// For byte unpacking, the lowest 8 bits contain the value. For short unpacking, the lowest 16 bits contain the value.
|
||||
// In both cases, all other bits are 0.
|
||||
private static final EnumMap<IntegerRepr, Function<GlslExpr, GlslExpr>> INT_UNPACKING_FUNCS = new EnumMap<>(IntegerRepr.class);
|
||||
private static final EnumMap<UnsignedIntegerRepr, Function<GlslExpr, GlslExpr>> UINT_UNPACKING_FUNCS = new EnumMap<>(UnsignedIntegerRepr.class);
|
||||
private static final EnumMap<FloatRepr, Function<GlslExpr, GlslExpr>> FLOAT_UNPACKING_FUNCS = new EnumMap<>(FloatRepr.class);
|
||||
|
||||
static {
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.BYTE, e -> signExtendByte(e).cast("int"));
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.SHORT, e -> signExtendShort(e).cast("int"));
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.INT, e -> e.cast("int"));
|
||||
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_BYTE, Function.identity());
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_SHORT, Function.identity());
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_INT, Function.identity());
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.BYTE, e -> signExtendByte(e).cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_BYTE, e -> signExtendByte(e).cast("int").cast("float").div(127f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_BYTE, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_BYTE, e -> e.cast("float").div(255f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.SHORT, e -> signExtendShort(e).cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_SHORT, e -> signExtendShort(e).cast("int").cast("float").div(32767f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_SHORT, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_SHORT, e -> e.cast("float").div(65535f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.INT, e -> e.cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_INT, e -> e.cast("int").cast("float").div(2147483647f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_INT, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_INT, e -> e.cast("float").div(4294967295f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.FLOAT, e -> e.callFunction("uintBitsToFloat")); // FIXME: GLSL 330+
|
||||
}
|
||||
|
||||
public BufferTextureInstanceComponent(InstanceType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public static BufferTextureInstanceComponent create(InstanceType<?> type) {
|
||||
return new BufferTextureInstanceComponent(type);
|
||||
}
|
||||
|
||||
public static BufferTextureInstanceComponent create(Pipeline.InstanceAssemblerContext ctx) {
|
||||
return create(ctx.instanceType());
|
||||
}
|
||||
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
|
||||
// Assumes bits higher than sign bit are zero
|
||||
private static GlslExpr signExtendByte(GlslExpr e) {
|
||||
return e.xor(0x80).sub(0x80);
|
||||
}
|
||||
|
||||
private static GlslExpr signExtendShort(GlslExpr e) {
|
||||
return e.xor(0x8000).sub(0x8000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return Flywheel.rl("buffer_texture_instance_assembler").toString();
|
||||
|
@ -91,16 +26,15 @@ public class BufferTextureInstanceComponent extends InstanceAssemblerComponent {
|
|||
|
||||
@Override
|
||||
protected void generateUnpacking(GlslBuilder builder) {
|
||||
var block = new GlslBlock();
|
||||
var fnBody = new GlslBlock();
|
||||
|
||||
// TODO: don't require writing to be 16 byte aligned
|
||||
var texels = MoreMath.ceilingDiv(layout.byteSize(), 16);
|
||||
|
||||
block.add(GlslStmt.raw("int base = " + UNPACK_ARG + " * " + texels + ";"));
|
||||
fnBody.add(GlslStmt.raw("int base = " + UNPACK_ARG + " * " + texels + ";"));
|
||||
|
||||
for (int i = 0; i < texels; i++) {
|
||||
// Fetch all the texels for the given instance ahead of time to simplify the unpacking generators.
|
||||
block.add(GlslStmt.raw("uvec4 u" + i + " = texelFetch(_flw_instances, base + " + i + ");"));
|
||||
fnBody.add(GlslStmt.raw("uvec4 u" + i + " = texelFetch(_flw_instances, base + " + i + ");"));
|
||||
}
|
||||
|
||||
var unpackArgs = new ArrayList<GlslExpr>();
|
||||
|
@ -111,7 +45,7 @@ public class BufferTextureInstanceComponent extends InstanceAssemblerComponent {
|
|||
uintOffset += element.type().byteSize() / 4;
|
||||
}
|
||||
|
||||
block.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
|
||||
fnBody.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
|
||||
|
||||
builder._addRaw("uniform usamplerBuffer _flw_instances;");
|
||||
builder.blankLine();
|
||||
|
@ -121,171 +55,11 @@ public class BufferTextureInstanceComponent extends InstanceAssemblerComponent {
|
|||
.name(UNPACK_FN_NAME)
|
||||
.arg("int", UNPACK_ARG)
|
||||
.build())
|
||||
.body(block);
|
||||
.body(fnBody);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackElement(Layout.Element element, int uintOffset) {
|
||||
var type = element.type();
|
||||
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return unpackScalar(scalar, uintOffset);
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
return unpackVector(vector, uintOffset);
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return unpackMatrix(matrix, uintOffset);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(ScalarElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc;
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
unpackingFunc = INT_UNPACKING_FUNCS.get(intRepr);
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
unpackingFunc = UINT_UNPACKING_FUNCS.get(uintRepr);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
unpackingFunc = FLOAT_UNPACKING_FUNCS.get(floatRepr);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedScalar(uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedScalar(uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedScalar(uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(VectorElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
int size = type.size();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc;
|
||||
String outType;
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
unpackingFunc = INT_UNPACKING_FUNCS.get(intRepr);
|
||||
outType = "ivec" + size;
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
unpackingFunc = UINT_UNPACKING_FUNCS.get(uintRepr);
|
||||
outType = "uvec" + size;
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
unpackingFunc = FLOAT_UNPACKING_FUNCS.get(floatRepr);
|
||||
outType = "vec" + size;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private static GlslExpr unpackMatrix(MatrixElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
int rows = type.rows();
|
||||
int columns = type.columns();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc = FLOAT_UNPACKING_FUNCS.get(repr);
|
||||
String outType = "mat" + columns + "x" + rows;
|
||||
int size = rows * columns;
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isByteBacked(ValueRepr repr) {
|
||||
return repr.byteSize() == Byte.BYTES;
|
||||
}
|
||||
|
||||
private static boolean isShortBacked(ValueRepr repr) {
|
||||
return repr.byteSize() == Short.BYTES;
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
GlslExpr e;
|
||||
if (BIG_ENDIAN) {
|
||||
e = access(uintOffset)
|
||||
.rsh(24)
|
||||
.and(0xFF);
|
||||
} else {
|
||||
e = access(uintOffset)
|
||||
.and(0xFF);
|
||||
}
|
||||
return perElement.apply(e);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
GlslExpr e;
|
||||
if (BIG_ENDIAN) {
|
||||
e = access(uintOffset)
|
||||
.rsh(16)
|
||||
.and(0xFFFF);
|
||||
} else {
|
||||
e = access(uintOffset)
|
||||
.and(0xFFFF);
|
||||
}
|
||||
return perElement.apply(e);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
return perElement.apply(access(uintOffset));
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
// Vectors cannot contain more than 4 elements, but matrix unpacking treats the matrix as a long vector, which for mat4x4 would be the equivalent of a vec16.
|
||||
int bitPos = (i % 4) * 8;
|
||||
if (BIG_ENDIAN) {
|
||||
bitPos = 24 - bitPos;
|
||||
}
|
||||
int wordOffset = i / 4;
|
||||
var element = access(uintOffset + wordOffset)
|
||||
.rsh(bitPos)
|
||||
.and(0xFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = (i % 2) * 16;
|
||||
if (BIG_ENDIAN) {
|
||||
bitPos = 16 - bitPos;
|
||||
}
|
||||
int wordOffset = i / 2;
|
||||
var element = access(uintOffset + wordOffset)
|
||||
.rsh(bitPos)
|
||||
.and(0xFFFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
args.add(perElement.apply(access(uintOffset + i)));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr access(int uintOffset) {
|
||||
@Override
|
||||
protected GlslExpr access(int uintOffset) {
|
||||
return GlslExpr.variable("u" + (uintOffset >> 2))
|
||||
.swizzle(SWIZZLE_SELECTORS[uintOffset & 3]);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,66 @@
|
|||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
import com.jozufozu.flywheel.backend.compile.LayoutInterpreter;
|
||||
import com.jozufozu.flywheel.api.layout.MatrixElementType;
|
||||
import com.jozufozu.flywheel.api.layout.ScalarElementType;
|
||||
import com.jozufozu.flywheel.api.layout.UnsignedIntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.ValueRepr;
|
||||
import com.jozufozu.flywheel.api.layout.VectorElementType;
|
||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
|
||||
public abstract class InstanceAssemblerComponent implements SourceComponent {
|
||||
protected static final String STRUCT_NAME = "FlwInstance";
|
||||
protected static final String UNPACK_FN_NAME = "_flw_unpackInstance";
|
||||
protected static final String UNPACK_ARG = "index";
|
||||
|
||||
protected static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||
private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||
|
||||
// Each function receives a uint expression as the input.
|
||||
// For byte unpacking, the lowest 8 bits contain the value. For short unpacking, the lowest 16 bits contain the value.
|
||||
// In both cases, all other bits are 0.
|
||||
private static final EnumMap<IntegerRepr, Function<GlslExpr, GlslExpr>> INT_UNPACKING_FUNCS = new EnumMap<>(IntegerRepr.class);
|
||||
private static final EnumMap<UnsignedIntegerRepr, Function<GlslExpr, GlslExpr>> UINT_UNPACKING_FUNCS = new EnumMap<>(UnsignedIntegerRepr.class);
|
||||
private static final EnumMap<FloatRepr, Function<GlslExpr, GlslExpr>> FLOAT_UNPACKING_FUNCS = new EnumMap<>(FloatRepr.class);
|
||||
|
||||
static {
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.BYTE, e -> signExtendByte(e).cast("int"));
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.SHORT, e -> signExtendShort(e).cast("int"));
|
||||
INT_UNPACKING_FUNCS.put(IntegerRepr.INT, e -> e.cast("int"));
|
||||
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_BYTE, Function.identity());
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_SHORT, Function.identity());
|
||||
UINT_UNPACKING_FUNCS.put(UnsignedIntegerRepr.UNSIGNED_INT, Function.identity());
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.BYTE, e -> signExtendByte(e).cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_BYTE, e -> signExtendByte(e).cast("int").cast("float").div(127f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_BYTE, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_BYTE, e -> e.cast("float").div(255f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.SHORT, e -> signExtendShort(e).cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_SHORT, e -> signExtendShort(e).cast("int").cast("float").div(32767f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_SHORT, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_SHORT, e -> e.cast("float").div(65535f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.INT, e -> e.cast("int").cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_INT, e -> e.cast("int").cast("float").div(2147483647f).clamp(-1, 1));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.UNSIGNED_INT, e -> e.cast("float"));
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.NORMALIZED_UNSIGNED_INT, e -> e.cast("float").div(4294967295f));
|
||||
|
||||
FLOAT_UNPACKING_FUNCS.put(FloatRepr.FLOAT, e -> e.callFunction("uintBitsToFloat")); // FIXME: GLSL 330+
|
||||
}
|
||||
|
||||
protected final Layout layout;
|
||||
|
||||
|
@ -22,6 +68,16 @@ public abstract class InstanceAssemblerComponent implements SourceComponent {
|
|||
layout = type.layout();
|
||||
}
|
||||
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend
|
||||
// Assumes bits higher than sign bit are zero
|
||||
private static GlslExpr signExtendByte(GlslExpr e) {
|
||||
return e.xor(0x80).sub(0x80);
|
||||
}
|
||||
|
||||
private static GlslExpr signExtendShort(GlslExpr e) {
|
||||
return e.xor(0x8000).sub(0x8000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return Collections.emptyList();
|
||||
|
@ -30,20 +86,173 @@ public abstract class InstanceAssemblerComponent implements SourceComponent {
|
|||
@Override
|
||||
public String source() {
|
||||
var builder = new GlslBuilder();
|
||||
generateInstanceStruct(builder);
|
||||
builder.blankLine();
|
||||
generateUnpacking(builder);
|
||||
builder.blankLine();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected void generateInstanceStruct(GlslBuilder builder) {
|
||||
var instance = builder.struct();
|
||||
instance.setName(STRUCT_NAME);
|
||||
for (var element : layout.elements()) {
|
||||
instance.addField(LayoutInterpreter.typeName(element.type()), element.name());
|
||||
protected abstract void generateUnpacking(GlslBuilder builder);
|
||||
|
||||
protected abstract GlslExpr access(int uintOffset);
|
||||
|
||||
protected GlslExpr unpackElement(Layout.Element element, int uintOffset) {
|
||||
var type = element.type();
|
||||
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return unpackScalar(scalar, uintOffset);
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
return unpackVector(vector, uintOffset);
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return unpackMatrix(matrix, uintOffset);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
private GlslExpr unpackScalar(ScalarElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc;
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
unpackingFunc = INT_UNPACKING_FUNCS.get(intRepr);
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
unpackingFunc = UINT_UNPACKING_FUNCS.get(uintRepr);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
unpackingFunc = FLOAT_UNPACKING_FUNCS.get(floatRepr);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedScalar(uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedScalar(uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedScalar(uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void generateUnpacking(GlslBuilder builder);
|
||||
private GlslExpr unpackVector(VectorElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
int size = type.size();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc;
|
||||
String outType;
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
unpackingFunc = INT_UNPACKING_FUNCS.get(intRepr);
|
||||
outType = "ivec" + size;
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
unpackingFunc = UINT_UNPACKING_FUNCS.get(uintRepr);
|
||||
outType = "uvec" + size;
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
unpackingFunc = FLOAT_UNPACKING_FUNCS.get(floatRepr);
|
||||
outType = "vec" + size;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private GlslExpr unpackMatrix(MatrixElementType type, int uintOffset) {
|
||||
var repr = type.repr();
|
||||
int rows = type.rows();
|
||||
int columns = type.columns();
|
||||
Function<GlslExpr, GlslExpr> unpackingFunc = FLOAT_UNPACKING_FUNCS.get(repr);
|
||||
String outType = "mat" + columns + "x" + rows;
|
||||
int size = rows * columns;
|
||||
|
||||
if (isByteBacked(repr)) {
|
||||
return unpackByteBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else if (isShortBacked(repr)) {
|
||||
return unpackShortBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
} else {
|
||||
return unpackIntBackedVector(outType, size, uintOffset, unpackingFunc);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isByteBacked(ValueRepr repr) {
|
||||
return repr.byteSize() == Byte.BYTES;
|
||||
}
|
||||
|
||||
private boolean isShortBacked(ValueRepr repr) {
|
||||
return repr.byteSize() == Short.BYTES;
|
||||
}
|
||||
|
||||
private GlslExpr unpackByteBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
GlslExpr e;
|
||||
if (BIG_ENDIAN) {
|
||||
e = access(uintOffset)
|
||||
.rsh(24)
|
||||
.and(0xFF);
|
||||
} else {
|
||||
e = access(uintOffset)
|
||||
.and(0xFF);
|
||||
}
|
||||
return perElement.apply(e);
|
||||
}
|
||||
|
||||
private GlslExpr unpackShortBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
GlslExpr e;
|
||||
if (BIG_ENDIAN) {
|
||||
e = access(uintOffset)
|
||||
.rsh(16)
|
||||
.and(0xFFFF);
|
||||
} else {
|
||||
e = access(uintOffset)
|
||||
.and(0xFFFF);
|
||||
}
|
||||
return perElement.apply(e);
|
||||
}
|
||||
|
||||
private GlslExpr unpackIntBackedScalar(int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
return perElement.apply(access(uintOffset));
|
||||
}
|
||||
|
||||
private GlslExpr unpackByteBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
// Vectors cannot contain more than 4 elements, but matrix unpacking treats the matrix as a long vector, which for mat4x4 would be the equivalent of a vec16.
|
||||
int bitPos = (i % 4) * 8;
|
||||
if (BIG_ENDIAN) {
|
||||
bitPos = 24 - bitPos;
|
||||
}
|
||||
int wordOffset = i / 4;
|
||||
var element = access(uintOffset + wordOffset)
|
||||
.rsh(bitPos)
|
||||
.and(0xFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private GlslExpr unpackShortBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = (i % 2) * 16;
|
||||
if (BIG_ENDIAN) {
|
||||
bitPos = 16 - bitPos;
|
||||
}
|
||||
int wordOffset = i / 2;
|
||||
var element = access(uintOffset + wordOffset)
|
||||
.rsh(bitPos)
|
||||
.and(0xFFFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private GlslExpr unpackIntBackedVector(String outType, int size, int uintOffset, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
args.add(perElement.apply(access(uintOffset + i)));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,56 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.ElementType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
import com.jozufozu.flywheel.api.layout.MatrixElementType;
|
||||
import com.jozufozu.flywheel.api.layout.ScalarElementType;
|
||||
import com.jozufozu.flywheel.api.layout.UnsignedIntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.ValueRepr;
|
||||
import com.jozufozu.flywheel.api.layout.VectorElementType;
|
||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
|
||||
public final class LayoutInterpreter {
|
||||
private LayoutInterpreter() {
|
||||
public class InstanceStructComponent implements SourceComponent {
|
||||
private static final String STRUCT_NAME = "FlwInstance";
|
||||
|
||||
private final Layout layout;
|
||||
|
||||
public InstanceStructComponent(InstanceType<?> type) {
|
||||
layout = type.layout();
|
||||
}
|
||||
|
||||
public static int attributeCount(ElementType type) {
|
||||
if (type instanceof ScalarElementType) {
|
||||
return 1;
|
||||
} else if (type instanceof VectorElementType) {
|
||||
return 1;
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return matrix.rows();
|
||||
@Override
|
||||
public String name() {
|
||||
return Flywheel.rl("instance_struct").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source() {
|
||||
var builder = new GlslBuilder();
|
||||
|
||||
var instance = builder.struct();
|
||||
instance.setName(STRUCT_NAME);
|
||||
for (var element : layout.elements()) {
|
||||
instance.addField(typeName(element.type()), element.name());
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
builder.blankLine();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static String typeName(ElementType type) {
|
||||
private static String typeName(ElementType type) {
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return scalarTypeName(scalar.repr());
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
|
@ -37,7 +62,7 @@ public final class LayoutInterpreter {
|
|||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
public static String scalarTypeName(ValueRepr repr) {
|
||||
private static String scalarTypeName(ValueRepr repr) {
|
||||
if (repr instanceof IntegerRepr) {
|
||||
return "int";
|
||||
} else if (repr instanceof UnsignedIntegerRepr) {
|
||||
|
@ -48,7 +73,7 @@ public final class LayoutInterpreter {
|
|||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
public static String vectorTypeName(ValueRepr repr, int size) {
|
||||
private static String vectorTypeName(ValueRepr repr, int size) {
|
||||
if (repr instanceof IntegerRepr) {
|
||||
return "ivec" + size;
|
||||
} else if (repr instanceof UnsignedIntegerRepr) {
|
||||
|
@ -59,7 +84,7 @@ public final class LayoutInterpreter {
|
|||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
public static String matrixTypeName(MatrixElementType matrix) {
|
||||
private static String matrixTypeName(MatrixElementType matrix) {
|
||||
return "mat" + matrix.columns() + "x" + matrix.rows();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
import com.jozufozu.flywheel.backend.engine.indirect.IndirectBuffers;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslStmt;
|
||||
|
||||
public class SsboInstanceComponent extends InstanceAssemblerComponent {
|
||||
public SsboInstanceComponent(InstanceType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return Flywheel.rl("ssbo_instance_assembler").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateUnpacking(GlslBuilder builder) {
|
||||
var fnBody = new GlslBlock();
|
||||
|
||||
var uintCount = layout.byteSize() / 4;
|
||||
|
||||
fnBody.add(GlslStmt.raw("uint base = " + UNPACK_ARG + " * " + uintCount + "u;"));
|
||||
|
||||
for (int i = 0; i < uintCount; i++) {
|
||||
// Retrieve all the uints for the given instance ahead of time to simplify the unpacking generators.
|
||||
fnBody.add(GlslStmt.raw("uint u" + i + " = _flw_instances[base + " + i + "u];"));
|
||||
}
|
||||
|
||||
var unpackArgs = new ArrayList<GlslExpr>();
|
||||
int uintOffset = 0;
|
||||
for (Layout.Element element : layout.elements()) {
|
||||
unpackArgs.add(unpackElement(element, uintOffset));
|
||||
// Element byte size is always a multiple of 4
|
||||
uintOffset += element.type().byteSize() / 4;
|
||||
}
|
||||
|
||||
fnBody.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
|
||||
|
||||
builder._addRaw("layout(std430, binding = " + IndirectBuffers.INSTANCE_INDEX + ") restrict readonly buffer InstanceBuffer {\n"
|
||||
+ " uint _flw_instances[];\n"
|
||||
+ "};");
|
||||
builder.blankLine();
|
||||
builder.function()
|
||||
.signature(FnSignature.create()
|
||||
.returnType(STRUCT_NAME)
|
||||
.name(UNPACK_FN_NAME)
|
||||
.arg("uint", UNPACK_ARG)
|
||||
.build())
|
||||
.body(fnBody);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlslExpr access(int uintOffset) {
|
||||
return GlslExpr.variable("u" + uintOffset);
|
||||
}
|
||||
}
|
|
@ -1,308 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.compile.component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.layout.FloatRepr;
|
||||
import com.jozufozu.flywheel.api.layout.IntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.Layout;
|
||||
import com.jozufozu.flywheel.api.layout.MatrixElementType;
|
||||
import com.jozufozu.flywheel.api.layout.ScalarElementType;
|
||||
import com.jozufozu.flywheel.api.layout.UnsignedIntegerRepr;
|
||||
import com.jozufozu.flywheel.api.layout.VectorElementType;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBlock;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.backend.glsl.generate.GlslStruct;
|
||||
|
||||
// TODO: Use a uvec4[] instead of a FlwPackedInstance[] in the SSBO to store data and reuse unpacking code from BufferTextureInstanceComponent.
|
||||
// Unpacking should be moved from BufferTextureInstanceComponent to InstanceAssemblerComponent and this class should be renamed to SsboInstanceComponent. Further abstraction may be possible.
|
||||
// Currently, some of the unpacking code generated by this class is incorrect. It is correct in BufferTextureInstanceComponent.
|
||||
public class StructInstanceComponent extends InstanceAssemblerComponent {
|
||||
private static final String UNPACK_ARG = "p";
|
||||
private static final GlslExpr.Variable UNPACKING_VARIABLE = GlslExpr.variable(UNPACK_ARG);
|
||||
private static final String PACKED_STRUCT_NAME = "FlwPackedInstance";
|
||||
|
||||
public StructInstanceComponent(InstanceType<?> type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public static StructInstanceComponent create(InstanceType<?> type) {
|
||||
return new StructInstanceComponent(type);
|
||||
}
|
||||
|
||||
public static StructInstanceComponent create(Pipeline.InstanceAssemblerContext ctx) {
|
||||
return create(ctx.instanceType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return Flywheel.rl("struct_instance_assembler").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void generateUnpacking(GlslBuilder builder) {
|
||||
var packed = builder.struct();
|
||||
packed.setName(PACKED_STRUCT_NAME);
|
||||
|
||||
var unpackArgs = new ArrayList<GlslExpr>();
|
||||
|
||||
for (Layout.Element element : layout.elements()) {
|
||||
unpackArgs.add(unpackElement(element, packed));
|
||||
}
|
||||
|
||||
var block = new GlslBlock();
|
||||
block.ret(GlslExpr.call(STRUCT_NAME, unpackArgs));
|
||||
|
||||
builder.blankLine();
|
||||
builder.function()
|
||||
.signature(FnSignature.create()
|
||||
.returnType(STRUCT_NAME)
|
||||
.name(UNPACK_FN_NAME)
|
||||
.arg(PACKED_STRUCT_NAME, UNPACK_ARG)
|
||||
.build())
|
||||
.body(block);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackElement(Layout.Element element, GlslStruct packed) {
|
||||
// FIXME: I don't think we're unpacking signed byte/short values correctly
|
||||
// FIXME: we definitely don't consider endianness. this all assumes little endian which works on my machine.
|
||||
var type = element.type();
|
||||
var name = element.name();
|
||||
|
||||
if (type instanceof ScalarElementType scalar) {
|
||||
return unpackScalar(scalar, name, packed);
|
||||
} else if (type instanceof VectorElementType vector) {
|
||||
return unpackVector(vector, name, packed);
|
||||
} else if (type instanceof MatrixElementType matrix) {
|
||||
return unpackMatrix(matrix, name, packed);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown type " + type);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(ScalarElementType type, String fieldName, GlslStruct packed) {
|
||||
var repr = type.repr();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntScalar(intRepr, fieldName, packed);
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
return unpackUintScalar(uintRepr, fieldName, packed);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatScalar(floatRepr, fieldName, packed);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntScalar(IntegerRepr repr, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF)
|
||||
.cast("int"));
|
||||
case SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF)
|
||||
.cast("int"));
|
||||
case INT -> unpackScalar("int", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUintScalar(UnsignedIntegerRepr repr, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case UNSIGNED_BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF));
|
||||
case UNSIGNED_SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF));
|
||||
case UNSIGNED_INT -> unpackScalar("uint", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatScalar(FloatRepr repr, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_BYTE -> unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackSnorm4x8")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_BYTE -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_BYTE ->
|
||||
unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackUnorm4x8")
|
||||
.swizzle("x"));
|
||||
case SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF)
|
||||
.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_SHORT -> unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackSnorm2x16")
|
||||
.swizzle("x"));
|
||||
case UNSIGNED_SHORT -> unpackScalar("uint", fieldName, packed, e -> e.and(0xFFFF)
|
||||
.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_SHORT ->
|
||||
unpackScalar("uint", fieldName, packed, e -> e.callFunction("unpackUnorm2x16")
|
||||
.swizzle("x"));
|
||||
case INT -> unpackScalar("int", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_INT -> unpackScalar("int", fieldName, packed, e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case UNSIGNED_INT -> unpackScalar("uint", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_INT -> unpackScalar("uint", fieldName, packed, e -> e.div(4294967295f));
|
||||
case FLOAT -> unpackScalar("float", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(String packedType, String fieldName, GlslStruct packed) {
|
||||
return unpackScalar(packedType, fieldName, packed, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpackScalar(String packedType, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
packed.addField(packedType, fieldName);
|
||||
return perElement.apply(UNPACKING_VARIABLE.access(fieldName));
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(VectorElementType type, String fieldName, GlslStruct packed) {
|
||||
var repr = type.repr();
|
||||
int size = type.size();
|
||||
|
||||
if (repr instanceof IntegerRepr intRepr) {
|
||||
return unpackIntVector(intRepr, size, fieldName, packed);
|
||||
} else if (repr instanceof UnsignedIntegerRepr uintRepr) {
|
||||
return unpackUintVector(uintRepr, size, fieldName, packed);
|
||||
} else if (repr instanceof FloatRepr floatRepr) {
|
||||
return unpackFloatVector(floatRepr, size, fieldName, packed);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown repr " + repr);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackIntVector(IntegerRepr repr, int size, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackByteBackedVector("ivec" + size, size, fieldName, packed, e -> e.cast("int"));
|
||||
case SHORT -> unpackShortBackedVector("ivec" + size, size, fieldName, packed, e -> e.cast("int"));
|
||||
case INT -> unpackVector("ivec" + size, size, "int", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackUintVector(UnsignedIntegerRepr repr, int size, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case UNSIGNED_BYTE -> unpackByteBackedVector("uvec" + size, size, fieldName, packed, e -> e.cast("uint"));
|
||||
case UNSIGNED_SHORT -> unpackShortBackedVector("uvec" + size, size, fieldName, packed, e -> e.cast("uint"));
|
||||
case UNSIGNED_INT -> unpackVector("uvec" + size, size, "uint", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackFloatVector(FloatRepr repr, int size, String fieldName, GlslStruct packed) {
|
||||
return switch (repr) {
|
||||
case BYTE -> unpackByteBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_BYTE -> unpackByteBuiltinVector(size, fieldName, packed, "unpackSnorm4x8");
|
||||
case UNSIGNED_BYTE -> unpackByteBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_BYTE -> unpackByteBuiltinVector(size, fieldName, packed, "unpackUnorm4x8");
|
||||
case SHORT -> unpackShortBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("int")
|
||||
.cast("float"));
|
||||
case NORMALIZED_SHORT -> unpackShortBuiltinVector(size, fieldName, packed, "unpackSnorm2x16");
|
||||
case UNSIGNED_SHORT -> unpackShortBackedVector("vec" + size, size, fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_SHORT -> unpackShortBuiltinVector(size, fieldName, packed, "unpackUnorm2x16");
|
||||
case INT -> unpackVector("vec" + size, size, "int", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_INT -> unpackVector("vec" + size, size, "int", fieldName, packed, e -> e.div(2147483647f)
|
||||
.clamp(-1, 1));
|
||||
case UNSIGNED_INT -> unpackVector("vec" + size, size, "float", fieldName, packed, e -> e.cast("float"));
|
||||
case NORMALIZED_UNSIGNED_INT ->
|
||||
unpackVector("vec" + size, size, "uint", fieldName, packed, e -> e.div(4294967295f));
|
||||
case FLOAT -> unpackVector("vec" + size, size, "float", fieldName, packed);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBackedVector(String outType, int size, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
packed.addField("uint", fieldName);
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int bitPos = i * 8;
|
||||
var element = UNPACKING_VARIABLE.access(fieldName)
|
||||
.rsh(bitPos)
|
||||
.and(0xFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBackedVector(String outType, int size, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
int unpackField = i / 2;
|
||||
int bitPos = (i % 2) * 16;
|
||||
var name = fieldName + "_" + unpackField;
|
||||
if (bitPos == 0) {
|
||||
// First time we're seeing this field, add it to the struct.
|
||||
packed.addField("uint", name);
|
||||
}
|
||||
var element = UNPACKING_VARIABLE.access(name)
|
||||
.rsh(bitPos)
|
||||
.and(0xFFFF);
|
||||
args.add(perElement.apply(element));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackByteBuiltinVector(int size, String fieldName, GlslStruct packed, String func) {
|
||||
packed.addField("uint", fieldName);
|
||||
GlslExpr expr = UNPACKING_VARIABLE.access(fieldName)
|
||||
.callFunction(func);
|
||||
return switch (size) {
|
||||
case 2 -> expr.swizzle("xy");
|
||||
case 3 -> expr.swizzle("xyz");
|
||||
case 4 -> expr;
|
||||
default -> throw new IllegalArgumentException("Invalid vector size " + size);
|
||||
};
|
||||
}
|
||||
|
||||
private static GlslExpr unpackShortBuiltinVector(int size, String fieldName, GlslStruct packed, String func) {
|
||||
if (size == 2) {
|
||||
packed.addField("uint", fieldName);
|
||||
return UNPACKING_VARIABLE.access(fieldName)
|
||||
.callFunction(func);
|
||||
} else {
|
||||
var name0 = fieldName + "_" + 0;
|
||||
var name1 = fieldName + "_" + 1;
|
||||
packed.addField("uint", name0);
|
||||
packed.addField("uint", name1);
|
||||
GlslExpr xy = UNPACKING_VARIABLE.access(name0)
|
||||
.callFunction(func);
|
||||
|
||||
GlslExpr zw = UNPACKING_VARIABLE.access(name1)
|
||||
.callFunction(func);
|
||||
|
||||
if (size == 3) {
|
||||
return GlslExpr.call("vec3", List.of(xy.swizzle("xy"), zw.swizzle("x")));
|
||||
} else {
|
||||
return GlslExpr.call("vec4", List.of(xy, zw));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(String outType, int size, String backingType, String fieldName, GlslStruct packed) {
|
||||
return unpackVector(outType, size, backingType, fieldName, packed, Function.identity());
|
||||
}
|
||||
|
||||
private static GlslExpr unpackVector(String outType, int size, String backingType, String fieldName, GlslStruct packed, Function<GlslExpr, GlslExpr> perElement) {
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
var name = fieldName + "_" + i;
|
||||
packed.addField(backingType, name);
|
||||
args.add(perElement.apply(UNPACKING_VARIABLE.access(name)));
|
||||
}
|
||||
return GlslExpr.call(outType, args);
|
||||
}
|
||||
|
||||
private static GlslExpr unpackMatrix(MatrixElementType type, String name, GlslStruct packed) {
|
||||
var repr = type.repr();
|
||||
int rows = type.rows();
|
||||
int columns = type.columns();
|
||||
|
||||
List<GlslExpr> args = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < columns; i++) {
|
||||
args.add(unpackFloatVector(repr, rows, name + "_" + i, packed));
|
||||
}
|
||||
|
||||
return GlslExpr.call("mat" + columns + "x" + rows, args);
|
||||
}
|
||||
}
|
|
@ -148,8 +148,8 @@ public class UberShaderComponent implements SourceComponent {
|
|||
int index = 0;
|
||||
for (var rl : materialSources) {
|
||||
SourceFile sourceFile = sources.find(rl);
|
||||
final int finalIndex = index;
|
||||
if (sourceFile != null) {
|
||||
final int finalIndex = index;
|
||||
var adapterMap = createAdapterMap(adaptedFunctions, fnName -> "_" + fnName + "_" + finalIndex);
|
||||
transformed.add(new StringSubstitutionComponent(sourceFile, adapterMap));
|
||||
} else {
|
||||
|
|
|
@ -43,7 +43,6 @@ public class Compile<K> {
|
|||
public static class ProgramStitcher<K> implements CompilationHarness.KeyCompiler<K> {
|
||||
private final Map<ShaderType, ShaderCompiler<K>> compilers = new EnumMap<>(ShaderType.class);
|
||||
private BiConsumer<K, GlProgram> postLink = (k, p) -> {
|
||||
|
||||
};
|
||||
private BiConsumer<K, GlProgram> preLink = (k, p) -> {
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
|||
|
||||
public class IndirectBuffers {
|
||||
// Number of vbos created.
|
||||
public static final int BUFFER_COUNT = 4;
|
||||
public static final int BUFFER_COUNT = 5;
|
||||
|
||||
public static final long INT_SIZE = Integer.BYTES;
|
||||
public static final long PTR_SIZE = Pointer.POINTER_SIZE;
|
||||
|
@ -22,10 +22,11 @@ public class IndirectBuffers {
|
|||
public static final long DRAW_COMMAND_STRIDE = 40;
|
||||
public static final long DRAW_COMMAND_OFFSET = 0;
|
||||
|
||||
public static final int OBJECT_INDEX = 0;
|
||||
public static final int INSTANCE_INDEX = 0;
|
||||
public static final int TARGET_INDEX = 1;
|
||||
public static final int MODEL_INDEX = 2;
|
||||
public static final int DRAW_INDEX = 3;
|
||||
public static final int MODEL_INDEX_INDEX = 2;
|
||||
public static final int MODEL_INDEX = 3;
|
||||
public static final int DRAW_INDEX = 4;
|
||||
|
||||
|
||||
// Offsets to the 3 segments
|
||||
|
@ -36,18 +37,20 @@ public class IndirectBuffers {
|
|||
private static final long BUFFERS_SIZE_BYTES = SIZE_OFFSET + BUFFER_COUNT * PTR_SIZE;
|
||||
|
||||
// Offsets to the vbos
|
||||
private static final long OBJECT_HANDLE_OFFSET = HANDLE_OFFSET;
|
||||
private static final long INSTANCE_HANDLE_OFFSET = HANDLE_OFFSET;
|
||||
private static final long TARGET_HANDLE_OFFSET = INT_SIZE;
|
||||
private static final long MODEL_HANDLE_OFFSET = INT_SIZE * 2;
|
||||
private static final long DRAW_HANDLE_OFFSET = INT_SIZE * 3;
|
||||
private static final long MODEL_INDEX_HANDLE_OFFSET = INT_SIZE * 2;
|
||||
private static final long MODEL_HANDLE_OFFSET = INT_SIZE * 3;
|
||||
private static final long DRAW_HANDLE_OFFSET = INT_SIZE * 4;
|
||||
|
||||
// Offsets to the sizes
|
||||
private static final long OBJECT_SIZE_OFFSET = SIZE_OFFSET;
|
||||
private static final long INSTANCE_SIZE_OFFSET = SIZE_OFFSET;
|
||||
private static final long TARGET_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE;
|
||||
private static final long MODEL_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 2;
|
||||
private static final long DRAW_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 3;
|
||||
private static final long MODEL_INDEX_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 2;
|
||||
private static final long MODEL_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 3;
|
||||
private static final long DRAW_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 4;
|
||||
|
||||
private static final float OBJECT_GROWTH_FACTOR = 1.25f;
|
||||
private static final float INSTANCE_GROWTH_FACTOR = 1.25f;
|
||||
private static final float MODEL_GROWTH_FACTOR = 2f;
|
||||
private static final float DRAW_GROWTH_FACTOR = 2f;
|
||||
|
||||
|
@ -61,39 +64,44 @@ public class IndirectBuffers {
|
|||
* {@code sizes}: an array of {@link IndirectBuffers#PTR_SIZE} byte lengths of the buffers.
|
||||
* <br>
|
||||
* Each segment stores {@link IndirectBuffers#BUFFER_COUNT} elements,
|
||||
* one for the object buffer, target buffer, model buffer, and draw buffer.
|
||||
* one for the instance buffer, target buffer, model index buffer, model buffer, and draw buffer.
|
||||
*/
|
||||
private final MemoryBlock multiBindBlock;
|
||||
private final long objectStride;
|
||||
public final ResizableStorageArray object;
|
||||
private final long instanceStride;
|
||||
public final ResizableStorageArray instance;
|
||||
public final ResizableStorageArray target;
|
||||
public final ResizableStorageArray modelIndex;
|
||||
public final ResizableStorageArray model;
|
||||
public final ResizableStorageArray draw;
|
||||
|
||||
IndirectBuffers(long objectStride) {
|
||||
this.objectStride = objectStride;
|
||||
IndirectBuffers(long instanceStride) {
|
||||
this.instanceStride = instanceStride;
|
||||
this.multiBindBlock = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1);
|
||||
|
||||
object = new ResizableStorageArray(objectStride, OBJECT_GROWTH_FACTOR);
|
||||
target = new ResizableStorageArray(INT_SIZE, OBJECT_GROWTH_FACTOR);
|
||||
instance = new ResizableStorageArray(instanceStride, INSTANCE_GROWTH_FACTOR);
|
||||
target = new ResizableStorageArray(INT_SIZE, INSTANCE_GROWTH_FACTOR);
|
||||
modelIndex = new ResizableStorageArray(INT_SIZE, INSTANCE_GROWTH_FACTOR);
|
||||
model = new ResizableStorageArray(MODEL_STRIDE, MODEL_GROWTH_FACTOR);
|
||||
draw = new ResizableStorageArray(DRAW_COMMAND_STRIDE, DRAW_GROWTH_FACTOR);
|
||||
}
|
||||
|
||||
void updateCounts(int objectCount, int modelCount, int drawCount) {
|
||||
object.ensureCapacity(objectCount);
|
||||
target.ensureCapacity(objectCount);
|
||||
void updateCounts(int instanceCount, int modelCount, int drawCount) {
|
||||
instance.ensureCapacity(instanceCount);
|
||||
target.ensureCapacity(instanceCount);
|
||||
modelIndex.ensureCapacity(instanceCount);
|
||||
model.ensureCapacity(modelCount);
|
||||
draw.ensureCapacity(drawCount);
|
||||
|
||||
final long ptr = multiBindBlock.ptr();
|
||||
MemoryUtil.memPutInt(ptr + OBJECT_HANDLE_OFFSET, object.handle());
|
||||
MemoryUtil.memPutInt(ptr + INSTANCE_HANDLE_OFFSET, instance.handle());
|
||||
MemoryUtil.memPutInt(ptr + TARGET_HANDLE_OFFSET, target.handle());
|
||||
MemoryUtil.memPutInt(ptr + MODEL_INDEX_HANDLE_OFFSET, modelIndex.handle());
|
||||
MemoryUtil.memPutInt(ptr + MODEL_HANDLE_OFFSET, model.handle());
|
||||
MemoryUtil.memPutInt(ptr + DRAW_HANDLE_OFFSET, draw.handle());
|
||||
|
||||
MemoryUtil.memPutAddress(ptr + OBJECT_SIZE_OFFSET, objectStride * objectCount);
|
||||
MemoryUtil.memPutAddress(ptr + TARGET_SIZE_OFFSET, INT_SIZE * objectCount);
|
||||
MemoryUtil.memPutAddress(ptr + INSTANCE_SIZE_OFFSET, instanceStride * instanceCount);
|
||||
MemoryUtil.memPutAddress(ptr + TARGET_SIZE_OFFSET, INT_SIZE * instanceCount);
|
||||
MemoryUtil.memPutAddress(ptr + MODEL_INDEX_SIZE_OFFSET, INT_SIZE * instanceCount);
|
||||
MemoryUtil.memPutAddress(ptr + MODEL_SIZE_OFFSET, MODEL_STRIDE * modelCount);
|
||||
MemoryUtil.memPutAddress(ptr + DRAW_SIZE_OFFSET, DRAW_COMMAND_STRIDE * drawCount);
|
||||
}
|
||||
|
@ -112,16 +120,20 @@ public class IndirectBuffers {
|
|||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, IndirectBuffers.BUFFER_COUNT, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind all buffers except the draw command buffer.
|
||||
*/
|
||||
public void bindForCrumbling() {
|
||||
final long ptr = multiBindBlock.ptr();
|
||||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, 3, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
nglBindBuffersRange(GL_SHADER_STORAGE_BUFFER, 0, 4, ptr, ptr + OFFSET_OFFSET, ptr + SIZE_OFFSET);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
multiBindBlock.free();
|
||||
|
||||
object.delete();
|
||||
instance.delete();
|
||||
target.delete();
|
||||
modelIndex.delete();
|
||||
model.delete();
|
||||
draw.delete();
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
|
||||
private final InstanceType<I> instanceType;
|
||||
private final Environment environment;
|
||||
private final long objectStride;
|
||||
private final long instanceStride;
|
||||
private final IndirectBuffers buffers;
|
||||
private final List<IndirectInstancer<?>> instancers = new ArrayList<>();
|
||||
private final List<IndirectDraw> indirectDraws = new ArrayList<>();
|
||||
|
@ -57,9 +57,9 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
IndirectCullingGroup(InstanceType<I> instanceType, Environment environment, IndirectPrograms programs) {
|
||||
this.instanceType = instanceType;
|
||||
this.environment = environment;
|
||||
objectStride = instanceType.layout()
|
||||
.byteSize() + IndirectBuffers.INT_SIZE;
|
||||
buffers = new IndirectBuffers(objectStride);
|
||||
instanceStride = instanceType.layout()
|
||||
.byteSize();
|
||||
buffers = new IndirectBuffers(instanceStride);
|
||||
|
||||
this.programs = programs;
|
||||
cullProgram = programs.getCullingProgram(instanceType);
|
||||
|
@ -100,8 +100,8 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
|
||||
buffers.updateCounts(instanceCountThisFrame, instancers.size(), indirectDraws.size());
|
||||
|
||||
// Upload only objects that have changed.
|
||||
uploadObjects(stagingBuffer);
|
||||
// Upload only instances that have changed.
|
||||
uploadInstances(stagingBuffer);
|
||||
|
||||
// We need to upload the models every frame to reset the instance count.
|
||||
uploadModels(stagingBuffer);
|
||||
|
@ -234,13 +234,9 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
}
|
||||
}
|
||||
|
||||
private void uploadObjects(StagingBuffer stagingBuffer) {
|
||||
long pos = 0;
|
||||
private void uploadInstances(StagingBuffer stagingBuffer) {
|
||||
for (var model : instancers) {
|
||||
var instanceCount = model.instanceCount();
|
||||
model.uploadObjects(stagingBuffer, pos, buffers.object.handle());
|
||||
|
||||
pos += instanceCount * objectStride;
|
||||
model.uploadInstances(stagingBuffer, buffers.instance.handle(), buffers.modelIndex.handle());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,21 +14,20 @@ import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
|||
import com.jozufozu.flywheel.backend.engine.embed.Environment;
|
||||
|
||||
public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I> {
|
||||
private final long objectStride;
|
||||
private final long instanceStride;
|
||||
private final InstanceWriter<I> writer;
|
||||
private final List<IndirectDraw> associatedDraws = new ArrayList<>();
|
||||
private final Vector4fc boundingSphere;
|
||||
|
||||
|
||||
public int index;
|
||||
public int index = -1;
|
||||
public int baseInstance = -1;
|
||||
private int lastModelIndex = -1;
|
||||
private long lastStartPos = -1;
|
||||
private int lastBaseInstance = -1;
|
||||
|
||||
public IndirectInstancer(InstanceType<I> type, Environment environment, Model model) {
|
||||
super(type, environment);
|
||||
this.objectStride = type.layout()
|
||||
.byteSize() + IndirectBuffers.INT_SIZE;
|
||||
instanceStride = type.layout()
|
||||
.byteSize();
|
||||
writer = this.type.writer();
|
||||
boundingSphere = model.boundingSphere();
|
||||
}
|
||||
|
@ -54,52 +53,65 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
MemoryUtil.memPutFloat(ptr + 20, boundingSphere.w());
|
||||
}
|
||||
|
||||
public void uploadObjects(StagingBuffer stagingBuffer, long startPos, int dstVbo) {
|
||||
if (shouldUploadAll(startPos)) {
|
||||
uploadAll(stagingBuffer, startPos, dstVbo);
|
||||
public void uploadInstances(StagingBuffer stagingBuffer, int instanceVbo, int modelIndexVbo) {
|
||||
long baseByte = baseInstance * instanceStride;
|
||||
long modelIndexBaseByte = baseInstance * IndirectBuffers.INT_SIZE;
|
||||
|
||||
if (shouldUploadAll()) {
|
||||
uploadAll(stagingBuffer, baseByte, modelIndexBaseByte, instanceVbo, modelIndexVbo);
|
||||
} else {
|
||||
uploadChanged(stagingBuffer, startPos, dstVbo);
|
||||
uploadChanged(stagingBuffer, baseByte, modelIndexBaseByte, instanceVbo, modelIndexVbo);
|
||||
}
|
||||
|
||||
changed.clear();
|
||||
lastStartPos = startPos;
|
||||
lastModelIndex = index;
|
||||
lastBaseInstance = baseInstance;
|
||||
}
|
||||
|
||||
private boolean shouldUploadAll(long startPos) {
|
||||
return startPos != lastStartPos || index != lastModelIndex;
|
||||
private boolean shouldUploadAll() {
|
||||
return baseInstance != lastBaseInstance || index != lastModelIndex;
|
||||
}
|
||||
|
||||
private void uploadChanged(StagingBuffer stagingBuffer, long baseByte, int dstVbo) {
|
||||
private void uploadChanged(StagingBuffer stagingBuffer, long baseByte, long modelIndexBaseByte, int instanceVbo, int modelIndexVbo) {
|
||||
changed.forEachSetSpan((startInclusive, endInclusive) -> {
|
||||
var totalSize = (endInclusive - startInclusive + 1) * objectStride;
|
||||
int instanceCount = endInclusive - startInclusive + 1;
|
||||
long totalSize = instanceCount * instanceStride;
|
||||
long modelIndexTotalSize = instanceCount * IndirectBuffers.INT_SIZE;
|
||||
|
||||
stagingBuffer.enqueueCopy(totalSize, dstVbo, baseByte + startInclusive * objectStride, ptr -> {
|
||||
stagingBuffer.enqueueCopy(totalSize, instanceVbo, baseByte + startInclusive * instanceStride, ptr -> {
|
||||
for (int i = startInclusive; i <= endInclusive; i++) {
|
||||
var instance = instances.get(i);
|
||||
writeOne(ptr, instance);
|
||||
ptr += objectStride;
|
||||
writer.write(ptr, instance);
|
||||
ptr += instanceStride;
|
||||
}
|
||||
});
|
||||
|
||||
stagingBuffer.enqueueCopy(modelIndexTotalSize, modelIndexVbo, modelIndexBaseByte + startInclusive * IndirectBuffers.INT_SIZE, ptr -> {
|
||||
for (int i = startInclusive; i <= endInclusive; i++) {
|
||||
MemoryUtil.memPutInt(ptr, index);
|
||||
ptr += IndirectBuffers.INT_SIZE;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void uploadAll(StagingBuffer stagingBuffer, long start, int dstVbo) {
|
||||
long totalSize = objectStride * instances.size();
|
||||
private void uploadAll(StagingBuffer stagingBuffer, long baseByte, long modelIndexBaseByte, int instanceVbo, int modelIndexVbo) {
|
||||
long totalSize = instances.size() * instanceStride;
|
||||
long modelIndexTotalSize = instances.size() * IndirectBuffers.INT_SIZE;
|
||||
|
||||
stagingBuffer.enqueueCopy(totalSize, dstVbo, start, this::uploadAll);
|
||||
}
|
||||
stagingBuffer.enqueueCopy(totalSize, instanceVbo, baseByte, ptr -> {
|
||||
for (I instance : instances) {
|
||||
writer.write(ptr, instance);
|
||||
ptr += instanceStride;
|
||||
}
|
||||
});
|
||||
|
||||
private void uploadAll(long ptr) {
|
||||
for (I instance : instances) {
|
||||
writeOne(ptr, instance);
|
||||
ptr += objectStride;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOne(long ptr, I instance) {
|
||||
MemoryUtil.memPutInt(ptr, index);
|
||||
writer.write(ptr + IndirectBuffers.INT_SIZE, instance);
|
||||
stagingBuffer.enqueueCopy(modelIndexTotalSize, modelIndexVbo, modelIndexBaseByte, ptr -> {
|
||||
for (int i = 0; i < instances.size(); i++) {
|
||||
MemoryUtil.memPutInt(ptr, index);
|
||||
ptr += IndirectBuffers.INT_SIZE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package com.jozufozu.flywheel.backend.engine.uniform;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
|
||||
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.config.DebugMode;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
package com.jozufozu.flywheel.backend.mixin;
|
||||
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
|
||||
import net.minecraft.client.Options;
|
||||
|
||||
@Mixin(Options.class)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#include "flywheel:internal/common_api_impl.frag"
|
||||
|
||||
uint _flw_uberMaterialFragmentIndex;
|
||||
uint _flw_uberFogIndex;
|
||||
uint _flw_uberCutoutIndex;
|
|
@ -0,0 +1 @@
|
|||
uint _flw_uberMaterialVertexIndex;
|
|
@ -1,5 +0,0 @@
|
|||
#include "flywheel:internal/common_api_impl.frag"
|
||||
|
||||
uint _flw_uberMaterialFragmentIndex;
|
||||
uint _flw_uberFogIndex;
|
||||
uint _flw_uberCutoutIndex;
|
|
@ -1,3 +0,0 @@
|
|||
#include "flywheel:internal/common_api_impl.vert"
|
||||
|
||||
uint _flw_uberMaterialVertexIndex;
|
|
@ -1,6 +1,6 @@
|
|||
#include "flywheel:internal/indirect/buffers.glsl"
|
||||
#include "flywheel:internal/indirect/model_descriptor.glsl"
|
||||
#include "flywheel:internal/indirect/buffer_bindings.glsl"
|
||||
#include "flywheel:internal/indirect/draw_command.glsl"
|
||||
#include "flywheel:internal/indirect/model_descriptor.glsl"
|
||||
|
||||
layout(local_size_x = _FLW_SUBGROUP_SIZE) in;
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#define _FLW_INSTANCE_BUFFER_BINDING 0
|
||||
#define _FLW_TARGET_BUFFER_BINDING 1
|
||||
#define _FLW_MODEL_INDEX_BUFFER_BINDING 2
|
||||
#define _FLW_MODEL_BUFFER_BINDING 3
|
||||
#define _FLW_DRAW_BUFFER_BINDING 4
|
|
@ -1,4 +0,0 @@
|
|||
#define _FLW_OBJECT_BUFFER_BINDING 0
|
||||
#define _FLW_TARGET_BUFFER_BINDING 1
|
||||
#define _FLW_MODEL_BUFFER_BINDING 2
|
||||
#define _FLW_DRAW_BUFFER_BINDING 3
|
|
@ -1,21 +1,20 @@
|
|||
#include "flywheel:internal/indirect/buffers.glsl"
|
||||
#include "flywheel:internal/indirect/buffer_bindings.glsl"
|
||||
#include "flywheel:internal/indirect/model_descriptor.glsl"
|
||||
#include "flywheel:internal/indirect/object.glsl"
|
||||
#include "flywheel:internal/uniforms/uniforms.glsl"
|
||||
#include "flywheel:util/matrix.glsl"
|
||||
|
||||
layout(local_size_x = _FLW_SUBGROUP_SIZE) in;
|
||||
|
||||
layout(std430, binding = _FLW_OBJECT_BUFFER_BINDING) restrict readonly buffer ObjectBuffer {
|
||||
Object objects[];
|
||||
layout(std430, binding = _FLW_TARGET_BUFFER_BINDING) restrict writeonly buffer TargetBuffer {
|
||||
uint _flw_instanceIndices[];
|
||||
};
|
||||
|
||||
layout(std430, binding = _FLW_TARGET_BUFFER_BINDING) restrict writeonly buffer TargetBuffer {
|
||||
uint objectIndices[];
|
||||
layout(std430, binding = _FLW_MODEL_INDEX_BUFFER_BINDING) restrict readonly buffer ModelIndexBuffer {
|
||||
uint _flw_modelIndices[];
|
||||
};
|
||||
|
||||
layout(std430, binding = _FLW_MODEL_BUFFER_BINDING) restrict buffer ModelBuffer {
|
||||
ModelDescriptor models[];
|
||||
ModelDescriptor _flw_models[];
|
||||
};
|
||||
|
||||
uniform mat4 _flw_embeddedModel;
|
||||
|
@ -34,14 +33,14 @@ bool _flw_testSphere(vec3 center, float radius) {
|
|||
return all(xyInside) && all(zInside);
|
||||
}
|
||||
|
||||
bool _flw_isVisible(uint objectIndex, uint modelIndex) {
|
||||
BoundingSphere sphere = models[modelIndex].boundingSphere;
|
||||
bool _flw_isVisible(uint instanceIndex, uint modelIndex) {
|
||||
BoundingSphere sphere = _flw_models[modelIndex].boundingSphere;
|
||||
|
||||
vec3 center;
|
||||
float radius;
|
||||
_flw_unpackBoundingSphere(sphere, center, radius);
|
||||
|
||||
FlwInstance instance = _flw_unpackInstance(objects[objectIndex].instance);
|
||||
FlwInstance instance = _flw_unpackInstance(instanceIndex);
|
||||
|
||||
flw_transformBoundingSphere(instance, center, radius);
|
||||
|
||||
|
@ -53,17 +52,17 @@ bool _flw_isVisible(uint objectIndex, uint modelIndex) {
|
|||
}
|
||||
|
||||
void main() {
|
||||
uint objectIndex = gl_GlobalInvocationID.x;
|
||||
uint instanceIndex = gl_GlobalInvocationID.x;
|
||||
|
||||
if (objectIndex >= objects.length()) {
|
||||
if (instanceIndex >= _flw_modelIndices.length()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint modelIndex = objects[objectIndex].modelIndex;
|
||||
uint modelIndex = _flw_modelIndices[instanceIndex];
|
||||
|
||||
if (_flw_isVisible(objectIndex, modelIndex)) {
|
||||
uint localIndex = atomicAdd(models[modelIndex].instanceCount, 1);
|
||||
uint targetIndex = models[modelIndex].baseInstance + localIndex;
|
||||
objectIndices[targetIndex] = objectIndex;
|
||||
if (_flw_isVisible(instanceIndex, modelIndex)) {
|
||||
uint localIndex = atomicAdd(_flw_models[modelIndex].instanceCount, 1);
|
||||
uint targetIndex = _flw_models[modelIndex].baseInstance + localIndex;
|
||||
_flw_instanceIndices[targetIndex] = instanceIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
#include "flywheel:internal/common.vert"
|
||||
#include "flywheel:internal/packed_material.glsl"
|
||||
#include "flywheel:internal/indirect/buffers.glsl"
|
||||
#include "flywheel:internal/indirect/buffer_bindings.glsl"
|
||||
#include "flywheel:internal/indirect/draw_command.glsl"
|
||||
#include "flywheel:internal/indirect/object.glsl"
|
||||
|
||||
layout(std430, binding = _FLW_OBJECT_BUFFER_BINDING) restrict readonly buffer ObjectBuffer {
|
||||
Object objects[];
|
||||
};
|
||||
|
||||
layout(std430, binding = _FLW_TARGET_BUFFER_BINDING) restrict readonly buffer TargetBuffer {
|
||||
uint objectIndices[];
|
||||
uint _flw_instanceIndices[];
|
||||
};
|
||||
|
||||
layout(std430, binding = _FLW_DRAW_BUFFER_BINDING) restrict readonly buffer DrawBuffer {
|
||||
MeshDrawCommand drawCommands[];
|
||||
MeshDrawCommand _flw_drawCommands[];
|
||||
};
|
||||
|
||||
uniform uint _flw_baseDraw;
|
||||
|
@ -22,15 +17,15 @@ flat out uvec3 _flw_packedMaterial;
|
|||
|
||||
void main() {
|
||||
uint drawIndex = gl_DrawID + _flw_baseDraw;
|
||||
MeshDrawCommand draw = drawCommands[drawIndex];
|
||||
MeshDrawCommand draw = _flw_drawCommands[drawIndex];
|
||||
|
||||
_flw_uberMaterialVertexIndex = draw.materialVertexIndex;
|
||||
uint packedMaterialProperties = draw.packedMaterialProperties;
|
||||
_flw_unpackMaterialProperties(packedMaterialProperties, flw_material);
|
||||
_flw_packedMaterial = uvec3(draw.materialFragmentIndex, draw.packedFogAndCutout, packedMaterialProperties);
|
||||
|
||||
uint objectIndex = objectIndices[gl_BaseInstance + gl_InstanceID];
|
||||
FlwInstance instance = _flw_unpackInstance(objects[objectIndex].instance);
|
||||
uint instanceIndex = _flw_instanceIndices[gl_BaseInstance + gl_InstanceID];
|
||||
FlwInstance instance = _flw_unpackInstance(instanceIndex);
|
||||
|
||||
_flw_main(instance, objectIndex);
|
||||
_flw_main(instance, instanceIndex);
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
struct Object {
|
||||
uint modelIndex;
|
||||
FlwPackedInstance instance;
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
#include "flywheel:internal/common_api_impl.vert"
|
||||
|
||||
uint _flw_uberMaterialVertexIndex;
|
|
@ -1,17 +1,17 @@
|
|||
in vec3 _flw_a_pos;
|
||||
in vec4 _flw_a_color;
|
||||
in vec2 _flw_a_texCoord;
|
||||
in vec2 _flw_a_overlay;
|
||||
in vec2 _flw_a_light;
|
||||
in vec3 _flw_a_normal;
|
||||
in vec3 _flw_aPos;
|
||||
in vec4 _flw_aColor;
|
||||
in vec2 _flw_aTexCoord;
|
||||
in vec2 _flw_aOverlay;
|
||||
in vec2 _flw_aLight;
|
||||
in vec3 _flw_aNormal;
|
||||
|
||||
void _flw_layoutVertex() {
|
||||
flw_vertexPos = vec4(_flw_a_pos, 1.0);
|
||||
flw_vertexColor = _flw_a_color;
|
||||
flw_vertexTexCoord = _flw_a_texCoord;
|
||||
flw_vertexPos = vec4(_flw_aPos, 1.0);
|
||||
flw_vertexColor = _flw_aColor;
|
||||
flw_vertexTexCoord = _flw_aTexCoord;
|
||||
// Integer vertex attributes explode on some drivers for some draw calls, so get the driver
|
||||
// to cast the int to a float so we can cast it back to an int and reliably get a sane value.
|
||||
flw_vertexOverlay = ivec2(_flw_a_overlay);
|
||||
flw_vertexLight = _flw_a_light / 256.0;
|
||||
flw_vertexNormal = _flw_a_normal;
|
||||
flw_vertexOverlay = ivec2(_flw_aOverlay);
|
||||
flw_vertexLight = _flw_aLight / 256.0;
|
||||
flw_vertexNormal = _flw_aNormal;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue