From c7651614a308819a52a1e2747708a99b3f544607 Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 02:09:05 +0000 Subject: [PATCH 01/16] Sync --- src/main/java/rs117/hd/HdPlugin.java | 148 +++++++------- src/main/java/rs117/hd/opengl/GLState.java | 7 + src/main/java/rs117/hd/opengl/GLVao.java | 145 ++++++++++++++ .../java/rs117/hd/opengl/GLVertexLayout.java | 184 ++++++++++++++++++ .../java/rs117/hd/overlays/ShaderOverlay.java | 6 +- .../hd/renderer/legacy/LegacyRenderer.java | 9 +- .../hd/renderer/zone/DynamicModelVAO.java | 71 ++----- .../rs117/hd/renderer/zone/SceneUploader.java | 2 +- .../java/rs117/hd/renderer/zone/Zone.java | 127 +++++------- .../rs117/hd/renderer/zone/ZoneRenderer.java | 31 ++- .../rs117/hd/renderer/zone/ZoneUploadJob.java | 3 +- .../java/rs117/hd/scene/MaterialManager.java | 4 +- .../java/rs117/hd/utils/CommandBuffer.java | 51 ++--- src/main/java/rs117/hd/utils/RenderState.java | 80 +++++--- .../java/rs117/hd/utils/buffer/GLBuffer.java | 3 +- 15 files changed, 577 insertions(+), 294 deletions(-) create mode 100644 src/main/java/rs117/hd/opengl/GLVao.java create mode 100644 src/main/java/rs117/hd/opengl/GLVertexLayout.java diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index 01f211c80d..02572e9a05 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -39,7 +39,6 @@ import java.awt.image.DataBufferInt; import java.io.IOException; import java.nio.ByteBuffer; -import java.nio.FloatBuffer; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.ArrayList; @@ -76,6 +75,7 @@ import org.lwjgl.opengl.*; import org.lwjgl.system.Callback; import org.lwjgl.system.Configuration; +import org.lwjgl.system.MemoryStack; import rs117.hd.config.ColorFilter; import rs117.hd.config.DynamicLights; import rs117.hd.config.SeasonalHemisphere; @@ -83,6 +83,11 @@ import rs117.hd.config.ShadingMode; import rs117.hd.config.ShadowMode; import rs117.hd.config.VanillaShadowMode; +import rs117.hd.opengl.GLVao; +import rs117.hd.opengl.GLVertexLayout; +import rs117.hd.opengl.GLVertexLayout.ArrayField; +import rs117.hd.opengl.GLVertexLayout.ComponentType; +import rs117.hd.opengl.GLVertexLayout.FormatType; import rs117.hd.opengl.shader.ShaderException; import rs117.hd.opengl.shader.ShaderIncludes; import rs117.hd.opengl.shader.TiledLightingShaderProgram; @@ -130,6 +135,7 @@ import rs117.hd.utils.jobs.JobSystem; import static net.runelite.api.Constants.*; +import static org.lwjgl.opengl.GL13C.glActiveTexture; import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPluginConfig.*; import static rs117.hd.utils.MathUtils.*; @@ -160,6 +166,7 @@ public class HdPlugin extends Plugin { public static int MAX_TEXTURE_UNITS; public static int TEXTURE_UNIT_COUNT = 0; + public static final int TEXTURE_UNIT_UNUSED = GL_TEXTURE0 + TEXTURE_UNIT_COUNT++; public static final int TEXTURE_UNIT_UI = GL_TEXTURE0 + TEXTURE_UNIT_COUNT++; public static final int TEXTURE_UNIT_GAME = GL_TEXTURE0 + TEXTURE_UNIT_COUNT++; public static final int TEXTURE_UNIT_SHADOW_MAP = GL_TEXTURE0 + TEXTURE_UNIT_COUNT++; @@ -344,11 +351,13 @@ public class HdPlugin extends Plugin { private static final ResourcePath SHADER_PATH = Props .getFolder("rlhd.shader-path", () -> path(HdPlugin.class)); - public int vaoQuad; - private int vboQuad; + private static final GLVertexLayout FULLSCREEN_VERTEX_LAYOUT = new GLVertexLayout("FULLSCREEN_VERTEX_LAYOUT") + .edit(ArrayField.VERTEX_FIELD_0).enabled().component(ComponentType.RG).format(FormatType.FLOAT).stride(16).offset(0) + .edit(ArrayField.VERTEX_FIELD_1).enabled().component(ComponentType.RG).format(FormatType.FLOAT).stride(16).offset(4) + .finish(); - public int vaoTri; - private int vboTri; + public GLVao quadVao; + public GLVao triVao; @Getter @Nullable @@ -564,7 +573,7 @@ protected void startUp() { INTEL_GPU = glRenderer.contains("Intel"); NVIDIA_GPU = glRenderer.toLowerCase().contains("nvidia"); - SUPPORTS_INDIRECT_DRAW = NVIDIA_GPU && !APPLE || config.forceIndirectDraw(); + SUPPORTS_INDIRECT_DRAW = false; //NVIDIA_GPU && !APPLE || config.forceIndirectDraw(); renderer = config.legacyRenderer() ? injector.getInstance(LegacyRenderer.class) : @@ -927,7 +936,7 @@ private void initializeShaders() throws ShaderException, IOException { var includes = getShaderIncludes(); // Bind a valid VAO, otherwise validation may fail on older Intel-based Macs - glBindVertexArray(vaoTri); + triVao.bind(); renderer.initializeShaders(includes); uiProgram.compile(includes); @@ -1018,76 +1027,45 @@ public void recompilePrograms() { } private void initializeVaos() { + try(MemoryStack stack = MemoryStack.stackPush()) { - // Create quad VAO - vaoQuad = glGenVertexArrays(); - vboQuad = glGenBuffers(); - glBindVertexArray(vaoQuad); - - FloatBuffer vboQuadData = BufferUtils.createFloatBuffer(16) - .put(new float[] { - // x, y, u, v - 1, 1, 1, 1, // top right - -1, 1, 0, 1, // top left - -1, -1, 0, 0, // bottom left - 1, -1, 1, 0 // bottom right - }) - .flip(); - glBindBuffer(GL_ARRAY_BUFFER, vboQuad); - glBufferData(GL_ARRAY_BUFFER, vboQuadData, GL_STATIC_DRAW); - - // position attribute - glVertexAttribPointer(0, 2, GL_FLOAT, false, 4 * Float.BYTES, 0); - glEnableVertexAttribArray(0); - - // texture coord attribute - glVertexAttribPointer(1, 2, GL_FLOAT, false, 4 * Float.BYTES, 2 * Float.BYTES); - glEnableVertexAttribArray(1); - } - - { - // Create tri VAO - vaoTri = glGenVertexArrays(); - vboTri = glGenBuffers(); - glBindVertexArray(vaoTri); - - FloatBuffer vboTriData = BufferUtils.createFloatBuffer(12) - .put(new float[] { - // x, y, u, v - -1, -1, 0, 0, // bottom left - 3, -1, 2, 0, // bottom right (off-screen) - -1, 3, 0, 2 // top left (off-screen) - }) - .flip(); - glBindBuffer(GL_ARRAY_BUFFER, vboTri); - glBufferData(GL_ARRAY_BUFFER, vboTriData, GL_STATIC_DRAW); - - // position attribute - glVertexAttribPointer(0, 2, GL_FLOAT, false, 4 * Float.BYTES, 0); - glEnableVertexAttribArray(0); - - // texture coord attribute - glVertexAttribPointer(1, 2, GL_FLOAT, false, 4 * Float.BYTES, 2 * Float.BYTES); - glEnableVertexAttribArray(1); + quadVao = new GLVao("FullscreenQuad::VAO", FULLSCREEN_VERTEX_LAYOUT); + quadVao.setBufferRange( + new GLBuffer("FullscreenQuad::VBO", GL_ARRAY_BUFFER, GL_STATIC_DRAW) + .upload( + stack.mallocFloat(16) + .put(new float[] { + // x, y, u, v + 1, 1, 1, 1, // top right + -1, 1, 0, 1, // top left + -1, -1, 0, 0, // bottom left + 1, -1, 1, 0 // bottom right + }).flip() + ), true, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_1); + + triVao = new GLVao("FullscreenQuad::VAO", FULLSCREEN_VERTEX_LAYOUT); + triVao.setBufferRange( + new GLBuffer("FullscreenQuad::VBO", GL_ARRAY_BUFFER, GL_STATIC_DRAW) + .upload( + stack.mallocFloat(16) + .put(new float[] { + // x, y, u, v + -1, -1, 0, 0, // bottom left + 3, -1, 2, 0, // bottom right (off-screen) + -1, 3, 0, 2 // top left (off-screen) + }).flip() + ), true, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_1); } } private void destroyVaos() { - if (vboQuad != 0) - glDeleteBuffers(vboQuad); - vboQuad = 0; - - if (vaoQuad != 0) - glDeleteVertexArrays(vaoQuad); - vaoQuad = 0; - - if (vboTri != 0) - glDeleteBuffers(vboTri); - vboTri = 0; + if(quadVao != null) + quadVao.destroy(); + quadVao = null; - if (vaoTri != 0) - glDeleteVertexArrays(vaoTri); - vaoTri = 0; + if(triVao != null) + triVao.destroy(); + triVao = null; } private void initializeUbos() { @@ -1134,12 +1112,12 @@ private void initializeUiTexture() { } texUi = glGenTextures(); - glActiveTexture(TEXTURE_UNIT_UI); - glBindTexture(GL_TEXTURE_2D, texUi); + bindTextureWithUnit(GL_TEXTURE_2D, TEXTURE_UNIT_UI, texUi); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); checkGLErrors(); } @@ -1173,8 +1151,7 @@ public void updateTiledLightingFbo() { fboTiledLighting = glGenFramebuffers(); texTiledLighting = glGenTextures(); - glActiveTexture(TEXTURE_UNIT_TILED_LIGHTING_MAP); - glBindTexture(GL_TEXTURE_2D_ARRAY, texTiledLighting); + bindTextureWithUnit(GL_TEXTURE_2D_ARRAY, TEXTURE_UNIT_TILED_LIGHTING_MAP, texTiledLighting); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -1200,6 +1177,7 @@ public void updateTiledLightingFbo() { ARBShaderImageLoadStore.glBindImageTexture( IMAGE_UNIT_TILED_LIGHTING, texTiledLighting, 0, true, 0, GL_WRITE_ONLY, GL_RGBA16UI); + glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, awtContext.getFramebuffer(false)); checkGLErrors(); @@ -1367,8 +1345,7 @@ private void initializeShadowMapFbo() { // Create texture texShadowMap = glGenTextures(); - glActiveTexture(TEXTURE_UNIT_SHADOW_MAP); - glBindTexture(GL_TEXTURE_2D, texShadowMap); + bindTextureWithUnit(GL_TEXTURE_2D, TEXTURE_UNIT_SHADOW_MAP, texShadowMap); shadowMapResolution = config.shadowResolution().getValue(); int maxResolution = glGetInteger(GL_MAX_TEXTURE_SIZE); @@ -1395,6 +1372,7 @@ private void initializeShadowMapFbo() { float[] color = { 1, 1, 1, 1 }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); + glBindTexture(GL_TEXTURE_2D, 0); // Bind texture glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texShadowMap, 0); @@ -1408,13 +1386,13 @@ private void initializeShadowMapFbo() { private void initializeDummyShadowMap() { // Create dummy texture texShadowMap = glGenTextures(); - glActiveTexture(TEXTURE_UNIT_SHADOW_MAP); - glBindTexture(GL_TEXTURE_2D, texShadowMap); + bindTextureWithUnit(GL_TEXTURE_2D, TEXTURE_UNIT_SHADOW_MAP, texShadowMap); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glBindTexture(GL_TEXTURE_2D, 0); } private void destroyShadowMapFbo() { @@ -1447,7 +1425,6 @@ public void prepareInterfaceTexture() { if (resize) { uiResolution = resolution; - glActiveTexture(TEXTURE_UNIT_UI); glBindTexture(GL_TEXTURE_2D, texUi); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, uiResolution[0], uiResolution[1], 0, GL_BGRA, GL_UNSIGNED_BYTE, 0); } @@ -1520,7 +1497,6 @@ public void drawUi(int overlayColor) { // See https://www.khronos.org/opengl/wiki/Sampler_Object for details. // GL_NEAREST makes sampling for bicubic/xBR simpler, so it should be used whenever linear/pixel isn't final int function = config.uiScalingMode().glSamplingFunction; - glActiveTexture(TEXTURE_UNIT_UI); glBindTexture(GL_TEXTURE_2D, texUi); if (uiCopyJob != null) { @@ -1544,8 +1520,10 @@ public void drawUi(int overlayColor) { glEnable(GL_BLEND); glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - glBindVertexArray(vaoTri); + + triVao.bind(); glDrawArrays(GL_TRIANGLES, 0, 3); + triVao.unbind(); shadowMapOverlay.render(); gammaCalibrationOverlay.render(); @@ -2000,6 +1978,12 @@ public void onFocusChanged(FocusChanged event) { isClientInFocus = event.isFocused(); } + public static void bindTextureWithUnit(int target, int unit, int textureId) { + glActiveTexture(unit); + glBindTexture(target, textureId); + glActiveTexture(TEXTURE_UNIT_UNUSED); + } + @SuppressWarnings("StatementWithEmptyBody") public static void clearGLErrors() { // @formatter:off diff --git a/src/main/java/rs117/hd/opengl/GLState.java b/src/main/java/rs117/hd/opengl/GLState.java index 5775c232e0..09d392b810 100644 --- a/src/main/java/rs117/hd/opengl/GLState.java +++ b/src/main/java/rs117/hd/opengl/GLState.java @@ -21,7 +21,14 @@ public void apply() { } } + public void setDefault() { + if (hasApplied) + applyDefault(); + } + + abstract void internalApply(); + protected abstract void applyDefault(); public abstract static class Bool extends GLState { private boolean value; diff --git a/src/main/java/rs117/hd/opengl/GLVao.java b/src/main/java/rs117/hd/opengl/GLVao.java new file mode 100644 index 0000000000..c40988b917 --- /dev/null +++ b/src/main/java/rs117/hd/opengl/GLVao.java @@ -0,0 +1,145 @@ +package rs117.hd.opengl; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import rs117.hd.utils.buffer.GLBuffer; + +import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; +import static org.lwjgl.opengl.GL15.glBindBuffer; +import static org.lwjgl.opengl.GL15C.GL_ELEMENT_ARRAY_BUFFER; +import static org.lwjgl.opengl.GL20.glVertexAttribPointer; +import static org.lwjgl.opengl.GL20C.glDisableVertexAttribArray; +import static org.lwjgl.opengl.GL30C.glBindVertexArray; +import static org.lwjgl.opengl.GL30C.glGenVertexArrays; +import static org.lwjgl.opengl.GL30C.glVertexAttribIPointer; +import static org.lwjgl.opengl.GL33C.*; +import static rs117.hd.HdPlugin.checkGLErrors; + +@RequiredArgsConstructor +@Slf4j +public class GLVao { + private final String name; + private final GLVertexLayout layout; + private final GLBuffer[] buffers = new GLBuffer[GLVertexLayout.MAX_ATTRIBUTES]; + private final boolean[] ownership = new boolean[GLVertexLayout.MAX_ATTRIBUTES]; + + private int glVAO; + private int layoutVersion; + + public void setBuffer(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField field) { + buffers[field.ordinal()] = buffer; + ownership[field.ordinal()] = takeOwnership; + layoutVersion = -1; + } + + public void setBufferRange(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField start, GLVertexLayout.ArrayField end) { + for(int i = start.ordinal(); i <= end.ordinal(); i++) { + buffers[i] = buffer; + ownership[i] = takeOwnership; + } + layoutVersion = -1; + } + + public void setBuffers(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField... fields) { + for(int i = 0; i < fields.length; i++) { + buffers[fields[i].ordinal()] = buffer; + ownership[fields[i].ordinal()] = takeOwnership; + } + layoutVersion = -1; + } + + public void associateBuffer(GLBuffer buffer, GLVertexLayout.ArrayField field) { setBuffer(buffer, false, field); } + + public void associateBuffers(GLBuffer buffer, GLVertexLayout.ArrayField... fields) { setBuffers(buffer, false, fields); } + + public void associateBufferRange(GLBuffer buffer, GLVertexLayout.ArrayField start, GLVertexLayout.ArrayField end) { setBufferRange(buffer, false, start, end); } + + public void remove(GLBuffer buffer) { + boolean found = false; + for(int i = 0; i < buffers.length; i++) { + GLBuffer b = buffers[i]; + if(b == buffer) { + buffers[i] = null; + ownership[i] = false; + found = true; + } + } + if(found) + layoutVersion = -1; + } + + public void bind() { + if(glVAO == 0) + glVAO = glGenVertexArrays(); + + glBindVertexArray(glVAO); + + if(layoutVersion != layout.getVersion()) { + final GLBuffer eboBuffer = buffers[GLVertexLayout.ArrayField.ELEMENT_BUFFER.ordinal()]; + if(eboBuffer != null) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboBuffer.id); + + GLVertexLayout.Attribute[] attributes = layout.getAttributes(); + for(int i = 0; i < attributes.length; i++) { + final GLVertexLayout.Attribute attrib = attributes[i]; + if(!attrib.isEnabled) { + glDisableVertexAttribArray(i); + continue; + } + + final GLBuffer arrayBuffer = buffers[i + 1]; + if(arrayBuffer == null) { + log.warn( + "ArrayField: {} is enabled but no buffer is associated, expect erroneous behaviour", + GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] + ); + } else { + glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer.id); + } + + glEnableVertexAttribArray(i); + + if(attrib.divisor > 0) + glVertexAttribDivisor(i, attrib.divisor); + + if(attrib.isInteger) { + assert attrib.format.ordinal() >= GLVertexLayout.FormatType.INT.ordinal(); + glVertexAttribIPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.stride, attrib.offset); + } else { + glVertexAttribPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.isNormalized, attrib.stride, attrib.offset); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + // Unbind VAO, so its safe to unbind the Array & Element buffers + glBindVertexArray(0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBindVertexArray(glVAO); + + checkGLErrors(() -> "Building VAO: " + name + " with layout: " + layout); + layoutVersion = layout.getVersion(); + } + } + + public void unbind() { + // TODO: Verify that we've bound & unbound in the correct order + glBindVertexArray(0); + } + + public void destroy() { + if(glVAO != 0) { + glDeleteVertexArrays(glVAO); + glVAO = 0; + } + + for(int i = 0; i < buffers.length; i++) { + if(buffers[i] == null) + continue; + + if(ownership[i]) + buffers[i].destroy(); + buffers[i] = null; + } + } +} diff --git a/src/main/java/rs117/hd/opengl/GLVertexLayout.java b/src/main/java/rs117/hd/opengl/GLVertexLayout.java new file mode 100644 index 0000000000..01ac3e36f7 --- /dev/null +++ b/src/main/java/rs117/hd/opengl/GLVertexLayout.java @@ -0,0 +1,184 @@ +package rs117.hd.opengl; + +import java.util.Arrays; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import static org.lwjgl.opengl.GL11.GL_BYTE; +import static org.lwjgl.opengl.GL11.GL_DOUBLE; +import static org.lwjgl.opengl.GL11.GL_FLOAT; +import static org.lwjgl.opengl.GL11.GL_INT; +import static org.lwjgl.opengl.GL11.GL_SHORT; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT; +import static org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT; +import static org.lwjgl.opengl.GL30.GL_HALF_FLOAT; + +@Slf4j +public class GLVertexLayout { + public static final int MAX_ATTRIBUTES = 12; + public static final String[] ARRAY_FIELD_NAMES = Arrays.stream(ArrayField.values()).map(ArrayField::name).toArray(String[]::new); + + @Getter + private final String name; + @Getter + private final Attribute[] attributes = new Attribute[MAX_ATTRIBUTES]; + @Getter + private int version; + private int editIdx; + + public GLVertexLayout(String name) { + this.name = name; + for(int i = 0; i < MAX_ATTRIBUTES; i++) + attributes[i] = new Attribute(); + } + + public GLVertexLayout edit(ArrayField field) { + assert field != ArrayField.ELEMENT_BUFFER : "Element buffer cannot be edited"; + editIdx = field.field; + return this; + } + + public GLVertexLayout enabled() { + attributes[editIdx].isEnabled = true; + return this; + } + + public GLVertexLayout disabled() { + attributes[editIdx].isEnabled = false; + return this; + } + + public GLVertexLayout normalized(boolean isNormalized) { + attributes[editIdx].isNormalized = isNormalized; + return this; + } + + public GLVertexLayout asFloat() { + attributes[editIdx].isInteger = false; + return this; + } + + public GLVertexLayout asInteger() { + attributes[editIdx].isInteger = true; + return this; + } + + public GLVertexLayout component(ComponentType component) { + attributes[editIdx].component = component; + return this; + } + + public GLVertexLayout format(FormatType format) { + attributes[editIdx].format = format; + return this; + } + + public GLVertexLayout offset(long offset) { + attributes[editIdx].offset = offset; + return this; + } + + public GLVertexLayout stride(int stride) { + attributes[editIdx].stride = stride; + return this; + } + + public GLVertexLayout divisor(int divisor) { + attributes[editIdx].divisor = divisor; + return this; + } + + public GLVertexLayout finish() { + editIdx = -1; + version++; + log.debug("{}", this); + return this; + } + + public String toString() { + StringBuilder str = new StringBuilder(); + str.append("\nGLVertexLayout - ").append(name).append(" - Version: ").append(version).append("\n"); + for(int i = 0; i < MAX_ATTRIBUTES; i++) { + Attribute attr = attributes[i]; + str.append(" * ARRAY_FIELD_").append(i).append(": "); + if(attr.isEnabled) { + str.append("ENABLED, isInteger: ") + .append(attr.isInteger) + .append(", isNormalized: ") + .append(attr.isNormalized) + .append(", component: ") + .append(attr.component) + .append(", format: ") + .append(attr.format) + .append(", stride: ") + .append(attr.stride) + .append(", divisor: ") + .append(attr.divisor) + .append(", offset: ") + .append(attr.offset) + .append("\n"); + } else { + str.append("DISABLED\n"); + } + } + return str.toString(); + } + + @RequiredArgsConstructor + public enum ArrayField { + ELEMENT_BUFFER(-1), + VERTEX_FIELD_0(0), + VERTEX_FIELD_1(1), + VERTEX_FIELD_2(2), + VERTEX_FIELD_3(3), + VERTEX_FIELD_4(4), + VERTEX_FIELD_5(5), + VERTEX_FIELD_6(6), + VERTEX_FIELD_7(7), + VERTEX_FIELD_8(8), + VERTEX_FIELD_9(9), + VERTEX_FIELD_10(10), + VERTEX_FIELD_11(11); + + public final int field; + } + + @RequiredArgsConstructor + public enum ComponentType { + R(1), + RG(2), + RGB(3), + RGBA(4); + + public final int size; + } + + @RequiredArgsConstructor + public enum FormatType { + FLOAT(GL_FLOAT), + DOUBLE(GL_DOUBLE), + HALF_FLOAT(GL_HALF_FLOAT), + INT(GL_INT), + SHORT(GL_SHORT), + UNSIGNED_INT(GL_UNSIGNED_INT), + UNSIGNED_SHORT(GL_UNSIGNED_SHORT), + BYTE(GL_BYTE), + UNSIGNED_BYTE(GL_UNSIGNED_BYTE),; + + public final int glFormatType; + } + + public static final class Attribute { + public ComponentType component; + public FormatType format; + public int stride; + public int divisor; + public long offset; + + public boolean isEnabled; + public boolean isInteger; // TODO: Turn into Flags + public boolean isNormalized; + } +} diff --git a/src/main/java/rs117/hd/overlays/ShaderOverlay.java b/src/main/java/rs117/hd/overlays/ShaderOverlay.java index f01799b15b..54b4676070 100644 --- a/src/main/java/rs117/hd/overlays/ShaderOverlay.java +++ b/src/main/java/rs117/hd/overlays/ShaderOverlay.java @@ -411,11 +411,13 @@ protected void renderShader() { glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); if (fullscreen) { - glBindVertexArray(plugin.vaoTri); + plugin.triVao.bind(); glDrawArrays(GL_TRIANGLES, 0, 3); + plugin.triVao.unbind(); } else { - glBindVertexArray(plugin.vaoQuad); + plugin.quadVao.bind(); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + plugin.quadVao.unbind(); } } diff --git a/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java b/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java index 32394d9568..50411b18ad 100644 --- a/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java +++ b/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java @@ -67,6 +67,7 @@ import static rs117.hd.HdPlugin.NEAR_PLANE; import static rs117.hd.HdPlugin.ORTHOGRAPHIC_ZOOM; import static rs117.hd.HdPlugin.TEXTURE_UNIT_TILE_HEIGHT_MAP; +import static rs117.hd.HdPlugin.bindTextureWithUnit; import static rs117.hd.HdPlugin.checkGLErrors; import static rs117.hd.HdPluginConfig.*; import static rs117.hd.utils.MathUtils.*; @@ -494,8 +495,7 @@ public void initializeTileHeightMap(Scene scene) { tileBuffer.flip(); texTileHeightMap = glGenTextures(); - glActiveTexture(TEXTURE_UNIT_TILE_HEIGHT_MAP); - glBindTexture(GL_TEXTURE_3D, texTileHeightMap); + bindTextureWithUnit(GL_TEXTURE_3D, TEXTURE_UNIT_TILE_HEIGHT_MAP, texTileHeightMap); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -505,6 +505,7 @@ public void initializeTileHeightMap(Scene scene) { Constants.EXTENDED_SCENE_SIZE, Constants.EXTENDED_SCENE_SIZE, Constants.MAX_Z, 0, GL_RED_INTEGER, GL_SHORT, tileBuffer ); + glBindTexture(GL_TEXTURE_3D, 0); } public void destroyTileHeightMap() { @@ -752,7 +753,7 @@ public void drawScene(double cameraX, double cameraY, double cameraZ, double cam glViewport(0, 0, plugin.tiledLightingResolution[0], plugin.tiledLightingResolution[1]); glBindFramebuffer(GL_FRAMEBUFFER, plugin.fboTiledLighting); - glBindVertexArray(plugin.vaoTri); + plugin.triVao.bind(); if (plugin.tiledLightingImageStoreProgram.isValid()) { plugin.tiledLightingImageStoreProgram.use(); @@ -768,6 +769,8 @@ public void drawScene(double cameraX, double cameraY, double cameraZ, double cam } } + plugin.triVao.unbind(); + frameTimer.end(Timer.RENDER_TILED_LIGHTING); frameTimer.end(Timer.DRAW_TILED_LIGHTING); } diff --git a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java index 1b243e66c7..58ac88e6b1 100644 --- a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java +++ b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java @@ -6,6 +6,11 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.Nonnull; import lombok.extern.slf4j.Slf4j; +import rs117.hd.opengl.GLVao; +import rs117.hd.opengl.GLVertexLayout; +import rs117.hd.opengl.GLVertexLayout.ArrayField; +import rs117.hd.opengl.GLVertexLayout.ComponentType; +import rs117.hd.opengl.GLVertexLayout.FormatType; import rs117.hd.utils.CommandBuffer; import rs117.hd.utils.buffer.GLBuffer; import rs117.hd.utils.buffer.GLMappedBufferIntWriter; @@ -14,7 +19,6 @@ import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPlugin.GL_CAPS; -import static rs117.hd.HdPlugin.NVIDIA_GPU; import static rs117.hd.HdPlugin.SUPPORTS_INDIRECT_DRAW; import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_TEXTURED_FACES; import static rs117.hd.utils.MathUtils.*; @@ -38,7 +42,18 @@ class DynamicModelVAO { // dummy sceneOffset ivec2 for macOS workaround static final int METADATA_SIZE = 12; - int vao; + public static final GLVertexLayout DYNAMIC_MODEL_VERTEX_LAYOUT = new GLVertexLayout("DYNAMIC_MODEL_VERTEX_LAYOUT") + // Mesh Data + .edit(ArrayField.VERTEX_FIELD_0).enabled().component(ComponentType.RGB).format(FormatType.FLOAT).stride(VERT_SIZE).offset(0) + .edit(ArrayField.VERTEX_FIELD_1).enabled().component(ComponentType.RGB).format(FormatType.HALF_FLOAT).stride(VERT_SIZE).offset(12) + .edit(ArrayField.VERTEX_FIELD_2).enabled().component(ComponentType.RGB).format(FormatType.SHORT).stride(VERT_SIZE).offset(18) + .edit(ArrayField.VERTEX_FIELD_3).enabled().asInteger().component(ComponentType.R).format(FormatType.INT).stride(VERT_SIZE).offset(24) + // Meta Data + .edit(ArrayField.VERTEX_FIELD_6).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(0) + .edit(ArrayField.VERTEX_FIELD_7).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(4) + .finish(); + + GLVao vao = new GLVao("DynamicModel::VAO", DYNAMIC_MODEL_VERTEX_LAYOUT); boolean used; private final GLBuffer vboRender; @@ -86,55 +101,16 @@ class DynamicModelVAO { public boolean hasStagingBuffer() { return vboRender != vboStaging; } void initialize() { - vao = glGenVertexArrays(); tbo.initialize(INITIAL_SIZE); vboRender.initialize(INITIAL_SIZE); if (vboRender != vboStaging) { vboStaging.initialize(INITIAL_SIZE); } - - bindRenderVAO(); + vao.associateBufferRange(vboRender, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_3); } public void bindMetadataVAO(@Nonnull GLBuffer vboMetadata) { - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, vboMetadata.id); - - // WorldView index (not ID) - glEnableVertexAttribArray(6); - glVertexAttribDivisor(6, 1); - glVertexAttribIPointer(6, 1, GL_INT, METADATA_SIZE, 0); - - if (!NVIDIA_GPU) { - // Workaround for incorrect implementations of disabled vertex attribs, particularly on macOS - glEnableVertexAttribArray(7); - glVertexAttribDivisor(7, 1); - glVertexAttribIPointer(7, 2, GL_INT, METADATA_SIZE, 4); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); - } - - void bindRenderVAO() { - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, vboRender.id); - - // Position - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, false, VERT_SIZE, 0); - - // UVs - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_HALF_FLOAT, false, VERT_SIZE, 12); - - // Normals - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_SHORT, false, VERT_SIZE, 18); - - // TextureFaceIdx - glEnableVertexAttribArray(3); - glVertexAttribIPointer(3, 1, GL_INT, VERT_SIZE, 24); + vao.associateBufferRange(vboMetadata, ArrayField.VERTEX_FIELD_6, ArrayField.VERTEX_FIELD_7); } void map() { @@ -145,7 +121,6 @@ void map() { } synchronized void unmap(boolean coalesce) { - final int renderVBOId = vboRender.id; long vboWrittenBytes = vboWriter.flush(); tboWriter.flush(); @@ -178,16 +153,12 @@ synchronized void unmap(boolean coalesce) { } } } - - if (renderVBOId != vboRender.id) - bindRenderVAO(); } void destroy() { vboStaging.destroy(); tbo.destroy(); - glDeleteVertexArrays(vao); - vao = 0; + vao.destroy(); } synchronized View beginDraw(int faceCount) { @@ -269,7 +240,7 @@ void reset() { public final class View { public ReservedView vbo; public ReservedView tbo; - public int vao; + public GLVao vao; public int tboTexId; private int drawIdx; diff --git a/src/main/java/rs117/hd/renderer/zone/SceneUploader.java b/src/main/java/rs117/hd/renderer/zone/SceneUploader.java index d0b06b884d..7b6e389913 100644 --- a/src/main/java/rs117/hd/renderer/zone/SceneUploader.java +++ b/src/main/java/rs117/hd/renderer/zone/SceneUploader.java @@ -768,7 +768,7 @@ private void uploadZoneRenderable( zone.addAlphaModel( plugin, materialManager, - zone.glVaoA, + zone.alphaVao, zone.tboF.getTexId(), model, modelOverride, alphaStart, alphaEnd, x - basex, y, z - basez, diff --git a/src/main/java/rs117/hd/renderer/zone/Zone.java b/src/main/java/rs117/hd/renderer/zone/Zone.java index 24dc3abba1..cba9aa95ed 100644 --- a/src/main/java/rs117/hd/renderer/zone/Zone.java +++ b/src/main/java/rs117/hd/renderer/zone/Zone.java @@ -17,6 +17,10 @@ import net.runelite.api.*; import org.lwjgl.system.MemoryStack; import rs117.hd.HdPlugin; +import rs117.hd.opengl.GLVao; +import rs117.hd.opengl.GLVertexLayout; +import rs117.hd.opengl.GLVertexLayout.ArrayField; +import rs117.hd.opengl.GLVertexLayout.FormatType; import rs117.hd.scene.MaterialManager; import rs117.hd.scene.SceneContext; import rs117.hd.scene.materials.Material; @@ -31,8 +35,9 @@ import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPlugin.GL_CAPS; import static rs117.hd.HdPlugin.SUPPORTS_INDIRECT_DRAW; -import static rs117.hd.HdPlugin.checkGLErrors; +import static rs117.hd.opengl.GLVertexLayout.ComponentType; import static rs117.hd.renderer.zone.ZoneRenderer.TEXTURE_UNIT_TEXTURED_FACES; +import static rs117.hd.renderer.zone.ZoneRenderer.eboAlpha; import static rs117.hd.utils.MathUtils.*; @Slf4j @@ -57,16 +62,27 @@ public class Zone { // sceneOffset int vec2(x, y) public static final int METADATA_SIZE = 12; + public static final GLVertexLayout ZONE_VERTEX_LAYOUT = new GLVertexLayout("ZONE_VERTEX_LAYOUT") + // Mesh Data + .edit(ArrayField.VERTEX_FIELD_0).enabled().component(ComponentType.RGB).format(FormatType.SHORT).stride(VERT_SIZE).offset(0) + .edit(ArrayField.VERTEX_FIELD_1).enabled().component(ComponentType.RGB).format(FormatType.HALF_FLOAT).stride(VERT_SIZE).offset(6) + .edit(ArrayField.VERTEX_FIELD_2).enabled().component(ComponentType.RGB).format(FormatType.SHORT).stride(VERT_SIZE).offset(12) + .edit(ArrayField.VERTEX_FIELD_3).enabled().asInteger().component(ComponentType.R).format(FormatType.INT).stride(VERT_SIZE).offset(20) + // Meta Data + .edit(ArrayField.VERTEX_FIELD_6).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(0) + .edit(ArrayField.VERTEX_FIELD_7).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(4) + .finish(); + public static final int LEVEL_WATER_SURFACE = 4; public static final BlockingDeque VBO_PENDING_DELETION = new LinkedBlockingDeque<>(); - public static final BlockingDeque VAO_PENDING_DELETION = new LinkedBlockingDeque<>(); + public static final BlockingDeque VAO_PENDING_DELETION = new LinkedBlockingDeque<>(); - public int glVao; + public GLVao opaqueVao; int bufLen; int dist; - public int glVaoA; + public GLVao alphaVao; public int bufLenA; public int sortedFacesLen; @@ -99,25 +115,25 @@ public class Zone { final List playerModels = new ArrayList<>(0); final ConcurrentLinkedQueue pendingModelJobs = new ConcurrentLinkedQueue<>(); - public void initialize(GLBuffer o, GLBuffer a, GLTextureBuffer f, int eboShared) { - assert glVao == 0; - assert glVaoA == 0; + public void initialize(GLBuffer o, GLBuffer a, GLTextureBuffer f) { if (o == null && a == null || f == null) return; vboM = new GLBuffer("ZoneMetadata", GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, 0); vboM.initialize(METADATA_SIZE); - if (o != null) { - vboO = o; - glVao = glGenVertexArrays(); - setupVao(glVao, o.id, vboM.id, eboShared); + if ((vboO = o) != null) { + opaqueVao = new GLVao("Zone::Opaque::VAO", ZONE_VERTEX_LAYOUT); + opaqueVao.associateBufferRange(vboO, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_3); + opaqueVao.associateBufferRange(vboM, ArrayField.VERTEX_FIELD_6, ArrayField.VERTEX_FIELD_7); + opaqueVao.associateBuffer(eboAlpha, ArrayField.ELEMENT_BUFFER); } - if (a != null) { - vboA = a; - glVaoA = glGenVertexArrays(); - setupVao(glVaoA, a.id, vboM.id, eboShared); + if ((vboA = a) != null) { + alphaVao = new GLVao("Zone::Opaque::VAO", ZONE_VERTEX_LAYOUT); + alphaVao.associateBufferRange(vboA, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_3); + alphaVao.associateBufferRange(vboM, ArrayField.VERTEX_FIELD_6, ArrayField.VERTEX_FIELD_7); + alphaVao.associateBuffer(eboAlpha, ArrayField.ELEMENT_BUFFER); } tboF = f; @@ -154,14 +170,14 @@ public void free() { tboF = null; } - if (glVao != 0) { - glDeleteVertexArrays(glVao); - glVao = 0; + if(opaqueVao != null) { + opaqueVao.destroy(); + opaqueVao = null; } - if (glVaoA != 0) { - glDeleteVertexArrays(glVaoA); - glVaoA = 0; + if(alphaVao != null) { + alphaVao.destroy(); + alphaVao = null; } if (uploadJob != null) { @@ -202,9 +218,9 @@ public static void processPendingDeletions() { leakCount++; } - Integer vao; + GLVao vao; while ((vao = VAO_PENDING_DELETION.poll()) != null) { - glDeleteVertexArrays(vao); + vao.destroy(); leakCount++; } @@ -232,14 +248,14 @@ protected void finalize() { vboM = null; } - if (glVao != 0) { - VAO_PENDING_DELETION.add(glVao); - glVao = 0; + if (opaqueVao != null) { + VAO_PENDING_DELETION.add(opaqueVao); + opaqueVao = null; } - if (glVaoA != 0) { - VAO_PENDING_DELETION.add(glVaoA); - glVaoA = 0; + if (alphaVao != null) { + VAO_PENDING_DELETION.add(alphaVao); + alphaVao = null; } } @@ -262,47 +278,6 @@ public void unmap() { } } - private void setupVao(int vao, int buffer, int metadata, int ebo) { - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, buffer); - - // The element buffer is part of VAO state - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); - - // Position - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_SHORT, false, VERT_SIZE, 0); - - // UVs - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_HALF_FLOAT, false, VERT_SIZE, 6); - - // Normals - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_SHORT, false, VERT_SIZE, 12); - - // TextureFaceIdx - glEnableVertexAttribArray(3); - glVertexAttribIPointer(3, 1, GL_INT, VERT_SIZE, 20); - - glBindBuffer(GL_ARRAY_BUFFER, metadata); - - // WorldView index (not ID) - glEnableVertexAttribArray(6); - glVertexAttribDivisor(6, 1); - glVertexAttribIPointer(6, 1, GL_INT, METADATA_SIZE, 0); - - // Scene offset - glEnableVertexAttribArray(7); - glVertexAttribDivisor(7, 1); - glVertexAttribIPointer(7, 2, GL_INT, METADATA_SIZE, 4); - - checkGLErrors(); - - glBindVertexArray(0); - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - public void setMetadata(WorldViewContext viewContext, SceneContext sceneContext, int mx, int mz) { if (vboM == null) return; @@ -407,7 +382,7 @@ void renderOpaque(CommandBuffer cmd, WorldViewContext ctx, boolean roofShadows) return; lastDrawMode = STATIC_UNSORTED; - lastVao = glVao; + lastVao = opaqueVao; lastTboF = tboF.getTexId(); flush(cmd); } @@ -421,7 +396,7 @@ void renderOpaqueLevel(CommandBuffer cmd, int level) { return; lastDrawMode = STATIC_UNSORTED; - lastVao = glVao; + lastVao = opaqueVao; lastTboF = tboF.getTexId(); flush(cmd); } @@ -446,7 +421,7 @@ public static class AlphaModel { int startpos, endpos; short x, y, z; // local position short rid; - int vao; + GLVao vao; int tboF; byte level; byte lx, lz, ux, uz; // lower/upper zone coords @@ -485,7 +460,7 @@ boolean isTemp() { void addAlphaModel( HdPlugin plugin, MaterialManager materialManager, - int vao, + GLVao vao, int tboF, Model model, ModelOverride modelOverride, @@ -717,7 +692,7 @@ private void cleanAlphaModels(List alphaModels) { private static int alphaFaceCount; private static int lastDrawMode; - private static int lastVao; + private static GLVao lastVao; private static int lastTboF; private static int lastzx, lastzz; @@ -875,7 +850,7 @@ void renderAlpha( if (m.sortedFaces == null || m.sortedFacesLen <= 0 || !ZoneRenderer.eboAlphaMapped.isMapped()) continue; - if ((long) (ZoneRenderer.eboAlphaOffset + m.sortedFacesLen) * Integer.BYTES < ZoneRenderer.eboAlpha.size) { + if ((long) (ZoneRenderer.eboAlphaOffset + m.sortedFacesLen) * Integer.BYTES < eboAlpha.size) { lastDrawMode = STATIC; m.eboOffset = ZoneRenderer.eboAlphaOffset - ZoneRenderer.eboAlphaPrevOffset; alphaFaceCount += m.sortedFacesLen / 3; diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java index d9efbc7fd2..6cc6554267 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java @@ -662,7 +662,7 @@ private void tiledLightingPass() { renderState.framebuffer.set(GL_FRAMEBUFFER, plugin.fboTiledLighting); renderState.viewport.set(0, 0, plugin.tiledLightingResolution[0], plugin.tiledLightingResolution[1]); - renderState.vao.set(plugin.vaoTri); + renderState.vao.set(plugin.triVao); if (plugin.tiledLightingImageStoreProgram.isValid()) { renderState.program.set(plugin.tiledLightingImageStoreProgram); @@ -680,6 +680,8 @@ private void tiledLightingPass() { } } + glBindVertexArray(0); + frameTimer.end(Timer.RENDER_TILED_LIGHTING); frameTimer.end(Timer.DRAW_TILED_LIGHTING); } @@ -693,21 +695,21 @@ private void directionalShadowPass() { // Render to the shadow depth map renderState.framebuffer.set(GL_FRAMEBUFFER, plugin.fboShadowMap); renderState.viewport.set(0, 0, plugin.shadowMapResolution, plugin.shadowMapResolution); - renderState.ido.set(indirectDrawCmds.id); + renderState.ido.set(indirectDrawCmds); renderState.apply(); glClearDepth(1); glClear(GL_DEPTH_BUFFER_BIT); - renderState.enable.set(GL_DEPTH_TEST); - renderState.disable.set(GL_CULL_FACE); + renderState.depthTest.set(true); + renderState.cullFace.set(false); renderState.depthFunc.set(GL_LEQUAL); CommandBuffer.SKIP_DEPTH_MASKING = true; directionalCmd.execute(); CommandBuffer.SKIP_DEPTH_MASKING = false; - renderState.disable.set(GL_DEPTH_TEST); + renderState.setDefaults(); frameTimer.end(Timer.RENDER_SHADOWS); } @@ -717,13 +719,9 @@ private void scenePass() { frameTimer.begin(Timer.DRAW_SCENE); renderState.framebuffer.set(GL_DRAW_FRAMEBUFFER, plugin.fboScene); - if (plugin.msaaSamples > 1) { - renderState.enable.set(GL_MULTISAMPLE); - } else { - renderState.disable.set(GL_MULTISAMPLE); - } + renderState.multisample.set(plugin.msaaSamples > 1); renderState.viewport.set(0, 0, plugin.sceneResolution[0], plugin.sceneResolution[1]); - renderState.ido.set(indirectDrawCmds.id); + renderState.ido.set(indirectDrawCmds); renderState.apply(); // Clear scene @@ -743,9 +741,9 @@ private void scenePass() { frameTimer.begin(Timer.RENDER_SCENE); - renderState.enable.set(GL_BLEND); - renderState.enable.set(GL_CULL_FACE); - renderState.enable.set(GL_DEPTH_TEST); + renderState.blend.set(true); + renderState.cullFace.set(true); + renderState.depthTest.set(true); renderState.depthFunc.set(GL_GEQUAL); renderState.blendFunc.set(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); @@ -756,10 +754,7 @@ private void scenePass() { frameTimer.end(Timer.RENDER_SCENE); // Done rendering the scene - renderState.disable.set(GL_BLEND); - renderState.disable.set(GL_CULL_FACE); - renderState.disable.set(GL_DEPTH_TEST); - renderState.apply(); + renderState.setDefaults(); frameTimer.end(Timer.DRAW_SCENE); } diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java b/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java index a9e2ed6508..3b0ea0ab77 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneUploadJob.java @@ -8,7 +8,6 @@ import rs117.hd.utils.jobs.Job; import static org.lwjgl.opengl.GL33C.*; -import static rs117.hd.renderer.zone.ZoneRenderer.eboAlpha; import static rs117.hd.utils.buffer.GLBuffer.MAP_WRITE; @Slf4j @@ -77,7 +76,7 @@ private void mapZoneVertexBuffers() { f.map(MAP_WRITE); } - zone.initialize(o, a, f, eboAlpha.id); + zone.initialize(o, a, f); zone.setMetadata(viewContext, sceneContext, x, z); } catch (Throwable ex) { log.warn( diff --git a/src/main/java/rs117/hd/scene/MaterialManager.java b/src/main/java/rs117/hd/scene/MaterialManager.java index ac6056334c..c6bd06acda 100644 --- a/src/main/java/rs117/hd/scene/MaterialManager.java +++ b/src/main/java/rs117/hd/scene/MaterialManager.java @@ -57,6 +57,7 @@ import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPlugin.TEXTURE_UNIT_GAME; +import static rs117.hd.HdPlugin.bindTextureWithUnit; import static rs117.hd.utils.MathUtils.*; import static rs117.hd.utils.ResourcePath.path; @@ -391,12 +392,11 @@ private void swapMaterials(Material[] parsedMaterials, boolean skipSceneReload) int textureSize = config.textureResolution().getSize(); textureResolution = ivec(textureSize, textureSize); - glActiveTexture(TEXTURE_UNIT_GAME); if (texMaterialTextureArray == 0 || previousLayerCount != textureLayers.size()) { if (texMaterialTextureArray != 0) glDeleteTextures(texMaterialTextureArray); texMaterialTextureArray = glGenTextures(); - glBindTexture(GL_TEXTURE_2D_ARRAY, texMaterialTextureArray); + bindTextureWithUnit(GL_TEXTURE_2D_ARRAY, TEXTURE_UNIT_GAME, texMaterialTextureArray); // Since we're reallocating the texture array, all layers need to be reuploaded for (var layer : textureLayers) diff --git a/src/main/java/rs117/hd/utils/CommandBuffer.java b/src/main/java/rs117/hd/utils/CommandBuffer.java index 410711c79b..c8a4229578 100644 --- a/src/main/java/rs117/hd/utils/CommandBuffer.java +++ b/src/main/java/rs117/hd/utils/CommandBuffer.java @@ -8,9 +8,11 @@ import lombok.extern.slf4j.Slf4j; import org.lwjgl.system.MemoryStack; import rs117.hd.opengl.GLFence; +import rs117.hd.opengl.GLVao; import rs117.hd.opengl.shader.ShaderProgram; import rs117.hd.overlays.FrameTimer; import rs117.hd.overlays.Timer; +import rs117.hd.utils.buffer.GLBuffer; import rs117.hd.utils.buffer.GpuIntBuffer; import static org.lwjgl.opengl.GL33C.*; @@ -32,7 +34,6 @@ public class CommandBuffer { private static final int GL_DRAW_CALL_TYPE_COUNT = 6; private static final int GL_BIND_VERTEX_ARRAY_TYPE = 6; - private static final int GL_BIND_ELEMENTS_ARRAY_TYPE = 7; private static final int GL_BIND_INDIRECT_ARRAY_TYPE = 8; private static final int GL_BIND_TEXTURE_UNIT_TYPE = 9; private static final int GL_DEPTH_MASK_TYPE = 10; @@ -89,9 +90,9 @@ public boolean isEmpty() { return writeHead == 0; } - public void BindVertexArray(int vao) { + public void BindVertexArray(GLVao vao) { ensureCapacity(1); - cmd[writeHead++] = GL_BIND_VERTEX_ARRAY_TYPE & 0xFF | (long) vao << 8; + cmd[writeHead++] = GL_BIND_VERTEX_ARRAY_TYPE & 0xFF | (long) writeObject(vao) << 8; } public void FenceSync(GLFence fence, int condition) { @@ -100,14 +101,9 @@ public void FenceSync(GLFence fence, int condition) { cmd[writeHead++] = writeObject(fence); } - public void BindElementsArray(int ebo) { + public void BindIndirectArray(GLBuffer ido) { ensureCapacity(1); - cmd[writeHead++] = GL_BIND_ELEMENTS_ARRAY_TYPE & 0xFF | (long) ebo << 8; - } - - public void BindIndirectArray(int ido) { - ensureCapacity(1); - cmd[writeHead++] = GL_BIND_INDIRECT_ARRAY_TYPE & 0xFF | (long) ido << 8; + cmd[writeHead++] = GL_BIND_INDIRECT_ARRAY_TYPE & 0xFF | (long) writeObject(ido) << 8; } public void BindTextureUnit(int type, int texId, int bindingIndex) { @@ -263,18 +259,17 @@ public void MultiDrawArraysIndirect(int mode, int[] vertexOffsets, int[] vertexC cmd[writeHead++] = (long) indirectOffset * Integer.BYTES; } - public void Enable(int capability) { - Toggle(capability, true); + public void Enable(RenderState.GLToggle toggle) { + Toggle(toggle, true); } - public void Disable(int capability) { - Toggle(capability, false); + public void Disable(RenderState.GLToggle toggle) { + Toggle(toggle, false); } - public void Toggle(int capability, boolean enabled) { - ensureCapacity(2); - cmd[writeHead++] = GL_TOGGLE_TYPE; - cmd[writeHead++] = (enabled ? 1L : 0) << 32 | capability & INT_MASK; + public void Toggle(RenderState.GLToggle toggle, boolean enabled) { + ensureCapacity(1); + cmd[writeHead++] = GL_TOGGLE_TYPE | (enabled ? 1L : 0) << 8 | (long) writeObject(toggle) << 9; } public void append(CommandBuffer other) { @@ -316,15 +311,13 @@ public void execute() { break; } case GL_BIND_VERTEX_ARRAY_TYPE: { - renderState.vao.set((int) (data >> 8)); - break; - } - case GL_BIND_ELEMENTS_ARRAY_TYPE: { - renderState.ebo.set((int) (data >> 8)); + int objectIdx = (int) (data >> 8); + renderState.vao.set((GLVao) objects[objectIdx]); break; } case GL_BIND_INDIRECT_ARRAY_TYPE: { - renderState.ido.set((int) (data >> 8)); + int objectIdx = (int) (data >> 8); + renderState.ido.set((GLBuffer) objects[objectIdx]); break; } case GL_BIND_TEXTURE_UNIT_TYPE: { @@ -343,13 +336,9 @@ public void execute() { break; } case GL_TOGGLE_TYPE: { - long packed = cmd[readHead++]; - int capability = (int) (packed & INT_MASK); - if ((packed >> 32) != 0) { - renderState.enable.set(capability); - } else { - renderState.disable.set(capability); - } + int objectIdx = (int) (data >> 9); + RenderState.GLToggle capability = (RenderState.GLToggle) objects[objectIdx]; + capability.set(((data >> 9) & 1) == 1); break; } case GL_FENCE_SYNC: { diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index 009a60eba1..7ac9ac45e1 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -3,9 +3,13 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; +import lombok.RequiredArgsConstructor; import rs117.hd.opengl.GLState; +import rs117.hd.opengl.GLVao; import rs117.hd.opengl.shader.ShaderProgram; +import rs117.hd.utils.buffer.GLBuffer; +import static org.lwjgl.opengl.GL20C.glUseProgram; import static org.lwjgl.opengl.GL33C.*; import static org.lwjgl.opengl.GL40.GL_DRAW_INDIRECT_BUFFER; @@ -18,21 +22,27 @@ public final class RenderState { public final GLShaderProgram program = addState(GLShaderProgram::new); public final GLViewport viewport = addState(GLViewport::new); public final GLBindVAO vao = addState(GLBindVAO::new); - public final GLBindEBO ebo = addState(GLBindEBO::new); public final GLBindIDO ido = addState(GLBindIDO::new); public final GLBindUBO ubo = addState(GLBindUBO::new); public final GLDepthMask depthMask = addState(GLDepthMask::new); public final GLDepthFunc depthFunc = addState(GLDepthFunc::new); public final GLColorMask colorMask = addState(GLColorMask::new); public final GLBlendFunc blendFunc = addState(GLBlendFunc::new); - public final GLEnable enable = addState(GLEnable::new); - public final GLDisable disable = addState(GLDisable::new); + public final GLToggle blend = new GLToggle(GL_BLEND, false); // TODO: Verify the default GL STATE + public final GLToggle cullFace = new GLToggle(GL_CULL_FACE, true); + public final GLToggle depthTest = new GLToggle(GL_DEPTH_TEST, false); + public final GLToggle multisample = new GLToggle(GL_DEPTH_TEST, false); public void apply() { for (GLState state : states) state.apply(); } + public void setDefaults(){ + for (GLState state : states) + state.setDefault(); + } + public void reset() { for (GLState state : states) state.reset(); @@ -51,6 +61,9 @@ private GLBindFramebuffer() { @Override protected void applyValues(int[] values) { glBindFramebuffer(values[0], values[1]); } + + @Override + protected void applyDefault() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } } public static final class GLFramebufferTextureLayer extends GLState.IntArray { @@ -60,55 +73,68 @@ public static final class GLFramebufferTextureLayer extends GLState.IntArray { protected void applyValues(int[] values) { glFramebufferTextureLayer(values[0], values[1], values[2], values[3], values[4]); } + + @Override + protected void applyDefault() { } } public static final class GLViewport extends GLState.IntArray { private GLViewport() { super(4); } - @Override protected void applyValues(int[] values) { glViewport(values[0], values[1], values[2], values[3]); } + @Override + protected void applyDefault() { glUseProgram(0); } } public static final class GLShaderProgram extends GLState.Object { @Override protected void applyValue(ShaderProgram program) { program.use(); } + @Override + protected void applyDefault() { glUseProgram(0); } } public static final class GLDrawBuffer extends GLState.Int { @Override protected void applyValue(int buf) { glDrawBuffer(buf); } - } - - public static final class GLBindVAO extends GLState.Int { @Override - protected void applyValue(int vao) { glBindVertexArray(vao); } + protected void applyDefault() { } } - public static final class GLBindEBO extends GLState.Int { + public static final class GLBindVAO extends GLState.Object { @Override - protected void applyValue(int ebo) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); } + protected void applyValue(GLVao vao) { vao.bind(); } + @Override + protected void applyDefault() { glBindVertexArray(0); } } - public static final class GLBindIDO extends GLState.Int { + public static final class GLBindIDO extends GLState.Object { + @Override + protected void applyValue(GLBuffer ido) { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ido.id); } @Override - protected void applyValue(int ebo) { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ebo); } + protected void applyDefault() { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); } } public static final class GLBindUBO extends GLState.Int { @Override protected void applyValue(int ubo) { glBindBuffer(GL_UNIFORM_BUFFER, ubo); } + @Override + protected void applyDefault() { glBindBuffer(GL_UNIFORM_BUFFER, 0); } } public static final class GLDepthMask extends GLState.Bool { @Override protected void applyValue(boolean enabled) { glDepthMask(enabled); } + @Override + protected void applyDefault() { glDepthMask(false); } } public static final class GLDepthFunc extends GLState.Int { @Override protected void applyValue(int func) { glDepthFunc(func); } + @Override + protected void applyDefault() { glDepthFunc(GL_LESS); } } public static final class GLBlendFunc extends GLState.IntArray { @@ -118,6 +144,8 @@ private GLBlendFunc() { @Override protected void applyValues(int[] values) { glBlendFuncSeparate(values[0], values[1], values[2], values[3]); } + @Override + protected void applyDefault() { glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); } } public static final class GLColorMask extends GLState.BoolArray { @@ -127,25 +155,25 @@ private GLColorMask() { @Override protected void applyValues(boolean[] values) { glColorMask(values[0], values[1], values[2], values[3]); } + @Override + protected void applyDefault() { glColorMask(true, true, true, true); } } - public final class GLEnable extends GLState.IntSet { - @Override - protected void applyTarget(int target) { glEnable(target); } + @RequiredArgsConstructor + public static final class GLToggle extends GLState.Bool { + private final int target; + private final boolean defaultState; - public void set(int target) { - add(target); - disable.remove(target); + @Override + protected void applyValue(boolean value) { + if(value) { + glEnable(target); + } else { + glDisable(target); + } } - } - public final class GLDisable extends GLState.IntSet { @Override - protected void applyTarget(int target) { glDisable(target); } - - public void set(int target) { - add(target); - enable.remove(target); - } + protected void applyDefault() { applyValue(defaultState); } } } diff --git a/src/main/java/rs117/hd/utils/buffer/GLBuffer.java b/src/main/java/rs117/hd/utils/buffer/GLBuffer.java index 971839fc68..58d027a43b 100644 --- a/src/main/java/rs117/hd/utils/buffer/GLBuffer.java +++ b/src/main/java/rs117/hd/utils/buffer/GLBuffer.java @@ -288,8 +288,9 @@ public void upload(IntBuffer data, long byteOffset) { )); } - public void upload(FloatBuffer data) { + public GLBuffer upload(FloatBuffer data) { upload(data, 0); + return this; } public void upload(FloatBuffer data, long byteOffset) { From c94dfc01e226d6d1a992d7e655de1326c330649f Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 02:27:08 +0000 Subject: [PATCH 02/16] Sync --- src/main/java/rs117/hd/HdPlugin.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index 02572e9a05..2706f76233 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -1032,6 +1032,7 @@ private void initializeVaos() { quadVao = new GLVao("FullscreenQuad::VAO", FULLSCREEN_VERTEX_LAYOUT); quadVao.setBufferRange( new GLBuffer("FullscreenQuad::VBO", GL_ARRAY_BUFFER, GL_STATIC_DRAW) + .initialize() .upload( stack.mallocFloat(16) .put(new float[] { @@ -1046,6 +1047,7 @@ private void initializeVaos() { triVao = new GLVao("FullscreenQuad::VAO", FULLSCREEN_VERTEX_LAYOUT); triVao.setBufferRange( new GLBuffer("FullscreenQuad::VBO", GL_ARRAY_BUFFER, GL_STATIC_DRAW) + .initialize() .upload( stack.mallocFloat(16) .put(new float[] { @@ -1982,6 +1984,8 @@ public static void bindTextureWithUnit(int target, int unit, int textureId) { glActiveTexture(unit); glBindTexture(target, textureId); glActiveTexture(TEXTURE_UNIT_UNUSED); + + checkGLErrors(); } @SuppressWarnings("StatementWithEmptyBody") From 47f778bdd437997e7c589989fc55a96a852a4643 Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 02:32:50 +0000 Subject: [PATCH 03/16] Sync --- src/main/java/rs117/hd/scene/MaterialManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/rs117/hd/scene/MaterialManager.java b/src/main/java/rs117/hd/scene/MaterialManager.java index c6bd06acda..ac6056334c 100644 --- a/src/main/java/rs117/hd/scene/MaterialManager.java +++ b/src/main/java/rs117/hd/scene/MaterialManager.java @@ -57,7 +57,6 @@ import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPlugin.TEXTURE_UNIT_GAME; -import static rs117.hd.HdPlugin.bindTextureWithUnit; import static rs117.hd.utils.MathUtils.*; import static rs117.hd.utils.ResourcePath.path; @@ -392,11 +391,12 @@ private void swapMaterials(Material[] parsedMaterials, boolean skipSceneReload) int textureSize = config.textureResolution().getSize(); textureResolution = ivec(textureSize, textureSize); + glActiveTexture(TEXTURE_UNIT_GAME); if (texMaterialTextureArray == 0 || previousLayerCount != textureLayers.size()) { if (texMaterialTextureArray != 0) glDeleteTextures(texMaterialTextureArray); texMaterialTextureArray = glGenTextures(); - bindTextureWithUnit(GL_TEXTURE_2D_ARRAY, TEXTURE_UNIT_GAME, texMaterialTextureArray); + glBindTexture(GL_TEXTURE_2D_ARRAY, texMaterialTextureArray); // Since we're reallocating the texture array, all layers need to be reuploaded for (var layer : textureLayers) From 96b4e7de90526416b2533e23cbf4eebc5d056b2d Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 02:36:24 +0000 Subject: [PATCH 04/16] Sync --- src/main/java/rs117/hd/HdPlugin.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index 2706f76233..c08b67ed61 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -353,7 +353,7 @@ public class HdPlugin extends Plugin { private static final GLVertexLayout FULLSCREEN_VERTEX_LAYOUT = new GLVertexLayout("FULLSCREEN_VERTEX_LAYOUT") .edit(ArrayField.VERTEX_FIELD_0).enabled().component(ComponentType.RG).format(FormatType.FLOAT).stride(16).offset(0) - .edit(ArrayField.VERTEX_FIELD_1).enabled().component(ComponentType.RG).format(FormatType.FLOAT).stride(16).offset(4) + .edit(ArrayField.VERTEX_FIELD_1).enabled().component(ComponentType.RG).format(FormatType.FLOAT).stride(16).offset(8) .finish(); public GLVao quadVao; @@ -1179,7 +1179,7 @@ public void updateTiledLightingFbo() { ARBShaderImageLoadStore.glBindImageTexture( IMAGE_UNIT_TILED_LIGHTING, texTiledLighting, 0, true, 0, GL_WRITE_ONLY, GL_RGBA16UI); - glBindTexture(GL_TEXTURE_2D, 0); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); glBindFramebuffer(GL_FRAMEBUFFER, awtContext.getFramebuffer(false)); checkGLErrors(); @@ -1374,7 +1374,6 @@ private void initializeShadowMapFbo() { float[] color = { 1, 1, 1, 1 }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); - glBindTexture(GL_TEXTURE_2D, 0); // Bind texture glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texShadowMap, 0); @@ -1383,6 +1382,7 @@ private void initializeShadowMapFbo() { // Reset FBO glBindFramebuffer(GL_FRAMEBUFFER, awtContext.getFramebuffer(false)); + glBindTexture(GL_TEXTURE_2D, 0); } private void initializeDummyShadowMap() { From 775de0d64918cecf9f26a183118af3bd864d66a7 Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 02:47:10 +0000 Subject: [PATCH 05/16] Sync --- src/main/java/rs117/hd/HdPlugin.java | 2 +- .../rs117/hd/renderer/zone/ZoneRenderer.java | 33 +++++++++---------- src/main/java/rs117/hd/utils/RenderState.java | 26 +++++++++++---- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index c08b67ed61..dd410a58dc 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -1179,8 +1179,8 @@ public void updateTiledLightingFbo() { ARBShaderImageLoadStore.glBindImageTexture( IMAGE_UNIT_TILED_LIGHTING, texTiledLighting, 0, true, 0, GL_WRITE_ONLY, GL_RGBA16UI); - glBindTexture(GL_TEXTURE_2D_ARRAY, 0); glBindFramebuffer(GL_FRAMEBUFFER, awtContext.getFramebuffer(false)); + glBindTexture(GL_TEXTURE_2D_ARRAY, 0); checkGLErrors(); diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java index 6cc6554267..645423e10f 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java @@ -660,7 +660,8 @@ private void tiledLightingPass() { frameTimer.begin(Timer.DRAW_TILED_LIGHTING); frameTimer.begin(Timer.RENDER_TILED_LIGHTING); - renderState.framebuffer.set(GL_FRAMEBUFFER, plugin.fboTiledLighting); + renderState.setDefaults(); + renderState.drawFramebuffer.set(plugin.fboTiledLighting); renderState.viewport.set(0, 0, plugin.tiledLightingResolution[0], plugin.tiledLightingResolution[1]); renderState.vao.set(plugin.triVao); @@ -674,14 +675,12 @@ private void tiledLightingPass() { int layerCount = plugin.configDynamicLights.getTiledLightingLayers(); for (int layer = 0; layer < layerCount; layer++) { renderState.program.set(plugin.tiledLightingShaderPrograms.get(layer)); - renderState.framebufferTextureLayer.set(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, plugin.texTiledLighting, 0, layer); + renderState.framebufferTextureLayer.set(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, plugin.texTiledLighting, 0, layer); renderState.apply(); glDrawArrays(GL_TRIANGLES, 0, 3); } } - glBindVertexArray(0); - frameTimer.end(Timer.RENDER_TILED_LIGHTING); frameTimer.end(Timer.DRAW_TILED_LIGHTING); } @@ -693,7 +692,8 @@ private void directionalShadowPass() { frameTimer.begin(Timer.RENDER_SHADOWS); // Render to the shadow depth map - renderState.framebuffer.set(GL_FRAMEBUFFER, plugin.fboShadowMap); + renderState.setDefaults(); + renderState.drawFramebuffer.set(plugin.fboShadowMap); renderState.viewport.set(0, 0, plugin.shadowMapResolution, plugin.shadowMapResolution); renderState.ido.set(indirectDrawCmds); renderState.apply(); @@ -709,8 +709,6 @@ private void directionalShadowPass() { directionalCmd.execute(); CommandBuffer.SKIP_DEPTH_MASKING = false; - renderState.setDefaults(); - frameTimer.end(Timer.RENDER_SHADOWS); } @@ -718,7 +716,8 @@ private void scenePass() { sceneProgram.use(); frameTimer.begin(Timer.DRAW_SCENE); - renderState.framebuffer.set(GL_DRAW_FRAMEBUFFER, plugin.fboScene); + renderState.setDefaults(); + renderState.drawFramebuffer.set(plugin.fboScene); renderState.multisample.set(plugin.msaaSamples > 1); renderState.viewport.set(0, 0, plugin.sceneResolution[0], plugin.sceneResolution[1]); renderState.ido.set(indirectDrawCmds); @@ -752,10 +751,6 @@ private void scenePass() { // TODO: Filler tiles frameTimer.end(Timer.RENDER_SCENE); - - // Done rendering the scene - renderState.setDefaults(); - frameTimer.end(Timer.DRAW_SCENE); } @@ -1018,23 +1013,26 @@ public void draw(int overlayColor) { tiledLightingPass(); directionalShadowPass(); scenePass(); + renderState.setDefaults(); } if (sceneFboValid && plugin.sceneResolution != null && plugin.sceneViewport != null) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, plugin.fboScene); + renderState.readFramebuffer.set(plugin.fboScene); if (plugin.fboSceneResolve != 0) { // Blit from the scene FBO to the multisample resolve FBO - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, plugin.fboSceneResolve); + renderState.drawFramebuffer.set(plugin.fboSceneResolve); + renderState.apply(); glBlitFramebuffer( 0, 0, plugin.sceneResolution[0], plugin.sceneResolution[1], 0, 0, plugin.sceneResolution[0], plugin.sceneResolution[1], GL_COLOR_BUFFER_BIT, GL_NEAREST ); - glBindFramebuffer(GL_READ_FRAMEBUFFER, plugin.fboSceneResolve); + renderState.readFramebuffer.set(plugin.fboSceneResolve); } // Blit from the resolved FBO to the default FBO - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, plugin.awtContext.getFramebuffer(false)); + renderState.drawFramebuffer.set(plugin.awtContext.getFramebuffer(false)); + renderState.apply(); glBlitFramebuffer( 0, 0, @@ -1048,7 +1046,8 @@ public void draw(int overlayColor) { config.sceneScalingMode().glFilter ); } else { - glBindFramebuffer(GL_FRAMEBUFFER, plugin.awtContext.getFramebuffer(false)); + renderState.framebuffer.set(plugin.awtContext.getFramebuffer(false)); + renderState.apply(); glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); } diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index 7ac9ac45e1..b67b678298 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -17,6 +17,8 @@ public final class RenderState { private final List states = new ArrayList<>(); public final GLBindFramebuffer framebuffer = addState(GLBindFramebuffer::new); + public final GLBindDrawFramebuffer drawFramebuffer = addState(GLBindDrawFramebuffer::new); + public final GLBindReadFramebuffer readFramebuffer = addState(GLBindReadFramebuffer::new); public final GLFramebufferTextureLayer framebufferTextureLayer = addState(GLFramebufferTextureLayer::new); public final GLDrawBuffer drawBuffer = addState(GLDrawBuffer::new); public final GLShaderProgram program = addState(GLShaderProgram::new); @@ -54,18 +56,30 @@ private T addState(Supplier supplier) { return state; } - public static final class GLBindFramebuffer extends GLState.IntArray { - private GLBindFramebuffer() { - super(2); - } - + public static class GLBindFramebuffer extends GLState.Int { @Override - protected void applyValues(int[] values) { glBindFramebuffer(values[0], values[1]); } + protected void applyValue(int value) { glBindFramebuffer(GL_FRAMEBUFFER, value); } @Override protected void applyDefault() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } } + public static class GLBindReadFramebuffer extends GLState.Int { + @Override + protected void applyValue(int value) { glBindFramebuffer(GL_READ_FRAMEBUFFER, value); } + + @Override + protected void applyDefault() { glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } + } + + public static class GLBindDrawFramebuffer extends GLState.Int { + @Override + protected void applyValue(int value) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, value); } + + @Override + protected void applyDefault() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } + } + public static final class GLFramebufferTextureLayer extends GLState.IntArray { private GLFramebufferTextureLayer() { super(5); } From 344add29d7ebf7a4c659bb4ae0d2b237aaed82e7 Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 03:02:22 +0000 Subject: [PATCH 06/16] Sync --- src/main/java/rs117/hd/HdPlugin.java | 35 ++++++++++++------- .../hd/renderer/legacy/LegacyRenderer.java | 6 ++-- .../rs117/hd/renderer/zone/ZoneRenderer.java | 3 +- src/main/java/rs117/hd/utils/RenderState.java | 8 ++++- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index dd410a58dc..f4e41fa442 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -135,7 +135,6 @@ import rs117.hd.utils.jobs.JobSystem; import static net.runelite.api.Constants.*; -import static org.lwjgl.opengl.GL13C.glActiveTexture; import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPluginConfig.*; import static rs117.hd.utils.MathUtils.*; @@ -1114,11 +1113,14 @@ private void initializeUiTexture() { } texUi = glGenTextures(); - bindTextureWithUnit(GL_TEXTURE_2D, TEXTURE_UNIT_UI, texUi); + glActiveTexture(TEXTURE_UNIT_UI); + glBindTexture(GL_TEXTURE_2D, texUi); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glActiveTexture(TEXTURE_UNIT_UNUSED); glBindTexture(GL_TEXTURE_2D, 0); checkGLErrors(); @@ -1153,7 +1155,8 @@ public void updateTiledLightingFbo() { fboTiledLighting = glGenFramebuffers(); texTiledLighting = glGenTextures(); - bindTextureWithUnit(GL_TEXTURE_2D_ARRAY, TEXTURE_UNIT_TILED_LIGHTING_MAP, texTiledLighting); + glActiveTexture(TEXTURE_UNIT_TILED_LIGHTING_MAP); + glBindTexture(GL_TEXTURE_2D_ARRAY, texTiledLighting); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -1180,6 +1183,8 @@ public void updateTiledLightingFbo() { IMAGE_UNIT_TILED_LIGHTING, texTiledLighting, 0, true, 0, GL_WRITE_ONLY, GL_RGBA16UI); glBindFramebuffer(GL_FRAMEBUFFER, awtContext.getFramebuffer(false)); + + glActiveTexture(TEXTURE_UNIT_UNUSED); glBindTexture(GL_TEXTURE_2D_ARRAY, 0); checkGLErrors(); @@ -1347,7 +1352,8 @@ private void initializeShadowMapFbo() { // Create texture texShadowMap = glGenTextures(); - bindTextureWithUnit(GL_TEXTURE_2D, TEXTURE_UNIT_SHADOW_MAP, texShadowMap); + glActiveTexture(TEXTURE_UNIT_SHADOW_MAP); + glBindTexture(GL_TEXTURE_2D, texShadowMap); shadowMapResolution = config.shadowResolution().getValue(); int maxResolution = glGetInteger(GL_MAX_TEXTURE_SIZE); @@ -1380,20 +1386,31 @@ private void initializeShadowMapFbo() { glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); + // Check framebuffer completeness + int status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + log.error("Shadow map framebuffer is not complete: 0x{}", Integer.toHexString(status)); + throw new RuntimeException("Failed to create shadow map framebuffer: status 0x" + Integer.toHexString(status)); + } + // Reset FBO glBindFramebuffer(GL_FRAMEBUFFER, awtContext.getFramebuffer(false)); + glActiveTexture(TEXTURE_UNIT_UNUSED); glBindTexture(GL_TEXTURE_2D, 0); } private void initializeDummyShadowMap() { // Create dummy texture texShadowMap = glGenTextures(); - bindTextureWithUnit(GL_TEXTURE_2D, TEXTURE_UNIT_SHADOW_MAP, texShadowMap); + glActiveTexture(TEXTURE_UNIT_SHADOW_MAP); + glBindTexture(GL_TEXTURE_2D, texShadowMap); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + glActiveTexture(TEXTURE_UNIT_UNUSED); glBindTexture(GL_TEXTURE_2D, 0); } @@ -1980,14 +1997,6 @@ public void onFocusChanged(FocusChanged event) { isClientInFocus = event.isFocused(); } - public static void bindTextureWithUnit(int target, int unit, int textureId) { - glActiveTexture(unit); - glBindTexture(target, textureId); - glActiveTexture(TEXTURE_UNIT_UNUSED); - - checkGLErrors(); - } - @SuppressWarnings("StatementWithEmptyBody") public static void clearGLErrors() { // @formatter:off diff --git a/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java b/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java index 50411b18ad..941486d72b 100644 --- a/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java +++ b/src/main/java/rs117/hd/renderer/legacy/LegacyRenderer.java @@ -67,7 +67,7 @@ import static rs117.hd.HdPlugin.NEAR_PLANE; import static rs117.hd.HdPlugin.ORTHOGRAPHIC_ZOOM; import static rs117.hd.HdPlugin.TEXTURE_UNIT_TILE_HEIGHT_MAP; -import static rs117.hd.HdPlugin.bindTextureWithUnit; +import static rs117.hd.HdPlugin.TEXTURE_UNIT_UNUSED; import static rs117.hd.HdPlugin.checkGLErrors; import static rs117.hd.HdPluginConfig.*; import static rs117.hd.utils.MathUtils.*; @@ -495,7 +495,8 @@ public void initializeTileHeightMap(Scene scene) { tileBuffer.flip(); texTileHeightMap = glGenTextures(); - bindTextureWithUnit(GL_TEXTURE_3D, TEXTURE_UNIT_TILE_HEIGHT_MAP, texTileHeightMap); + glActiveTexture(TEXTURE_UNIT_TILE_HEIGHT_MAP); + glBindTexture(GL_TEXTURE_3D, texTileHeightMap); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -505,6 +506,7 @@ public void initializeTileHeightMap(Scene scene) { Constants.EXTENDED_SCENE_SIZE, Constants.EXTENDED_SCENE_SIZE, Constants.MAX_Z, 0, GL_RED_INTEGER, GL_SHORT, tileBuffer ); + glActiveTexture(TEXTURE_UNIT_UNUSED); glBindTexture(GL_TEXTURE_3D, 0); } diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java index 645423e10f..6b23ab51b5 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java @@ -720,7 +720,6 @@ private void scenePass() { renderState.drawFramebuffer.set(plugin.fboScene); renderState.multisample.set(plugin.msaaSamples > 1); renderState.viewport.set(0, 0, plugin.sceneResolution[0], plugin.sceneResolution[1]); - renderState.ido.set(indirectDrawCmds); renderState.apply(); // Clear scene @@ -745,6 +744,8 @@ private void scenePass() { renderState.depthTest.set(true); renderState.depthFunc.set(GL_GEQUAL); renderState.blendFunc.set(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + renderState.ido.set(indirectDrawCmds); + renderState.apply(); // Render the scene sceneCmd.execute(); diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index b67b678298..a4a0773007 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -118,7 +118,13 @@ protected void applyDefault() { } public static final class GLBindVAO extends GLState.Object { @Override - protected void applyValue(GLVao vao) { vao.bind(); } + protected void applyValue(GLVao vao) { + if(vao != null) { + vao.bind(); + } else { + glBindVertexArray(0); + } + } @Override protected void applyDefault() { glBindVertexArray(0); } } From e187835959fdb5da0a411d5dac2c355935447fad Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 03:10:59 +0000 Subject: [PATCH 07/16] Handle the EBO Buffer changing when binding the VAO --- src/main/java/rs117/hd/opengl/GLVao.java | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/rs117/hd/opengl/GLVao.java b/src/main/java/rs117/hd/opengl/GLVao.java index c40988b917..7d69e856f1 100644 --- a/src/main/java/rs117/hd/opengl/GLVao.java +++ b/src/main/java/rs117/hd/opengl/GLVao.java @@ -23,7 +23,7 @@ public class GLVao { private final GLBuffer[] buffers = new GLBuffer[GLVertexLayout.MAX_ATTRIBUTES]; private final boolean[] ownership = new boolean[GLVertexLayout.MAX_ATTRIBUTES]; - private int glVAO; + private int glVAO, glBoundEBO; private int layoutVersion; public void setBuffer(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField field) { @@ -75,9 +75,6 @@ public void bind() { glBindVertexArray(glVAO); if(layoutVersion != layout.getVersion()) { - final GLBuffer eboBuffer = buffers[GLVertexLayout.ArrayField.ELEMENT_BUFFER.ordinal()]; - if(eboBuffer != null) - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eboBuffer.id); GLVertexLayout.Attribute[] attributes = layout.getAttributes(); for(int i = 0; i < attributes.length; i++) { @@ -112,13 +109,23 @@ public void bind() { glBindBuffer(GL_ARRAY_BUFFER, 0); } - // Unbind VAO, so its safe to unbind the Array & Element buffers + checkGLErrors(() -> "Building VAO: " + name + " with layout: " + layout); + layoutVersion = layout.getVersion(); + } + + final GLBuffer eboBuffer = buffers[GLVertexLayout.ArrayField.ELEMENT_BUFFER.ordinal()]; + if(eboBuffer != null && glBoundEBO != eboBuffer.id) { + // Element buffer id has changed, rebind it to the VAO State + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO = eboBuffer.id); + + // Rebind the VAO State, so that its safe to unbind the EBO without clearing it off the state glBindVertexArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindVertexArray(glVAO); - - checkGLErrors(() -> "Building VAO: " + name + " with layout: " + layout); - layoutVersion = layout.getVersion(); + } else if(glBoundEBO != 0) { + // Element buffer was previously bound, but is now null clear it off the VAO State + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glBoundEBO = 0; } } From c929a47d8f547d8e362e5fe9f0ccf02a448e93ac Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 05:12:12 +0000 Subject: [PATCH 08/16] Sync --- src/main/java/rs117/hd/opengl/GLState.java | 2 + src/main/java/rs117/hd/opengl/GLVao.java | 90 +++++++++++-------- src/main/java/rs117/hd/utils/RenderState.java | 14 +-- 3 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/main/java/rs117/hd/opengl/GLState.java b/src/main/java/rs117/hd/opengl/GLState.java index 09d392b810..73e3ca2488 100644 --- a/src/main/java/rs117/hd/opengl/GLState.java +++ b/src/main/java/rs117/hd/opengl/GLState.java @@ -4,6 +4,7 @@ import java.util.HashSet; import java.util.Objects; import java.util.Set; +import lombok.Getter; public abstract class GLState { protected boolean hasValue; @@ -72,6 +73,7 @@ void internalApply() { public abstract static class Object extends GLState { private T value; + @Getter private T appliedValue; public final void set(T v) { diff --git a/src/main/java/rs117/hd/opengl/GLVao.java b/src/main/java/rs117/hd/opengl/GLVao.java index 7d69e856f1..6a3d68948f 100644 --- a/src/main/java/rs117/hd/opengl/GLVao.java +++ b/src/main/java/rs117/hd/opengl/GLVao.java @@ -18,6 +18,8 @@ @RequiredArgsConstructor @Slf4j public class GLVao { + private static GLVao previousVao; + private final String name; private final GLVertexLayout layout; private final GLBuffer[] buffers = new GLBuffer[GLVertexLayout.MAX_ATTRIBUTES]; @@ -69,49 +71,16 @@ public void remove(GLBuffer buffer) { } public void bind() { + if(previousVao != null && previousVao != this) + log.warn("Binding VAO: {} when it was already bound by: {}", name, previousVao.name); + if(glVAO == 0) glVAO = glGenVertexArrays(); glBindVertexArray(glVAO); + previousVao = this; - if(layoutVersion != layout.getVersion()) { - - GLVertexLayout.Attribute[] attributes = layout.getAttributes(); - for(int i = 0; i < attributes.length; i++) { - final GLVertexLayout.Attribute attrib = attributes[i]; - if(!attrib.isEnabled) { - glDisableVertexAttribArray(i); - continue; - } - - final GLBuffer arrayBuffer = buffers[i + 1]; - if(arrayBuffer == null) { - log.warn( - "ArrayField: {} is enabled but no buffer is associated, expect erroneous behaviour", - GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] - ); - } else { - glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer.id); - } - - glEnableVertexAttribArray(i); - - if(attrib.divisor > 0) - glVertexAttribDivisor(i, attrib.divisor); - - if(attrib.isInteger) { - assert attrib.format.ordinal() >= GLVertexLayout.FormatType.INT.ordinal(); - glVertexAttribIPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.stride, attrib.offset); - } else { - glVertexAttribPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.isNormalized, attrib.stride, attrib.offset); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - checkGLErrors(() -> "Building VAO: " + name + " with layout: " + layout); - layoutVersion = layout.getVersion(); - } + ensureBuilt(); final GLBuffer eboBuffer = buffers[GLVertexLayout.ArrayField.ELEMENT_BUFFER.ordinal()]; if(eboBuffer != null && glBoundEBO != eboBuffer.id) { @@ -129,9 +98,52 @@ public void bind() { } } + private void ensureBuilt() { + if(layoutVersion == layout.getVersion()) + return; + + GLVertexLayout.Attribute[] attributes = layout.getAttributes(); + for(int i = 0; i < attributes.length; i++) { + final GLVertexLayout.Attribute attrib = attributes[i]; + if(!attrib.isEnabled) { + glDisableVertexAttribArray(i); + continue; + } + + final GLBuffer arrayBuffer = buffers[i + 1]; + if(arrayBuffer == null) { + log.warn( + "ArrayField: {} is enabled but no buffer is associated, expect erroneous behaviour", + GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] + ); + } else { + glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer.id); + } + + glEnableVertexAttribArray(i); + + if(attrib.divisor > 0) + glVertexAttribDivisor(i, attrib.divisor); + + if(attrib.isInteger) { + assert attrib.format.ordinal() >= GLVertexLayout.FormatType.INT.ordinal(); + glVertexAttribIPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.stride, attrib.offset); + } else { + glVertexAttribPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.isNormalized, attrib.stride, attrib.offset); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + + checkGLErrors(() -> "Building VAO: " + name + " with layout: " + layout); + layoutVersion = layout.getVersion(); + } + public void unbind() { - // TODO: Verify that we've bound & unbound in the correct order + if(previousVao != null && previousVao != this) + log.warn("Unbinding VAO: {} when it was bound by: {}", name, previousVao.name); glBindVertexArray(0); + previousVao = null; } public void destroy() { diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index a4a0773007..9b98cf0719 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -119,14 +119,18 @@ protected void applyDefault() { } public static final class GLBindVAO extends GLState.Object { @Override protected void applyValue(GLVao vao) { - if(vao != null) { + if(getAppliedValue() != null) + getAppliedValue().unbind(); + + if(vao != null) vao.bind(); - } else { - glBindVertexArray(0); - } + } @Override - protected void applyDefault() { glBindVertexArray(0); } + protected void applyDefault() { + if(getAppliedValue() != null) + getAppliedValue().unbind(); + } } public static final class GLBindIDO extends GLState.Object { From f374173e05bb33f0a299ad545e397e9b5a9c727f Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 05:31:46 +0000 Subject: [PATCH 09/16] Sync --- src/main/java/rs117/hd/opengl/GLVao.java | 35 +++++++++---------- .../java/rs117/hd/renderer/zone/Zone.java | 6 ++-- .../rs117/hd/renderer/zone/ZoneRenderer.java | 4 +-- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/main/java/rs117/hd/opengl/GLVao.java b/src/main/java/rs117/hd/opengl/GLVao.java index 6a3d68948f..9228ef5c68 100644 --- a/src/main/java/rs117/hd/opengl/GLVao.java +++ b/src/main/java/rs117/hd/opengl/GLVao.java @@ -83,19 +83,9 @@ public void bind() { ensureBuilt(); final GLBuffer eboBuffer = buffers[GLVertexLayout.ArrayField.ELEMENT_BUFFER.ordinal()]; - if(eboBuffer != null && glBoundEBO != eboBuffer.id) { - // Element buffer id has changed, rebind it to the VAO State - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO = eboBuffer.id); - - // Rebind the VAO State, so that its safe to unbind the EBO without clearing it off the state - glBindVertexArray(0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBindVertexArray(glVAO); - } else if(glBoundEBO != 0) { - // Element buffer was previously bound, but is now null clear it off the VAO State - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - glBoundEBO = 0; - } + final int newEboValue = eboBuffer != null ? eboBuffer.id : 0; + if(glBoundEBO != newEboValue) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO = newEboValue); } private void ensureBuilt() { @@ -103,6 +93,7 @@ private void ensureBuilt() { return; GLVertexLayout.Attribute[] attributes = layout.getAttributes(); + int prevBufferId = 0; for(int i = 0; i < attributes.length; i++) { final GLVertexLayout.Attribute attrib = attributes[i]; if(!attrib.isEnabled) { @@ -111,17 +102,20 @@ private void ensureBuilt() { } final GLBuffer arrayBuffer = buffers[i + 1]; + final int arrayBufferId = arrayBuffer != null ? arrayBuffer.id : 0; if(arrayBuffer == null) { log.warn( "ArrayField: {} is enabled but no buffer is associated, expect erroneous behaviour", GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] ); - } else { - glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer.id); } - glEnableVertexAttribArray(i); + if(prevBufferId != arrayBufferId) { + glBindBuffer(GL_ARRAY_BUFFER, arrayBufferId); + prevBufferId = arrayBufferId; + } + glEnableVertexAttribArray(i); if(attrib.divisor > 0) glVertexAttribDivisor(i, attrib.divisor); @@ -131,10 +125,13 @@ private void ensureBuilt() { } else { glVertexAttribPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.isNormalized, attrib.stride, attrib.offset); } - - glBindBuffer(GL_ARRAY_BUFFER, 0); } + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindVertexArray(glVAO); + checkGLErrors(() -> "Building VAO: " + name + " with layout: " + layout); layoutVersion = layout.getVersion(); } @@ -143,6 +140,8 @@ public void unbind() { if(previousVao != null && previousVao != this) log.warn("Unbinding VAO: {} when it was bound by: {}", name, previousVao.name); glBindVertexArray(0); + if(glBoundEBO != 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO); previousVao = null; } diff --git a/src/main/java/rs117/hd/renderer/zone/Zone.java b/src/main/java/rs117/hd/renderer/zone/Zone.java index cba9aa95ed..1ffb601c86 100644 --- a/src/main/java/rs117/hd/renderer/zone/Zone.java +++ b/src/main/java/rs117/hd/renderer/zone/Zone.java @@ -67,10 +67,10 @@ public class Zone { .edit(ArrayField.VERTEX_FIELD_0).enabled().component(ComponentType.RGB).format(FormatType.SHORT).stride(VERT_SIZE).offset(0) .edit(ArrayField.VERTEX_FIELD_1).enabled().component(ComponentType.RGB).format(FormatType.HALF_FLOAT).stride(VERT_SIZE).offset(6) .edit(ArrayField.VERTEX_FIELD_2).enabled().component(ComponentType.RGB).format(FormatType.SHORT).stride(VERT_SIZE).offset(12) - .edit(ArrayField.VERTEX_FIELD_3).enabled().asInteger().component(ComponentType.R).format(FormatType.INT).stride(VERT_SIZE).offset(20) + .edit(ArrayField.VERTEX_FIELD_3).enabled().component(ComponentType.R).format(FormatType.INT).stride(VERT_SIZE).offset(20).asInteger() // Meta Data - .edit(ArrayField.VERTEX_FIELD_6).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(0) - .edit(ArrayField.VERTEX_FIELD_7).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(4) + .edit(ArrayField.VERTEX_FIELD_6).enabled().component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(0).asInteger().divisor(1) + .edit(ArrayField.VERTEX_FIELD_7).enabled().component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(4).asInteger().divisor(1) .finish(); public static final int LEVEL_WATER_SURFACE = 4; diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java index 6b23ab51b5..a597d31baf 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java @@ -704,6 +704,7 @@ private void directionalShadowPass() { renderState.depthTest.set(true); renderState.cullFace.set(false); renderState.depthFunc.set(GL_LEQUAL); + renderState.program.set(sceneProgram); CommandBuffer.SKIP_DEPTH_MASKING = true; directionalCmd.execute(); @@ -713,8 +714,6 @@ private void directionalShadowPass() { } private void scenePass() { - sceneProgram.use(); - frameTimer.begin(Timer.DRAW_SCENE); renderState.setDefaults(); renderState.drawFramebuffer.set(plugin.fboScene); @@ -745,6 +744,7 @@ private void scenePass() { renderState.depthFunc.set(GL_GEQUAL); renderState.blendFunc.set(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); renderState.ido.set(indirectDrawCmds); + renderState.program.set(sceneProgram); renderState.apply(); // Render the scene From 3abbc072a87fa67245eb10e737f4564ee4f28253 Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 05:52:45 +0000 Subject: [PATCH 10/16] Sync --- src/main/java/rs117/hd/HdPlugin.java | 2 +- src/main/java/rs117/hd/opengl/GLState.java | 8 +-- .../java/rs117/hd/renderer/zone/Zone.java | 2 +- .../rs117/hd/renderer/zone/ZoneRenderer.java | 3 +- src/main/java/rs117/hd/utils/RenderState.java | 49 ++++++++++--------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index f4e41fa442..d8689bc64c 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -572,7 +572,7 @@ protected void startUp() { INTEL_GPU = glRenderer.contains("Intel"); NVIDIA_GPU = glRenderer.toLowerCase().contains("nvidia"); - SUPPORTS_INDIRECT_DRAW = false; //NVIDIA_GPU && !APPLE || config.forceIndirectDraw(); + SUPPORTS_INDIRECT_DRAW = false; //NVIDIA_GPU && !APPLE || config.forceIndirectDraw(); TODO: This isn't working at the moment, not sure why just yet renderer = config.legacyRenderer() ? injector.getInstance(LegacyRenderer.class) : diff --git a/src/main/java/rs117/hd/opengl/GLState.java b/src/main/java/rs117/hd/opengl/GLState.java index 73e3ca2488..4008bd4318 100644 --- a/src/main/java/rs117/hd/opengl/GLState.java +++ b/src/main/java/rs117/hd/opengl/GLState.java @@ -22,14 +22,8 @@ public void apply() { } } - public void setDefault() { - if (hasApplied) - applyDefault(); - } - - abstract void internalApply(); - protected abstract void applyDefault(); + public abstract void setDefault(); public abstract static class Bool extends GLState { private boolean value; diff --git a/src/main/java/rs117/hd/renderer/zone/Zone.java b/src/main/java/rs117/hd/renderer/zone/Zone.java index 1ffb601c86..261a525d7e 100644 --- a/src/main/java/rs117/hd/renderer/zone/Zone.java +++ b/src/main/java/rs117/hd/renderer/zone/Zone.java @@ -70,7 +70,7 @@ public class Zone { .edit(ArrayField.VERTEX_FIELD_3).enabled().component(ComponentType.R).format(FormatType.INT).stride(VERT_SIZE).offset(20).asInteger() // Meta Data .edit(ArrayField.VERTEX_FIELD_6).enabled().component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(0).asInteger().divisor(1) - .edit(ArrayField.VERTEX_FIELD_7).enabled().component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(4).asInteger().divisor(1) + .edit(ArrayField.VERTEX_FIELD_7).enabled().component(ComponentType.RG).format(FormatType.INT).stride(METADATA_SIZE).offset(4).asInteger().divisor(1) .finish(); public static final int LEVEL_WATER_SURFACE = 4; diff --git a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java index a597d31baf..66f5e7affd 100644 --- a/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java +++ b/src/main/java/rs117/hd/renderer/zone/ZoneRenderer.java @@ -702,9 +702,9 @@ private void directionalShadowPass() { glClear(GL_DEPTH_BUFFER_BIT); renderState.depthTest.set(true); + renderState.depthMask.set(true); renderState.cullFace.set(false); renderState.depthFunc.set(GL_LEQUAL); - renderState.program.set(sceneProgram); CommandBuffer.SKIP_DEPTH_MASKING = true; directionalCmd.execute(); @@ -741,6 +741,7 @@ private void scenePass() { renderState.blend.set(true); renderState.cullFace.set(true); renderState.depthTest.set(true); + renderState.depthMask.set(true); renderState.depthFunc.set(GL_GEQUAL); renderState.blendFunc.set(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); renderState.ido.set(indirectDrawCmds); diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index 9b98cf0719..a7b9714673 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -30,10 +30,10 @@ public final class RenderState { public final GLDepthFunc depthFunc = addState(GLDepthFunc::new); public final GLColorMask colorMask = addState(GLColorMask::new); public final GLBlendFunc blendFunc = addState(GLBlendFunc::new); - public final GLToggle blend = new GLToggle(GL_BLEND, false); // TODO: Verify the default GL STATE + public final GLToggle blend = new GLToggle(GL_BLEND, false); public final GLToggle cullFace = new GLToggle(GL_CULL_FACE, true); public final GLToggle depthTest = new GLToggle(GL_DEPTH_TEST, false); - public final GLToggle multisample = new GLToggle(GL_DEPTH_TEST, false); + public final GLToggle multisample = new GLToggle(GL_MULTISAMPLE, false); public void apply() { for (GLState state : states) @@ -61,7 +61,7 @@ public static class GLBindFramebuffer extends GLState.Int { protected void applyValue(int value) { glBindFramebuffer(GL_FRAMEBUFFER, value); } @Override - protected void applyDefault() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } + public void setDefault() { set(0); } } public static class GLBindReadFramebuffer extends GLState.Int { @@ -69,7 +69,7 @@ public static class GLBindReadFramebuffer extends GLState.Int { protected void applyValue(int value) { glBindFramebuffer(GL_READ_FRAMEBUFFER, value); } @Override - protected void applyDefault() { glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); } + public void setDefault() { set(0); } } public static class GLBindDrawFramebuffer extends GLState.Int { @@ -77,7 +77,7 @@ public static class GLBindDrawFramebuffer extends GLState.Int { protected void applyValue(int value) { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, value); } @Override - protected void applyDefault() { glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } + public void setDefault() { set(0); } } public static final class GLFramebufferTextureLayer extends GLState.IntArray { @@ -85,11 +85,13 @@ public static final class GLFramebufferTextureLayer extends GLState.IntArray { @Override protected void applyValues(int[] values) { + if(values[0] == 0) + return; glFramebufferTextureLayer(values[0], values[1], values[2], values[3], values[4]); } @Override - protected void applyDefault() { } + public void setDefault() { set(0, 0, 0, 0, 0); } } public static final class GLViewport extends GLState.IntArray { @@ -99,21 +101,27 @@ private GLViewport() { @Override protected void applyValues(int[] values) { glViewport(values[0], values[1], values[2], values[3]); } @Override - protected void applyDefault() { glUseProgram(0); } + public void setDefault() { set(0, 0, 0, 0); } } public static final class GLShaderProgram extends GLState.Object { @Override - protected void applyValue(ShaderProgram program) { program.use(); } + protected void applyValue(ShaderProgram program) { + if(program != null) { + program.use(); + } else { + glUseProgram(0); + } + } @Override - protected void applyDefault() { glUseProgram(0); } + public void setDefault() { set(null); } } public static final class GLDrawBuffer extends GLState.Int { @Override protected void applyValue(int buf) { glDrawBuffer(buf); } @Override - protected void applyDefault() { } + public void setDefault() { } } public static final class GLBindVAO extends GLState.Object { @@ -127,38 +135,35 @@ protected void applyValue(GLVao vao) { } @Override - protected void applyDefault() { - if(getAppliedValue() != null) - getAppliedValue().unbind(); - } + public void setDefault() { set(null); } } public static final class GLBindIDO extends GLState.Object { @Override - protected void applyValue(GLBuffer ido) { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ido.id); } + protected void applyValue(GLBuffer ido) { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, ido != null ? ido.id : 0); } @Override - protected void applyDefault() { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); } + public void setDefault() { set(null); } } public static final class GLBindUBO extends GLState.Int { @Override protected void applyValue(int ubo) { glBindBuffer(GL_UNIFORM_BUFFER, ubo); } @Override - protected void applyDefault() { glBindBuffer(GL_UNIFORM_BUFFER, 0); } + public void setDefault() { set(0); } } public static final class GLDepthMask extends GLState.Bool { @Override protected void applyValue(boolean enabled) { glDepthMask(enabled); } @Override - protected void applyDefault() { glDepthMask(false); } + public void setDefault() { set(false); } } public static final class GLDepthFunc extends GLState.Int { @Override protected void applyValue(int func) { glDepthFunc(func); } @Override - protected void applyDefault() { glDepthFunc(GL_LESS); } + public void setDefault() { set(GL_LESS); } } public static final class GLBlendFunc extends GLState.IntArray { @@ -169,7 +174,7 @@ private GLBlendFunc() { @Override protected void applyValues(int[] values) { glBlendFuncSeparate(values[0], values[1], values[2], values[3]); } @Override - protected void applyDefault() { glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); } + public void setDefault() { set(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO); } } public static final class GLColorMask extends GLState.BoolArray { @@ -180,7 +185,7 @@ private GLColorMask() { @Override protected void applyValues(boolean[] values) { glColorMask(values[0], values[1], values[2], values[3]); } @Override - protected void applyDefault() { glColorMask(true, true, true, true); } + public void setDefault() { set(true, true, true, true); } } @RequiredArgsConstructor @@ -198,6 +203,6 @@ protected void applyValue(boolean value) { } @Override - protected void applyDefault() { applyValue(defaultState); } + public void setDefault() { set(defaultState); } } } From c62515f04122102443583e98bad926b334a9cd0a Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 05:58:25 +0000 Subject: [PATCH 11/16] Sync --- src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java index 58ac88e6b1..8eeae52c76 100644 --- a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java +++ b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java @@ -47,10 +47,10 @@ class DynamicModelVAO { .edit(ArrayField.VERTEX_FIELD_0).enabled().component(ComponentType.RGB).format(FormatType.FLOAT).stride(VERT_SIZE).offset(0) .edit(ArrayField.VERTEX_FIELD_1).enabled().component(ComponentType.RGB).format(FormatType.HALF_FLOAT).stride(VERT_SIZE).offset(12) .edit(ArrayField.VERTEX_FIELD_2).enabled().component(ComponentType.RGB).format(FormatType.SHORT).stride(VERT_SIZE).offset(18) - .edit(ArrayField.VERTEX_FIELD_3).enabled().asInteger().component(ComponentType.R).format(FormatType.INT).stride(VERT_SIZE).offset(24) + .edit(ArrayField.VERTEX_FIELD_3).enabled().component(ComponentType.R).format(FormatType.INT).stride(VERT_SIZE).offset(24).asInteger() // Meta Data - .edit(ArrayField.VERTEX_FIELD_6).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(0) - .edit(ArrayField.VERTEX_FIELD_7).enabled().asInteger().divisor(1).component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(4) + .edit(ArrayField.VERTEX_FIELD_6).enabled().component(ComponentType.R).format(FormatType.INT).stride(METADATA_SIZE).offset(0).asInteger().divisor(1) + .edit(ArrayField.VERTEX_FIELD_7).enabled().component(ComponentType.RG).format(FormatType.INT).stride(METADATA_SIZE).offset(4).asInteger().divisor(1) .finish(); GLVao vao = new GLVao("DynamicModel::VAO", DYNAMIC_MODEL_VERTEX_LAYOUT); From 64634ce78784feef3cc9c8288cbd97e010352bb7 Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 06:01:28 +0000 Subject: [PATCH 12/16] Sync --- src/main/java/rs117/hd/opengl/GLVao.java | 5 +++++ src/main/java/rs117/hd/renderer/zone/Zone.java | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/rs117/hd/opengl/GLVao.java b/src/main/java/rs117/hd/opengl/GLVao.java index 9228ef5c68..01d647197b 100644 --- a/src/main/java/rs117/hd/opengl/GLVao.java +++ b/src/main/java/rs117/hd/opengl/GLVao.java @@ -108,6 +108,11 @@ private void ensureBuilt() { "ArrayField: {} is enabled but no buffer is associated, expect erroneous behaviour", GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] ); + } else if(arrayBuffer.target != GL_ARRAY_BUFFER) { + log.warn( + "ArrayField: {} is enabled but buffer is not an array buffer, expect erroneous behaviour", + GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] + ); } if(prevBufferId != arrayBufferId) { diff --git a/src/main/java/rs117/hd/renderer/zone/Zone.java b/src/main/java/rs117/hd/renderer/zone/Zone.java index 261a525d7e..f51fc9a70e 100644 --- a/src/main/java/rs117/hd/renderer/zone/Zone.java +++ b/src/main/java/rs117/hd/renderer/zone/Zone.java @@ -126,11 +126,10 @@ public void initialize(GLBuffer o, GLBuffer a, GLTextureBuffer f) { opaqueVao = new GLVao("Zone::Opaque::VAO", ZONE_VERTEX_LAYOUT); opaqueVao.associateBufferRange(vboO, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_3); opaqueVao.associateBufferRange(vboM, ArrayField.VERTEX_FIELD_6, ArrayField.VERTEX_FIELD_7); - opaqueVao.associateBuffer(eboAlpha, ArrayField.ELEMENT_BUFFER); } if ((vboA = a) != null) { - alphaVao = new GLVao("Zone::Opaque::VAO", ZONE_VERTEX_LAYOUT); + alphaVao = new GLVao("Zone::Alpha::VAO", ZONE_VERTEX_LAYOUT); alphaVao.associateBufferRange(vboA, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_3); alphaVao.associateBufferRange(vboM, ArrayField.VERTEX_FIELD_6, ArrayField.VERTEX_FIELD_7); alphaVao.associateBuffer(eboAlpha, ArrayField.ELEMENT_BUFFER); From 9ccc1c6a07ee3dd884055f36abff13ad7b43d52c Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 06:09:24 +0000 Subject: [PATCH 13/16] Sync --- src/main/java/rs117/hd/utils/RenderState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index a7b9714673..422ae1d8aa 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -156,7 +156,7 @@ public static final class GLDepthMask extends GLState.Bool { @Override protected void applyValue(boolean enabled) { glDepthMask(enabled); } @Override - public void setDefault() { set(false); } + public void setDefault() { set(true); } } public static final class GLDepthFunc extends GLState.Int { From d85ef96bfeda23ad9fadd896b3335ce0622fae11 Mon Sep 17 00:00:00 2001 From: Hooder Date: Sun, 1 Mar 2026 12:21:38 +0100 Subject: [PATCH 14/16] Reformat --- src/main/java/rs117/hd/HdPlugin.java | 55 ++++++++------ src/main/java/rs117/hd/opengl/GLVao.java | 73 ++++++++++--------- .../java/rs117/hd/opengl/GLVertexLayout.java | 19 ++--- .../java/rs117/hd/renderer/zone/Zone.java | 10 +-- src/main/java/rs117/hd/utils/RenderState.java | 13 ++-- 5 files changed, 88 insertions(+), 82 deletions(-) diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index d8689bc64c..0a58d067a0 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -1026,45 +1026,54 @@ public void recompilePrograms() { } private void initializeVaos() { - try(MemoryStack stack = MemoryStack.stackPush()) - { + try (MemoryStack stack = MemoryStack.stackPush()) { quadVao = new GLVao("FullscreenQuad::VAO", FULLSCREEN_VERTEX_LAYOUT); quadVao.setBufferRange( new GLBuffer("FullscreenQuad::VBO", GL_ARRAY_BUFFER, GL_STATIC_DRAW) .initialize() - .upload( - stack.mallocFloat(16) - .put(new float[] { - // x, y, u, v - 1, 1, 1, 1, // top right - -1, 1, 0, 1, // top left - -1, -1, 0, 0, // bottom left - 1, -1, 1, 0 // bottom right - }).flip() - ), true, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_1); + .upload(stack + .mallocFloat(16) + .put(new float[] { + // x, y, u, v + 1, 1, 1, 1, // top right + -1, 1, 0, 1, // top left + -1, -1, 0, 0, // bottom left + 1, -1, 1, 0 // bottom right + }) + .flip() + ), + true, + ArrayField.VERTEX_FIELD_0, + ArrayField.VERTEX_FIELD_1 + ); triVao = new GLVao("FullscreenQuad::VAO", FULLSCREEN_VERTEX_LAYOUT); triVao.setBufferRange( new GLBuffer("FullscreenQuad::VBO", GL_ARRAY_BUFFER, GL_STATIC_DRAW) .initialize() - .upload( - stack.mallocFloat(16) - .put(new float[] { - // x, y, u, v - -1, -1, 0, 0, // bottom left - 3, -1, 2, 0, // bottom right (off-screen) - -1, 3, 0, 2 // top left (off-screen) - }).flip() - ), true, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_1); + .upload(stack + .mallocFloat(16) + .put(new float[] { + // x, y, u, v + -1, -1, 0, 0, // bottom left + 3, -1, 2, 0, // bottom right (off-screen) + -1, 3, 0, 2 // top left (off-screen) + }) + .flip() + ), + true, + ArrayField.VERTEX_FIELD_0, + ArrayField.VERTEX_FIELD_1 + ); } } private void destroyVaos() { - if(quadVao != null) + if (quadVao != null) quadVao.destroy(); quadVao = null; - if(triVao != null) + if (triVao != null) triVao.destroy(); triVao = null; } diff --git a/src/main/java/rs117/hd/opengl/GLVao.java b/src/main/java/rs117/hd/opengl/GLVao.java index 01d647197b..5c9a2f1a09 100644 --- a/src/main/java/rs117/hd/opengl/GLVao.java +++ b/src/main/java/rs117/hd/opengl/GLVao.java @@ -4,14 +4,6 @@ import lombok.extern.slf4j.Slf4j; import rs117.hd.utils.buffer.GLBuffer; -import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER; -import static org.lwjgl.opengl.GL15.glBindBuffer; -import static org.lwjgl.opengl.GL15C.GL_ELEMENT_ARRAY_BUFFER; -import static org.lwjgl.opengl.GL20.glVertexAttribPointer; -import static org.lwjgl.opengl.GL20C.glDisableVertexAttribArray; -import static org.lwjgl.opengl.GL30C.glBindVertexArray; -import static org.lwjgl.opengl.GL30C.glGenVertexArrays; -import static org.lwjgl.opengl.GL30C.glVertexAttribIPointer; import static org.lwjgl.opengl.GL33C.*; import static rs117.hd.HdPlugin.checkGLErrors; @@ -35,7 +27,7 @@ public void setBuffer(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.Arr } public void setBufferRange(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField start, GLVertexLayout.ArrayField end) { - for(int i = start.ordinal(); i <= end.ordinal(); i++) { + for (int i = start.ordinal(); i <= end.ordinal(); i++) { buffers[i] = buffer; ownership[i] = takeOwnership; } @@ -43,38 +35,44 @@ public void setBufferRange(GLBuffer buffer, boolean takeOwnership, GLVertexLayou } public void setBuffers(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField... fields) { - for(int i = 0; i < fields.length; i++) { + for (int i = 0; i < fields.length; i++) { buffers[fields[i].ordinal()] = buffer; ownership[fields[i].ordinal()] = takeOwnership; } layoutVersion = -1; } - public void associateBuffer(GLBuffer buffer, GLVertexLayout.ArrayField field) { setBuffer(buffer, false, field); } + public void associateBuffer(GLBuffer buffer, GLVertexLayout.ArrayField field) { + setBuffer(buffer, false, field); + } - public void associateBuffers(GLBuffer buffer, GLVertexLayout.ArrayField... fields) { setBuffers(buffer, false, fields); } + public void associateBuffers(GLBuffer buffer, GLVertexLayout.ArrayField... fields) { + setBuffers(buffer, false, fields); + } - public void associateBufferRange(GLBuffer buffer, GLVertexLayout.ArrayField start, GLVertexLayout.ArrayField end) { setBufferRange(buffer, false, start, end); } + public void associateBufferRange(GLBuffer buffer, GLVertexLayout.ArrayField start, GLVertexLayout.ArrayField end) { + setBufferRange(buffer, false, start, end); + } public void remove(GLBuffer buffer) { boolean found = false; - for(int i = 0; i < buffers.length; i++) { + for (int i = 0; i < buffers.length; i++) { GLBuffer b = buffers[i]; - if(b == buffer) { + if (b == buffer) { buffers[i] = null; ownership[i] = false; found = true; } } - if(found) + if (found) layoutVersion = -1; } public void bind() { - if(previousVao != null && previousVao != this) + if (previousVao != null && previousVao != this) log.warn("Binding VAO: {} when it was already bound by: {}", name, previousVao.name); - if(glVAO == 0) + if (glVAO == 0) glVAO = glGenVertexArrays(); glBindVertexArray(glVAO); @@ -84,51 +82,58 @@ public void bind() { final GLBuffer eboBuffer = buffers[GLVertexLayout.ArrayField.ELEMENT_BUFFER.ordinal()]; final int newEboValue = eboBuffer != null ? eboBuffer.id : 0; - if(glBoundEBO != newEboValue) + if (glBoundEBO != newEboValue) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO = newEboValue); } private void ensureBuilt() { - if(layoutVersion == layout.getVersion()) + if (layoutVersion == layout.getVersion()) return; GLVertexLayout.Attribute[] attributes = layout.getAttributes(); int prevBufferId = 0; - for(int i = 0; i < attributes.length; i++) { + for (int i = 0; i < attributes.length; i++) { final GLVertexLayout.Attribute attrib = attributes[i]; - if(!attrib.isEnabled) { + if (!attrib.isEnabled) { glDisableVertexAttribArray(i); continue; } final GLBuffer arrayBuffer = buffers[i + 1]; final int arrayBufferId = arrayBuffer != null ? arrayBuffer.id : 0; - if(arrayBuffer == null) { + if (arrayBuffer == null) { log.warn( "ArrayField: {} is enabled but no buffer is associated, expect erroneous behaviour", GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] ); - } else if(arrayBuffer.target != GL_ARRAY_BUFFER) { + } else if (arrayBuffer.target != GL_ARRAY_BUFFER) { log.warn( "ArrayField: {} is enabled but buffer is not an array buffer, expect erroneous behaviour", GLVertexLayout.ARRAY_FIELD_NAMES[i + 1] ); } - if(prevBufferId != arrayBufferId) { + if (prevBufferId != arrayBufferId) { glBindBuffer(GL_ARRAY_BUFFER, arrayBufferId); prevBufferId = arrayBufferId; } glEnableVertexAttribArray(i); - if(attrib.divisor > 0) + if (attrib.divisor > 0) glVertexAttribDivisor(i, attrib.divisor); - if(attrib.isInteger) { + if (attrib.isInteger) { assert attrib.format.ordinal() >= GLVertexLayout.FormatType.INT.ordinal(); glVertexAttribIPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.stride, attrib.offset); } else { - glVertexAttribPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.isNormalized, attrib.stride, attrib.offset); + glVertexAttribPointer( + i, + attrib.component.size, + attrib.format.glFormatType, + attrib.isNormalized, + attrib.stride, + attrib.offset + ); } } @@ -142,25 +147,25 @@ private void ensureBuilt() { } public void unbind() { - if(previousVao != null && previousVao != this) + if (previousVao != null && previousVao != this) log.warn("Unbinding VAO: {} when it was bound by: {}", name, previousVao.name); glBindVertexArray(0); - if(glBoundEBO != 0) + if (glBoundEBO != 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO); previousVao = null; } public void destroy() { - if(glVAO != 0) { + if (glVAO != 0) { glDeleteVertexArrays(glVAO); glVAO = 0; } - for(int i = 0; i < buffers.length; i++) { - if(buffers[i] == null) + for (int i = 0; i < buffers.length; i++) { + if (buffers[i] == null) continue; - if(ownership[i]) + if (ownership[i]) buffers[i].destroy(); buffers[i] = null; } diff --git a/src/main/java/rs117/hd/opengl/GLVertexLayout.java b/src/main/java/rs117/hd/opengl/GLVertexLayout.java index 01ac3e36f7..2815a100e2 100644 --- a/src/main/java/rs117/hd/opengl/GLVertexLayout.java +++ b/src/main/java/rs117/hd/opengl/GLVertexLayout.java @@ -5,15 +5,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import static org.lwjgl.opengl.GL11.GL_BYTE; -import static org.lwjgl.opengl.GL11.GL_DOUBLE; -import static org.lwjgl.opengl.GL11.GL_FLOAT; -import static org.lwjgl.opengl.GL11.GL_INT; -import static org.lwjgl.opengl.GL11.GL_SHORT; -import static org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE; -import static org.lwjgl.opengl.GL11.GL_UNSIGNED_INT; -import static org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT; -import static org.lwjgl.opengl.GL30.GL_HALF_FLOAT; +import static org.lwjgl.opengl.GL33C.*; @Slf4j public class GLVertexLayout { @@ -30,7 +22,7 @@ public class GLVertexLayout { public GLVertexLayout(String name) { this.name = name; - for(int i = 0; i < MAX_ATTRIBUTES; i++) + for (int i = 0; i < MAX_ATTRIBUTES; i++) attributes[i] = new Attribute(); } @@ -100,10 +92,10 @@ public GLVertexLayout finish() { public String toString() { StringBuilder str = new StringBuilder(); str.append("\nGLVertexLayout - ").append(name).append(" - Version: ").append(version).append("\n"); - for(int i = 0; i < MAX_ATTRIBUTES; i++) { + for (int i = 0; i < MAX_ATTRIBUTES; i++) { Attribute attr = attributes[i]; str.append(" * ARRAY_FIELD_").append(i).append(": "); - if(attr.isEnabled) { + if (attr.isEnabled) { str.append("ENABLED, isInteger: ") .append(attr.isInteger) .append(", isNormalized: ") @@ -165,7 +157,8 @@ public enum FormatType { UNSIGNED_INT(GL_UNSIGNED_INT), UNSIGNED_SHORT(GL_UNSIGNED_SHORT), BYTE(GL_BYTE), - UNSIGNED_BYTE(GL_UNSIGNED_BYTE),; + UNSIGNED_BYTE(GL_UNSIGNED_BYTE), + ; public final int glFormatType; } diff --git a/src/main/java/rs117/hd/renderer/zone/Zone.java b/src/main/java/rs117/hd/renderer/zone/Zone.java index f51fc9a70e..6bf87466d1 100644 --- a/src/main/java/rs117/hd/renderer/zone/Zone.java +++ b/src/main/java/rs117/hd/renderer/zone/Zone.java @@ -169,14 +169,14 @@ public void free() { tboF = null; } - if(opaqueVao != null) { + if (opaqueVao != null) { opaqueVao.destroy(); - opaqueVao = null; + opaqueVao = null; } - if(alphaVao != null) { - alphaVao.destroy(); - alphaVao = null; + if (alphaVao != null) { + alphaVao.destroy(); + alphaVao = null; } if (uploadJob != null) { diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index 422ae1d8aa..cf08ae0e35 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -9,7 +9,6 @@ import rs117.hd.opengl.shader.ShaderProgram; import rs117.hd.utils.buffer.GLBuffer; -import static org.lwjgl.opengl.GL20C.glUseProgram; import static org.lwjgl.opengl.GL33C.*; import static org.lwjgl.opengl.GL40.GL_DRAW_INDIRECT_BUFFER; @@ -85,7 +84,7 @@ public static final class GLFramebufferTextureLayer extends GLState.IntArray { @Override protected void applyValues(int[] values) { - if(values[0] == 0) + if (values[0] == 0) return; glFramebufferTextureLayer(values[0], values[1], values[2], values[3], values[4]); } @@ -107,7 +106,7 @@ private GLViewport() { public static final class GLShaderProgram extends GLState.Object { @Override protected void applyValue(ShaderProgram program) { - if(program != null) { + if (program != null) { program.use(); } else { glUseProgram(0); @@ -121,16 +120,16 @@ public static final class GLDrawBuffer extends GLState.Int { @Override protected void applyValue(int buf) { glDrawBuffer(buf); } @Override - public void setDefault() { } + public void setDefault() {} } public static final class GLBindVAO extends GLState.Object { @Override protected void applyValue(GLVao vao) { - if(getAppliedValue() != null) + if (getAppliedValue() != null) getAppliedValue().unbind(); - if(vao != null) + if (vao != null) vao.bind(); } @@ -195,7 +194,7 @@ public static final class GLToggle extends GLState.Bool { @Override protected void applyValue(boolean value) { - if(value) { + if (value) { glEnable(target); } else { glDisable(target); From 6050bbf23eafcc2fa0d14bcbf8752c4f1f8235ea Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Sun, 1 Mar 2026 17:23:10 +0000 Subject: [PATCH 15/16] Fixed Renderstate --- src/main/java/rs117/hd/opengl/GLState.java | 68 +++++++++++-------- src/main/java/rs117/hd/utils/RenderState.java | 52 ++++++++------ 2 files changed, 74 insertions(+), 46 deletions(-) diff --git a/src/main/java/rs117/hd/opengl/GLState.java b/src/main/java/rs117/hd/opengl/GLState.java index 4008bd4318..6f095827ff 100644 --- a/src/main/java/rs117/hd/opengl/GLState.java +++ b/src/main/java/rs117/hd/opengl/GLState.java @@ -1,9 +1,7 @@ package rs117.hd.opengl; import java.util.Arrays; -import java.util.HashSet; import java.util.Objects; -import java.util.Set; import lombok.Getter; public abstract class GLState { @@ -25,6 +23,10 @@ public void apply() { abstract void internalApply(); public abstract void setDefault(); + public void printState(StringBuffer sb) { + sb.append(getClass().getSimpleName()).append(": ").append(hasApplied ? "applied " : " "); + } + public abstract static class Bool extends GLState { private boolean value; private boolean appliedValue; @@ -43,6 +45,12 @@ void internalApply() { } protected abstract void applyValue(boolean value); + + @Override + public void printState(StringBuffer sb) { + super.printState(sb); + sb.append("(").append(appliedValue).append(") \n"); + } } public abstract static class Int extends GLState { @@ -63,6 +71,12 @@ void internalApply() { } protected abstract void applyValue(int value); + + @Override + public void printState(StringBuffer sb) { + super.printState(sb); + sb.append("(").append(appliedValue).append(") \n"); + } } public abstract static class Object extends GLState { @@ -84,6 +98,12 @@ void internalApply() { } protected abstract void applyValue(T value); + + @Override + public void printState(StringBuffer sb) { + super.printState(sb); + sb.append("(").append(appliedValue).append(") \n"); + } } public abstract static class IntArray extends GLState { @@ -109,6 +129,17 @@ void internalApply() { } protected abstract void applyValues(int[] values); + + @Override + public void printState(StringBuffer sb) { + super.printState(sb); + sb.append("("); + for(int i = 0; i < value.length; i++) { + if(i > 0) sb.append(", "); + sb.append(value[i]); + } + sb.append(") \n"); + } } public abstract static class BoolArray extends GLState { @@ -134,33 +165,16 @@ void internalApply() { } protected abstract void applyValues(boolean[] values); - } - - public abstract static class IntSet extends GLState { - private final Set targets = new HashSet<>(); - - public void add(int target) { - hasValue = true; - targets.add(target); - } - - public void remove(int target) { - targets.remove(target); - hasApplied = !targets.isEmpty(); - } @Override - void internalApply() { - for (int t : targets) applyTarget(t); - targets.clear(); - } - - @Override - public void reset() { - super.reset(); - targets.clear(); + public void printState(StringBuffer sb) { + super.printState(sb); + sb.append("("); + for(int i = 0; i < value.length; i++) { + if(i > 0) sb.append(", "); + sb.append(value[i]); + } + sb.append(") \n"); } - - protected abstract void applyTarget(int target); } } diff --git a/src/main/java/rs117/hd/utils/RenderState.java b/src/main/java/rs117/hd/utils/RenderState.java index cf08ae0e35..31ac1d4e77 100644 --- a/src/main/java/rs117/hd/utils/RenderState.java +++ b/src/main/java/rs117/hd/utils/RenderState.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.function.Supplier; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import rs117.hd.opengl.GLState; import rs117.hd.opengl.GLVao; import rs117.hd.opengl.shader.ShaderProgram; @@ -12,27 +13,28 @@ import static org.lwjgl.opengl.GL33C.*; import static org.lwjgl.opengl.GL40.GL_DRAW_INDIRECT_BUFFER; +@Slf4j public final class RenderState { private final List states = new ArrayList<>(); - public final GLBindFramebuffer framebuffer = addState(GLBindFramebuffer::new); - public final GLBindDrawFramebuffer drawFramebuffer = addState(GLBindDrawFramebuffer::new); - public final GLBindReadFramebuffer readFramebuffer = addState(GLBindReadFramebuffer::new); - public final GLFramebufferTextureLayer framebufferTextureLayer = addState(GLFramebufferTextureLayer::new); - public final GLDrawBuffer drawBuffer = addState(GLDrawBuffer::new); - public final GLShaderProgram program = addState(GLShaderProgram::new); - public final GLViewport viewport = addState(GLViewport::new); - public final GLBindVAO vao = addState(GLBindVAO::new); - public final GLBindIDO ido = addState(GLBindIDO::new); - public final GLBindUBO ubo = addState(GLBindUBO::new); - public final GLDepthMask depthMask = addState(GLDepthMask::new); - public final GLDepthFunc depthFunc = addState(GLDepthFunc::new); - public final GLColorMask colorMask = addState(GLColorMask::new); - public final GLBlendFunc blendFunc = addState(GLBlendFunc::new); - public final GLToggle blend = new GLToggle(GL_BLEND, false); - public final GLToggle cullFace = new GLToggle(GL_CULL_FACE, true); - public final GLToggle depthTest = new GLToggle(GL_DEPTH_TEST, false); - public final GLToggle multisample = new GLToggle(GL_MULTISAMPLE, false); + public final GLBindFramebuffer framebuffer = createState(GLBindFramebuffer::new); + public final GLBindDrawFramebuffer drawFramebuffer = createState(GLBindDrawFramebuffer::new); + public final GLBindReadFramebuffer readFramebuffer = createState(GLBindReadFramebuffer::new); + public final GLFramebufferTextureLayer framebufferTextureLayer = createState(GLFramebufferTextureLayer::new); + public final GLDrawBuffer drawBuffer = createState(GLDrawBuffer::new); + public final GLShaderProgram program = createState(GLShaderProgram::new); + public final GLViewport viewport = createState(GLViewport::new); + public final GLBindVAO vao = createState(GLBindVAO::new); + public final GLBindIDO ido = createState(GLBindIDO::new); + public final GLBindUBO ubo = createState(GLBindUBO::new); + public final GLDepthMask depthMask = createState(GLDepthMask::new); + public final GLDepthFunc depthFunc = createState(GLDepthFunc::new); + public final GLColorMask colorMask = createState(GLColorMask::new); + public final GLBlendFunc blendFunc = createState(GLBlendFunc::new); + public final GLToggle blend = addState(new GLToggle(GL_BLEND, false)); + public final GLToggle cullFace = addState(new GLToggle(GL_CULL_FACE, true)); + public final GLToggle depthTest = addState(new GLToggle(GL_DEPTH_TEST, false)); + public final GLToggle multisample = addState(new GLToggle(GL_MULTISAMPLE, false)); public void apply() { for (GLState state : states) @@ -49,7 +51,19 @@ public void reset() { state.reset(); } - private T addState(Supplier supplier) { + public void printState() { + StringBuffer sb = new StringBuffer(); + for (GLState state : states) + state.printState(sb); + log.debug("GLRenderState:\n{}", sb.toString().trim()); + } + + private T addState(T state) { + states.add(state); + return state; + } + + private T createState(Supplier supplier) { T state = supplier.get(); states.add(state); return state; From 99fa9abb19d7f3ac2efc3b1b31a8a6d117d9d798 Mon Sep 17 00:00:00 2001 From: Ruffled <105522716+RuffledPlume@users.noreply.github.com> Date: Mon, 2 Mar 2026 10:54:28 +0000 Subject: [PATCH 16/16] Sync --- src/main/java/rs117/hd/opengl/GLVao.java | 52 +++++++++++----- .../java/rs117/hd/opengl/GLVertexLayout.java | 60 +++++++++++++++---- .../hd/renderer/zone/DynamicModelVAO.java | 3 +- 3 files changed, 88 insertions(+), 27 deletions(-) diff --git a/src/main/java/rs117/hd/opengl/GLVao.java b/src/main/java/rs117/hd/opengl/GLVao.java index 5c9a2f1a09..bd287f331b 100644 --- a/src/main/java/rs117/hd/opengl/GLVao.java +++ b/src/main/java/rs117/hd/opengl/GLVao.java @@ -15,21 +15,32 @@ public class GLVao { private final String name; private final GLVertexLayout layout; private final GLBuffer[] buffers = new GLBuffer[GLVertexLayout.MAX_ATTRIBUTES]; - private final boolean[] ownership = new boolean[GLVertexLayout.MAX_ATTRIBUTES]; + private final long[] builtData = new long[GLVertexLayout.MAX_ATTRIBUTES]; - private int glVAO, glBoundEBO; + private int glVAO; private int layoutVersion; + private static long packBufferData(int bufferId, boolean owned) { + return ((long) bufferId << 1) | (owned ? 1L : 0L); + } + + private static int unpackBufferId(long data) { + return (int) (data >>> 1); + } + + private static boolean unpackOwnership(long data) { + return (data & 1L) != 0; + } + public void setBuffer(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField field) { buffers[field.ordinal()] = buffer; - ownership[field.ordinal()] = takeOwnership; + // Note: ownership will be stored in builtData during bind/ensureBuilt layoutVersion = -1; } public void setBufferRange(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField start, GLVertexLayout.ArrayField end) { for (int i = start.ordinal(); i <= end.ordinal(); i++) { buffers[i] = buffer; - ownership[i] = takeOwnership; } layoutVersion = -1; } @@ -37,7 +48,6 @@ public void setBufferRange(GLBuffer buffer, boolean takeOwnership, GLVertexLayou public void setBuffers(GLBuffer buffer, boolean takeOwnership, GLVertexLayout.ArrayField... fields) { for (int i = 0; i < fields.length; i++) { buffers[fields[i].ordinal()] = buffer; - ownership[fields[i].ordinal()] = takeOwnership; } layoutVersion = -1; } @@ -60,7 +70,6 @@ public void remove(GLBuffer buffer) { GLBuffer b = buffers[i]; if (b == buffer) { buffers[i] = null; - ownership[i] = false; found = true; } } @@ -82,19 +91,31 @@ public void bind() { final GLBuffer eboBuffer = buffers[GLVertexLayout.ArrayField.ELEMENT_BUFFER.ordinal()]; final int newEboValue = eboBuffer != null ? eboBuffer.id : 0; - if (glBoundEBO != newEboValue) - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO = newEboValue); + final int boundEboId = unpackBufferId(builtData[0]); + if (boundEboId != newEboValue) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, newEboValue); + builtData[0] = packBufferData(newEboValue, false); + } } private void ensureBuilt() { - if (layoutVersion == layout.getVersion()) + boolean hasArrayBuffersChanged = false; + for (int i = 1; i < buffers.length; i++) { + GLBuffer buffer = buffers[i]; + if (buffer != null && buffer.id != unpackBufferId(builtData[i])) { + hasArrayBuffersChanged = true; + break; + } + } + + if (layoutVersion == layout.getVersion() && !hasArrayBuffersChanged) return; GLVertexLayout.Attribute[] attributes = layout.getAttributes(); int prevBufferId = 0; for (int i = 0; i < attributes.length; i++) { final GLVertexLayout.Attribute attrib = attributes[i]; - if (!attrib.isEnabled) { + if (!attrib.isEnabled()) { glDisableVertexAttribArray(i); continue; } @@ -122,7 +143,7 @@ private void ensureBuilt() { if (attrib.divisor > 0) glVertexAttribDivisor(i, attrib.divisor); - if (attrib.isInteger) { + if (attrib.isInteger()) { assert attrib.format.ordinal() >= GLVertexLayout.FormatType.INT.ordinal(); glVertexAttribIPointer(i, attrib.component.size, attrib.format.glFormatType, attrib.stride, attrib.offset); } else { @@ -130,11 +151,12 @@ private void ensureBuilt() { i, attrib.component.size, attrib.format.glFormatType, - attrib.isNormalized, + attrib.isNormalized(), attrib.stride, attrib.offset ); } + builtData[i + 1] = packBufferData(arrayBufferId, false); } glBindVertexArray(0); @@ -150,8 +172,8 @@ public void unbind() { if (previousVao != null && previousVao != this) log.warn("Unbinding VAO: {} when it was bound by: {}", name, previousVao.name); glBindVertexArray(0); - if (glBoundEBO != 0) - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBoundEBO); + if (unpackBufferId(builtData[0]) != 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); previousVao = null; } @@ -165,7 +187,7 @@ public void destroy() { if (buffers[i] == null) continue; - if (ownership[i]) + if (unpackOwnership(builtData[i])) buffers[i].destroy(); buffers[i] = null; } diff --git a/src/main/java/rs117/hd/opengl/GLVertexLayout.java b/src/main/java/rs117/hd/opengl/GLVertexLayout.java index 2815a100e2..0f2be76f45 100644 --- a/src/main/java/rs117/hd/opengl/GLVertexLayout.java +++ b/src/main/java/rs117/hd/opengl/GLVertexLayout.java @@ -33,27 +33,27 @@ public GLVertexLayout edit(ArrayField field) { } public GLVertexLayout enabled() { - attributes[editIdx].isEnabled = true; + attributes[editIdx].setEnabled(true); return this; } public GLVertexLayout disabled() { - attributes[editIdx].isEnabled = false; + attributes[editIdx].setEnabled(false); return this; } public GLVertexLayout normalized(boolean isNormalized) { - attributes[editIdx].isNormalized = isNormalized; + attributes[editIdx].setNormalized(isNormalized); return this; } public GLVertexLayout asFloat() { - attributes[editIdx].isInteger = false; + attributes[editIdx].setInteger(false); return this; } public GLVertexLayout asInteger() { - attributes[editIdx].isInteger = true; + attributes[editIdx].setInteger(true); return this; } @@ -95,11 +95,11 @@ public String toString() { for (int i = 0; i < MAX_ATTRIBUTES; i++) { Attribute attr = attributes[i]; str.append(" * ARRAY_FIELD_").append(i).append(": "); - if (attr.isEnabled) { + if (attr.isEnabled()) { str.append("ENABLED, isInteger: ") - .append(attr.isInteger) + .append(attr.isInteger()) .append(", isNormalized: ") - .append(attr.isNormalized) + .append(attr.isNormalized()) .append(", component: ") .append(attr.component) .append(", format: ") @@ -164,14 +164,52 @@ public enum FormatType { } public static final class Attribute { + private static final byte FLAG_ENABLED = 1 << 0; + private static final byte FLAG_INTEGER = 1 << 1; + private static final byte FLAG_NORMALIZED = 1 << 2; + public ComponentType component; public FormatType format; public int stride; public int divisor; public long offset; - public boolean isEnabled; - public boolean isInteger; // TODO: Turn into Flags - public boolean isNormalized; + private byte flags; + + public boolean isEnabled() { + return (flags & FLAG_ENABLED) != 0; + } + + public void setEnabled(boolean enabled) { + if (enabled) { + flags |= FLAG_ENABLED; + } else { + flags &= ~FLAG_ENABLED; + } + } + + public boolean isInteger() { + return (flags & FLAG_INTEGER) != 0; + } + + public void setInteger(boolean integer) { + if (integer) { + flags |= FLAG_INTEGER; + } else { + flags &= ~FLAG_INTEGER; + } + } + + public boolean isNormalized() { + return (flags & FLAG_NORMALIZED) != 0; + } + + public void setNormalized(boolean normalized) { + if (normalized) { + flags |= FLAG_NORMALIZED; + } else { + flags &= ~FLAG_NORMALIZED; + } + } } } diff --git a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java index 8eeae52c76..4890b1611f 100644 --- a/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java +++ b/src/main/java/rs117/hd/renderer/zone/DynamicModelVAO.java @@ -53,7 +53,7 @@ class DynamicModelVAO { .edit(ArrayField.VERTEX_FIELD_7).enabled().component(ComponentType.RG).format(FormatType.INT).stride(METADATA_SIZE).offset(4).asInteger().divisor(1) .finish(); - GLVao vao = new GLVao("DynamicModel::VAO", DYNAMIC_MODEL_VERTEX_LAYOUT); + GLVao vao; boolean used; private final GLBuffer vboRender; @@ -106,6 +106,7 @@ void initialize() { if (vboRender != vboStaging) { vboStaging.initialize(INITIAL_SIZE); } + vao = new GLVao("DynamicModel::VAO", DYNAMIC_MODEL_VERTEX_LAYOUT); vao.associateBufferRange(vboRender, ArrayField.VERTEX_FIELD_0, ArrayField.VERTEX_FIELD_3); }