mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Consolidated compilation
- Note: heavily broken - Move all compilation logic into a single package - FlwCompiler is responsible for compilation - CompilationEnvironment generates combinations and performs analysis - Create source components for vertex/fragment ubershader codegen - More hacky glsl generation utils - Strip explicit uniform buffers from uniform shaders
This commit is contained in:
parent
79464361d2
commit
28e16a7810
52 changed files with 1113 additions and 779 deletions
|
@ -7,14 +7,13 @@ import com.jozufozu.flywheel.backend.Backend;
|
|||
import com.jozufozu.flywheel.backend.RenderWork;
|
||||
import com.jozufozu.flywheel.backend.ShadersModHandler;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||
import com.jozufozu.flywheel.backend.instancing.batching.DrawBuffer;
|
||||
import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.config.BackendTypeArgument;
|
||||
import com.jozufozu.flywheel.config.FlwCommands;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
import com.jozufozu.flywheel.core.BackendTypes;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.DebugRender;
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
import com.jozufozu.flywheel.core.StitchedSprite;
|
||||
|
@ -81,7 +80,7 @@ public class Flywheel {
|
|||
forgeEventBus.addListener(FlwCommands::registerClientCommands);
|
||||
|
||||
forgeEventBus.addListener(EventPriority.HIGHEST, QuadConverter::onReloadRenderers);
|
||||
forgeEventBus.addListener(PipelineCompiler::onReloadRenderers);
|
||||
forgeEventBus.addListener(FlwCompiler::onReloadRenderers);
|
||||
forgeEventBus.addListener(Models::onReloadRenderers);
|
||||
forgeEventBus.addListener(DrawBuffer::onReloadRenderers);
|
||||
|
||||
|
@ -108,7 +107,6 @@ public class Flywheel {
|
|||
// forgeEventBus.addListener(ExampleEffect::onReload);
|
||||
|
||||
Components.init();
|
||||
DebugRender.init();
|
||||
|
||||
VanillaInstances.init();
|
||||
|
||||
|
|
|
@ -2,21 +2,21 @@ package com.jozufozu.flywheel.api.uniform;
|
|||
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public abstract class UniformProvider {
|
||||
public interface UniformProvider {
|
||||
|
||||
protected long ptr;
|
||||
protected Notifier notifier;
|
||||
int byteSize();
|
||||
|
||||
public abstract int getActualByteSize();
|
||||
FileResolution uniformShader();
|
||||
|
||||
public void updatePtr(long ptr, Notifier notifier) {
|
||||
this.ptr = ptr;
|
||||
this.notifier = notifier;
|
||||
ActiveUniformProvider activate(long ptr, Notifier notifier);
|
||||
|
||||
interface ActiveUniformProvider {
|
||||
void delete();
|
||||
|
||||
void poll();
|
||||
}
|
||||
|
||||
public abstract FileResolution getUniformShader();
|
||||
|
||||
public interface Notifier {
|
||||
interface Notifier {
|
||||
void signalChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
@ -17,4 +20,6 @@ public interface BackendType {
|
|||
BackendType findFallback();
|
||||
|
||||
boolean supported();
|
||||
|
||||
@Nullable PipelineShader pipelineShader();
|
||||
}
|
||||
|
|
|
@ -1,23 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||
import com.jozufozu.flywheel.backend.instancing.indirect.ComputeCullerCompiler;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.compile.ShaderCompilationException;
|
||||
import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler;
|
||||
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;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
|
@ -68,46 +55,7 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
|
||||
Backend.LOGGER.info("All shaders passed checks.");
|
||||
|
||||
long compileStart = System.nanoTime();
|
||||
int programCounter = 0;
|
||||
boolean crash = false;
|
||||
|
||||
for (Material material : ComponentRegistry.materials) {
|
||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||
for (ContextShader contextShader : ComponentRegistry.contextShaders) {
|
||||
for (PipelineShader pipelineShader : List.of(Components.INSTANCED_ARRAYS, Components.INDIRECT)) {
|
||||
var ctx = new PipelineCompiler.Context(vertexType, material, structType, contextShader, pipelineShader);
|
||||
try {
|
||||
PipelineCompiler.INSTANCE.getProgram(ctx);
|
||||
} catch (ShaderCompilationException e) {
|
||||
Backend.LOGGER.error(e.errors);
|
||||
crash = true;
|
||||
}
|
||||
programCounter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
try {
|
||||
ComputeCullerCompiler.INSTANCE.get(structType);
|
||||
} catch (ShaderCompilationException e) {
|
||||
Backend.LOGGER.error(e.errors);
|
||||
crash = true;
|
||||
}
|
||||
programCounter++;
|
||||
}
|
||||
|
||||
long compileEnd = System.nanoTime();
|
||||
|
||||
Backend.LOGGER.info("Compiled " + programCounter + " programs in " + StringUtil.formatTime(compileEnd - compileStart));
|
||||
|
||||
if (crash) {
|
||||
throw new ShaderLoadingException("Compilation failed");
|
||||
}
|
||||
FlwCompiler.INSTANCE.run();
|
||||
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
if (Backend.canUseInstancing(level)) {
|
||||
|
|
|
@ -3,6 +3,9 @@ package com.jozufozu.flywheel.backend;
|
|||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.core.BackendTypes;
|
||||
|
||||
|
@ -17,14 +20,16 @@ public class SimpleBackendType implements BackendType {
|
|||
private final Supplier<Engine> engineSupplier;
|
||||
private final Supplier<BackendType> fallback;
|
||||
private final BooleanSupplier isSupported;
|
||||
private final PipelineShader pipelineShader;
|
||||
|
||||
public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier<Engine> engineSupplier, Supplier<BackendType> fallback, BooleanSupplier isSupported) {
|
||||
public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier<Engine> engineSupplier, Supplier<BackendType> fallback, BooleanSupplier isSupported, @Nullable PipelineShader pipelineShader) {
|
||||
this.properName = properName;
|
||||
this.shortName = shortName;
|
||||
this.engineMessage = engineMessage;
|
||||
this.engineSupplier = engineSupplier;
|
||||
this.fallback = fallback;
|
||||
this.isSupported = isSupported;
|
||||
this.pipelineShader = pipelineShader;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
@ -66,6 +71,11 @@ public class SimpleBackendType implements BackendType {
|
|||
return isSupported.getAsBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PipelineShader pipelineShader() {
|
||||
return pipelineShader;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private String properName;
|
||||
private String shortName;
|
||||
|
@ -73,6 +83,7 @@ public class SimpleBackendType implements BackendType {
|
|||
private Supplier<Engine> engineSupplier;
|
||||
private Supplier<BackendType> fallback;
|
||||
private BooleanSupplier isSupported;
|
||||
private PipelineShader pipelineShader;
|
||||
|
||||
public Builder properName(String properName) {
|
||||
this.properName = properName;
|
||||
|
@ -104,8 +115,13 @@ public class SimpleBackendType implements BackendType {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder pipelineShader(PipelineShader pipelineShader) {
|
||||
this.pipelineShader = pipelineShader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BackendType register() {
|
||||
return BackendTypes.register(new SimpleBackendType(properName, shortName, engineMessage, engineSupplier, fallback, isSupported));
|
||||
return BackendTypes.register(new SimpleBackendType(properName, shortName, engineMessage, engineSupplier, fallback, isSupported, pipelineShader));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.gl.shader;
|
|||
import static org.lwjgl.opengl.GL20.glDeleteProgram;
|
||||
import static org.lwjgl.opengl.GL20.glGetUniformLocation;
|
||||
import static org.lwjgl.opengl.GL20.glUniform1i;
|
||||
import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -11,17 +10,13 @@ import com.jozufozu.flywheel.backend.Backend;
|
|||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.mojang.blaze3d.shaders.ProgramManager;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class GlProgram extends GlObject {
|
||||
|
||||
public final ResourceLocation name;
|
||||
|
||||
public GlProgram(ResourceLocation name, int handle) {
|
||||
this.name = name;
|
||||
public GlProgram(int handle) {
|
||||
setHandle(handle);
|
||||
}
|
||||
|
||||
// TODO: Programs bind the uniform buffers they need
|
||||
public void bind() {
|
||||
ProgramManager.glUseProgram(handle());
|
||||
}
|
||||
|
@ -40,7 +35,7 @@ public class GlProgram extends GlObject {
|
|||
int index = glGetUniformLocation(this.handle(), uniform);
|
||||
|
||||
if (index < 0) {
|
||||
Backend.LOGGER.debug("No active uniform '{}' exists in program '{}'. Could be unused.", uniform, this.name);
|
||||
Backend.LOGGER.debug("No active uniform '{}' exists. Could be unused.", uniform);
|
||||
}
|
||||
|
||||
return index;
|
||||
|
@ -69,17 +64,11 @@ public class GlProgram extends GlObject {
|
|||
glDeleteProgram(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "program " + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* A factory interface to create a {@link GlProgram}.
|
||||
*/
|
||||
public interface Factory {
|
||||
|
||||
@NotNull
|
||||
GlProgram create(ResourceLocation name, int handle);
|
||||
@NotNull GlProgram create(int handle);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.lwjgl.opengl.GL20;
|
|||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.core.compile.ShaderCompilationException;
|
||||
import com.jozufozu.flywheel.backend.instancing.compile.ShaderCompilationException;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
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.struct.StructType;
|
||||
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.SourceComponent;
|
||||
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.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.structType.getInstanceShader()
|
||||
.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 onReloadRenderers(ReloadRenderersEvent event) {
|
||||
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. TODO: Flatten materials
|
||||
* @param structType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
*/
|
||||
public record Context(VertexType vertexType, Material material, StructType<?> structType,
|
||||
ContextShader contextShader, PipelineShader pipelineShader) {
|
||||
|
||||
ImmutableList<SourceComponent> getVertexComponents() {
|
||||
var layout = vertexType.getLayoutShader()
|
||||
.getFile();
|
||||
var instanceAssembly = pipelineShader.assemble(vertexType, structType);
|
||||
var instance = structType.getInstanceShader()
|
||||
.getFile();
|
||||
var material = this.material.getVertexShader()
|
||||
.getFile();
|
||||
var context = contextShader.getVertexShader();
|
||||
var pipeline = pipelineShader.vertex()
|
||||
.getFile();
|
||||
return ImmutableList.of(layout, instanceAssembly, instance, material, context, pipeline);
|
||||
}
|
||||
|
||||
ImmutableList<SourceComponent> getFragmentComponents() {
|
||||
var material = this.material.getFragmentShader()
|
||||
.getFile();
|
||||
var context = contextShader.getFragmentShader();
|
||||
var pipeline = pipelineShader.fragment()
|
||||
.getFile();
|
||||
return ImmutableList.of(material, context, pipeline);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles compilation and deletion of vertex shaders.
|
||||
*/
|
||||
public static class ShaderCompiler extends Memoizer<ShaderCompiler.Context, GlShader> {
|
||||
|
||||
private ShaderCompiler() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlShader _create(Context key) {
|
||||
StringBuilder finalSource = new StringBuilder(key.generateHeader());
|
||||
finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n");
|
||||
finalSource.append("#extension GL_ARB_conservative_depth : enable\n");
|
||||
|
||||
var ctx = new CompilationContext();
|
||||
|
||||
var names = ImmutableList.<ResourceLocation>builder();
|
||||
var included = new LinkedHashSet<SourceComponent>(); // linked to preserve order
|
||||
for (var component : key.sourceComponents) {
|
||||
included.addAll(component.included());
|
||||
names.add(component.name());
|
||||
}
|
||||
|
||||
for (var include : included) {
|
||||
finalSource.append(include.source(ctx));
|
||||
}
|
||||
|
||||
for (var component : key.sourceComponents) {
|
||||
finalSource.append(component.source(ctx));
|
||||
}
|
||||
|
||||
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 sourceComponents A list of shader components to stitch together, in order.
|
||||
*/
|
||||
public record Context(GLSLVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
|
||||
|
||||
public String generateHeader() {
|
||||
return CompileUtil.generateHeader(glslVersion, shaderType);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.uniform.UniformProvider;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.core.BackendTypes;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
class CompilationEnvironment {
|
||||
final VertexMaterialComponent vertexMaterialComponent;
|
||||
final FragmentMaterialComponent fragmentMaterialComponent;
|
||||
|
||||
boolean needsCrash = false;
|
||||
|
||||
final long compileStart = System.nanoTime();
|
||||
final Multimap<Set<UniformProvider>, PipelineContext> uniformProviderGroups = ArrayListMultimap.create();
|
||||
final List<PipelineContext> pipelineContexts = new ArrayList<>();
|
||||
|
||||
CompilationEnvironment() {
|
||||
for (PipelineShader pipelineShader : BackendTypes.availablePipelineShaders()) {
|
||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||
for (ContextShader contextShader : ComponentRegistry.contextShaders) {
|
||||
acknowledgeContext(new PipelineContext(vertexType, structType, contextShader, pipelineShader));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.vertexMaterialComponent = new VertexMaterialComponent(ComponentRegistry.materials.vertexSources());
|
||||
this.fragmentMaterialComponent = new FragmentMaterialComponent(ComponentRegistry.materials.fragmentSources());
|
||||
}
|
||||
|
||||
private void acknowledgeContext(PipelineContext ctx) {
|
||||
uniformProviderGroups.put(ctx.uniformProviders(), ctx);
|
||||
|
||||
pipelineContexts.add(ctx);
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
long compileEnd = System.nanoTime();
|
||||
|
||||
Backend.LOGGER.info("Compiled " + pipelineContexts.size() + " programs in " + StringUtil.formatTime(compileEnd - compileStart));
|
||||
|
||||
if (needsCrash) {
|
||||
throw new ShaderLoadingException("Compilation failed");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
|
@ -0,0 +1,129 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
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.backend.instancing.indirect.IndirectComponent;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FlwCompiler {
|
||||
|
||||
public static final FlwCompiler INSTANCE = new FlwCompiler();
|
||||
|
||||
public static void onReloadRenderers(ReloadRenderersEvent t) {
|
||||
|
||||
}
|
||||
|
||||
private final ShaderCompiler shaderCompiler = new ShaderCompiler();
|
||||
public final Map<PipelineContext, GlProgram> pipelinePrograms = new HashMap<>();
|
||||
|
||||
public final Map<StructType<?>, GlProgram> cullingPrograms = new HashMap<>();
|
||||
|
||||
private CompilationEnvironment environment;
|
||||
|
||||
FlwCompiler() {
|
||||
|
||||
}
|
||||
|
||||
public void run() {
|
||||
environment = new CompilationEnvironment();
|
||||
|
||||
for (PipelineContext context : environment.pipelineContexts) {
|
||||
try {
|
||||
var glProgram = compilePipelineContext(context);
|
||||
pipelinePrograms.put(context, glProgram);
|
||||
} catch (ShaderCompilationException e) {
|
||||
environment.needsCrash = true;
|
||||
Backend.LOGGER.error(e.errors);
|
||||
}
|
||||
}
|
||||
|
||||
for (StructType<?> type : ComponentRegistry.structTypes) {
|
||||
try {
|
||||
var glProgram = compileComputeCuller(type);
|
||||
cullingPrograms.put(type, glProgram);
|
||||
} catch (ShaderCompilationException e) {
|
||||
environment.needsCrash = true;
|
||||
Backend.LOGGER.error(e.errors);
|
||||
}
|
||||
}
|
||||
|
||||
environment.finish();
|
||||
}
|
||||
|
||||
public GlProgram getPipelineProgram(VertexType vertexType, StructType<?> structType, ContextShader contextShader, PipelineShader pipelineShader) {
|
||||
return pipelinePrograms.get(new PipelineContext(vertexType, structType, contextShader, pipelineShader));
|
||||
}
|
||||
|
||||
public GlProgram getCullingProgram(StructType<?> structType) {
|
||||
return cullingPrograms.get(structType);
|
||||
}
|
||||
|
||||
protected GlProgram compilePipelineContext(PipelineContext ctx) throws ShaderCompilationException {
|
||||
|
||||
var glslVersion = ctx.pipelineShader()
|
||||
.glslVersion();
|
||||
|
||||
var vertex = new ShaderContext(glslVersion, ShaderType.VERTEX, ctx.getVertexComponents());
|
||||
var fragment = new ShaderContext(glslVersion, ShaderType.FRAGMENT, ctx.getFragmentComponents());
|
||||
|
||||
return ctx.contextShader()
|
||||
.factory()
|
||||
.create(new ProgramAssembler().attachShader(shaderCompiler.get(vertex))
|
||||
.attachShader(shaderCompiler.get(fragment))
|
||||
.link());
|
||||
}
|
||||
|
||||
protected GlProgram compileComputeCuller(StructType<?> structType) {
|
||||
var location = structType.getInstanceShader();
|
||||
|
||||
var finalSource = new StringBuilder();
|
||||
CompilationContext context = new CompilationContext();
|
||||
var components = List.of(new IndirectComponent(structType.getLayout().layoutItems), location.getFile(), Components.Pipeline.INDIRECT_CULL.getFile());
|
||||
|
||||
var names = ImmutableList.<ResourceLocation>builder();
|
||||
var included = new LinkedHashSet<SourceComponent>(); // linked to preserve order
|
||||
for (var component : components) {
|
||||
included.addAll(component.included());
|
||||
names.add(component.name());
|
||||
}
|
||||
|
||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE));
|
||||
for (var include : included) {
|
||||
finalSource.append(include.source(context));
|
||||
}
|
||||
|
||||
for (var component : components) {
|
||||
finalSource.append(component.source(context));
|
||||
}
|
||||
|
||||
try {
|
||||
var fileLoc = location.getFileLoc();
|
||||
var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(fileLoc));
|
||||
|
||||
var program = new ProgramAssembler().attachShader(shader)
|
||||
.link();
|
||||
return new GlProgram(program);
|
||||
} catch (ShaderCompilationException e) {
|
||||
throw e.withErrorLog(context);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FragmentMaterialComponent implements SourceComponent {
|
||||
|
||||
private static final String flw_materialFragment = "flw_materialFragment";
|
||||
private static final String flw_discardPredicate = "flw_discardPredicate";
|
||||
private static final String flw_fogFilter = "flw_fogFilter";
|
||||
|
||||
private static final GlslExpr flw_materialFragmentID = GlslExpr.variable(flw_materialFragment + "ID");
|
||||
|
||||
private final List<TransformedSourceComponent> transformedMaterials;
|
||||
|
||||
public FragmentMaterialComponent(List<FileResolution> sourceMaterials) {
|
||||
|
||||
this.transformedMaterials = sourceMaterials.stream()
|
||||
.map(FileResolution::getFile)
|
||||
.map(s -> {
|
||||
var newName = flw_materialFragment + '_' + ResourceUtil.toSafeString(s.name());
|
||||
return new TransformedSourceComponent(s, flw_materialFragment, newName);
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return transformedMaterials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source(CompilationContext ctx) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.uniform.UniformProvider;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param vertexType The vertexType the program should be adapted for.
|
||||
* @param structType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
*/
|
||||
public record PipelineContext(VertexType vertexType, StructType<?> structType, ContextShader contextShader,
|
||||
PipelineShader pipelineShader) {
|
||||
|
||||
@NotNull
|
||||
public Set<UniformProvider> uniformProviders() {
|
||||
var fragmentComponents = getFragmentComponents();
|
||||
var vertexComponents = getVertexComponents();
|
||||
|
||||
return Stream.concat(fragmentComponents.stream(), vertexComponents.stream())
|
||||
.map(SourceComponent::included)
|
||||
.flatMap(Collection::stream)
|
||||
.map(SourceComponent::name)
|
||||
.<UniformProvider>mapMulti((component, consumer) -> {
|
||||
var uniformProvider = ComponentRegistry.getUniformProvider(component);
|
||||
if (uniformProvider != null) {
|
||||
consumer.accept(uniformProvider);
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
ImmutableList<SourceComponent> getVertexComponents() {
|
||||
var layout = vertexType.getLayoutShader()
|
||||
.getFile();
|
||||
var instanceAssembly = pipelineShader.assemble(vertexType, structType);
|
||||
var instance = structType.getInstanceShader()
|
||||
.getFile();
|
||||
var context = contextShader.getVertexShader();
|
||||
var pipeline = pipelineShader.vertex()
|
||||
.getFile();
|
||||
return ImmutableList.of(layout, instanceAssembly, instance, context, pipeline);
|
||||
}
|
||||
|
||||
ImmutableList<SourceComponent> getFragmentComponents() {
|
||||
var context = contextShader.getFragmentShader();
|
||||
var pipeline = pipelineShader.fragment()
|
||||
.getFile();
|
||||
return ImmutableList.of(context, pipeline);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_TRUE;
|
||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
||||
|
@ -9,30 +9,26 @@ import static org.lwjgl.opengl.GL20.glGetProgrami;
|
|||
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
@Deprecated
|
||||
public class ProgramAssembler {
|
||||
public final int program;
|
||||
private final ResourceLocation name;
|
||||
private final int program;
|
||||
|
||||
public ProgramAssembler(ResourceLocation name) {
|
||||
this.name = name;
|
||||
public ProgramAssembler() {
|
||||
this.program = glCreateProgram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Links the attached shaders to this program.
|
||||
*/
|
||||
public ProgramAssembler link() {
|
||||
public int link() {
|
||||
glLinkProgram(this.program);
|
||||
|
||||
String log = glGetProgramInfoLog(this.program);
|
||||
|
||||
if (!log.isEmpty()) {
|
||||
Backend.LOGGER.debug("Program link log for " + name + ": " + log);
|
||||
Backend.LOGGER.debug("Program link log: " + log);
|
||||
}
|
||||
|
||||
int result = glGetProgrami(this.program, GL_LINK_STATUS);
|
||||
|
@ -41,15 +37,11 @@ public class ProgramAssembler {
|
|||
throw new RuntimeException("Shader program linking failed, see log for details");
|
||||
}
|
||||
|
||||
return this;
|
||||
return program;
|
||||
}
|
||||
|
||||
public ProgramAssembler attachShader(GlShader glShader) {
|
||||
glAttachShader(this.program, glShader.handle());
|
||||
return this;
|
||||
}
|
||||
|
||||
public GlProgram build(GlProgram.Factory factory) {
|
||||
return factory.create(name, program);
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Handles compilation and deletion of vertex shaders.
|
||||
*/
|
||||
public class ShaderCompiler {
|
||||
|
||||
private final Map<ShaderContext, GlShader> map = new HashMap<>();
|
||||
|
||||
ShaderCompiler() {
|
||||
}
|
||||
|
||||
public GlShader get(ShaderContext key) {
|
||||
return map.computeIfAbsent(key, this::_create);
|
||||
}
|
||||
|
||||
protected GlShader _create(ShaderContext key) {
|
||||
StringBuilder finalSource = new StringBuilder(key.generateHeader());
|
||||
finalSource.append("#extension GL_ARB_explicit_attrib_location : enable\n");
|
||||
finalSource.append("#extension GL_ARB_conservative_depth : enable\n");
|
||||
|
||||
var ctx = new CompilationContext();
|
||||
|
||||
var names = ImmutableList.<ResourceLocation>builder();
|
||||
var included = new LinkedHashSet<SourceComponent>(); // linked to preserve order
|
||||
for (var component : key.sourceComponents()) {
|
||||
included.addAll(component.included());
|
||||
names.add(component.name());
|
||||
}
|
||||
|
||||
for (var include : included) {
|
||||
finalSource.append(include.source(ctx));
|
||||
}
|
||||
|
||||
for (var component : key.sourceComponents()) {
|
||||
finalSource.append(component.source(ctx));
|
||||
}
|
||||
|
||||
try {
|
||||
return new GlShader(finalSource.toString(), key.shaderType(), names.build());
|
||||
} catch (ShaderCompilationException e) {
|
||||
throw e.withErrorLog(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
map.values()
|
||||
.forEach(GlObject::delete);
|
||||
map.clear();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
|
||||
/**
|
||||
* @param glslVersion The GLSL version to use.
|
||||
* @param sourceComponents A list of shader components to stitch together, in order.
|
||||
*/
|
||||
public record ShaderContext(GLSLVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
|
||||
|
||||
public String generateHeader() {
|
||||
return CompileUtil.generateHeader(glslVersion, shaderType);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class TransformedSourceComponent implements SourceComponent {
|
||||
final SourceComponent source;
|
||||
final String find;
|
||||
final String replacement;
|
||||
|
||||
public TransformedSourceComponent(SourceComponent source, String find, String replacement) {
|
||||
this.source = source;
|
||||
this.find = find;
|
||||
this.replacement = replacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source(CompilationContext ctx) {
|
||||
return source.source(ctx)
|
||||
.replace(find, replacement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return ResourceUtil.subPath(source.name(), "_renamed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return source.included();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class VertexMaterialComponent implements SourceComponent {
|
||||
|
||||
private static final String flw_materialVertex = "flw_materialVertex";
|
||||
private static final GlslExpr flw_materialVertexID = GlslExpr.variable(flw_materialVertex + "ID");
|
||||
|
||||
private final List<TransformedSourceComponent> transformedMaterials;
|
||||
|
||||
public VertexMaterialComponent(List<FileResolution> sourceMaterials) {
|
||||
|
||||
this.transformedMaterials = sourceMaterials.stream()
|
||||
.map(FileResolution::getFile)
|
||||
.map(s -> {
|
||||
var newName = flw_materialVertex + '_' + ResourceUtil.toSafeString(s.name());
|
||||
return new TransformedSourceComponent(s, flw_materialVertex, newName);
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return transformedMaterials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source(CompilationContext ctx) {
|
||||
String out = genSource();
|
||||
return ctx.generatedHeader(out, "material adapter") + out;
|
||||
}
|
||||
|
||||
public String genSource() {
|
||||
var builder = new GlslBuilder();
|
||||
|
||||
builder.function()
|
||||
.returnType("void")
|
||||
.name("flw_materialVertex")
|
||||
.body(this::accept);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return Flywheel.rl("vertex_material_adapter");
|
||||
}
|
||||
|
||||
private void accept(GlslBuilder.BlockBuilder body) {
|
||||
var sw = new GlslBuilder.SwitchBuilder(flw_materialVertexID);
|
||||
for (int i = 0; i < transformedMaterials.size(); i++) {
|
||||
var variant = transformedMaterials.get(i).replacement;
|
||||
|
||||
sw.case_(i, b -> b.eval(GlslExpr.call(variant))
|
||||
.break_());
|
||||
}
|
||||
body.add(sw.build());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -1,74 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.indirect;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
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.SourceComponent;
|
||||
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.event.ReloadRenderersEvent;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class ComputeCullerCompiler extends Memoizer<StructType<?>, GlProgram> {
|
||||
|
||||
public static final ComputeCullerCompiler INSTANCE = new ComputeCullerCompiler();
|
||||
|
||||
private ComputeCullerCompiler() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlProgram _create(StructType<?> structType) {
|
||||
var location = structType.getInstanceShader();
|
||||
|
||||
var finalSource = new StringBuilder();
|
||||
CompilationContext context = new CompilationContext();
|
||||
var components = List.of(new IndirectComponent(structType.getLayout().layoutItems), location.getFile(), Components.Pipeline.INDIRECT_CULL.getFile());
|
||||
|
||||
var names = ImmutableList.<ResourceLocation>builder();
|
||||
var included = new LinkedHashSet<SourceComponent>(); // linked to preserve order
|
||||
for (var component : components) {
|
||||
included.addAll(component.included());
|
||||
names.add(component.name());
|
||||
}
|
||||
|
||||
finalSource.append(CompileUtil.generateHeader(GLSLVersion.V460, ShaderType.COMPUTE));
|
||||
for (var include : included) {
|
||||
finalSource.append(include.source(context));
|
||||
}
|
||||
|
||||
for (var component : components) {
|
||||
finalSource.append(component.source(context));
|
||||
}
|
||||
|
||||
try {
|
||||
var fileLoc = location.getFileLoc();
|
||||
var shader = new GlShader(finalSource.toString(), ShaderType.COMPUTE, ImmutableList.of(fileLoc));
|
||||
|
||||
return new ProgramAssembler(fileLoc).attachShader(shader)
|
||||
.link()
|
||||
.build(GlProgram::new);
|
||||
} catch (ShaderCompilationException e) {
|
||||
throw e.withErrorLog(context);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _destroy(GlProgram value) {
|
||||
value.delete();
|
||||
}
|
||||
|
||||
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
||||
INSTANCE.invalidate();
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend.instancing.indirect;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
|
@ -60,17 +59,13 @@ public class IndirectComponent implements SourceComponent {
|
|||
|
||||
builder.blankLine();
|
||||
|
||||
var func = builder.function()
|
||||
builder.function()
|
||||
.returnType(structName)
|
||||
.name("flw_unpackInstance")
|
||||
.argumentIn(packedStructName, UNPACK_ARG);
|
||||
|
||||
var args = layoutItems.stream()
|
||||
.map(layoutItem -> layoutItem.unpackField(UNPACKING_VARIABLE))
|
||||
.map(GlslExpr::minPrint)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
func.statement("return " + structName + "(" + args + ");");
|
||||
.argumentIn(packedStructName, UNPACK_ARG)
|
||||
.body(b -> b.ret(GlslExpr.call(structName, layoutItems.stream()
|
||||
.map(layoutItem -> layoutItem.unpackField(UNPACKING_VARIABLE))
|
||||
.toList())));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -17,11 +17,9 @@ import com.jozufozu.flywheel.api.struct.StructType;
|
|||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.instancing.PipelineCompiler;
|
||||
import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
||||
|
||||
public class IndirectCullingGroup<T extends InstancedPart> {
|
||||
|
||||
|
@ -65,8 +63,8 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
.quads2Tris(2048).buffer.handle();
|
||||
setupVertexArray();
|
||||
|
||||
compute = ComputeCullerCompiler.INSTANCE.get(structType);
|
||||
draw = PipelineCompiler.INSTANCE.get(new PipelineCompiler.Context(vertexType, Materials.SHULKER, structType, Components.WORLD, Components.INDIRECT));
|
||||
compute = FlwCompiler.INSTANCE.getCullingProgram(structType);
|
||||
draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, Components.WORLD, Components.INDIRECT);
|
||||
}
|
||||
|
||||
private void setupVertexArray() {
|
||||
|
@ -116,9 +114,6 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
uploadInstanceData();
|
||||
uploadIndirectCommands();
|
||||
|
||||
UniformBuffer.getInstance()
|
||||
.sync();
|
||||
|
||||
compute.bind();
|
||||
buffers.bindAll();
|
||||
|
||||
|
@ -137,9 +132,6 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
buffers.bindObjectAndTarget();
|
||||
buffers.bindIndirectBuffer();
|
||||
|
||||
UniformBuffer.getInstance()
|
||||
.sync();
|
||||
|
||||
memoryBarrier();
|
||||
|
||||
drawSet.submit(stage);
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
|
@ -68,16 +67,13 @@ public class InstancedArraysComponent implements SourceComponent {
|
|||
|
||||
builder.blankLine();
|
||||
|
||||
var func = builder.function()
|
||||
// unpacking function
|
||||
builder.function()
|
||||
.returnType(structName)
|
||||
.name("flw_unpackInstance");
|
||||
|
||||
var args = layoutItems.stream()
|
||||
.map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX))
|
||||
.map(GlslExpr::minPrint)
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
func.statement("return " + structName + "(" + args + ");");
|
||||
.name("flw_unpackInstance")
|
||||
.body(b -> b.ret(GlslExpr.call(structName, layoutItems.stream()
|
||||
.map(it -> new GlslExpr.Variable(it.name() + ATTRIBUTE_SUFFIX))
|
||||
.toList())));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
|
|
@ -16,11 +16,10 @@ import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
|||
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.backend.instancing.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.uniform.UniformBuffer;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
|
@ -124,12 +123,8 @@ public class InstancingEngine implements Engine {
|
|||
var structType = desc.instance();
|
||||
var material = desc.material();
|
||||
|
||||
var ctx = new PipelineCompiler.Context(vertexType, material, structType, context, Components.INSTANCED_ARRAYS);
|
||||
|
||||
PipelineCompiler.INSTANCE.getProgram(ctx)
|
||||
FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Components.INSTANCED_ARRAYS)
|
||||
.bind();
|
||||
UniformBuffer.getInstance()
|
||||
.sync();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -4,9 +4,12 @@ import java.util.Collection;
|
|||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||
import com.jozufozu.flywheel.backend.BackendType;
|
||||
import com.jozufozu.flywheel.backend.ShadersModHandler;
|
||||
import com.jozufozu.flywheel.backend.SimpleBackendType;
|
||||
|
@ -55,6 +58,7 @@ public class BackendTypes {
|
|||
.fallback(() -> BackendTypes.BATCHING)
|
||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
|
||||
.instancedArraysSupported())
|
||||
.pipelineShader(Components.INSTANCED_ARRAYS)
|
||||
.register();
|
||||
|
||||
/**
|
||||
|
@ -68,6 +72,7 @@ public class BackendTypes {
|
|||
.fallback(() -> BackendTypes.INSTANCING)
|
||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
|
||||
.supportsIndirect())
|
||||
.pipelineShader(Components.INDIRECT)
|
||||
.register();
|
||||
|
||||
public static BackendType register(BackendType type) {
|
||||
|
@ -94,4 +99,12 @@ public class BackendTypes {
|
|||
}
|
||||
|
||||
|
||||
public static Collection<PipelineShader> availablePipelineShaders() {
|
||||
return BACKEND_TYPES.values()
|
||||
.stream()
|
||||
.filter(BackendType::supported)
|
||||
.map(BackendType::pipelineShader)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,22 +3,29 @@ package com.jozufozu.flywheel.core;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.uniform.UniformProvider;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class ComponentRegistry {
|
||||
private static final Registry<UniformProvider> uniformProviders = new Registry<>();
|
||||
|
||||
public static final Set<Material> materials = new HashSet<>();
|
||||
public static final MaterialRegistry materials = new MaterialRegistry();
|
||||
public static final Set<StructType<?>> structTypes = new HashSet<>();
|
||||
public static final Set<VertexType> vertexTypes = new HashSet<>();
|
||||
public static final Set<ContextShader> contextShaders = new HashSet<>();
|
||||
|
@ -26,8 +33,7 @@ public class ComponentRegistry {
|
|||
// TODO: fill out the rest of the registry
|
||||
|
||||
public static <T extends Material> T register(T material) {
|
||||
materials.add(material);
|
||||
return material;
|
||||
return materials.add(material);
|
||||
}
|
||||
|
||||
public static <T extends StructType<?>> T register(T type) {
|
||||
|
@ -46,7 +52,7 @@ public class ComponentRegistry {
|
|||
}
|
||||
|
||||
public static <T extends UniformProvider> T register(T provider) {
|
||||
return uniformProviders.register(provider.getUniformShader()
|
||||
return uniformProviders.register(provider.uniformShader()
|
||||
.getFileLoc(), provider);
|
||||
}
|
||||
|
||||
|
@ -54,17 +60,71 @@ public class ComponentRegistry {
|
|||
return Collections.unmodifiableCollection(uniformProviders.objects);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static UniformProvider getUniformProvider(ResourceLocation loc) {
|
||||
return uniformProviders.get(loc);
|
||||
}
|
||||
|
||||
private static class Registry<T> {
|
||||
private final Set<ResourceLocation> files = new HashSet<>();
|
||||
private final Map<ResourceLocation, T> files = new HashMap<>();
|
||||
private final List<T> objects = new ArrayList<>();
|
||||
|
||||
public <O extends T> O register(ResourceLocation loc, O object) {
|
||||
if (files.contains(loc)) {
|
||||
if (files.containsKey(loc)) {
|
||||
throw new IllegalArgumentException("Shader file already registered: " + loc);
|
||||
}
|
||||
files.add(loc);
|
||||
files.put(loc, object);
|
||||
objects.add(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T get(ResourceLocation loc) {
|
||||
return files.get(loc);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MaterialRegistry {
|
||||
|
||||
private final Set<Material> materials = new HashSet<>();
|
||||
private final MaterialSources vertexSources = new MaterialSources();
|
||||
private final MaterialSources fragmentSources = new MaterialSources();
|
||||
|
||||
public <T extends Material> T add(T material) {
|
||||
materials.add(material);
|
||||
|
||||
vertexSources.register(material, material.getVertexShader());
|
||||
fragmentSources.register(material, material.getFragmentShader());
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of vertex shader sources where the index in the list is the shader's ID.
|
||||
*/
|
||||
public List<FileResolution> vertexSources() {
|
||||
return vertexSources.sourceView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of fragment shader sources where the index in the list is the shader's ID.
|
||||
*/
|
||||
public List<FileResolution> fragmentSources() {
|
||||
return fragmentSources.sourceView;
|
||||
}
|
||||
|
||||
private static class MaterialSources {
|
||||
private final Set<FileResolution> registered = new HashSet<>();
|
||||
private final List<FileResolution> orderedSources = new ArrayList<>();
|
||||
private final Reference2IntMap<Material> material2ID = new Reference2IntOpenHashMap<>();
|
||||
private final List<FileResolution> sourceView = Collections.unmodifiableList(orderedSources);
|
||||
|
||||
public void register(Material material, FileResolution vertexShader) {
|
||||
if (registered.add(vertexShader)) {
|
||||
material2ID.put(material, orderedSources.size());
|
||||
orderedSources.add(vertexShader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import org.lwjgl.opengl.GL46;
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.compile.DebugCompiler;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
import com.jozufozu.flywheel.util.joml.FrustumIntersection;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
public class DebugRender {
|
||||
|
||||
private static final Lazy<GlProgram> SHADER = Lazy.of(() -> DebugCompiler.INSTANCE.get(new DebugCompiler.Context(Files.VERTEX, Files.FRAGMENT)));
|
||||
|
||||
private static final Lazy<Frustum> FRUSTUM_VBO = Lazy.of(Frustum::new);
|
||||
|
||||
public static void init() {
|
||||
Files.init();
|
||||
}
|
||||
|
||||
public static void updateFrustum(FrustumIntersection culler) {
|
||||
FRUSTUM_VBO.get()
|
||||
.upload(culler);
|
||||
}
|
||||
|
||||
public static void drawFrustum() {
|
||||
if (!FRUSTUM_VBO.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderSystem.disableCull();
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
|
||||
try (var ignored = GlStateTracker.getRestoreState()) {
|
||||
SHADER.get()
|
||||
.bind();
|
||||
FRUSTUM_VBO.get()
|
||||
.draw();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Files {
|
||||
public static final FileResolution VERTEX = FileResolution.get(Flywheel.rl("debug/debug.vert"));
|
||||
public static final FileResolution FRAGMENT = FileResolution.get(Flywheel.rl("debug/debug.frag"));
|
||||
|
||||
public static void init() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This never worked (and the thing it was meant to debug is already fixed),
|
||||
// but it should be a quick turnaround
|
||||
private static class Frustum {
|
||||
private static final int[] indices = new int[]{
|
||||
0, 2, 3, 0, 3, 1,
|
||||
2, 6, 7, 2, 7, 3,
|
||||
6, 4, 5, 6, 5, 7,
|
||||
4, 0, 1, 4, 1, 5,
|
||||
0, 4, 6, 0, 6, 2,
|
||||
1, 5, 7, 1, 7, 3,
|
||||
};
|
||||
|
||||
private static final int elementCount = indices.length;
|
||||
private static final int indicesSize = elementCount * 4;
|
||||
private static final int verticesSize = 3 * 8 * 4;
|
||||
private final int buffer;
|
||||
private final int vao;
|
||||
|
||||
public Frustum() {
|
||||
// holy moly DSA is nice
|
||||
buffer = GL46.glCreateBuffers();
|
||||
GL46.glNamedBufferStorage(buffer, verticesSize + indicesSize, GL46.GL_DYNAMIC_STORAGE_BIT);
|
||||
GL46.glNamedBufferSubData(buffer, 0, indices);
|
||||
|
||||
vao = GL46.glCreateVertexArrays();
|
||||
GL46.glEnableVertexArrayAttrib(vao, 0);
|
||||
GL46.glVertexArrayElementBuffer(vao, buffer);
|
||||
GL46.glVertexArrayVertexBuffer(vao, 0, buffer, indicesSize, 3 * 4);
|
||||
GL46.glVertexArrayAttribFormat(vao, 0, 3, GL46.GL_FLOAT, false, 0);
|
||||
}
|
||||
|
||||
public void upload(FrustumIntersection culler) {
|
||||
try (var stack = MemoryStack.stackPush()) {
|
||||
var buf = stack.malloc(3 * 8 * 4);
|
||||
|
||||
culler.getCorners(buf);
|
||||
|
||||
GL46.glNamedBufferSubData(buffer, indicesSize, buf);
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
GL46.glEnableVertexArrayAttrib(vao, 0);
|
||||
GL46.glVertexArrayElementBuffer(vao, buffer);
|
||||
GL46.glBindVertexArray(vao);
|
||||
GL46.glDrawElements(GL46.GL_TRIANGLES, elementCount, GL46.GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,8 +2,6 @@ package com.jozufozu.flywheel.core;
|
|||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class WorldProgram extends GlProgram {
|
||||
|
||||
// TODO: sampler registry?
|
||||
|
@ -11,8 +9,8 @@ public class WorldProgram extends GlProgram {
|
|||
protected int overlayTex;
|
||||
protected int lightTex;
|
||||
|
||||
public WorldProgram(ResourceLocation name, int handle) {
|
||||
super(name, handle);
|
||||
public WorldProgram(int handle) {
|
||||
super(handle);
|
||||
|
||||
bind();
|
||||
registerSamplers();
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
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.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
|
||||
/**
|
||||
* Simple shader compiler that pulls no excessive tricks.<p>
|
||||
* Useful for writing experimental shaders or
|
||||
*/
|
||||
public class DebugCompiler extends Memoizer<DebugCompiler.Context, GlProgram> {
|
||||
|
||||
public static final DebugCompiler INSTANCE = new DebugCompiler();
|
||||
|
||||
private final ShaderCompiler shaderCompiler;
|
||||
|
||||
private DebugCompiler() {
|
||||
this.shaderCompiler = new ShaderCompiler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
super.invalidate();
|
||||
shaderCompiler.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlProgram _create(DebugCompiler.Context ctx) {
|
||||
|
||||
return new ProgramAssembler(ctx.vertex.getFileLoc())
|
||||
.attachShader(shaderCompiler.vertex(ctx.vertex))
|
||||
.attachShader(shaderCompiler.fragment(ctx.fragment))
|
||||
.link()
|
||||
.build(GlProgram::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _destroy(GlProgram value) {
|
||||
value.delete();
|
||||
}
|
||||
|
||||
public static void invalidateAll(ReloadRenderersEvent ignored) {
|
||||
INSTANCE.invalidate();
|
||||
}
|
||||
|
||||
public record Context(FileResolution vertex, FileResolution fragment) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles compilation and deletion of vertex shaders.
|
||||
*/
|
||||
private static class ShaderCompiler extends Memoizer<ShaderCompiler.Context, GlShader> {
|
||||
|
||||
public GlShader vertex(FileResolution source) {
|
||||
return get(new Context(source, ShaderType.VERTEX));
|
||||
}
|
||||
|
||||
public GlShader fragment(FileResolution source) {
|
||||
return get(new Context(source, ShaderType.FRAGMENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GlShader _create(Context ctx) {
|
||||
var index = new CompilationContext();
|
||||
|
||||
StringBuilder source = new StringBuilder(CompileUtil.generateHeader(GLSLVersion.V420, ctx.type));
|
||||
|
||||
var file = ctx.source.getFile();
|
||||
for (var include : file.flattenedImports) {
|
||||
source.append(include.source(index));
|
||||
}
|
||||
|
||||
source.append(file.source(index));
|
||||
|
||||
try {
|
||||
return new GlShader(source.toString(), ctx.type, ImmutableList.of(ctx.source.getFileLoc()));
|
||||
} catch (ShaderCompilationException e) {
|
||||
throw e.withErrorLog(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _destroy(GlShader value) {
|
||||
value.delete();
|
||||
}
|
||||
|
||||
public record Context(FileResolution source, ShaderType type) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.compile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class Memoizer<K, V> {
|
||||
|
||||
private final Map<K, V> map = new HashMap<>();
|
||||
|
||||
public V get(K key) {
|
||||
return map.computeIfAbsent(key, this::_create);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
map.values().forEach(this::_destroy);
|
||||
map.clear();
|
||||
}
|
||||
|
||||
protected abstract V _create(K key);
|
||||
|
||||
protected abstract void _destroy(V value);
|
||||
}
|
|
@ -2,11 +2,9 @@ package com.jozufozu.flywheel.core.crumbling;
|
|||
|
||||
import com.jozufozu.flywheel.core.WorldProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class CrumblingProgram extends WorldProgram {
|
||||
public CrumblingProgram(ResourceLocation name, int handle) {
|
||||
super(name, handle);
|
||||
public CrumblingProgram(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,11 +27,11 @@ public class CompilationContext {
|
|||
|
||||
generatedLines += lines;
|
||||
|
||||
if (comment != null) {
|
||||
out += " // " + comment;
|
||||
if (comment == null) {
|
||||
comment = "";
|
||||
}
|
||||
|
||||
return out + '\n';
|
||||
return out + " // (generated) " + comment + '\n';
|
||||
}
|
||||
|
||||
public boolean contains(SourceFile sourceFile) {
|
||||
|
|
|
@ -80,7 +80,7 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
@Override
|
||||
public String source(CompilationContext ctx) {
|
||||
return ctx.sourceHeader(this) + this.elideImports();
|
||||
return ctx.sourceHeader(this) + this.genFinalSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,7 +188,7 @@ public class SourceFile implements SourceComponent {
|
|||
return "Source for shader '" + name + "':\n" + lines.printLinesWithNumbers();
|
||||
}
|
||||
|
||||
private CharSequence elideImports() {
|
||||
private CharSequence genFinalSource() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
int lastEnd = 0;
|
||||
|
|
|
@ -2,13 +2,15 @@ package com.jozufozu.flywheel.core.source.generate;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
|
||||
public class GlslBuilder {
|
||||
public static final String INDENT = " ";
|
||||
|
||||
private final List<SourceElement> elements = new ArrayList<>();
|
||||
private final List<GlslRootElement> elements = new ArrayList<>();
|
||||
|
||||
public void define(String name, String value) {
|
||||
add(new Define(name, value));
|
||||
|
@ -26,7 +28,7 @@ public class GlslBuilder {
|
|||
return add(new VertexInputBuilder());
|
||||
}
|
||||
|
||||
public <T extends SourceElement> T add(T element) {
|
||||
public <T extends GlslRootElement> T add(T element) {
|
||||
elements.add(element);
|
||||
return element;
|
||||
}
|
||||
|
@ -37,15 +39,19 @@ public class GlslBuilder {
|
|||
|
||||
public String build() {
|
||||
return elements.stream()
|
||||
.map(SourceElement::build)
|
||||
.map(GlslRootElement::minPrint)
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public interface SourceElement {
|
||||
String build();
|
||||
public static String indent(int indentation) {
|
||||
return INDENT.repeat(indentation);
|
||||
}
|
||||
|
||||
public enum Separators implements SourceElement {
|
||||
public interface GlslRootElement {
|
||||
String minPrint();
|
||||
}
|
||||
|
||||
public enum Separators implements GlslRootElement {
|
||||
BLANK_LINE(""),
|
||||
;
|
||||
|
||||
|
@ -54,21 +60,21 @@ public class GlslBuilder {
|
|||
Separators(String separator) {
|
||||
this.separator = separator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
public String minPrint() {
|
||||
return separator;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public record Define(String name, String value) implements SourceElement {
|
||||
public record Define(String name, String value) implements GlslRootElement {
|
||||
@Override
|
||||
public String build() {
|
||||
public String minPrint() {
|
||||
return "#define " + name + " " + value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VertexInputBuilder implements SourceElement {
|
||||
public static class VertexInputBuilder implements GlslRootElement {
|
||||
|
||||
private int binding;
|
||||
private String type;
|
||||
|
@ -90,12 +96,12 @@ public class GlslBuilder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String build() {
|
||||
public String minPrint() {
|
||||
return "layout(location = " + binding + ") in " + type + " " + name + ";";
|
||||
}
|
||||
}
|
||||
|
||||
public static class StructBuilder implements SourceElement {
|
||||
public static class StructBuilder implements GlslRootElement {
|
||||
|
||||
private final List<Pair<String, String>> fields = new ArrayList<>();
|
||||
private String name;
|
||||
|
@ -110,11 +116,11 @@ public class GlslBuilder {
|
|||
|
||||
private String buildFields() {
|
||||
return fields.stream()
|
||||
.map(p -> '\t' + p.first() + ' ' + p.second() + ';')
|
||||
.map(p -> INDENT + p.first() + ' ' + p.second() + ';')
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public String build() {
|
||||
public String minPrint() {
|
||||
return """
|
||||
struct %s {
|
||||
%s
|
||||
|
@ -123,9 +129,9 @@ public class GlslBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
public static class FunctionBuilder implements SourceElement {
|
||||
public static class FunctionBuilder implements GlslRootElement {
|
||||
private final List<Pair<String, String>> arguments = new ArrayList<>();
|
||||
private final List<String> body = new ArrayList<>();
|
||||
private final BlockBuilder body = new BlockBuilder();
|
||||
private String returnType;
|
||||
private String name;
|
||||
|
||||
|
@ -149,24 +155,17 @@ public class GlslBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public FunctionBuilder statement(String statement) {
|
||||
this.body.add(statement);
|
||||
public FunctionBuilder body(Consumer<BlockBuilder> f) {
|
||||
f.accept(body);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public String build() {
|
||||
public String minPrint() {
|
||||
return """
|
||||
%s %s(%s) {
|
||||
%s
|
||||
}
|
||||
""".formatted(returnType, name, buildArguments(), buildBody());
|
||||
}
|
||||
|
||||
private String buildBody() {
|
||||
return body.stream()
|
||||
.map(s -> '\t' + s)
|
||||
.collect(Collectors.joining("\n"));
|
||||
""".formatted(returnType, name, buildArguments(), body.prettyPrint());
|
||||
}
|
||||
|
||||
private String buildArguments() {
|
||||
|
@ -175,4 +174,61 @@ public class GlslBuilder {
|
|||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
}
|
||||
|
||||
public static class BlockBuilder implements LangItem {
|
||||
private final List<GlslStmt> body = new ArrayList<>();
|
||||
|
||||
public BlockBuilder add(GlslStmt stmt) {
|
||||
body.add(stmt);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockBuilder eval(GlslExpr expr) {
|
||||
return add(GlslStmt.eval(expr));
|
||||
}
|
||||
|
||||
public BlockBuilder switchOn(GlslExpr expr, Consumer<SwitchBuilder> f) {
|
||||
var builder = new SwitchBuilder(expr);
|
||||
f.accept(builder);
|
||||
return add(builder.build());
|
||||
}
|
||||
|
||||
public void ret(GlslExpr call) {
|
||||
add(GlslStmt.ret(call));
|
||||
}
|
||||
|
||||
public void break_() {
|
||||
add(GlslStmt.BREAK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return body.stream()
|
||||
.map(GlslStmt::prettyPrint)
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SwitchBuilder {
|
||||
|
||||
private final GlslExpr on;
|
||||
|
||||
private final List<Pair<GlslExpr, BlockBuilder>> cases = new ArrayList<>();
|
||||
|
||||
public SwitchBuilder(GlslExpr on) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
public SwitchBuilder case_(int expr, Consumer<BlockBuilder> f) {
|
||||
var builder = new BlockBuilder();
|
||||
f.accept(builder);
|
||||
cases.add(Pair.of(GlslExpr.literal(expr), builder));
|
||||
return this;
|
||||
}
|
||||
|
||||
public GlslStmt.Switch build() {
|
||||
return new GlslStmt.Switch(on, cases);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
package com.jozufozu.flywheel.core.source.generate;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public sealed interface GlslExpr {
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
public interface GlslExpr extends LangItem {
|
||||
|
||||
/**
|
||||
* Create a glsl variable with the given name.
|
||||
|
@ -14,7 +18,17 @@ public sealed interface GlslExpr {
|
|||
return new Variable(name);
|
||||
}
|
||||
|
||||
String minPrint();
|
||||
static FunctionCall call(String functionName, Collection<? extends GlslExpr> args) {
|
||||
return new FunctionCall(functionName, args);
|
||||
}
|
||||
|
||||
static FunctionCall0 call(String functionName) {
|
||||
return new FunctionCall0(functionName);
|
||||
}
|
||||
|
||||
static GlslExpr literal(int expr) {
|
||||
return new Literal(expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a one-parameter function with the given name on this expression.
|
||||
|
@ -58,29 +72,55 @@ public sealed interface GlslExpr {
|
|||
|
||||
record Variable(String name) implements GlslExpr {
|
||||
@Override
|
||||
public String minPrint() {
|
||||
public String prettyPrint() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record FunctionCall(String name, GlslExpr target) implements GlslExpr {
|
||||
@Override
|
||||
public String minPrint() {
|
||||
return name + "(" + target.minPrint() + ")";
|
||||
record FunctionCall(String name, Collection<? extends GlslExpr> args) implements GlslExpr {
|
||||
public FunctionCall(String name, GlslExpr target) {
|
||||
this(name, ImmutableList.of(target));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
var args = this.args.stream()
|
||||
.map(GlslExpr::prettyPrint)
|
||||
.collect(Collectors.joining(","));
|
||||
return name + "(" + args + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record FunctionCall0(String name) implements GlslExpr {
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return name + "()";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record Swizzle(GlslExpr target, String selection) implements GlslExpr {
|
||||
@Override
|
||||
public String minPrint() {
|
||||
return target.minPrint() + "." + selection;
|
||||
public String prettyPrint() {
|
||||
return target.prettyPrint() + "." + selection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record Access(GlslExpr target, String argName) implements GlslExpr {
|
||||
@Override
|
||||
public String minPrint() {
|
||||
return target.minPrint() + "." + argName;
|
||||
public String prettyPrint() {
|
||||
return target.prettyPrint() + "." + argName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record Literal(int value) implements GlslExpr {
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return Integer.toString(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package com.jozufozu.flywheel.core.source.generate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
|
||||
public interface GlslStmt extends LangItem {
|
||||
|
||||
static GlslStmt eval(GlslExpr expr) {
|
||||
return new Eval(expr);
|
||||
}
|
||||
|
||||
static GlslStmt ret(GlslExpr value) {
|
||||
return new Return(value);
|
||||
}
|
||||
|
||||
static GlslStmt BREAK = () -> "break;";
|
||||
|
||||
static GlslStmt CONTINUE = () -> "continue;";
|
||||
|
||||
static GlslStmt RETURN = () -> "return;";
|
||||
|
||||
record Eval(GlslExpr expr) implements GlslStmt {
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return expr.prettyPrint() + ";";
|
||||
}
|
||||
}
|
||||
|
||||
record Return(GlslExpr expr) implements GlslStmt {
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return "return " + expr.prettyPrint() + ";";
|
||||
}
|
||||
}
|
||||
|
||||
record Switch(GlslExpr expr, List<Pair<GlslExpr, GlslBuilder.BlockBuilder>> body) implements GlslStmt {
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
var cases = body.stream()
|
||||
.map(Switch::prettyPrintCase)
|
||||
.collect(Collectors.joining("\n"));
|
||||
return """
|
||||
switch (%s) {
|
||||
%s
|
||||
}""".formatted(expr.prettyPrint(), cases);
|
||||
}
|
||||
|
||||
private static String prettyPrintCase(Pair<GlslExpr, GlslBuilder.BlockBuilder> p) {
|
||||
var variant = p.first()
|
||||
.prettyPrint();
|
||||
var block = p.second()
|
||||
.prettyPrint();
|
||||
return """
|
||||
case %s:
|
||||
%s""".formatted(variant, block);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.source.generate;
|
||||
|
||||
public interface LangItem {
|
||||
|
||||
String prettyPrint();
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.core.compile;
|
||||
package com.jozufozu.flywheel.core.source.generate;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
|
@ -7,33 +7,59 @@ import com.jozufozu.flywheel.core.Components;
|
|||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
public class FogProvider extends UniformProvider {
|
||||
public class FogProvider implements UniformProvider {
|
||||
|
||||
public static boolean FOG_UPDATE = true;
|
||||
|
||||
@Override
|
||||
public int getActualByteSize() {
|
||||
public int byteSize() {
|
||||
return 16 + 8 + 4;
|
||||
}
|
||||
|
||||
public void update() {
|
||||
if (ptr == MemoryUtil.NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
var color = RenderSystem.getShaderFogColor();
|
||||
|
||||
MemoryUtil.memPutFloat(ptr, color[0]);
|
||||
MemoryUtil.memPutFloat(ptr + 4, color[1]);
|
||||
MemoryUtil.memPutFloat(ptr + 8, color[2]);
|
||||
MemoryUtil.memPutFloat(ptr + 12, color[3]);
|
||||
MemoryUtil.memPutFloat(ptr + 16, RenderSystem.getShaderFogStart());
|
||||
MemoryUtil.memPutFloat(ptr + 20, RenderSystem.getShaderFogEnd());
|
||||
MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape().getIndex());
|
||||
|
||||
notifier.signalChanged();
|
||||
@Override
|
||||
public FileResolution uniformShader() {
|
||||
return Components.Files.FOG_UNIFORMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getUniformShader() {
|
||||
return Components.Files.FOG_UNIFORMS;
|
||||
public ActiveUniformProvider activate(long ptr, Notifier notifier) {
|
||||
return new Active(ptr, notifier);
|
||||
}
|
||||
|
||||
public static class Active implements ActiveUniformProvider {
|
||||
|
||||
private final long ptr;
|
||||
private final Notifier notifier;
|
||||
|
||||
public Active(long ptr, Notifier notifier) {
|
||||
this.ptr = ptr;
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void poll() {
|
||||
if (!FOG_UPDATE) {
|
||||
return;
|
||||
}
|
||||
|
||||
var color = RenderSystem.getShaderFogColor();
|
||||
|
||||
MemoryUtil.memPutFloat(ptr, color[0]);
|
||||
MemoryUtil.memPutFloat(ptr + 4, color[1]);
|
||||
MemoryUtil.memPutFloat(ptr + 8, color[2]);
|
||||
MemoryUtil.memPutFloat(ptr + 12, color[3]);
|
||||
MemoryUtil.memPutFloat(ptr + 16, RenderSystem.getShaderFogStart());
|
||||
MemoryUtil.memPutFloat(ptr + 20, RenderSystem.getShaderFogEnd());
|
||||
MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape()
|
||||
.getIndex());
|
||||
|
||||
notifier.signalChanged();
|
||||
|
||||
FOG_UPDATE = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.uniform;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.uniform.UniformProvider;
|
||||
|
@ -13,47 +15,71 @@ import net.minecraft.core.Vec3i;
|
|||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
public class FrustumProvider extends UniformProvider {
|
||||
public class FrustumProvider implements UniformProvider {
|
||||
|
||||
public static boolean PAUSED = false;
|
||||
public static boolean CAPTURE = false;
|
||||
|
||||
public FrustumProvider() {
|
||||
MinecraftForge.EVENT_BUS.addListener(this::beginFrame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActualByteSize() {
|
||||
public int byteSize() {
|
||||
return 96;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getUniformShader() {
|
||||
public FileResolution uniformShader() {
|
||||
return Components.Files.FRUSTUM_UNIFORMS;
|
||||
}
|
||||
|
||||
public void beginFrame(BeginFrameEvent event) {
|
||||
update(event.getContext());
|
||||
@Override
|
||||
public ActiveUniformProvider activate(long ptr, Notifier notifier) {
|
||||
return new Active(ptr, notifier);
|
||||
}
|
||||
|
||||
public void update(RenderContext context) {
|
||||
if (ptr == MemoryUtil.NULL || (PAUSED && !CAPTURE)) {
|
||||
return;
|
||||
static class Active implements ActiveUniformProvider, Consumer<BeginFrameEvent> {
|
||||
|
||||
private final long ptr;
|
||||
private final Notifier notifier;
|
||||
|
||||
public Active(long ptr, Notifier notifier) {
|
||||
this.ptr = ptr;
|
||||
this.notifier = notifier;
|
||||
MinecraftForge.EVENT_BUS.addListener(this);
|
||||
}
|
||||
|
||||
Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level());
|
||||
Vec3 camera = context.camera()
|
||||
.getPosition();
|
||||
@Override
|
||||
public void delete() {
|
||||
MinecraftForge.EVENT_BUS.unregister(this);
|
||||
}
|
||||
|
||||
var camX = (float) (camera.x - originCoordinate.getX());
|
||||
var camY = (float) (camera.y - originCoordinate.getY());
|
||||
var camZ = (float) (camera.z - originCoordinate.getZ());
|
||||
@Override
|
||||
public void poll() {
|
||||
|
||||
var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ);
|
||||
}
|
||||
|
||||
shiftedCuller.getJozuPackedPlanes(ptr);
|
||||
@Override
|
||||
public void accept(BeginFrameEvent event) {
|
||||
update(event.getContext());
|
||||
}
|
||||
|
||||
notifier.signalChanged();
|
||||
CAPTURE = false;
|
||||
public void update(RenderContext context) {
|
||||
if (ptr == MemoryUtil.NULL || (PAUSED && !CAPTURE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(context.level());
|
||||
Vec3 camera = context.camera()
|
||||
.getPosition();
|
||||
|
||||
var camX = (float) (camera.x - originCoordinate.getX());
|
||||
var camY = (float) (camera.y - originCoordinate.getY());
|
||||
var camZ = (float) (camera.z - originCoordinate.getZ());
|
||||
|
||||
var shiftedCuller = RenderContext.createCuller(context.viewProjection(), -camX, -camY, -camZ);
|
||||
|
||||
shiftedCuller.getJozuPackedPlanes(ptr);
|
||||
|
||||
notifier.signalChanged();
|
||||
CAPTURE = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class UniformBuffer {
|
|||
int totalBytes = 0;
|
||||
int index = 0;
|
||||
for (UniformProvider provider : providers) {
|
||||
int size = alignPo2(provider.getActualByteSize(), 16);
|
||||
int size = align16(provider.byteSize());
|
||||
|
||||
builder.add(new Allocated(provider, totalBytes, size, index));
|
||||
|
||||
|
@ -64,6 +64,7 @@ public class UniformBuffer {
|
|||
}
|
||||
|
||||
public void sync() {
|
||||
allocatedProviders.forEach(Allocated::pollActive);
|
||||
if (changedBytes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -88,8 +89,8 @@ public class UniformBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
private static int alignPo2(int numToRound, int alignment) {
|
||||
return (numToRound + alignment - 1) & -alignment;
|
||||
private static int align16(int numToRound) {
|
||||
return (numToRound + 16 - 1) & -16;
|
||||
}
|
||||
|
||||
private class Allocated implements UniformProvider.Notifier {
|
||||
|
@ -97,6 +98,7 @@ public class UniformBuffer {
|
|||
private final int offset;
|
||||
private final int size;
|
||||
private final int index;
|
||||
private UniformProvider.ActiveUniformProvider activeProvider;
|
||||
|
||||
private Allocated(UniformProvider provider, int offset, int size, int index) {
|
||||
this.provider = provider;
|
||||
|
@ -111,7 +113,10 @@ public class UniformBuffer {
|
|||
}
|
||||
|
||||
private void updatePtr(MemoryBlock bufferBase) {
|
||||
provider.updatePtr(bufferBase.ptr() + offset, this);
|
||||
if (activeProvider != null) {
|
||||
activeProvider.delete();
|
||||
}
|
||||
activeProvider = provider.activate(bufferBase.ptr() + offset, this);
|
||||
}
|
||||
|
||||
public UniformProvider provider() {
|
||||
|
@ -129,5 +134,11 @@ public class UniformBuffer {
|
|||
public int index() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public void pollActive() {
|
||||
if (activeProvider != null) {
|
||||
activeProvider.poll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.core.uniform;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.uniform.UniformProvider;
|
||||
|
@ -15,54 +17,75 @@ import net.minecraft.core.Vec3i;
|
|||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
||||
public class ViewProvider extends UniformProvider {
|
||||
public class ViewProvider implements UniformProvider {
|
||||
|
||||
public ViewProvider() {
|
||||
MinecraftForge.EVENT_BUS.addListener(this::beginFrame);
|
||||
}
|
||||
public static final int SIZE = 4 * 16 + 16 + 4;
|
||||
|
||||
public void beginFrame(BeginFrameEvent event) {
|
||||
update(event.getContext());
|
||||
@Override
|
||||
public int byteSize() {
|
||||
return SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActualByteSize() {
|
||||
return 4 * 16 + 16 + 4;
|
||||
}
|
||||
|
||||
public void update(RenderContext context) {
|
||||
if (ptr == MemoryUtil.NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClientLevel level = context.level();
|
||||
|
||||
int constantAmbientLight = level.effects()
|
||||
.constantAmbientLight() ? 1 : 0;
|
||||
|
||||
Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(level);
|
||||
Vec3 camera = context.camera()
|
||||
.getPosition();
|
||||
|
||||
var camX = (float) (camera.x - originCoordinate.getX());
|
||||
var camY = (float) (camera.y - originCoordinate.getY());
|
||||
var camZ = (float) (camera.z - originCoordinate.getZ());
|
||||
|
||||
// don't want to mutate viewProjection
|
||||
var vp = context.viewProjection().copy();
|
||||
vp.multiplyWithTranslation(-camX, -camY, -camZ);
|
||||
|
||||
MatrixWrite.writeUnsafe(vp, ptr);
|
||||
MemoryUtil.memPutFloat(ptr + 64, camX);
|
||||
MemoryUtil.memPutFloat(ptr + 68, camY);
|
||||
MemoryUtil.memPutFloat(ptr + 72, camZ);
|
||||
MemoryUtil.memPutInt(ptr + 76, constantAmbientLight);
|
||||
|
||||
notifier.signalChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution getUniformShader() {
|
||||
public FileResolution uniformShader() {
|
||||
return Components.Files.VIEW_UNIFORMS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActiveUniformProvider activate(long ptr, Notifier notifier) {
|
||||
return new Active(ptr, notifier);
|
||||
}
|
||||
|
||||
public static class Active implements ActiveUniformProvider, Consumer<BeginFrameEvent> {
|
||||
private final long ptr;
|
||||
private final Notifier notifier;
|
||||
|
||||
public Active(long ptr, Notifier notifier) {
|
||||
this.ptr = ptr;
|
||||
this.notifier = notifier;
|
||||
MinecraftForge.EVENT_BUS.addListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
MinecraftForge.EVENT_BUS.unregister(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void poll() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(BeginFrameEvent event) {
|
||||
update(event.getContext());
|
||||
}
|
||||
|
||||
public void update(RenderContext context) {
|
||||
ClientLevel level = context.level();
|
||||
|
||||
int constantAmbientLight = level.effects()
|
||||
.constantAmbientLight() ? 1 : 0;
|
||||
|
||||
Vec3i originCoordinate = InstancedRenderDispatcher.getOriginCoordinate(level);
|
||||
Vec3 camera = context.camera()
|
||||
.getPosition();
|
||||
|
||||
var camX = (float) (camera.x - originCoordinate.getX());
|
||||
var camY = (float) (camera.y - originCoordinate.getY());
|
||||
var camZ = (float) (camera.z - originCoordinate.getZ());
|
||||
|
||||
// don't want to mutate viewProjection
|
||||
var vp = context.viewProjection()
|
||||
.copy();
|
||||
vp.multiplyWithTranslation(-camX, -camY, -camZ);
|
||||
|
||||
MatrixWrite.writeUnsafe(vp, ptr);
|
||||
MemoryUtil.memPutFloat(ptr + 64, camX);
|
||||
MemoryUtil.memPutFloat(ptr + 68, camY);
|
||||
MemoryUtil.memPutFloat(ptr + 72, camZ);
|
||||
MemoryUtil.memPutInt(ptr + 76, constantAmbientLight);
|
||||
|
||||
notifier.signalChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,14 @@ 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.core.Components;
|
||||
import com.jozufozu.flywheel.core.uniform.FogProvider;
|
||||
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
|
||||
@Mixin(FogRenderer.class)
|
||||
public class FogUpdateMixin {
|
||||
private static void flywheel$updateFog() {
|
||||
Components.FOG_PROVIDER.update();
|
||||
FogProvider.FOG_UPDATE = true;
|
||||
}
|
||||
|
||||
@Inject(method = "setupNoFog", at = @At("TAIL"))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
public record Pair<F, S>(F first, S second) {
|
||||
|
||||
|
@ -8,6 +9,10 @@ public record Pair<F, S>(F first, S second) {
|
|||
return new Pair<>(first, second);
|
||||
}
|
||||
|
||||
public static <I, O> Function<Pair<? extends I, ? extends I>, Pair<O, O>> both(Function<I, O> map) {
|
||||
return pair -> of(map.apply(pair.first), map.apply(pair.second));
|
||||
}
|
||||
|
||||
public Pair<S, F> swap() {
|
||||
return Pair.of(second, first);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class ResourceUtil {
|
||||
|
||||
// Match the complement of alphanumeric and underscore.
|
||||
private static final Pattern UNSAFE_CHARS = Pattern.compile("[^a-zA-Z0-9_]");
|
||||
|
||||
public static ResourceLocation subPath(ResourceLocation root, String subPath) {
|
||||
return new ResourceLocation(root.getNamespace(), root.getPath() + subPath);
|
||||
}
|
||||
|
@ -17,4 +22,9 @@ public class ResourceUtil {
|
|||
String path = loc.getPath();
|
||||
return new ResourceLocation(loc.getNamespace(), path.substring(prefix.length(), path.length() - suffix.length()));
|
||||
}
|
||||
|
||||
public static String toSafeString(ResourceLocation rl) {
|
||||
return UNSAFE_CHARS.matcher(rl.toString())
|
||||
.replaceAll("_");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ in vec4 flw_var1;
|
|||
in vec4 flw_var2;
|
||||
in vec4 flw_var3;
|
||||
|
||||
flat in uint flw_materialFragmentID;
|
||||
|
||||
//
|
||||
|
||||
/*const*/ vec4 flw_sampleColor;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#ifdef VERTEX_SHADER
|
||||
uint flw_materialVertexID;
|
||||
|
||||
out vec4 flw_vertexPos;
|
||||
out vec4 flw_vertexColor;
|
||||
out vec2 flw_vertexTexCoord;
|
||||
|
@ -12,4 +14,5 @@ out vec4 flw_var0;
|
|||
out vec4 flw_var1;
|
||||
out vec4 flw_var2;
|
||||
out vec4 flw_var3;
|
||||
flat out uint flw_materialFragmentID;
|
||||
#endif
|
||||
|
|
50
src/main/resources/assets/flywheel/flywheel/compute/mat.glsl
Normal file
50
src/main/resources/assets/flywheel/flywheel/compute/mat.glsl
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
This is what generated ubershaders should look like
|
||||
|
||||
uint flw_materialVertexID = 0;
|
||||
uint flw_materialFragmentID = 0;
|
||||
|
||||
void flw_materialVertex() {
|
||||
switch (flw_materialVertexID) {
|
||||
case 0: flw_materialVertex_flywheel_cutout_vert(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void flw_materialFragment() {
|
||||
switch (flw_materialFragmentID) {
|
||||
case 0: flw_materialFragment_flywheel_cutout_frag(); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
bool flw_discardPredicate(vec4 finalColor) {
|
||||
switch (flw_materialFragmentID) {
|
||||
case 0: return flw_discardPredicate_flywheel_cutout_frag(finalColor);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
vec4 flw_fogFilter(vec4 color) {
|
||||
switch (flw_materialFragmentID) {
|
||||
case 0: return flw_fogFilter_flywheel_cutout_frag(color);
|
||||
default: return color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void flw_materialVertex_flywheel_cutout_vert() {
|
||||
}
|
||||
|
||||
void flw_materialFragment_flywheel_cutout_frag() {
|
||||
}
|
||||
|
||||
bool flw_discardPredicate_flywheel_cutout_frag(vec4 finalColor) {
|
||||
return finalColor.a < 0.1;
|
||||
}
|
||||
|
||||
vec4 flw_fogFilter_flywheel_cutout_frag(vec4 color) {
|
||||
return linear_fog(color, flw_distance, flw_fogRange.x, flw_fogRange.y, flw_fogColor);
|
||||
}
|
||||
|
||||
*/
|
|
@ -1,5 +1,4 @@
|
|||
layout(std140, binding = 1) uniform flw_fog {
|
||||
vec4 flw_fogColor;
|
||||
vec2 flw_fogRange;
|
||||
int flw_fogShape;
|
||||
};
|
||||
// TODO: Transform uniform shaders
|
||||
vec4 flw_fogColor;
|
||||
vec2 flw_fogRange;
|
||||
int flw_fogShape;
|
||||
|
|
|
@ -9,6 +9,4 @@ struct FLWPackedPlanes {
|
|||
vec2 zW; // <nz.w, pz.w>
|
||||
};
|
||||
|
||||
layout(std140, binding = 2) uniform FLWFrustum {
|
||||
FLWPackedPlanes flw_planes;
|
||||
};
|
||||
FLWPackedPlanes flw_planes;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
layout(std140, binding = 0) uniform flw_view {
|
||||
mat4 flw_viewProjection;
|
||||
vec4 flw_cameraPos;
|
||||
int flw_constantAmbientLight;
|
||||
};
|
||||
mat4 flw_viewProjection;
|
||||
vec4 flw_cameraPos;
|
||||
int flw_constantAmbientLight;
|
||||
|
|
Loading…
Reference in a new issue