From 2520da4dcaea009142926376665d18bbe502c789 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 1 Mar 2022 22:02:44 -0500 Subject: [PATCH] gpu: move texture animation to gpu --- .../client/plugins/gpu/GpuPlugin.java | 38 ++++---- .../client/plugins/gpu/TextureManager.java | 91 +++++++------------ .../net/runelite/client/plugins/gpu/frag.glsl | 5 +- .../net/runelite/client/plugins/gpu/vert.glsl | 19 +++- 4 files changed, 66 insertions(+), 87 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index 96c992f2da..23e2f4fe46 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -223,7 +223,6 @@ public class GpuPlugin extends Plugin implements DrawCallbacks private int textureArrayId; private final GLBuffer uniformBuffer = new GLBuffer(); - private final float[] textureOffsets = new float[256]; private GpuIntBuffer vertexBuffer; private GpuFloatBuffer uvBuffer; @@ -291,12 +290,13 @@ public class GpuPlugin extends Plugin implements DrawCallbacks private int uniTexTargetDimensions; private int uniUiAlphaOverlay; private int uniTextures; - private int uniTextureOffsets; + private int uniTextureAnimations; private int uniBlockSmall; private int uniBlockLarge; private int uniBlockMain; private int uniSmoothBanding; private int uniTextureLightMode; + private int uniTick; private int needsReset; @@ -665,6 +665,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks uniDrawDistance = gl.glGetUniformLocation(glProgram, "drawDistance"); uniColorBlindMode = gl.glGetUniformLocation(glProgram, "colorBlindMode"); uniTextureLightMode = gl.glGetUniformLocation(glProgram, "textureLightMode"); + uniTick = gl.glGetUniformLocation(glProgram, "tick"); uniTex = gl.glGetUniformLocation(glUiProgram, "tex"); uniTexSamplingMode = gl.glGetUniformLocation(glUiProgram, "samplingMode"); @@ -673,7 +674,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks uniUiColorBlindMode = gl.glGetUniformLocation(glUiProgram, "colorBlindMode"); uniUiAlphaOverlay = gl.glGetUniformLocation(glUiProgram, "alphaOverlay"); uniTextures = gl.glGetUniformLocation(glProgram, "textures"); - uniTextureOffsets = gl.glGetUniformLocation(glProgram, "textureOffsets"); + uniTextureAnimations = gl.glGetUniformLocation(glProgram, "textureAnimations"); uniBlockSmall = gl.glGetUniformBlockIndex(glSmallComputeProgram, "uniforms"); uniBlockLarge = gl.glGetUniformBlockIndex(glComputeProgram, "uniforms"); @@ -1222,18 +1223,25 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glClear(gl.GL_COLOR_BUFFER_BIT); // Draw 3d scene - final TextureProvider textureProvider = client.getTextureProvider(); final GameState gameState = client.getGameState(); - if (textureProvider != null && gameState.getState() >= GameState.LOADING.getState()) + if (gameState.getState() >= GameState.LOADING.getState()) { + final TextureProvider textureProvider = client.getTextureProvider(); if (textureArrayId == -1) { // lazy init textures as they may not be loaded at plugin start. // this will return -1 and retry if not all textures are loaded yet, too. textureArrayId = textureManager.initTextureArray(textureProvider, gl); + if (textureArrayId > -1) + { + // if texture upload is successful, compute and set texture animations + float[] texAnims = textureManager.computeTextureAnimations(textureProvider); + gl.glUseProgram(glProgram); + gl.glUniform2fv(uniTextureAnimations, texAnims.length, texAnims, 0); + gl.glUseProgram(0); + } } - final Texture[] textures = textureProvider.getTextures(); int renderWidthOff = viewportOffsetX; int renderHeightOff = viewportOffsetY; int renderCanvasHeight = canvasHeight; @@ -1285,6 +1293,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks gl.glUniform1f(uniSmoothBanding, config.smoothBanding() ? 0f : 1f); gl.glUniform1i(uniColorBlindMode, config.colorBlindMode().ordinal()); gl.glUniform1f(uniTextureLightMode, config.brightTextures() ? 1f : 0f); + gl.glUniform1i(uniTick, client.getGameCycle()); // Calculate projection matrix Matrix4 projectionMatrix = new Matrix4(); @@ -1295,24 +1304,9 @@ public class GpuPlugin extends Plugin implements DrawCallbacks projectionMatrix.translate(-client.getCameraX2(), -client.getCameraY2(), -client.getCameraZ2()); gl.glUniformMatrix4fv(uniProjectionMatrix, 1, false, projectionMatrix.getMatrix(), 0); - for (int id = 0; id < textures.length; ++id) - { - Texture texture = textures[id]; - if (texture == null) - { - continue; - } - - textureProvider.load(id); // trips the texture load flag which lets textures animate - - textureOffsets[id * 2] = texture.getU(); - textureOffsets[id * 2 + 1] = texture.getV(); - } - // Bind uniforms gl.glUniformBlockBinding(glProgram, uniBlockMain, 0); gl.glUniform1i(uniTextures, 1); // texture sampler array is bound to texture1 - gl.glUniform2fv(uniTextureOffsets, textureOffsets.length, textureOffsets, 0); // We just allow the GL to do face culling. Note this requires the priority renderer // to have logic to disregard culled faces in the priority depth testing. @@ -1518,7 +1512,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks @Override public void animate(Texture texture, int diff) { - textureManager.animate(texture, diff); + // texture animation happens on gpu } @Subscribe diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java index 351eba2823..00f984f778 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/TextureManager.java @@ -35,9 +35,6 @@ import net.runelite.api.TextureProvider; @Slf4j class TextureManager { - private static final float PERC_64 = 1f / 64f; - private static final float PERC_128 = 1f / 128f; - private static final int TEXTURE_SIZE = 128; int initTextureArray(TextureProvider textureProvider, GL4 gl) @@ -207,64 +204,40 @@ class TextureManager return pixels; } - /** - * Animate the given texture - * - * @param texture - * @param diff Number of elapsed client ticks since last animation - */ - void animate(Texture texture, int diff) + float[] computeTextureAnimations(TextureProvider textureProvider) { - final int[] pixels = texture.getPixels(); - if (pixels == null) + Texture[] textures = textureProvider.getTextures(); + float[] anims = new float[TEXTURE_SIZE * 2]; + int idx = 0; + for (Texture texture : textures) { - return; + if (texture != null) + { + float u = 0f, v = 0f; + switch (texture.getAnimationDirection()) + { + case 1: + v = -1f; + break; + case 3: + v = 1f; + break; + case 2: + u = -1f; + break; + case 4: + u = 1f; + break; + } + + int speed = texture.getAnimationSpeed(); + u *= speed; + v *= speed; + + anims[idx++] = u; + anims[idx++] = v; + } } - - final int animationSpeed = texture.getAnimationSpeed(); - final float uvdiff = pixels.length == 4096 ? PERC_64 : PERC_128; - - float u = texture.getU(); - float v = texture.getV(); - - int offset = animationSpeed * diff; - float d = (float) offset * uvdiff; - - switch (texture.getAnimationDirection()) - { - case 1: - v -= d; - if (v < 0f) - { - v += 1f; - } - break; - case 3: - v += d; - if (v > 1f) - { - v -= 1f; - } - break; - case 2: - u -= d; - if (u < 0f) - { - u += 1f; - } - break; - case 4: - u += d; - if (u > 1f) - { - u -= 1f; - } - break; - default: - return; - } - - texture.setU(u); - texture.setV(v); + return anims; } } diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl index d028c4ce40..8c4b53dec1 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/frag.glsl @@ -25,7 +25,6 @@ #version 330 uniform sampler2DArray textures; -uniform vec2 textureOffsets[128]; uniform float brightness; uniform float smoothBanding; uniform vec4 fogColor; @@ -49,9 +48,7 @@ void main() { if (textureId > 0) { int textureIdx = textureId - 1; - vec2 animatedUv = fUv + textureOffsets[textureIdx]; - - vec4 textureColor = texture(textures, vec3(animatedUv, float(textureIdx))); + vec4 textureColor = texture(textures, vec3(fUv, float(textureIdx))); vec4 textureColorBrightness = pow(textureColor, vec4(brightness, brightness, brightness, 1.0f)); // textured triangles hsl is a 7 bit lightness 2-126 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl index 0b161a1149..6e19adfdb9 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/gpu/vert.glsl @@ -27,6 +27,10 @@ #define TILE_SIZE 128 +// smallest unit of the texture which can be moved per tick. textures are all +// 128x128px - so this is equivalent to +1px +#define TEXTURE_ANIM_UNIT (1.0f / 128.0f) + #define FOG_SCENE_EDGE_MIN TILE_SIZE #define FOG_SCENE_EDGE_MAX (103 * TILE_SIZE) #define FOG_CORNER_ROUNDING 1.5 @@ -52,6 +56,8 @@ uniform int useFog; uniform int fogDepth; uniform int drawDistance; uniform mat4 projectionMatrix; +uniform vec2 textureAnimations[128]; +uniform int tick; out vec4 Color; noperspective centroid out float fHsl; @@ -77,8 +83,17 @@ void main() gl_Position = projectionMatrix * vec4(vertex, 1.f); Color = vec4(rgb, 1.f - a); fHsl = float(hsl); - textureId = int(uv.x); - fUv = uv.yz; + + int textureIdx = int(uv.x); // the texture id + 1 + vec2 textureUv = uv.yz; + + vec2 textureAnim = vec2(0); + if (textureIdx > 0) { + textureAnim = textureAnimations[textureIdx - 1]; + } + + textureId = textureIdx; + fUv = textureUv + tick * textureAnim * TEXTURE_ANIM_UNIT; int fogWest = max(FOG_SCENE_EDGE_MIN, cameraX - drawDistance); int fogEast = min(FOG_SCENE_EDGE_MAX, cameraX + drawDistance - TILE_SIZE);