From 3bb42522b87d54c585e655cfb7d72668164a154a Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 23 Oct 2023 19:07:55 +0100 Subject: [PATCH] Pack vertex attributes and palette into a single integer bitfield. --- OpenRA.Game/Graphics/RgbaColorRenderer.cs | 34 +++--- OpenRA.Game/Graphics/TerrainSpriteLayer.cs | 7 +- OpenRA.Game/Graphics/Util.cs | 12 +- OpenRA.Game/Graphics/Vertex.cs | 22 ++-- glsl/combined.frag | 115 ++++++++++-------- glsl/combined.vert | 134 +++++++-------------- 6 files changed, 143 insertions(+), 181 deletions(-) diff --git a/OpenRA.Game/Graphics/RgbaColorRenderer.cs b/OpenRA.Game/Graphics/RgbaColorRenderer.cs index 6927b39f0f..d9a4436cb6 100644 --- a/OpenRA.Game/Graphics/RgbaColorRenderer.cs +++ b/OpenRA.Game/Graphics/RgbaColorRenderer.cs @@ -45,10 +45,10 @@ namespace OpenRA.Graphics var eb = endColor.B / 255.0f; var ea = endColor.A / 255.0f; - vertices[0] = new Vertex(start - corner + Offset, sr, sg, sb, sa, 0, 0); - vertices[1] = new Vertex(start + corner + Offset, sr, sg, sb, sa, 0, 0); - vertices[2] = new Vertex(end + corner + Offset, er, eg, eb, ea, 0, 0); - vertices[3] = new Vertex(end - corner + Offset, er, eg, eb, ea, 0, 0); + vertices[0] = new Vertex(start - corner + Offset, sr, sg, sb, sa, 0); + vertices[1] = new Vertex(start + corner + Offset, sr, sg, sb, sa, 0); + vertices[2] = new Vertex(end + corner + Offset, er, eg, eb, ea, 0); + vertices[3] = new Vertex(end - corner + Offset, er, eg, eb, ea, 0); parent.DrawRGBAQuad(vertices, blendMode); } @@ -64,10 +64,10 @@ namespace OpenRA.Graphics var b = color.B / 255.0f; var a = color.A / 255.0f; - vertices[0] = new Vertex(start - corner + Offset, r, g, b, a, 0, 0); - vertices[1] = new Vertex(start + corner + Offset, r, g, b, a, 0, 0); - vertices[2] = new Vertex(end + corner + Offset, r, g, b, a, 0, 0); - vertices[3] = new Vertex(end - corner + Offset, r, g, b, a, 0, 0); + vertices[0] = new Vertex(start - corner + Offset, r, g, b, a, 0); + vertices[1] = new Vertex(start + corner + Offset, r, g, b, a, 0); + vertices[2] = new Vertex(end + corner + Offset, r, g, b, a, 0); + vertices[3] = new Vertex(end - corner + Offset, r, g, b, a, 0); parent.DrawRGBAQuad(vertices, blendMode); } @@ -153,10 +153,10 @@ namespace OpenRA.Graphics var cd = closed || i < limit - 1 ? IntersectionOf(end - corner, dir, end - nextCorner, nextDir) : end - corner; // Fill segment - vertices[0] = new Vertex(ca + Offset, r, g, b, a, 0, 0); - vertices[1] = new Vertex(cb + Offset, r, g, b, a, 0, 0); - vertices[2] = new Vertex(cc + Offset, r, g, b, a, 0, 0); - vertices[3] = new Vertex(cd + Offset, r, g, b, a, 0, 0); + vertices[0] = new Vertex(ca + Offset, r, g, b, a, 0); + vertices[1] = new Vertex(cb + Offset, r, g, b, a, 0); + vertices[2] = new Vertex(cc + Offset, r, g, b, a, 0); + vertices[3] = new Vertex(cd + Offset, r, g, b, a, 0); parent.DrawRGBAQuad(vertices, blendMode); // Advance line segment @@ -209,10 +209,10 @@ namespace OpenRA.Graphics var cb = color.B / 255.0f; var ca = color.A / 255.0f; - vertices[0] = new Vertex(a + Offset, cr, cg, cb, ca, 0, 0); - vertices[1] = new Vertex(b + Offset, cr, cg, cb, ca, 0, 0); - vertices[2] = new Vertex(c + Offset, cr, cg, cb, ca, 0, 0); - vertices[3] = new Vertex(d + Offset, cr, cg, cb, ca, 0, 0); + vertices[0] = new Vertex(a + Offset, cr, cg, cb, ca, 0); + vertices[1] = new Vertex(b + Offset, cr, cg, cb, ca, 0); + vertices[2] = new Vertex(c + Offset, cr, cg, cb, ca, 0); + vertices[3] = new Vertex(d + Offset, cr, cg, cb, ca, 0); parent.DrawRGBAQuad(vertices, blendMode); } @@ -234,7 +234,7 @@ namespace OpenRA.Graphics var cb = color.B / 255.0f; var ca = color.A / 255.0f; - return new Vertex(xyz, cr, cg, cb, ca, 0, 0); + return new Vertex(xyz, cr, cg, cb, ca, 0); } public void FillEllipse(in float3 tl, in float3 br, Color color, BlendMode blendMode = BlendMode.Alpha) diff --git a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs index 28c8e46a76..58913cd21b 100644 --- a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs +++ b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs @@ -76,7 +76,8 @@ namespace OpenRA.Graphics { var v = vertices[i]; var p = palettes[i / 4]?.TextureIndex ?? 0; - vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, p, v.C, v.R, v.G, v.B, v.A); + var c = (uint)((p & 0xFFFF) << 16) | (v.C & 0xFFFF); + vertices[i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, c, v.R, v.G, v.B, v.A); } for (var row = 0; row < map.MapSize.Y; row++) @@ -113,7 +114,7 @@ namespace OpenRA.Graphics for (var i = 0; i < 4; i++) { var v = vertices[offset + i]; - vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, v.P, v.C, v.A * float3.Ones, v.A); + vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, v.C, v.A * float3.Ones, v.A); } return; @@ -138,7 +139,7 @@ namespace OpenRA.Graphics for (var i = 0; i < 4; i++) { var v = vertices[offset + i]; - vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, v.P, v.C, v.A * weights[i], v.A); + vertices[offset + i] = new Vertex(v.X, v.Y, v.Z, v.S, v.T, v.U, v.V, v.C, v.A * weights[i], v.A); } dirtyRows.Add(uv.V); diff --git a/OpenRA.Game/Graphics/Util.cs b/OpenRA.Game/Graphics/Util.cs index d08ec8191e..a5669913fe 100644 --- a/OpenRA.Game/Graphics/Util.cs +++ b/OpenRA.Game/Graphics/Util.cs @@ -94,11 +94,13 @@ namespace OpenRA.Graphics attribC |= samplers.Y << 9; } - var fAttribC = (float)attribC; - vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint, alpha); - vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, paletteTextureIndex, fAttribC, tint, alpha); - vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint, alpha); - vertices[nv + 3] = new Vertex(d, r.Left, r.Bottom, sl, sb, paletteTextureIndex, fAttribC, tint, alpha); + attribC |= (paletteTextureIndex & 0xFFFF) << 16; + + var uAttribC = (uint)attribC; + vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, uAttribC, tint, alpha); + vertices[nv + 1] = new Vertex(b, r.Right, r.Top, sr, st, uAttribC, tint, alpha); + vertices[nv + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, uAttribC, tint, alpha); + vertices[nv + 3] = new Vertex(d, r.Left, r.Bottom, sl, sb, uAttribC, tint, alpha); } public static void FastCopyIntoChannel(Sprite dest, byte[] src, SpriteFrameType srcType) diff --git a/OpenRA.Game/Graphics/Vertex.cs b/OpenRA.Game/Graphics/Vertex.cs index a7c726ffbe..c3b90d1cd4 100644 --- a/OpenRA.Game/Graphics/Vertex.cs +++ b/OpenRA.Game/Graphics/Vertex.cs @@ -23,26 +23,26 @@ namespace OpenRA.Graphics public readonly float S, T, U, V; // Palette and channel flags - public readonly float P, C; + public readonly uint C; // Color tint public readonly float R, G, B, A; - public Vertex(in float3 xyz, float s, float t, float u, float v, float p, float c) - : this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c, float3.Ones, 1f) { } + public Vertex(in float3 xyz, float s, float t, float u, float v, uint c) + : this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, c, float3.Ones, 1f) { } - public Vertex(in float3 xyz, float s, float t, float u, float v, float p, float c, in float3 tint, float a) - : this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, p, c, tint.X, tint.Y, tint.Z, a) { } + public Vertex(in float3 xyz, float s, float t, float u, float v, uint c, in float3 tint, float a) + : this(xyz.X, xyz.Y, xyz.Z, s, t, u, v, c, tint.X, tint.Y, tint.Z, a) { } - public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c, in float3 tint, float a) - : this(x, y, z, s, t, u, v, p, c, tint.X, tint.Y, tint.Z, a) { } + public Vertex(float x, float y, float z, float s, float t, float u, float v, uint c, in float3 tint, float a) + : this(x, y, z, s, t, u, v, c, tint.X, tint.Y, tint.Z, a) { } - public Vertex(float x, float y, float z, float s, float t, float u, float v, float p, float c, float r, float g, float b, float a) + public Vertex(float x, float y, float z, float s, float t, float u, float v, uint c, float r, float g, float b, float a) { X = x; Y = y; Z = z; S = s; T = t; U = u; V = v; - P = p; C = c; + C = c; R = r; G = g; B = b; A = a; } } @@ -57,8 +57,8 @@ namespace OpenRA.Graphics { new ShaderVertexAttribute("aVertexPosition", ShaderVertexAttributeType.Float, 3, 0), new ShaderVertexAttribute("aVertexTexCoord", ShaderVertexAttributeType.Float, 4, 12), - new ShaderVertexAttribute("aVertexTexMetadata", ShaderVertexAttributeType.Float, 2, 28), - new ShaderVertexAttribute("aVertexTint", ShaderVertexAttributeType.Float, 4, 36) + new ShaderVertexAttribute("aVertexAttributes", ShaderVertexAttributeType.UInt, 1, 28), + new ShaderVertexAttribute("aVertexTint", ShaderVertexAttributeType.Float, 4, 32) }; } } diff --git a/glsl/combined.frag b/glsl/combined.frag index bb629b7e5b..30fb5017f0 100644 --- a/glsl/combined.frag +++ b/glsl/combined.frag @@ -19,17 +19,13 @@ uniform vec2 DepthPreviewParams; uniform float DepthTextureScale; uniform float AntialiasPixelsPerTexel; -in vec4 vColor; - in vec4 vTexCoord; -in float vTexPalette; -in vec4 vChannelMask; -in vec4 vDepthMask; -in vec2 vTexSampler; - -in vec4 vColorFraction; -in vec4 vRGBAFraction; -in vec4 vPalettedFraction; +flat in float vTexPalette; +flat in vec4 vChannelMask; +flat in uint vChannelSampler; +flat in uint vChannelType; +flat in vec4 vDepthMask; +flat in uint vDepthSampler; in vec4 vTint; out vec4 fragColor; @@ -77,47 +73,53 @@ vec4 linear2srgb(vec4 c) return c.a * vec4(linear2srgb(c.r / c.a), linear2srgb(c.g / c.a), linear2srgb(c.b / c.a), 1.0f); } -ivec2 Size(float samplerIndex) +ivec2 Size(uint samplerIndex) { - if (samplerIndex < 0.5) - return textureSize(Texture0, 0); - else if (samplerIndex < 1.5) - return textureSize(Texture1, 0); - else if (samplerIndex < 2.5) - return textureSize(Texture2, 0); - else if (samplerIndex < 3.5) - return textureSize(Texture3, 0); - else if (samplerIndex < 4.5) - return textureSize(Texture4, 0); - else if (samplerIndex < 5.5) - return textureSize(Texture5, 0); - else if (samplerIndex < 6.5) - return textureSize(Texture6, 0); - - return textureSize(Texture7, 0); + switch (samplerIndex) + { + case 7u: + return textureSize(Texture7, 0); + case 6u: + return textureSize(Texture6, 0); + case 5u: + return textureSize(Texture5, 0); + case 4u: + return textureSize(Texture4, 0); + case 3u: + return textureSize(Texture3, 0); + case 2u: + return textureSize(Texture2, 0); + case 1u: + return textureSize(Texture1, 0); + default: + return textureSize(Texture0, 0); + } } -vec4 Sample(float samplerIndex, vec2 pos) +vec4 Sample(uint samplerIndex, vec2 pos) { - if (samplerIndex < 0.5) - return texture(Texture0, pos); - else if (samplerIndex < 1.5) - return texture(Texture1, pos); - else if (samplerIndex < 2.5) - return texture(Texture2, pos); - else if (samplerIndex < 3.5) - return texture(Texture3, pos); - else if (samplerIndex < 4.5) - return texture(Texture4, pos); - else if (samplerIndex < 5.5) - return texture(Texture5, pos); - else if (samplerIndex < 6.5) - return texture(Texture6, pos); - - return texture(Texture7, pos); + switch (samplerIndex) + { + case 7u: + return texture(Texture7, pos); + case 6u: + return texture(Texture6, pos); + case 5u: + return texture(Texture5, pos); + case 4u: + return texture(Texture4, pos); + case 3u: + return texture(Texture3, pos); + case 2u: + return texture(Texture2, pos); + case 1u: + return texture(Texture1, pos); + default: + return texture(Texture0, pos); + } } -vec4 SamplePalettedBilinear(float samplerIndex, vec2 coords, vec2 textureSize) +vec4 SamplePalettedBilinear(uint samplerIndex, vec2 coords, vec2 textureSize) { vec2 texPos = (coords * textureSize) - vec2(0.5); vec2 interp = fract(texPos); @@ -152,11 +154,13 @@ vec4 ColorShift(vec4 c, float p) void main() { vec2 coords = vTexCoord.st; + bool isPaletted = (vChannelType & 0x01u) != 0u; + bool isColor = vChannelType == 0u; vec4 c; if (AntialiasPixelsPerTexel > 0.0) { - vec2 textureSize = vec2(Size(vTexSampler.s)); + vec2 textureSize = vec2(Size(vChannelSampler)); vec2 offset = fract(coords.st * textureSize); // Offset the sampling point to simulate bilinear intepolation in window coordinates instead of texture coordinates @@ -167,28 +171,33 @@ void main() vec2 interp = clamp(offset * ik * AntialiasPixelsPerTexel, 0.0, .5) + clamp((offset - 1.0) * ik * AntialiasPixelsPerTexel + .5, 0.0, .5); coords = (floor(coords.st * textureSize) + interp) / textureSize; - if (vPalettedFraction.x > 0.0) - c = SamplePalettedBilinear(vTexSampler.s, coords, textureSize); + if (isPaletted) + c = SamplePalettedBilinear(vChannelSampler, coords, textureSize); } - if (!(AntialiasPixelsPerTexel > 0.0 && vPalettedFraction.x > 0.0)) + if (!(AntialiasPixelsPerTexel > 0.0 && isPaletted)) { - vec4 x = Sample(vTexSampler.s, coords); + vec4 x = Sample(vChannelSampler, coords); vec2 p = vec2(dot(x, vChannelMask), vTexPalette); - c = vPalettedFraction * texture(Palette, p) + vRGBAFraction * x + vColorFraction * vTexCoord; + if (isPaletted) + c = texture(Palette, p); + else if (isColor) + c = vTexCoord; + else + c = x; } // Discard any transparent fragments (both color and depth) if (c.a == 0.0) discard; - if (vRGBAFraction.r > 0.0 && vTexPalette > 0.0) + if (!isPaletted && vTexPalette > 0.0) c = ColorShift(c, vTexPalette); float depth = gl_FragCoord.z; if (length(vDepthMask) > 0.0) { - vec4 y = Sample(vTexSampler.t, vTexCoord.pq); + vec4 y = Sample(vDepthSampler, vTexCoord.pq); depth = depth + DepthTextureScale * dot(y, vDepthMask); } diff --git a/glsl/combined.vert b/glsl/combined.vert index b78058137a..602fcf690f 100644 --- a/glsl/combined.vert +++ b/glsl/combined.vert @@ -6,109 +6,59 @@ uniform float PaletteRows; in vec3 aVertexPosition; in vec4 aVertexTexCoord; -in vec2 aVertexTexMetadata; +in uint aVertexAttributes; in vec4 aVertexTint; out vec4 vTexCoord; -out float vTexPalette; -out vec4 vChannelMask; -out vec4 vDepthMask; -out vec2 vTexSampler; - -out vec4 vColorFraction; -out vec4 vRGBAFraction; -out vec4 vPalettedFraction; +flat out float vTexPalette; +flat out vec4 vChannelMask; +flat out uint vChannelSampler; +flat out uint vChannelType; +flat out vec4 vDepthMask; +flat out uint vDepthSampler; out vec4 vTint; - -vec4 UnpackChannelAttributes(float x) + +vec4 SelectChannelMask(uint x) { - // The channel attributes float encodes a set of attributes - // stored as flags in the mantissa of the unnormalized float value. - // Bits 9-11 define the sampler index (0-7) that the secondary texture is bound to - // Bits 6-8 define the sampler index (0-7) that the primary texture is bound to - // Bits 3-5 define the behaviour of the secondary texture channel: - // 000: Channel is not used - // 001, 011, 101, 111: Sample depth sprite from channel R,G,B,A - // Bits 0-2 define the behaviour of the primary texture channel: - // 000: Channel is not used (aVertexTexCoord instead defines a color value) - // 010: Sample RGBA sprite from all four channels - // 001, 011, 101, 111: Sample paletted sprite from channel R,G,B,A - - float secondarySampler = 0.0; - if (x >= 2048.0) { x -= 2048.0; secondarySampler += 4.0; } - if (x >= 1024.0) { x -= 1024.0; secondarySampler += 2.0; } - if (x >= 512.0) { x -= 512.0; secondarySampler += 1.0; } - - float primarySampler = 0.0; - if (x >= 256.0) { x -= 256.0; primarySampler += 4.0; } - if (x >= 128.0) { x -= 128.0; primarySampler += 2.0; } - if (x >= 64.0) { x -= 64.0; primarySampler += 1.0; } - - float secondaryChannel = 0.0; - if (x >= 32.0) { x -= 32.0; secondaryChannel += 4.0; } - if (x >= 16.0) { x -= 16.0; secondaryChannel += 2.0; } - if (x >= 8.0) { x -= 8.0; secondaryChannel += 1.0; } - - float primaryChannel = 0.0; - if (x >= 4.0) { x -= 4.0; primaryChannel += 4.0; } - if (x >= 2.0) { x -= 2.0; primaryChannel += 2.0; } - if (x >= 1.0) { x -= 1.0; primaryChannel += 1.0; } - - return vec4(primaryChannel, secondaryChannel, primarySampler, secondarySampler); -} - -vec4 SelectChannelMask(float x) -{ - if (x >= 7.0) - return vec4(0,0,0,1); - if (x >= 5.0) - return vec4(0,0,1,0); - if (x >= 3.0) - return vec4(0,1,0,0); - if (x >= 2.0) - return vec4(1,1,1,1); - if (x >= 1.0) - return vec4(1,0,0,0); - - return vec4(0, 0, 0, 0); -} - -vec4 SelectColorFraction(float x) -{ - if (x > 0.0) - return vec4(0, 0, 0, 0); - - return vec4(1, 1, 1, 1); -} - -vec4 SelectRGBAFraction(float x) -{ - if (x == 2.0) - return vec4(1, 1, 1, 1); - - return vec4(0, 0, 0, 0); -} - -vec4 SelectPalettedFraction(float x) -{ - if (x == 0.0 || x == 2.0) - return vec4(0, 0, 0, 0); - - return vec4(1, 1, 1, 1); + switch (x) + { + case 7u: + return vec4(0.0, 0.0, 0.0, 1.0); + case 5u: + return vec4(0.0, 0.0, 1.0, 0.0); + case 3u: + return vec4(0, 1.0, 0.0, 0.0); + case 2u: + return vec4(1.0, 1.0, 1.0, 1.0); + case 1u: + return vec4(1.0, 0.0, 0.0, 0.0); + default: + return vec4(0.0, 0.0, 0.0, 0.0); + } } void main() { gl_Position = vec4((aVertexPosition - Scroll) * p1 + p2, 1); vTexCoord = aVertexTexCoord; - vTexPalette = aVertexTexMetadata.s / PaletteRows; - vec4 attrib = UnpackChannelAttributes(aVertexTexMetadata.t); - vChannelMask = SelectChannelMask(attrib.s); - vColorFraction = SelectColorFraction(attrib.s); - vRGBAFraction = SelectRGBAFraction(attrib.s); - vPalettedFraction = SelectPalettedFraction(attrib.s); - vDepthMask = SelectChannelMask(attrib.t); - vTexSampler = attrib.pq; + // aVertexAttributes is a packed bitfield, where: + // Bits 0-2 define the behaviour of the primary texture channel: + // 000: Channel is not used (aVertexTexCoord instead defines a color value) + // 010: Sample RGBA sprite from all four channels + // 001, 011, 101, 111: Sample paletted sprite from channel R,G,B,A + // Bits 3-5 define the behaviour of the secondary texture channel: + // 000: Channel is not used + // 001, 011, 101, 111: Sample depth sprite from channel R,G,B,A + // Bits 6-8 define the sampler index (0-7) that the primary texture is bound to + // Bits 9-11 define the sampler index (0-7) that the secondary texture is bound to + // Bits 16-31 define the palette row for paletted sprites + vChannelType = aVertexAttributes & 0x07u; + vChannelMask = SelectChannelMask(vChannelType); + vDepthMask = SelectChannelMask((aVertexAttributes >> 3) & 0x07u); + vChannelSampler = (aVertexAttributes >> 6) & 0x07u; + vDepthSampler = (aVertexAttributes >> 9) & 0x07u; + vTexPalette = (aVertexAttributes >> 16) / PaletteRows; + vTint = aVertexTint; }