mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Finally have time off
- Attempt at componentizing ShaderCompiler, starting with Includer - Begin refactoring uniform providers - Context as an interface - Separate ContextSet objects for Pipeline shaders and Culling shaders - Inline ProgramAssembler - Replace StringUtil#trimEnd with String#stripTrailing - Add StringUtil#trimPrefix and #trimSuffix
This commit is contained in:
parent
ef568d22f7
commit
9a746f700d
26 changed files with 437 additions and 221 deletions
12
src/main/java/com/jozufozu/flywheel/api/context/Context.java
Normal file
12
src/main/java/com/jozufozu/flywheel/api/context/Context.java
Normal file
|
@ -0,0 +1,12 @@
|
|||
package com.jozufozu.flywheel.api.context;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public interface Context {
|
||||
void setup(GlProgram program);
|
||||
|
||||
FileResolution vertexShader();
|
||||
|
||||
FileResolution fragmentShader();
|
||||
}
|
|
@ -3,6 +3,20 @@ package com.jozufozu.flywheel.api.context;
|
|||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
|
||||
public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader, FileResolution fragmentShader) {
|
||||
public record ContextShader(GlProgram.Factory factory, FileResolution vertexShader,
|
||||
FileResolution fragmentShader) implements Context {
|
||||
@Override
|
||||
public void setup(GlProgram program) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution vertexShader() {
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileResolution fragmentShader() {
|
||||
return fragmentShader;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,16 @@ public interface UniformProvider {
|
|||
|
||||
FileResolution uniformShader();
|
||||
|
||||
ActiveUniformProvider activate(long ptr, Notifier notifier);
|
||||
ActiveUniformProvider activate(long ptr);
|
||||
|
||||
interface ActiveUniformProvider {
|
||||
void delete();
|
||||
|
||||
void poll();
|
||||
}
|
||||
|
||||
interface Notifier {
|
||||
void signalChanged();
|
||||
/**
|
||||
* Poll the provider for changes.
|
||||
*
|
||||
* @return {@code true} if the provider updated its backing store.
|
||||
*/
|
||||
boolean poll();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ public class GlProgram extends GlObject {
|
|||
setHandle(handle);
|
||||
}
|
||||
|
||||
// TODO: Programs bind the uniform buffers they need
|
||||
// TODO: Programs bind the uniform buffers they need, no more GlProgram inheritance
|
||||
public void bind() {
|
||||
ProgramManager.glUseProgram(handle());
|
||||
}
|
||||
|
|
|
@ -83,7 +83,8 @@ public class Compilation {
|
|||
.toString()));
|
||||
}
|
||||
|
||||
fullSource.append(source);
|
||||
fullSource.append(source)
|
||||
.append('\n');
|
||||
}
|
||||
|
||||
private String sourceHeader(SourceFile sourceFile) {
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
||||
import static org.lwjgl.opengl.GL20.GL_TRUE;
|
||||
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
|
||||
import static org.lwjgl.opengl.GL20.glGetProgrami;
|
||||
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -7,6 +13,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.core.source.SourceFile;
|
||||
|
@ -17,9 +24,7 @@ public class CompileUtil {
|
|||
public static final Pattern matType = Pattern.compile("^mat([234])(?:x([234]))?$");
|
||||
|
||||
public static String generateHeader(GLSLVersion version, ShaderType type) {
|
||||
return version.getVersionLine()
|
||||
+ type.getDefineStatement()
|
||||
+ '\n';
|
||||
return version.getVersionLine() + type.getDefineStatement() + '\n';
|
||||
}
|
||||
|
||||
public static int getElementCount(String type) {
|
||||
|
@ -53,10 +58,31 @@ public class CompileUtil {
|
|||
return 1;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String generateDebugName(SourceFile... stages) {
|
||||
return Stream.of(stages)
|
||||
.map(SourceFile::toString)
|
||||
.collect(Collectors.joining(" -> "));
|
||||
}
|
||||
@NotNull
|
||||
public static String generateDebugName(SourceFile... stages) {
|
||||
return Stream.of(stages)
|
||||
.map(SourceFile::toString)
|
||||
.collect(Collectors.joining(" -> "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the program info log for errors.
|
||||
*
|
||||
* @param handle The handle of the program to check.
|
||||
*/
|
||||
public static void checkLinkLog(int handle) {
|
||||
glLinkProgram(handle);
|
||||
|
||||
String log = glGetProgramInfoLog(handle);
|
||||
|
||||
if (!log.isEmpty()) {
|
||||
Backend.LOGGER.debug("Program link log: " + log);
|
||||
}
|
||||
|
||||
int result = glGetProgrami(handle, GL_LINK_STATUS);
|
||||
|
||||
if (result != GL_TRUE) {
|
||||
throw new RuntimeException("Shader program linking failed, see log for details");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
||||
public record CullingContext(StructType<?> structType) {
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
|
||||
public class CullingContextSet {
|
||||
static CullingContextSet create() {
|
||||
var builder = new CullingContextSet();
|
||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
builder.add(structType);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private final List<CullingContext> contexts = new ArrayList<>();
|
||||
private final List<CullingContext> contextView = Collections.unmodifiableList(contexts);
|
||||
|
||||
CullingContextSet() {
|
||||
}
|
||||
|
||||
public List<CullingContext> all() {
|
||||
return contextView;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return contexts.size();
|
||||
}
|
||||
|
||||
private void add(StructType<?> structType) {
|
||||
var ctx = new CullingContext(structType);
|
||||
|
||||
contexts.add(ctx);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import com.jozufozu.flywheel.core.source.SourceLines;
|
|||
import com.jozufozu.flywheel.core.source.error.ErrorBuilder;
|
||||
import com.jozufozu.flywheel.core.source.span.Span;
|
||||
import com.jozufozu.flywheel.util.ConsoleColors;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class FailedCompilation {
|
||||
private static final Pattern ERROR_LINE = Pattern.compile("(\\d+)\\((\\d+)\\) : (.*)");
|
||||
|
@ -49,7 +50,8 @@ public class FailedCompilation {
|
|||
if (matcher.find()) {
|
||||
int fileId = Integer.parseInt(matcher.group(1));
|
||||
int lineNo = Integer.parseInt(matcher.group(2));
|
||||
var msg = matcher.group(3);
|
||||
var msg = StringUtil.trimPrefix(matcher.group(3), "error")
|
||||
.stripLeading();
|
||||
|
||||
if (fileId == 0) {
|
||||
return interpretGeneratedError(lineNo, msg);
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import static org.lwjgl.opengl.GL20.glAttachShader;
|
||||
import static org.lwjgl.opengl.GL20.glCreateProgram;
|
||||
import static org.lwjgl.opengl.GL20.glLinkProgram;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -21,9 +25,7 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
|||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
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;
|
||||
|
@ -41,7 +43,9 @@ public class FlwCompiler {
|
|||
private final ShaderSources sources;
|
||||
private final MaterialAdapterComponent vertexMaterialComponent;
|
||||
private final MaterialAdapterComponent fragmentMaterialComponent;
|
||||
private final List<PipelineContext> pipelineContexts;
|
||||
|
||||
private final PipelineContextSet pipelineContexts;
|
||||
private final CullingContextSet cullingContexts;
|
||||
|
||||
final ShaderCompiler shaderCompiler;
|
||||
final Multimap<Set<UniformProvider>, PipelineContext> uniformProviderGroups = ArrayListMultimap.create();
|
||||
|
@ -50,7 +54,10 @@ public class FlwCompiler {
|
|||
final List<FailedCompilation> errors = new ArrayList<>();
|
||||
|
||||
public FlwCompiler(ShaderSources sources) {
|
||||
this.shaderCompiler = new ShaderCompiler(errors::add);
|
||||
this.shaderCompiler = ShaderCompiler.builder()
|
||||
.errorConsumer(errors::add)
|
||||
.build();
|
||||
|
||||
this.sources = sources;
|
||||
this.vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.materialSources(ComponentRegistry.materials.vertexSources())
|
||||
|
@ -73,21 +80,24 @@ public class FlwCompiler {
|
|||
.switchOn(GlslExpr.variable("flw_materialFragmentID"))
|
||||
.build(sources);
|
||||
|
||||
this.pipelineContexts = buildPipelineSet();
|
||||
this.pipelineContexts = PipelineContextSet.create();
|
||||
this.cullingContexts = CullingContextSet.create();
|
||||
|
||||
// TODO: analyze uniform providers and group them into sets; break up this ctor
|
||||
|
||||
for (PipelineContext context : pipelineContexts) {
|
||||
compilePipelineContext(context);
|
||||
}
|
||||
|
||||
for (StructType<?> type : ComponentRegistry.structTypes) {
|
||||
compileComputeCuller(type);
|
||||
}
|
||||
doCompilation();
|
||||
|
||||
finish();
|
||||
}
|
||||
|
||||
private void doCompilation() {
|
||||
for (var ctx : pipelineContexts.all()) {
|
||||
compilePipelineContext(ctx);
|
||||
}
|
||||
|
||||
for (var ctx : cullingContexts.all()) {
|
||||
compileComputeCuller(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
long compileEnd = System.nanoTime();
|
||||
int programCount = pipelineContexts.size() + ComponentRegistry.structTypes.size();
|
||||
|
@ -132,22 +142,31 @@ public class FlwCompiler {
|
|||
return;
|
||||
}
|
||||
|
||||
pipelinePrograms.put(ctx, ctx.contextShader()
|
||||
.factory()
|
||||
.create(new ProgramAssembler().attachShader(vertex)
|
||||
.attachShader(fragment)
|
||||
.link()));
|
||||
var glProgram = link(vertex.handle(), fragment.handle());
|
||||
ctx.contextShader()
|
||||
.setup(glProgram);
|
||||
pipelinePrograms.put(ctx, glProgram);
|
||||
}
|
||||
|
||||
private void compileComputeCuller(StructType<?> structType) {
|
||||
var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, getComputeComponents(structType));
|
||||
private void compileComputeCuller(CullingContext ctx) {
|
||||
var computeComponents = getComputeComponents(ctx.structType());
|
||||
var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, computeComponents);
|
||||
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
cullingPrograms.put(structType, new GlProgram(new ProgramAssembler().attachShader(result)
|
||||
.link()));
|
||||
cullingPrograms.put(ctx.structType(), link(result.handle()));
|
||||
}
|
||||
|
||||
private GlProgram link(int... shaders) {
|
||||
var handle = glCreateProgram();
|
||||
for (var shader : shaders) {
|
||||
glAttachShader(handle, shader);
|
||||
}
|
||||
glLinkProgram(handle);
|
||||
CompileUtil.checkLinkLog(handle);
|
||||
return new GlProgram(handle);
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getVertexComponents(PipelineContext ctx) {
|
||||
|
@ -189,16 +208,4 @@ public class FlwCompiler {
|
|||
return ImmutableList.of(instanceAssembly, instance, pipeline);
|
||||
}
|
||||
|
||||
private static List<PipelineContext> buildPipelineSet() {
|
||||
ImmutableList.Builder<PipelineContext> builder = ImmutableList.builder();
|
||||
for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) {
|
||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||
// TODO: context ubershaders, or not?
|
||||
builder.add(new PipelineContext(vertexType, structType, Components.WORLD, pipelineShader));
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
|
||||
/**
|
||||
* A component of a ShaderCompiler, responsible for expanding root sources into the complete set of included sources.
|
||||
*/
|
||||
public interface Includer {
|
||||
|
||||
/**
|
||||
* Expand the given root sources into the complete set of included sources.
|
||||
* <p> Each unique source will be seen exactly once.
|
||||
*
|
||||
* @param rootSources The root sources to expand.
|
||||
* @param out A consumer to which all sources should be passed in the order they should be included.
|
||||
*/
|
||||
void expand(ImmutableList<SourceComponent> rootSources, Consumer<SourceComponent> out);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.BackendTypes;
|
||||
import com.jozufozu.flywheel.core.ComponentRegistry;
|
||||
import com.jozufozu.flywheel.core.Components;
|
||||
import com.jozufozu.flywheel.core.pipeline.SimplePipeline;
|
||||
|
||||
public class PipelineContextSet {
|
||||
static PipelineContextSet create() {
|
||||
var builder = new PipelineContextSet();
|
||||
for (SimplePipeline pipelineShader : BackendTypes.availablePipelineShaders()) {
|
||||
for (StructType<?> structType : ComponentRegistry.structTypes) {
|
||||
for (VertexType vertexType : ComponentRegistry.vertexTypes) {
|
||||
builder.add(vertexType, structType, Components.WORLD, pipelineShader);
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private final List<PipelineContext> contexts = new ArrayList<>();
|
||||
private final List<PipelineContext> contextView = Collections.unmodifiableList(contexts);
|
||||
|
||||
PipelineContextSet() {
|
||||
}
|
||||
|
||||
public List<PipelineContext> all() {
|
||||
return contextView;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return contexts.size();
|
||||
}
|
||||
|
||||
private void add(VertexType vertexType, StructType<?> structType, ContextShader world, SimplePipeline pipelineShader) {
|
||||
var ctx = new PipelineContext(vertexType, structType, world, pipelineShader);
|
||||
|
||||
|
||||
contexts.add(ctx);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_TRUE;
|
||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
||||
import static org.lwjgl.opengl.GL20.glAttachShader;
|
||||
import static org.lwjgl.opengl.GL20.glCreateProgram;
|
||||
import static org.lwjgl.opengl.GL20.glGetProgramInfoLog;
|
||||
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.GlShader;
|
||||
|
||||
@Deprecated
|
||||
public class ProgramAssembler {
|
||||
private final int program;
|
||||
|
||||
public ProgramAssembler() {
|
||||
this.program = glCreateProgram();
|
||||
}
|
||||
|
||||
/**
|
||||
* Links the attached shaders to this program.
|
||||
*/
|
||||
public int link() {
|
||||
glLinkProgram(this.program);
|
||||
|
||||
String log = glGetProgramInfoLog(this.program);
|
||||
|
||||
if (!log.isEmpty()) {
|
||||
Backend.LOGGER.debug("Program link log: " + log);
|
||||
}
|
||||
|
||||
int result = glGetProgrami(this.program, GL_LINK_STATUS);
|
||||
|
||||
if (result != GL_TRUE) {
|
||||
throw new RuntimeException("Shader program linking failed, see log for details");
|
||||
}
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
public ProgramAssembler attachShader(GlShader glShader) {
|
||||
glAttachShader(this.program, glShader.handle());
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.core.SourceComponent;
|
||||
|
||||
public class RecursiveIncluder implements Includer {
|
||||
|
||||
public static final RecursiveIncluder INSTANCE = new RecursiveIncluder();
|
||||
|
||||
private RecursiveIncluder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expand(ImmutableList<SourceComponent> rootSources, Consumer<SourceComponent> out) {
|
||||
var included = depthFirstInclude(rootSources);
|
||||
included.forEach(out);
|
||||
rootSources.forEach(out);
|
||||
}
|
||||
|
||||
private static LinkedHashSet<SourceComponent> depthFirstInclude(ImmutableList<SourceComponent> root) {
|
||||
var included = new LinkedHashSet<SourceComponent>(); // linked to preserve order
|
||||
for (var component : root) {
|
||||
recursiveDepthFirstInclude(included, component);
|
||||
}
|
||||
return included;
|
||||
}
|
||||
|
||||
private static void recursiveDepthFirstInclude(Set<SourceComponent> included, SourceComponent component) {
|
||||
for (var include : component.included()) {
|
||||
recursiveDepthFirstInclude(included, include);
|
||||
}
|
||||
included.addAll(component.included());
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.compile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
@ -15,13 +13,18 @@ import com.jozufozu.flywheel.backend.gl.GLSLVersion;
|
|||
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.util.FlwUtil;
|
||||
|
||||
public class ShaderCompiler {
|
||||
private final Map<ShaderKey, CompilationResult> shaderCache = new HashMap<>();
|
||||
private final Consumer<FailedCompilation> errorConsumer;
|
||||
private final CompilationFactory factory;
|
||||
private final Includer includer;
|
||||
|
||||
public ShaderCompiler(Consumer<FailedCompilation> errorConsumer) {
|
||||
public ShaderCompiler(Consumer<FailedCompilation> errorConsumer, CompilationFactory factory, Includer includer) {
|
||||
this.errorConsumer = errorConsumer;
|
||||
this.factory = factory;
|
||||
this.includer = includer;
|
||||
}
|
||||
|
||||
public int shaderCount() {
|
||||
|
@ -36,7 +39,7 @@ public class ShaderCompiler {
|
|||
return cached.unwrap();
|
||||
}
|
||||
|
||||
CompilationResult out = compileUncached(glslVersion, shaderType, sourceComponents);
|
||||
CompilationResult out = compileUncached(factory.create(glslVersion, shaderType), sourceComponents);
|
||||
shaderCache.put(key, out);
|
||||
return unwrapAndReportError(out);
|
||||
}
|
||||
|
@ -60,40 +63,51 @@ public class ShaderCompiler {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
private static CompilationResult compileUncached(GLSLVersion glslVersion, ShaderType shaderType, ImmutableList<SourceComponent> sourceComponents) {
|
||||
var ctx = new Compilation(glslVersion, shaderType);
|
||||
private CompilationResult compileUncached(Compilation ctx, ImmutableList<SourceComponent> sourceComponents) {
|
||||
ctx.enableExtension("GL_ARB_explicit_attrib_location");
|
||||
ctx.enableExtension("GL_ARB_conservative_depth");
|
||||
|
||||
for (var include : depthFirstInclude(sourceComponents)) {
|
||||
ctx.appendComponent(include);
|
||||
}
|
||||
|
||||
for (var component : sourceComponents) {
|
||||
ctx.appendComponent(component);
|
||||
ctx.addComponentName(component.name());
|
||||
}
|
||||
includer.expand(sourceComponents, ctx::appendComponent);
|
||||
|
||||
return ctx.compile();
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private static void recursiveDepthFirstInclude(Set<SourceComponent> included, SourceComponent component) {
|
||||
for (var include : component.included()) {
|
||||
recursiveDepthFirstInclude(included, include);
|
||||
}
|
||||
included.addAll(component.included());
|
||||
}
|
||||
|
||||
private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType,
|
||||
ImmutableList<SourceComponent> sourceComponents) {
|
||||
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CompilationFactory {
|
||||
Compilation create(GLSLVersion version, ShaderType shaderType);
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private Consumer<FailedCompilation> errorConsumer = FlwUtil::noop;
|
||||
private CompilationFactory factory = Compilation::new;
|
||||
private Includer includer = RecursiveIncluder.INSTANCE;
|
||||
|
||||
public Builder errorConsumer(Consumer<FailedCompilation> errorConsumer) {
|
||||
this.errorConsumer = errorConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder compilationFactory(CompilationFactory factory) {
|
||||
this.factory = factory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder includer(Includer includer) {
|
||||
this.includer = includer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ShaderCompiler build() {
|
||||
return new ShaderCompiler(errorConsumer, factory, includer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ 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;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
|
@ -102,7 +101,8 @@ public class SourceLines implements CharSequence {
|
|||
int start = lines.getInt(i - 1);
|
||||
int end = lines.getInt(i);
|
||||
|
||||
builder.add(StringUtil.trimEnd(source.substring(start, end)));
|
||||
builder.add(source.substring(start, end)
|
||||
.stripTrailing());
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
|
|
@ -11,6 +11,10 @@ public class GlslBuilder {
|
|||
add(new Define(name, value));
|
||||
}
|
||||
|
||||
public void undef(String key) {
|
||||
add(new Undef(key));
|
||||
}
|
||||
|
||||
public GlslStruct struct() {
|
||||
return add(new GlslStruct());
|
||||
}
|
||||
|
@ -32,6 +36,10 @@ public class GlslBuilder {
|
|||
elements.add(Separators.BLANK_LINE);
|
||||
}
|
||||
|
||||
public void _addRaw(String sourceString) {
|
||||
elements.add(() -> sourceString);
|
||||
}
|
||||
|
||||
public String build() {
|
||||
return elements.stream()
|
||||
.map(Declaration::prettyPrint)
|
||||
|
@ -65,4 +73,11 @@ public class GlslBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
public record Undef(String name) implements Declaration {
|
||||
@Override
|
||||
public String prettyPrint() {
|
||||
return "#undef " + name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,18 +22,16 @@ public class FogProvider implements UniformProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ActiveUniformProvider activate(long ptr, Notifier notifier) {
|
||||
return new Active(ptr, notifier);
|
||||
public ActiveUniformProvider activate(long ptr) {
|
||||
return new Active(ptr);
|
||||
}
|
||||
|
||||
public static class Active implements ActiveUniformProvider {
|
||||
|
||||
private final long ptr;
|
||||
private final Notifier notifier;
|
||||
|
||||
public Active(long ptr, Notifier notifier) {
|
||||
public Active(long ptr) {
|
||||
this.ptr = ptr;
|
||||
this.notifier = notifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -41,9 +39,9 @@ public class FogProvider implements UniformProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void poll() {
|
||||
public boolean poll() {
|
||||
if (!FOG_UPDATE) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var color = RenderSystem.getShaderFogColor();
|
||||
|
@ -57,9 +55,9 @@ public class FogProvider implements UniformProvider {
|
|||
MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape()
|
||||
.getIndex());
|
||||
|
||||
notifier.signalChanged();
|
||||
|
||||
FOG_UPDATE = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,18 +31,17 @@ public class FrustumProvider implements UniformProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ActiveUniformProvider activate(long ptr, Notifier notifier) {
|
||||
return new Active(ptr, notifier);
|
||||
public ActiveUniformProvider activate(long ptr) {
|
||||
return new Active(ptr);
|
||||
}
|
||||
|
||||
static class Active implements ActiveUniformProvider, Consumer<BeginFrameEvent> {
|
||||
|
||||
private final long ptr;
|
||||
private final Notifier notifier;
|
||||
private boolean dirty = true;
|
||||
|
||||
public Active(long ptr, Notifier notifier) {
|
||||
public Active(long ptr) {
|
||||
this.ptr = ptr;
|
||||
this.notifier = notifier;
|
||||
MinecraftForge.EVENT_BUS.addListener(this);
|
||||
}
|
||||
|
||||
|
@ -52,8 +51,12 @@ public class FrustumProvider implements UniformProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void poll() {
|
||||
|
||||
public boolean poll() {
|
||||
if (dirty) {
|
||||
dirty = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -78,7 +81,7 @@ public class FrustumProvider implements UniformProvider {
|
|||
|
||||
shiftedCuller.getJozuPackedPlanes(ptr);
|
||||
|
||||
notifier.signalChanged();
|
||||
dirty = true;
|
||||
CAPTURE = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ public class UniformBuffer {
|
|||
private static final boolean PO2_ALIGNMENT = RenderMath.isPowerOf2(OFFSET_ALIGNMENT);
|
||||
|
||||
private static UniformBuffer instance;
|
||||
private final List<Allocated> allocatedProviders;
|
||||
private final AllocatedProviderSet providerSet;
|
||||
|
||||
public static UniformBuffer getInstance() {
|
||||
if (instance == null) {
|
||||
|
@ -32,50 +32,19 @@ public class UniformBuffer {
|
|||
}
|
||||
|
||||
private final GlBuffer buffer;
|
||||
private final MemoryBlock data;
|
||||
|
||||
private final BitSet changedBytes;
|
||||
|
||||
private UniformBuffer() {
|
||||
buffer = new GlBuffer(GlBufferType.UNIFORM_BUFFER);
|
||||
|
||||
Collection<UniformProvider> providers = ComponentRegistry.getAllUniformProviders();
|
||||
|
||||
var builder = ImmutableList.<Allocated>builder();
|
||||
int totalBytes = 0;
|
||||
int index = 0;
|
||||
for (UniformProvider provider : providers) {
|
||||
int size = align16(provider.byteSize());
|
||||
|
||||
builder.add(new Allocated(provider, totalBytes, size, index));
|
||||
|
||||
totalBytes = alignUniformBuffer(totalBytes + size);
|
||||
index++;
|
||||
}
|
||||
|
||||
allocatedProviders = builder.build();
|
||||
|
||||
data = MemoryBlock.mallocTracked(totalBytes);
|
||||
changedBytes = new BitSet(totalBytes);
|
||||
|
||||
for (Allocated p : allocatedProviders) {
|
||||
p.updatePtr(data);
|
||||
}
|
||||
providerSet = new AllocatedProviderSet(ComponentRegistry.getAllUniformProviders());
|
||||
}
|
||||
|
||||
public void sync() {
|
||||
allocatedProviders.forEach(Allocated::pollActive);
|
||||
if (changedBytes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
providerSet.sync();
|
||||
|
||||
// TODO: upload only changed bytes
|
||||
changedBytes.clear();
|
||||
|
||||
buffer.upload(data);
|
||||
buffer.upload(providerSet.data);
|
||||
|
||||
int handle = buffer.handle();
|
||||
for (Allocated p : allocatedProviders) {
|
||||
for (Allocated p : providerSet.allocatedProviders) {
|
||||
GL32.glBindBufferRange(GL32.GL_UNIFORM_BUFFER, p.index, handle, p.offset, p.size);
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +62,7 @@ public class UniformBuffer {
|
|||
return (numToRound + 16 - 1) & -16;
|
||||
}
|
||||
|
||||
private class Allocated implements UniformProvider.Notifier {
|
||||
private static class Allocated {
|
||||
private final UniformProvider provider;
|
||||
private final int offset;
|
||||
private final int size;
|
||||
|
@ -107,20 +76,11 @@ public class UniformBuffer {
|
|||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void signalChanged() {
|
||||
changedBytes.set(offset, offset + size);
|
||||
}
|
||||
|
||||
private void updatePtr(MemoryBlock bufferBase) {
|
||||
if (activeProvider != null) {
|
||||
activeProvider.delete();
|
||||
}
|
||||
activeProvider = provider.activate(bufferBase.ptr() + offset, this);
|
||||
}
|
||||
|
||||
public UniformProvider provider() {
|
||||
return provider;
|
||||
activeProvider = provider.activate(bufferBase.ptr() + offset);
|
||||
}
|
||||
|
||||
public int offset() {
|
||||
|
@ -135,9 +95,46 @@ public class UniformBuffer {
|
|||
return index;
|
||||
}
|
||||
|
||||
public void pollActive() {
|
||||
if (activeProvider != null) {
|
||||
activeProvider.poll();
|
||||
public boolean maybePoll() {
|
||||
return activeProvider != null && activeProvider.poll();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AllocatedProviderSet {
|
||||
private final List<Allocated> allocatedProviders;
|
||||
|
||||
private final MemoryBlock data;
|
||||
|
||||
private final BitSet changedBytes;
|
||||
|
||||
private AllocatedProviderSet(final Collection<UniformProvider> providers) {
|
||||
var builder = ImmutableList.<Allocated>builder();
|
||||
int totalBytes = 0;
|
||||
int index = 0;
|
||||
for (UniformProvider provider : providers) {
|
||||
int size = align16(provider.byteSize());
|
||||
|
||||
builder.add(new Allocated(provider, totalBytes, size, index));
|
||||
|
||||
totalBytes = alignUniformBuffer(totalBytes + size);
|
||||
index++;
|
||||
}
|
||||
|
||||
allocatedProviders = builder.build();
|
||||
|
||||
data = MemoryBlock.mallocTracked(totalBytes);
|
||||
changedBytes = new BitSet(totalBytes);
|
||||
|
||||
for (Allocated p : allocatedProviders) {
|
||||
p.updatePtr(data);
|
||||
}
|
||||
}
|
||||
|
||||
public void sync() {
|
||||
for (Allocated p : allocatedProviders) {
|
||||
if (p.maybePoll()) {
|
||||
changedBytes.set(p.offset(), p.offset() + p.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,17 +32,16 @@ public class ViewProvider implements UniformProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ActiveUniformProvider activate(long ptr, Notifier notifier) {
|
||||
return new Active(ptr, notifier);
|
||||
public ActiveUniformProvider activate(long ptr) {
|
||||
return new Active(ptr);
|
||||
}
|
||||
|
||||
public static class Active implements ActiveUniformProvider, Consumer<BeginFrameEvent> {
|
||||
private final long ptr;
|
||||
private final Notifier notifier;
|
||||
private boolean dirty = true;
|
||||
|
||||
public Active(long ptr, Notifier notifier) {
|
||||
public Active(long ptr) {
|
||||
this.ptr = ptr;
|
||||
this.notifier = notifier;
|
||||
MinecraftForge.EVENT_BUS.addListener(this);
|
||||
}
|
||||
|
||||
|
@ -52,7 +51,12 @@ public class ViewProvider implements UniformProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void poll() {
|
||||
public boolean poll() {
|
||||
if (dirty) {
|
||||
dirty = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,7 +89,7 @@ public class ViewProvider implements UniformProvider {
|
|||
MemoryUtil.memPutFloat(ptr + 72, camZ);
|
||||
MemoryUtil.memPutInt(ptr + 76, constantAmbientLight);
|
||||
|
||||
notifier.signalChanged();
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,11 @@ public class FlwUtil {
|
|||
}
|
||||
|
||||
public static <R> Stream<R> mapValues(Map<?, R> map) {
|
||||
return map.values().stream();
|
||||
return map.values()
|
||||
.stream();
|
||||
}
|
||||
|
||||
public static <T> void noop(T object) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,13 +64,20 @@ public class StringUtil {
|
|||
.collect(Collectors.joining(", ")) + ')';
|
||||
}
|
||||
|
||||
public static String trimEnd(String value) {
|
||||
int len = value.length();
|
||||
int st = 0;
|
||||
while ((st < len) && Character.isWhitespace(value.charAt(len - 1))) {
|
||||
len--;
|
||||
public static String trimPrefix(String s, String prefix) {
|
||||
if (s.startsWith(prefix)) {
|
||||
return s.substring(prefix.length());
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
public static String trimSuffix(String s, String prefix) {
|
||||
if (s.endsWith(prefix)) {
|
||||
return s.substring(0, s.length() - prefix.length());
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
return value.substring(0, len);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
// TODO: Transform uniform shaders
|
||||
vec4 flw_fogColor;
|
||||
vec2 flw_fogRange;
|
||||
int flw_fogShape;
|
||||
// TODO: inject FLW_UNIFORM_BINDING definitions
|
||||
layout(std140, binding = FLW_UNIFORM_BINDING) uniform flw_fog {
|
||||
vec4 flw_fogColor;
|
||||
vec2 flw_fogRange;
|
||||
int flw_fogShape;
|
||||
};
|
||||
|
|
|
@ -9,4 +9,6 @@ struct FLWPackedPlanes {
|
|||
vec2 zW; // <nz.w, pz.w>
|
||||
};
|
||||
|
||||
FLWPackedPlanes flw_planes;
|
||||
layout(std140, binding = FLW_UNIFORM_BINDING) uniform FLWFrustum {
|
||||
FLWPackedPlanes flw_planes;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
mat4 flw_viewProjection;
|
||||
vec4 flw_cameraPos;
|
||||
int flw_constantAmbientLight;
|
||||
layout(std140, binding = FLW_UNIFORM_BINDING) uniform flw_view {
|
||||
mat4 flw_viewProjection;
|
||||
vec4 flw_cameraPos;
|
||||
int flw_constantAmbientLight;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue