mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-11 20:55:00 +01:00
Taxi shaders
- Not *quite* ubershaders yet - Note: heavily broken - "Pull" based compilation - Sources are only ready when they are needed by the compiler - Compiler is responsible for import resolution - Compiler prepends file headers - Reduces need for FileResolution - May replace with ResourceLocations? - Not sure about the future of source checks - TODO: Lots of dead code left in FileResolution - PipelineShader -> Pipeline interface + Simple impl - Use Context object for assembler factory
This commit is contained in:
parent
28e16a7810
commit
99e4105e94
45 changed files with 703 additions and 759 deletions
|
@ -2,15 +2,7 @@ package com.jozufozu.flywheel.api.context;
|
|||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
|
||||
public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader, FileResolution fragmentShader) {
|
||||
|
||||
public SourceFile getVertexShader() {
|
||||
return vertexShader.getFile();
|
||||
}
|
||||
|
||||
public SourceFile getFragmentShader() {
|
||||
return fragmentShader.getFile();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
package com.jozufozu.flywheel.api.pipeline;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
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.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
|
||||
public record PipelineShader(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment,
|
||||
InstanceAssemblerFactory factory) {
|
||||
public interface Pipeline {
|
||||
|
||||
GLSLVersion glslVersion();
|
||||
|
||||
FileResolution vertex();
|
||||
|
||||
FileResolution fragment();
|
||||
|
||||
/**
|
||||
* Generate the source component necessary to convert a packed {@link StructType} into its shader representation.
|
||||
*
|
||||
* @param structType The struct type to convert.
|
||||
* @return A source component defining functions that unpack a representation of the given struct type.
|
||||
*/
|
||||
public SourceComponent assemble(VertexType vertexType, StructType<?> structType) {
|
||||
return factory.apply(vertexType, structType);
|
||||
}
|
||||
|
||||
public interface InstanceAssemblerFactory extends BiFunction<VertexType, StructType<?>, SourceComponent> {
|
||||
SourceComponent assemble(InstanceAssemblerContext context);
|
||||
|
||||
record InstanceAssemblerContext(ShaderSources sources, VertexType vertexType, StructType<?> structType) {
|
||||
}
|
||||
}
|
|
@ -2,8 +2,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 com.jozufozu.flywheel.core.pipeline.SimplePipeline;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
|
@ -21,5 +21,5 @@ public interface BackendType {
|
|||
|
||||
boolean supported();
|
||||
|
||||
@Nullable PipelineShader pipelineShader();
|
||||
@Nullable SimplePipeline pipelineShader();
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.jozufozu.flywheel.backend;
|
|||
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
|
||||
|
@ -24,11 +23,12 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
Loader() {
|
||||
// Can be null when running datagenerators due to the unfortunate time we call this
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
if (minecraft != null) {
|
||||
ResourceManager manager = minecraft.getResourceManager();
|
||||
if (manager instanceof ReloadableResourceManager) {
|
||||
((ReloadableResourceManager) manager).registerReloadListener(this);
|
||||
}
|
||||
if (minecraft == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (minecraft.getResourceManager() instanceof ReloadableResourceManager reloadable) {
|
||||
reloadable.registerReloadListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,23 +39,7 @@ public class Loader implements ResourceManagerReloadListener {
|
|||
var errorReporter = new ErrorReporter();
|
||||
ShaderSources sources = new ShaderSources(errorReporter, manager);
|
||||
|
||||
Backend.LOGGER.info("Loaded all shader sources in " + sources.getLoadTime());
|
||||
|
||||
FileResolution.run(errorReporter, sources);
|
||||
|
||||
if (errorReporter.hasErrored()) {
|
||||
throw errorReporter.dump();
|
||||
}
|
||||
|
||||
sources.postResolve();
|
||||
|
||||
Backend.LOGGER.info("Successfully resolved all source files.");
|
||||
|
||||
FileResolution.checkAll(errorReporter);
|
||||
|
||||
Backend.LOGGER.info("All shaders passed checks.");
|
||||
|
||||
FlwCompiler.INSTANCE.run();
|
||||
FlwCompiler.INSTANCE = new FlwCompiler(sources);
|
||||
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
if (Backend.canUseInstancing(level)) {
|
||||
|
|
|
@ -5,9 +5,9 @@ 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;
|
||||
import com.jozufozu.flywheel.core.pipeline.SimplePipeline;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
|
@ -20,9 +20,9 @@ public class SimpleBackendType implements BackendType {
|
|||
private final Supplier<Engine> engineSupplier;
|
||||
private final Supplier<BackendType> fallback;
|
||||
private final BooleanSupplier isSupported;
|
||||
private final PipelineShader pipelineShader;
|
||||
private final SimplePipeline pipelineShader;
|
||||
|
||||
public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier<Engine> engineSupplier, Supplier<BackendType> fallback, BooleanSupplier isSupported, @Nullable PipelineShader pipelineShader) {
|
||||
public SimpleBackendType(String properName, String shortName, Component engineMessage, Supplier<Engine> engineSupplier, Supplier<BackendType> fallback, BooleanSupplier isSupported, @Nullable SimplePipeline pipelineShader) {
|
||||
this.properName = properName;
|
||||
this.shortName = shortName;
|
||||
this.engineMessage = engineMessage;
|
||||
|
@ -72,7 +72,7 @@ public class SimpleBackendType implements BackendType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public @Nullable PipelineShader pipelineShader() {
|
||||
public @Nullable SimplePipeline pipelineShader() {
|
||||
return pipelineShader;
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ public class SimpleBackendType implements BackendType {
|
|||
private Supplier<Engine> engineSupplier;
|
||||
private Supplier<BackendType> fallback;
|
||||
private BooleanSupplier isSupported;
|
||||
private PipelineShader pipelineShader;
|
||||
private SimplePipeline pipelineShader;
|
||||
|
||||
public Builder properName(String properName) {
|
||||
this.properName = properName;
|
||||
|
@ -115,7 +115,7 @@ public class SimpleBackendType implements BackendType {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Builder pipelineShader(PipelineShader pipelineShader) {
|
||||
public Builder pipelineShader(SimplePipeline pipelineShader) {
|
||||
this.pipelineShader = pipelineShader;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
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,14 +1,21 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
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.pipeline.Pipeline;
|
||||
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.backend.gl.GLSLVersion;
|
||||
|
@ -16,42 +23,64 @@ 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.BackendTypes;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.Pipelines;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.pipeline.SimplePipeline;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FlwCompiler {
|
||||
|
||||
public static final FlwCompiler INSTANCE = new FlwCompiler();
|
||||
public static FlwCompiler INSTANCE;
|
||||
|
||||
public static void onReloadRenderers(ReloadRenderersEvent t) {
|
||||
|
||||
}
|
||||
|
||||
private final ShaderCompiler shaderCompiler = new ShaderCompiler();
|
||||
public final Map<PipelineContext, GlProgram> pipelinePrograms = new HashMap<>();
|
||||
final Map<PipelineContext, GlProgram> pipelinePrograms = new HashMap<>();
|
||||
final Map<StructType<?>, GlProgram> cullingPrograms = new HashMap<>();
|
||||
|
||||
public final Map<StructType<?>, GlProgram> cullingPrograms = new HashMap<>();
|
||||
boolean needsCrash = false;
|
||||
|
||||
private CompilationEnvironment environment;
|
||||
final long compileStart = System.nanoTime();
|
||||
final Multimap<Set<UniformProvider>, PipelineContext> uniformProviderGroups = ArrayListMultimap.create();
|
||||
final List<PipelineContext> pipelineContexts = new ArrayList<>();
|
||||
|
||||
FlwCompiler() {
|
||||
private final ShaderSources sources;
|
||||
private final VertexMaterialComponent vertexMaterialComponent;
|
||||
private final FragmentMaterialComponent fragmentMaterialComponent;
|
||||
|
||||
}
|
||||
public FlwCompiler(ShaderSources sources) {
|
||||
this.sources = sources;
|
||||
this.vertexMaterialComponent = new VertexMaterialComponent(sources, ComponentRegistry.materials.vertexSources());
|
||||
this.fragmentMaterialComponent = new FragmentMaterialComponent(sources, ComponentRegistry.materials.fragmentSources());
|
||||
|
||||
public void run() {
|
||||
environment = new CompilationEnvironment();
|
||||
for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) {
|
||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||
// TODO: context ubershaders, or not?
|
||||
pipelineContexts.add(new PipelineContext(vertexType, structType, Components.WORLD, pipelineShader));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (PipelineContext context : environment.pipelineContexts) {
|
||||
// TODO: analyze uniform providers and group them into sets; break up this ctor
|
||||
|
||||
for (PipelineContext context : pipelineContexts) {
|
||||
try {
|
||||
var glProgram = compilePipelineContext(context);
|
||||
pipelinePrograms.put(context, glProgram);
|
||||
} catch (ShaderCompilationException e) {
|
||||
environment.needsCrash = true;
|
||||
needsCrash = true;
|
||||
Backend.LOGGER.error(e.errors);
|
||||
}
|
||||
}
|
||||
|
@ -61,15 +90,25 @@ public class FlwCompiler {
|
|||
var glProgram = compileComputeCuller(type);
|
||||
cullingPrograms.put(type, glProgram);
|
||||
} catch (ShaderCompilationException e) {
|
||||
environment.needsCrash = true;
|
||||
needsCrash = true;
|
||||
Backend.LOGGER.error(e.errors);
|
||||
}
|
||||
}
|
||||
|
||||
environment.finish();
|
||||
finish();
|
||||
}
|
||||
|
||||
public GlProgram getPipelineProgram(VertexType vertexType, StructType<?> structType, ContextShader contextShader, PipelineShader pipelineShader) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
public GlProgram getPipelineProgram(VertexType vertexType, StructType<?> structType, ContextShader contextShader, SimplePipeline pipelineShader) {
|
||||
return pipelinePrograms.get(new PipelineContext(vertexType, structType, contextShader, pipelineShader));
|
||||
}
|
||||
|
||||
|
@ -82,48 +121,110 @@ public class FlwCompiler {
|
|||
var glslVersion = ctx.pipelineShader()
|
||||
.glslVersion();
|
||||
|
||||
var vertex = new ShaderContext(glslVersion, ShaderType.VERTEX, ctx.getVertexComponents());
|
||||
var fragment = new ShaderContext(glslVersion, ShaderType.FRAGMENT, ctx.getFragmentComponents());
|
||||
var vertex = compileShader(glslVersion, ShaderType.VERTEX, getVertexComponents(ctx));
|
||||
var fragment = compileShader(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(ctx));
|
||||
|
||||
return ctx.contextShader()
|
||||
.factory()
|
||||
.create(new ProgramAssembler().attachShader(shaderCompiler.get(vertex))
|
||||
.attachShader(shaderCompiler.get(fragment))
|
||||
.create(new ProgramAssembler().attachShader(vertex)
|
||||
.attachShader(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());
|
||||
return new GlProgram(new ProgramAssembler().attachShader(compileShader(GLSLVersion.V460, ShaderType.COMPUTE, getComputeComponents(structType)))
|
||||
.link());
|
||||
}
|
||||
|
||||
ImmutableList<SourceComponent> getVertexComponents(PipelineContext ctx) {
|
||||
var instanceAssembly = ctx.pipelineShader()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(sources, ctx.vertexType(), ctx.structType()));
|
||||
|
||||
var layout = sources.find(ctx.vertexType()
|
||||
.getLayoutShader()
|
||||
.resourceLocation());
|
||||
var instance = sources.find(ctx.structType()
|
||||
.getInstanceShader()
|
||||
.resourceLocation());
|
||||
var context = sources.find(ctx.contextShader()
|
||||
.vertexShader()
|
||||
.resourceLocation());
|
||||
var pipeline = sources.find(ctx.pipelineShader()
|
||||
.vertex()
|
||||
.resourceLocation());
|
||||
|
||||
return ImmutableList.of(vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline);
|
||||
}
|
||||
|
||||
ImmutableList<SourceComponent> getFragmentComponents(PipelineContext ctx) {
|
||||
var context = sources.find(ctx.contextShader()
|
||||
.fragmentShader()
|
||||
.resourceLocation());
|
||||
var pipeline = sources.find(ctx.pipelineShader()
|
||||
.fragment()
|
||||
.resourceLocation());
|
||||
return ImmutableList.of(fragmentMaterialComponent, context, pipeline);
|
||||
}
|
||||
|
||||
@NotNull ImmutableList<SourceComponent> getComputeComponents(StructType<?> structType) {
|
||||
var instanceAssembly = new IndirectComponent(sources, structType);
|
||||
var instance = sources.find(structType.getInstanceShader()
|
||||
.resourceLocation());
|
||||
var pipeline = sources.find(Pipelines.Files.INDIRECT_CULL.resourceLocation());
|
||||
|
||||
return ImmutableList.of(instanceAssembly, instance, pipeline);
|
||||
}
|
||||
|
||||
protected GlShader compileShader(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList<SourceComponent> sourceComponents) {
|
||||
StringBuilder finalSource = new StringBuilder(CompileUtil.generateHeader(glslVersion, shaderType));
|
||||
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 : components) {
|
||||
included.addAll(component.included());
|
||||
|
||||
for (var include : depthFirstInclude(sourceComponents)) {
|
||||
appendFinalSource(finalSource, ctx, include);
|
||||
}
|
||||
|
||||
for (var component : sourceComponents) {
|
||||
appendFinalSource(finalSource, ctx, component);
|
||||
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);
|
||||
return new GlShader(finalSource.toString(), shaderType, names.build());
|
||||
} catch (ShaderCompilationException e) {
|
||||
throw e.withErrorLog(context);
|
||||
throw e.withErrorLog(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendFinalSource(StringBuilder finalSource, CompilationContext ctx, SourceComponent component) {
|
||||
var source = component.source();
|
||||
|
||||
if (component instanceof SourceFile file) {
|
||||
finalSource.append(ctx.sourceHeader(file));
|
||||
} else {
|
||||
finalSource.append(ctx.generatedHeader(source, component.name()
|
||||
.toString()));
|
||||
}
|
||||
|
||||
finalSource.append(source);
|
||||
}
|
||||
|
||||
protected static Set<SourceComponent> depthFirstInclude(ImmutableList<SourceComponent> root) {
|
||||
var included = new LinkedHashSet<SourceComponent>(); // linked to preserve order
|
||||
for (var component : root) {
|
||||
recursiveDepthFirstInclude(included, component);
|
||||
}
|
||||
return included;
|
||||
}
|
||||
|
||||
protected static void recursiveDepthFirstInclude(Set<SourceComponent> included, SourceComponent component) {
|
||||
for (var include : component.included()) {
|
||||
recursiveDepthFirstInclude(included, include);
|
||||
}
|
||||
included.addAll(component.included());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,29 @@
|
|||
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.Flywheel;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FragmentMaterialComponent implements SourceComponent {
|
||||
public class FragmentMaterialComponent extends MaterialAdapterComponent {
|
||||
|
||||
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 List<String> adaptedFunctions = List.of(flw_materialFragment, flw_discardPredicate, 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;
|
||||
public FragmentMaterialComponent(ShaderSources sources, List<FileResolution> sourceMaterials) {
|
||||
super(sources, sourceMaterials, flw_materialFragmentID, adaptedFunctions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return null;
|
||||
return Flywheel.rl("fragment_material_adapter");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
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 abstract class MaterialAdapterComponent implements SourceComponent {
|
||||
|
||||
// TODO: material id handling in pipeline shader
|
||||
private final GlslExpr switchArg;
|
||||
private final List<String> adaptedFunctions;
|
||||
private final List<RenamedFunctionsSourceComponent> transformedMaterials;
|
||||
|
||||
// TODO: Create builder and remove Fragment* and Vertex* classes
|
||||
public MaterialAdapterComponent(ShaderSources sources, List<FileResolution> sourceMaterials, GlslExpr switchArg, List<String> adaptedFunctions) {
|
||||
this.switchArg = switchArg;
|
||||
this.adaptedFunctions = adaptedFunctions;
|
||||
|
||||
var transformed = ImmutableList.<RenamedFunctionsSourceComponent>builder();
|
||||
|
||||
for (FileResolution fileResolution : sourceMaterials) {
|
||||
var loc = fileResolution.resourceLocation();
|
||||
var sourceFile = sources.find(loc);
|
||||
|
||||
transformed.add(new RenamedFunctionsSourceComponent(sourceFile, createAdapterMap(adaptedFunctions, loc)));
|
||||
}
|
||||
|
||||
this.transformedMaterials = transformed.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return transformedMaterials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source() {
|
||||
var builder = new GlslBuilder();
|
||||
|
||||
for (String adaptedFunction : adaptedFunctions) {
|
||||
// TODO: support different function signatures
|
||||
builder.function()
|
||||
.returnType("void")
|
||||
.name(adaptedFunction)
|
||||
.body(body -> generateAdapter(body, adaptedFunction));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void generateAdapter(GlslBuilder.BlockBuilder body, String adaptedFunction) {
|
||||
var sw = new GlslBuilder.SwitchBuilder(switchArg);
|
||||
for (int i = 0; i < transformedMaterials.size(); i++) {
|
||||
var variant = transformedMaterials.get(i)
|
||||
.replacement(adaptedFunction);
|
||||
|
||||
sw.case_(i, b -> b.eval(GlslExpr.call(variant))
|
||||
.break_());
|
||||
}
|
||||
body.add(sw.build());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static HashMap<String, String> createAdapterMap(List<String> adaptedFunctions, ResourceLocation loc) {
|
||||
HashMap<String, String> out = new HashMap<>();
|
||||
|
||||
var suffix = '_' + ResourceUtil.toSafeString(loc);
|
||||
|
||||
for (String fnName : adaptedFunctions) {
|
||||
out.put(fnName, fnName + suffix);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
|
@ -1,20 +1,9 @@
|
|||
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;
|
||||
import com.jozufozu.flywheel.core.pipeline.SimplePipeline;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
|
@ -24,42 +13,5 @@ import com.jozufozu.flywheel.core.SourceComponent;
|
|||
* @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);
|
||||
}
|
||||
SimplePipeline pipelineShader) {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class RenamedFunctionsSourceComponent implements SourceComponent {
|
||||
private final SourceComponent source;
|
||||
private final Map<String, String> replacements;
|
||||
|
||||
public RenamedFunctionsSourceComponent(SourceComponent source, String find, String replace) {
|
||||
this.source = source;
|
||||
this.replacements = Map.of(find, replace);
|
||||
}
|
||||
|
||||
public RenamedFunctionsSourceComponent(SourceComponent source, Map<String, String> replacements) {
|
||||
this.source = source;
|
||||
this.replacements = replacements;
|
||||
}
|
||||
|
||||
public String replacement(String name) {
|
||||
return replacements.getOrDefault(name, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source() {
|
||||
var source = this.source.source();
|
||||
|
||||
for (var entry : replacements.entrySet()) {
|
||||
source = source.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation name() {
|
||||
return ResourceUtil.subPath(source.name(), "_renamed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return source.included();
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
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();
|
||||
}
|
||||
}
|
|
@ -1,71 +1,27 @@
|
|||
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.ShaderSources;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.util.ResourceUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class VertexMaterialComponent implements SourceComponent {
|
||||
public class VertexMaterialComponent extends MaterialAdapterComponent {
|
||||
|
||||
private static final String flw_materialVertex = "flw_materialVertex";
|
||||
private static final List<String> adaptedFunctions = List.of(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();
|
||||
public VertexMaterialComponent(ShaderSources sources, List<FileResolution> sourceMaterials) {
|
||||
super(sources, sourceMaterials, flw_materialVertexID, adaptedFunctions);
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,15 @@ package com.jozufozu.flywheel.backend.instancing.indirect;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.api.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.Pipelines;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.layout.LayoutItem;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.core.source.ShaderSources;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslExpr;
|
||||
|
||||
|
@ -19,14 +23,20 @@ public class IndirectComponent implements SourceComponent {
|
|||
private static final GlslExpr.Variable UNPACKING_VARIABLE = GlslExpr.variable(UNPACK_ARG);
|
||||
|
||||
private final List<LayoutItem> layoutItems;
|
||||
private final ImmutableList<SourceFile> included;
|
||||
|
||||
public IndirectComponent(List<LayoutItem> layoutItems) {
|
||||
this.layoutItems = layoutItems;
|
||||
public IndirectComponent(Pipeline.InstanceAssemblerContext ctx) {
|
||||
this(ctx.sources(), ctx.structType());
|
||||
}
|
||||
|
||||
public IndirectComponent(ShaderSources sources, StructType<?> structType) {
|
||||
this.layoutItems = structType.getLayout().layoutItems;
|
||||
included = ImmutableList.of(sources.find(Pipelines.Files.UTIL_TYPES.resourceLocation()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return List.of(Components.UTIL_TYPES.getFile());
|
||||
return included;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,9 +45,8 @@ public class IndirectComponent implements SourceComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String source(CompilationContext ctx) {
|
||||
var generated = generateIndirect("IndirectStruct");
|
||||
return ctx.generatedHeader(generated, name().toString()) + generated;
|
||||
public String source() {
|
||||
return generateIndirect("IndirectStruct");
|
||||
}
|
||||
|
||||
public String generateIndirect(String structName) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
|||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.instancing.compile.FlwCompiler;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.Pipelines;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
|
||||
public class IndirectCullingGroup<T extends InstancedPart> {
|
||||
|
@ -64,7 +65,7 @@ public class IndirectCullingGroup<T extends InstancedPart> {
|
|||
setupVertexArray();
|
||||
|
||||
compute = FlwCompiler.INSTANCE.getCullingProgram(structType);
|
||||
draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, Components.WORLD, Components.INDIRECT);
|
||||
draw = FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, Components.WORLD, Pipelines.INDIRECT);
|
||||
}
|
||||
|
||||
private void setupVertexArray() {
|
||||
|
|
|
@ -5,9 +5,9 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.layout.LayoutItem;
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslBuilder;
|
||||
import com.jozufozu.flywheel.core.source.generate.GlslExpr;
|
||||
|
||||
|
@ -19,9 +19,12 @@ public class InstancedArraysComponent implements SourceComponent {
|
|||
private final List<LayoutItem> layoutItems;
|
||||
private final int baseIndex;
|
||||
|
||||
public InstancedArraysComponent(List<LayoutItem> layoutItems, int baseIndex) {
|
||||
this.layoutItems = layoutItems;
|
||||
this.baseIndex = baseIndex;
|
||||
public InstancedArraysComponent(Pipeline.InstanceAssemblerContext ctx) {
|
||||
this.layoutItems = ctx.structType()
|
||||
.getLayout().layoutItems;
|
||||
this.baseIndex = ctx.vertexType()
|
||||
.getLayout()
|
||||
.getAttributeCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,9 +33,8 @@ public class InstancedArraysComponent implements SourceComponent {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String source(CompilationContext ctx) {
|
||||
var generated = generateInstancedArrays("Instance");
|
||||
return ctx.generatedHeader(generated, name().toString()) + generated;
|
||||
public String source() {
|
||||
return generateInstancedArrays("Instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,7 +18,7 @@ import com.jozufozu.flywheel.backend.instancing.Engine;
|
|||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
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.Pipelines;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
@ -123,7 +123,7 @@ public class InstancingEngine implements Engine {
|
|||
var structType = desc.instance();
|
||||
var material = desc.material();
|
||||
|
||||
FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Components.INSTANCED_ARRAYS)
|
||||
FlwCompiler.INSTANCE.getPipelineProgram(vertexType, structType, context, Pipelines.INSTANCED_ARRAYS)
|
||||
.bind();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ 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;
|
||||
|
@ -17,6 +16,7 @@ import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
|||
import com.jozufozu.flywheel.backend.instancing.batching.BatchingEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.indirect.IndirectEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.core.pipeline.SimplePipeline;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
|
@ -58,7 +58,7 @@ public class BackendTypes {
|
|||
.fallback(() -> BackendTypes.BATCHING)
|
||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
|
||||
.instancedArraysSupported())
|
||||
.pipelineShader(Components.INSTANCED_ARRAYS)
|
||||
.pipelineShader(Pipelines.INSTANCED_ARRAYS)
|
||||
.register();
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ public class BackendTypes {
|
|||
.fallback(() -> BackendTypes.INSTANCING)
|
||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.getInstance()
|
||||
.supportsIndirect())
|
||||
.pipelineShader(Components.INDIRECT)
|
||||
.pipelineShader(Pipelines.INDIRECT)
|
||||
.register();
|
||||
|
||||
public static BackendType register(BackendType type) {
|
||||
|
@ -99,7 +99,7 @@ public class BackendTypes {
|
|||
}
|
||||
|
||||
|
||||
public static Collection<PipelineShader> availablePipelineShaders() {
|
||||
public static Collection<SimplePipeline> availablePipelineShaders() {
|
||||
return BACKEND_TYPES.values()
|
||||
.stream()
|
||||
.filter(BackendType::supported)
|
||||
|
|
|
@ -53,7 +53,7 @@ public class ComponentRegistry {
|
|||
|
||||
public static <T extends UniformProvider> T register(T provider) {
|
||||
return uniformProviders.register(provider.uniformShader()
|
||||
.getFileLoc(), provider);
|
||||
.resourceLocation(), provider);
|
||||
}
|
||||
|
||||
public static Collection<UniformProvider> getAllUniformProviders() {
|
||||
|
|
|
@ -4,10 +4,6 @@ import java.util.function.BiConsumer;
|
|||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.pipeline.PipelineShader;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.instancing.indirect.IndirectComponent;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysComponent;
|
||||
import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.SourceChecks;
|
||||
|
@ -31,28 +27,12 @@ public class Components {
|
|||
public static final ContextShader WORLD = ComponentRegistry.register(new ContextShader(WorldProgram::new, Files.WORLD_VERTEX, Files.WORLD_FRAGMENT));
|
||||
public static final ContextShader CRUMBLING = ComponentRegistry.register(new ContextShader(CrumblingProgram::new, Files.WORLD_VERTEX, Files.CRUMBLING_FRAGMENT));
|
||||
|
||||
public static final PipelineShader INSTANCED_ARRAYS = new PipelineShader(GLSLVersion.V420, Pipeline.INSTANCED_ARRAYS_DRAW, Pipeline.DRAW_FRAGMENT, (vertexType, structType) -> new InstancedArraysComponent(structType.getLayout().layoutItems, vertexType.getLayout()
|
||||
.getAttributeCount()));
|
||||
public static final PipelineShader INDIRECT = new PipelineShader(GLSLVersion.V460, Pipeline.INDIRECT_DRAW, Pipeline.DRAW_FRAGMENT, (vertexType, structType) -> new IndirectComponent(structType.getLayout().layoutItems));
|
||||
public static final FileResolution UTIL_TYPES = FileResolution.get(Flywheel.rl("util/types.glsl"));
|
||||
|
||||
public static void init() {
|
||||
Files.init();
|
||||
Formats.init();
|
||||
StructTypes.init();
|
||||
Materials.init();
|
||||
}
|
||||
|
||||
public static class Pipeline {
|
||||
public static final FileResolution DRAW_FRAGMENT = pipeline("pipeline/draw.frag");
|
||||
public static final FileResolution INSTANCED_ARRAYS_DRAW = pipeline("pipeline/instanced_arrays_draw.vert");
|
||||
public static final FileResolution INDIRECT_DRAW = pipeline("pipeline/indirect_draw.vert");
|
||||
public static final FileResolution INDIRECT_CULL = pipeline("pipeline/indirect_cull.glsl");
|
||||
|
||||
private static FileResolution pipeline(String name) {
|
||||
return FileResolution.get(Flywheel.rl(name))
|
||||
.validateWith(Checks.PIPELINE);
|
||||
}
|
||||
Pipelines.init();
|
||||
}
|
||||
|
||||
public static class Files {
|
||||
|
|
40
src/main/java/com/jozufozu/flywheel/core/Pipelines.java
Normal file
40
src/main/java/com/jozufozu/flywheel/core/Pipelines.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.instancing.indirect.IndirectComponent;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedArraysComponent;
|
||||
import com.jozufozu.flywheel.core.pipeline.SimplePipeline;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public class Pipelines {
|
||||
public static final SimplePipeline INSTANCED_ARRAYS = SimplePipeline.builder()
|
||||
.glslVersion(GLSLVersion.V420)
|
||||
.vertex(Files.INSTANCED_ARRAYS_DRAW)
|
||||
.fragment(Files.DRAW_FRAGMENT)
|
||||
.assemblerFactory(InstancedArraysComponent::new)
|
||||
.build();
|
||||
public static final SimplePipeline INDIRECT = SimplePipeline.builder()
|
||||
.glslVersion(GLSLVersion.V460)
|
||||
.vertex(Files.INDIRECT_DRAW)
|
||||
.fragment(Files.DRAW_FRAGMENT)
|
||||
.assemblerFactory(IndirectComponent::new)
|
||||
.build();
|
||||
|
||||
public static void init() {
|
||||
// noop
|
||||
}
|
||||
|
||||
public static class Files {
|
||||
public static final FileResolution DRAW_FRAGMENT = pipeline("pipeline/draw.frag");
|
||||
public static final FileResolution INSTANCED_ARRAYS_DRAW = pipeline("pipeline/instanced_arrays_draw.vert");
|
||||
public static final FileResolution INDIRECT_DRAW = pipeline("pipeline/indirect_draw.vert");
|
||||
public static final FileResolution INDIRECT_CULL = pipeline("pipeline/indirect_cull.glsl");
|
||||
public static final FileResolution UTIL_TYPES = FileResolution.get(Flywheel.rl("util/types.glsl"));
|
||||
|
||||
private static FileResolution pipeline(String name) {
|
||||
return FileResolution.get(Flywheel.rl(name))
|
||||
.validateWith(Components.Checks.PIPELINE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,12 @@ package com.jozufozu.flywheel.core;
|
|||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.CompilationContext;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface SourceComponent {
|
||||
Collection<? extends SourceComponent> included();
|
||||
|
||||
String source(CompilationContext ctx);
|
||||
String source();
|
||||
|
||||
ResourceLocation name();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package com.jozufozu.flywheel.core.pipeline;
|
||||
|
||||
import com.jozufozu.flywheel.api.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public final class SimplePipeline implements Pipeline {
|
||||
private final GLSLVersion glslVersion;
|
||||
private final FileResolution vertex;
|
||||
private final FileResolution fragment;
|
||||
private final InstanceAssemblerFactory factory;
|
||||
|
||||
public SimplePipeline(GLSLVersion glslVersion, FileResolution vertex, FileResolution fragment, InstanceAssemblerFactory factory) {
|
||||
this.glslVersion = glslVersion;
|
||||
this.vertex = vertex;
|
||||
this.fragment = fragment;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the source component necessary to convert a packed {@link StructType} into its shader representation.
|
||||
*
|
||||
* @return A source component defining functions that unpack a representation of the given struct type.
|
||||
*/
|
||||
@Override
|
||||
public SourceComponent assemble(InstanceAssemblerContext context) {
|
||||
return factory.apply(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GLSLVersion glslVersion() {
|
||||
return glslVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution vertex() {
|
||||
return vertex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution fragment() {
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface InstanceAssemblerFactory {
|
||||
SourceComponent apply(InstanceAssemblerContext context);
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private GLSLVersion glslVersion;
|
||||
private FileResolution vertex;
|
||||
private FileResolution fragment;
|
||||
private InstanceAssemblerFactory factory;
|
||||
|
||||
public Builder glslVersion(GLSLVersion glslVersion) {
|
||||
this.glslVersion = glslVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder vertex(FileResolution vertex) {
|
||||
this.vertex = vertex;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fragment(FileResolution fragment) {
|
||||
this.fragment = fragment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder assemblerFactory(InstanceAssemblerFactory factory) {
|
||||
this.factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimplePipeline build() {
|
||||
return new SimplePipeline(glslVersion, vertex, fragment, factory);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ public class CompilationContext {
|
|||
private int generatedLines = 0;
|
||||
|
||||
|
||||
String sourceHeader(SourceFile sourceFile) {
|
||||
public String sourceHeader(SourceFile sourceFile) {
|
||||
return "#line " + 0 + ' ' + getOrCreateFileID(sourceFile) + " // " + sourceFile.name + '\n';
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,6 @@ public class FileResolution {
|
|||
private final ResourceLocation fileLoc;
|
||||
private final boolean weak;
|
||||
|
||||
private SourceFile file;
|
||||
|
||||
private FileResolution(ResourceLocation fileLoc, boolean weak) {
|
||||
this.fileLoc = fileLoc;
|
||||
this.weak = weak;
|
||||
|
@ -76,40 +74,12 @@ public class FileResolution {
|
|||
return WEAK.computeIfAbsent(file, loc -> new FileResolution(loc, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try and resolve all referenced source files, printing errors if any aren't found.
|
||||
*/
|
||||
public static void run(ErrorReporter errorReporter, SourceFinder sources) {
|
||||
for (FileResolution resolution : ALL.values()) {
|
||||
resolution.resolve(errorReporter, sources);
|
||||
}
|
||||
|
||||
for (FileResolution resolution : WEAK.values()) {
|
||||
resolution.resolve(errorReporter, sources);
|
||||
}
|
||||
|
||||
WEAK.clear();
|
||||
|
||||
tooLate = true;
|
||||
}
|
||||
|
||||
public static void checkAll(ErrorReporter errorReporter) {
|
||||
for (FileResolution resolution : ALL.values()) {
|
||||
resolution.runChecks(errorReporter);
|
||||
}
|
||||
}
|
||||
|
||||
private void resolve(ErrorReporter errorReporter, SourceFinder sources) {
|
||||
file = sources.findSource(fileLoc);
|
||||
|
||||
if (file == null) {
|
||||
reportMissing(errorReporter);
|
||||
}
|
||||
|
||||
// Let the GC do its thing
|
||||
neededAt.clear();
|
||||
}
|
||||
|
||||
private void reportMissing(ErrorReporter errorReporter) {
|
||||
ErrorBuilder builder = errorReporter.error(String.format("could not find source for file %s", fileLoc));
|
||||
for (Span location : neededAt) {
|
||||
|
@ -119,22 +89,15 @@ public class FileResolution {
|
|||
}
|
||||
|
||||
private void runChecks(ErrorReporter errorReporter) {
|
||||
for (var check : checks) {
|
||||
check.accept(errorReporter, file);
|
||||
}
|
||||
// for (var check : checks) {
|
||||
// check.accept(errorReporter, file);
|
||||
// }
|
||||
}
|
||||
|
||||
public ResourceLocation getFileLoc() {
|
||||
public ResourceLocation resourceLocation() {
|
||||
return fileLoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Non-null if this file is resolved because there would have been a crash otherwise.
|
||||
* @return The file that this resolution resolves to.
|
||||
*/
|
||||
public SourceFile getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public boolean isWeak() {
|
||||
return weak;
|
||||
|
|
|
@ -5,4 +5,8 @@ public class ShaderLoadingException extends RuntimeException {
|
|||
public ShaderLoadingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ShaderLoadingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
|
@ -15,72 +16,66 @@ import com.jozufozu.flywheel.util.ResourceUtil;
|
|||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.Resource;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
|
||||
/**
|
||||
* The main object for loading and parsing source files.
|
||||
*/
|
||||
public class ShaderSources implements SourceFinder {
|
||||
public class ShaderSources {
|
||||
public static final String SHADER_DIR = "flywheel/";
|
||||
public static final ArrayList<String> EXTENSIONS = Lists.newArrayList(".vert", ".vsh", ".frag", ".fsh", ".glsl");
|
||||
|
||||
private final Map<ResourceLocation, SourceFile> shaderSources = new HashMap<>();
|
||||
private final Map<ResourceLocation, SourceFile> cache = new HashMap<>();
|
||||
|
||||
public final Index index;
|
||||
/**
|
||||
* Tracks
|
||||
*/
|
||||
private final Deque<ResourceLocation> findStack = new ArrayDeque<>();
|
||||
|
||||
public final long loadTimeNs;
|
||||
public final long indexTimeNs;
|
||||
public final long totalTimeNs;
|
||||
private final ResourceManager manager;
|
||||
private final ErrorReporter errorReporter;
|
||||
|
||||
public ShaderSources(ErrorReporter errorReporter, ResourceManager manager) {
|
||||
long loadStart = System.nanoTime();
|
||||
|
||||
for (ResourceLocation location : getValidShaderFiles(manager)) {
|
||||
try (Resource resource = manager.getResource(location)) {
|
||||
String source = StringUtil.readToString(resource.getInputStream());
|
||||
|
||||
ResourceLocation name = ResourceUtil.removePrefixUnchecked(location, SHADER_DIR);
|
||||
|
||||
shaderSources.put(name, new SourceFile(errorReporter, this, name, source));
|
||||
} catch (IOException e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
long loadEnd = System.nanoTime();
|
||||
|
||||
long indexStart = System.nanoTime();
|
||||
index = new Index(shaderSources);
|
||||
long indexEnd = System.nanoTime();
|
||||
|
||||
loadTimeNs = loadEnd - loadStart;
|
||||
indexTimeNs = indexEnd - indexStart;
|
||||
totalTimeNs = indexEnd - loadStart;
|
||||
this.errorReporter = errorReporter;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
public void postResolve() {
|
||||
for (SourceFile file : shaderSources.values()) {
|
||||
file.postResolve();
|
||||
@Nonnull
|
||||
public SourceFile find(ResourceLocation location) {
|
||||
if (findStack.contains(location)) {
|
||||
generateRecursiveImportException(location);
|
||||
}
|
||||
findStack.add(location);
|
||||
// Can't use computeIfAbsent because mutual recursion causes ConcurrentModificationExceptions
|
||||
var out = cache.get(location);
|
||||
if (out == null) {
|
||||
out = load(location);
|
||||
cache.put(location, out);
|
||||
}
|
||||
findStack.pop();
|
||||
return out;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private SourceFile load(ResourceLocation loc) {
|
||||
try {
|
||||
var resource = manager.getResource(ResourceUtil.prefixed(SHADER_DIR, loc));
|
||||
|
||||
var sourceString = StringUtil.readToString(resource.getInputStream());
|
||||
|
||||
return new SourceFile(this, loc, sourceString);
|
||||
} catch (IOException ioException) {
|
||||
throw new ShaderLoadingException("Could not load shader " + loc, ioException);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public SourceFile findSource(ResourceLocation name) {
|
||||
return shaderSources.get(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Collection<ResourceLocation> getValidShaderFiles(ResourceManager manager) {
|
||||
return manager.listResources(SHADER_DIR, s -> {
|
||||
for (String ext : EXTENSIONS) {
|
||||
if (s.endsWith(ext)) return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public String getLoadTime() {
|
||||
return StringUtil.formatTime(totalTimeNs);
|
||||
private void generateRecursiveImportException(ResourceLocation location) {
|
||||
findStack.add(location);
|
||||
String path = findStack.stream()
|
||||
.dropWhile(l -> !l.equals(location))
|
||||
.map(ResourceLocation::toString)
|
||||
.collect(Collectors.joining(" -> "));
|
||||
findStack.clear();
|
||||
throw new ShaderLoadingException("recursive import: " + path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
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.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.parse.Import;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderField;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
|
@ -37,9 +32,8 @@ public class SourceFile implements SourceComponent {
|
|||
public final ResourceLocation name;
|
||||
|
||||
public final ShaderSources parent;
|
||||
public final String source;
|
||||
|
||||
public final SourceLines lines;
|
||||
public final SourceLines source;
|
||||
|
||||
/**
|
||||
* Function lookup by name.
|
||||
|
@ -57,30 +51,45 @@ public class SourceFile implements SourceComponent {
|
|||
public final ImmutableList<Import> imports;
|
||||
public final ImmutableMap<String, ShaderField> fields;
|
||||
|
||||
// POST-RESOLUTION
|
||||
public List<SourceFile> flattenedImports;
|
||||
public final List<SourceFile> included;
|
||||
|
||||
public SourceFile(ErrorReporter errorReporter, ShaderSources parent, ResourceLocation name, String source) {
|
||||
this.parent = parent;
|
||||
public SourceFile(ShaderSources sourceFinder, ResourceLocation name, String source) {
|
||||
this.parent = sourceFinder;
|
||||
this.name = name;
|
||||
this.source = source;
|
||||
|
||||
this.lines = new SourceLines(source);
|
||||
this.source = new SourceLines(source);
|
||||
|
||||
this.imports = parseImports(errorReporter);
|
||||
this.functions = parseFunctions();
|
||||
this.structs = parseStructs();
|
||||
this.fields = parseFields();
|
||||
this.imports = parseImports(source);
|
||||
this.functions = parseFunctions(source);
|
||||
this.structs = parseStructs(source);
|
||||
this.fields = parseFields(source);
|
||||
|
||||
this.included = imports.stream()
|
||||
.map(i -> i.file)
|
||||
.map(Span::toString)
|
||||
.distinct()
|
||||
.<SourceFile>mapMulti((file, sink) -> {
|
||||
try {
|
||||
var loc = new ResourceLocation(file);
|
||||
var sourceFile = sourceFinder.find(loc);
|
||||
|
||||
if (sourceFile != null) {
|
||||
sink.accept(sourceFile);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends SourceComponent> included() {
|
||||
return flattenedImports;
|
||||
return included;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String source(CompilationContext ctx) {
|
||||
return ctx.sourceHeader(this) + this.genFinalSource();
|
||||
public String source() {
|
||||
return this.genFinalSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,52 +97,23 @@ public class SourceFile implements SourceComponent {
|
|||
return name;
|
||||
}
|
||||
|
||||
public void postResolve() {
|
||||
this.flattenImports();
|
||||
}
|
||||
|
||||
private void flattenImports() {
|
||||
// somebody #used us and got resolved before we did
|
||||
if (this.flattenedImports != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.imports.isEmpty()) {
|
||||
this.flattenedImports = Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList<SourceFile> flat = new ArrayList<>(this.imports.size());
|
||||
|
||||
for (Import include : this.imports) {
|
||||
SourceFile file = include.resolution.getFile();
|
||||
|
||||
file.flattenImports();
|
||||
|
||||
flat.addAll(file.flattenedImports);
|
||||
flat.add(file);
|
||||
}
|
||||
|
||||
this.flattenedImports = flat.stream()
|
||||
.distinct()
|
||||
.toList();
|
||||
}
|
||||
|
||||
public Span getLineSpan(int line) {
|
||||
int begin = lines.getLineStart(line);
|
||||
int end = begin + lines.getLine(line).length();
|
||||
return new StringSpan(this, lines.getCharPos(begin), lines.getCharPos(end));
|
||||
public Span getLineSpan(int lineNo) {
|
||||
int begin = source.getLineStart(lineNo);
|
||||
int end = begin + source.getLine(lineNo)
|
||||
.length();
|
||||
return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end));
|
||||
}
|
||||
|
||||
public Span getLineSpanNoWhitespace(int line) {
|
||||
int begin = lines.getLineStart(line);
|
||||
int end = begin + lines.getLine(line).length();
|
||||
int begin = source.getLineStart(line);
|
||||
int end = begin + source.getLine(line)
|
||||
.length();
|
||||
|
||||
while (begin < end && Character.isWhitespace(source.charAt(begin))) {
|
||||
begin++;
|
||||
}
|
||||
|
||||
return new StringSpan(this, lines.getCharPos(begin), lines.getCharPos(end));
|
||||
return new StringSpan(this, source.getCharPos(begin), source.getCharPos(end));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -147,7 +127,7 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
if (struct != null) return Optional.of(struct);
|
||||
|
||||
for (var include : flattenedImports) {
|
||||
for (var include : included) {
|
||||
var external = include.structs.get(name);
|
||||
|
||||
if (external != null) {
|
||||
|
@ -169,7 +149,7 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
if (local != null) return Optional.of(local);
|
||||
|
||||
for (var include : flattenedImports) {
|
||||
for (var include : included) {
|
||||
var external = include.functions.get(name);
|
||||
|
||||
if (external != null) {
|
||||
|
@ -185,10 +165,10 @@ public class SourceFile implements SourceComponent {
|
|||
}
|
||||
|
||||
public String printSource() {
|
||||
return "Source for shader '" + name + "':\n" + lines.printLinesWithNumbers();
|
||||
return "Source for shader '" + name + "':\n" + source.printLinesWithNumbers();
|
||||
}
|
||||
|
||||
private CharSequence genFinalSource() {
|
||||
private String genFinalSource() {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
int lastEnd = 0;
|
||||
|
@ -203,13 +183,50 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
out.append(this.source, lastEnd, this.source.length());
|
||||
|
||||
return out;
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// SourceFiles are only equal by reference.
|
||||
return this == o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan the source for {@code #use "..."} directives.
|
||||
* Records the contents of the directive into an {@link Import} object, and marks the directive for elision.
|
||||
*/
|
||||
private ImmutableList<Import> parseImports(String source) {
|
||||
Matcher uses = Import.PATTERN.matcher(source);
|
||||
|
||||
var imports = ImmutableList.<Import>builder();
|
||||
|
||||
while (uses.find()) {
|
||||
Span use = Span.fromMatcher(this, uses);
|
||||
Span file = Span.fromMatcher(this, uses, 1);
|
||||
|
||||
imports.add(new Import(use, file));
|
||||
}
|
||||
|
||||
return imports.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan the source for function definitions and "parse" them into objects that contain properties of the function.
|
||||
*/
|
||||
private ImmutableMap<String, ShaderFunction> parseFunctions() {
|
||||
private ImmutableMap<String, ShaderFunction> parseFunctions(String source) {
|
||||
Matcher matcher = ShaderFunction.PATTERN.matcher(source);
|
||||
|
||||
Map<String, ShaderFunction> functions = new HashMap<>();
|
||||
|
@ -220,7 +237,7 @@ public class SourceFile implements SourceComponent {
|
|||
Span args = Span.fromMatcher(this, matcher, 3);
|
||||
|
||||
int blockStart = matcher.end();
|
||||
int blockEnd = findEndOfBlock(blockStart);
|
||||
int blockEnd = findEndOfBlock(source, blockStart);
|
||||
|
||||
Span self;
|
||||
Span body;
|
||||
|
@ -243,7 +260,7 @@ public class SourceFile implements SourceComponent {
|
|||
/**
|
||||
* Scan the source for function definitions and "parse" them into objects that contain properties of the function.
|
||||
*/
|
||||
private ImmutableMap<String, ShaderStruct> parseStructs() {
|
||||
private ImmutableMap<String, ShaderStruct> parseStructs(String source) {
|
||||
Matcher matcher = ShaderStruct.PATTERN.matcher(source);
|
||||
|
||||
ImmutableMap.Builder<String, ShaderStruct> structs = ImmutableMap.builder();
|
||||
|
@ -263,7 +280,7 @@ public class SourceFile implements SourceComponent {
|
|||
/**
|
||||
* Scan the source for function definitions and "parse" them into objects that contain properties of the function.
|
||||
*/
|
||||
private ImmutableMap<String, ShaderField> parseFields() {
|
||||
private ImmutableMap<String, ShaderField> parseFields(String source) {
|
||||
Matcher matcher = ShaderField.PATTERN.matcher(source);
|
||||
|
||||
ImmutableMap.Builder<String, ShaderField> fields = ImmutableMap.builder();
|
||||
|
@ -280,36 +297,10 @@ public class SourceFile implements SourceComponent {
|
|||
return fields.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the source for {@code #use "..."} directives.
|
||||
* Records the contents of the directive into an {@link Import} object, and marks the directive for elision.
|
||||
*/
|
||||
private ImmutableList<Import> parseImports(ErrorReporter errorReporter) {
|
||||
Matcher uses = Import.PATTERN.matcher(source);
|
||||
|
||||
Set<String> importedFiles = new HashSet<>();
|
||||
var imports = ImmutableList.<Import>builder();
|
||||
|
||||
while (uses.find()) {
|
||||
Span use = Span.fromMatcher(this, uses);
|
||||
Span file = Span.fromMatcher(this, uses, 1);
|
||||
|
||||
String fileName = file.get();
|
||||
if (importedFiles.add(fileName)) {
|
||||
var checked = Import.create(errorReporter, use, file);
|
||||
if (checked != null) {
|
||||
imports.add(checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imports.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given the position of an opening brace, scans through the source for a paired closing brace.
|
||||
*/
|
||||
private int findEndOfBlock(int start) {
|
||||
private static int findEndOfBlock(String source, int start) {
|
||||
int blockDepth = 0;
|
||||
for (int i = start + 1; i < source.length(); i++) {
|
||||
char ch = source.charAt(i);
|
||||
|
@ -324,20 +315,4 @@ public class SourceFile implements SourceComponent {
|
|||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
// SourceFiles are only equal by reference.
|
||||
return this == o;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return System.identityHashCode(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.source;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* A minimal source file lookup function.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SourceFinder {
|
||||
|
||||
@Nullable
|
||||
SourceFile findSource(ResourceLocation name);
|
||||
}
|
|
@ -3,6 +3,8 @@ package com.jozufozu.flywheel.core.source;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.core.source.span.CharPos;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
@ -10,7 +12,7 @@ import com.jozufozu.flywheel.util.StringUtil;
|
|||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
||||
public class SourceLines {
|
||||
public class SourceLines implements CharSequence {
|
||||
|
||||
private static final Pattern newLine = Pattern.compile("(\\r\\n|\\r|\\n)");
|
||||
|
||||
|
@ -23,10 +25,12 @@ public class SourceLines {
|
|||
* 0-indexed line lookup
|
||||
*/
|
||||
private final ImmutableList<String> lines;
|
||||
public final String raw;
|
||||
|
||||
public SourceLines(String source) {
|
||||
this.lineStarts = createLineLookup(source);
|
||||
this.lines = getLines(source, lineStarts);
|
||||
public SourceLines(String raw) {
|
||||
this.raw = raw;
|
||||
this.lineStarts = createLineLookup(raw);
|
||||
this.lines = getLines(raw, lineStarts);
|
||||
}
|
||||
|
||||
public int getLineCount() {
|
||||
|
@ -38,7 +42,6 @@ public class SourceLines {
|
|||
}
|
||||
|
||||
public int getLineStart(int lineNo) {
|
||||
|
||||
return lineStarts.getInt(lineNo);
|
||||
}
|
||||
|
||||
|
@ -99,4 +102,23 @@ public class SourceLines {
|
|||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return raw.subSequence(start, end);
|
||||
}
|
||||
|
||||
public char charAt(int i) {
|
||||
return raw.charAt(i);
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return raw.length();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public class ErrorBuilder {
|
|||
public ErrorBuilder pointAt(Span span, int ctxLines) {
|
||||
|
||||
if (span.lines() == 1) {
|
||||
SourceLines lines = span.getSourceFile().lines;
|
||||
SourceLines lines = span.getSourceFile().source;
|
||||
|
||||
int spanLine = span.firstLine();
|
||||
|
||||
|
|
|
@ -2,15 +2,11 @@ package com.jozufozu.flywheel.core.source.error;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.core.source.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderFunction;
|
||||
import com.jozufozu.flywheel.core.source.parse.ShaderStruct;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
import com.jozufozu.flywheel.util.FlwUtil;
|
||||
|
||||
|
@ -23,15 +19,15 @@ public class ErrorReporter {
|
|||
}
|
||||
|
||||
public void generateMissingStruct(SourceFile file, Span vertexName, CharSequence msg, CharSequence hint) {
|
||||
Optional<Span> span = file.parent.index.getStructDefinitionsMatching(vertexName)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(ShaderStruct::getName);
|
||||
|
||||
this.error(msg)
|
||||
.pointAtFile(file)
|
||||
.pointAt(vertexName, 1)
|
||||
.hintIncludeFor(span.orElse(null), hint);
|
||||
// Optional<Span> span = file.parent.index.getStructDefinitionsMatching(vertexName)
|
||||
// .stream()
|
||||
// .findFirst()
|
||||
// .map(ShaderStruct::getName);
|
||||
//
|
||||
// this.error(msg)
|
||||
// .pointAtFile(file)
|
||||
// .pointAt(vertexName, 1)
|
||||
// .hintIncludeFor(span.orElse(null), hint);
|
||||
}
|
||||
|
||||
public void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg) {
|
||||
|
@ -39,14 +35,14 @@ public class ErrorReporter {
|
|||
}
|
||||
|
||||
public void generateMissingFunction(SourceFile file, CharSequence functionName, CharSequence msg, CharSequence hint) {
|
||||
Optional<Span> span = file.parent.index.getFunctionDefinitionsMatching(functionName)
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(ShaderFunction::getName);
|
||||
|
||||
this.error(msg)
|
||||
.pointAtFile(file)
|
||||
.hintIncludeFor(span.orElse(null), hint);
|
||||
// Optional<Span> span = file.parent.index.getFunctionDefinitionsMatching(functionName)
|
||||
// .stream()
|
||||
// .findFirst()
|
||||
// .map(ShaderFunction::getName);
|
||||
//
|
||||
// this.error(msg)
|
||||
// .pointAtFile(file)
|
||||
// .hintIncludeFor(span.orElse(null), hint);
|
||||
}
|
||||
|
||||
public ErrorBuilder generateFunctionArgumentCountError(String name, int requiredArguments, Span span) {
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.source.parse;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
public abstract class AbstractShaderElement {
|
||||
|
||||
public final Span self;
|
||||
|
||||
public AbstractShaderElement(Span self) {
|
||||
this.self = self;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,52 +1,19 @@
|
|||
package com.jozufozu.flywheel.core.source.parse;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
import com.jozufozu.flywheel.core.source.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class Import extends AbstractShaderElement {
|
||||
public class Import {
|
||||
|
||||
public static final Pattern PATTERN = Pattern.compile("^\\s*#\\s*use\\s+\"(.*)\"", Pattern.MULTILINE);
|
||||
|
||||
public final FileResolution resolution;
|
||||
public final Span self;
|
||||
public final Span file;
|
||||
|
||||
protected Import(Span self, FileResolution resolution, Span file) {
|
||||
super(self);
|
||||
this.resolution = resolution.addSpan(file);
|
||||
public Import(Span self, Span file) {
|
||||
this.self = self;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Import create(ErrorReporter errorReporter, Span self, Span file) {
|
||||
ResourceLocation fileLocation;
|
||||
try {
|
||||
fileLocation = new ResourceLocation(file.get());
|
||||
} catch (ResourceLocationException e) {
|
||||
errorReporter.generateSpanError(file, "malformed source location");
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Import(self, FileResolution.weak(fileLocation), file);
|
||||
}
|
||||
|
||||
public Optional<SourceFile> getOptional() {
|
||||
return Optional.ofNullable(resolution.getFile());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SourceFile getFile() {
|
||||
return resolution.getFile();
|
||||
}
|
||||
|
||||
public ResourceLocation getFileLoc() {
|
||||
return resolution.getFileLoc();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,17 @@ import org.jetbrains.annotations.Nullable;
|
|||
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
public class ShaderField extends AbstractShaderElement {
|
||||
public class ShaderField {
|
||||
public static final Pattern PATTERN = Pattern.compile("layout\\s*\\(location\\s*=\\s*(\\d+)\\)\\s+(in|out)\\s+([\\w\\d]+)\\s+" + "([\\w\\d]+)");
|
||||
|
||||
public final Span location;
|
||||
public final @Nullable Decoration decoration;
|
||||
public final Span type;
|
||||
public final Span name;
|
||||
public final Span self;
|
||||
|
||||
public ShaderField(Span self, Span location, Span inOut, Span type, Span name) {
|
||||
super(self);
|
||||
this.self = self;
|
||||
|
||||
this.location = location;
|
||||
this.decoration = Decoration.fromSpan(inOut);
|
||||
|
|
|
@ -7,13 +7,14 @@ import java.util.stream.Collectors;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
public class ShaderFunction extends AbstractShaderElement {
|
||||
public class ShaderFunction {
|
||||
|
||||
// https://regexr.com/60n3d
|
||||
public static final Pattern PATTERN = Pattern.compile("(\\w+)\\s+(\\w+)\\s*\\(([\\w,\\s]*)\\)\\s*\\{");
|
||||
|
||||
public static final Pattern argument = Pattern.compile("(?:(inout|in|out) )?(\\w+)\\s+(\\w+)");
|
||||
public static final Pattern assignment = Pattern.compile("(\\w+)\\s*=");
|
||||
public final Span self;
|
||||
|
||||
private final Span type;
|
||||
private final Span name;
|
||||
|
@ -23,7 +24,7 @@ public class ShaderFunction extends AbstractShaderElement {
|
|||
private final ImmutableList<ShaderVariable> parameters;
|
||||
|
||||
public ShaderFunction(Span self, Span type, Span name, Span args, Span body) {
|
||||
super(self);
|
||||
this.self = self;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.args = args;
|
||||
|
|
|
@ -7,19 +7,20 @@ import com.google.common.collect.ImmutableList;
|
|||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
public class ShaderStruct extends AbstractShaderElement {
|
||||
public class ShaderStruct {
|
||||
|
||||
// https://regexr.com/61rpe
|
||||
public static final Pattern PATTERN = Pattern.compile("struct\\s+([\\w\\d]*)\\s*\\{([\\w\\d\\s,;]*)}\\s*;\\s");
|
||||
|
||||
public final Span name;
|
||||
public final Span body;
|
||||
public final Span self;
|
||||
|
||||
private final ImmutableList<StructField> fields;
|
||||
private final ImmutableMap<String, Span> fields2Types;
|
||||
|
||||
public ShaderStruct(Span self, Span name, Span body) {
|
||||
super(self);
|
||||
this.self = self;
|
||||
this.name = name;
|
||||
this.body = body;
|
||||
this.fields = parseFields();
|
||||
|
|
|
@ -2,15 +2,16 @@ package com.jozufozu.flywheel.core.source.parse;
|
|||
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
public class ShaderVariable extends AbstractShaderElement {
|
||||
public class ShaderVariable {
|
||||
|
||||
public final Span qualifierSpan;
|
||||
public final Span type;
|
||||
public final Span name;
|
||||
public final Qualifier qualifier;
|
||||
public final Span self;
|
||||
|
||||
public ShaderVariable(Span self, Span qualifier, Span type, Span name) {
|
||||
super(self);
|
||||
this.self = self;
|
||||
this.qualifierSpan = qualifier;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
|
|
|
@ -4,14 +4,15 @@ import java.util.regex.Pattern;
|
|||
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
|
||||
public class StructField extends AbstractShaderElement {
|
||||
public class StructField {
|
||||
public static final Pattern fieldPattern = Pattern.compile("(\\S+)\\s*(\\S+);");
|
||||
public final Span self;
|
||||
|
||||
public Span type;
|
||||
public Span name;
|
||||
|
||||
public StructField(Span self, Span type, Span name) {
|
||||
super(self);
|
||||
this.self = self;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public abstract class Span implements CharSequence, Comparable<Span> {
|
|||
protected final CharPos end;
|
||||
|
||||
public Span(SourceFile in, int start, int end) {
|
||||
this(in, in.lines.getCharPos(start), in.lines.getCharPos(end));
|
||||
this(in, in.source.getCharPos(start), in.source.getCharPos(end));
|
||||
}
|
||||
|
||||
public Span(SourceFile in, CharPos start, CharPos end) {
|
||||
|
|
|
@ -19,8 +19,7 @@ public class StringSpan extends Span {
|
|||
|
||||
@Override
|
||||
public String get() {
|
||||
return in.source
|
||||
.substring(start.pos(), end.pos());
|
||||
return in.source.raw.substring(start.pos(), end.pos());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,4 +27,9 @@ public class ResourceUtil {
|
|||
return UNSAFE_CHARS.matcher(rl.toString())
|
||||
.replaceAll("_");
|
||||
}
|
||||
|
||||
public static ResourceLocation prefixed(String basePath, ResourceLocation resourceLocation) {
|
||||
String path = resourceLocation.getPath();
|
||||
return new ResourceLocation(resourceLocation.getNamespace(), basePath + path);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ import java.text.NumberFormat;
|
|||
import java.util.Arrays;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.backend.memory.FlwMemoryTracker;
|
||||
|
@ -65,7 +67,8 @@ public class StringUtil {
|
|||
return value.substring(0, len);
|
||||
}
|
||||
|
||||
public static String readToString(InputStream is) {
|
||||
@Nonnull
|
||||
public static String readToString(InputStream is) throws IOException {
|
||||
ByteBuffer bytebuffer = null;
|
||||
|
||||
try {
|
||||
|
@ -73,17 +76,14 @@ public class StringUtil {
|
|||
int i = bytebuffer.position();
|
||||
((Buffer) bytebuffer).rewind();
|
||||
return MemoryUtil.memASCII(bytebuffer, i);
|
||||
} catch (IOException ignored) {
|
||||
//
|
||||
} finally {
|
||||
if (bytebuffer != null) {
|
||||
FlwMemoryTracker.freeBuffer(bytebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ByteBuffer readToBuffer(InputStream is) throws IOException {
|
||||
if (is instanceof FileInputStream fileinputstream) {
|
||||
return readFileInputStream(fileinputstream);
|
||||
|
@ -92,6 +92,7 @@ public class StringUtil {
|
|||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static ByteBuffer readInputStream(InputStream is) throws IOException {
|
||||
ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer(8192);
|
||||
ReadableByteChannel readablebytechannel = Channels.newChannel(is);
|
||||
|
@ -104,6 +105,7 @@ public class StringUtil {
|
|||
return bytebuffer;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private static ByteBuffer readFileInputStream(FileInputStream fileinputstream) throws IOException {
|
||||
FileChannel filechannel = fileinputstream.getChannel();
|
||||
ByteBuffer bytebuffer = FlwMemoryTracker.mallocBuffer((int) filechannel.size() + 1);
|
||||
|
|
Loading…
Reference in a new issue