From a600ecfa0ee3df41ce39741f8fd50f41cb72d271 Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Wed, 3 Jun 2026 08:07:19 +0800 Subject: [PATCH 1/9] Add compute pipeline and buffer layout support --- module.rendering/build.gradle | 17 +- .../lib/v2/rendering/AnvilLibRendering.java | 7 + .../rendering/bloom/BloomParametersUbo.java | 21 ++- .../bloom/BloomPipelineParametersUbo.java | 22 ++- .../v2/rendering/bloom/BloomPostEffect.java | 7 +- .../v2/rendering/bloom/BlurParametersUbo.java | 35 ---- .../lib/v2/rendering/bloom/TransformsUbo.java | 17 +- .../v2/rendering/blur/BlurParametersUbo.java | 38 ++++ .../lib/v2/rendering/blur/GaussianBlur.java | 6 +- .../event/RegisterComputePipelinesEvent.java | 21 +++ .../ALRCommandEncoderBackendExtension.java | 18 ++ .../blaze3d/ALRCommandEncoderExtension.java | 19 ++ .../blaze3d/ALRGpuDeviceBackendExtension.java | 11 ++ .../blaze3d/ALRGpuDeviceExtension.java | 11 ++ .../extension/blaze3d/MemoryBarrierFlag.java | 31 ++++ .../blaze3d/compute/package-info.java | 5 + .../compute/pipeline/ALRComputePass.java | 87 +++++++++ .../pipeline/ALRComputePassBackend.java | 28 +++ .../compute/pipeline/ALRComputePipeline.java | 98 ++++++++++ .../bindings/AtomicCounterBinding.java | 19 ++ .../bindings/ComputeBindingLayout.java | 12 ++ .../pipeline/bindings/ImageBinding.java | 28 +++ .../bindings/ShaderStorageBinding.java | 19 ++ .../pipeline/bindings/TextureBinding.java | 25 +++ .../bindings/UniformBlockBinding.java | 19 ++ .../pipeline/gl/GlComputePassBackend.java | 64 +++++++ .../shader/ALRComputeShaderInstance.java | 4 + .../shader/ALRComputeShaderInstanceKey.java | 7 + .../shader/ALRComputeShaderManager.java | 81 ++++++++ .../compute/shader/ShaderResourceType.java | 9 + .../buffers/layout/BufferLayout.java | 38 ++++ .../buffers/layout/BufferSizeCalculator.java | 27 +++ .../buffers/layout/BufferWriter.java | 42 +++++ .../layout/std140/Std140SizeCalculator.java | 76 ++++++++ .../buffers/layout/std140/Std140Writer.java | 132 +++++++++++++ .../layout/std430/Std430SizeCalculator.java | 75 ++++++++ .../buffers/layout/std430/Std430Writer.java | 134 ++++++++++++++ .../BufferObject.java} | 25 ++- .../object/BufferObjectLayoutDefinition.java | 51 ++++++ .../object/BufferObjectLayoutEntry.java | 87 +++++++++ .../object/BufferObjectLayoutEntryType.java | 173 ++++++++++++++++++ .../object/ShaderBufferObjectUsage.java | 6 + .../buffers/ubo/UboLayoutDefinition.java | 38 ---- .../buffers/ubo/UboLayoutEntry.java | 82 --------- .../buffers/ubo/UboLayoutEntryType.java | 125 ------------- .../lib/v2/rendering/sdf/SdfGraphics.java | 3 +- .../lib/v2/rendering/sdf/SdfParameters.java | 26 ++- .../resources/META-INF/accesstransformer.cfg | 4 +- .../buffers/layout/Std140LayoutRulesTest.java | 139 ++++++++++++++ .../anvillib_test/shaders/compute/test.csh | 20 ++ 50 files changed, 1758 insertions(+), 331 deletions(-) delete mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BlurParametersUbo.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/BlurParametersUbo.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/RegisterComputePipelinesEvent.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/package-info.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ComputeBindingLayout.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ImageBinding.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/TextureBinding.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstanceKey.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ShaderResourceType.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferLayout.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferSizeCalculator.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferWriter.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java rename module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/{ubo/UboObject.java => object/BufferObject.java} (51%) create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutDefinition.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntry.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntryType.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/ShaderBufferObjectUsage.java delete mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutDefinition.java delete mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntry.java delete mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntryType.java create mode 100644 module.rendering/src/test/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/Std140LayoutRulesTest.java create mode 100644 module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh diff --git a/module.rendering/build.gradle b/module.rendering/build.gradle index 571b4175..6c2415ce 100644 --- a/module.rendering/build.gradle +++ b/module.rendering/build.gradle @@ -1,2 +1,17 @@ dependencies { -} \ No newline at end of file +} + +tasks.register('runStd140LayoutRulesTest', JavaExec) { + group = 'verification' + description = 'Runs lightweight std140 layout rule checks.' + classpath = sourceSets.test.runtimeClasspath + sourceSets.main.compileClasspath + mainClass = 'dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.Std140LayoutRulesTest' +} + +tasks.named('test') { + failOnNoDiscoveredTests = false +} + +tasks.named('check') { + dependsOn tasks.named('runStd140LayoutRulesTest') +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java index c0341d32..3cc10419 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java @@ -1,6 +1,7 @@ package dev.anvilcraft.lib.v2.rendering; import dev.anvilcraft.lib.v2.rendering.cachedber.pipeline.CachedBlockEntityRenderingPipeline; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderManager; import dev.anvilcraft.lib.v2.rendering.gui.renderer.BlockStatePipRenderer; import dev.anvilcraft.lib.v2.rendering.gui.renderer.StructurePipRenderer; import dev.anvilcraft.lib.v2.rendering.gui.state.BlockStatePipRenderingState; @@ -11,6 +12,7 @@ import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.client.event.AddClientReloadListenersEvent; import net.neoforged.neoforge.client.event.RegisterPictureInPictureRenderersEvent; import net.neoforged.neoforge.client.event.RenderFrameEvent; import net.neoforged.neoforge.client.event.RenderLevelStageEvent; @@ -36,6 +38,11 @@ public static void on(RenderFrameEvent.Pre event) { ALRPostEffects.getBloomPostEffect().beginFrame(); } + @SubscribeEvent + public static void on(AddClientReloadListenersEvent event){ + event.addListener(AnvilLibRendering.location("compute_shader_manager"), ALRComputeShaderManager.INSTANCE); + } + @SubscribeEvent public static void on(RenderLevelStageEvent.AfterTranslucentParticles event) { if (CachedBlockEntityRenderingPipeline.getInstance() != null) { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomParametersUbo.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomParametersUbo.java index 982daf1a..47497b31 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomParametersUbo.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomParametersUbo.java @@ -1,19 +1,21 @@ package dev.anvilcraft.lib.v2.rendering.bloom; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutDefinition; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutEntry; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.ShaderBufferObjectUsage; import lombok.Getter; import lombok.Setter; @Setter @Getter -public class BloomParametersUbo extends UboObject { +public class BloomParametersUbo extends BufferObject { - public static final UboLayoutDefinition DEFINITION = UboLayoutDefinition.create( - UboLayoutEntry.ofFloat().forGetter(BloomParametersUbo::getBloomIntensity).build(), - UboLayoutEntry.ofFloat().forGetter(BloomParametersUbo::getBloomBlendThreshold).build(), - UboLayoutEntry.ofFloat().forGetter(BloomParametersUbo::getLuminanceSensitivity).build() + public static final BufferObjectLayoutDefinition DEFINITION = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofFloat().forGetter(BloomParametersUbo::getBloomIntensity).build(), + BufferObjectLayoutEntry.ofFloat().forGetter(BloomParametersUbo::getBloomBlendThreshold).build(), + BufferObjectLayoutEntry.ofFloat().forGetter(BloomParametersUbo::getLuminanceSensitivity).build() ); private float bloomIntensity; @@ -21,13 +23,14 @@ public class BloomParametersUbo extends UboObject { private float luminanceSensitivity; public BloomParametersUbo(float bloomIntensity, float bloomBlendThreshold, float luminanceSensitivity) { + super(BufferLayout.STD140, ShaderBufferObjectUsage.UBO); this.bloomIntensity = bloomIntensity; this.bloomBlendThreshold = bloomBlendThreshold; this.luminanceSensitivity = luminanceSensitivity; } @Override - protected UboLayoutDefinition getDefinition() { + protected BufferObjectLayoutDefinition getDefinition() { return DEFINITION; } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPipelineParametersUbo.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPipelineParametersUbo.java index a1b889fe..17be00c3 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPipelineParametersUbo.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPipelineParametersUbo.java @@ -1,24 +1,30 @@ package dev.anvilcraft.lib.v2.rendering.bloom; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutDefinition; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutEntry; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.ShaderBufferObjectUsage; import lombok.Getter; import lombok.Setter; import org.joml.Vector2f; @Getter @Setter -public class BloomPipelineParametersUbo extends UboObject { +public class BloomPipelineParametersUbo extends BufferObject { - public static final UboLayoutDefinition DEFINITION = UboLayoutDefinition.create( - UboLayoutEntry.ofVec2f().forGetter(BloomPipelineParametersUbo::getResolution).build(), - UboLayoutEntry.ofInt().forGetter(BloomPipelineParametersUbo::getFrameIndex).build() + public static final BufferObjectLayoutDefinition DEFINITION = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofVec2f().forGetter(BloomPipelineParametersUbo::getResolution).build(), + BufferObjectLayoutEntry.ofInt().forGetter(BloomPipelineParametersUbo::getFrameIndex).build() ); private final Vector2f resolution = new Vector2f(); private int frameIndex; + protected BloomPipelineParametersUbo() { + super(BufferLayout.STD140, ShaderBufferObjectUsage.UBO); + } + public void setResolution(int width, int height) { this.resolution.set( 1.0f / Math.max(width, 1.0f), @@ -27,7 +33,7 @@ public void setResolution(int width, int height) { } @Override - protected UboLayoutDefinition getDefinition() { + protected BufferObjectLayoutDefinition getDefinition() { return DEFINITION; } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java index 17b031c6..49161621 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java @@ -22,6 +22,7 @@ import com.mojang.blaze3d.vertex.VertexFormat; import dev.anvilcraft.lib.v2.rendering.ALRPipelines; import dev.anvilcraft.lib.v2.rendering.AnvilLibRendering; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; import dev.anvilcraft.lib.v2.rendering.foundation.compound.CompoundSubmitNodeStorage; import dev.anvilcraft.lib.v2.rendering.foundation.compound.DirtyTracked; import lombok.Getter; @@ -43,9 +44,9 @@ @SuppressWarnings({"FieldMayBeFinal", "SameParameterValue"}) public class BloomPostEffect implements DirtyTracked { - public static final int UNIFORM_TRANSFORM_SIZE = TransformsUbo.DEFINITION.size(); - public static final int UNIFORM_BLOOM_SIZE = BloomParametersUbo.DEFINITION.size(); - public static final int UNIFORM_ENHANCED_BLOOM_SIZE = BloomPipelineParametersUbo.DEFINITION.size(); + public static final int UNIFORM_TRANSFORM_SIZE = TransformsUbo.DEFINITION.size(BufferLayout.STD140); + public static final int UNIFORM_BLOOM_SIZE = BloomParametersUbo.DEFINITION.size(BufferLayout.STD140); + public static final int UNIFORM_ENHANCED_BLOOM_SIZE = BloomPipelineParametersUbo.DEFINITION.size(BufferLayout.STD140); // todo: uses config or options private static final int PASSES_AMOUNT = 5; diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BlurParametersUbo.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BlurParametersUbo.java deleted file mode 100644 index 68414dda..00000000 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BlurParametersUbo.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.anvilcraft.lib.v2.rendering.bloom; - -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutDefinition; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutEntry; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboObject; -import lombok.Getter; -import lombok.Setter; -import org.joml.Vector2f; - -@Setter -@Getter -public class BlurParametersUbo extends UboObject { - - public static final UboLayoutDefinition DEFINITION = UboLayoutDefinition.create( - UboLayoutEntry.ofVec2f().forGetter(BlurParametersUbo::getDirection).build(), - UboLayoutEntry.ofFloat().forGetter(BlurParametersUbo::getSampleStepLength).build(), - UboLayoutEntry.ofFloat().forGetter(BlurParametersUbo::getColorMultiplier).build() - ); - - private float sampleStepLength; - - private float colorMultiplier; - private Vector2f direction; - - public BlurParametersUbo(float sampleStepLength, float colorMultiplier, Vector2f direction) { - this.sampleStepLength = sampleStepLength; - this.colorMultiplier = colorMultiplier; - this.direction = direction; - } - - @Override - protected UboLayoutDefinition getDefinition() { - return DEFINITION; - } -} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/TransformsUbo.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/TransformsUbo.java index fd742076..ed9203bb 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/TransformsUbo.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/TransformsUbo.java @@ -1,28 +1,31 @@ package dev.anvilcraft.lib.v2.rendering.bloom; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutDefinition; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutEntry; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.ShaderBufferObjectUsage; import lombok.Getter; import lombok.Setter; import org.joml.Matrix4f; @Setter @Getter -public class TransformsUbo extends UboObject { +public class TransformsUbo extends BufferObject { - public static final UboLayoutDefinition DEFINITION = UboLayoutDefinition.create( - UboLayoutEntry.ofMat4f().forGetter(TransformsUbo::getProjMat).build() + public static final BufferObjectLayoutDefinition DEFINITION = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofMat4f().forGetter(TransformsUbo::getProjMat).build() ); private Matrix4f projMat; public TransformsUbo(Matrix4f projMat) { + super(BufferLayout.STD140, ShaderBufferObjectUsage.UBO); this.projMat = projMat; } @Override - protected UboLayoutDefinition getDefinition() { + protected BufferObjectLayoutDefinition getDefinition() { return DEFINITION; } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/BlurParametersUbo.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/BlurParametersUbo.java new file mode 100644 index 00000000..bffa5227 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/BlurParametersUbo.java @@ -0,0 +1,38 @@ +package dev.anvilcraft.lib.v2.rendering.blur; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.ShaderBufferObjectUsage; +import lombok.Getter; +import lombok.Setter; +import org.joml.Vector2f; + +@Setter +@Getter +public class BlurParametersUbo extends BufferObject { + + public static final BufferObjectLayoutDefinition DEFINITION = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofVec2f().forGetter(BlurParametersUbo::getDirection).build(), + BufferObjectLayoutEntry.ofFloat().forGetter(BlurParametersUbo::getSampleStepLength).build(), + BufferObjectLayoutEntry.ofFloat().forGetter(BlurParametersUbo::getColorMultiplier).build() + ); + + private float sampleStepLength; + + private float colorMultiplier; + private Vector2f direction; + + public BlurParametersUbo(float sampleStepLength, float colorMultiplier, Vector2f direction) { + super(BufferLayout.STD140, ShaderBufferObjectUsage.UBO); + this.sampleStepLength = sampleStepLength; + this.colorMultiplier = colorMultiplier; + this.direction = direction; + } + + @Override + protected BufferObjectLayoutDefinition getDefinition() { + return DEFINITION; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/GaussianBlur.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/GaussianBlur.java index 2c373b00..49fb9f27 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/GaussianBlur.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/blur/GaussianBlur.java @@ -19,8 +19,8 @@ import com.mojang.blaze3d.vertex.Tesselator; import com.mojang.blaze3d.vertex.VertexFormat; import dev.anvilcraft.lib.v2.rendering.ALRPipelines; -import dev.anvilcraft.lib.v2.rendering.bloom.BlurParametersUbo; import dev.anvilcraft.lib.v2.rendering.bloom.TransformsUbo; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; import lombok.Getter; import net.minecraft.client.Minecraft; import org.joml.Matrix4f; @@ -38,7 +38,7 @@ public class GaussianBlur implements AutoCloseable { private final GpuBuffer blurUBO = device.createBuffer( () -> "BloomPostEffect->BlurUBO", GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_UNIFORM, - BlurParametersUbo.DEFINITION.size() + BlurParametersUbo.DEFINITION.size(BufferLayout.STD140) ); private final GpuBuffer vertexBuffer = device.createBuffer( @@ -50,7 +50,7 @@ public class GaussianBlur implements AutoCloseable { private final GpuBuffer transformUBO = device.createBuffer( () -> "BloomPostEffect->TransformUBO", GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_UNIFORM, - TransformsUbo.DEFINITION.size() + TransformsUbo.DEFINITION.size(BufferLayout.STD140) ); @Getter diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/RegisterComputePipelinesEvent.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/RegisterComputePipelinesEvent.java new file mode 100644 index 00000000..a7307c5e --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/RegisterComputePipelinesEvent.java @@ -0,0 +1,21 @@ +package dev.anvilcraft.lib.v2.rendering.event; + +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePipeline; +import net.neoforged.bus.api.Event; +import net.neoforged.fml.event.IModBusEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class RegisterComputePipelinesEvent extends Event implements IModBusEvent { + private final List pipelines = new ArrayList<>(); + + public void registerPipeline(ALRComputePipeline pipeline) { + this.pipelines.add(pipeline); + } + + public List getPipelines() { + return Collections.unmodifiableList(this.pipelines); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java new file mode 100644 index 00000000..d123a88c --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java @@ -0,0 +1,18 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; + +import com.mojang.blaze3d.buffers.GpuBuffer; + +public interface ALRCommandEncoderBackendExtension { + void alrDispatchWorkgroups( + int groupCountX, + int groupCountY, + int groupCountZ + ); + + void alrDispatchWorkgroupsIndirect( + GpuBuffer parameters, + long offset + ); + + void alrMemoryBarrier(MemoryBarrierFlag... flags); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java new file mode 100644 index 00000000..c0642ace --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java @@ -0,0 +1,19 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; + +import com.mojang.blaze3d.buffers.GpuBuffer; + +public interface ALRCommandEncoderExtension { + + void alrDispatchWorkgroups( + int groupCountX, + int groupCountY, + int groupCountZ + ); + + void alrDispatchWorkgroupsIndirect( + GpuBuffer parameters, + long offset + ); + + void alrMemoryBarrier(MemoryBarrierFlag... flags); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java new file mode 100644 index 00000000..f21c9dfe --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java @@ -0,0 +1,11 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; + +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstance; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstanceKey; + +public interface ALRGpuDeviceBackendExtension { + ALRComputeShaderInstance alrCompileComputeShader(ALRComputeShaderInstanceKey instanceKey); + + ALRComputePass alrCreateComputePass(); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java new file mode 100644 index 00000000..b3a47f75 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java @@ -0,0 +1,11 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; + +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstance; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstanceKey; + +public interface ALRGpuDeviceExtension { + ALRComputeShaderInstance alrCompileComputeShader(ALRComputeShaderInstanceKey instanceKey); + + ALRComputePass alrCreateComputePass(); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java new file mode 100644 index 00000000..a08f163f --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java @@ -0,0 +1,31 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; + +import org.lwjgl.opengl.GL42; +import org.lwjgl.opengl.GL43; + +public enum MemoryBarrierFlag { + VERTEX_ATTRIB_ARRAY_BARRIER(GL42.GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT), + ELEMENT_ARRAY_BARRIER(GL42.GL_ELEMENT_ARRAY_BARRIER_BIT), + UNIFORM_BARRIER(GL42.GL_UNIFORM_BARRIER_BIT), + TEXTURE_FETCH_BARRIER(GL42.GL_TEXTURE_FETCH_BARRIER_BIT), + SHADER_IMAGE_ACCESS_BARRIER(GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT), + COMMAND_BARRIER(GL42.GL_COMMAND_BARRIER_BIT), + PIXEL_BUFFER_BARRIER(GL42.GL_PIXEL_BUFFER_BARRIER_BIT), + TEXTURE_UPDATE_BARRIER(GL42.GL_TEXTURE_UPDATE_BARRIER_BIT), + BUFFER_UPDATE_BARRIER(GL42.GL_BUFFER_UPDATE_BARRIER_BIT), + FRAMEBUFFER_BARRIER(GL42.GL_FRAMEBUFFER_BARRIER_BIT), + TRANSFORM_FEEDBACK_BARRIER(GL42.GL_TRANSFORM_FEEDBACK_BARRIER_BIT), + ATOMIC_COUNTER_BARRIER(GL42.GL_ATOMIC_COUNTER_BARRIER_BIT), + SHADER_STORAGE_BARRIER(GL43.GL_SHADER_STORAGE_BARRIER_BIT), + ALL_BARRIER(GL42.GL_ALL_BARRIER_BITS); + + private final int glEnum; + + MemoryBarrierFlag(int glEnum) { + this.glEnum = glEnum; + } + + public int glEnum() { + return glEnum; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/package-info.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/package-info.java new file mode 100644 index 00000000..a131e53f --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/package-info.java @@ -0,0 +1,5 @@ +@NullMarked +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute; + +import org.jspecify.annotations.NullMarked; + diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java new file mode 100644 index 00000000..13e0ab12 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java @@ -0,0 +1,87 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.textures.GpuTexture; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ComputeBindingLayout; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; +import lombok.Setter; + +import java.util.List; + +public class ALRComputePass implements AutoCloseable { + @Setter + private ALRComputePipeline pipeline; + private final ALRComputePassBackend backend; + private final GpuDevice device; + + public ALRComputePass(GpuDevice device, ALRComputePassBackend backend) { + this.backend = backend; + this.device = device; + } + + public void pushDebugGroup(String name) { + this.backend.pushDebugGroup(name); + } + + public void popDebugGroup(String name) { + this.backend.popDebugGroup(name); + } + + public void memoryBarrier(MemoryBarrierFlag... flags) { + this.backend.memoryBarrier(flags); + } + + public void dispatchWorkgroups( + int groupCountX, + int groupCountY, + int groupCountZ + ) { + this.backend.dispatchWorkgroups(groupCountX, groupCountY, groupCountZ); + } + + public void dispatchWorkgroupsIndirect( + GpuBuffer buffer, + long offset + ) { + this.backend.dispatchWorkgroupsIndirect(buffer, offset); + } + + @Override + public void close() throws Exception { + this.backend.close(); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + public void bindAll(List elements) { + int bindingPoint = 0; + for (ComputeBindingLayout binding : pipeline.bindings()) { + this.bind(bindingPoint++, binding, elements.get(bindingPoint)); + } + } + + public void bind(int bindingPoint, ComputeBindingLayout layout, T resource) { + layout.apply(bindingPoint, resource, this); + } + + public void bindTexture(int bindingPoint, TextureBinding.SamplerAndTexture resource) { + this.backend.bindTexture(bindingPoint, resource); + } + + public void bindImage(int bindingPoint, GpuTexture resource, boolean read, boolean write) { + this.backend.bindImage(bindingPoint, resource, read, write); + } + + public void bindUniformBlock(int bindingPoint, GpuBuffer resource) { + this.backend.bindUniformBlock(bindingPoint, resource); + } + + public void bindShaderStorage(int bindingPoint, GpuBuffer resource) { + this.backend.bindShaderStorage(bindingPoint, resource); + } + + public void bindAtomicCounter(int bindingPoint, GpuBuffer resource) { + this.backend.bindAtomicCounter(bindingPoint, resource); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java new file mode 100644 index 00000000..ec142e9f --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java @@ -0,0 +1,28 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.textures.GpuTexture; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; + +public interface ALRComputePassBackend extends AutoCloseable { + void pushDebugGroup(String name); + + void popDebugGroup(String name); + + void dispatchWorkgroups(int groupCountX, int groupCountY, int groupCountZ); + + void dispatchWorkgroupsIndirect(GpuBuffer buffer, long offset); + + void memoryBarrier(MemoryBarrierFlag... flags); + + void bindTexture(int bindingPoint, TextureBinding.SamplerAndTexture resource); + + void bindImage(int bindingPoint, GpuTexture resource, boolean read, boolean write); + + void bindUniformBlock(int bindingPoint, GpuBuffer resource); + + void bindShaderStorage(int bindingPoint, GpuBuffer resource); + + void bindAtomicCounter(int bindingPoint, GpuBuffer resource); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java new file mode 100644 index 00000000..745aa775 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java @@ -0,0 +1,98 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline; + +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ComputeBindingLayout; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.AtomicCounterBinding; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ImageBinding; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ShaderStorageBinding; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.UniformBlockBinding; +import net.minecraft.client.renderer.ShaderDefines; +import net.minecraft.resources.Identifier; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public record ALRComputePipeline(List> bindings, Identifier shaderLocation, ShaderDefines defines) { + + public static Builder builder() { + return new Builder(); + } + + public static Builder builder(ALRComputePipeline pipeline) { + return builder().withPipeline(pipeline); + } + + public static class Builder { + private final List> bindings = new ArrayList<>(); + private Identifier shaderLocation; + private ShaderDefines defines = ShaderDefines.EMPTY; + + public Builder withPipeline(ALRComputePipeline pipeline) { + this.bindings.clear(); + this.bindings.addAll(pipeline.bindings()); + this.shaderLocation = pipeline.shaderLocation(); + this.defines = pipeline.defines(); + return this; + } + + public Builder withShader(Identifier shaderLocation) { + this.shaderLocation = shaderLocation; + return this; + } + + public Builder withShaderLocation(Identifier shaderLocation) { + return this.withShader(shaderLocation); + } + + public Builder withDefines(ShaderDefines defines) { + this.defines = defines; + return this; + } + + public Builder withBinding(ComputeBindingLayout binding) { + this.bindings.add(binding); + return this; + } + + public Builder withTexture(String name) { + return this.withBinding(new TextureBinding(name)); + } + + public Builder withImage(String name, boolean read, boolean write) { + return this.withBinding(new ImageBinding(name, read, write)); + } + + public Builder withReadOnlyImage(String name) { + return this.withImage(name, true, false); + } + + public Builder withWriteOnlyImage(String name) { + return this.withImage(name, false, true); + } + + public Builder withReadWriteImage(String name) { + return this.withImage(name, true, true); + } + + public Builder withUniformBlock(String name) { + return this.withBinding(new UniformBlockBinding(name)); + } + + public Builder withShaderStorage(String name) { + return this.withBinding(new ShaderStorageBinding(name)); + } + + public Builder withAtomicCounter(String name) { + return this.withBinding(new AtomicCounterBinding(name)); + } + + public ALRComputePipeline build() { + return new ALRComputePipeline( + this.bindings, + Objects.requireNonNull(this.shaderLocation, "shaderLocation"), + this.defines + ); + } + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java new file mode 100644 index 00000000..3506c9d7 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java @@ -0,0 +1,19 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; + +public record AtomicCounterBinding( + String name +) implements ComputeBindingLayout { + @Override + public ShaderResourceType type() { + return ShaderResourceType.ATOMIC_COUNTER; + } + + @Override + public void apply(int bindingPoint, GpuBuffer resource, ALRComputePass computePass) { + computePass.bindAtomicCounter(bindingPoint, resource); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ComputeBindingLayout.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ComputeBindingLayout.java new file mode 100644 index 00000000..b9bbb054 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ComputeBindingLayout.java @@ -0,0 +1,12 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; + +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; + +public interface ComputeBindingLayout { + ShaderResourceType type(); + + String name(); + + void apply(int bindingPoint, T resource, ALRComputePass computePass); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ImageBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ImageBinding.java new file mode 100644 index 00000000..cbb1be70 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ImageBinding.java @@ -0,0 +1,28 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; + +import com.mojang.blaze3d.textures.GpuTexture; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; + +public record ImageBinding( + String name, + boolean read, + boolean write +) implements ComputeBindingLayout { + + public ImageBinding { + if (!read && !write) { + throw new IllegalArgumentException("ImageResource does not allow both read and write are false"); + } + } + + @Override + public ShaderResourceType type() { + return ShaderResourceType.IMAGE; + } + + @Override + public void apply(int bindingPoint, GpuTexture resource, ALRComputePass computePass) { + computePass.bindImage(bindingPoint, resource, read, write); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java new file mode 100644 index 00000000..9f34f62b --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java @@ -0,0 +1,19 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; + +public record ShaderStorageBinding( + String name +) implements ComputeBindingLayout { + @Override + public ShaderResourceType type() { + return ShaderResourceType.SHADER_STORAGE; + } + + @Override + public void apply(int bindingPoint, GpuBuffer resource, ALRComputePass computePass) { + computePass.bindShaderStorage(bindingPoint, resource); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/TextureBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/TextureBinding.java new file mode 100644 index 00000000..b3496008 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/TextureBinding.java @@ -0,0 +1,25 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; + +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTexture; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; + +public record TextureBinding( + String name +) implements ComputeBindingLayout { + @Override + public ShaderResourceType type() { + return ShaderResourceType.TEXTURE; + } + + @Override + public void apply(int bindingPoint, SamplerAndTexture resource, ALRComputePass pass) { + pass.bindTexture(bindingPoint, resource); + } + + public record SamplerAndTexture( + GpuSampler sampler, + GpuTexture texture + ){} +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java new file mode 100644 index 00000000..a1f621f3 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java @@ -0,0 +1,19 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; + +public record UniformBlockBinding( + String name +) implements ComputeBindingLayout { + @Override + public ShaderResourceType type() { + return ShaderResourceType.UNIFORM_BLOCK; + } + + @Override + public void apply(int bindingPoint, GpuBuffer resource, ALRComputePass computePass) { + computePass.bindUniformBlock(bindingPoint, resource); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java new file mode 100644 index 00000000..3d70a258 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java @@ -0,0 +1,64 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.gl; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.textures.GpuTexture; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePassBackend; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; + +public class GlComputePassBackend implements ALRComputePassBackend { + @Override + public void pushDebugGroup(String name) { + + } + + @Override + public void popDebugGroup(String name) { + + } + + @Override + public void dispatchWorkgroups(int groupCountX, int groupCountY, int groupCountZ) { + + } + + @Override + public void dispatchWorkgroupsIndirect(GpuBuffer buffer, long offset) { + + } + + @Override + public void memoryBarrier(MemoryBarrierFlag... flags) { + + } + + @Override + public void bindTexture(int bindingPoint, TextureBinding.SamplerAndTexture resource) { + + } + + @Override + public void bindImage(int bindingPoint, GpuTexture resource, boolean read, boolean write) { + + } + + @Override + public void bindUniformBlock(int bindingPoint, GpuBuffer resource) { + + } + + @Override + public void bindShaderStorage(int bindingPoint, GpuBuffer resource) { + + } + + @Override + public void bindAtomicCounter(int bindingPoint, GpuBuffer resource) { + + } + + @Override + public void close() throws Exception { + + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java new file mode 100644 index 00000000..31df7c7b --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java @@ -0,0 +1,4 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader; + +public class ALRComputeShaderInstance { +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstanceKey.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstanceKey.java new file mode 100644 index 00000000..bbed1a74 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstanceKey.java @@ -0,0 +1,7 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader; + +import net.minecraft.client.renderer.ShaderDefines; +import net.minecraft.resources.Identifier; + +public record ALRComputeShaderInstanceKey(Identifier identifier, ShaderDefines defines) { +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java new file mode 100644 index 00000000..5311ef4d --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java @@ -0,0 +1,81 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader; + +import com.google.common.collect.ImmutableMap; +import com.mojang.blaze3d.preprocessor.GlslPreprocessor; +import com.mojang.blaze3d.systems.RenderSystem; +import dev.anvilcraft.lib.v2.rendering.event.RegisterComputePipelinesEvent; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePipeline; +import lombok.extern.slf4j.Slf4j; +import net.minecraft.client.renderer.ShaderManager; +import net.minecraft.resources.Identifier; +import net.minecraft.server.packs.resources.Resource; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.server.packs.resources.SimplePreparableReloadListener; +import net.minecraft.util.profiling.ProfilerFiller; +import net.neoforged.fml.ModLoader; +import org.apache.commons.io.IOUtils; +import org.jetbrains.annotations.UnknownNullability; +import org.jspecify.annotations.Nullable; + +import java.io.IOException; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class ALRComputeShaderManager extends SimplePreparableReloadListener { + public static final ALRComputeShaderManager INSTANCE = new ALRComputeShaderManager(); + + @UnknownNullability + private ComputeShaderSource source = null; + + private Map shaderInstanceMap = new HashMap<>(); + + @Override + protected ComputeShaderSource prepare(ResourceManager manager, ProfilerFiller profiler) { + ImmutableMap.Builder sources = new ImmutableMap.Builder<>(); + + Map shaders = manager.listResources( + "shaders", + it -> it.getPath().endsWith(".csh") || it.getPath().endsWith(".compute") || it.getPath().endsWith(".glsl") + ); + + for (Map.Entry it : shaders.entrySet()) { + GlslPreprocessor preprocessor = ShaderManager.createPreprocessor(shaders, it.getKey()); + + try (Reader reader = it.getValue().openAsReader()) { + String source = IOUtils.toString(reader); + sources.put(it.getKey(), String.join("", preprocessor.process(source))); + } catch (IOException ex) { + log.error("Failed to load compute shader source at {}", it.getKey(), ex); + } + } + + return new ComputeShaderSource(sources.build()); + } + + @Override + protected void apply(ComputeShaderSource preparations, ResourceManager manager, ProfilerFiller profiler) { + this.source = preparations; + RegisterComputePipelinesEvent event = new RegisterComputePipelinesEvent(); + ModLoader.postEvent(event); + ALRGpuDeviceExtension deviceExtension = (ALRGpuDeviceExtension) RenderSystem.getDevice(); + for (ALRComputePipeline pipeline : event.getPipelines()) { + ALRComputeShaderInstanceKey key = new ALRComputeShaderInstanceKey(pipeline.shaderLocation(), pipeline.defines()); + + ALRComputeShaderInstance instance = deviceExtension.alrCompileComputeShader(key); + } + + } + + @Nullable + public String getSource(Identifier location) { + return source.source.get(location); + } + + public record ComputeShaderSource( + Map source + ) { + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ShaderResourceType.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ShaderResourceType.java new file mode 100644 index 00000000..e615402c --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ShaderResourceType.java @@ -0,0 +1,9 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader; + +public enum ShaderResourceType { + TEXTURE, + IMAGE, + UNIFORM_BLOCK, + SHADER_STORAGE, + ATOMIC_COUNTER +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferLayout.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferLayout.java new file mode 100644 index 00000000..3a95b3d2 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferLayout.java @@ -0,0 +1,38 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std140.Std140SizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std140.Std140Writer; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std430.Std430SizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std430.Std430Writer; + +import java.nio.ByteBuffer; + +public interface BufferLayout { + BufferLayout STD140 = new BufferLayout() { + @Override + public BufferSizeCalculator createSizeCalculator() { + return new Std140SizeCalculator(); + } + + @Override + public BufferWriter createWriter(ByteBuffer buffer) { + return new Std140Writer(buffer); + } + }; + + BufferLayout STD430 = new BufferLayout() { + @Override + public BufferSizeCalculator createSizeCalculator() { + return new Std430SizeCalculator(); + } + + @Override + public BufferWriter createWriter(ByteBuffer buffer) { + return new Std430Writer(buffer); + } + }; + + BufferSizeCalculator createSizeCalculator(); + + BufferWriter createWriter(ByteBuffer buffer); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferSizeCalculator.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferSizeCalculator.java new file mode 100644 index 00000000..4cefe363 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferSizeCalculator.java @@ -0,0 +1,27 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; + +public interface BufferSizeCalculator { + void putFloat(); + + void putVec2(); + + void putVec3(); + + void putVec4(); + + void putInt(); + + void putIVec2(); + + void putIVec3(); + + void putIVec4(); + + void putMat4f(); + + void putStructArray(BufferObjectLayoutDefinition definition, int size); + + int get(); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferWriter.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferWriter.java new file mode 100644 index 00000000..ab77d5c8 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/BufferWriter.java @@ -0,0 +1,42 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector4f; +import org.joml.Vector4i; + +import java.nio.ByteBuffer; + +public interface BufferWriter { + void putMat4f(Matrix4f object); + + void putIVec4(Vector4i object); + + void putIVec3(Vector3i object); + + void putIVec2(Vector2i object); + + void putInt(int object); + + void putVec4(Vector4f object); + + void putVec3(Vector3f object); + + void putVec2(Vector2f object); + + void putFloat(float object); + + ByteBuffer intoBuffer(); + + void putStructArray(int index, E object, BufferObjectLayoutDefinition definition); + + default void putStructArray(E[] objects, BufferObjectLayoutDefinition definition) { + for (int i = 0; i < objects.length; i++) { + putStructArray(i, objects[i], definition); + } + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java new file mode 100644 index 00000000..b74d92d7 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java @@ -0,0 +1,76 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std140; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferSizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import net.minecraft.util.Mth; + +public final class Std140SizeCalculator implements BufferSizeCalculator { + + private int size; + + public Std140SizeCalculator() { + } + + public void align(int alignment) { + this.size = Mth.roundToward(this.size, alignment); + } + + public void putFloat() { + this.align(4); + this.size += 4; + } + + public void putInt() { + this.align(4); + this.size += 4; + } + + public void putVec2() { + this.align(8); + this.size += 8; + } + + public void putIVec2() { + this.align(8); + this.size += 8; + } + + public void putVec3() { + this.align(16); + this.size += 16; + } + + public void putIVec3() { + this.align(16); + this.size += 16; + } + + public void putVec4() { + this.align(16); + this.size += 16; + } + + public void putIVec4() { + this.align(16); + this.size += 16; + } + + public void putMat4f() { + this.align(16); + this.size += 64; + } + + @Override + public void putStructArray(BufferObjectLayoutDefinition definition, int size) { + int alignment = Mth.roundToward(definition.alignment(BufferLayout.STD140), 16); + int stride = Mth.roundToward(definition.size(BufferLayout.STD140), alignment); + this.align(alignment); + this.size += stride * size; + } + + @Override + public int get() { + return size; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java new file mode 100644 index 00000000..33b3f473 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java @@ -0,0 +1,132 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std140; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferWriter; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import net.minecraft.util.Mth; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector4f; +import org.joml.Vector4i; + +import java.nio.ByteBuffer; + +public final class Std140Writer implements BufferWriter { + + private final ByteBuffer buffer; + private final int pointer; + private BufferObjectLayoutDefinition indexedArrayDefinition; + private int indexedArrayStart; + private int indexedArrayStride; + private int indexedArrayEnd; + + public Std140Writer(ByteBuffer buffer) { + this.buffer = buffer; + this.pointer = buffer.position(); + } + + public void align(int alignment) { + int position = this.buffer.position(); + this.buffer.position(this.pointer + Mth.roundToward(position - this.pointer, alignment)); + } + + public void putFloat(float value) { + this.align(4); + this.buffer.putFloat(value); + } + + public void putInt(int value) { + this.align(4); + this.buffer.putInt(value); + } + + public void putVec2(Vector2f vec) { + this.align(8); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 8); + } + + public void putIVec2(Vector2i vec) { + this.align(8); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 8); + } + + public void putVec3(Vector3f vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putIVec3(Vector3i vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putVec4(Vector4f vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putIVec4(Vector4i vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putMat4f(Matrix4f vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 64); + } + + public ByteBuffer intoBuffer() { + return this.buffer.flip(); + } + + @Override + public void putStructArray(int index, E object, BufferObjectLayoutDefinition definition) { + int alignment = Mth.roundToward(definition.alignment(BufferLayout.STD140), 16); + int stride = Mth.roundToward(definition.size(BufferLayout.STD140), alignment); + int arrayStart = this.indexedArrayStart(definition, alignment, stride); + int elementStart = arrayStart + stride * index; + this.buffer.position(elementStart); + definition.writeInto(this, object); + this.indexedArrayEnd = Math.max(this.indexedArrayEnd, elementStart + stride); + this.buffer.position(this.indexedArrayEnd); + } + + @Override + public void putStructArray(E[] objects, BufferObjectLayoutDefinition definition) { + int alignment = Mth.roundToward(definition.alignment(BufferLayout.STD140), 16); + int stride = Mth.roundToward(definition.size(BufferLayout.STD140), alignment); + int arrayStart = this.pointer + Mth.roundToward(this.buffer.position() - this.pointer, alignment); + for (int i = 0; i < objects.length; i++) { + this.buffer.position(arrayStart + stride * i); + definition.writeInto(this, objects[i]); + } + this.buffer.position(arrayStart + stride * objects.length); + this.indexedArrayDefinition = null; + } + + private int indexedArrayStart(BufferObjectLayoutDefinition definition, int alignment, int stride) { + int position = this.buffer.position(); + if (this.indexedArrayDefinition == definition + && this.indexedArrayStride == stride + && position >= this.indexedArrayStart + && position <= this.indexedArrayEnd) { + return this.indexedArrayStart; + } + + this.indexedArrayDefinition = definition; + this.indexedArrayStart = this.pointer + Mth.roundToward(position - this.pointer, alignment); + this.indexedArrayStride = stride; + this.indexedArrayEnd = this.indexedArrayStart; + return this.indexedArrayStart; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java new file mode 100644 index 00000000..e822ac63 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java @@ -0,0 +1,75 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std430; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferSizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import net.minecraft.util.Mth; + +public class Std430SizeCalculator implements BufferSizeCalculator { + private int size; + + public Std430SizeCalculator() { + } + + public void align(int alignment) { + this.size = Mth.roundToward(this.size, alignment); + } + + public void putFloat() { + this.align(4); + this.size += 4; + } + + public void putInt() { + this.align(4); + this.size += 4; + } + + public void putVec2() { + this.align(8); + this.size += 8; + } + + public void putIVec2() { + this.align(8); + this.size += 8; + } + + public void putVec3() { + this.align(16); + this.size += 16; + } + + public void putIVec3() { + this.align(16); + this.size += 16; + } + + public void putVec4() { + this.align(16); + this.size += 16; + } + + public void putIVec4() { + this.align(16); + this.size += 16; + } + + public void putMat4f() { + this.align(16); + this.size += 64; + } + + @Override + public void putStructArray(BufferObjectLayoutDefinition definition, int size) { + int alignment = definition.alignment(BufferLayout.STD430); + int stride = Mth.roundToward(definition.size(BufferLayout.STD430), alignment); + this.align(alignment); + this.size += stride * size; + } + + @Override + public int get() { + return size; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java new file mode 100644 index 00000000..46dd12fd --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java @@ -0,0 +1,134 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std430; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferWriter; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import net.minecraft.util.Mth; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector4f; +import org.joml.Vector4i; + +import java.nio.ByteBuffer; + +public class Std430Writer implements BufferWriter { + + private final ByteBuffer buffer; + private final int pointer; + private BufferObjectLayoutDefinition indexedArrayDefinition; + private int indexedArrayStart; + private int indexedArrayStride; + private int indexedArrayEnd; + + public Std430Writer(ByteBuffer buffer) { + this.buffer = buffer; + this.pointer = buffer.position(); + } + + public void align(int alignment) { + int position = this.buffer.position(); + this.buffer.position(this.pointer + Mth.roundToward(position - this.pointer, alignment)); + } + + public void putFloat(float value) { + this.align(4); + this.buffer.putFloat(value); + } + + public void putInt(int value) { + this.align(4); + this.buffer.putInt(value); + } + + public void putVec2(Vector2f vec) { + this.align(8); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 8); + } + + public void putIVec2(Vector2i vec) { + this.align(8); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 8); + } + + public void putVec3(Vector3f vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putIVec3(Vector3i vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putVec4(Vector4f vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putIVec4(Vector4i vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 16); + } + + public void putMat4f(Matrix4f vec) { + this.align(16); + vec.get(this.buffer); + this.buffer.position(this.buffer.position() + 64); + } + + public ByteBuffer intoBuffer() { + return this.buffer.flip(); + } + + @Override + public void putStructArray(int index, E object, BufferObjectLayoutDefinition definition) { + int alignment = definition.alignment(BufferLayout.STD430); + int stride = Mth.roundToward(definition.size(BufferLayout.STD430), alignment); + int arrayStart = this.indexedArrayStart(definition, alignment, stride); + int elementStart = arrayStart + stride * index; + this.buffer.position(elementStart); + definition.writeInto(this, object); + this.indexedArrayEnd = Math.max(this.indexedArrayEnd, elementStart + stride); + this.buffer.position(this.indexedArrayEnd); + } + + @Override + public void putStructArray(E[] objects, BufferObjectLayoutDefinition definition) { + int alignment = definition.alignment(BufferLayout.STD430); + int stride = Mth.roundToward(definition.size(BufferLayout.STD430), alignment); + int arrayStart = this.pointer + Mth.roundToward(this.buffer.position() - this.pointer, alignment); + for (int i = 0; i < objects.length; i++) { + this.buffer.position(arrayStart + stride * i); + definition.writeInto(this, objects[i]); + } + this.buffer.position(arrayStart + stride * objects.length); + this.indexedArrayDefinition = null; + } + + private int indexedArrayStart(BufferObjectLayoutDefinition definition, int alignment, int stride) { + int position = this.buffer.position(); + if ( + this.indexedArrayDefinition == definition + && this.indexedArrayStride == stride + && position >= this.indexedArrayStart + && position <= this.indexedArrayEnd + ) { + return this.indexedArrayStart; + } + + this.indexedArrayDefinition = definition; + this.indexedArrayStart = this.pointer + Mth.roundToward(position - this.pointer, alignment); + this.indexedArrayStride = stride; + this.indexedArrayEnd = this.indexedArrayStart; + return this.indexedArrayStart; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboObject.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObject.java similarity index 51% rename from module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboObject.java rename to module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObject.java index a016e6b4..a0c1ff2a 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboObject.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObject.java @@ -1,22 +1,31 @@ -package dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo; +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.object; import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.systems.CommandEncoder; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; import net.minecraft.client.renderer.DynamicUniformStorage; import org.jspecify.annotations.NonNull; import org.lwjgl.system.MemoryStack; import java.nio.ByteBuffer; -public abstract class UboObject> implements DynamicUniformStorage.DynamicUniform { +public abstract class BufferObject> implements DynamicUniformStorage.DynamicUniform { - protected abstract UboLayoutDefinition getDefinition(); + protected final BufferLayout layout; + protected final ShaderBufferObjectUsage usage; + + protected BufferObject(BufferLayout layout, ShaderBufferObjectUsage usage) { + this.layout = layout; + this.usage = usage; + } + + protected abstract BufferObjectLayoutDefinition getDefinition(); @SuppressWarnings("unchecked") public void upload(CommandEncoder commandEncoder, GpuBufferSlice dest) { try (MemoryStack memoryStack = MemoryStack.stackPush()) { - ByteBuffer malloc = getDefinition().write(memoryStack.malloc(getDefinition().size()), (T) this); + ByteBuffer malloc = getDefinition().write(memoryStack.malloc(getDefinition().size(this.layout)), (T) this, this.layout); commandEncoder.writeToBuffer(dest, malloc); } } @@ -24,14 +33,14 @@ public void upload(CommandEncoder commandEncoder, GpuBufferSlice dest) { @Override @SuppressWarnings("unchecked") public void write(@NonNull ByteBuffer buffer) { - getDefinition().write(buffer, (T) this); + getDefinition().write(buffer, (T) this, this.layout); } public DynamicUniformStorage createDynamicStorage(String label) { return new DynamicUniformStorage<>( - label, - getDefinition().size(), - GpuBuffer.USAGE_UNIFORM | GpuBuffer.USAGE_COPY_DST + label, + getDefinition().size(this.layout), + GpuBuffer.USAGE_UNIFORM | GpuBuffer.USAGE_COPY_DST ); } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutDefinition.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutDefinition.java new file mode 100644 index 00000000..39235b4a --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutDefinition.java @@ -0,0 +1,51 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.object; + +import com.google.common.collect.ImmutableList; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferSizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferWriter; + +import java.nio.ByteBuffer; + +public class BufferObjectLayoutDefinition { + private final ImmutableList> entries; + + public BufferObjectLayoutDefinition(ImmutableList> entries) { + this.entries = entries; + } + + public ByteBuffer write(ByteBuffer buffer, T object, BufferLayout layout) { + BufferWriter builder = layout.createWriter(buffer); + this.writeInto(builder, object); + return builder.intoBuffer(); + } + + public void writeInto(BufferWriter writer, T object) { + for (BufferObjectLayoutEntry entry : entries) { + entry.acceptWriter(writer, object); + } + } + + public int size(BufferLayout layout) { + BufferSizeCalculator sizeCalculator = layout.createSizeCalculator(); + for (BufferObjectLayoutEntry entry : entries) { + entry.acceptSizeCalculator(sizeCalculator); + } + return sizeCalculator.get(); + } + + public int alignment(BufferLayout layout) { + int alignment = 1; + for (BufferObjectLayoutEntry entry : entries) { + alignment = Math.max(alignment, entry.alignment(layout)); + } + return layout == BufferLayout.STD140 ? Math.max(alignment, 16) : alignment; + } + + @SafeVarargs + public static BufferObjectLayoutDefinition create(BufferObjectLayoutEntry... entries) { + ImmutableList.Builder> builder = ImmutableList.builder(); + builder.add(entries); + return new BufferObjectLayoutDefinition<>(builder.build()); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntry.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntry.java new file mode 100644 index 00000000..c44fad34 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntry.java @@ -0,0 +1,87 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.object; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferSizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferWriter; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector4f; +import org.joml.Vector4i; + +import java.util.function.Function; + +public record BufferObjectLayoutEntry(BufferObjectLayoutEntryType type, Function getter) { + + void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + type.acceptSizeCalculator(sizeCalculator); + } + + void acceptWriter(BufferWriter writer, I object) { + type.acceptWriter(writer, getter.apply(object)); + } + + int alignment(BufferLayout layout) { + return type.alignment(layout); + } + + public static Builder builder(BufferObjectLayoutEntryType type) { + return new Builder<>(type); + } + + public static Builder ofInt() { + return builder(BufferObjectLayoutEntryType.INT); + } + + public static Builder ofFloat() { + return builder(BufferObjectLayoutEntryType.FLOAT); + } + + public static Builder ofVec2f() { + return builder(BufferObjectLayoutEntryType.VEC2); + } + + public static Builder ofVec3f() { + return builder(BufferObjectLayoutEntryType.VEC3); + } + + public static Builder ofVec4f() { + return builder(BufferObjectLayoutEntryType.VEC4); + } + + public static Builder ofVec2i() { + return builder(BufferObjectLayoutEntryType.IVEC2); + } + + public static Builder ofVec3i() { + return builder(BufferObjectLayoutEntryType.IVEC3); + } + + public static Builder ofVec4i() { + return builder(BufferObjectLayoutEntryType.IVEC4); + } + + public static Builder ofMat4f() { + return builder(BufferObjectLayoutEntryType.MAT4); + } + + public static class Builder { + private final BufferObjectLayoutEntryType type; + private Function getter; + + public Builder(BufferObjectLayoutEntryType type) { + this.type = type; + } + + public Builder forGetter(Function getter) { + this.getter = getter; + return this; + } + + public BufferObjectLayoutEntry build() { + return new BufferObjectLayoutEntry<>(type, getter); + } + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntryType.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntryType.java new file mode 100644 index 00000000..59619c46 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/BufferObjectLayoutEntryType.java @@ -0,0 +1,173 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.object; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferSizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferWriter; +import org.joml.Matrix4f; +import org.joml.Vector2f; +import org.joml.Vector2i; +import org.joml.Vector3f; +import org.joml.Vector3i; +import org.joml.Vector4f; +import org.joml.Vector4i; + +public interface BufferObjectLayoutEntryType { + BufferObjectLayoutEntryType FLOAT = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putFloat(); + } + + @Override + public void acceptWriter(BufferWriter writer, Float object) { + writer.putFloat(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 4; + } + }; + + BufferObjectLayoutEntryType VEC2 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putVec2(); + } + + @Override + public void acceptWriter(BufferWriter writer, Vector2f object) { + writer.putVec2(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 8; + } + }; + + BufferObjectLayoutEntryType VEC3 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putVec3(); + } + + @Override + public void acceptWriter(BufferWriter writer, Vector3f object) { + writer.putVec3(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 16; + } + }; + + BufferObjectLayoutEntryType VEC4 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putVec4(); + } + + @Override + public void acceptWriter(BufferWriter writer, Vector4f object) { + writer.putVec4(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 16; + } + }; + + BufferObjectLayoutEntryType INT = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putInt(); + } + + @Override + public void acceptWriter(BufferWriter writer, Integer object) { + writer.putInt(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 4; + } + }; + + BufferObjectLayoutEntryType IVEC2 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putIVec2(); + } + + @Override + public void acceptWriter(BufferWriter writer, Vector2i object) { + writer.putIVec2(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 8; + } + }; + + BufferObjectLayoutEntryType IVEC3 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putIVec3(); + } + + @Override + public void acceptWriter(BufferWriter writer, Vector3i object) { + writer.putIVec3(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 16; + } + }; + + BufferObjectLayoutEntryType IVEC4 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putIVec4(); + } + + @Override + public void acceptWriter(BufferWriter writer, Vector4i object) { + writer.putIVec4(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 16; + } + }; + + BufferObjectLayoutEntryType MAT4 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putMat4f(); + } + + @Override + public void acceptWriter(BufferWriter writer, Matrix4f object) { + writer.putMat4f(object); + } + + @Override + public int alignment(BufferLayout layout) { + return 16; + } + }; + + void acceptSizeCalculator(BufferSizeCalculator sizeCalculator); + + void acceptWriter(BufferWriter writer, T object); + + int alignment(BufferLayout layout); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/ShaderBufferObjectUsage.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/ShaderBufferObjectUsage.java new file mode 100644 index 00000000..923648bb --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/object/ShaderBufferObjectUsage.java @@ -0,0 +1,6 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.object; + +public enum ShaderBufferObjectUsage { + UBO, + SSBO +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutDefinition.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutDefinition.java deleted file mode 100644 index c567d850..00000000 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutDefinition.java +++ /dev/null @@ -1,38 +0,0 @@ -package dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo; - -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.buffers.Std140Builder; -import com.mojang.blaze3d.buffers.Std140SizeCalculator; - -import java.nio.ByteBuffer; - -public class UboLayoutDefinition { - private final ImmutableList> entries; - - public UboLayoutDefinition(ImmutableList> entries) { - this.entries = entries; - } - - public ByteBuffer write(ByteBuffer buffer, T object) { - Std140Builder builder = Std140Builder.intoBuffer(buffer); - for (UboLayoutEntry entry : entries) { - entry.acceptWriter(builder, object); - } - return builder.get(); - } - - public int size() { - Std140SizeCalculator sizeCalculator = new Std140SizeCalculator(); - for (UboLayoutEntry entry : entries) { - entry.acceptSizeCalculator(sizeCalculator); - } - return sizeCalculator.get(); - } - - @SafeVarargs - public static UboLayoutDefinition create(UboLayoutEntry... entries) { - ImmutableList.Builder> builder = ImmutableList.builder(); - builder.add(entries); - return new UboLayoutDefinition<>(builder.build()); - } -} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntry.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntry.java deleted file mode 100644 index 7f3b5da5..00000000 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntry.java +++ /dev/null @@ -1,82 +0,0 @@ -package dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo; - -import com.mojang.blaze3d.buffers.Std140Builder; -import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import org.joml.Matrix4f; -import org.joml.Vector2f; -import org.joml.Vector2i; -import org.joml.Vector3f; -import org.joml.Vector3i; -import org.joml.Vector4f; -import org.joml.Vector4i; - -import java.util.function.Function; - -public record UboLayoutEntry(UboLayoutEntryType type, Function getter) { - - void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - type.acceptSizeCalculator(sizeCalculator); - } - - void acceptWriter(Std140Builder writer, I object) { - type.acceptWriter(writer, getter.apply(object)); - } - - public static Builder builder(UboLayoutEntryType type) { - return new Builder<>(type); - } - - public static Builder ofInt() { - return builder(UboLayoutEntryType.INT); - } - - public static Builder ofFloat() { - return builder(UboLayoutEntryType.FLOAT); - } - - public static Builder ofVec2f() { - return builder(UboLayoutEntryType.VEC2); - } - - public static Builder ofVec3f() { - return builder(UboLayoutEntryType.VEC3); - } - - public static Builder ofVec4f() { - return builder(UboLayoutEntryType.VEC4); - } - - public static Builder ofVec2i() { - return builder(UboLayoutEntryType.IVEC2); - } - - public static Builder ofVec3i() { - return builder(UboLayoutEntryType.IVEC3); - } - - public static Builder ofVec4i() { - return builder(UboLayoutEntryType.IVEC4); - } - - public static Builder ofMat4f() { - return builder(UboLayoutEntryType.MAT4); - } - - public static class Builder { - private final UboLayoutEntryType type; - private Function getter; - - public Builder(UboLayoutEntryType type) { - this.type = type; - } - - public Builder forGetter(Function getter) { - this.getter = getter; - return this; - } - - public UboLayoutEntry build() { - return new UboLayoutEntry<>(type, getter); - } - } -} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntryType.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntryType.java deleted file mode 100644 index b0a68957..00000000 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/ubo/UboLayoutEntryType.java +++ /dev/null @@ -1,125 +0,0 @@ -package dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo; - -import com.mojang.blaze3d.buffers.Std140Builder; -import com.mojang.blaze3d.buffers.Std140SizeCalculator; -import org.joml.Matrix4f; -import org.joml.Vector2f; -import org.joml.Vector2i; -import org.joml.Vector3f; -import org.joml.Vector3i; -import org.joml.Vector4f; -import org.joml.Vector4i; - -public interface UboLayoutEntryType { - UboLayoutEntryType FLOAT = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putFloat(); - } - - @Override - public void acceptWriter(Std140Builder writer, Float object) { - writer.putFloat(object); - } - }; - - UboLayoutEntryType VEC2 = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putVec2(); - } - - @Override - public void acceptWriter(Std140Builder writer, Vector2f object) { - writer.putVec2(object); - } - }; - - UboLayoutEntryType VEC3 = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putVec3(); - } - - @Override - public void acceptWriter(Std140Builder writer, Vector3f object) { - writer.putVec3(object); - } - }; - - UboLayoutEntryType VEC4 = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putVec4(); - } - - @Override - public void acceptWriter(Std140Builder writer, Vector4f object) { - writer.putVec4(object); - } - }; - - UboLayoutEntryType INT = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putInt(); - } - - @Override - public void acceptWriter(Std140Builder writer, Integer object) { - writer.putInt(object); - } - }; - - UboLayoutEntryType IVEC2 = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putIVec2(); - } - - @Override - public void acceptWriter(Std140Builder writer, Vector2i object) { - writer.putIVec2(object); - } - }; - - UboLayoutEntryType IVEC3 = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putIVec3(); - } - - @Override - public void acceptWriter(Std140Builder writer, Vector3i object) { - writer.putIVec3(object); - } - }; - - UboLayoutEntryType IVEC4 = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putIVec4(); - } - - @Override - public void acceptWriter(Std140Builder writer, Vector4i object) { - writer.putIVec4(object); - } - }; - - UboLayoutEntryType MAT4 = new UboLayoutEntryType<>() { - @Override - public void acceptSizeCalculator(Std140SizeCalculator sizeCalculator) { - sizeCalculator.putMat4f(); - } - - @Override - public void acceptWriter(Std140Builder writer, Matrix4f object) { - writer.putMat4f(object); - } - }; - - void acceptSizeCalculator(Std140SizeCalculator sizeCalculator); - - void acceptWriter(Std140Builder writer, T object); -} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfGraphics.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfGraphics.java index 75304500..a469b3a8 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfGraphics.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfGraphics.java @@ -9,6 +9,7 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import dev.anvilcraft.lib.v2.rendering.ALRPipelines; import dev.anvilcraft.lib.v2.rendering.AnvilLibRendering; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; import dev.anvilcraft.lib.v2.rendering.state.LibGuiElementRenderState; import lombok.AccessLevel; import lombok.Getter; @@ -34,7 +35,7 @@ @RequiredArgsConstructor(access = AccessLevel.PRIVATE) public final class SdfGraphics { private static final int MAX_SDF_AMOUNT = 256; - private static final long SDF_PARAMETER_SIZE = SdfParameters.DEFINITION.size(); + private static final long SDF_PARAMETER_SIZE = SdfParameters.DEFINITION.size(BufferLayout.STD140); @Getter public static final SdfGraphics instance = new SdfGraphics(new SdfParameters()); diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfParameters.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfParameters.java index 04963a39..8add02dc 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfParameters.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/sdf/SdfParameters.java @@ -1,21 +1,23 @@ package dev.anvilcraft.lib.v2.rendering.sdf; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutDefinition; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboLayoutEntry; -import dev.anvilcraft.lib.v2.rendering.foundation.buffers.ubo.UboObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.ShaderBufferObjectUsage; import lombok.Getter; import net.minecraft.util.Mth; import org.joml.Vector4f; import org.joml.Vector4i; @Getter -public class SdfParameters extends UboObject { +public class SdfParameters extends BufferObject { - public static final UboLayoutDefinition DEFINITION = UboLayoutDefinition.create( - UboLayoutEntry.ofVec4f().forGetter(SdfParameters::getSharedParams).build(), - UboLayoutEntry.ofVec4f().forGetter(SdfParameters::getShapeParams).build(), - UboLayoutEntry.ofVec4f().forGetter(SdfParameters::getRect).build(), - UboLayoutEntry.ofVec4i().forGetter(SdfParameters::getTypeParams).build() + public static final BufferObjectLayoutDefinition DEFINITION = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofVec4f().forGetter(SdfParameters::getSharedParams).build(), + BufferObjectLayoutEntry.ofVec4f().forGetter(SdfParameters::getShapeParams).build(), + BufferObjectLayoutEntry.ofVec4f().forGetter(SdfParameters::getRect).build(), + BufferObjectLayoutEntry.ofVec4i().forGetter(SdfParameters::getTypeParams).build() ); private final Vector4f sharedParams = new Vector4f(); @@ -27,6 +29,10 @@ public class SdfParameters extends UboObject { private float rotation; private boolean center; + protected SdfParameters() { + super(BufferLayout.STD140, ShaderBufferObjectUsage.UBO); + } + public void box(float width, float height) { this ._renderType(SdfRenderType.BOX); this.shapeParams .set(width * 0.5f, height * 0.5f, 0.0f, 0.0f); @@ -184,7 +190,7 @@ private void _renderType(SdfRenderType value) { } @Override - protected UboLayoutDefinition getDefinition() { + protected BufferObjectLayoutDefinition getDefinition() { return DEFINITION; } diff --git a/module.rendering/src/main/resources/META-INF/accesstransformer.cfg b/module.rendering/src/main/resources/META-INF/accesstransformer.cfg index 882b550f..c2fa8ec3 100644 --- a/module.rendering/src/main/resources/META-INF/accesstransformer.cfg +++ b/module.rendering/src/main/resources/META-INF/accesstransformer.cfg @@ -12,4 +12,6 @@ public net.minecraft.client.renderer.rendertype.RenderSetup pipeline public net.minecraft.client.renderer.rendertype.RenderSetup outputTarget public net.minecraft.client.renderer.rendertype.RenderSetup textureTransform public net.minecraft.client.renderer.rendertype.RenderType name -public net.minecraft.client.renderer.rendertype.RenderType outline \ No newline at end of file +public net.minecraft.client.renderer.rendertype.RenderType outline + +public net.minecraft.client.renderer.ShaderManager createPreprocessor(Ljava/util/Map;Lnet/minecraft/resources/Identifier;)Lcom/mojang/blaze3d/preprocessor/GlslPreprocessor; \ No newline at end of file diff --git a/module.rendering/src/test/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/Std140LayoutRulesTest.java b/module.rendering/src/test/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/Std140LayoutRulesTest.java new file mode 100644 index 00000000..e8b98154 --- /dev/null +++ b/module.rendering/src/test/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/Std140LayoutRulesTest.java @@ -0,0 +1,139 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std140.Std140SizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std140.Std140Writer; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std430.Std430SizeCalculator; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.std430.Std430Writer; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntryType; + +import java.nio.ByteBuffer; + +public final class Std140LayoutRulesTest { + private static final BufferObjectLayoutEntryType TEST_VEC2 = new BufferObjectLayoutEntryType<>() { + @Override + public void acceptSizeCalculator(BufferSizeCalculator sizeCalculator) { + sizeCalculator.putVec2(); + } + + @Override + public void acceptWriter(BufferWriter writer, Object object) { + } + + @Override + public int alignment(BufferLayout layout) { + return 8; + } + }; + + private Std140LayoutRulesTest() { + } + + public static void main(String[] args) { + BufferObjectLayoutDefinition structDefinition = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.builder(TEST_VEC2).forGetter(ignored -> null).build(), + BufferObjectLayoutEntry.ofFloat().forGetter(TestStruct::value).build() + ); + + assertEquals(16, structDefinition.alignment(BufferLayout.STD140), "std140 struct alignment"); + + Std140SizeCalculator calculator = new Std140SizeCalculator(); + calculator.putStructArray(structDefinition, 2); + + assertEquals(32, calculator.get(), "std140 struct array size"); + + BufferObjectLayoutDefinition compactStructDefinition = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofFloat().forGetter(TestStruct::value).build(), + BufferObjectLayoutEntry.ofFloat().forGetter(TestStruct::value).build() + ); + + Std430SizeCalculator std430Calculator = new Std430SizeCalculator(); + std430Calculator.putStructArray(compactStructDefinition, 2); + + assertEquals(16, std430Calculator.get(), "std430 struct array size"); + + BufferObjectLayoutDefinition pairDefinition = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofFloat().forGetter(TestPair::first).build(), + BufferObjectLayoutEntry.ofFloat().forGetter(TestPair::second).build() + ); + + ByteBuffer std140Buffer = ByteBuffer.allocate(64); + Std140Writer std140Writer = new Std140Writer(std140Buffer); + std140Writer.putStructArray(new TestPair[]{ + new TestPair(1.0f, 2.0f), + new TestPair(3.0f, 4.0f) + }, pairDefinition); + + assertFloatEquals(1.0f, std140Buffer.getFloat(0), "std140 array[0].first"); + assertFloatEquals(2.0f, std140Buffer.getFloat(4), "std140 array[0].second"); + assertFloatEquals(3.0f, std140Buffer.getFloat(16), "std140 array[1].first"); + assertFloatEquals(4.0f, std140Buffer.getFloat(20), "std140 array[1].second"); + + ByteBuffer std430Buffer = ByteBuffer.allocate(64); + Std430Writer std430Writer = new Std430Writer(std430Buffer); + std430Writer.putStructArray(new TestPair[]{ + new TestPair(1.0f, 2.0f), + new TestPair(3.0f, 4.0f) + }, pairDefinition); + + assertFloatEquals(1.0f, std430Buffer.getFloat(0), "std430 array[0].first"); + assertFloatEquals(2.0f, std430Buffer.getFloat(4), "std430 array[0].second"); + assertFloatEquals(3.0f, std430Buffer.getFloat(8), "std430 array[1].first"); + assertFloatEquals(4.0f, std430Buffer.getFloat(12), "std430 array[1].second"); + + ByteBuffer std140IndexedBuffer = ByteBuffer.allocate(64); + Std140Writer std140IndexedWriter = new Std140Writer(std140IndexedBuffer); + std140IndexedWriter.putStructArray(1, new TestPair(5.0f, 6.0f), pairDefinition); + + assertFloatEquals(0.0f, std140IndexedBuffer.getFloat(0), "std140 indexed array[0].first"); + assertFloatEquals(5.0f, std140IndexedBuffer.getFloat(16), "std140 indexed array[1].first"); + assertFloatEquals(6.0f, std140IndexedBuffer.getFloat(20), "std140 indexed array[1].second"); + + ByteBuffer std430IndexedBuffer = ByteBuffer.allocate(64); + Std430Writer std430IndexedWriter = new Std430Writer(std430IndexedBuffer); + std430IndexedWriter.putStructArray(1, new TestPair(5.0f, 6.0f), pairDefinition); + + assertFloatEquals(0.0f, std430IndexedBuffer.getFloat(0), "std430 indexed array[0].first"); + assertFloatEquals(5.0f, std430IndexedBuffer.getFloat(8), "std430 indexed array[1].first"); + assertFloatEquals(6.0f, std430IndexedBuffer.getFloat(12), "std430 indexed array[1].second"); + + ByteBuffer std140SequentialIndexedBuffer = ByteBuffer.allocate(64); + Std140Writer std140SequentialIndexedWriter = new Std140Writer(std140SequentialIndexedBuffer); + std140SequentialIndexedWriter.putStructArray(0, new TestPair(1.0f, 2.0f), pairDefinition); + std140SequentialIndexedWriter.putStructArray(1, new TestPair(3.0f, 4.0f), pairDefinition); + + assertFloatEquals(1.0f, std140SequentialIndexedBuffer.getFloat(0), "std140 sequential indexed array[0].first"); + assertFloatEquals(2.0f, std140SequentialIndexedBuffer.getFloat(4), "std140 sequential indexed array[0].second"); + assertFloatEquals(3.0f, std140SequentialIndexedBuffer.getFloat(16), "std140 sequential indexed array[1].first"); + assertFloatEquals(4.0f, std140SequentialIndexedBuffer.getFloat(20), "std140 sequential indexed array[1].second"); + + ByteBuffer std430SequentialIndexedBuffer = ByteBuffer.allocate(64); + Std430Writer std430SequentialIndexedWriter = new Std430Writer(std430SequentialIndexedBuffer); + std430SequentialIndexedWriter.putStructArray(0, new TestPair(1.0f, 2.0f), pairDefinition); + std430SequentialIndexedWriter.putStructArray(1, new TestPair(3.0f, 4.0f), pairDefinition); + + assertFloatEquals(1.0f, std430SequentialIndexedBuffer.getFloat(0), "std430 sequential indexed array[0].first"); + assertFloatEquals(2.0f, std430SequentialIndexedBuffer.getFloat(4), "std430 sequential indexed array[0].second"); + assertFloatEquals(3.0f, std430SequentialIndexedBuffer.getFloat(8), "std430 sequential indexed array[1].first"); + assertFloatEquals(4.0f, std430SequentialIndexedBuffer.getFloat(12), "std430 sequential indexed array[1].second"); + } + + private static void assertEquals(int expected, int actual, String label) { + if (expected != actual) { + throw new AssertionError(label + ": expected " + expected + ", got " + actual); + } + } + + private static void assertFloatEquals(float expected, float actual, String label) { + if (Float.compare(expected, actual) != 0) { + throw new AssertionError(label + ": expected " + expected + ", got " + actual); + } + } + + private record TestStruct(float value) { + } + + private record TestPair(float first, float second) { + } +} diff --git a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh new file mode 100644 index 00000000..e9200d49 --- /dev/null +++ b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh @@ -0,0 +1,20 @@ +#version 460 core + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +struct Value { + float f; +}; + +layout(std430, binding = 0) readonly buffer Input { + Value data[]; +} a; + +layout(std430, binding = 1) writeonly buffer Output { + Value data[]; +} b; + +void main() { + uint idx = gl_GlobalInvocationID.x; + b.data[idx].f = a.data[idx].f * 2.0; +} \ No newline at end of file From f10ecce56361009a8fbd13095edec48dbce3772b Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Thu, 4 Jun 2026 03:56:11 +0800 Subject: [PATCH 2/9] Add compute pipeline part 2 --- .../lib/v2/font/sdf/SdfAtlasTexture.java | 2 +- .../ALRCommandEncoderBackendExtension.java | 8 +- .../blaze3d/ALRCommandEncoderExtension.java | 13 +- .../blaze3d/ALRGpuDeviceBackendExtension.java | 12 +- .../blaze3d/ALRGpuDeviceExtension.java | 9 +- .../extension/blaze3d/MemoryBarrierFlag.java | 8 + .../compute/ALRComputeCapabilities.java | 15 ++ .../compute/ALRDebugLabelExtension.java | 7 + .../compute/pipeline/ALRComputePass.java | 22 +-- .../pipeline/ALRComputePassBackend.java | 17 +- .../bindings/AtomicCounterBinding.java | 6 +- .../bindings/ShaderStorageBinding.java | 5 +- .../bindings/UniformBlockBinding.java | 6 +- .../pipeline/gl/GlComputePassBackend.java | 168 ++++++++++++++++-- .../shader/ALRComputeProgramInstance.java | 15 ++ ...java => ALRComputeProgramInstanceKey.java} | 2 +- .../shader/ALRComputeShaderInstance.java | 4 - .../shader/ALRComputeShaderManager.java | 44 ++++- .../buffers/GpuBufferConstants.java | 5 + .../v2/rendering/mixins/MinecraftMixin.java | 2 + .../mixins/blaze3d/CommandEncoderMixin.java | 44 +++++ .../mixins/blaze3d/GpuDeviceMixin.java | 36 ++++ .../blaze3d/gl/DirectStateAccessMixin.java | 25 +++ .../blaze3d/gl/GlCommandEncoderMixin.java | 45 +++++ .../mixins/blaze3d/gl/GlDebugLabelMixin.java | 60 +++++++ .../mixins/blaze3d/gl/GlDeviceMixin.java | 67 +++++++ .../resources/META-INF/accesstransformer.cfg | 5 +- .../resources/anvillib_rendering.mixins.json | 9 +- .../v2/test/client/compute/TestPipelines.java | 26 +++ .../v2/test/client/screen/GuiTestScreen.java | 12 ++ .../anvillib_test/shaders/compute/empty.csh | 6 + .../anvillib_test/shaders/compute/test.csh | 34 +++- 32 files changed, 660 insertions(+), 79 deletions(-) create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRComputeCapabilities.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRDebugLabelExtension.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeProgramInstance.java rename module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/{ALRComputeShaderInstanceKey.java => ALRComputeProgramInstanceKey.java} (65%) delete mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/CommandEncoderMixin.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/GpuDeviceMixin.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/DirectStateAccessMixin.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlCommandEncoderMixin.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDeviceMixin.java create mode 100644 module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java create mode 100644 module.test/src/main/resources/assets/anvillib_test/shaders/compute/empty.csh diff --git a/module.font/src/main/java/dev/anvilcraft/lib/v2/font/sdf/SdfAtlasTexture.java b/module.font/src/main/java/dev/anvilcraft/lib/v2/font/sdf/SdfAtlasTexture.java index 7b4e9a25..11ef20a1 100644 --- a/module.font/src/main/java/dev/anvilcraft/lib/v2/font/sdf/SdfAtlasTexture.java +++ b/module.font/src/main/java/dev/anvilcraft/lib/v2/font/sdf/SdfAtlasTexture.java @@ -23,7 +23,7 @@ private SdfAtlasTexture() { } /** - * Upload a single atlas page to the GPU, returning its texture identifier. + * Upload a single atlas page to the GPU, returning its texture location. */ public static Identifier uploadPage(SdfGlyphAtlas atlas, int pageIndex) { SdfGlyphPage page = atlas.page(pageIndex); diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java index d123a88c..46531242 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderBackendExtension.java @@ -1,6 +1,7 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; -import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; public interface ALRCommandEncoderBackendExtension { void alrDispatchWorkgroups( @@ -10,9 +11,10 @@ void alrDispatchWorkgroups( ); void alrDispatchWorkgroupsIndirect( - GpuBuffer parameters, - long offset + GpuBufferSlice parameters ); void alrMemoryBarrier(MemoryBarrierFlag... flags); + + ALRComputePass alrCreateComputePass(); } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java index c0642ace..1d9b6669 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRCommandEncoderExtension.java @@ -1,6 +1,8 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; -import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.systems.CommandEncoder; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; public interface ALRCommandEncoderExtension { @@ -11,9 +13,14 @@ void alrDispatchWorkgroups( ); void alrDispatchWorkgroupsIndirect( - GpuBuffer parameters, - long offset + GpuBufferSlice parameters ); void alrMemoryBarrier(MemoryBarrierFlag... flags); + + ALRComputePass alrCreateComputePass(); + + static ALRCommandEncoderExtension of(CommandEncoder commandEncoder){ + return (ALRCommandEncoderExtension) commandEncoder; + } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java index f21c9dfe..c510fc0e 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceBackendExtension.java @@ -1,11 +1,15 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; -import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstance; -import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstanceKey; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstance; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstanceKey; public interface ALRGpuDeviceBackendExtension { - ALRComputeShaderInstance alrCompileComputeShader(ALRComputeShaderInstanceKey instanceKey); + ALRComputeProgramInstance alrCompileComputeShader(ALRComputeProgramInstanceKey instanceKey); - ALRComputePass alrCreateComputePass(); + void alrDestroyComputeShader(ALRComputeProgramInstance instance); + + void alrPushDebugGroup(String name); + + void alrPopDebugGroup(); } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java index b3a47f75..184600c1 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java @@ -1,11 +1,10 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d; -import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; -import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstance; -import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderInstanceKey; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstance; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstanceKey; public interface ALRGpuDeviceExtension { - ALRComputeShaderInstance alrCompileComputeShader(ALRComputeShaderInstanceKey instanceKey); + ALRComputeProgramInstance alrCompileComputeShader(ALRComputeProgramInstanceKey instanceKey); - ALRComputePass alrCreateComputePass(); + void alrDestroyComputeShader(ALRComputeProgramInstance instance); } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java index a08f163f..85d08c3f 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/MemoryBarrierFlag.java @@ -28,4 +28,12 @@ public enum MemoryBarrierFlag { public int glEnum() { return glEnum; } + + public static int compound(MemoryBarrierFlag... flags){ + int i = 0; + for (MemoryBarrierFlag flag : flags) { + i |= flag.glEnum; + } + return i; + } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRComputeCapabilities.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRComputeCapabilities.java new file mode 100644 index 00000000..ab178600 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRComputeCapabilities.java @@ -0,0 +1,15 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute; + +import org.lwjgl.opengl.GL; + +public class ALRComputeCapabilities { + private static boolean COMPUTE_SUPPORTED; + + public static void init() { + COMPUTE_SUPPORTED = GL.getCapabilities().GL_ARB_compute_shader; + } + + public static boolean isComputeSupported() { + return COMPUTE_SUPPORTED; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRDebugLabelExtension.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRDebugLabelExtension.java new file mode 100644 index 00000000..aa356eb4 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/ALRDebugLabelExtension.java @@ -0,0 +1,7 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute; + +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstance; + +public interface ALRDebugLabelExtension { + void alrApplyLabel(ALRComputeProgramInstance shaderInstance); +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java index 13e0ab12..91875341 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java @@ -1,7 +1,6 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline; -import com.mojang.blaze3d.buffers.GpuBuffer; -import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.textures.GpuTexture; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ComputeBindingLayout; @@ -14,11 +13,9 @@ public class ALRComputePass implements AutoCloseable { @Setter private ALRComputePipeline pipeline; private final ALRComputePassBackend backend; - private final GpuDevice device; - public ALRComputePass(GpuDevice device, ALRComputePassBackend backend) { + public ALRComputePass(ALRComputePassBackend backend) { this.backend = backend; - this.device = device; } public void pushDebugGroup(String name) { @@ -26,7 +23,7 @@ public void pushDebugGroup(String name) { } public void popDebugGroup(String name) { - this.backend.popDebugGroup(name); + this.backend.popDebugGroup(); } public void memoryBarrier(MemoryBarrierFlag... flags) { @@ -42,14 +39,13 @@ public void dispatchWorkgroups( } public void dispatchWorkgroupsIndirect( - GpuBuffer buffer, - long offset + GpuBufferSlice buffer ) { - this.backend.dispatchWorkgroupsIndirect(buffer, offset); + this.backend.dispatchWorkgroupsIndirect(buffer); } @Override - public void close() throws Exception { + public void close() { this.backend.close(); } @@ -73,15 +69,15 @@ public void bindImage(int bindingPoint, GpuTexture resource, boolean read, boole this.backend.bindImage(bindingPoint, resource, read, write); } - public void bindUniformBlock(int bindingPoint, GpuBuffer resource) { + public void bindUniformBlock(int bindingPoint, GpuBufferSlice resource) { this.backend.bindUniformBlock(bindingPoint, resource); } - public void bindShaderStorage(int bindingPoint, GpuBuffer resource) { + public void bindShaderStorage(int bindingPoint, GpuBufferSlice resource) { this.backend.bindShaderStorage(bindingPoint, resource); } - public void bindAtomicCounter(int bindingPoint, GpuBuffer resource) { + public void bindAtomicCounter(int bindingPoint, GpuBufferSlice resource) { this.backend.bindAtomicCounter(bindingPoint, resource); } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java index ec142e9f..ec56de85 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePassBackend.java @@ -1,18 +1,21 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline; import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; import com.mojang.blaze3d.textures.GpuTexture; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; -public interface ALRComputePassBackend extends AutoCloseable { +public interface ALRComputePassBackend { + void setPipeline(ALRComputePipeline pipeline); + void pushDebugGroup(String name); - void popDebugGroup(String name); + void popDebugGroup(); void dispatchWorkgroups(int groupCountX, int groupCountY, int groupCountZ); - void dispatchWorkgroupsIndirect(GpuBuffer buffer, long offset); + void dispatchWorkgroupsIndirect(GpuBufferSlice buffer); void memoryBarrier(MemoryBarrierFlag... flags); @@ -20,9 +23,11 @@ public interface ALRComputePassBackend extends AutoCloseable { void bindImage(int bindingPoint, GpuTexture resource, boolean read, boolean write); - void bindUniformBlock(int bindingPoint, GpuBuffer resource); + void bindUniformBlock(int bindingPoint, GpuBufferSlice resource); + + void bindShaderStorage(int bindingPoint, GpuBufferSlice resource); - void bindShaderStorage(int bindingPoint, GpuBuffer resource); + void bindAtomicCounter(int bindingPoint, GpuBufferSlice resource); - void bindAtomicCounter(int bindingPoint, GpuBuffer resource); + void close(); } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java index 3506c9d7..de8c0e78 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/AtomicCounterBinding.java @@ -1,19 +1,19 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; -import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; public record AtomicCounterBinding( String name -) implements ComputeBindingLayout { +) implements ComputeBindingLayout { @Override public ShaderResourceType type() { return ShaderResourceType.ATOMIC_COUNTER; } @Override - public void apply(int bindingPoint, GpuBuffer resource, ALRComputePass computePass) { + public void apply(int bindingPoint, GpuBufferSlice resource, ALRComputePass computePass) { computePass.bindAtomicCounter(bindingPoint, resource); } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java index 9f34f62b..85cdd54f 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/ShaderStorageBinding.java @@ -1,19 +1,20 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; public record ShaderStorageBinding( String name -) implements ComputeBindingLayout { +) implements ComputeBindingLayout { @Override public ShaderResourceType type() { return ShaderResourceType.SHADER_STORAGE; } @Override - public void apply(int bindingPoint, GpuBuffer resource, ALRComputePass computePass) { + public void apply(int bindingPoint, GpuBufferSlice resource, ALRComputePass computePass) { computePass.bindShaderStorage(bindingPoint, resource); } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java index a1f621f3..1420888c 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/bindings/UniformBlockBinding.java @@ -1,19 +1,19 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings; -import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ShaderResourceType; public record UniformBlockBinding( String name -) implements ComputeBindingLayout { +) implements ComputeBindingLayout { @Override public ShaderResourceType type() { return ShaderResourceType.UNIFORM_BLOCK; } @Override - public void apply(int bindingPoint, GpuBuffer resource, ALRComputePass computePass) { + public void apply(int bindingPoint, GpuBufferSlice resource, ALRComputePass computePass) { computePass.bindUniformBlock(bindingPoint, resource); } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java index 3d70a258..a102eac1 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java @@ -1,64 +1,202 @@ package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.gl; -import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.opengl.GlBuffer; +import com.mojang.blaze3d.opengl.GlConst; +import com.mojang.blaze3d.opengl.GlSampler; +import com.mojang.blaze3d.opengl.GlStateManager; +import com.mojang.blaze3d.opengl.GlTexture; +import com.mojang.blaze3d.systems.GpuDeviceBackend; import com.mojang.blaze3d.textures.GpuTexture; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderBackendExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceBackendExtension; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePassBackend; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePipeline; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderManager; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.lwjgl.opengl.ARBShaderAtomicCounters; +import org.lwjgl.opengl.ARBShaderImageLoadStore; +import org.lwjgl.opengl.ARBShaderStorageBufferObject; +import org.lwjgl.opengl.GL13; +import org.lwjgl.opengl.GL33; +import org.lwjgl.opengl.GL46; public class GlComputePassBackend implements ALRComputePassBackend { - @Override - public void pushDebugGroup(String name) { + private final GpuDeviceBackend backend; + private final ALRGpuDeviceBackendExtension backendExtension; + private final ALRCommandEncoderBackendExtension commandEncoderExtension; + private final Int2ObjectMap textureBindings = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap imageBindings = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap uniformBlockBindings = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap shaderStorageBindings = new Int2ObjectOpenHashMap<>(); + private final Int2ObjectMap atomicCounterBindings = new Int2ObjectOpenHashMap<>(); + private ALRComputePipeline pipeline = null; + + public GlComputePassBackend( + ALRCommandEncoderBackendExtension commandEncoderExtension, + ALRGpuDeviceBackendExtension backendExtension + ) { + this.commandEncoderExtension = commandEncoderExtension; + this.backend = (GpuDeviceBackend) backendExtension; + this.backendExtension = backendExtension; + } + @Override + public void setPipeline(ALRComputePipeline pipeline) { + this.pipeline = pipeline; } @Override - public void popDebugGroup(String name) { + public void pushDebugGroup(String name) { + this.backendExtension.alrPushDebugGroup(name); + } + @Override + public void popDebugGroup() { + this.backendExtension.alrPopDebugGroup(); } @Override public void dispatchWorkgroups(int groupCountX, int groupCountY, int groupCountZ) { - + this.setupState(); + this.commandEncoderExtension.alrDispatchWorkgroups(groupCountX, groupCountY, groupCountZ); } @Override - public void dispatchWorkgroupsIndirect(GpuBuffer buffer, long offset) { - + public void dispatchWorkgroupsIndirect(GpuBufferSlice buffer) { + this.setupState(); + this.commandEncoderExtension.alrDispatchWorkgroupsIndirect(buffer); } @Override public void memoryBarrier(MemoryBarrierFlag... flags) { - + this.commandEncoderExtension.alrMemoryBarrier(flags); } @Override public void bindTexture(int bindingPoint, TextureBinding.SamplerAndTexture resource) { - + this.textureBindings.put(bindingPoint, resource); } @Override public void bindImage(int bindingPoint, GpuTexture resource, boolean read, boolean write) { + if (!read && !write) { + throw new IllegalArgumentException("ImageResource does not allow both read and write are false"); + } + this.imageBindings.put(bindingPoint, new ImageState(resource, read, write)); + } + @Override + public void bindUniformBlock(int bindingPoint, GpuBufferSlice resource) { + this.uniformBlockBindings.put(bindingPoint, resource); } @Override - public void bindUniformBlock(int bindingPoint, GpuBuffer resource) { + public void bindShaderStorage(int bindingPoint, GpuBufferSlice resource) { + this.shaderStorageBindings.put(bindingPoint, resource); + } + @Override + public void bindAtomicCounter(int bindingPoint, GpuBufferSlice resource) { + this.atomicCounterBindings.put(bindingPoint, resource); } @Override - public void bindShaderStorage(int bindingPoint, GpuBuffer resource) { + public void close() { } - @Override - public void bindAtomicCounter(int bindingPoint, GpuBuffer resource) { + private void setupState() { + int program = ALRComputeShaderManager.INSTANCE.getShader(pipeline).id(); + GL46.glUseProgram(program); + + for (Int2ObjectMap.Entry entry : this.textureBindings.int2ObjectEntrySet()) { + this.setupTexture(entry.getIntKey(), entry.getValue()); + } + for (Int2ObjectMap.Entry entry : this.imageBindings.int2ObjectEntrySet()) { + this.setupImage(entry.getIntKey(), entry.getValue()); + } + for (Int2ObjectMap.Entry entry : this.uniformBlockBindings.int2ObjectEntrySet()) { + this.setupUniformBlock(entry.getIntKey(), entry.getValue()); + } + for (Int2ObjectMap.Entry entry : this.shaderStorageBindings.int2ObjectEntrySet()) { + this.setupShaderStorage(entry.getIntKey(), entry.getValue()); + } + for (Int2ObjectMap.Entry entry : this.atomicCounterBindings.int2ObjectEntrySet()) { + this.setupAtomicCounter(entry.getIntKey(), entry.getValue()); + } + } + private void setupTexture(int bindingPoint, TextureBinding.SamplerAndTexture resource) { + int sampler = ((GlSampler) resource.sampler()).getId(); + int texture = ((GlTexture) resource.texture()).glId(); + + GlStateManager._activeTexture(GL13.GL_TEXTURE0 + bindingPoint); + GlStateManager._bindTexture(texture); + GL33.glBindSampler(bindingPoint, sampler); } - @Override - public void close() throws Exception { + private void setupImage(int bindingPoint, ImageState state) { + int access = 0; + if (state.read() && state.write()) { + access = GL46.GL_READ_WRITE; + } else { + if (state.read()) { + access |= GL46.GL_READ_ONLY; + } + if (state.write()) { + access |= GL46.GL_WRITE_ONLY; + } + } + + ARBShaderImageLoadStore.glBindImageTexture( + bindingPoint, + ((GlTexture) state.resource()).glId(), + 0, + false, + 0, + access, + GlConst.toGlInternalId(state.resource().getFormat()) + ); + } + + private void setupUniformBlock(int bindingPoint, GpuBufferSlice resource) { + GL46.glBindBufferRange( + GL46.GL_UNIFORM_BUFFER, + bindingPoint, + ((GlBuffer) resource.buffer()).handle, + resource.offset(), + resource.length() + ); + } + + private void setupShaderStorage(int bindingPoint, GpuBufferSlice resource) { + GL46.glBindBufferRange( + ARBShaderStorageBufferObject.GL_SHADER_STORAGE_BUFFER, + bindingPoint, + ((GlBuffer) resource.buffer()).handle, + resource.offset(), + resource.length() + ); + } + + private void setupAtomicCounter(int bindingPoint, GpuBufferSlice resource) { + GL46.glBindBufferRange( + ARBShaderAtomicCounters.GL_ATOMIC_COUNTER_BUFFER, + bindingPoint, + ((GlBuffer) resource.buffer()).handle, + resource.offset(), + resource.length() + ); + } + private record ImageState( + GpuTexture resource, + boolean read, + boolean write + ) { } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeProgramInstance.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeProgramInstance.java new file mode 100644 index 00000000..ed61ac87 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeProgramInstance.java @@ -0,0 +1,15 @@ +package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader; + +import dev.anvilcraft.lib.v2.rendering.AnvilLibRendering; +import net.minecraft.client.renderer.ShaderDefines; + +public record ALRComputeProgramInstance(int id, ALRComputeProgramInstanceKey key) { + public static final ALRComputeProgramInstance INVALID = new ALRComputeProgramInstance( + 0, + new ALRComputeProgramInstanceKey( + AnvilLibRendering.location("compute/invalid"), + ShaderDefines.builder().build() + ) + ); + +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstanceKey.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeProgramInstanceKey.java similarity index 65% rename from module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstanceKey.java rename to module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeProgramInstanceKey.java index bbed1a74..af5810b0 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstanceKey.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeProgramInstanceKey.java @@ -3,5 +3,5 @@ import net.minecraft.client.renderer.ShaderDefines; import net.minecraft.resources.Identifier; -public record ALRComputeShaderInstanceKey(Identifier identifier, ShaderDefines defines) { +public record ALRComputeProgramInstanceKey(Identifier location, ShaderDefines defines) { } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java deleted file mode 100644 index 31df7c7b..00000000 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderInstance.java +++ /dev/null @@ -1,4 +0,0 @@ -package dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader; - -public class ALRComputeShaderInstance { -} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java index 5311ef4d..973ca375 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java @@ -5,6 +5,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import dev.anvilcraft.lib.v2.rendering.event.RegisterComputePipelinesEvent; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.ALRComputeCapabilities; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePipeline; import lombok.extern.slf4j.Slf4j; import net.minecraft.client.renderer.ShaderManager; @@ -16,6 +17,7 @@ import net.neoforged.fml.ModLoader; import org.apache.commons.io.IOUtils; import org.jetbrains.annotations.UnknownNullability; +import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; import java.io.IOException; @@ -30,10 +32,11 @@ public class ALRComputeShaderManager extends SimplePreparableReloadListener shaderInstanceMap = new HashMap<>(); + private final Map shaderInstanceMap = new HashMap<>(); + private final Map pipelineToProgramMap = new HashMap<>(); @Override - protected ComputeShaderSource prepare(ResourceManager manager, ProfilerFiller profiler) { + protected @NonNull ComputeShaderSource prepare(ResourceManager manager, ProfilerFiller profiler) { ImmutableMap.Builder sources = new ImmutableMap.Builder<>(); Map shaders = manager.listResources( @@ -51,27 +54,50 @@ protected ComputeShaderSource prepare(ResourceManager manager, ProfilerFiller pr log.error("Failed to load compute shader source at {}", it.getKey(), ex); } } - + log.info("Loaded {} compute shader.", shaders.size()); return new ComputeShaderSource(sources.build()); } @Override protected void apply(ComputeShaderSource preparations, ResourceManager manager, ProfilerFiller profiler) { + if (!ALRComputeCapabilities.isComputeSupported()) { + return; + } + ALRGpuDeviceExtension deviceExtension = (ALRGpuDeviceExtension) RenderSystem.getDevice(); + for (ALRComputeProgramInstance value : shaderInstanceMap.values()) { + deviceExtension.alrDestroyComputeShader(value); + } + shaderInstanceMap.clear(); + pipelineToProgramMap.clear(); + this.source = preparations; RegisterComputePipelinesEvent event = new RegisterComputePipelinesEvent(); ModLoader.postEvent(event); - ALRGpuDeviceExtension deviceExtension = (ALRGpuDeviceExtension) RenderSystem.getDevice(); - for (ALRComputePipeline pipeline : event.getPipelines()) { - ALRComputeShaderInstanceKey key = new ALRComputeShaderInstanceKey(pipeline.shaderLocation(), pipeline.defines()); - ALRComputeShaderInstance instance = deviceExtension.alrCompileComputeShader(key); + for (ALRComputePipeline pipeline : event.getPipelines()) { + ALRComputeProgramInstanceKey key = new ALRComputeProgramInstanceKey( + pipeline.shaderLocation(), + pipeline.defines() + ); + log.debug("Compiled COMPUTE shader {}", pipeline.shaderLocation()); + ALRComputeProgramInstance instance = deviceExtension.alrCompileComputeShader(key); + this.shaderInstanceMap.put(key, instance); + this.pipelineToProgramMap.put(pipeline, instance); } + } + public String getSource(Identifier location) { + return source.source.get(location.withPrefix("shaders/")); } @Nullable - public String getSource(Identifier location) { - return source.source.get(location); + public ALRComputeProgramInstance getShader(ALRComputeProgramInstanceKey location) { + return this.shaderInstanceMap.get(location); + } + + @Nullable + public ALRComputeProgramInstance getShader(ALRComputePipeline pipeline) { + return this.pipelineToProgramMap.get(pipeline); } public record ComputeShaderSource( diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java new file mode 100644 index 00000000..493b1712 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java @@ -0,0 +1,5 @@ +package dev.anvilcraft.lib.v2.rendering.foundation.buffers; + +public class GpuBufferConstants { + public static final int USAGE_SHADER_STORAGE = 512; +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/MinecraftMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/MinecraftMixin.java index a5fef7c7..33b07aa5 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/MinecraftMixin.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/MinecraftMixin.java @@ -5,6 +5,7 @@ import dev.anvilcraft.lib.v2.rendering.AnvilLibRendering; import dev.anvilcraft.lib.v2.rendering.bloom.BloomPostEffect; import dev.anvilcraft.lib.v2.rendering.cachedber.pipeline.CachedBlockEntityRenderingPipeline; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.ALRComputeCapabilities; import net.minecraft.client.Minecraft; import net.minecraft.client.main.GameConfig; import net.minecraft.client.multiplayer.ClientLevel; @@ -28,6 +29,7 @@ public class MinecraftMixin { ) private void onCreateInstance(GameConfig gameConfig, CallbackInfo ci) { ALRPostEffects.createPostEffects(); + ALRComputeCapabilities.init(); } // @Inject( diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/CommandEncoderMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/CommandEncoderMixin.java new file mode 100644 index 00000000..47f5f79c --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/CommandEncoderMixin.java @@ -0,0 +1,44 @@ +package dev.anvilcraft.lib.v2.rendering.mixins.blaze3d; + +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.CommandEncoderBackend; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderBackendExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.gl.GlComputePassBackend; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(CommandEncoder.class) +public class CommandEncoderMixin implements ALRCommandEncoderExtension { + @Shadow + @Final + private CommandEncoderBackend backend; + + @Override + public void alrDispatchWorkgroups(int groupCountX, int groupCountY, int groupCountZ) { + alrBackend().alrDispatchWorkgroups(groupCountX, groupCountY, groupCountZ); + } + + @Override + public void alrDispatchWorkgroupsIndirect(GpuBufferSlice parameters) { + alrBackend().alrDispatchWorkgroupsIndirect(parameters); + } + + private ALRCommandEncoderBackendExtension alrBackend() { + return (ALRCommandEncoderBackendExtension) this.backend; + } + + @Override + public void alrMemoryBarrier(MemoryBarrierFlag... flags) { + alrBackend().alrMemoryBarrier(flags); + } + + @Override + public ALRComputePass alrCreateComputePass() { + return alrBackend().alrCreateComputePass(); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/GpuDeviceMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/GpuDeviceMixin.java new file mode 100644 index 00000000..7107d4e7 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/GpuDeviceMixin.java @@ -0,0 +1,36 @@ +package dev.anvilcraft.lib.v2.rendering.mixins.blaze3d; + +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.GpuDeviceBackend; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceBackendExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstance; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstanceKey; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; + +@SuppressWarnings("AddedMixinMembersNamePattern") +@Mixin(GpuDevice.class) +public class GpuDeviceMixin implements ALRGpuDeviceExtension { + @Shadow + @Final + private GpuDeviceBackend backend; + + @Override + public ALRComputeProgramInstance alrCompileComputeShader(ALRComputeProgramInstanceKey instanceKey) { + return alrBackend().alrCompileComputeShader(instanceKey); + } + + @Override + public void alrDestroyComputeShader(ALRComputeProgramInstance instance) { + alrBackend().alrDestroyComputeShader(instance); + } + + @Unique + private ALRGpuDeviceBackendExtension alrBackend() { + return ((ALRGpuDeviceBackendExtension) this.backend); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/DirectStateAccessMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/DirectStateAccessMixin.java new file mode 100644 index 00000000..2ac5bc20 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/DirectStateAccessMixin.java @@ -0,0 +1,25 @@ +package dev.anvilcraft.lib.v2.rendering.mixins.blaze3d.gl; + +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.GpuBufferConstants; +import org.lwjgl.opengl.ARBShaderStorageBufferObject; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +public class DirectStateAccessMixin { + + @Mixin(targets = "com.mojang.blaze3d.opengl.DirectStateAccess$Emulated") + public static class Emulated { + @Inject( + method = "selectBufferBindTarget", + at = @At("HEAD"), + cancellable = true + ) + void handleSSBO(int usage, CallbackInfoReturnable cir) { + if ((usage & GpuBufferConstants.USAGE_SHADER_STORAGE) != 0) { + cir.setReturnValue(ARBShaderStorageBufferObject.GL_SHADER_STORAGE_BUFFER); + } + } + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlCommandEncoderMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlCommandEncoderMixin.java new file mode 100644 index 00000000..093efda8 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlCommandEncoderMixin.java @@ -0,0 +1,45 @@ +package dev.anvilcraft.lib.v2.rendering.mixins.blaze3d.gl; + +import com.mojang.blaze3d.buffers.GpuBufferSlice; +import com.mojang.blaze3d.opengl.GlBuffer; +import com.mojang.blaze3d.opengl.GlDevice; +import com.mojang.blaze3d.opengl.GlStateManager; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderBackendExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceBackendExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.gl.GlComputePassBackend; +import org.lwjgl.opengl.ARBComputeShader; +import org.lwjgl.opengl.ARBShaderImageLoadStore; +import org.lwjgl.opengl.GL46; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(targets = "com.mojang.blaze3d.opengl.GlCommandEncoder") +public class GlCommandEncoderMixin implements ALRCommandEncoderBackendExtension { + @Shadow + @Final + private GlDevice device; + + @Override + public void alrDispatchWorkgroups(int groupCountX, int groupCountY, int groupCountZ) { + ARBComputeShader.glDispatchCompute(groupCountX, groupCountY, groupCountZ); + } + + @Override + public void alrDispatchWorkgroupsIndirect(GpuBufferSlice parameters) { + GlStateManager._glBindBuffer(GL46.GL_DISPATCH_INDIRECT_BUFFER, ((GlBuffer) parameters.buffer()).handle); + ARBComputeShader.glDispatchComputeIndirect(parameters.offset()); + } + + @Override + public void alrMemoryBarrier(MemoryBarrierFlag... flags) { + ARBShaderImageLoadStore.glMemoryBarrier(MemoryBarrierFlag.compound(flags)); + } + + @Override + public ALRComputePass alrCreateComputePass() { + return new ALRComputePass(new GlComputePassBackend(this, (ALRGpuDeviceBackendExtension) device)); + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java new file mode 100644 index 00000000..f35e2f84 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java @@ -0,0 +1,60 @@ +package dev.anvilcraft.lib.v2.rendering.mixins.blaze3d.gl; + +import com.mojang.blaze3d.opengl.GlDebugLabel; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.ALRDebugLabelExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstance; +import net.minecraft.util.StringUtil; +import org.lwjgl.opengl.EXTDebugLabel; +import org.lwjgl.opengl.GL46; +import org.lwjgl.opengl.KHRDebug; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +public class GlDebugLabelMixin { + @Mixin(GlDebugLabel.class) + public class Self implements ALRDebugLabelExtension { + + @Override + public void alrApplyLabel(ALRComputeProgramInstance shaderInstance) { + } + } + + @Mixin(targets = "com.mojang.blaze3d.opengl.GlDebugLabel$Core") + public class Core implements ALRDebugLabelExtension { + + @Shadow + @Final + private int maxLabelLength; + + @Override + public void alrApplyLabel(ALRComputeProgramInstance shaderInstance) { + KHRDebug.glObjectLabel( + GL46.GL_SHADER, + shaderInstance.id(), + StringUtil.truncateStringIfNecessary( + shaderInstance.key().location().toString(), + this.maxLabelLength, + true + ) + ); + } + } + + @Mixin(targets = "com.mojang.blaze3d.opengl.GlDebugLabel$Ext") + public class Ext implements ALRDebugLabelExtension { + + @Override + public void alrApplyLabel(ALRComputeProgramInstance shaderInstance) { + EXTDebugLabel.glLabelObjectEXT( + EXTDebugLabel.GL_SHADER_OBJECT_EXT, + shaderInstance.id(), + StringUtil.truncateStringIfNecessary( + shaderInstance.key().location().toString(), + 256, + true + ) + ); + } + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDeviceMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDeviceMixin.java new file mode 100644 index 00000000..0afc7b7f --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDeviceMixin.java @@ -0,0 +1,67 @@ +package dev.anvilcraft.lib.v2.rendering.mixins.blaze3d.gl; + +import com.mojang.blaze3d.opengl.GlDebugLabel; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceBackendExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.ALRDebugLabelExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.gl.GlComputePassBackend; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstance; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstanceKey; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderManager; +import org.lwjgl.opengl.ARBComputeShader; +import org.lwjgl.opengl.GL46; +import org.slf4j.Logger; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(targets = "com.mojang.blaze3d.opengl.GlDevice") +public abstract class GlDeviceMixin implements ALRGpuDeviceBackendExtension { + + @Shadow + @Final + private static Logger LOGGER; + + @Shadow + public abstract GlDebugLabel debugLabels(); + + @Override + public void alrDestroyComputeShader(ALRComputeProgramInstance instance) { + GL46.glDeleteProgram(instance.id()); + } + + @Override + public ALRComputeProgramInstance alrCompileComputeShader(ALRComputeProgramInstanceKey instanceKey) { + String source = ALRComputeShaderManager.INSTANCE.getSource(instanceKey.location()); + int shaderId = GL46.glCreateShader(ARBComputeShader.GL_COMPUTE_SHADER); + GL46.glShaderSource(shaderId, source); + GL46.glCompileShader(shaderId); + if (GL46.glGetShaderi(shaderId, GL46.GL_COMPILE_STATUS) == 0) { + String infoLog = GL46.glGetShaderInfoLog(shaderId); + LOGGER.error("Could not compile COMPUTE shader {}: {}", instanceKey.location(), infoLog); + return ALRComputeProgramInstance.INVALID; + } + int program = GL46.glCreateProgram(); + GL46.glAttachShader(program, shaderId); + GL46.glLinkProgram(program); + if (GL46.glGetProgrami(program, GL46.GL_LINK_STATUS) == 0) { + String infoLog = GL46.glGetProgramInfoLog(shaderId); + LOGGER.error("Could not link COMPUTE shader {}: {}", instanceKey.location(), infoLog); + return ALRComputeProgramInstance.INVALID; + } + GL46.glDeleteShader(shaderId); + ALRComputeProgramInstance instance = new ALRComputeProgramInstance(program, instanceKey); + ((ALRDebugLabelExtension) this.debugLabels()).alrApplyLabel(instance); + return instance; + } + + @Override + public void alrPushDebugGroup(String name) { + this.debugLabels().pushDebugGroup(() -> name); + } + + @Override + public void alrPopDebugGroup() { + this.debugLabels().popDebugGroup(); + } +} diff --git a/module.rendering/src/main/resources/META-INF/accesstransformer.cfg b/module.rendering/src/main/resources/META-INF/accesstransformer.cfg index c2fa8ec3..90a0040c 100644 --- a/module.rendering/src/main/resources/META-INF/accesstransformer.cfg +++ b/module.rendering/src/main/resources/META-INF/accesstransformer.cfg @@ -14,4 +14,7 @@ public net.minecraft.client.renderer.rendertype.RenderSetup textureTransform public net.minecraft.client.renderer.rendertype.RenderType name public net.minecraft.client.renderer.rendertype.RenderType outline -public net.minecraft.client.renderer.ShaderManager createPreprocessor(Ljava/util/Map;Lnet/minecraft/resources/Identifier;)Lcom/mojang/blaze3d/preprocessor/GlslPreprocessor; \ No newline at end of file +public net.minecraft.client.renderer.ShaderManager createPreprocessor(Ljava/util/Map;Lnet/minecraft/resources/Identifier;)Lcom/mojang/blaze3d/preprocessor/GlslPreprocessor; + +public com.mojang.blaze3d.opengl.GlDevice +public com.mojang.blaze3d.opengl.GlBuffer handle \ No newline at end of file diff --git a/module.rendering/src/main/resources/anvillib_rendering.mixins.json b/module.rendering/src/main/resources/anvillib_rendering.mixins.json index 88a32ab4..e442b36b 100644 --- a/module.rendering/src/main/resources/anvillib_rendering.mixins.json +++ b/module.rendering/src/main/resources/anvillib_rendering.mixins.json @@ -12,7 +12,14 @@ "GuiRendererMixin", "ItemStackRenderStateMixin", "MinecraftMixin", - "RenderTypeMixin" + "RenderTypeMixin", + "blaze3d.GpuDeviceMixin", + "blaze3d.gl.DirectStateAccessMixin$Emulated", + "blaze3d.gl.GlCommandEncoderMixin", + "blaze3d.gl.GlDebugLabelMixin$Core", + "blaze3d.gl.GlDebugLabelMixin$Ext", + "blaze3d.gl.GlDebugLabelMixin$Self", + "blaze3d.gl.GlDeviceMixin" ], "injectors": { "defaultRequire": 1 diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java new file mode 100644 index 00000000..a541ebe4 --- /dev/null +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java @@ -0,0 +1,26 @@ +package dev.anvilcraft.lib.v2.test.client.compute; + +import dev.anvilcraft.lib.v2.rendering.event.RegisterComputePipelinesEvent; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePipeline; +import dev.anvilcraft.lib.v2.test.AnvilLibTest; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; + +@EventBusSubscriber(Dist.CLIENT) +public class TestPipelines { + public static final ALRComputePipeline TEST = ALRComputePipeline.builder() + .withShaderStorage("Input") + .withShaderStorage("Output") + .withShader(AnvilLibTest.of("compute/test.csh")) + .build(); + + public static final ALRComputePipeline EMPTY = ALRComputePipeline.builder() + .withShader(AnvilLibTest.of("compute/empty.csh")) + .build(); + + @SubscribeEvent + public static void on(RegisterComputePipelinesEvent event) { + event.registerPipeline(TEST); + } +} diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java index 09e75527..8b223a3a 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java @@ -1,9 +1,13 @@ package dev.anvilcraft.lib.v2.test.client.screen; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; import dev.anvilcraft.lib.v2.rendering.foundation.fakeworld.FakeDisplayLevel; import dev.anvilcraft.lib.v2.rendering.gui.GuiRenderExtras; +import dev.anvilcraft.lib.v2.test.client.compute.TestPipelines; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; import net.minecraft.client.gui.screens.Screen; @@ -193,6 +197,14 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo graphics.pose().popMatrix(); } + public void dispatchComputeTest() { + ALRCommandEncoderExtension commandEncoder = ALRCommandEncoderExtension.of(RenderSystem.getDevice().createCommandEncoder()); + try (ALRComputePass pass = commandEncoder.alrCreateComputePass()) { + pass.setPipeline(TestPipelines.EMPTY); + pass.dispatchWorkgroups(16, 16, 1); + } + } + @Override public boolean isInGameUi() { return true; diff --git a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/empty.csh b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/empty.csh new file mode 100644 index 00000000..05b072a2 --- /dev/null +++ b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/empty.csh @@ -0,0 +1,6 @@ +#version 460 core + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +void main() { +} \ No newline at end of file diff --git a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh index e9200d49..8bdf2571 100644 --- a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh +++ b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/test.csh @@ -3,18 +3,42 @@ layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; struct Value { - float f; + vec4 va; + vec4 vb; }; -layout(std430, binding = 0) readonly buffer Input { +layout(std140, binding = 0) uniform ComputeUniform { + mat4 ProjMat; +}; + +layout(std430, binding = 1) readonly buffer Input { Value data[]; } a; -layout(std430, binding = 1) writeonly buffer Output { - Value data[]; +layout(std430, binding = 2) writeonly buffer Output { + vec4 result[]; } b; +layout(binding = 3, rgba8) uniform image2D Img; + +layout(binding = 4, offset = 0) uniform atomic_uint InvocationCounter; + +layout(binding = 5) uniform sampler2D TestTex; + void main() { uint idx = gl_GlobalInvocationID.x; - b.data[idx].f = a.data[idx].f * 2.0; + + ivec2 imgSize = imageSize(Img); + ivec2 pos = ivec2(int(idx) % imgSize.x, int(idx) / imgSize.x); + + if (pos.y >= imgSize.y) return; + + vec2 uv = (vec2(pos) + 0.5) / vec2(imgSize); + vec4 sampled = texture(TestTex, uv); + + imageStore(Img, pos, sampled); + + b.result[idx] = sampled; + + atomicCounterIncrement(InvocationCounter); } \ No newline at end of file From cea4b9127acd78796683ca18f7b1a0845aaa7af8 Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Thu, 4 Jun 2026 05:32:10 +0800 Subject: [PATCH 3/9] Add compute pipeline part 3 --- module.gradle | 1 + .../compute/pipeline/ALRComputePass.java | 11 +- .../compute/pipeline/ALRComputePipeline.java | 14 ++- .../shader/ALRComputeShaderManager.java | 1 + .../v2/rendering/mixins/MinecraftMixin.java | 1 - .../mixins/blaze3d/CommandEncoderMixin.java | 1 - .../mixins/blaze3d/gl/GlDebugLabelMixin.java | 6 +- .../mixins/blaze3d/gl/GlDeviceMixin.java | 2 - .../resources/anvillib_rendering.mixins.json | 1 + .../v2/test/client/AnvilLibTestClient.java | 41 ++++++- .../test/client/compute/ComputeSupport.java | 109 ++++++++++++++++++ .../v2/test/client/compute/TestPipelines.java | 12 ++ .../v2/test/client/screen/GuiTestScreen.java | 18 +++ .../lib/v2/test/mixin/MinecraftMixin.java | 35 ++++++ .../anvillib_test/shaders/compute/add.csh | 24 ++++ 15 files changed, 265 insertions(+), 12 deletions(-) create mode 100644 module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java create mode 100644 module.test/src/main/java/dev/anvilcraft/lib/v2/test/mixin/MinecraftMixin.java create mode 100644 module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh diff --git a/module.gradle b/module.gradle index 20314e4a..83ae97ac 100644 --- a/module.gradle +++ b/module.gradle @@ -61,6 +61,7 @@ neoForge { systemProperty 'anvillib.rendering.debugMode', 'true' systemProperty('neoforge.rendernurse.renderdoc.library', rootProject.file("libs/renderdoc.dll").absolutePath) taskBefore(rootProject.project('renderdoc-loader-internal').tasks.getByName('jar')) + programArgument("--renderDebugLabels") jvmArgument("-javaagent:" + rootProject.project('renderdoc-loader-internal').tasks.getByName('jar').archiveFile.get().asFile.absolutePath) } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java index 91875341..db71a687 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java @@ -5,12 +5,10 @@ import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ComputeBindingLayout; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; -import lombok.Setter; import java.util.List; public class ALRComputePass implements AutoCloseable { - @Setter private ALRComputePipeline pipeline; private final ALRComputePassBackend backend; @@ -35,7 +33,9 @@ public void dispatchWorkgroups( int groupCountY, int groupCountZ ) { + this.backend.pushDebugGroup("Compute " + pipeline.identifier()); this.backend.dispatchWorkgroups(groupCountX, groupCountY, groupCountZ); + this.backend.popDebugGroup(); } public void dispatchWorkgroupsIndirect( @@ -49,11 +49,16 @@ public void close() { this.backend.close(); } + public void setPipeline(ALRComputePipeline pipeline) { + this.pipeline = pipeline; + this.backend.setPipeline(pipeline); + } + @SuppressWarnings({"unchecked", "rawtypes"}) public void bindAll(List elements) { int bindingPoint = 0; for (ComputeBindingLayout binding : pipeline.bindings()) { - this.bind(bindingPoint++, binding, elements.get(bindingPoint)); + this.bind(bindingPoint++, binding, elements.get(bindingPoint - 1)); } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java index 745aa775..7adab954 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePipeline.java @@ -13,7 +13,12 @@ import java.util.List; import java.util.Objects; -public record ALRComputePipeline(List> bindings, Identifier shaderLocation, ShaderDefines defines) { +public record ALRComputePipeline( + Identifier identifier, + List> bindings, + Identifier shaderLocation, + ShaderDefines defines +) { public static Builder builder() { return new Builder(); @@ -25,6 +30,7 @@ public static Builder builder(ALRComputePipeline pipeline) { public static class Builder { private final List> bindings = new ArrayList<>(); + private Identifier name; private Identifier shaderLocation; private ShaderDefines defines = ShaderDefines.EMPTY; @@ -41,6 +47,11 @@ public Builder withShader(Identifier shaderLocation) { return this; } + public Builder withName(Identifier name) { + this.name = name; + return this; + } + public Builder withShaderLocation(Identifier shaderLocation) { return this.withShader(shaderLocation); } @@ -89,6 +100,7 @@ public Builder withAtomicCounter(String name) { public ALRComputePipeline build() { return new ALRComputePipeline( + Objects.requireNonNull(this.name, "name"), this.bindings, Objects.requireNonNull(this.shaderLocation, "shaderLocation"), this.defines diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java index 973ca375..88584987 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/shader/ALRComputeShaderManager.java @@ -60,6 +60,7 @@ public class ALRComputeShaderManager extends SimplePreparableReloadListener - CachedBlockEntityRenderDispatcher.INSTANCE.registerRenderer(TestTiles.TEST_CACHED_RENDERING, new TestCachedRenderer()) + CachedBlockEntityRenderDispatcher.INSTANCE.registerRenderer( + TestTiles.TEST_CACHED_RENDERING, + new TestCachedRenderer() + ) ); } @@ -46,6 +56,35 @@ public static void on(RegisterClientCommandsEvent event) { Minecraft.getInstance().setScreen(new GuiTestScreen()); return 1; }) + ). + then( + literal("compute"). + then( + literal("add"). + then( + argument("what", FloatArgumentType.floatArg()). + executes( + ctx -> { + try { + float[] fs = new float[32]; + Random random = new Random(System.nanoTime()); + for (int i = 0; i < 32; i++) { + fs[i] = random.nextInt(0, 10); + } + float with = ctx.getArgument("what", Float.class); + float[] add = ComputeSupport.INSTANCE.add(fs, with); + String a = Arrays.toString(fs); + String result = Arrays.toString(add); + System.out.println("a = " + a); + System.out.println("result = " + result); + }catch (Throwable ex){ + ex.printStackTrace(); + } + return 0; + } + ) + ) + ) ) ); } diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java new file mode 100644 index 00000000..be3dc9d6 --- /dev/null +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java @@ -0,0 +1,109 @@ +package dev.anvilcraft.lib.v2.test.client.compute; + +import com.mojang.blaze3d.buffers.GpuBuffer; +import com.mojang.blaze3d.buffers.GpuFence; +import com.mojang.blaze3d.systems.CommandEncoder; +import com.mojang.blaze3d.systems.GpuDevice; +import com.mojang.blaze3d.systems.RenderSystem; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.GpuBufferConstants; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObject; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; +import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.ShaderBufferObjectUsage; +import org.lwjgl.system.MemoryStack; + +import java.nio.ByteBuffer; +import java.util.List; + +public class ComputeSupport { + public static final ComputeSupport INSTANCE = new ComputeSupport(); + private final GpuDevice device = RenderSystem.getDevice(); + + private final GpuBuffer addInputSSBO = device.createBuffer( + () -> "Test Compute Input SSBO", + GpuBuffer.USAGE_COPY_SRC | GpuBuffer.USAGE_COPY_DST | GpuBufferConstants.USAGE_SHADER_STORAGE, + 4 * 1024 + ); + + private final GpuBuffer addOutputSSBO = device.createBuffer( + () -> "Test Compute Output SSBO", + GpuBuffer.USAGE_COPY_SRC | GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_MAP_READ | GpuBufferConstants.USAGE_SHADER_STORAGE, + 4 * 1024 + ); + + private final GpuBuffer addParamUBO = device.createBuffer( + () -> "Test Compute Param UBO", + GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_UNIFORM, + AddParamUbo.LAYOUT.size(BufferLayout.STD140) + ); + + private final AddParamUbo addParam = new AddParamUbo(); + + public float[] add(float[] input, float f) { + CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder(); + ALRCommandEncoderExtension commandEncoderExtension = ALRCommandEncoderExtension.of(commandEncoder); + addParam.arraySize = input.length; + addParam.f1 = f; + try (MemoryStack stack = MemoryStack.stackPush()) { + int inputSize = 4 * input.length; + ByteBuffer inputBuffer = stack.malloc(inputSize); + for (float v : input) { + inputBuffer.putFloat(v); + } + inputBuffer.rewind(); + commandEncoder.writeToBuffer(addInputSSBO.slice(0, inputSize), inputBuffer); + } + addParam.upload(commandEncoder, addParamUBO.slice()); + try (ALRComputePass pass = commandEncoderExtension.alrCreateComputePass()) { + pass.setPipeline(TestPipelines.ADD); + pass.bindAll( + List.of( + addInputSSBO.slice(), + addOutputSSBO.slice(), + addParamUBO.slice() + ) + ); + pass.dispatchWorkgroups((input.length + 16 - 1) / 16, 1, 1); + pass.memoryBarrier(MemoryBarrierFlag.SHADER_STORAGE_BARRIER, MemoryBarrierFlag.BUFFER_UPDATE_BARRIER); + } + try (GpuFence fence = commandEncoder.createFence()) { + fence.awaitCompletion(Long.MAX_VALUE); + } + float[] result = new float[input.length]; + GpuBuffer.MappedView mappedView = commandEncoder.mapBuffer(addOutputSSBO, true, false); + ByteBuffer data = mappedView.data(); + for (int i = 0; i < input.length; i++) { + result[i] = data.getFloat(); + } + return result; + } + + + private static class AddParamUbo extends BufferObject { + + float f1 = 1; + int arraySize = 0; + + public static final BufferObjectLayoutDefinition LAYOUT = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofFloat().forGetter(it -> it.f1).build(), + BufferObjectLayoutEntry.ofInt().forGetter(it -> it.arraySize).build() + ); + + protected AddParamUbo() { + super(BufferLayout.STD140, ShaderBufferObjectUsage.UBO); + } + + @Override + protected BufferObjectLayoutDefinition getDefinition() { + return LAYOUT; + } + } + + + public static void init() { + } +} diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java index a541ebe4..befe02cc 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java @@ -10,17 +10,29 @@ @EventBusSubscriber(Dist.CLIENT) public class TestPipelines { public static final ALRComputePipeline TEST = ALRComputePipeline.builder() + .withName(AnvilLibTest.of("test")) .withShaderStorage("Input") .withShaderStorage("Output") .withShader(AnvilLibTest.of("compute/test.csh")) .build(); public static final ALRComputePipeline EMPTY = ALRComputePipeline.builder() + .withName(AnvilLibTest.of("empty")) .withShader(AnvilLibTest.of("compute/empty.csh")) .build(); + public static final ALRComputePipeline ADD = ALRComputePipeline.builder() + .withName(AnvilLibTest.of("add")) + .withShaderStorage("Input") + .withShaderStorage("Output") + .withUniformBlock("AddParameter") + .withShader(AnvilLibTest.of("compute/add.csh")) + .build(); + @SubscribeEvent public static void on(RegisterComputePipelinesEvent event) { event.registerPipeline(TEST); + event.registerPipeline(EMPTY); + event.registerPipeline(ADD); } } diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java index 8b223a3a..2a0f852d 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java @@ -7,6 +7,7 @@ import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; import dev.anvilcraft.lib.v2.rendering.foundation.fakeworld.FakeDisplayLevel; import dev.anvilcraft.lib.v2.rendering.gui.GuiRenderExtras; +import dev.anvilcraft.lib.v2.test.client.compute.ComputeSupport; import dev.anvilcraft.lib.v2.test.client.compute.TestPipelines; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphicsExtractor; @@ -19,6 +20,9 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluids; +import java.util.Arrays; +import java.util.Random; + public class GuiTestScreen extends Screen { private final FakeDisplayLevel level = new FakeDisplayLevel(Minecraft.getInstance().level); @@ -195,6 +199,8 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo ); graphics.pose().popMatrix(); + + dispatchComputeTest(); } public void dispatchComputeTest() { @@ -203,6 +209,18 @@ public void dispatchComputeTest() { pass.setPipeline(TestPipelines.EMPTY); pass.dispatchWorkgroups(16, 16, 1); } + + try { + float[] fs = new float[32]; + Random random = new Random(System.nanoTime()); + for (int i = 0; i < 32; i++) { + fs[i] = random.nextInt(0, 10); + } + float with = 10; + ComputeSupport.INSTANCE.add(fs, with); + }catch (Throwable ex){ + ex.printStackTrace(); + } } @Override diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/mixin/MinecraftMixin.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/mixin/MinecraftMixin.java new file mode 100644 index 00000000..72b95901 --- /dev/null +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/mixin/MinecraftMixin.java @@ -0,0 +1,35 @@ +package dev.anvilcraft.lib.v2.test.mixin; + +import com.mojang.blaze3d.platform.Window; +import dev.anvilcraft.lib.v2.rendering.ALRPostEffects; +import dev.anvilcraft.lib.v2.rendering.AnvilLibRendering; +import dev.anvilcraft.lib.v2.rendering.bloom.BloomPostEffect; +import dev.anvilcraft.lib.v2.rendering.cachedber.pipeline.CachedBlockEntityRenderingPipeline; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.ALRComputeCapabilities; +import dev.anvilcraft.lib.v2.test.client.compute.ComputeSupport; +import net.minecraft.client.Minecraft; +import net.minecraft.client.main.GameConfig; +import net.minecraft.client.multiplayer.ClientLevel; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Minecraft.class) +public class MinecraftMixin { + + @Shadow + @Final + private Window window; + + @Inject( + method = "", + at = @At("RETURN") + ) + private void onCreateInstance(GameConfig gameConfig, CallbackInfo ci) { + ComputeSupport.init(); + } + +} diff --git a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh new file mode 100644 index 00000000..7c6d22db --- /dev/null +++ b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh @@ -0,0 +1,24 @@ +#version 460 core + +layout(local_size_x = 16, local_size_y = 1, local_size_z = 1) in; + +layout(std430, binding = 0) readonly buffer Input { + float data[]; +} a; + +layout(std430, binding = 1) writeonly buffer Output { + float data[]; +} b; + +layout(std140, binding = 2) uniform AddParameter { + float f1; + int arraySize; +}; + +void main() { + uint idx = gl_GlobalInvocationID.x; + if (idx >= arraySize) { + return; + } + b.data[idx] = a.data[idx] + f1; +} \ No newline at end of file From a13c4be2ebfb1c4f55c7347a951d7f7e229ceccf Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Thu, 4 Jun 2026 05:35:23 +0800 Subject: [PATCH 4/9] Add compute pipeline part 3.1 --- .../anvilcraft/lib/v2/test/client/compute/ComputeSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java index be3dc9d6..64358652 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java @@ -67,7 +67,7 @@ public float[] add(float[] input, float f) { addParamUBO.slice() ) ); - pass.dispatchWorkgroups((input.length + 16 - 1) / 16, 1, 1); + pass.dispatchWorkgroups(Math.ceilDiv(input.length, 16), 1, 1); pass.memoryBarrier(MemoryBarrierFlag.SHADER_STORAGE_BARRIER, MemoryBarrierFlag.BUFFER_UPDATE_BARRIER); } try (GpuFence fence = commandEncoder.createFence()) { From 3962bf349bb38e0ade4e1dd3c260af0436ad89b2 Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Sun, 7 Jun 2026 05:46:00 +0800 Subject: [PATCH 5/9] Add compute pipeline part 4 --- .../lib/v2/rendering/ALRPipelines.java | 54 +++---- .../lib/v2/rendering/ALRPostEffects.java | 17 +- .../lib/v2/rendering/AnvilLibRendering.java | 23 ++- .../v2/rendering/bloom/BloomPostEffect.java | 2 - .../CachedBlockEntityRenderingPipeline.java | 4 +- .../pipeline/CachedRenderingChunk.java | 14 +- .../event/MainTargetResizeEvent.java | 16 ++ .../buffers/GpuBufferConstants.java | 1 + .../lib/v2/rendering/gui/GuiRenderExtras.java | 146 +++++++++++++++++- .../state/DynamicTextureBlitRenderState.java | 99 ++++++++++++ .../rendering/mixins/GameRendererMixin.java | 12 +- .../v2/test/client/AnvilLibTestClient.java | 15 +- .../test/client/cber/TestCachedRenderer.java | 16 ++ .../test/client/compute/ComputeSupport.java | 130 +++++++++++++++- .../v2/test/client/compute/TestPipelines.java | 10 ++ .../v2/test/client/screen/GuiTestScreen.java | 28 +++- .../anvillib_test/shaders/compute/add.csh | 3 + .../shaders/compute/image_and_sampler.csh | 36 +++++ 18 files changed, 557 insertions(+), 69 deletions(-) create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/MainTargetResizeEvent.java create mode 100644 module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java create mode 100644 module.test/src/main/resources/assets/anvillib_test/shaders/compute/image_and_sampler.csh diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPipelines.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPipelines.java index ead8a6af..3ce2c3fe 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPipelines.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPipelines.java @@ -36,38 +36,38 @@ public class ALRPipelines { .build(); public static final RenderPipeline DOWNSAMPLE = RenderPipeline.builder(POST_PASS) - .withLocation(AnvilLibRendering.location("down_sample")) - .withFragmentShader(AnvilLibRendering.location("core/down_sample")) - .withSampler("DiffuseSampler") - .withUniform("BloomParameters", UniformType.UNIFORM_BUFFER) - .build(); + .withLocation(AnvilLibRendering.location("down_sample")) + .withFragmentShader(AnvilLibRendering.location("core/down_sample")) + .withSampler("DiffuseSampler") + .withUniform("BloomParameters", UniformType.UNIFORM_BUFFER) + .build(); public static final RenderPipeline UPSAMPLE = RenderPipeline.builder(POST_PASS) - .withLocation(AnvilLibRendering.location("up_sample")) - .withFragmentShader(AnvilLibRendering.location("core/up_sample")) - .withSampler("DiffuseSampler") - .withSampler("PreviousSampler") - .withUniform("BloomParameters", UniformType.UNIFORM_BUFFER) - .build(); + .withLocation(AnvilLibRendering.location("up_sample")) + .withFragmentShader(AnvilLibRendering.location("core/up_sample")) + .withSampler("DiffuseSampler") + .withSampler("PreviousSampler") + .withUniform("BloomParameters", UniformType.UNIFORM_BUFFER) + .build(); - public static final VertexFormat SDF_GRAPHICS_FORMAT = VertexFormat.builder() - .add("Position", VertexFormatElement.POSITION) - .add("Color", VertexFormatElement.COLOR) - .add("UV0", VertexFormatElement.UV) - .add("UV1", VertexFormatElement.UV1) - .build(); + public static final VertexFormat SDF_GRAPHICS_FORMAT = VertexFormat.builder() + .add("Position", VertexFormatElement.POSITION) + .add("Color", VertexFormatElement.COLOR) + .add("UV0", VertexFormatElement.UV) + .add("UV1", VertexFormatElement.UV1) + .build(); public static final RenderPipeline SDF_GRAPHICS = RenderPipeline.builder() - .withLocation(AnvilLibRendering.location("sdf_graphics")) - .withVertexShader(AnvilLibRendering.location("core/sdf_graphics")) - .withFragmentShader(AnvilLibRendering.location("core/sdf_graphics")) - .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) - .withVertexFormat(SDF_GRAPHICS_FORMAT, VertexFormat.Mode.QUADS) - .withUniform("DynamicTransforms", UniformType.UNIFORM_BUFFER) - .withUniform("Projection", UniformType.UNIFORM_BUFFER) - .withUniform("SDFParameters", UniformType.UNIFORM_BUFFER) - .withCull(false) - .build(); + .withLocation(AnvilLibRendering.location("sdf_graphics")) + .withVertexShader(AnvilLibRendering.location("core/sdf_graphics")) + .withFragmentShader(AnvilLibRendering.location("core/sdf_graphics")) + .withColorTargetState(new ColorTargetState(BlendFunction.TRANSLUCENT)) + .withVertexFormat(SDF_GRAPHICS_FORMAT, VertexFormat.Mode.QUADS) + .withUniform("DynamicTransforms", UniformType.UNIFORM_BUFFER) + .withUniform("Projection", UniformType.UNIFORM_BUFFER) + .withUniform("SDFParameters", UniformType.UNIFORM_BUFFER) + .withCull(false) + .build(); @SubscribeEvent diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPostEffects.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPostEffects.java index ff214b84..414db1e2 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPostEffects.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/ALRPostEffects.java @@ -1,12 +1,16 @@ package dev.anvilcraft.lib.v2.rendering; import dev.anvilcraft.lib.v2.rendering.bloom.BloomPostEffect; +import dev.anvilcraft.lib.v2.rendering.event.MainTargetResizeEvent; import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderBuffers; import net.minecraft.client.renderer.feature.FeatureRenderDispatcher; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; import org.joml.Matrix4fc; +@EventBusSubscriber public class ALRPostEffects { @Getter private static BloomPostEffect bloomPostEffect; @@ -15,7 +19,7 @@ public static void createPostEffects() { bloomPostEffect = new BloomPostEffect(); } - public static void runBloomDraws(Matrix4fc mvMat){ + public static void runBloomDraws(Matrix4fc mvMat) { Minecraft minecraft = Minecraft.getInstance(); RenderBuffers renderBuffers = minecraft.renderBuffers(); FeatureRenderDispatcher frd = new FeatureRenderDispatcher( @@ -30,4 +34,15 @@ public static void runBloomDraws(Matrix4fc mvMat){ ); bloomPostEffect.runBloomDraws(mvMat, frd); } + + @SubscribeEvent + public static void on(MainTargetResizeEvent event) { + BloomPostEffect bloomPostEffect = ALRPostEffects.getBloomPostEffect(); + if (bloomPostEffect != null) { + bloomPostEffect.resize( + event.getNewWidth(), + event.getNewHeight() + ); + } + } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java index 3cc10419..a63720b0 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/AnvilLibRendering.java @@ -39,15 +39,32 @@ public static void on(RenderFrameEvent.Pre event) { } @SubscribeEvent - public static void on(AddClientReloadListenersEvent event){ + public static void on(AddClientReloadListenersEvent event) { event.addListener(AnvilLibRendering.location("compute_shader_manager"), ALRComputeShaderManager.INSTANCE); } @SubscribeEvent - public static void on(RenderLevelStageEvent.AfterTranslucentParticles event) { + public static void on(RenderLevelStageEvent.AfterOpaqueBlocks event) { + if (CachedBlockEntityRenderingPipeline.getInstance() != null) { + CachedBlockEntityRenderingPipeline.getInstance().render( + event.getLevelRenderState().cameraRenderState.cullFrustum, + false + ); + } + } + + @SubscribeEvent + public static void on(RenderLevelStageEvent.AfterTranslucentFeatures event) { if (CachedBlockEntityRenderingPipeline.getInstance() != null) { - CachedBlockEntityRenderingPipeline.getInstance().render(event.getLevelRenderState().cameraRenderState.cullFrustum); + CachedBlockEntityRenderingPipeline.getInstance().render( + event.getLevelRenderState().cameraRenderState.cullFrustum, + true + ); } + } + + @SubscribeEvent + public static void on(RenderLevelStageEvent.AfterTranslucentParticles event) { ALRPostEffects.runBloomDraws(event.getModelViewMatrix()); } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java index 49161621..98749f8b 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/bloom/BloomPostEffect.java @@ -269,8 +269,6 @@ private void applyBloom( bloomPass.close(); } - - private void doDownSample( CommandEncoder commandEncoder, RenderTarget inputTarget diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedBlockEntityRenderingPipeline.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedBlockEntityRenderingPipeline.java index 36f744af..cc033e60 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedBlockEntityRenderingPipeline.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedBlockEntityRenderingPipeline.java @@ -120,9 +120,9 @@ public void releaseBuffers() { valid = false; } - public void render(Frustum frustum) { + public void render(Frustum frustum, boolean translucent) { for (CachedRenderingChunk value : chunks.values()) { - value.render(frustum); + value.render(frustum, translucent); } } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedRenderingChunk.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedRenderingChunk.java index df0b26ce..f1d62af3 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedRenderingChunk.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/cachedber/pipeline/CachedRenderingChunk.java @@ -10,7 +10,6 @@ import com.mojang.blaze3d.vertex.ByteBufferBuilder; import com.mojang.blaze3d.vertex.MeshData; import com.mojang.blaze3d.vertex.VertexFormat; -import com.mojang.blaze3d.vertex.VertexSorting; import dev.anvilcraft.lib.v2.rendering.ALRPostEffects; import dev.anvilcraft.lib.v2.rendering.extension.ALRRenderTypeExtension; import dev.anvilcraft.lib.v2.rendering.foundation.ALRMeshSorting; @@ -20,7 +19,6 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; -import lombok.experimental.ExtensionMethod; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.culling.Frustum; import net.minecraft.client.renderer.rendertype.RenderSetup; @@ -34,12 +32,9 @@ import org.joml.Vector4f; import org.jspecify.annotations.Nullable; -import java.util.ArrayList; import java.util.Collection; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.OptionalDouble; import java.util.OptionalInt; @@ -121,9 +116,9 @@ public void blockRemoved(BlockEntity be) { } } - public void render(Frustum frustum) { + public void render(Frustum frustum, boolean translucent) { if (!frustum.isVisible(renderingBB)) return; - renderInternal(buffers.keySet()); + renderInternal(buffers.keySet(), translucent); } public GpuBuffer getBuffer(Map buffers, RenderType renderType, long size, int usage) { @@ -166,7 +161,7 @@ public ByteBufferBuilder getSortingByteBufferBuilder(RenderType renderType) { return builder; } - private void renderInternal(Collection renderTypes) { + private void renderInternal(Collection renderTypes, boolean translucent) { if (isEmpty) return; Vec3 cameraPosition = minecraft.gameRenderer.getMainCamera().position(); @@ -176,8 +171,7 @@ private void renderInternal(Collection renderTypes) { return; } - renderLayers(renderTypes, cameraPosition, false); - renderLayers(renderTypes, cameraPosition, true); + renderLayers(renderTypes, cameraPosition, translucent); } private void renderLayers(Collection renderingOrders, Vec3 cameraPosition, boolean translucent) { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/MainTargetResizeEvent.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/MainTargetResizeEvent.java new file mode 100644 index 00000000..cb3c0d9c --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/event/MainTargetResizeEvent.java @@ -0,0 +1,16 @@ +package dev.anvilcraft.lib.v2.rendering.event; + +import lombok.Getter; +import net.neoforged.bus.api.Event; +import net.neoforged.fml.event.IModBusEvent; + +@Getter +public class MainTargetResizeEvent extends Event implements IModBusEvent { + private final int newWidth; + private final int newHeight; + + public MainTargetResizeEvent(int newWidth, int newHeight) { + this.newWidth = newWidth; + this.newHeight = newHeight; + } +} diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java index 493b1712..0c94b2d5 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/GpuBufferConstants.java @@ -2,4 +2,5 @@ public class GpuBufferConstants { public static final int USAGE_SHADER_STORAGE = 512; + public static final int USAGE_ATOMIC_COUNTER = 1024; } diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java index d034c4d7..f255eec9 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/GuiRenderExtras.java @@ -1,24 +1,70 @@ package dev.anvilcraft.lib.v2.rendering.gui; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTextureView; import com.mojang.blaze3d.vertex.PoseStack; import dev.anvilcraft.lib.v2.rendering.ALRSharedMath; import dev.anvilcraft.lib.v2.rendering.extension.GuiGraphicsExtractorExtension; import dev.anvilcraft.lib.v2.rendering.gui.state.BlockStatePipRenderingState; +import dev.anvilcraft.lib.v2.rendering.gui.state.DynamicTextureBlitRenderState; import dev.anvilcraft.lib.v2.rendering.gui.state.StructurePipRenderingState; import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.RenderPipelines; import net.minecraft.client.renderer.block.BlockAndTintGetter; +import net.minecraft.client.renderer.state.gui.BlitRenderState; import net.minecraft.core.BlockPos; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState; import org.joml.Matrix3x2f; import org.jspecify.annotations.Nullable; +import java.util.function.Supplier; + public class GuiRenderExtras { - public static void itemWithTransparency(GuiGraphicsExtractor guiGraphicsExtractor, ItemStack stack, int x, int y, float alpha) { + public static void itemWithTransparency( + GuiGraphicsExtractor guiGraphicsExtractor, + ItemStack stack, + int x, + int y, + float alpha + ) { GuiGraphicsExtractorExtension.of(guiGraphicsExtractor).translucentItem(stack, x, y, alpha); } + public static void blitDynamicTexture( + GuiGraphicsExtractor extractor, + Supplier texture, + GpuSampler sampler, + int x0, + int y0, + int x1, + int y1, + float u0, + float v0, + float u1, + float v1 + ) { + extractor.submitGuiElementRenderState( + new DynamicTextureBlitRenderState( + RenderPipelines.GUI_TEXTURED, + () -> TextureSetup.singleTexture(texture.get(), sampler), + new Matrix3x2f(extractor.pose()), + x0, + y0, + x1, + y1, + u0, + v0, + u1, + v1, + -1, + extractor.peekScissorStack() + ) + ); + } + public static void tessellateBlock( GuiGraphicsExtractor guiGraphicsExtractor, BlockState blockState, @@ -63,7 +109,19 @@ public static void tessellateBlock( boolean ambientOcclusion, PoseStack poseStack3D ) { - tessellateBlock(guiGraphicsExtractor, blockState, level, blockPos, x0, y0, x1, y1, color, ambientOcclusion, poseStack3D.last().copy()); + tessellateBlock( + guiGraphicsExtractor, + blockState, + level, + blockPos, + x0, + y0, + x1, + y1, + color, + ambientOcclusion, + poseStack3D.last().copy() + ); } public static void tessellateBlock( @@ -78,7 +136,19 @@ public static void tessellateBlock( boolean ambientOcclusion, PoseStack poseStack3D ) { - tessellateBlock(guiGraphicsExtractor, blockState, level, blockPos, x0, y0, x1, y1, -1, ambientOcclusion, poseStack3D); + tessellateBlock( + guiGraphicsExtractor, + blockState, + level, + blockPos, + x0, + y0, + x1, + y1, + -1, + ambientOcclusion, + poseStack3D + ); } public static void tessellateBlock( @@ -92,7 +162,19 @@ public static void tessellateBlock( boolean ambientOcclusion, PoseStack poseStack3D ) { - tessellateBlock(guiGraphicsExtractor, blockState, level, blockPos, x0, y0, x0 + width, y0 + width, -1, ambientOcclusion, poseStack3D); + tessellateBlock( + guiGraphicsExtractor, + blockState, + level, + blockPos, + x0, + y0, + x0 + width, + y0 + width, + -1, + ambientOcclusion, + poseStack3D + ); } public static void tessellateBlock( @@ -105,7 +187,19 @@ public static void tessellateBlock( boolean ambientOcclusion, PoseStack poseStack3D ) { - tessellateBlock(guiGraphicsExtractor, blockState, level, blockPos, x0, y0, x0 + 32f, y0 + 32f, -1, ambientOcclusion, poseStack3D); + tessellateBlock( + guiGraphicsExtractor, + blockState, + level, + blockPos, + x0, + y0, + x0 + 32f, + y0 + 32f, + -1, + ambientOcclusion, + poseStack3D + ); } public static void tessellateBlock( @@ -115,7 +209,19 @@ public static void tessellateBlock( float y0, PoseStack poseStack3D ) { - tessellateBlock(guiGraphicsExtractor, blockState, null, null, x0, y0, x0 + 32f, y0 + 32f, -1, false, poseStack3D); + tessellateBlock( + guiGraphicsExtractor, + blockState, + null, + null, + x0, + y0, + x0 + 32f, + y0 + 32f, + -1, + false, + poseStack3D + ); } public static void tessellateBlock( @@ -126,7 +232,19 @@ public static void tessellateBlock( boolean ambientOcclusion, PoseStack poseStack3D ) { - tessellateBlock(guiGraphicsExtractor, blockState, null, null, x0, y0, x0 + 32f, y0 + 32f, -1, ambientOcclusion, poseStack3D); + tessellateBlock( + guiGraphicsExtractor, + blockState, + null, + null, + x0, + y0, + x0 + 32f, + y0 + 32f, + -1, + ambientOcclusion, + poseStack3D + ); } public static void tessellateBlock( @@ -135,7 +253,19 @@ public static void tessellateBlock( float x0, float y0 ) { - tessellateBlock(guiGraphicsExtractor, blockState, null, null, x0, y0, x0 + 32f, y0 + 32f, -1, false, ALRSharedMath.IDENTITY_POSE_3D); + tessellateBlock( + guiGraphicsExtractor, + blockState, + null, + null, + x0, + y0, + x0 + 32f, + y0 + 32f, + -1, + false, + ALRSharedMath.IDENTITY_POSE_3D + ); } public static void submitStructure( diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java new file mode 100644 index 00000000..da85e046 --- /dev/null +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java @@ -0,0 +1,99 @@ +package dev.anvilcraft.lib.v2.rendering.gui.state; + +import com.mojang.blaze3d.pipeline.RenderPipeline; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.gui.navigation.ScreenRectangle; +import net.minecraft.client.gui.render.TextureSetup; +import net.minecraft.client.renderer.state.gui.GuiElementRenderState; +import org.joml.Matrix3x2f; +import org.jspecify.annotations.Nullable; + +import java.util.function.Supplier; + +public record DynamicTextureBlitRenderState( + RenderPipeline pipeline, + Supplier textureSetupSupplier, + Matrix3x2f pose, + int x0, + int y0, + int x1, + int y1, + float u0, + float v0, + float u1, + float v1, + int color, + @Nullable ScreenRectangle scissorArea, + @Nullable ScreenRectangle bounds +) implements GuiElementRenderState { + + public DynamicTextureBlitRenderState( + RenderPipeline pipeline, + Supplier textureSetup, + Matrix3x2f pose, + int x0, + int y0, + int x1, + int y1, + float u0, + float v0, + float u1, + float v1, + int color, + @Nullable ScreenRectangle scissorArea + ) { + this( + pipeline, + textureSetup, + pose, + x0, + y0, + x1, + y1, + u0, + u1, + v0, + v1, + color, + scissorArea, + getBounds(x0, y0, x1, y1, pose, scissorArea) + ); + } + + public void buildVertices(VertexConsumer vertexConsumer) { + vertexConsumer.addVertexWith2DPose(this.pose(), (float) this.x0(), (float) this.y0()).setUv( + this.u0(), + this.v0() + ).setColor(this.color()); + vertexConsumer.addVertexWith2DPose(this.pose(), (float) this.x0(), (float) this.y1()).setUv( + this.u0(), + this.v1() + ).setColor(this.color()); + vertexConsumer.addVertexWith2DPose(this.pose(), (float) this.x1(), (float) this.y1()).setUv( + this.u1(), + this.v1() + ).setColor(this.color()); + vertexConsumer.addVertexWith2DPose(this.pose(), (float) this.x1(), (float) this.y0()).setUv( + this.u1(), + this.v0() + ).setColor(this.color()); + } + + @Override + public TextureSetup textureSetup() { + return textureSetupSupplier.get(); + } + + private static @Nullable ScreenRectangle getBounds( + int x0, + int y0, + int x1, + int y1, + Matrix3x2f pose, + @Nullable ScreenRectangle scissorArea + ) { + ScreenRectangle bounds = (new ScreenRectangle(x0, y0, x1 - x0, y1 - y0)).transformMaxBounds(pose); + return scissorArea != null ? scissorArea.intersection(bounds) : bounds; + } +} + diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/GameRendererMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/GameRendererMixin.java index 8d9be6bc..b315c7ba 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/GameRendererMixin.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/GameRendererMixin.java @@ -1,8 +1,8 @@ package dev.anvilcraft.lib.v2.rendering.mixins; -import dev.anvilcraft.lib.v2.rendering.ALRPostEffects; -import dev.anvilcraft.lib.v2.rendering.bloom.BloomPostEffect; +import dev.anvilcraft.lib.v2.rendering.event.MainTargetResizeEvent; import net.minecraft.client.renderer.GameRenderer; +import net.neoforged.fml.ModLoader; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -16,12 +16,6 @@ public class GameRendererMixin { at = @At("HEAD") ) void onResize(int width, int height, CallbackInfo ci) { - BloomPostEffect bloomPostEffect = ALRPostEffects.getBloomPostEffect(); - if (bloomPostEffect != null) { - bloomPostEffect.resize( - width, - height - ); - } + ModLoader.postEvent(new MainTargetResizeEvent(width, height)); } } diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java index 68c373a7..a92896e8 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java @@ -2,6 +2,7 @@ import com.mojang.brigadier.arguments.FloatArgumentType; import dev.anvilcraft.lib.v2.rendering.cachedber.renderer.CachedBlockEntityRenderDispatcher; +import dev.anvilcraft.lib.v2.rendering.event.MainTargetResizeEvent; import dev.anvilcraft.lib.v2.test.AnvilLibTest; import dev.anvilcraft.lib.v2.test.all.TestTiles; import dev.anvilcraft.lib.v2.test.client.cber.TestCachedRenderer; @@ -12,12 +13,14 @@ import net.minecraft.client.Minecraft; import net.minecraft.commands.Commands; import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.neoforge.client.event.RegisterClientCommandsEvent; import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent; +import net.neoforged.neoforge.client.event.RenderLevelStageEvent; import java.util.Arrays; import java.util.Random; @@ -46,6 +49,16 @@ public static void onRegisterGuiLayers(RegisterGuiLayersEvent e) { e.registerAboveAll(SdfGraphicsLayer.LOCATION, new SdfGraphicsLayer()); } + @SubscribeEvent + public static void on(MainTargetResizeEvent event) { + ComputeSupport.INSTANCE.resize(event.getNewWidth(), event.getNewHeight()); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public static void on(RenderLevelStageEvent.AfterLevel level) { + ComputeSupport.INSTANCE.computeBlur(); + } + @SubscribeEvent public static void on(RegisterClientCommandsEvent event) { event.getDispatcher().register( @@ -77,7 +90,7 @@ public static void on(RegisterClientCommandsEvent event) { String result = Arrays.toString(add); System.out.println("a = " + a); System.out.println("result = " + result); - }catch (Throwable ex){ + } catch (Throwable ex) { ex.printStackTrace(); } return 0; diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/cber/TestCachedRenderer.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/cber/TestCachedRenderer.java index ca2f6649..5053785c 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/cber/TestCachedRenderer.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/cber/TestCachedRenderer.java @@ -47,6 +47,12 @@ public State extractRenderState(TestCachedRenderingTile blockEntity, State state state.displayContext ); + minecraft.getBlockModelResolver().update( + state.blockModelRenderState1, + Blocks.LIME_STAINED_GLASS.defaultBlockState(), + state.displayContext + ); + return state; } @@ -72,12 +78,22 @@ public void submit(State renderState, PoseStack poseStack, SubmitNodeCollector s OverlayTexture.NO_OVERLAY, 0 ); + + poseStack.translate(0, 1, 0); + renderState.blockModelRenderState1.submit( + poseStack, + submitNodeCollector, + LightCoordsUtil.FULL_BRIGHT, + OverlayTexture.NO_OVERLAY, + 0 + ); poseStack.popPose(); } public static class State extends CachedBlockEntityRenderState { private final ItemStackRenderState renderState = new ItemStackRenderState(); private final BlockModelRenderState blockModelRenderState = new BlockModelRenderState(); + private final BlockModelRenderState blockModelRenderState1 = new BlockModelRenderState(); private final BlockDisplayContext displayContext = BlockDisplayContext.create(); } } diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java index 64358652..f6f82d6a 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java @@ -5,22 +5,33 @@ import com.mojang.blaze3d.systems.CommandEncoder; import com.mojang.blaze3d.systems.GpuDevice; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.AddressMode; +import com.mojang.blaze3d.textures.FilterMode; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTexture; +import com.mojang.blaze3d.textures.GpuTextureView; +import com.mojang.blaze3d.textures.TextureFormat; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderExtension; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; import dev.anvilcraft.lib.v2.rendering.foundation.buffers.GpuBufferConstants; import dev.anvilcraft.lib.v2.rendering.foundation.buffers.layout.BufferLayout; import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObject; import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutDefinition; import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.BufferObjectLayoutEntry; import dev.anvilcraft.lib.v2.rendering.foundation.buffers.object.ShaderBufferObjectUsage; +import lombok.Getter; +import net.minecraft.client.Minecraft; import org.lwjgl.system.MemoryStack; import java.nio.ByteBuffer; import java.util.List; +import java.util.OptionalDouble; public class ComputeSupport { public static final ComputeSupport INSTANCE = new ComputeSupport(); + @Getter private final GpuDevice device = RenderSystem.getDevice(); private final GpuBuffer addInputSSBO = device.createBuffer( @@ -35,13 +46,48 @@ public class ComputeSupport { 4 * 1024 ); + private final GpuBuffer addOutputCounter = device.createBuffer( + () -> "Test Compute Output Atomic Counter", + GpuBuffer.USAGE_COPY_SRC | GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_MAP_READ | GpuBufferConstants.USAGE_ATOMIC_COUNTER, + 4 + ); + private final GpuBuffer addParamUBO = device.createBuffer( () -> "Test Compute Param UBO", GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_UNIFORM, AddParamUbo.LAYOUT.size(BufferLayout.STD140) ); + @Getter + private final GpuSampler theSampler = device.createSampler( + AddressMode.CLAMP_TO_EDGE, + AddressMode.CLAMP_TO_EDGE, + FilterMode.LINEAR, + FilterMode.LINEAR, + 1, + OptionalDouble.empty() + ); + + private GpuTexture outputTexture = device.createTexture( + "Test Compute Output Texture", + GpuTexture.USAGE_COPY_SRC | GpuTexture.USAGE_COPY_DST | GpuTexture.USAGE_TEXTURE_BINDING | GpuTexture.USAGE_RENDER_ATTACHMENT, + TextureFormat.RGBA8, + 854, 480, + 1, + 1 + ); + + @Getter + private GpuTextureView outputTextureView = device.createTextureView(outputTexture); + + private final GpuBuffer blurParamUBO = device.createBuffer( + () -> "Test Compute Blur Param UBO", + GpuBuffer.USAGE_COPY_DST | GpuBuffer.USAGE_UNIFORM, + BlurParamUbo.LAYOUT.size(BufferLayout.STD140) + ); + private final AddParamUbo addParam = new AddParamUbo(); + private final BlurParamUbo blurParam = new BlurParamUbo(); public float[] add(float[] input, float f) { CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder(); @@ -56,6 +102,10 @@ public float[] add(float[] input, float f) { } inputBuffer.rewind(); commandEncoder.writeToBuffer(addInputSSBO.slice(0, inputSize), inputBuffer); + ByteBuffer counterBuffer = stack.malloc(4); + counterBuffer.putInt(0); + counterBuffer.rewind(); + commandEncoder.writeToBuffer(addOutputCounter.slice(), counterBuffer); } addParam.upload(commandEncoder, addParamUBO.slice()); try (ALRComputePass pass = commandEncoderExtension.alrCreateComputePass()) { @@ -64,11 +114,16 @@ public float[] add(float[] input, float f) { List.of( addInputSSBO.slice(), addOutputSSBO.slice(), - addParamUBO.slice() + addParamUBO.slice(), + addOutputCounter.slice() ) ); pass.dispatchWorkgroups(Math.ceilDiv(input.length, 16), 1, 1); - pass.memoryBarrier(MemoryBarrierFlag.SHADER_STORAGE_BARRIER, MemoryBarrierFlag.BUFFER_UPDATE_BARRIER); + pass.memoryBarrier( + MemoryBarrierFlag.SHADER_STORAGE_BARRIER, + MemoryBarrierFlag.ATOMIC_COUNTER_BARRIER, + MemoryBarrierFlag.BUFFER_UPDATE_BARRIER + ); } try (GpuFence fence = commandEncoder.createFence()) { fence.awaitCompletion(Long.MAX_VALUE); @@ -79,9 +134,80 @@ public float[] add(float[] input, float f) { for (int i = 0; i < input.length; i++) { result[i] = data.getFloat(); } + + GpuBuffer.MappedView mappedCounterBuffer = commandEncoder.mapBuffer(addOutputCounter, true, false); + ByteBuffer counterData = mappedCounterBuffer.data(); + + int anInt = counterData.getInt(); return result; } + public void resize(int width, int height) { + outputTextureView.close(); + outputTexture.close(); + outputTexture = device.createTexture( + "Test Compute Output Texture", + GpuTexture.USAGE_COPY_SRC | GpuTexture.USAGE_COPY_DST | GpuTexture.USAGE_TEXTURE_BINDING | GpuTexture.USAGE_RENDER_ATTACHMENT, + TextureFormat.RGBA8, + width, height, + 1, + 1 + ); + outputTextureView = device.createTextureView(outputTexture); + } + + public GpuTextureView computeBlur() { + GpuTexture colorTexture = Minecraft.getInstance().getMainRenderTarget().getColorTexture(); + int width = colorTexture.getWidth(0); + int height = colorTexture.getHeight(0); + CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder(); + blurParam.width = width; + blurParam.height = height; + ALRCommandEncoderExtension commandEncoderExtension = ALRCommandEncoderExtension.of(commandEncoder); + blurParam.upload(commandEncoder, blurParamUBO.slice()); + commandEncoder.clearColorTexture(outputTexture, 0); + + try (ALRComputePass pass = commandEncoderExtension.alrCreateComputePass()) { + pass.setPipeline(TestPipelines.BLUR); + pass.bindAll( + List.of( + blurParamUBO.slice(), + new TextureBinding.SamplerAndTexture(theSampler, colorTexture), + outputTexture + ) + ); + + pass.dispatchWorkgroups(Math.ceilDiv(width, 16), Math.ceilDiv(height, 16), 1); + pass.memoryBarrier( + MemoryBarrierFlag.TEXTURE_UPDATE_BARRIER, + MemoryBarrierFlag.SHADER_IMAGE_ACCESS_BARRIER, + MemoryBarrierFlag.BUFFER_UPDATE_BARRIER + ); + } + + return outputTextureView; + } + + private static class BlurParamUbo extends BufferObject { + int width; + int height; + + public static final BufferObjectLayoutDefinition LAYOUT = BufferObjectLayoutDefinition.create( + BufferObjectLayoutEntry.ofInt().forGetter(it -> it.width).build(), + BufferObjectLayoutEntry.ofInt().forGetter(it -> it.height).build() + ); + + protected BlurParamUbo() { + super(BufferLayout.STD140, ShaderBufferObjectUsage.UBO); + } + + + @Override + protected BufferObjectLayoutDefinition getDefinition() { + return LAYOUT; + } + } + private static class AddParamUbo extends BufferObject { diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java index befe02cc..d1446390 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/TestPipelines.java @@ -26,13 +26,23 @@ public class TestPipelines { .withShaderStorage("Input") .withShaderStorage("Output") .withUniformBlock("AddParameter") + .withAtomicCounter("Counter") .withShader(AnvilLibTest.of("compute/add.csh")) .build(); + public static final ALRComputePipeline BLUR = ALRComputePipeline.builder() + .withName(AnvilLibTest.of("image_and_sampler")) + .withUniformBlock("BlurParam") + .withTexture("InTexture") + .withWriteOnlyImage("OutImage") + .withShader(AnvilLibTest.of("compute/image_and_sampler.csh")) + .build(); + @SubscribeEvent public static void on(RegisterComputePipelinesEvent event) { event.registerPipeline(TEST); event.registerPipeline(EMPTY); event.registerPipeline(ADD); + event.registerPipeline(BLUR); } } diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java index 2a0f852d..fc5318f6 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java @@ -1,6 +1,9 @@ package dev.anvilcraft.lib.v2.test.client.screen; import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.textures.GpuSampler; +import com.mojang.blaze3d.textures.GpuTexture; +import com.mojang.blaze3d.textures.GpuTextureView; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderExtension; @@ -20,7 +23,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluids; -import java.util.Arrays; import java.util.Random; public class GuiTestScreen extends Screen { @@ -60,6 +62,7 @@ public void extractBackground(GuiGraphicsExtractor graphics, int mouseX, int mou @Override public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) { super.extractRenderState(graphics, mouseX, mouseY, a); + dispatchComputeTest(graphics); graphics.pose().pushMatrix().scale(1); int startX = 10; int startY = 30; @@ -200,10 +203,9 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo graphics.pose().popMatrix(); - dispatchComputeTest(); } - public void dispatchComputeTest() { + public void dispatchComputeTest(GuiGraphicsExtractor graphics) { ALRCommandEncoderExtension commandEncoder = ALRCommandEncoderExtension.of(RenderSystem.getDevice().createCommandEncoder()); try (ALRComputePass pass = commandEncoder.alrCreateComputePass()) { pass.setPipeline(TestPipelines.EMPTY); @@ -218,9 +220,27 @@ public void dispatchComputeTest() { } float with = 10; ComputeSupport.INSTANCE.add(fs, with); - }catch (Throwable ex){ + } catch (Throwable ex) { ex.printStackTrace(); } + + GpuSampler sampler = ComputeSupport.INSTANCE.getTheSampler(); + int scaledWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); + int scaledHeight = Minecraft.getInstance().getWindow().getGuiScaledHeight(); + + GuiRenderExtras.blitDynamicTexture( + graphics, + ComputeSupport.INSTANCE::getOutputTextureView, + sampler, + 0, + 0, + scaledWidth, + scaledHeight, + 0, + 1, + 1, + 0 + ); } @Override diff --git a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh index 7c6d22db..8a5f6edd 100644 --- a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh +++ b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/add.csh @@ -15,10 +15,13 @@ layout(std140, binding = 2) uniform AddParameter { int arraySize; }; +layout(binding = 3) uniform atomic_uint Counter; + void main() { uint idx = gl_GlobalInvocationID.x; if (idx >= arraySize) { return; } b.data[idx] = a.data[idx] + f1; + atomicCounterIncrement(Counter); } \ No newline at end of file diff --git a/module.test/src/main/resources/assets/anvillib_test/shaders/compute/image_and_sampler.csh b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/image_and_sampler.csh new file mode 100644 index 00000000..648c9600 --- /dev/null +++ b/module.test/src/main/resources/assets/anvillib_test/shaders/compute/image_and_sampler.csh @@ -0,0 +1,36 @@ +#version 460 core + +layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; + +layout(std140, binding = 0) uniform BlurParam { + int uWidth; + int uHeight; +}; + +layout(binding = 1) uniform sampler2D InTexture; + +layout(binding = 2, rgba8) writeonly uniform image2D OutImage; + +void main() { + ivec2 idx = ivec2(gl_GlobalInvocationID.xy); + + if (idx.x >= uWidth || idx.y >= uHeight) return; + + const int r = 4; + + vec4 accum = vec4(0.0); + int count = 0; + + for (int dy = -r; dy <= r; dy++) { + for (int dx = -r; dx <= r; dx++) { + ivec2 p = clamp(idx + ivec2(dx, dy), + ivec2(0), + ivec2(uWidth - 1, uHeight - 1)); + accum += texelFetch(InTexture, p, 0); + count++; + } + } + + accum /= float(count); + imageStore(OutImage, idx, accum); +} From 6f4a3be541b0735c65eac2937fb2c9922acee485 Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Sun, 7 Jun 2026 05:48:05 +0800 Subject: [PATCH 6/9] Add compute pipeline part 4.1 --- .../lib/v2/test/client/compute/ComputeSupport.java | 5 +++++ .../anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java index f6f82d6a..4be25801 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java @@ -13,6 +13,7 @@ import com.mojang.blaze3d.textures.TextureFormat; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderExtension; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.MemoryBarrierFlag; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.ALRComputeCapabilities; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; import dev.anvilcraft.lib.v2.rendering.foundation.buffers.GpuBufferConstants; @@ -31,6 +32,7 @@ public class ComputeSupport { public static final ComputeSupport INSTANCE = new ComputeSupport(); + public static final float[] UNSUPPORTED = {}; @Getter private final GpuDevice device = RenderSystem.getDevice(); @@ -90,6 +92,9 @@ public class ComputeSupport { private final BlurParamUbo blurParam = new BlurParamUbo(); public float[] add(float[] input, float f) { + if (!ALRComputeCapabilities.isComputeSupported()) { + return UNSUPPORTED; + } CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder(); ALRCommandEncoderExtension commandEncoderExtension = ALRCommandEncoderExtension.of(commandEncoder); addParam.arraySize = input.length; diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java index fc5318f6..1be49ede 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/screen/GuiTestScreen.java @@ -7,6 +7,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRCommandEncoderExtension; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.ALRComputeCapabilities; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass; import dev.anvilcraft.lib.v2.rendering.foundation.fakeworld.FakeDisplayLevel; import dev.anvilcraft.lib.v2.rendering.gui.GuiRenderExtras; @@ -200,12 +201,11 @@ public void extractRenderState(GuiGraphicsExtractor graphics, int mouseX, int mo true, poseStack ); - graphics.pose().popMatrix(); - } public void dispatchComputeTest(GuiGraphicsExtractor graphics) { + if (!ALRComputeCapabilities.isComputeSupported()) return; ALRCommandEncoderExtension commandEncoder = ALRCommandEncoderExtension.of(RenderSystem.getDevice().createCommandEncoder()); try (ALRComputePass pass = commandEncoder.alrCreateComputePass()) { pass.setPipeline(TestPipelines.EMPTY); From 36d8c578f711b9117f9c740124bd7a36a466fc1a Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Sun, 7 Jun 2026 06:17:30 +0800 Subject: [PATCH 7/9] Add compute pipeline part 4.2 --- .../blaze3d/compute/pipeline/gl/GlComputePassBackend.java | 8 ++++---- .../gui/state/DynamicTextureBlitRenderState.java | 2 +- .../v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java | 2 +- .../anvilcraft/lib/v2/test/client/AnvilLibTestClient.java | 2 -- .../lib/v2/test/client/compute/ComputeSupport.java | 3 +++ module.test/src/main/resources/anvillib_test.mixins.json | 1 + 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java index a102eac1..76c32056 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/gl/GlComputePassBackend.java @@ -14,6 +14,7 @@ import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePassBackend; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePipeline; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.TextureBinding; +import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeProgramInstance; import dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.shader.ALRComputeShaderManager; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -25,7 +26,6 @@ import org.lwjgl.opengl.GL46; public class GlComputePassBackend implements ALRComputePassBackend { - private final GpuDeviceBackend backend; private final ALRGpuDeviceBackendExtension backendExtension; private final ALRCommandEncoderBackendExtension commandEncoderExtension; private final Int2ObjectMap textureBindings = new Int2ObjectOpenHashMap<>(); @@ -40,7 +40,6 @@ public GlComputePassBackend( ALRGpuDeviceBackendExtension backendExtension ) { this.commandEncoderExtension = commandEncoderExtension; - this.backend = (GpuDeviceBackend) backendExtension; this.backendExtension = backendExtension; } @@ -110,8 +109,9 @@ public void close() { } private void setupState() { - int program = ALRComputeShaderManager.INSTANCE.getShader(pipeline).id(); - GL46.glUseProgram(program); + ALRComputeProgramInstance program = ALRComputeShaderManager.INSTANCE.getShader(pipeline); + if (program == null || program == ALRComputeProgramInstance.INVALID) return; + GL46.glUseProgram(program.id()); for (Int2ObjectMap.Entry entry : this.textureBindings.int2ObjectEntrySet()) { this.setupTexture(entry.getIntKey(), entry.getValue()); diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java index da85e046..cc96c8cf 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/gui/state/DynamicTextureBlitRenderState.java @@ -51,8 +51,8 @@ public DynamicTextureBlitRenderState( x1, y1, u0, - u1, v0, + u1, v1, color, scissorArea, diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java index 08cf9f49..6c5c833d 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java @@ -30,7 +30,7 @@ public static class Core implements ALRDebugLabelExtension { @Override public void alrApplyLabel(ALRComputeProgramInstance shaderInstance) { KHRDebug.glObjectLabel( - GL46.GL_SHADER, + GL46.GL_PROGRAM, shaderInstance.id(), StringUtil.truncateStringIfNecessary( shaderInstance.key().location().toString(), diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java index a92896e8..d7fa6a08 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/AnvilLibTestClient.java @@ -9,9 +9,7 @@ import dev.anvilcraft.lib.v2.test.client.compute.ComputeSupport; import dev.anvilcraft.lib.v2.test.client.gui.SdfGraphicsLayer; import dev.anvilcraft.lib.v2.test.client.screen.GuiTestScreen; -import javafx.util.Pair; import net.minecraft.client.Minecraft; -import net.minecraft.commands.Commands; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.EventPriority; import net.neoforged.bus.api.SubscribeEvent; diff --git a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java index 4be25801..47a92e29 100644 --- a/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java +++ b/module.test/src/main/java/dev/anvilcraft/lib/v2/test/client/compute/ComputeSupport.java @@ -144,6 +144,9 @@ public float[] add(float[] input, float f) { ByteBuffer counterData = mappedCounterBuffer.data(); int anInt = counterData.getInt(); + if (anInt != input.length){ + System.out.printf("Compute counter does not match with input size: %d/%d%n", anInt, input.length); + } return result; } diff --git a/module.test/src/main/resources/anvillib_test.mixins.json b/module.test/src/main/resources/anvillib_test.mixins.json index 5305e09b..b2e92d0c 100644 --- a/module.test/src/main/resources/anvillib_test.mixins.json +++ b/module.test/src/main/resources/anvillib_test.mixins.json @@ -8,6 +8,7 @@ "ChestBlockMixin" ], "client": [ + "MinecraftMixin" ], "injectors": { "defaultRequire": 1 From ecb42f9afbf6e0e18060b4d2b95ed06d578c8bab Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Mon, 8 Jun 2026 01:35:47 +0800 Subject: [PATCH 8/9] fix incorrect size of vec3 in std140 and std430 --- .../foundation/buffers/layout/std140/Std140SizeCalculator.java | 2 +- .../foundation/buffers/layout/std140/Std140Writer.java | 2 +- .../foundation/buffers/layout/std430/Std430SizeCalculator.java | 2 +- .../foundation/buffers/layout/std430/Std430Writer.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java index b74d92d7..3a6f946d 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java @@ -38,7 +38,7 @@ public void putIVec2() { public void putVec3() { this.align(16); - this.size += 16; + this.size += 12; } public void putIVec3() { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java index 33b3f473..296f00b4 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java @@ -58,7 +58,7 @@ public void putIVec2(Vector2i vec) { public void putVec3(Vector3f vec) { this.align(16); vec.get(this.buffer); - this.buffer.position(this.buffer.position() + 16); + this.buffer.position(this.buffer.position() + 12); } public void putIVec3(Vector3i vec) { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java index e822ac63..6401bbfd 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java @@ -37,7 +37,7 @@ public void putIVec2() { public void putVec3() { this.align(16); - this.size += 16; + this.size += 12; } public void putIVec3() { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java index 46dd12fd..876f03aa 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java @@ -58,7 +58,7 @@ public void putIVec2(Vector2i vec) { public void putVec3(Vector3f vec) { this.align(16); vec.get(this.buffer); - this.buffer.position(this.buffer.position() + 16); + this.buffer.position(this.buffer.position() + 12); } public void putIVec3(Vector3i vec) { From 386b71be9ab57fe5683c26e05964f9be3929119f Mon Sep 17 00:00:00 2001 From: ZhuRuoLing Date: Mon, 8 Jun 2026 02:08:03 +0800 Subject: [PATCH 9/9] fix incorrect size of ivec3 in std140 and std430 --- .../foundation/buffers/layout/std140/Std140SizeCalculator.java | 2 +- .../foundation/buffers/layout/std140/Std140Writer.java | 2 +- .../foundation/buffers/layout/std430/Std430SizeCalculator.java | 2 +- .../foundation/buffers/layout/std430/Std430Writer.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java index 3a6f946d..2b9360de 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140SizeCalculator.java @@ -43,7 +43,7 @@ public void putVec3() { public void putIVec3() { this.align(16); - this.size += 16; + this.size += 12; } public void putVec4() { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java index 296f00b4..568864bb 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std140/Std140Writer.java @@ -64,7 +64,7 @@ public void putVec3(Vector3f vec) { public void putIVec3(Vector3i vec) { this.align(16); vec.get(this.buffer); - this.buffer.position(this.buffer.position() + 16); + this.buffer.position(this.buffer.position() + 12); } public void putVec4(Vector4f vec) { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java index 6401bbfd..0a165ef3 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430SizeCalculator.java @@ -42,7 +42,7 @@ public void putVec3() { public void putIVec3() { this.align(16); - this.size += 16; + this.size += 12; } public void putVec4() { diff --git a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java index 876f03aa..63ef1369 100644 --- a/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java +++ b/module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/foundation/buffers/layout/std430/Std430Writer.java @@ -64,7 +64,7 @@ public void putVec3(Vector3f vec) { public void putIVec3(Vector3i vec) { this.align(16); vec.get(this.buffer); - this.buffer.position(this.buffer.position() + 16); + this.buffer.position(this.buffer.position() + 12); } public void putVec4(Vector4f vec) {