mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-27 07:26:48 +01:00
A shady API
- Remove storage qualifiers and compile guards from api sources. - Replace api sources with empty stubs by poisoning the ShaderSources cache. - Pipelines redefine the shader api and are inserted at the top of a compilation. - Declare shader api methods in api sources. - Fix crash in ErrorBuilder#pointAtLine
This commit is contained in:
parent
b947470089
commit
d730ab02a9
18 changed files with 243 additions and 91 deletions
|
@ -59,4 +59,28 @@ public class CompilationHarness<K> {
|
|||
public interface KeyCompiler<K> {
|
||||
@Nullable GlProgram compile(K key, SourceLoader loader, ShaderCompiler shaderCompiler, ProgramLinker programLinker);
|
||||
}
|
||||
|
||||
public static class Builder<K> {
|
||||
private final ShaderSources sources;
|
||||
private ImmutableList<K> keys;
|
||||
private KeyCompiler<K> compiler;
|
||||
|
||||
public Builder(ShaderSources sources) {
|
||||
this.sources = sources;
|
||||
}
|
||||
|
||||
public Builder<K> keys(ImmutableList<K> keys) {
|
||||
this.keys = keys;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<K> compiler(KeyCompiler<K> compiler) {
|
||||
this.compiler = compiler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CompilationHarness<K> build() {
|
||||
return new CompilationHarness<>(sources, keys, compiler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,19 +19,34 @@ import com.jozufozu.flywheel.gl.shader.GlProgram;
|
|||
import com.jozufozu.flywheel.gl.shader.GlShader;
|
||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class Compile {
|
||||
public static <K> ShaderCompilerBuilder<K> shader(GLSLVersion glslVersion, ShaderType shaderType) {
|
||||
/**
|
||||
* A typed provider for shader compiler builders.
|
||||
* <br>
|
||||
* This could just be a static utility class, but creating an instance of Compile
|
||||
* and calling the functors on it prevents you from having to specify the key type everywhere.
|
||||
* <br>
|
||||
* Consider {@code Compile.<PipelineKey>shader(...)} vs {@code PIPELINE.shader(...)}
|
||||
*
|
||||
* @param <K> The type of the key used to compile shaders.
|
||||
*/
|
||||
public class Compile<K> {
|
||||
public ShaderCompilerBuilder<K> shader(GLSLVersion glslVersion, ShaderType shaderType) {
|
||||
return new ShaderCompilerBuilder<>(glslVersion, shaderType);
|
||||
}
|
||||
|
||||
public static <K> ProgramLinkBuilder<K> program() {
|
||||
public ProgramLinkBuilder<K> program() {
|
||||
return new ProgramLinkBuilder<>();
|
||||
}
|
||||
|
||||
public CompilationHarness.Builder<K> harness(ShaderSources sources) {
|
||||
return new CompilationHarness.Builder<>(sources);
|
||||
}
|
||||
|
||||
public static class ProgramLinkBuilder<K> implements CompilationHarness.KeyCompiler<K> {
|
||||
private final Map<ShaderType, ShaderCompilerBuilder<K>> compilers = new EnumMap<>(ShaderType.class);
|
||||
private BiConsumer<K, GlProgram> onLink = (k, p) -> {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
|
@ -22,7 +24,8 @@ public class FlwPrograms {
|
|||
}
|
||||
|
||||
public static void reload(ResourceManager resourceManager) {
|
||||
var sources = new ShaderSources(resourceManager);
|
||||
var empty = List.of(Flywheel.rl("api/fragment.glsl"), Flywheel.rl("api/vertex.glsl"));
|
||||
var sources = new ShaderSources(resourceManager, empty);
|
||||
|
||||
var preLoadStats = new CompilerStats();
|
||||
var loadChecker = new SourceLoader(sources, preLoadStats);
|
||||
|
|
|
@ -22,6 +22,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
|
||||
public class IndirectPrograms {
|
||||
public static IndirectPrograms instance;
|
||||
private static final Compile<InstanceType<?>> CULL = new Compile<>();
|
||||
private final Map<PipelineProgramKey, GlProgram> pipeline;
|
||||
private final Map<InstanceType<?>, GlProgram> culling;
|
||||
|
||||
|
@ -74,16 +75,17 @@ public class IndirectPrograms {
|
|||
}
|
||||
|
||||
private static CompilationHarness<InstanceType<?>> createCullingCompiler(UniformComponent uniformComponent, ShaderSources sources) {
|
||||
return new CompilationHarness<>(sources, createCullingKeys(), Compile.<InstanceType<?>>program()
|
||||
.link(Compile.<InstanceType<?>>shader(GLSLVersion.V460, ShaderType.COMPUTE)
|
||||
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
||||
.withComponent(uniformComponent)
|
||||
.withComponent(IndirectComponent::create)
|
||||
.withResource(InstanceType::instanceShader)
|
||||
.withResource(Files.INDIRECT_CULL))
|
||||
.then((InstanceType<?> key, GlProgram program) -> {
|
||||
program.setUniformBlockBinding("FLWUniforms", 0);
|
||||
}));
|
||||
return CULL.harness(sources)
|
||||
.keys(createCullingKeys())
|
||||
.compiler(CULL.program()
|
||||
.link(CULL.shader(GLSLVersion.V460, ShaderType.COMPUTE)
|
||||
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
||||
.withComponent(uniformComponent)
|
||||
.withComponent(IndirectComponent::create)
|
||||
.withResource(Files.INDIRECT_CULL)
|
||||
.withResource(InstanceType::instanceShader))
|
||||
.then((key, program) -> program.setUniformBlockBinding("FLWUniforms", 0)))
|
||||
.build();
|
||||
}
|
||||
|
||||
public GlProgram getIndirectProgram(VertexType vertexType, InstanceType<?> instanceType, Context contextShader) {
|
||||
|
|
|
@ -2,12 +2,12 @@ package com.jozufozu.flywheel.backend.compile;
|
|||
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.compile.Pipeline.InstanceAssembler;
|
||||
import com.jozufozu.flywheel.glsl.GLSLVersion;
|
||||
import com.jozufozu.flywheel.glsl.SourceComponent;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
// TODO: move shader api redefinition to a separate file?
|
||||
public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, ResourceLocation fragmentShader, InstanceAssembler assembler) {
|
||||
@FunctionalInterface
|
||||
public interface InstanceAssembler {
|
||||
|
|
|
@ -3,36 +3,40 @@ package com.jozufozu.flywheel.backend.compile;
|
|||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.backend.compile.component.MaterialAdapterComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
|
||||
import com.jozufozu.flywheel.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.gl.shader.ShaderType;
|
||||
import com.jozufozu.flywheel.glsl.ShaderSources;
|
||||
|
||||
public class PipelineCompiler {
|
||||
private static final Compile<PipelineProgramKey> PIPELINE = new Compile<>();
|
||||
|
||||
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, ImmutableList<PipelineProgramKey> pipelineKeys, UniformComponent uniformComponent, MaterialAdapterComponent vertexMaterialComponent, MaterialAdapterComponent fragmentMaterialComponent) {
|
||||
return new CompilationHarness<>(sources, pipelineKeys, Compile.<PipelineProgramKey>program()
|
||||
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.VERTEX)
|
||||
.withComponent(uniformComponent)
|
||||
.withComponent(vertexMaterialComponent)
|
||||
.withComponent(key -> pipeline.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType())))
|
||||
.withResource(key -> key.vertexType()
|
||||
.layoutShader())
|
||||
.withResource(key -> key.instanceType()
|
||||
.instanceShader())
|
||||
.withResource(key -> key.contextShader()
|
||||
.vertexShader())
|
||||
.withResource(pipeline.vertexShader()))
|
||||
.link(Compile.<PipelineProgramKey>shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
||||
.enableExtension("GL_ARB_conservative_depth")
|
||||
.withComponent(uniformComponent)
|
||||
.withComponent(fragmentMaterialComponent)
|
||||
.withResource(key -> key.contextShader()
|
||||
.fragmentShader())
|
||||
.withResource(pipeline.fragmentShader()))
|
||||
.then((PipelineProgramKey key, GlProgram program) -> {
|
||||
key.contextShader()
|
||||
.onProgramLink(program);
|
||||
program.setUniformBlockBinding("FLWUniforms", 0);
|
||||
}));
|
||||
return PIPELINE.harness(sources)
|
||||
.keys(pipelineKeys)
|
||||
.compiler(PIPELINE.program()
|
||||
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.VERTEX)
|
||||
.withComponent(uniformComponent)
|
||||
.withComponent(key -> pipeline.assembler()
|
||||
.assemble(new Pipeline.InstanceAssemblerContext(key.vertexType(), key.instanceType())))
|
||||
.withResource(pipeline.vertexShader())
|
||||
.withComponent(vertexMaterialComponent)
|
||||
.withResource(key -> key.vertexType()
|
||||
.layoutShader())
|
||||
.withResource(key -> key.instanceType()
|
||||
.instanceShader())
|
||||
.withResource(key -> key.contextShader()
|
||||
.vertexShader()))
|
||||
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
||||
.enableExtension("GL_ARB_conservative_depth")
|
||||
.withComponent(uniformComponent)
|
||||
.withResource(pipeline.fragmentShader())
|
||||
.withComponent(fragmentMaterialComponent)
|
||||
.withResource(key -> key.contextShader()
|
||||
.fragmentShader()))
|
||||
.then((key, program) -> {
|
||||
key.contextShader()
|
||||
.onProgramLink(program);
|
||||
program.setUniformBlockBinding("FLWUniforms", 0);
|
||||
}))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
|
||||
public class SourceLoader {
|
||||
|
||||
public final ShaderSources sources;
|
||||
private final ShaderSources sources;
|
||||
private final CompilerStats stats;
|
||||
|
||||
public SourceLoader(ShaderSources sources, CompilerStats stats) {
|
||||
|
|
|
@ -35,6 +35,18 @@ public class ShaderSources {
|
|||
this.manager = manager;
|
||||
}
|
||||
|
||||
public ShaderSources(ResourceManager manager, Map<ResourceLocation, LoadResult> preloadCache) {
|
||||
this.manager = manager;
|
||||
cache.putAll(preloadCache);
|
||||
}
|
||||
|
||||
public ShaderSources(ResourceManager manager, List<ResourceLocation> preloadEmpty) {
|
||||
this.manager = manager;
|
||||
for (ResourceLocation rl : preloadEmpty) {
|
||||
cache.put(rl, SourceFile.empty(rl));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public LoadResult find(ResourceLocation location) {
|
||||
if (findStack.contains(location)) {
|
||||
|
|
|
@ -67,6 +67,10 @@ public class SourceFile implements SourceComponent {
|
|||
this.finalSource = finalSource;
|
||||
}
|
||||
|
||||
public static LoadResult empty(ResourceLocation name) {
|
||||
return new LoadResult.Success(new SourceFile(name, new SourceLines(name, ""), ImmutableMap.of(), ImmutableMap.of(), ImmutableList.of(), ImmutableMap.of(), ImmutableList.of(), ""));
|
||||
}
|
||||
|
||||
public static LoadResult parse(ShaderSources sourceFinder, ResourceLocation name, String stringSource) {
|
||||
var source = new SourceLines(name, stringSource);
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ public class ErrorBuilder {
|
|||
|
||||
public ErrorBuilder pointAtLine(SourceLines lines, int spanLine, int ctxLines, int firstCol, int lastCol) {
|
||||
int firstLine = Math.max(0, spanLine - ctxLines);
|
||||
int lastLine = Math.min(lines.count(), spanLine + ctxLines);
|
||||
int lastLine = Math.min(lines.count() - 1, spanLine + ctxLines);
|
||||
|
||||
|
||||
for (int i = firstLine; i <= lastLine; i++) {
|
||||
|
|
|
@ -1,22 +1,16 @@
|
|||
#ifdef FRAGMENT_SHADER
|
||||
in vec4 flw_vertexPos;
|
||||
in vec4 flw_vertexColor;
|
||||
in vec2 flw_vertexTexCoord;
|
||||
flat in ivec2 flw_vertexOverlay;
|
||||
in vec2 flw_vertexLight;
|
||||
in vec3 flw_vertexNormal;
|
||||
/*const*/ vec4 flw_vertexPos;
|
||||
/*const*/ vec4 flw_vertexColor;
|
||||
/*const*/ vec2 flw_vertexTexCoord;
|
||||
/*const*/ ivec2 flw_vertexOverlay;
|
||||
/*const*/ vec2 flw_vertexLight;
|
||||
/*const*/ vec3 flw_vertexNormal;
|
||||
|
||||
in float flw_distance;
|
||||
/*const*/ float flw_distance;
|
||||
|
||||
in vec4 flw_var0;
|
||||
in vec4 flw_var1;
|
||||
in vec4 flw_var2;
|
||||
in vec4 flw_var3;
|
||||
|
||||
flat in uint _flw_materialFragmentID;
|
||||
flat in uint _flw_packedMaterialProperties;
|
||||
|
||||
//
|
||||
/*const*/ vec4 flw_var0;
|
||||
/*const*/ vec4 flw_var1;
|
||||
/*const*/ vec4 flw_var2;
|
||||
/*const*/ vec4 flw_var3;
|
||||
|
||||
/*const*/ vec4 flw_sampleColor;
|
||||
|
||||
|
@ -24,13 +18,11 @@ vec4 flw_fragColor;
|
|||
ivec2 flw_fragOverlay;
|
||||
vec2 flw_fragLight;
|
||||
|
||||
/*
|
||||
* Must be implemented by materials.
|
||||
*/
|
||||
// To be implemented by material shaders.
|
||||
vec4 flw_fogFilter(vec4 color);
|
||||
|
||||
/*
|
||||
* Must be implemented by materials.
|
||||
*/
|
||||
bool flw_discardPredicate(vec4 finalColor);
|
||||
#endif
|
||||
void flw_materialFragment();
|
||||
|
||||
// To be implemented by the context shader.
|
||||
void flw_initFragment();
|
||||
void flw_contextFragment();
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
#ifdef VERTEX_SHADER
|
||||
uint _flw_materialVertexID;
|
||||
vec4 flw_vertexPos;
|
||||
vec4 flw_vertexColor;
|
||||
vec2 flw_vertexTexCoord;
|
||||
ivec2 flw_vertexOverlay;
|
||||
vec2 flw_vertexLight;
|
||||
vec3 flw_vertexNormal;
|
||||
|
||||
out vec4 flw_vertexPos;
|
||||
out vec4 flw_vertexColor;
|
||||
out vec2 flw_vertexTexCoord;
|
||||
flat out ivec2 flw_vertexOverlay;
|
||||
out vec2 flw_vertexLight;
|
||||
out vec3 flw_vertexNormal;
|
||||
float flw_distance;
|
||||
|
||||
out float flw_distance;
|
||||
vec4 flw_var0;
|
||||
vec4 flw_var1;
|
||||
vec4 flw_var2;
|
||||
vec4 flw_var3;
|
||||
|
||||
out vec4 flw_var0;
|
||||
out vec4 flw_var1;
|
||||
out vec4 flw_var2;
|
||||
out vec4 flw_var3;
|
||||
flat out uint _flw_materialFragmentID;
|
||||
flat out uint _flw_packedMaterialProperties;
|
||||
#endif
|
||||
// To be implemented by the layout shader.
|
||||
void flw_layoutVertex();
|
||||
|
||||
// To be implemented by the instance shader.
|
||||
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius);
|
||||
void flw_instanceVertex(FlwInstance i);
|
||||
|
||||
// To be implemented by material shaders.
|
||||
void flw_materialVertex();
|
||||
|
||||
// To be implemented by the context shader.
|
||||
void flw_initVertex();
|
||||
void flw_contextVertex();
|
||||
|
|
|
@ -9,11 +9,9 @@ void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout floa
|
|||
center = rotateVertexByQuat(center - pivot, rotation) + pivot + pos;
|
||||
}
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
void flw_instanceVertex(in FlwInstance i) {
|
||||
flw_vertexPos = vec4(rotateVertexByQuat(flw_vertexPos.xyz - i.pivot, i.rotation) + i.pivot + i.position, 1.0);
|
||||
flw_vertexNormal = rotateVertexByQuat(flw_vertexNormal, i.rotation);
|
||||
flw_vertexColor = i.color;
|
||||
flw_vertexLight = i.light / 15.0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -8,11 +8,9 @@ void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout floa
|
|||
radius *= scale;
|
||||
}
|
||||
|
||||
#ifdef VERTEX_SHADER
|
||||
void flw_instanceVertex(in FlwInstance i) {
|
||||
flw_vertexPos = i.pose * flw_vertexPos;
|
||||
flw_vertexNormal = i.normal * flw_vertexNormal;
|
||||
flw_vertexColor = i.color;
|
||||
flw_vertexLight = i.light / 15.0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,33 @@
|
|||
#include "flywheel:api/fragment.glsl"
|
||||
in vec4 flw_vertexPos;
|
||||
in vec4 flw_vertexColor;
|
||||
in vec2 flw_vertexTexCoord;
|
||||
flat in ivec2 flw_vertexOverlay;
|
||||
in vec2 flw_vertexLight;
|
||||
in vec3 flw_vertexNormal;
|
||||
|
||||
in float flw_distance;
|
||||
|
||||
in vec4 flw_var0;
|
||||
in vec4 flw_var1;
|
||||
in vec4 flw_var2;
|
||||
in vec4 flw_var3;
|
||||
|
||||
flat in uint _flw_materialFragmentID;
|
||||
flat in uint _flw_packedMaterialProperties;
|
||||
|
||||
vec4 flw_sampleColor;
|
||||
|
||||
vec4 flw_fragColor;
|
||||
ivec2 flw_fragOverlay;
|
||||
vec2 flw_fragLight;
|
||||
|
||||
vec4 flw_fogFilter(vec4 color);
|
||||
|
||||
bool flw_discardPredicate(vec4 finalColor);
|
||||
|
||||
void flw_initFragment();
|
||||
void flw_materialFragment();
|
||||
void flw_contextFragment();
|
||||
|
||||
void main() {
|
||||
flw_initFragment();
|
||||
|
|
|
@ -2,6 +2,21 @@ layout(local_size_x = FLW_SUBGROUP_SIZE) in;
|
|||
|
||||
#include "flywheel:internal/indirect_draw_command.glsl"
|
||||
|
||||
// need to add stubs so the instance shader compiles.
|
||||
vec4 flw_vertexPos;
|
||||
vec4 flw_vertexColor;
|
||||
vec2 flw_vertexTexCoord;
|
||||
ivec2 flw_vertexOverlay;
|
||||
vec2 flw_vertexLight;
|
||||
vec3 flw_vertexNormal;
|
||||
float flw_distance;
|
||||
vec4 flw_var0;
|
||||
vec4 flw_var1;
|
||||
vec4 flw_var2;
|
||||
vec4 flw_var3;
|
||||
|
||||
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius);
|
||||
|
||||
struct Object {
|
||||
uint batchID;
|
||||
FlwPackedInstance instance;
|
||||
|
|
|
@ -1,6 +1,23 @@
|
|||
#include "flywheel:api/vertex.glsl"
|
||||
#include "flywheel:internal/indirect_draw_command.glsl"
|
||||
|
||||
out vec4 flw_vertexPos;
|
||||
out vec4 flw_vertexColor;
|
||||
out vec2 flw_vertexTexCoord;
|
||||
flat out ivec2 flw_vertexOverlay;
|
||||
out vec2 flw_vertexLight;
|
||||
out vec3 flw_vertexNormal;
|
||||
|
||||
out float flw_distance;
|
||||
|
||||
out vec4 flw_var0;
|
||||
out vec4 flw_var1;
|
||||
out vec4 flw_var2;
|
||||
out vec4 flw_var3;
|
||||
|
||||
uint _flw_materialVertexID;
|
||||
flat out uint _flw_materialFragmentID;
|
||||
flat out uint _flw_packedMaterialProperties;
|
||||
|
||||
struct Object {
|
||||
uint batchID;
|
||||
FlwPackedInstance instance;
|
||||
|
@ -19,6 +36,14 @@ layout(std430, binding = 2) restrict readonly buffer DrawCommands {
|
|||
MeshDrawCommand drawCommands[];
|
||||
};
|
||||
|
||||
FlwInstance _flw_unpackInstance(FlwPackedInstance i);
|
||||
|
||||
void flw_layoutVertex();
|
||||
void flw_initVertex();
|
||||
void flw_instanceVertex(FlwInstance i);
|
||||
void flw_materialVertex();
|
||||
void flw_contextVertex();
|
||||
|
||||
void main() {
|
||||
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
|
||||
uint batchID = objects[instanceIndex].batchID;
|
||||
|
|
|
@ -1,7 +1,30 @@
|
|||
#include "flywheel:api/vertex.glsl"
|
||||
out vec4 flw_vertexPos;
|
||||
out vec4 flw_vertexColor;
|
||||
out vec2 flw_vertexTexCoord;
|
||||
flat out ivec2 flw_vertexOverlay;
|
||||
out vec2 flw_vertexLight;
|
||||
out vec3 flw_vertexNormal;
|
||||
|
||||
out float flw_distance;
|
||||
|
||||
out vec4 flw_var0;
|
||||
out vec4 flw_var1;
|
||||
out vec4 flw_var2;
|
||||
out vec4 flw_var3;
|
||||
|
||||
uint _flw_materialVertexID;
|
||||
flat out uint _flw_materialFragmentID;
|
||||
flat out uint _flw_packedMaterialProperties;
|
||||
|
||||
|
||||
uniform uvec3 _flw_material_instancing;
|
||||
|
||||
void flw_layoutVertex();
|
||||
void flw_initVertex();
|
||||
void flw_instanceVertex(FlwInstance i);
|
||||
void flw_materialVertex();
|
||||
void flw_contextVertex();
|
||||
|
||||
void main() {
|
||||
_flw_materialVertexID = _flw_material_instancing.x;
|
||||
_flw_materialFragmentID = _flw_material_instancing.y;
|
||||
|
|
Loading…
Reference in a new issue