mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-05 01:34:58 +01:00
GLSL to the max
- Always compile with highest supported GLSL version - Allow indirect shaders to compile with as low as GLSL 420 - Fix GL extension checks for indirect - Explicitly initialize GlCompat as early as possible to avoid invalid initialization off render thread
This commit is contained in:
parent
08476b5779
commit
2ee3944ca6
11 changed files with 251 additions and 166 deletions
|
@ -17,7 +17,7 @@ public final class Backends {
|
||||||
*/
|
*/
|
||||||
public static final Backend INSTANCING = SimpleBackend.builder()
|
public static final Backend INSTANCING = SimpleBackend.builder()
|
||||||
.engineFactory(level -> new EngineImpl(new InstancedDrawManager(InstancingPrograms.get()), 256))
|
.engineFactory(level -> new EngineImpl(new InstancedDrawManager(InstancingPrograms.get()), 256))
|
||||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsInstancing() && InstancingPrograms.allLoaded())
|
.supported(() -> GlCompat.SUPPORTS_INSTANCING && InstancingPrograms.allLoaded() && !ShadersModHandler.isShaderPackInUse())
|
||||||
.register(Flywheel.rl("instancing"));
|
.register(Flywheel.rl("instancing"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,7 +26,7 @@ public final class Backends {
|
||||||
public static final Backend INDIRECT = SimpleBackend.builder()
|
public static final Backend INDIRECT = SimpleBackend.builder()
|
||||||
.engineFactory(level -> new EngineImpl(new IndirectDrawManager(IndirectPrograms.get()), 256))
|
.engineFactory(level -> new EngineImpl(new IndirectDrawManager(IndirectPrograms.get()), 256))
|
||||||
.fallback(() -> Backends.INSTANCING)
|
.fallback(() -> Backends.INSTANCING)
|
||||||
.supported(() -> !ShadersModHandler.isShaderPackInUse() && GlCompat.supportsIndirect() && IndirectPrograms.allLoaded())
|
.supported(() -> GlCompat.SUPPORTS_INDIRECT && IndirectPrograms.allLoaded() && !ShadersModHandler.isShaderPackInUse())
|
||||||
.register(Flywheel.rl("indirect"));
|
.register(Flywheel.rl("indirect"));
|
||||||
|
|
||||||
private Backends() {
|
private Backends() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.jozufozu.flywheel.backend.compile;
|
package com.jozufozu.flywheel.backend.compile;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -33,6 +34,9 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
private static final Compile<InstanceType<?>> CULL = new Compile<>();
|
private static final Compile<InstanceType<?>> CULL = new Compile<>();
|
||||||
private static final Compile<ResourceLocation> UTIL = new Compile<>();
|
private static final Compile<ResourceLocation> UTIL = new Compile<>();
|
||||||
|
|
||||||
|
private static final List<String> EXTENSIONS = getExtensions(GlCompat.MAX_GLSL_VERSION);
|
||||||
|
private static final List<String> COMPUTE_EXTENSIONS = getComputeExtensions(GlCompat.MAX_GLSL_VERSION);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static IndirectPrograms instance;
|
private static IndirectPrograms instance;
|
||||||
|
|
||||||
|
@ -48,10 +52,33 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
this.scatter = scatter;
|
this.scatter = scatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<String> getExtensions(GlslVersion glslVersion) {
|
||||||
|
List<String> extensions = new ArrayList<>();
|
||||||
|
if (glslVersion.compareTo(GlslVersion.V430) < 0) {
|
||||||
|
extensions.add("GL_ARB_shader_storage_buffer_object");
|
||||||
|
}
|
||||||
|
if (glslVersion.compareTo(GlslVersion.V460) < 0) {
|
||||||
|
extensions.add("GL_ARB_shader_draw_parameters");
|
||||||
|
}
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> getComputeExtensions(GlslVersion glslVersion) {
|
||||||
|
List<String> extensions = new ArrayList<>();
|
||||||
|
if (glslVersion.compareTo(GlslVersion.V430) < 0) {
|
||||||
|
extensions.add("GL_ARB_compute_shader");
|
||||||
|
}
|
||||||
|
return extensions;
|
||||||
|
}
|
||||||
|
|
||||||
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
|
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
|
||||||
|
if (!GlCompat.SUPPORTS_INDIRECT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IndirectPrograms newInstance = null;
|
IndirectPrograms newInstance = null;
|
||||||
|
|
||||||
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, vertexComponents, fragmentComponents);
|
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, vertexComponents, fragmentComponents, EXTENSIONS);
|
||||||
var cullingCompiler = createCullingCompiler(sources);
|
var cullingCompiler = createCullingCompiler(sources);
|
||||||
var applyCompiler = createUtilCompiler(sources);
|
var applyCompiler = createUtilCompiler(sources);
|
||||||
|
|
||||||
|
@ -76,8 +103,10 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
|
|
||||||
private static CompilationHarness<InstanceType<?>> createCullingCompiler(ShaderSources sources) {
|
private static CompilationHarness<InstanceType<?>> createCullingCompiler(ShaderSources sources) {
|
||||||
return CULL.program()
|
return CULL.program()
|
||||||
.link(CULL.shader(GlslVersion.V460, ShaderType.COMPUTE)
|
.link(CULL.shader(GlCompat.MAX_GLSL_VERSION, ShaderType.COMPUTE)
|
||||||
.nameMapper(instanceType -> "culling/" + ResourceUtil.toDebugFileNameNoExtension(instanceType.cullShader()))
|
.nameMapper(instanceType -> "culling/" + ResourceUtil.toDebugFileNameNoExtension(instanceType.cullShader()))
|
||||||
|
.enableExtensions(EXTENSIONS)
|
||||||
|
.enableExtensions(COMPUTE_EXTENSIONS)
|
||||||
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
||||||
.withResource(CULL_SHADER_API_IMPL)
|
.withResource(CULL_SHADER_API_IMPL)
|
||||||
.withComponent(InstanceStructComponent::new)
|
.withComponent(InstanceStructComponent::new)
|
||||||
|
@ -96,8 +125,10 @@ public class IndirectPrograms extends AtomicReferenceCounted {
|
||||||
|
|
||||||
private static CompilationHarness<ResourceLocation> createUtilCompiler(ShaderSources sources) {
|
private static CompilationHarness<ResourceLocation> createUtilCompiler(ShaderSources sources) {
|
||||||
return UTIL.program()
|
return UTIL.program()
|
||||||
.link(UTIL.shader(GlslVersion.V460, ShaderType.COMPUTE)
|
.link(UTIL.shader(GlCompat.MAX_GLSL_VERSION, ShaderType.COMPUTE)
|
||||||
.nameMapper(resourceLocation -> "utilities/" + ResourceUtil.toDebugFileNameNoExtension(resourceLocation))
|
.nameMapper(resourceLocation -> "utilities/" + ResourceUtil.toDebugFileNameNoExtension(resourceLocation))
|
||||||
|
.enableExtensions(EXTENSIONS)
|
||||||
|
.enableExtensions(COMPUTE_EXTENSIONS)
|
||||||
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
|
||||||
.withResource(s -> s))
|
.withResource(s -> s))
|
||||||
.harness("utilities", sources);
|
.harness("utilities", sources);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GlCompat;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.backend.glsl.ShaderSources;
|
import com.jozufozu.flywheel.backend.glsl.ShaderSources;
|
||||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||||
|
@ -23,6 +24,10 @@ public class InstancingPrograms extends AtomicReferenceCounted {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
|
static void reload(ShaderSources sources, ImmutableList<PipelineProgramKey> pipelineKeys, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
|
||||||
|
if (!GlCompat.SUPPORTS_INSTANCING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
InstancingPrograms newInstance = null;
|
InstancingPrograms newInstance = null;
|
||||||
|
|
||||||
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCING, vertexComponents, fragmentComponents);
|
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INSTANCING, vertexComponents, fragmentComponents);
|
||||||
|
|
|
@ -8,12 +8,11 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import com.jozufozu.flywheel.api.instance.Instance;
|
import com.jozufozu.flywheel.api.instance.Instance;
|
||||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.backend.glsl.GlslVersion;
|
|
||||||
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
import com.jozufozu.flywheel.backend.glsl.SourceComponent;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, ResourceLocation fragmentMain,
|
public record Pipeline(ResourceLocation vertexMain, ResourceLocation fragmentMain,
|
||||||
InstanceAssembler assembler, String compilerMarker, Consumer<GlProgram> onLink) {
|
InstanceAssembler assembler, String compilerMarker, Consumer<GlProgram> onLink) {
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
|
@ -31,8 +30,6 @@ public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, Res
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
@Nullable
|
|
||||||
private GlslVersion glslVersion;
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ResourceLocation vertexMain;
|
private ResourceLocation vertexMain;
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -44,11 +41,6 @@ public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, Res
|
||||||
@Nullable
|
@Nullable
|
||||||
private Consumer<GlProgram> onLink;
|
private Consumer<GlProgram> onLink;
|
||||||
|
|
||||||
public Builder glslVersion(GlslVersion glslVersion) {
|
|
||||||
this.glslVersion = glslVersion;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder vertexMain(ResourceLocation shader) {
|
public Builder vertexMain(ResourceLocation shader) {
|
||||||
this.vertexMain = shader;
|
this.vertexMain = shader;
|
||||||
return this;
|
return this;
|
||||||
|
@ -75,13 +67,12 @@ public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, Res
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pipeline build() {
|
public Pipeline build() {
|
||||||
Objects.requireNonNull(glslVersion);
|
|
||||||
Objects.requireNonNull(vertexMain);
|
Objects.requireNonNull(vertexMain);
|
||||||
Objects.requireNonNull(fragmentMain);
|
Objects.requireNonNull(fragmentMain);
|
||||||
Objects.requireNonNull(assembler);
|
Objects.requireNonNull(assembler);
|
||||||
Objects.requireNonNull(compilerMarker);
|
Objects.requireNonNull(compilerMarker);
|
||||||
Objects.requireNonNull(onLink);
|
Objects.requireNonNull(onLink);
|
||||||
return new Pipeline(glslVersion, vertexMain, fragmentMain, assembler, compilerMarker, onLink);
|
return new Pipeline(vertexMain, fragmentMain, assembler, compilerMarker, onLink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.jozufozu.flywheel.backend.compile;
|
package com.jozufozu.flywheel.backend.compile;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.Flywheel;
|
import com.jozufozu.flywheel.Flywheel;
|
||||||
|
@ -9,6 +11,7 @@ import com.jozufozu.flywheel.backend.compile.component.InstanceStructComponent;
|
||||||
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
|
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
|
||||||
import com.jozufozu.flywheel.backend.compile.core.Compile;
|
import com.jozufozu.flywheel.backend.compile.core.Compile;
|
||||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GlCompat;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||||
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
import com.jozufozu.flywheel.backend.gl.shader.ShaderType;
|
||||||
import com.jozufozu.flywheel.backend.glsl.ShaderSources;
|
import com.jozufozu.flywheel.backend.glsl.ShaderSources;
|
||||||
|
@ -23,9 +26,9 @@ public final class PipelineCompiler {
|
||||||
private static final ResourceLocation API_IMPL_VERT = Flywheel.rl("internal/api_impl.vert");
|
private static final ResourceLocation API_IMPL_VERT = Flywheel.rl("internal/api_impl.vert");
|
||||||
private static final ResourceLocation API_IMPL_FRAG = Flywheel.rl("internal/api_impl.frag");
|
private static final ResourceLocation API_IMPL_FRAG = Flywheel.rl("internal/api_impl.frag");
|
||||||
|
|
||||||
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
|
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents, Collection<String> extensions) {
|
||||||
return PIPELINE.program()
|
return PIPELINE.program()
|
||||||
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.VERTEX)
|
.link(PIPELINE.shader(GlCompat.MAX_GLSL_VERSION, ShaderType.VERTEX)
|
||||||
.nameMapper(key -> {
|
.nameMapper(key -> {
|
||||||
var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
|
var instance = ResourceUtil.toDebugFileNameNoExtension(key.instanceType()
|
||||||
.vertexShader());
|
.vertexShader());
|
||||||
|
@ -34,6 +37,7 @@ public final class PipelineCompiler {
|
||||||
.nameLowerCase();
|
.nameLowerCase();
|
||||||
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context;
|
return "pipeline/" + pipeline.compilerMarker() + "/" + instance + "_" + context;
|
||||||
})
|
})
|
||||||
|
.enableExtensions(extensions)
|
||||||
.onCompile((key, comp) -> key.contextShader()
|
.onCompile((key, comp) -> key.contextShader()
|
||||||
.onCompile(comp))
|
.onCompile(comp))
|
||||||
.withResource(API_IMPL_VERT)
|
.withResource(API_IMPL_VERT)
|
||||||
|
@ -45,12 +49,13 @@ public final class PipelineCompiler {
|
||||||
.withComponent(key -> pipeline.assembler()
|
.withComponent(key -> pipeline.assembler()
|
||||||
.assemble(key.instanceType()))
|
.assemble(key.instanceType()))
|
||||||
.withResource(pipeline.vertexMain()))
|
.withResource(pipeline.vertexMain()))
|
||||||
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
|
.link(PIPELINE.shader(GlCompat.MAX_GLSL_VERSION, ShaderType.FRAGMENT)
|
||||||
.nameMapper(key -> {
|
.nameMapper(key -> {
|
||||||
var context = key.contextShader()
|
var context = key.contextShader()
|
||||||
.nameLowerCase();
|
.nameLowerCase();
|
||||||
return "pipeline/" + pipeline.compilerMarker() + "/" + context;
|
return "pipeline/" + pipeline.compilerMarker() + "/" + context;
|
||||||
})
|
})
|
||||||
|
.enableExtensions(extensions)
|
||||||
.enableExtension("GL_ARB_conservative_depth")
|
.enableExtension("GL_ARB_conservative_depth")
|
||||||
.onCompile((key, comp) -> key.contextShader()
|
.onCompile((key, comp) -> key.contextShader()
|
||||||
.onCompile(comp))
|
.onCompile(comp))
|
||||||
|
@ -86,4 +91,8 @@ public final class PipelineCompiler {
|
||||||
})
|
})
|
||||||
.harness(pipeline.compilerMarker(), sources);
|
.harness(pipeline.compilerMarker(), sources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CompilationHarness<PipelineProgramKey> create(ShaderSources sources, Pipeline pipeline, List<SourceComponent> vertexComponents, List<SourceComponent> fragmentComponents) {
|
||||||
|
return create(sources, pipeline, vertexComponents, fragmentComponents, Collections.emptyList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,10 @@ import com.jozufozu.flywheel.Flywheel;
|
||||||
import com.jozufozu.flywheel.backend.Samplers;
|
import com.jozufozu.flywheel.backend.Samplers;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.BufferTextureInstanceComponent;
|
import com.jozufozu.flywheel.backend.compile.component.BufferTextureInstanceComponent;
|
||||||
import com.jozufozu.flywheel.backend.compile.component.SsboInstanceComponent;
|
import com.jozufozu.flywheel.backend.compile.component.SsboInstanceComponent;
|
||||||
import com.jozufozu.flywheel.backend.glsl.GlslVersion;
|
|
||||||
|
|
||||||
public final class Pipelines {
|
public final class Pipelines {
|
||||||
public static final Pipeline INSTANCING = Pipeline.builder()
|
public static final Pipeline INSTANCING = Pipeline.builder()
|
||||||
.compilerMarker("instancing")
|
.compilerMarker("instancing")
|
||||||
.glslVersion(GlslVersion.V330)
|
|
||||||
.vertexMain(Flywheel.rl("internal/instancing/main.vert"))
|
.vertexMain(Flywheel.rl("internal/instancing/main.vert"))
|
||||||
.fragmentMain(Flywheel.rl("internal/instancing/main.frag"))
|
.fragmentMain(Flywheel.rl("internal/instancing/main.frag"))
|
||||||
.assembler(BufferTextureInstanceComponent::new)
|
.assembler(BufferTextureInstanceComponent::new)
|
||||||
|
@ -18,7 +16,6 @@ public final class Pipelines {
|
||||||
|
|
||||||
public static final Pipeline INDIRECT = Pipeline.builder()
|
public static final Pipeline INDIRECT = Pipeline.builder()
|
||||||
.compilerMarker("indirect")
|
.compilerMarker("indirect")
|
||||||
.glslVersion(GlslVersion.V460)
|
|
||||||
.vertexMain(Flywheel.rl("internal/indirect/main.vert"))
|
.vertexMain(Flywheel.rl("internal/indirect/main.vert"))
|
||||||
.fragmentMain(Flywheel.rl("internal/indirect/main.frag"))
|
.fragmentMain(Flywheel.rl("internal/indirect/main.frag"))
|
||||||
.assembler(SsboInstanceComponent::new)
|
.assembler(SsboInstanceComponent::new)
|
||||||
|
|
|
@ -40,6 +40,100 @@ public class Compile<K> {
|
||||||
return new ProgramStitcher<>();
|
return new ProgramStitcher<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ShaderCompiler<K> {
|
||||||
|
private final GlslVersion glslVersion;
|
||||||
|
private final ShaderType shaderType;
|
||||||
|
private final List<BiFunction<K, SourceLoader, @Nullable SourceComponent>> fetchers = new ArrayList<>();
|
||||||
|
private BiConsumer<K, Compilation> compilationCallbacks = ($, $$) -> {
|
||||||
|
};
|
||||||
|
private Function<K, String> nameMapper = Object::toString;
|
||||||
|
|
||||||
|
public ShaderCompiler(GlslVersion glslVersion, ShaderType shaderType) {
|
||||||
|
this.glslVersion = glslVersion;
|
||||||
|
this.shaderType = shaderType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> nameMapper(Function<K, String> nameMapper) {
|
||||||
|
this.nameMapper = nameMapper;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> with(BiFunction<K, SourceLoader, @Nullable SourceComponent> fetch) {
|
||||||
|
fetchers.add(fetch);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> withComponents(Collection<@Nullable SourceComponent> components) {
|
||||||
|
components.forEach(this::withComponent);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> withComponent(@Nullable SourceComponent component) {
|
||||||
|
return withComponent($ -> component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> withComponent(Function<K, @Nullable SourceComponent> sourceFetcher) {
|
||||||
|
return with((key, $) -> sourceFetcher.apply(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> withResource(Function<K, ResourceLocation> sourceFetcher) {
|
||||||
|
return with((key, loader) -> loader.find(sourceFetcher.apply(key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> withResource(ResourceLocation resourceLocation) {
|
||||||
|
return withResource($ -> resourceLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> onCompile(BiConsumer<K, Compilation> cb) {
|
||||||
|
compilationCallbacks = compilationCallbacks.andThen(cb);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> define(String def, int value) {
|
||||||
|
return onCompile(($, ctx) -> ctx.define(def, String.valueOf(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> enableExtension(String extension) {
|
||||||
|
return onCompile(($, ctx) -> ctx.enableExtension(extension));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> enableExtensions(String... extensions) {
|
||||||
|
return onCompile(($, ctx) -> {
|
||||||
|
for (String extension : extensions) {
|
||||||
|
ctx.enableExtension(extension);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ShaderCompiler<K> enableExtensions(Collection<String> extensions) {
|
||||||
|
return onCompile(($, ctx) -> {
|
||||||
|
for (String extension : extensions) {
|
||||||
|
ctx.enableExtension(extension);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private GlShader compile(K key, ShaderCache compiler, SourceLoader loader) {
|
||||||
|
var components = new ArrayList<SourceComponent>();
|
||||||
|
boolean ok = true;
|
||||||
|
for (var fetcher : fetchers) {
|
||||||
|
SourceComponent apply = fetcher.apply(key, loader);
|
||||||
|
if (apply == null) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
components.add(apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Consumer<Compilation> cb = ctx -> compilationCallbacks.accept(key, ctx);
|
||||||
|
return compiler.compile(glslVersion, shaderType, nameMapper.apply(key), cb, components);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class ProgramStitcher<K> implements CompilationHarness.KeyCompiler<K> {
|
public static class ProgramStitcher<K> implements CompilationHarness.KeyCompiler<K> {
|
||||||
private final Map<ShaderType, ShaderCompiler<K>> compilers = new EnumMap<>(ShaderType.class);
|
private final Map<ShaderType, ShaderCompiler<K>> compilers = new EnumMap<>(ShaderType.class);
|
||||||
private BiConsumer<K, GlProgram> postLink = (k, p) -> {
|
private BiConsumer<K, GlProgram> postLink = (k, p) -> {
|
||||||
|
@ -100,82 +194,4 @@ public class Compile<K> {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ShaderCompiler<K> {
|
|
||||||
private final GlslVersion glslVersion;
|
|
||||||
private final ShaderType shaderType;
|
|
||||||
private final List<BiFunction<K, SourceLoader, @Nullable SourceComponent>> fetchers = new ArrayList<>();
|
|
||||||
private BiConsumer<K, Compilation> compilationCallbacks = ($, $$) -> {
|
|
||||||
};
|
|
||||||
private Function<K, String> nameMapper = Object::toString;
|
|
||||||
|
|
||||||
public ShaderCompiler(GlslVersion glslVersion, ShaderType shaderType) {
|
|
||||||
this.glslVersion = glslVersion;
|
|
||||||
this.shaderType = shaderType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> nameMapper(Function<K, String> nameMapper) {
|
|
||||||
this.nameMapper = nameMapper;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> with(BiFunction<K, SourceLoader, @Nullable SourceComponent> fetch) {
|
|
||||||
fetchers.add(fetch);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> withComponents(Collection<@Nullable SourceComponent> components) {
|
|
||||||
components.forEach(this::withComponent);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> withComponent(@Nullable SourceComponent component) {
|
|
||||||
return withComponent($ -> component);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> withComponent(Function<K, @Nullable SourceComponent> sourceFetcher) {
|
|
||||||
return with((key, $) -> sourceFetcher.apply(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> withResource(Function<K, ResourceLocation> sourceFetcher) {
|
|
||||||
return with((key, loader) -> loader.find(sourceFetcher.apply(key)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> withResource(ResourceLocation resourceLocation) {
|
|
||||||
return withResource($ -> resourceLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> onCompile(BiConsumer<K, Compilation> cb) {
|
|
||||||
compilationCallbacks = compilationCallbacks.andThen(cb);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> define(String def, int value) {
|
|
||||||
return onCompile(($, ctx) -> ctx.define(def, String.valueOf(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShaderCompiler<K> enableExtension(String extension) {
|
|
||||||
return onCompile(($, ctx) -> ctx.enableExtension(extension));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private GlShader compile(K key, ShaderCache compiler, SourceLoader loader) {
|
|
||||||
var components = new ArrayList<SourceComponent>();
|
|
||||||
boolean ok = true;
|
|
||||||
for (var fetcher : fetchers) {
|
|
||||||
SourceComponent apply = fetcher.apply(key, loader);
|
|
||||||
if (apply == null) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
components.add(apply);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ok) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Consumer<Compilation> cb = ctx -> compilationCallbacks.accept(key, ctx);
|
|
||||||
return compiler.compile(glslVersion, shaderType, nameMapper.apply(key), cb, components);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,78 +10,23 @@ import org.lwjgl.opengl.GLCapabilities;
|
||||||
import org.lwjgl.opengl.KHRShaderSubgroup;
|
import org.lwjgl.opengl.KHRShaderSubgroup;
|
||||||
import org.lwjgl.system.MemoryStack;
|
import org.lwjgl.system.MemoryStack;
|
||||||
|
|
||||||
|
import com.jozufozu.flywheel.backend.glsl.GlslVersion;
|
||||||
import com.jozufozu.flywheel.lib.math.MoreMath;
|
import com.jozufozu.flywheel.lib.math.MoreMath;
|
||||||
|
|
||||||
import net.minecraft.Util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An instance of this class stores information about what OpenGL features are available.
|
|
||||||
* <br>
|
|
||||||
* Each field stores an enum variant that provides access to the most appropriate version of a feature for the current
|
|
||||||
* system.
|
|
||||||
*/
|
|
||||||
public final class GlCompat {
|
public final class GlCompat {
|
||||||
public static final GLCapabilities CAPABILITIES = GL.createCapabilities();
|
public static final GLCapabilities CAPABILITIES = GL.getCapabilities();
|
||||||
public static final boolean WINDOWS = _decideIfWeAreWindows();
|
public static final Driver DRIVER = readVendorString();
|
||||||
|
public static final int SUBGROUP_SIZE = subgroupSize();
|
||||||
public static final boolean ALLOW_DSA = true;
|
public static final boolean ALLOW_DSA = true;
|
||||||
public static final boolean SUPPORTS_INDIRECT = _decideIfWeSupportIndirect();
|
public static final GlslVersion MAX_GLSL_VERSION = maxGlslVersion();
|
||||||
public static final int SUBGROUP_SIZE = _subgroupSize();
|
|
||||||
public static final Driver DRIVER = _readVendorString();
|
public static final boolean SUPPORTS_INSTANCING = isInstancingSupported();
|
||||||
|
public static final boolean SUPPORTS_INDIRECT = isIndirectSupported();
|
||||||
|
|
||||||
private GlCompat() {
|
private GlCompat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean onAMDWindows() {
|
public static void init() {
|
||||||
return DRIVER == Driver.AMD && WINDOWS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean supportsInstancing() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean supportsIndirect() {
|
|
||||||
return SUPPORTS_INDIRECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Driver _readVendorString() {
|
|
||||||
String vendor = GL20C.glGetString(GL20C.GL_VENDOR);
|
|
||||||
|
|
||||||
if (vendor == null) {
|
|
||||||
return Driver.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
// vendor string I got was "ATI Technologies Inc."
|
|
||||||
if (vendor.contains("ATI") || vendor.contains("AMD")) {
|
|
||||||
return Driver.AMD;
|
|
||||||
} else if (vendor.contains("NVIDIA")) {
|
|
||||||
return Driver.NVIDIA;
|
|
||||||
} else if (vendor.contains("Intel")) {
|
|
||||||
return Driver.INTEL;
|
|
||||||
} else if (vendor.contains("Mesa")) {
|
|
||||||
return Driver.MESA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Driver.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean _decideIfWeAreWindows() {
|
|
||||||
return Util.getPlatform() == Util.OS.WINDOWS;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean _decideIfWeSupportIndirect() {
|
|
||||||
return CAPABILITIES.OpenGL46 || (CAPABILITIES.GL_ARB_compute_shader && CAPABILITIES.GL_ARB_shader_draw_parameters && CAPABILITIES.GL_ARB_base_instance && CAPABILITIES.GL_ARB_multi_draw_indirect && CAPABILITIES.GL_ARB_direct_state_access);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int _subgroupSize() {
|
|
||||||
if (CAPABILITIES.GL_KHR_shader_subgroup) {
|
|
||||||
return GL31C.glGetInteger(KHRShaderSubgroup.GL_SUBGROUP_SIZE_KHR);
|
|
||||||
}
|
|
||||||
// Try to guess.
|
|
||||||
// Newer (RDNA) AMD cards have 32 threads in a wavefront, older ones have 64.
|
|
||||||
// I assume the newer drivers will implement the above extension, so 64 is a
|
|
||||||
// reasonable guess for AMD hardware. In the worst case we'll just spread
|
|
||||||
// load across multiple SIMDs
|
|
||||||
return DRIVER == Driver.AMD || DRIVER == Driver.MESA ? 64 : 32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getComputeGroupCount(int invocations) {
|
public static int getComputeGroupCount(int invocations) {
|
||||||
|
@ -108,5 +53,83 @@ public final class GlCompat {
|
||||||
GL20C.nglShaderSource(glId, 1, pointers.address0(), 0);
|
GL20C.nglShaderSource(glId, 1, pointers.address0(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
private static Driver readVendorString() {
|
||||||
|
String vendor = GL20C.glGetString(GL20C.GL_VENDOR);
|
||||||
|
|
||||||
|
if (vendor == null) {
|
||||||
|
return Driver.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vendor string I got was "ATI Technologies Inc."
|
||||||
|
if (vendor.contains("ATI") || vendor.contains("AMD")) {
|
||||||
|
return Driver.AMD;
|
||||||
|
} else if (vendor.contains("NVIDIA")) {
|
||||||
|
return Driver.NVIDIA;
|
||||||
|
} else if (vendor.contains("Intel")) {
|
||||||
|
return Driver.INTEL;
|
||||||
|
} else if (vendor.contains("Mesa")) {
|
||||||
|
return Driver.MESA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Driver.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int subgroupSize() {
|
||||||
|
if (CAPABILITIES.GL_KHR_shader_subgroup) {
|
||||||
|
return GL31C.glGetInteger(KHRShaderSubgroup.GL_SUBGROUP_SIZE_KHR);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to guess.
|
||||||
|
// Newer (RDNA) AMD cards have 32 threads in a wavefront, older ones have 64.
|
||||||
|
// I assume the newer drivers will implement the above extension, so 64 is a
|
||||||
|
// reasonable guess for AMD hardware. In the worst case we'll just spread
|
||||||
|
// load across multiple SIMDs
|
||||||
|
return DRIVER == Driver.AMD || DRIVER == Driver.MESA ? 64 : 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GlslVersion maxGlslVersion() {
|
||||||
|
if (CAPABILITIES.OpenGL46) {
|
||||||
|
return GlslVersion.V460;
|
||||||
|
} else if (CAPABILITIES.OpenGL45) {
|
||||||
|
return GlslVersion.V450;
|
||||||
|
} else if (CAPABILITIES.OpenGL44) {
|
||||||
|
return GlslVersion.V440;
|
||||||
|
} else if (CAPABILITIES.OpenGL43) {
|
||||||
|
return GlslVersion.V430;
|
||||||
|
} else if (CAPABILITIES.OpenGL42) {
|
||||||
|
return GlslVersion.V420;
|
||||||
|
} else if (CAPABILITIES.OpenGL41) {
|
||||||
|
return GlslVersion.V410;
|
||||||
|
} else if (CAPABILITIES.OpenGL40) {
|
||||||
|
return GlslVersion.V400;
|
||||||
|
} else if (CAPABILITIES.OpenGL33) {
|
||||||
|
return GlslVersion.V330;
|
||||||
|
} else {
|
||||||
|
return GlslVersion.V150;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isInstancingSupported() {
|
||||||
|
if (!CAPABILITIES.OpenGL33) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isIndirectSupported() {
|
||||||
|
// The GL requirement cannot be lower because GL_ARB_compute_shader requires at least GL 4.2.
|
||||||
|
if (!CAPABILITIES.OpenGL42) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (CAPABILITIES.OpenGL46) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return CAPABILITIES.GL_ARB_compute_shader
|
||||||
|
&& CAPABILITIES.GL_ARB_direct_state_access
|
||||||
|
&& CAPABILITIES.GL_ARB_multi_bind
|
||||||
|
&& CAPABILITIES.GL_ARB_multi_draw_indirect
|
||||||
|
&& CAPABILITIES.GL_ARB_shader_draw_parameters
|
||||||
|
&& CAPABILITIES.GL_ARB_shader_storage_buffer_object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -26,5 +26,4 @@ public enum GlslVersion {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return Integer.toString(version);
|
return Integer.toString(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,16 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||||
|
import com.jozufozu.flywheel.backend.gl.GlCompat;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
@Mixin(RenderSystem.class)
|
@Mixin(RenderSystem.class)
|
||||||
abstract class RenderSystemMixin {
|
abstract class RenderSystemMixin {
|
||||||
|
@Inject(method = "initRenderer(IZ)V", at = @At("RETURN"))
|
||||||
|
private static void flywheel$onInitRenderer(CallbackInfo ci) {
|
||||||
|
GlCompat.init();
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(method = "setShaderFogStart(F)V", at = @At("RETURN"))
|
@Inject(method = "setShaderFogStart(F)V", at = @At("RETURN"))
|
||||||
private static void flywheel$onSetFogStart(CallbackInfo ci) {
|
private static void flywheel$onSetFogStart(CallbackInfo ci) {
|
||||||
Uniforms.onFogUpdate();
|
Uniforms.onFogUpdate();
|
||||||
|
|
|
@ -16,7 +16,11 @@ uniform uint _flw_baseDraw;
|
||||||
flat out uvec3 _flw_packedMaterial;
|
flat out uvec3 _flw_packedMaterial;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
#if __VERSION__ < 460
|
||||||
|
uint drawIndex = gl_DrawIDARB + _flw_baseDraw;
|
||||||
|
#else
|
||||||
uint drawIndex = gl_DrawID + _flw_baseDraw;
|
uint drawIndex = gl_DrawID + _flw_baseDraw;
|
||||||
|
#endif
|
||||||
MeshDrawCommand draw = _flw_drawCommands[drawIndex];
|
MeshDrawCommand draw = _flw_drawCommands[drawIndex];
|
||||||
|
|
||||||
_flw_uberMaterialVertexIndex = draw.materialVertexIndex;
|
_flw_uberMaterialVertexIndex = draw.materialVertexIndex;
|
||||||
|
@ -24,7 +28,11 @@ void main() {
|
||||||
_flw_unpackMaterialProperties(packedMaterialProperties, flw_material);
|
_flw_unpackMaterialProperties(packedMaterialProperties, flw_material);
|
||||||
_flw_packedMaterial = uvec3(draw.materialFragmentIndex, draw.packedFogAndCutout, packedMaterialProperties);
|
_flw_packedMaterial = uvec3(draw.materialFragmentIndex, draw.packedFogAndCutout, packedMaterialProperties);
|
||||||
|
|
||||||
|
#if __VERSION__ < 460
|
||||||
|
uint instanceIndex = _flw_instanceIndices[gl_BaseInstanceARB + gl_InstanceID];
|
||||||
|
#else
|
||||||
uint instanceIndex = _flw_instanceIndices[gl_BaseInstance + gl_InstanceID];
|
uint instanceIndex = _flw_instanceIndices[gl_BaseInstance + gl_InstanceID];
|
||||||
|
#endif
|
||||||
FlwInstance instance = _flw_unpackInstance(instanceIndex);
|
FlwInstance instance = _flw_unpackInstance(instanceIndex);
|
||||||
|
|
||||||
_flw_main(instance, instanceIndex);
|
_flw_main(instance, instanceIndex);
|
||||||
|
|
Loading…
Reference in a new issue