Add index buffer to TerrainSpriteLayer

This commit is contained in:
Gustas
2023-08-24 17:00:06 +03:00
committed by Matthias Mailänder
parent 9b8895df39
commit 0b90622251
3 changed files with 55 additions and 22 deletions

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
using OpenRA.Primitives; using OpenRA.Primitives;
namespace OpenRA.Graphics namespace OpenRA.Graphics
@@ -19,6 +20,7 @@ namespace OpenRA.Graphics
{ {
public const int SheetCount = 8; public const int SheetCount = 8;
static readonly string[] SheetIndexToTextureName = Exts.MakeArray(SheetCount, i => $"Texture{i}"); static readonly string[] SheetIndexToTextureName = Exts.MakeArray(SheetCount, i => $"Texture{i}");
static readonly int UintSize = Marshal.SizeOf(typeof(uint));
readonly Renderer renderer; readonly Renderer renderer;
readonly IShader shader; readonly IShader shader;
@@ -171,7 +173,7 @@ namespace OpenRA.Graphics
nv += 6; nv += 6;
} }
public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, int start, int length, PrimitiveType type, IEnumerable<Sheet> sheets, BlendMode blendMode) public void DrawVertexBuffer(IVertexBuffer<Vertex> buffer, IIndexBuffer indices, int start, int length, IEnumerable<Sheet> sheets, BlendMode blendMode)
{ {
var i = 0; var i = 0;
foreach (var s in sheets) foreach (var s in sheets)
@@ -185,7 +187,7 @@ namespace OpenRA.Graphics
renderer.Context.SetBlendMode(blendMode); renderer.Context.SetBlendMode(blendMode);
shader.PrepareRender(); shader.PrepareRender();
renderer.DrawBatch(buffer, start, length, type); renderer.DrawBatch(buffer, indices, length, UintSize * start);
renderer.Context.SetBlendMode(BlendMode.None); renderer.Context.SetBlendMode(BlendMode.None);
} }

View File

@@ -12,12 +12,15 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.CompilerServices;
namespace OpenRA.Graphics namespace OpenRA.Graphics
{ {
public sealed class TerrainSpriteLayer : IDisposable public sealed class TerrainSpriteLayer : IDisposable
{ {
static readonly int[] CornerVertexMap = { 0, 1, 2, 2, 3, 0 }; // PERF: we can reuse the IndexBuffer as all layers have the same size.
static readonly ConditionalWeakTable<World, IndexBufferRc> IndexBuffers = new();
readonly IndexBufferRc indexBufferWrapper;
public readonly BlendMode BlendMode; public readonly BlendMode BlendMode;
@@ -28,7 +31,8 @@ namespace OpenRA.Graphics
readonly Vertex[] vertices; readonly Vertex[] vertices;
readonly bool[] ignoreTint; readonly bool[] ignoreTint;
readonly HashSet<int> dirtyRows = new(); readonly HashSet<int> dirtyRows = new();
readonly int rowStride; readonly int indexRowStride;
readonly int vertexRowStride;
readonly bool restrictToBounds; readonly bool restrictToBounds;
readonly WorldRenderer worldRenderer; readonly WorldRenderer worldRenderer;
@@ -43,19 +47,25 @@ namespace OpenRA.Graphics
this.emptySprite = emptySprite; this.emptySprite = emptySprite;
sheets = new Sheet[SpriteRenderer.SheetCount]; sheets = new Sheet[SpriteRenderer.SheetCount];
BlendMode = blendMode; BlendMode = blendMode;
map = world.Map; map = world.Map;
rowStride = 6 * map.MapSize.X;
vertices = new Vertex[rowStride * map.MapSize.Y]; vertexRowStride = 4 * map.MapSize.X;
palettes = new PaletteReference[map.MapSize.X * map.MapSize.Y]; vertices = new Vertex[vertexRowStride * map.MapSize.Y];
vertexBuffer = Game.Renderer.Context.CreateVertexBuffer(vertices.Length); vertexBuffer = Game.Renderer.Context.CreateVertexBuffer(vertices.Length);
indexRowStride = 6 * map.MapSize.X;
lock (IndexBuffers)
{
indexBufferWrapper = IndexBuffers.GetValue(world, world => new IndexBufferRc(world));
indexBufferWrapper.AddRef();
}
palettes = new PaletteReference[map.MapSize.X * map.MapSize.Y];
wr.PaletteInvalidated += UpdatePaletteIndices; wr.PaletteInvalidated += UpdatePaletteIndices;
if (wr.TerrainLighting != null) if (wr.TerrainLighting != null)
{ {
ignoreTint = new bool[rowStride * map.MapSize.Y]; ignoreTint = new bool[vertexRowStride * map.MapSize.Y];
wr.TerrainLighting.CellChanged += UpdateTint; wr.TerrainLighting.CellChanged += UpdateTint;
} }
} }
@@ -65,7 +75,7 @@ namespace OpenRA.Graphics
for (var i = 0; i < vertices.Length; i++) for (var i = 0; i < vertices.Length; i++)
{ {
var v = vertices[i]; var v = vertices[i];
var p = palettes[i / 6]?.TextureIndex ?? 0; 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); 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);
} }
@@ -97,10 +107,10 @@ namespace OpenRA.Graphics
void UpdateTint(MPos uv) void UpdateTint(MPos uv)
{ {
var offset = rowStride * uv.V + 6 * uv.U; var offset = vertexRowStride * uv.V + 4 * uv.U;
if (ignoreTint[offset]) if (ignoreTint[offset])
{ {
for (var i = 0; i < 6; i++) for (var i = 0; i < 4; i++)
{ {
var v = vertices[offset + 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.P, v.C, v.A * float3.Ones, v.A);
@@ -125,10 +135,10 @@ namespace OpenRA.Graphics
// Apply tint directly to the underlying vertices // Apply tint directly to the underlying vertices
// This saves us from having to re-query the sprite information, which has not changed // This saves us from having to re-query the sprite information, which has not changed
for (var i = 0; i < 6; i++) for (var i = 0; i < 4; i++)
{ {
var v = vertices[offset + 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[CornerVertexMap[i]], v.A); 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);
} }
dirtyRows.Add(uv.V); dirtyRows.Add(uv.V);
@@ -180,7 +190,7 @@ namespace OpenRA.Graphics
if (!map.Tiles.Contains(uv)) if (!map.Tiles.Contains(uv))
return; return;
var offset = rowStride * uv.V + 6 * uv.U; var offset = vertexRowStride * uv.V + 4 * uv.U;
Util.FastCreateQuad(vertices, pos, sprite, samplers, palette?.TextureIndex ?? 0, offset, scale * sprite.Size, alpha * float3.Ones, alpha); Util.FastCreateQuad(vertices, pos, sprite, samplers, palette?.TextureIndex ?? 0, offset, scale * sprite.Size, alpha * float3.Ones, alpha);
palettes[uv.V * map.MapSize.X + uv.U] = palette; palettes[uv.V * map.MapSize.X + uv.U] = palette;
@@ -209,13 +219,13 @@ namespace OpenRA.Graphics
if (!dirtyRows.Remove(row)) if (!dirtyRows.Remove(row))
continue; continue;
var rowOffset = rowStride * row; var rowOffset = vertexRowStride * row;
vertexBuffer.SetData(vertices, rowOffset, rowOffset, rowStride); vertexBuffer.SetData(vertices, rowOffset, rowOffset, vertexRowStride);
} }
Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer( Game.Renderer.WorldSpriteRenderer.DrawVertexBuffer(
vertexBuffer, rowStride * firstRow, rowStride * (lastRow - firstRow), vertexBuffer, indexBufferWrapper.Buffer, indexRowStride * firstRow,
PrimitiveType.TriangleList, sheets, BlendMode); indexRowStride * (lastRow - firstRow), sheets, BlendMode);
Game.Renderer.Flush(); Game.Renderer.Flush();
} }
@@ -227,6 +237,29 @@ namespace OpenRA.Graphics
worldRenderer.TerrainLighting.CellChanged -= UpdateTint; worldRenderer.TerrainLighting.CellChanged -= UpdateTint;
vertexBuffer.Dispose(); vertexBuffer.Dispose();
lock (IndexBuffers)
indexBufferWrapper.Dispose();
}
sealed class IndexBufferRc : IDisposable
{
public IIndexBuffer Buffer;
int count;
public IndexBufferRc(World world)
{
Buffer = Game.Renderer.Context.CreateIndexBuffer(Util.CreateQuadIndices(world.Map.MapSize.X * world.Map.MapSize.Y));
}
public void AddRef() { count++; }
public void Dispose()
{
count--;
if (count == 0)
Buffer.Dispose();
}
} }
} }
} }

View File

@@ -98,9 +98,7 @@ namespace OpenRA.Graphics
vertices[nv] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint, alpha); 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 + 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 + 2] = new Vertex(c, r.Right, r.Bottom, sr, sb, paletteTextureIndex, fAttribC, tint, alpha);
vertices[nv + 3] = 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);
vertices[nv + 4] = new Vertex(d, r.Left, r.Bottom, sl, sb, paletteTextureIndex, fAttribC, tint, alpha);
vertices[nv + 5] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint, alpha);
} }
public static void FastCopyIntoChannel(Sprite dest, byte[] src, SpriteFrameType srcType) public static void FastCopyIntoChannel(Sprite dest, byte[] src, SpriteFrameType srcType)