mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-06 04:16:36 +01:00
Pre-processing post-pre-refactor-refactor
- Separate pipeline compiler from compute compiler - Remove Pipeline field from PipelineProgramKey - Share one UniformComponent across compilers - Use AbstractCompiler to deduplicate some shared code - Separate indirect programs from instancing programs - Move compilation tracking information to CompilerStats - Improve compilation result/link result reporting
This commit is contained in:
parent
b30d686785
commit
4c8e174712
18 changed files with 523 additions and 377 deletions
|
@ -0,0 +1,47 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
||||
public abstract class AbstractCompiler<K> {
|
||||
protected final ShaderSources sources;
|
||||
protected final ShaderCompiler shaderCompiler;
|
||||
protected final ProgramLinker programLinker;
|
||||
private final ImmutableList<K> keys;
|
||||
private final CompilerStats stats = new CompilerStats();
|
||||
|
||||
public AbstractCompiler(ShaderSources sources, ImmutableList<K> keys) {
|
||||
this.sources = sources;
|
||||
this.keys = keys;
|
||||
|
||||
shaderCompiler = ShaderCompiler.builder()
|
||||
.build(stats);
|
||||
programLinker = new ProgramLinker(stats);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract GlProgram compile(K key);
|
||||
|
||||
public Map<K, GlProgram> compile() {
|
||||
stats.start();
|
||||
Map<K, GlProgram> out = new HashMap<>();
|
||||
for (var key : keys) {
|
||||
GlProgram glProgram = compile(key);
|
||||
if (glProgram != null) {
|
||||
out.put(key, glProgram);
|
||||
}
|
||||
}
|
||||
stats.finish();
|
||||
return out;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
shaderCompiler.delete();
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ public class Compilation {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
public CompilationResult compile() {
|
||||
public ShaderResult compile() {
|
||||
int handle = GL20.glCreateShader(shaderType.glEnum);
|
||||
var source = fullSource.toString();
|
||||
|
||||
|
@ -56,13 +56,14 @@ public class Compilation {
|
|||
var shaderName = buildShaderName();
|
||||
dumpSource(source, shaderType.getFileName(shaderName));
|
||||
|
||||
var infoLog = GL20.glGetShaderInfoLog(handle);
|
||||
|
||||
if (compiledSuccessfully(handle)) {
|
||||
return CompilationResult.success(new GlShader(handle, shaderType, shaderName));
|
||||
return ShaderResult.success(new GlShader(handle, shaderType, shaderName), infoLog);
|
||||
}
|
||||
|
||||
var errorLog = GL20.glGetShaderInfoLog(handle);
|
||||
GL20.glDeleteShader(handle);
|
||||
return CompilationResult.failure(new FailedCompilation(shaderName, files, generatedSource.toString(), errorLog));
|
||||
return ShaderResult.failure(new FailedCompilation(shaderName, files, generatedSource.toString(), infoLog));
|
||||
}
|
||||
|
||||
public void enableExtension(String ext) {
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.gl.shader.GlShader;
|
||||
|
||||
public sealed interface CompilationResult {
|
||||
@Nullable
|
||||
default GlShader unwrap() {
|
||||
if (this instanceof Success s) {
|
||||
return s.shader();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
record Success(GlShader shader) implements CompilationResult {
|
||||
}
|
||||
|
||||
record Failure(FailedCompilation failure) implements CompilationResult {
|
||||
}
|
||||
|
||||
static CompilationResult success(GlShader program) {
|
||||
return new Success(program);
|
||||
}
|
||||
|
||||
static CompilationResult failure(FailedCompilation failure) {
|
||||
return new Failure(failure);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,5 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.GL_TRUE;
|
||||
import static org.lwjgl.opengl.GL20.GL_LINK_STATUS;
|
||||
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;
|
||||
|
@ -13,7 +7,6 @@ import java.util.stream.Stream;
|
|||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
|
@ -64,25 +57,4 @@ public class CompileUtil {
|
|||
.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()) {
|
||||
Flywheel.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,57 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
public class CompilerStats {
|
||||
private long compileStart;
|
||||
|
||||
private final List<FailedCompilation> shaderErrors = new ArrayList<>();
|
||||
private final List<String> programErrors = new ArrayList<>();
|
||||
private boolean errored = false;
|
||||
private int shaderCount = 0;
|
||||
private int programCount = 0;
|
||||
|
||||
public void start() {
|
||||
compileStart = System.nanoTime();
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
long compileEnd = System.nanoTime();
|
||||
var elapsed = StringUtil.formatTime(compileEnd - compileStart);
|
||||
|
||||
Flywheel.LOGGER.info("Compiled " + shaderCount + " shaders (with " + shaderErrors.size() + " compile errors) " + "and " + programCount + " programs (with " + programErrors.size() + " link errors) in " + elapsed);
|
||||
|
||||
}
|
||||
|
||||
// TODO: use this to turn off backends
|
||||
public boolean errored() {
|
||||
return errored;
|
||||
}
|
||||
|
||||
private String generateLog() {
|
||||
return String.join("\n", programErrors) + '\n' + shaderErrors.stream()
|
||||
.map(FailedCompilation::getMessage)
|
||||
.collect(Collectors.joining("\n"));
|
||||
}
|
||||
|
||||
public void shaderResult(ShaderResult result) {
|
||||
if (result instanceof ShaderResult.Failure f) {
|
||||
shaderErrors.add(f.failure());
|
||||
errored = true;
|
||||
}
|
||||
shaderCount++;
|
||||
}
|
||||
|
||||
public void linkResult(LinkResult linkResult) {
|
||||
if (linkResult instanceof LinkResult.Failure f) {
|
||||
programErrors.add(f.failure());
|
||||
errored = true;
|
||||
}
|
||||
programCount++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.backend.engine.indirect.IndirectComponent;
|
||||
import com.jozufozu.flywheel.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class CullingCompiler extends AbstractCompiler<InstanceType<?>> {
|
||||
private final UniformComponent uniformComponent;
|
||||
private final SourceFile pipelineCompute;
|
||||
|
||||
public CullingCompiler(ShaderSources sources, ImmutableList<InstanceType<?>> keys, UniformComponent uniformComponent) {
|
||||
super(sources, keys);
|
||||
|
||||
this.uniformComponent = uniformComponent;
|
||||
pipelineCompute = sources.find(Files.INDIRECT_CULL);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected GlProgram compile(InstanceType<?> key) {
|
||||
var computeComponents = getComputeComponents(key);
|
||||
var compute = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, computeComponents);
|
||||
|
||||
if (compute == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return programLinker.link(compute);
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getComputeComponents(InstanceType<?> instanceType) {
|
||||
var instanceAssembly = new IndirectComponent(sources, instanceType);
|
||||
var instance = sources.find(instanceType.instanceShader());
|
||||
|
||||
return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipelineCompute);
|
||||
}
|
||||
|
||||
private static final class Files {
|
||||
public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("internal/indirect_cull.glsl");
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.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;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwPrograms.PipelineProgramKey;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.engine.indirect.IndirectComponent;
|
||||
import com.jozufozu.flywheel.gl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.ShaderLoadingException;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.lib.material.MaterialIndices;
|
||||
import com.jozufozu.flywheel.util.StringUtil;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class FlwCompiler {
|
||||
private final long compileStart = System.nanoTime();
|
||||
|
||||
private final ShaderSources sources;
|
||||
|
||||
private final ImmutableList<PipelineProgramKey> pipelineKeys;
|
||||
private final ImmutableList<InstanceType<?>> cullingKeys;
|
||||
|
||||
private final ShaderCompiler shaderCompiler;
|
||||
private final List<FailedCompilation> errors = new ArrayList<>();
|
||||
|
||||
private final MaterialAdapterComponent vertexMaterialComponent;
|
||||
private final MaterialAdapterComponent fragmentMaterialComponent;
|
||||
private final UniformComponent uniformComponent;
|
||||
|
||||
private final Map<PipelineProgramKey, GlProgram> pipelinePrograms = new HashMap<>();
|
||||
private final Map<InstanceType<?>, GlProgram> cullingPrograms = new HashMap<>();
|
||||
|
||||
public FlwCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, ImmutableList<InstanceType<?>> cullingKeys) {
|
||||
this.sources = sources;
|
||||
|
||||
this.pipelineKeys = pipelineKeys;
|
||||
this.cullingKeys = cullingKeys;
|
||||
|
||||
shaderCompiler = ShaderCompiler.builder()
|
||||
.errorConsumer(errors::add)
|
||||
.build();
|
||||
|
||||
vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllVertexShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
|
||||
.build(sources);
|
||||
fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllFragmentShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("bool")
|
||||
.name("flw_discardPredicate")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.literal(false))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
.name("flw_fogFilter")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
|
||||
.build(sources);
|
||||
uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms"))
|
||||
.sources(ShaderUniforms.REGISTRY.getAll()
|
||||
.stream()
|
||||
.map(ShaderUniforms::uniformShader)
|
||||
.toList())
|
||||
.build(sources);
|
||||
}
|
||||
|
||||
public FlwPrograms compile() {
|
||||
doCompilation();
|
||||
|
||||
finish();
|
||||
|
||||
return new FlwPrograms(pipelinePrograms, cullingPrograms);
|
||||
}
|
||||
|
||||
private void doCompilation() {
|
||||
for (var key : pipelineKeys) {
|
||||
GlProgram glProgram = compilePipelineProgram(key);
|
||||
if (glProgram != null) {
|
||||
pipelinePrograms.put(key, glProgram);
|
||||
}
|
||||
}
|
||||
|
||||
for (var key : cullingKeys) {
|
||||
GlProgram glProgram = compileCullingProgram(key);
|
||||
if (glProgram != null) {
|
||||
cullingPrograms.put(key, glProgram);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static GlProgram link(int... shaders) {
|
||||
var handle = glCreateProgram();
|
||||
for (var shader : shaders) {
|
||||
glAttachShader(handle, shader);
|
||||
}
|
||||
glLinkProgram(handle);
|
||||
CompileUtil.checkLinkLog(handle);
|
||||
return new GlProgram(handle);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GlProgram compilePipelineProgram(PipelineProgramKey key) {
|
||||
var glslVersion = key.pipelineShader()
|
||||
.glslVersion();
|
||||
|
||||
var vertex = shaderCompiler.compile(glslVersion, ShaderType.VERTEX, getVertexComponents(key));
|
||||
var fragment = shaderCompiler.compile(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(key));
|
||||
|
||||
if (vertex == null || fragment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var glProgram = link(vertex.handle(), fragment.handle());
|
||||
key.contextShader()
|
||||
.onProgramLink(glProgram);
|
||||
return glProgram;
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getVertexComponents(PipelineProgramKey key) {
|
||||
var instanceAssembly = key.pipelineShader()
|
||||
.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(sources, key.vertexType(), key.instanceType()));
|
||||
|
||||
var layout = sources.find(key.vertexType()
|
||||
.layoutShader());
|
||||
var instance = sources.find(key.instanceType()
|
||||
.instanceShader());
|
||||
var context = sources.find(key.contextShader()
|
||||
.vertexShader());
|
||||
var pipeline = sources.find(key.pipelineShader()
|
||||
.vertexShader());
|
||||
|
||||
return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipeline);
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getFragmentComponents(PipelineProgramKey key) {
|
||||
var context = sources.find(key.contextShader()
|
||||
.fragmentShader());
|
||||
var pipeline = sources.find(key.pipelineShader()
|
||||
.fragmentShader());
|
||||
return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipeline);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GlProgram compileCullingProgram(InstanceType<?> key) {
|
||||
var computeComponents = getComputeComponents(key);
|
||||
var result = shaderCompiler.compile(GLSLVersion.V460, ShaderType.COMPUTE, computeComponents);
|
||||
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return link(result.handle());
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getComputeComponents(InstanceType<?> instanceType) {
|
||||
var instanceAssembly = new IndirectComponent(sources, instanceType);
|
||||
var instance = sources.find(instanceType.instanceShader());
|
||||
var pipeline = sources.find(Files.INDIRECT_CULL);
|
||||
|
||||
return ImmutableList.of(uniformComponent, instanceAssembly, instance, pipeline);
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
long compileEnd = System.nanoTime();
|
||||
int programCount = pipelineKeys.size() + cullingKeys.size();
|
||||
int shaderCount = shaderCompiler.shaderCount();
|
||||
int errorCount = errors.size();
|
||||
var elapsed = StringUtil.formatTime(compileEnd - compileStart);
|
||||
|
||||
Flywheel.LOGGER.info("Compiled " + programCount + " programs and " + shaderCount + " shaders in " + elapsed + " with " + errorCount + " errors.");
|
||||
|
||||
if (errorCount > 0) {
|
||||
var details = errors.stream()
|
||||
.map(FailedCompilation::getMessage)
|
||||
.collect(Collectors.joining("\n"));
|
||||
// TODO: disable backend instead of crashing if compilation fails
|
||||
throw new ShaderLoadingException("Compilation failed.\n" + details);
|
||||
}
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
shaderCompiler.delete();
|
||||
}
|
||||
|
||||
private static final class Files {
|
||||
public static final ResourceLocation INDIRECT_CULL = Flywheel.rl("internal/indirect_cull.glsl");
|
||||
}
|
||||
}
|
|
@ -1,16 +1,10 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.error.ErrorReporter;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
|
@ -18,77 +12,32 @@ import com.jozufozu.flywheel.lib.context.Contexts;
|
|||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
|
||||
public class FlwPrograms {
|
||||
private static FlwPrograms instance;
|
||||
|
||||
private final Map<PipelineProgramKey, GlProgram> pipelinePrograms;
|
||||
private final Map<InstanceType<?>, GlProgram> cullingPrograms;
|
||||
|
||||
public FlwPrograms(Map<PipelineProgramKey, GlProgram> pipelinePrograms, Map<InstanceType<?>, GlProgram> cullingPrograms) {
|
||||
this.pipelinePrograms = pipelinePrograms;
|
||||
this.cullingPrograms = cullingPrograms;
|
||||
private FlwPrograms() {
|
||||
}
|
||||
|
||||
public static void reload(ResourceManager resourceManager) {
|
||||
if (instance != null) {
|
||||
instance.delete();
|
||||
}
|
||||
var errorReporter = new ErrorReporter();
|
||||
|
||||
ErrorReporter errorReporter = new ErrorReporter();
|
||||
ShaderSources sources = new ShaderSources(errorReporter, resourceManager);
|
||||
FlwCompiler compiler = new FlwCompiler(sources, createPipelineKeys(), createCullingKeys());
|
||||
instance = compiler.compile();
|
||||
compiler.delete();
|
||||
var sources = new ShaderSources(errorReporter, resourceManager);
|
||||
var pipelineKeys = createPipelineKeys();
|
||||
var uniformComponent = UniformComponent.builder(Flywheel.rl("uniforms"))
|
||||
.sources(ShaderUniforms.REGISTRY.getAll()
|
||||
.stream()
|
||||
.map(ShaderUniforms::uniformShader)
|
||||
.toList())
|
||||
.build(sources);
|
||||
|
||||
InstancingPrograms.reload(sources, pipelineKeys, uniformComponent);
|
||||
IndirectPrograms.reload(sources, pipelineKeys, uniformComponent);
|
||||
}
|
||||
|
||||
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
|
||||
ImmutableList.Builder<PipelineProgramKey> builder = ImmutableList.builder();
|
||||
for (Pipeline pipelineShader : Pipelines.ALL) {
|
||||
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
|
||||
for (VertexType vertexType : VertexType.REGISTRY) {
|
||||
builder.add(new PipelineProgramKey(vertexType, instanceType, Contexts.WORLD, pipelineShader));
|
||||
}
|
||||
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
|
||||
for (VertexType vertexType : VertexType.REGISTRY) {
|
||||
builder.add(new PipelineProgramKey(vertexType, instanceType, Contexts.WORLD));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static ImmutableList<InstanceType<?>> createCullingKeys() {
|
||||
ImmutableList.Builder<InstanceType<?>> builder = ImmutableList.builder();
|
||||
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
|
||||
builder.add(instanceType);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FlwPrograms get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public GlProgram getPipelineProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader, Pipeline pipelineShader) {
|
||||
return pipelinePrograms.get(new PipelineProgramKey(vertexType, instanceType, contextShader, pipelineShader));
|
||||
}
|
||||
|
||||
public GlProgram getCullingProgram(InstanceType<?> instanceType) {
|
||||
return cullingPrograms.get(instanceType);
|
||||
}
|
||||
|
||||
private void delete() {
|
||||
pipelinePrograms.values()
|
||||
.forEach(GlProgram::delete);
|
||||
cullingPrograms.values()
|
||||
.forEach(GlProgram::delete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param vertexType The vertex type the program should be adapted for.
|
||||
* @param instanceType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
* @param pipelineShader The pipeline shader to use.
|
||||
*/
|
||||
public record PipelineProgramKey(VertexType vertexType, InstanceType<?> instanceType, Context contextShader,
|
||||
Pipeline pipelineShader) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
||||
public class IndirectPrograms {
|
||||
private static IndirectPrograms instance;
|
||||
private final Map<PipelineProgramKey, GlProgram> pipeline;
|
||||
private final Map<InstanceType<?>, GlProgram> culling;
|
||||
|
||||
public IndirectPrograms(Map<PipelineProgramKey, GlProgram> pipeline, Map<InstanceType<?>, GlProgram> culling) {
|
||||
this.pipeline = pipeline;
|
||||
this.culling = culling;
|
||||
}
|
||||
|
||||
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) {
|
||||
if (instance != null) {
|
||||
instance.delete();
|
||||
}
|
||||
var indirectCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INDIRECT, uniformComponent);
|
||||
var cullingCompiler = new CullingCompiler(sources, createCullingKeys(), uniformComponent);
|
||||
instance = new IndirectPrograms(indirectCompiler.compile(), cullingCompiler.compile());
|
||||
indirectCompiler.delete();
|
||||
cullingCompiler.delete();
|
||||
}
|
||||
|
||||
private static ImmutableList<InstanceType<?>> createCullingKeys() {
|
||||
ImmutableList.Builder<InstanceType<?>> builder = ImmutableList.builder();
|
||||
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
|
||||
builder.add(instanceType);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IndirectPrograms get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
||||
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
|
||||
}
|
||||
|
||||
public GlProgram getCullingProgram(InstanceType<?> instanceType) {
|
||||
return culling.get(instanceType);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
pipeline.values()
|
||||
.forEach(GlProgram::delete);
|
||||
culling.values()
|
||||
.forEach(GlProgram::delete);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
||||
public class InstancingPrograms {
|
||||
private static InstancingPrograms instance;
|
||||
private final Map<PipelineProgramKey, GlProgram> pipeline;
|
||||
|
||||
public InstancingPrograms(Map<PipelineProgramKey, GlProgram> pipeline) {
|
||||
this.pipeline = pipeline;
|
||||
}
|
||||
|
||||
public static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent) {
|
||||
if (instance != null) {
|
||||
instance.delete();
|
||||
}
|
||||
var instancingCompiler = new PipelineCompiler(sources, pipelineKeys, Pipelines.INSTANCED_ARRAYS, uniformComponent);
|
||||
instance = new InstancingPrograms(instancingCompiler.compile());
|
||||
instancingCompiler.delete();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static InstancingPrograms get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public GlProgram get(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
||||
return pipeline.get(new PipelineProgramKey(vertexType, instanceType, contextShader));
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
pipeline.values()
|
||||
.forEach(GlProgram::delete);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
|
||||
public sealed interface LinkResult {
|
||||
|
||||
@Nullable
|
||||
default GlProgram unwrap() {
|
||||
if (this instanceof Success s) {
|
||||
return s.program();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
record Success(GlProgram program, String log) implements LinkResult {
|
||||
}
|
||||
|
||||
record Failure(String failure) implements LinkResult {
|
||||
}
|
||||
|
||||
static LinkResult success(GlProgram program, String log) {
|
||||
return new Success(program, log);
|
||||
}
|
||||
|
||||
static LinkResult failure(String failure) {
|
||||
return new Failure(failure);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipeline;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
import com.jozufozu.flywheel.glsl.SourceFile;
|
||||
import com.jozufozu.flywheel.glsl.generate.FnSignature;
|
||||
import com.jozufozu.flywheel.glsl.generate.GlslExpr;
|
||||
import com.jozufozu.flywheel.lib.material.MaterialIndices;
|
||||
|
||||
public class PipelineCompiler extends AbstractCompiler<PipelineProgramKey> {
|
||||
private final Pipeline pipeline;
|
||||
private final MaterialAdapterComponent vertexMaterialComponent;
|
||||
private final MaterialAdapterComponent fragmentMaterialComponent;
|
||||
private final UniformComponent uniformComponent;
|
||||
private final SourceFile pipelineFragment;
|
||||
private final SourceFile pipelineVertex;
|
||||
|
||||
public PipelineCompiler(ShaderSources sources, ImmutableList<PipelineProgramKey> keys, Pipeline pipeline, UniformComponent uniformComponent) {
|
||||
super(sources, keys);
|
||||
this.pipeline = pipeline;
|
||||
this.uniformComponent = uniformComponent;
|
||||
|
||||
vertexMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("vertex_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllVertexShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialVertex"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
|
||||
.build(sources);
|
||||
fragmentMaterialComponent = MaterialAdapterComponent.builder(Flywheel.rl("fragment_material_adapter"))
|
||||
.materialSources(MaterialIndices.getAllFragmentShaders())
|
||||
.adapt(FnSignature.ofVoid("flw_materialFragment"))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("bool")
|
||||
.name("flw_discardPredicate")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.literal(false))
|
||||
.adapt(FnSignature.create()
|
||||
.returnType("vec4")
|
||||
.name("flw_fogFilter")
|
||||
.arg("vec4", "color")
|
||||
.build(), GlslExpr.variable("color"))
|
||||
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
|
||||
.build(sources);
|
||||
|
||||
pipelineFragment = sources.find(pipeline.fragmentShader());
|
||||
pipelineVertex = sources.find(pipeline.vertexShader());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected GlProgram compile(PipelineProgramKey key) {
|
||||
var glslVersion = pipeline.glslVersion();
|
||||
|
||||
var vertex = shaderCompiler.compile(glslVersion, ShaderType.VERTEX, getVertexComponents(key));
|
||||
var fragment = shaderCompiler.compile(glslVersion, ShaderType.FRAGMENT, getFragmentComponents(key));
|
||||
|
||||
if (vertex == null || fragment == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var glProgram = programLinker.link(vertex, fragment);
|
||||
key.contextShader()
|
||||
.onProgramLink(glProgram);
|
||||
return glProgram;
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getVertexComponents(PipelineProgramKey key) {
|
||||
var instanceAssembly = pipeline.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(sources, key.vertexType(), key.instanceType()));
|
||||
|
||||
var layout = sources.find(key.vertexType()
|
||||
.layoutShader());
|
||||
var instance = sources.find(key.instanceType()
|
||||
.instanceShader());
|
||||
var context = sources.find(key.contextShader()
|
||||
.vertexShader());
|
||||
|
||||
return ImmutableList.of(uniformComponent, vertexMaterialComponent, instanceAssembly, layout, instance, context, pipelineVertex);
|
||||
}
|
||||
|
||||
private ImmutableList<SourceComponent> getFragmentComponents(PipelineProgramKey key) {
|
||||
var context = sources.find(key.contextShader()
|
||||
.fragmentShader());
|
||||
return ImmutableList.of(uniformComponent, fragmentMaterialComponent, context, pipelineFragment);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
|
||||
/**
|
||||
* Represents the entire context of a program's usage.
|
||||
*
|
||||
* @param vertexType The vertex type the program should be adapted for.
|
||||
* @param instanceType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
*/
|
||||
public record PipelineProgramKey(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.jozufozu.flywheel.backend.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 org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.gl.shader.GlShader;
|
||||
|
||||
public class ProgramLinker {
|
||||
private final CompilerStats stats;
|
||||
|
||||
public ProgramLinker(CompilerStats stats) {
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GlProgram link(GlShader... shaders) {
|
||||
// this probably doesn't need caching
|
||||
var linkResult = linkInternal(shaders);
|
||||
stats.linkResult(linkResult);
|
||||
return linkResult.unwrap();
|
||||
}
|
||||
|
||||
private LinkResult linkInternal(GlShader... shaders) {
|
||||
int handle = glCreateProgram();
|
||||
|
||||
for (GlShader shader : shaders) {
|
||||
glAttachShader(handle, shader.handle());
|
||||
}
|
||||
|
||||
glLinkProgram(handle);
|
||||
String log = glGetProgramInfoLog(handle);
|
||||
|
||||
if (linkSuccessful(handle)) {
|
||||
return LinkResult.success(new GlProgram(handle), log);
|
||||
} else {
|
||||
return LinkResult.failure(log);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean linkSuccessful(int handle) {
|
||||
return glGetProgrami(handle, GL_LINK_STATUS) == GL_TRUE;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,6 @@ package com.jozufozu.flywheel.backend.compile;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -15,13 +14,13 @@ import com.jozufozu.flywheel.gl.shader.ShaderType;
|
|||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
|
||||
public class ShaderCompiler {
|
||||
private final Map<ShaderKey, CompilationResult> shaderCache = new HashMap<>();
|
||||
private final Consumer<FailedCompilation> errorConsumer;
|
||||
private final Map<ShaderKey, ShaderResult> shaderCache = new HashMap<>();
|
||||
private final CompilerStats stats;
|
||||
private final CompilationFactory factory;
|
||||
private final Includer includer;
|
||||
|
||||
public ShaderCompiler(Consumer<FailedCompilation> errorConsumer, CompilationFactory factory, Includer includer) {
|
||||
this.errorConsumer = errorConsumer;
|
||||
public ShaderCompiler(CompilerStats stats, CompilationFactory factory, Includer includer) {
|
||||
this.stats = stats;
|
||||
this.factory = factory;
|
||||
this.includer = includer;
|
||||
}
|
||||
|
@ -38,31 +37,22 @@ public class ShaderCompiler {
|
|||
return cached.unwrap();
|
||||
}
|
||||
|
||||
CompilationResult out = compileUncached(factory.create(glslVersion, shaderType), sourceComponents);
|
||||
ShaderResult out = compileUncached(factory.create(glslVersion, shaderType), sourceComponents);
|
||||
shaderCache.put(key, out);
|
||||
return unwrapAndReportError(out);
|
||||
stats.shaderResult(out);
|
||||
return out.unwrap();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
shaderCache.values()
|
||||
.stream()
|
||||
.map(CompilationResult::unwrap)
|
||||
.map(ShaderResult::unwrap)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(GlShader::delete);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private GlShader unwrapAndReportError(CompilationResult result) {
|
||||
if (result instanceof CompilationResult.Success s) {
|
||||
return s.shader();
|
||||
} else if (result instanceof CompilationResult.Failure f) {
|
||||
errorConsumer.accept(f.failure());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CompilationResult compileUncached(Compilation ctx, ImmutableList<SourceComponent> sourceComponents) {
|
||||
private ShaderResult compileUncached(Compilation ctx, ImmutableList<SourceComponent> sourceComponents) {
|
||||
ctx.enableExtension("GL_ARB_explicit_attrib_location");
|
||||
ctx.enableExtension("GL_ARB_conservative_depth");
|
||||
|
||||
|
@ -86,15 +76,9 @@ public class ShaderCompiler {
|
|||
}
|
||||
|
||||
public static class Builder {
|
||||
private Consumer<FailedCompilation> errorConsumer = error -> {};
|
||||
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;
|
||||
|
@ -105,8 +89,8 @@ public class ShaderCompiler {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ShaderCompiler build() {
|
||||
return new ShaderCompiler(errorConsumer, factory, includer);
|
||||
public ShaderCompiler build(CompilerStats stats) {
|
||||
return new ShaderCompiler(stats, factory, includer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.gl.shader.GlShader;
|
||||
|
||||
public sealed interface ShaderResult {
|
||||
@Nullable
|
||||
default GlShader unwrap() {
|
||||
if (this instanceof Success s) {
|
||||
return s.shader();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
record Success(GlShader shader, String infoLog) implements ShaderResult {
|
||||
}
|
||||
|
||||
record Failure(FailedCompilation failure) implements ShaderResult {
|
||||
}
|
||||
|
||||
static ShaderResult success(GlShader program, String infoLog) {
|
||||
return new Success(program, infoLog);
|
||||
}
|
||||
|
||||
static ShaderResult failure(FailedCompilation failure) {
|
||||
return new Failure(failure);
|
||||
}
|
||||
}
|
|
@ -15,8 +15,7 @@ import com.jozufozu.flywheel.api.event.RenderStage;
|
|||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwPrograms;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
|
||||
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
|
@ -62,8 +61,9 @@ public class IndirectCullingGroup<I extends Instance> {
|
|||
.quads2Tris(2048).glBuffer;
|
||||
setupVertexArray();
|
||||
|
||||
compute = FlwPrograms.get().getCullingProgram(instanceType);
|
||||
draw = FlwPrograms.get().getPipelineProgram(vertexType, instanceType, Contexts.WORLD, Pipelines.INDIRECT);
|
||||
var indirectPrograms = IndirectPrograms.get();
|
||||
compute = indirectPrograms.getCullingProgram(instanceType);
|
||||
draw = indirectPrograms.getIndirectProgram(vertexType, instanceType, Contexts.WORLD);
|
||||
}
|
||||
|
||||
private void setupVertexArray() {
|
||||
|
|
|
@ -13,8 +13,7 @@ import com.jozufozu.flywheel.api.instance.Instancer;
|
|||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.task.Plan;
|
||||
import com.jozufozu.flywheel.api.task.TaskExecutor;
|
||||
import com.jozufozu.flywheel.backend.compile.FlwPrograms;
|
||||
import com.jozufozu.flywheel.backend.compile.pipeline.Pipelines;
|
||||
import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
|
||||
import com.jozufozu.flywheel.backend.engine.AbstractEngine;
|
||||
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
|
||||
import com.jozufozu.flywheel.gl.GlStateTracker;
|
||||
|
@ -106,7 +105,8 @@ public class InstancingEngine extends AbstractEngine {
|
|||
var vertexType = desc.vertexType();
|
||||
var instanceType = desc.instanceType();
|
||||
|
||||
var program = FlwPrograms.get().getPipelineProgram(vertexType, instanceType, context, Pipelines.INSTANCED_ARRAYS);
|
||||
var program = InstancingPrograms.get()
|
||||
.get(vertexType, instanceType, context);
|
||||
UniformBuffer.syncAndBind(program);
|
||||
|
||||
var uniformLocation = program.getUniformLocation("_flw_materialID_instancing");
|
||||
|
|
Loading…
Reference in a new issue