Skip to content

Commit

Permalink
Added dynamic shader buffer swapping
Browse files Browse the repository at this point in the history
  • Loading branch information
Ocelot5836 committed Nov 23, 2024
1 parent 77d2351 commit fcdcc37
Show file tree
Hide file tree
Showing 25 changed files with 573 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.*;
import foundry.veil.Veil;
import foundry.veil.api.client.render.dynamicbuffer.DynamicBufferType;
import foundry.veil.api.client.render.shader.ShaderManager;
import foundry.veil.api.client.render.shader.definition.ShaderBlock;
import foundry.veil.api.client.render.shader.program.ShaderProgram;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package foundry.veil.api.client.render;

import com.mojang.blaze3d.systems.RenderSystem;
import foundry.veil.api.client.editor.EditorManager;
import foundry.veil.api.client.render.deferred.VeilDeferredRenderer;
import foundry.veil.api.client.render.dynamicbuffer.DynamicBufferType;
import foundry.veil.api.client.render.framebuffer.FramebufferManager;
import foundry.veil.api.client.render.post.PostPipeline;
import foundry.veil.api.client.render.post.PostProcessingManager;
Expand All @@ -12,6 +14,7 @@
import foundry.veil.api.quasar.particle.ParticleSystemManager;
import foundry.veil.ext.LevelRendererExtension;
import foundry.veil.impl.client.imgui.VeilImGuiImpl;
import foundry.veil.impl.client.render.dynamicbuffer.DynamicBufferManger;
import foundry.veil.mixin.accessor.ReloadableResourceManagerAccessor;
import net.minecraft.client.Minecraft;
import net.minecraft.server.packs.resources.PreparableReloadListener;
Expand All @@ -28,6 +31,7 @@
*/
public class VeilRenderer implements NativeResource {

private final DynamicBufferManger dynamicBufferManger;
private final ShaderModificationManager shaderModificationManager;
private final ShaderPreDefinitions shaderPreDefinitions;
private final ShaderManager shaderManager;
Expand All @@ -42,12 +46,13 @@ public class VeilRenderer implements NativeResource {

@ApiStatus.Internal
public VeilRenderer(ReloadableResourceManager resourceManager) {
this.dynamicBufferManger = new DynamicBufferManger();
this.shaderModificationManager = new ShaderModificationManager();
this.shaderPreDefinitions = new ShaderPreDefinitions();
this.shaderManager = new ShaderManager(ShaderManager.PROGRAM_SET, this.shaderPreDefinitions);
this.shaderManager = new ShaderManager(ShaderManager.PROGRAM_SET, this.shaderPreDefinitions, this.dynamicBufferManger);
this.framebufferManager = new FramebufferManager();
this.postProcessingManager = new PostProcessingManager();
ShaderManager deferredShaderManager = new ShaderManager(ShaderManager.DEFERRED_SET, this.shaderPreDefinitions);
ShaderManager deferredShaderManager = new ShaderManager(ShaderManager.DEFERRED_SET, this.shaderPreDefinitions, this.dynamicBufferManger);
this.deferredRenderer = new VeilDeferredRenderer(deferredShaderManager, this.shaderPreDefinitions, this.framebufferManager, this.postProcessingManager);
this.dynamicRenderTypeManager = new DynamicRenderTypeManager();
this.quasarParticleManager = new ParticleSystemManager();
Expand All @@ -67,6 +72,38 @@ public VeilRenderer(ReloadableResourceManager resourceManager) {
resourceManager.registerReloadListener(this.dynamicRenderTypeManager);
}

/**
* Enables the specified dynamic render buffers.
*
* @param buffers The buffers to enable
* @return Whether any change occurred
*/
public boolean enableBuffers(DynamicBufferType... buffers) {
RenderSystem.assertOnRenderThreadOrInit();
if (buffers.length == 0) {
return false;
}

int active = this.dynamicBufferManger.getActiveBuffers() | DynamicBufferType.encode(buffers);
return this.dynamicBufferManger.setActiveBuffers(active);
}

/**
* Disables the specified dynamic render buffers.
*
* @param buffers The buffers to disable
* @return Whether any change occurred
*/
public boolean disableBuffers(DynamicBufferType... buffers) {
RenderSystem.assertOnRenderThreadOrInit();
if (buffers.length == 0) {
return false;
}

int active = this.dynamicBufferManger.getActiveBuffers() & ~DynamicBufferType.encode(buffers);
return this.dynamicBufferManger.setActiveBuffers(active);
}

/**
* @return The manager for all custom shader modifications
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package foundry.veil.api.client.render.dynamicbuffer;

public enum DynamicBufferType {
ALBEDO("albedo", "Albedo", false, 4),
NORMAL("normal", "Normal", false, 3),
LIGHT_COLOR("light_color", "LightColor", false, 4),
LIGHT_UV("light_uv", "LightUv", true, 2),
DEBUG("debug", "Debug", false, 4);

private final String name;
private final String sourceName;
private final boolean integer;
private final int components;
private final int mask;

DynamicBufferType(String name, String sourceName, boolean integer, int components) {
this.name = name;
this.sourceName = "VeilDynamic"+sourceName;
this.integer = integer;
this.components = components;
this.mask = 1 << this.ordinal();
}

public String getName() {
return this.name;
}

public String getSourceName() {
return this.sourceName;
}

public String getType() {
if (this.components == 1) {
return this.isInteger() ? "int" : "float";
}
return (this.isInteger() ? "u" : "") + "vec" + this.components;
}

public boolean isInteger() {
return this.integer;
}

public int getComponents() {
return this.components;
}

public int getMask() {
return this.mask;
}

public static int encode(DynamicBufferType... types) {
int mask = 0;
for (DynamicBufferType type : types) {
mask |= type.mask;
}
return mask;
}

public static DynamicBufferType[] decode(int mask) {
int next = 0;
DynamicBufferType[] types = new DynamicBufferType[Integer.bitCount(mask)];
for (DynamicBufferType value : values()) {
if ((value.mask & mask) != 0) {
types[next++] = value;
}
}
return types;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.system.NativeResource;

import java.util.Set;

import static org.lwjgl.opengl.GL20C.glDeleteShader;

/**
* A shader instance that has additional pre-compiled data.
* {@link #apply(ShaderProgram)} should be called after this shader is attached to a program.
*
* @param sourceFile The source file this shader was compiled from or <code>null</code> if the shader has no file
* @param id The OpenGL id of the shader. The shader is automatically deleted later
* @param id The OpenGL id of the shader
* @param uniformBindings The bindings set by the shader
* @param definitionDependencies The shader pre-definitions this shader is dependent on
* @param includes All shader imports included in this file
Expand All @@ -22,12 +25,17 @@ public record CompiledShader(@Nullable ResourceLocation sourceFile,
int id,
Object2IntMap<String> uniformBindings,
Set<String> definitionDependencies,
Set<ResourceLocation> includes) {
Set<ResourceLocation> includes) implements NativeResource {

/**
* Applies the additional attributes of this shader to the specified program.
*/
public void apply(ShaderProgram program) {
this.uniformBindings.forEach(program::setInt);
}

@Override
public void free() {
glDeleteShader(this.id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ public interface ShaderCompiler extends NativeResource {
* @param context The context for compiling the shader
* @param type The type of shader to create
* @param id The id of the shader to attach
* @param flags Additional compilation flags
* @return A new shader that can be attached to programs
* @throws IOException If the file could not be found.
* @throws ShaderException If an error occurs compiling the shader
*/
CompiledShader compile(Context context, int type, ProgramDefinition.SourceType sourceType, ResourceLocation id) throws IOException, ShaderException;
CompiledShader compile(Context context, int type, ProgramDefinition.SourceType sourceType, ResourceLocation id, int flags) throws IOException, ShaderException;

/**
* Creates a new shader and attempts to attach the specified sources to it.
Expand All @@ -42,11 +43,12 @@ public interface ShaderCompiler extends NativeResource {
* @param context The context for compiling the shader
* @param type The type of shader to create
* @param source The source of the shader to attach
* @param flags Additional compilation flags
* @return A new shader that can be attached to programs
* @throws IOException If an error occurs processing the shader source
* @throws ShaderException If an error occurs compiling the shader
*/
CompiledShader compile(Context context, int type, ProgramDefinition.SourceType sourceType, String source) throws IOException, ShaderException;
CompiledShader compile(Context context, int type, ProgramDefinition.SourceType sourceType, String source, int flags) throws IOException, ShaderException;

/**
* Adds the specified pre-processor to the end of the stack.
Expand Down Expand Up @@ -95,10 +97,12 @@ static ShaderCompiler cached(@Nullable ResourceProvider provider) {
*
* @param preDefinitions The set of all shader pre-definitions
* @param sourceSet The location to load relative shader files from
* @param activeBuffers The currently active buffers
* @param definition The definition the shader is being compiled for or <code>null</code> if there is no program
*/
record Context(ShaderPreDefinitions preDefinitions,
ShaderSourceSet sourceSet,
int activeBuffers,
@Nullable ProgramDefinition definition) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@
import foundry.veil.api.client.render.shader.processor.ShaderModifyProcessor;
import foundry.veil.api.client.render.shader.program.ProgramDefinition;
import foundry.veil.api.client.render.shader.program.ShaderProgram;
import foundry.veil.impl.client.render.dynamicbuffer.DynamicBufferManger;
import foundry.veil.impl.client.render.shader.ShaderProgramImpl;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.ReportedException;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.FileToIdConverter;
Expand All @@ -26,6 +31,7 @@
import net.minecraft.util.GsonHelper;
import net.minecraft.util.profiling.InactiveProfiler;
import net.minecraft.util.profiling.ProfilerFiller;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;

import java.io.*;
Expand Down Expand Up @@ -70,6 +76,7 @@ public class ShaderManager implements PreparableReloadListener, Closeable {
GL_COMPUTE_SHADER, "compute"
);

private final DynamicBufferManger dynamicBufferManager;
private final ShaderSourceSet sourceSet;
private final ShaderPreDefinitions definitions;
private final Map<ResourceLocation, ShaderProgram> shaders;
Expand All @@ -83,8 +90,10 @@ public class ShaderManager implements PreparableReloadListener, Closeable {
*
* @param sourceSet The source set to load all shaders from
* @param shaderPreDefinitions The set of shader pre-definitions
* @param dynamicBufferManager The manager for dynamic buffers
*/
public ShaderManager(ShaderSourceSet sourceSet, ShaderPreDefinitions shaderPreDefinitions) {
public ShaderManager(ShaderSourceSet sourceSet, ShaderPreDefinitions shaderPreDefinitions, DynamicBufferManger dynamicBufferManager) {
this.dynamicBufferManager = dynamicBufferManager;
this.sourceSet = sourceSet;
this.definitions = shaderPreDefinitions;
this.definitions.addListener(this::onDefinitionChanged);
Expand Down Expand Up @@ -183,7 +192,7 @@ private Map<ResourceLocation, Resource> readIncludes(ResourceManager resourceMan
private void compile(ShaderProgram program, ProgramDefinition definition, ShaderCompiler compiler) {
ResourceLocation id = program.getId();
try {
program.compile(new ShaderCompiler.Context(this.definitions, this.sourceSet, definition), compiler);
program.compile(new ShaderCompiler.Context(this.definitions, this.sourceSet, this.dynamicBufferManager.getActiveBuffers(), definition), compiler);
} catch (ShaderException e) {
Veil.LOGGER.error("Failed to create shader {}: {}", id, e.getMessage());
String error = e.getGlError();
Expand Down Expand Up @@ -284,7 +293,7 @@ private void apply(ShaderManager.ReloadState reloadState) {
this.shaders.clear();

ResourceProvider sourceProvider = loc -> Optional.ofNullable(reloadState.shaderSources().get(loc));
try (ShaderCompiler compiler = this.addProcessors(ShaderCompiler.cached(sourceProvider), sourceProvider)) {
try (ShaderCompiler compiler = this.addProcessors(ShaderCompiler.direct(sourceProvider), sourceProvider)) {
for (Map.Entry<ResourceLocation, ProgramDefinition> entry : reloadState.definitions().entrySet()) {
ResourceLocation id = entry.getKey();
ShaderProgram program = ShaderProgram.create(id);
Expand All @@ -300,7 +309,7 @@ private void apply(ShaderManager.ReloadState reloadState) {

private void applyRecompile(ShaderManager.ReloadState reloadState, Collection<ResourceLocation> shaders) {
ResourceProvider sourceProvider = loc -> Optional.ofNullable(reloadState.shaderSources().get(loc));
try (ShaderCompiler compiler = this.addProcessors(ShaderCompiler.cached(sourceProvider), sourceProvider)) {
try (ShaderCompiler compiler = this.addProcessors(ShaderCompiler.direct(sourceProvider), sourceProvider)) {
for (Map.Entry<ResourceLocation, ProgramDefinition> entry : reloadState.definitions().entrySet()) {
ResourceLocation id = entry.getKey();
ShaderProgram program = this.getShader(id);
Expand Down Expand Up @@ -370,6 +379,36 @@ public void scheduleRecompile(ResourceLocation shader) {
this.scheduleRecompile(0);
}

@ApiStatus.Internal
public void setActiveBuffers(int activeBuffers) {
ResourceProvider sourceProvider = Minecraft.getInstance().getResourceManager();
ShaderProgram active = null;
try (ShaderCompiler compiler = this.addProcessors(ShaderCompiler.direct(sourceProvider), sourceProvider)) {
for (ShaderProgram program : this.shaders.values()) {
active = program;
if (program instanceof ShaderProgramImpl impl) {
if (impl.getActiveBuffers() != activeBuffers) {
impl.setActiveBuffers(new ShaderCompiler.Context(this.definitions, this.sourceSet, this.dynamicBufferManager.getActiveBuffers(), program.getDefinition()), compiler, activeBuffers);
}
}
}
} catch (ShaderException e) {
CrashReport crashreport = CrashReport.forThrowable(e, "Setting Active Buffers");
CrashReportCategory crashreportcategory = crashreport.addCategory("Compiling Program");
crashreportcategory.setDetail("Name", active.getId());
String glError = e.getGlError();
if (glError != null) {
Veil.LOGGER.error(glError);
}
throw new ReportedException(crashreport);
} catch (Exception e) {
CrashReport crashreport = CrashReport.forThrowable(e, "Setting Active Buffers");
CrashReportCategory crashreportcategory = crashreport.addCategory("Compiling Program");
crashreportcategory.setDetail("Name", active != null ? active.getId() : "null");
throw new ReportedException(crashreport);
}
}

@Override
public CompletableFuture<Void> reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, ProfilerFiller preparationsProfiler, ProfilerFiller reloadProfiler, Executor backgroundExecutor, Executor gameExecutor) {
if (this.reloadFuture != null && !this.reloadFuture.isDone()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,6 @@ public void addStaticDefinitions(Consumer<String> definitionConsumer) {
* @return A view of all definitions
*/
public Map<String, String> getDefinitions() {
return this.definitions;
return this.definitionsView;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ static ShaderPreProcessor allOf(ShaderPreProcessor... processors) {
static ShaderPreProcessor allOf(Collection<ShaderPreProcessor> processors) {
List<ShaderPreProcessor> list = new ArrayList<>(processors.size());
for (ShaderPreProcessor processor : processors) {
if (processor instanceof ShaderMultiProcessor multiProcessor) {
list.addAll(Arrays.asList(multiProcessor.processors()));
if (processor instanceof ShaderMultiProcessor(ShaderPreProcessor[] values)) {
list.addAll(Arrays.asList(values));
} else if (processor != NOOP) {
list.add(processor);
}
Expand All @@ -53,9 +53,9 @@ static ShaderPreProcessor allOf(Collection<ShaderPreProcessor> processors) {
return NOOP;
}
if (list.size() == 1) {
return list.get(0);
return list.getFirst();
}
return new ShaderMultiProcessor(list.toArray(new ShaderPreProcessor[0]));
return new ShaderMultiProcessor(list.toArray(ShaderPreProcessor[]::new));
}

/**
Expand Down Expand Up @@ -121,5 +121,10 @@ interface Context {
*/
@Nullable
ShaderPreDefinitions preDefinitions();

/**
* @return The OpenGL type of the compiling shader
*/
int type();
}
}
Loading

0 comments on commit fcdcc37

Please sign in to comment.