Skip to content

Commit

Permalink
Multiple misc changes to shader interfaces (#2690)
Browse files Browse the repository at this point in the history
* Multiple misc changes to shader interfaces

* Replace ShaderBindingContext methods with optional and non-optional
  • Loading branch information
IMS212 authored Aug 22, 2024
1 parent 9085a12 commit e1efb0d
Show file tree
Hide file tree
Showing 20 changed files with 235 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ static VertexSerializerRegistry instance() {
}

VertexSerializer get(VertexFormatDescription srcFormat, VertexFormatDescription dstFormat);

void registerSerializer(VertexFormatDescription srcFormat, VertexFormatDescription dstFormat, VertexSerializer serializer);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
*/
public record GlVertexAttributeFormat(int typeId, int size) {
public static final GlVertexAttributeFormat FLOAT = new GlVertexAttributeFormat(GL33C.GL_FLOAT, 4);
public static final GlVertexAttributeFormat INT = new GlVertexAttributeFormat(GL33C.GL_INT, 4);
public static final GlVertexAttributeFormat SHORT = new GlVertexAttributeFormat(GL33C.GL_SHORT, 2);
public static final GlVertexAttributeFormat BYTE = new GlVertexAttributeFormat(GL33C.GL_BYTE, 1);
public static final GlVertexAttributeFormat UNSIGNED_SHORT = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_SHORT, 2);
public static final GlVertexAttributeFormat UNSIGNED_BYTE = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_BYTE, 1);
public static final GlVertexAttributeFormat UNSIGNED_INT = new GlVertexAttributeFormat(GL33C.GL_UNSIGNED_INT, 4);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
package net.caffeinemc.mods.sodium.client.gl.attribute;

import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.caffeinemc.mods.sodium.client.render.vertex.VertexFormatAttribute;

import java.util.EnumMap;
import java.util.Map;

/**
* Provides a generic vertex format which contains the attributes defined by {@param T}. Other code can then retrieve
* Provides a generic vertex format which contains the attributes defined by a {@link VertexFormatAttribute}. Other code can then retrieve
* the attributes and work with encoded data in a generic manner without needing to rely on a specific format.
*
* @param <T> The enumeration over the vertex attributes
*/
public class GlVertexFormat<T extends Enum<T>> {
private final Class<T> attributeEnum;
private final EnumMap<T, GlVertexAttribute> attributesKeyed;
public class GlVertexFormat {
private final Map<VertexFormatAttribute, GlVertexAttribute> attributesKeyed;

private final int stride;
private final GlVertexAttributeBinding[] bindings;

public GlVertexFormat(Class<T> attributeEnum, EnumMap<T, GlVertexAttribute> attributesKeyed, int stride) {
this.attributeEnum = attributeEnum;
public GlVertexFormat(Map<VertexFormatAttribute, GlVertexAttribute> attributesKeyed, GlVertexAttributeBinding[] bindings, int stride) {
this.attributesKeyed = attributesKeyed;
this.bindings = bindings;
this.stride = stride;
}

public static <T extends Enum<T>> Builder<T> builder(Class<T> type, int stride) {
return new Builder<>(type, stride);
public static Builder builder(int stride) {
return new Builder(stride);
}

/**
* Returns the {@link GlVertexAttribute} of this vertex format bound to the type {@param name}.
* @throws NullPointerException If the attribute does not exist in this format
*/
public GlVertexAttribute getAttribute(T name) {
public GlVertexAttribute getAttribute(VertexFormatAttribute name) {
GlVertexAttribute attr = this.attributesKeyed.get(name);

if (attr == null) {
Expand All @@ -47,23 +51,27 @@ public int getStride() {

@Override
public String toString() {
return String.format("GlVertexFormat<%s>{attributes=%d,stride=%d}", this.attributeEnum.getName(),
return String.format("GlVertexFormat{attributes=%d,stride=%d}",
this.attributesKeyed.size(), this.stride);
}

public static class Builder<T extends Enum<T>> {
private final EnumMap<T, GlVertexAttribute> attributes;
private final Class<T> type;
public GlVertexAttributeBinding[] getShaderBindings() {
return bindings;
}

public static class Builder {
private final Map<VertexFormatAttribute, GlVertexAttribute> attributes;
private final Object2IntMap<GlVertexAttribute> bindings;
private final int stride;

public Builder(Class<T> type, int stride) {
this.type = type;
this.attributes = new EnumMap<>(type);
public Builder(int stride) {
this.attributes = new Object2ObjectArrayMap<>();
this.bindings = new Object2IntArrayMap<>();
this.stride = stride;
}

public Builder<T> addElement(T type, int pointer, GlVertexAttributeFormat format, int count, boolean normalized, boolean intType) {
return this.addElement(type, new GlVertexAttribute(format, count, normalized, pointer, this.stride, intType));
public Builder addElement(VertexFormatAttribute attribute, int binding, int pointer) {
return this.addElement(attribute, binding, new GlVertexAttribute(attribute.format(), attribute.count(), attribute.normalized(), pointer, this.stride, attribute.intType()));
}

/**
Expand All @@ -73,7 +81,7 @@ public Builder<T> addElement(T type, int pointer, GlVertexAttributeFormat format
* @param attribute The attribute to bind
* @throws IllegalStateException If an attribute is already bound to the generic type
*/
private Builder<T> addElement(T type, GlVertexAttribute attribute) {
private Builder addElement(VertexFormatAttribute type, int binding, GlVertexAttribute attribute) {
if (attribute.getPointer() >= this.stride) {
throw new IllegalArgumentException("Element starts outside vertex format");
}
Expand All @@ -86,22 +94,20 @@ private Builder<T> addElement(T type, GlVertexAttribute attribute) {
throw new IllegalStateException("Generic attribute " + type.name() + " already defined in vertex format");
}

if (binding != -1) {
this.bindings.put(attribute, binding);
}

return this;
}

/**
* Creates a {@link GlVertexFormat} from the current builder.
*/
public GlVertexFormat<T> build() {
public GlVertexFormat build() {
int size = 0;

for (T key : this.type.getEnumConstants()) {
GlVertexAttribute attribute = this.attributes.get(key);

if (attribute == null) {
throw new NullPointerException("Generic attribute not assigned to enumeration " + key.name());
}

for (GlVertexAttribute attribute : this.attributes.values()) {
size = Math.max(size, attribute.getPointer() + attribute.getSize());
}

Expand All @@ -111,7 +117,11 @@ public GlVertexFormat<T> build() {
throw new IllegalArgumentException("Stride is too small");
}

return new GlVertexFormat<>(this.type, this.attributes, this.stride);
GlVertexAttributeBinding[] bindings = this.bindings.object2IntEntrySet().stream()
.map(entry -> new GlVertexAttributeBinding(entry.getIntValue(), entry.getKey()))
.toArray(GlVertexAttributeBinding[]::new);

return new GlVertexFormat(this.attributes, bindings, this.stride);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/**
* Helper type for tagging the vertex format alongside the raw buffer data.
*/
public record IndexedVertexData(GlVertexFormat<?> vertexFormat,
public record IndexedVertexData(GlVertexFormat vertexFormat,
NativeBuffer vertexBuffer,
NativeBuffer indexBuffer) {
public void delete() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import net.minecraft.resources.ResourceLocation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.lwjgl.opengl.GL20C;
import org.lwjgl.opengl.GL30C;
import org.lwjgl.opengl.GL32C;
Expand Down Expand Up @@ -51,7 +52,7 @@ public void delete() {
}

@Override
public <U extends GlUniform<?>> U bindUniform(String name, IntFunction<U> factory) {
public <U extends GlUniform<?>> @NotNull U bindUniform(String name, IntFunction<U> factory) {
int index = GL20C.glGetUniformLocation(this.handle(), name);

if (index < 0) {
Expand All @@ -62,7 +63,18 @@ public <U extends GlUniform<?>> U bindUniform(String name, IntFunction<U> factor
}

@Override
public GlUniformBlock bindUniformBlock(String name, int bindingPoint) {
public <U extends GlUniform<?>> U bindUniformOptional(String name, IntFunction<U> factory) {
int index = GL20C.glGetUniformLocation(this.handle(), name);

if (index < 0) {
return null;
}

return factory.apply(index);
}

@Override
public @NotNull GlUniformBlock bindUniformBlock(String name, int bindingPoint) {
int index = GL32C.glGetUniformBlockIndex(this.handle(), name);

if (index < 0) {
Expand All @@ -74,6 +86,19 @@ public GlUniformBlock bindUniformBlock(String name, int bindingPoint) {
return new GlUniformBlock(bindingPoint);
}

@Override
public GlUniformBlock bindUniformBlockOptional(String name, int bindingPoint) {
int index = GL32C.glGetUniformBlockIndex(this.handle(), name);

if (index < 0) {
return null;
}

GL32C.glUniformBlockBinding(this.handle(), index, bindingPoint);

return new GlUniformBlock(bindingPoint);
}

public static class Builder {
private final ResourceLocation name;
private final int program;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
package net.caffeinemc.mods.sodium.client.gl.shader;

import org.lwjgl.opengl.GL20C;
import org.lwjgl.opengl.GL32C;
import org.lwjgl.opengl.GL40C;

/**
* An enumeration over the supported OpenGL shader types.
*/
public enum ShaderType {
VERTEX(GL20C.GL_VERTEX_SHADER),
GEOMETRY(GL32C.GL_GEOMETRY_SHADER),
TESS_CONTROL(GL40C.GL_TESS_CONTROL_SHADER),
TESS_EVALUATION(GL40C.GL_TESS_EVALUATION_SHADER),
FRAGMENT(GL20C.GL_FRAGMENT_SHADER);

public final int id;

ShaderType(int id) {
this.id = id;
}

public static ShaderType fromGlShaderType(int id) {
for (ShaderType type : values()) {
if (type.id == id) {
return type;
}
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package net.caffeinemc.mods.sodium.client.gl.tessellation;

import org.lwjgl.opengl.GL20C;
import org.lwjgl.opengl.GL40C;

public enum GlPrimitiveType {
TRIANGLES(GL20C.GL_TRIANGLES);
POINTS(GL20C.GL_POINTS),
LINES(GL20C.GL_LINES),
TRIANGLES(GL20C.GL_TRIANGLES),
PATCHES(GL40C.GL_PATCHES);

private final int id;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ public static OptionPage performance() {
.setControl(TickBoxControl::new)
.setImpact(OptionImpact.LOW)
.setBinding((opts, value) -> opts.performance.useNoErrorGLContext = value, opts -> opts.performance.useNoErrorGLContext)
.setEnabled(supportsNoErrorContext())
.setEnabled(SodiumGameOptionPages::supportsNoErrorContext)
.setFlags(OptionFlag.REQUIRES_GAME_RESTART)
.build())
.build());
Expand Down Expand Up @@ -338,13 +338,15 @@ private static boolean supportsNoErrorContext() {
public static OptionPage advanced() {
List<OptionGroup> groups = new ArrayList<>();

boolean isPersistentMappingSupported = MappedStagingBuffer.isSupported(RenderDevice.INSTANCE);

groups.add(OptionGroup.createBuilder()
.add(OptionImpl.createBuilder(boolean.class, sodiumOpts)
.setName(Component.translatable("sodium.options.use_persistent_mapping.name"))
.setTooltip(Component.translatable("sodium.options.use_persistent_mapping.tooltip"))
.setControl(TickBoxControl::new)
.setImpact(OptionImpact.MEDIUM)
.setEnabled(MappedStagingBuffer.isSupported(RenderDevice.INSTANCE))
.setEnabled(() -> isPersistentMappingSupported)
.setBinding((opts, value) -> opts.advanced.useAdvancedStagingBuffers = value, opts -> opts.advanced.useAdvancedStagingBuffers)
.setFlags(OptionFlag.REQUIRES_RENDERER_RELOAD)
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import java.util.function.Function;

public class OptionImpl<S, T> implements Option<T> {
Expand All @@ -29,7 +30,7 @@ public class OptionImpl<S, T> implements Option<T> {
private T value;
private T modifiedValue;

private final boolean enabled;
private final BooleanSupplier enabled;

private OptionImpl(OptionStorage<S> storage,
Component name,
Expand All @@ -38,7 +39,7 @@ private OptionImpl(OptionStorage<S> storage,
Function<OptionImpl<S, T>, Control<T>> control,
EnumSet<OptionFlag> flags,
OptionImpact impact,
boolean enabled) {
BooleanSupplier enabled) {
this.storage = storage;
this.name = name;
this.tooltip = tooltip;
Expand Down Expand Up @@ -94,7 +95,7 @@ public OptionStorage<?> getStorage() {

@Override
public boolean isAvailable() {
return this.enabled;
return this.enabled.getAsBoolean();
}

@Override
Expand Down Expand Up @@ -125,7 +126,7 @@ public static class Builder<S, T> {
private Function<OptionImpl<S, T>, Control<T>> control;
private OptionImpact impact;
private final EnumSet<OptionFlag> flags = EnumSet.noneOf(OptionFlag.class);
private boolean enabled = true;
private BooleanSupplier enabled = () -> true;

private Builder(OptionStorage<S> storage) {
this.storage = storage;
Expand Down Expand Up @@ -179,7 +180,7 @@ public Builder<S, T> setImpact(OptionImpact impact) {
return this;
}

public Builder<S, T> setEnabled(boolean value) {
public Builder<S, T> setEnabled(BooleanSupplier value) {
this.enabled = value;

return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import net.caffeinemc.mods.sodium.client.render.chunk.shader.ChunkShaderInterface;
import net.caffeinemc.mods.sodium.client.render.chunk.terrain.TerrainRenderPass;
import net.caffeinemc.mods.sodium.client.render.chunk.translucent_sorting.SortBehavior;
import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkMeshAttribute;
import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.ChunkVertexType;
import net.caffeinemc.mods.sodium.client.render.viewport.CameraTransform;
import net.caffeinemc.mods.sodium.client.util.BitwiseMath;
Expand Down Expand Up @@ -316,18 +315,7 @@ private GlTessellation prepareIndexedTessellation(CommandList commandList, Rende

private GlTessellation createRegionTessellation(CommandList commandList, RenderRegion.DeviceResources resources, boolean useSharedIndexBuffer) {
return commandList.createTessellation(GlPrimitiveType.TRIANGLES, new TessellationBinding[] {
TessellationBinding.forVertexBuffer(resources.getGeometryBuffer(), new GlVertexAttributeBinding[] {
new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_POSITION_HI,
this.vertexFormat.getAttribute(ChunkMeshAttribute.POSITION_HI)),
new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_POSITION_LO,
this.vertexFormat.getAttribute(ChunkMeshAttribute.POSITION_LO)),
new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_COLOR,
this.vertexFormat.getAttribute(ChunkMeshAttribute.COLOR)),
new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_TEXTURE,
this.vertexFormat.getAttribute(ChunkMeshAttribute.TEXTURE)),
new GlVertexAttributeBinding(ChunkShaderBindingPoints.ATTRIBUTE_LIGHT_MATERIAL_INDEX,
this.vertexFormat.getAttribute(ChunkMeshAttribute.LIGHT_MATERIAL_INDEX))
}),
TessellationBinding.forVertexBuffer(resources.getGeometryBuffer(), this.vertexFormat.getShaderBindings()),
TessellationBinding.forElementBuffer(useSharedIndexBuffer
? this.sharedIndexBuffer.getBufferObject()
: resources.getIndexBuffer())
Expand Down
Loading

0 comments on commit e1efb0d

Please sign in to comment.