Remove Vertex from PlatformInterfaces

This commit is contained in:
Gustas
2023-09-13 10:44:08 +03:00
committed by Matthias Mailänder
parent d77fd5c13e
commit 0a90c2a95e
7 changed files with 67 additions and 41 deletions

View File

@@ -10,7 +10,6 @@
#endregion #endregion
using System; using System;
using OpenRA.Graphics;
using OpenRA.Primitives; using OpenRA.Primitives;
namespace OpenRA namespace OpenRA
@@ -83,9 +82,9 @@ namespace OpenRA
public interface IGraphicsContext : IDisposable public interface IGraphicsContext : IDisposable
{ {
IVertexBuffer<Vertex> CreateVertexBuffer(int size); IVertexBuffer<T> CreateVertexBuffer<T>(int size) where T : struct;
T[] CreateVertices<T>(int size) where T : struct;
IIndexBuffer CreateIndexBuffer(uint[] indices); IIndexBuffer CreateIndexBuffer(uint[] indices);
Vertex[] CreateVertices(int size);
ITexture CreateTexture(); ITexture CreateTexture();
IFrameBuffer CreateFrameBuffer(Size s); IFrameBuffer CreateFrameBuffer(Size s);
IFrameBuffer CreateFrameBuffer(Size s, Color clearColor); IFrameBuffer CreateFrameBuffer(Size s, Color clearColor);
@@ -104,7 +103,7 @@ namespace OpenRA
string GLVersion { get; } string GLVersion { get; }
} }
public interface IVertexBuffer<T> : IDisposable public interface IVertexBuffer<T> : IDisposable where T : struct
{ {
void Bind(); void Bind();
void SetData(T[] vertices, int length); void SetData(T[] vertices, int length);

View File

@@ -36,7 +36,7 @@ namespace OpenRA.Graphics
{ {
this.renderer = renderer; this.renderer = renderer;
this.shader = shader; this.shader = shader;
vertices = renderer.Context.CreateVertices(renderer.TempVertexBufferSize); vertices = renderer.Context.CreateVertices<Vertex>(renderer.TempVertexBufferSize);
} }
public void Flush() public void Flush()

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Graphics
vertexRowStride = 4 * map.MapSize.X; vertexRowStride = 4 * map.MapSize.X;
vertices = new Vertex[vertexRowStride * map.MapSize.Y]; vertices = new Vertex[vertexRowStride * map.MapSize.Y];
vertexBuffer = Game.Renderer.Context.CreateVertexBuffer(vertices.Length); vertexBuffer = Game.Renderer.Context.CreateVertexBuffer<Vertex>(vertices.Length);
indexRowStride = 6 * map.MapSize.X; indexRowStride = 6 * map.MapSize.X;
lock (IndexBuffers) lock (IndexBuffers)

View File

@@ -96,7 +96,7 @@ namespace OpenRA
RgbaSpriteRenderer = new RgbaSpriteRenderer(SpriteRenderer); RgbaSpriteRenderer = new RgbaSpriteRenderer(SpriteRenderer);
RgbaColorRenderer = new RgbaColorRenderer(SpriteRenderer); RgbaColorRenderer = new RgbaColorRenderer(SpriteRenderer);
tempVertexBuffer = Context.CreateVertexBuffer(TempVertexBufferSize); tempVertexBuffer = Context.CreateVertexBuffer<Vertex>(TempVertexBufferSize);
quadIndexBuffer = Context.CreateIndexBuffer(Util.CreateQuadIndices(TempIndexBufferSize / 6)); quadIndexBuffer = Context.CreateIndexBuffer(Util.CreateQuadIndices(TempIndexBufferSize / 6));
} }
@@ -382,9 +382,9 @@ namespace OpenRA
} }
} }
public IVertexBuffer<Vertex> CreateVertexBuffer(int length) public IVertexBuffer<T> CreateVertexBuffer<T>(int length) where T : struct
{ {
return Context.CreateVertexBuffer(length); return Context.CreateVertexBuffer<T>(length);
} }
public void EnableScissor(Rectangle rect) public void EnableScissor(Rectangle rect)

View File

@@ -195,7 +195,7 @@ namespace OpenRA.Mods.Cnc.Graphics
public void RefreshBuffer() public void RefreshBuffer()
{ {
vertexBuffer?.Dispose(); vertexBuffer?.Dispose();
vertexBuffer = Game.Renderer.CreateVertexBuffer(totalVertexCount); vertexBuffer = Game.Renderer.CreateVertexBuffer<Vertex>(totalVertexCount);
vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount); vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount);
cachedVertexCount = totalVertexCount; cachedVertexCount = totalVertexCount;
} }

View File

@@ -10,7 +10,6 @@
#endregion #endregion
using System; using System;
using OpenRA.Graphics;
using OpenRA.Primitives; using OpenRA.Primitives;
using SDL2; using SDL2;
@@ -62,10 +61,10 @@ namespace OpenRA.Platforms.Default
OpenGL.CheckGLError(); OpenGL.CheckGLError();
} }
public IVertexBuffer<Vertex> CreateVertexBuffer(int size) public IVertexBuffer<T> CreateVertexBuffer<T>(int size) where T : struct
{ {
VerifyThreadAffinity(); VerifyThreadAffinity();
return new VertexBuffer<Vertex>(size); return new VertexBuffer<T>(size);
} }
public IIndexBuffer CreateIndexBuffer(uint[] indices) public IIndexBuffer CreateIndexBuffer(uint[] indices)
@@ -74,10 +73,10 @@ namespace OpenRA.Platforms.Default
return new StaticIndexBuffer(indices); return new StaticIndexBuffer(indices);
} }
public Vertex[] CreateVertices(int size) public T[] CreateVertices<T>(int size) where T : struct
{ {
VerifyThreadAffinity(); VerifyThreadAffinity();
return new Vertex[size]; return new T[size];
} }
public ITexture CreateTexture() public ITexture CreateTexture()

View File

@@ -13,7 +13,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.ExceptionServices; using System.Runtime.ExceptionServices;
using System.Threading; using System.Threading;
using OpenRA.Graphics;
using OpenRA.Primitives; using OpenRA.Primitives;
namespace OpenRA.Platforms.Default namespace OpenRA.Platforms.Default
@@ -25,7 +24,7 @@ namespace OpenRA.Platforms.Default
sealed class ThreadedGraphicsContext : IGraphicsContext sealed class ThreadedGraphicsContext : IGraphicsContext
{ {
// PERF: Maintain several object pools to reduce allocations. // PERF: Maintain several object pools to reduce allocations.
readonly Stack<Vertex[]> verticesPool = new(); readonly Dictionary<Type, object> vertexBufferPools = new();
readonly Stack<Message> messagePool = new(); readonly Stack<Message> messagePool = new();
readonly Queue<Message> messages = new(); readonly Queue<Message> messages = new();
@@ -46,7 +45,7 @@ namespace OpenRA.Platforms.Default
Func<ITexture> getCreateTexture; Func<ITexture> getCreateTexture;
Func<object, IFrameBuffer> getCreateFrameBuffer; Func<object, IFrameBuffer> getCreateFrameBuffer;
Func<object, IShader> getCreateShader; Func<object, IShader> getCreateShader;
Func<object, IVertexBuffer<Vertex>> getCreateVertexBuffer; Func<object, object> getCreateVertexBuffer;
Func<object, IIndexBuffer> getCreateIndexBuffer; Func<object, IIndexBuffer> getCreateIndexBuffer;
Action<object> doDrawPrimitives; Action<object> doDrawPrimitives;
Action<object> doDrawElements; Action<object> doDrawElements;
@@ -97,7 +96,13 @@ namespace OpenRA.Platforms.Default
context.CreateFrameBuffer(t.Item1, (ITextureInternal)CreateTexture(), t.Item2)); context.CreateFrameBuffer(t.Item1, (ITextureInternal)CreateTexture(), t.Item2));
}; };
getCreateShader = name => new ThreadedShader(this, context.CreateShader((string)name)); getCreateShader = name => new ThreadedShader(this, context.CreateShader((string)name));
getCreateVertexBuffer = length => new ThreadedVertexBuffer(this, context.CreateVertexBuffer((int)length)); getCreateVertexBuffer =
tuple =>
{
(object t, var type) = ((int, Type))tuple;
var vertexBuffer = context.GetType().GetMethod(nameof(CreateVertexBuffer)).MakeGenericMethod(type).Invoke(context, new[] { t });
return typeof(ThreadedVertexBuffer<>).MakeGenericType(type).GetConstructors()[0].Invoke(new[] { this, vertexBuffer });
};
getCreateIndexBuffer = indices => new ThreadedIndexBuffer(this, context.CreateIndexBuffer((uint[])indices)); getCreateIndexBuffer = indices => new ThreadedIndexBuffer(this, context.CreateIndexBuffer((uint[])indices));
doDrawPrimitives = doDrawPrimitives =
tuple => tuple =>
@@ -150,20 +155,31 @@ namespace OpenRA.Platforms.Default
} }
} }
internal Vertex[] GetVertices(int size) internal T[] GetVertices<T>(int size)
{ {
lock (verticesPool) lock (vertexBufferPools)
if (size <= VertexBatchSize && verticesPool.Count > 0) {
return verticesPool.Pop(); Stack<T[]> pool;
if (!vertexBufferPools.TryGetValue(typeof(T), out var poolObject))
{
pool = new Stack<T[]>();
vertexBufferPools.Add(typeof(T), pool);
}
else
pool = (Stack<T[]>)poolObject;
return new Vertex[size < VertexBatchSize ? VertexBatchSize : size]; if (size <= VertexBatchSize && pool.Count > 0)
return pool.Pop();
}
return new T[size < VertexBatchSize ? VertexBatchSize : size];
} }
internal void ReturnVertices(Vertex[] vertices) internal void ReturnVertices<T>(T[] vertices)
{ {
if (vertices.Length == VertexBatchSize) if (vertices.Length == VertexBatchSize)
lock (verticesPool) lock (vertexBufferPools)
verticesPool.Push(vertices); ((Stack<T[]>)vertexBufferPools[typeof(T)]).Push(vertices);
} }
sealed class Message sealed class Message
@@ -410,9 +426,9 @@ namespace OpenRA.Platforms.Default
return Send(getCreateTexture); return Send(getCreateTexture);
} }
public IVertexBuffer<Vertex> CreateVertexBuffer(int length) public IVertexBuffer<T> CreateVertexBuffer<T>(int size) where T : struct
{ {
return Send(getCreateVertexBuffer, length); return (IVertexBuffer<T>)Send(getCreateVertexBuffer, (size, typeof(T)));
} }
public IIndexBuffer CreateIndexBuffer(uint[] indices) public IIndexBuffer CreateIndexBuffer(uint[] indices)
@@ -420,9 +436,9 @@ namespace OpenRA.Platforms.Default
return Send(getCreateIndexBuffer, indices); return Send(getCreateIndexBuffer, indices);
} }
public Vertex[] CreateVertices(int size) public T[] CreateVertices<T>(int size) where T : struct
{ {
return GetVertices(size); return GetVertices<T>(size);
} }
public void DisableDepthBuffer() public void DisableDepthBuffer()
@@ -521,7 +537,7 @@ namespace OpenRA.Platforms.Default
} }
} }
sealed class ThreadedVertexBuffer : IVertexBuffer<Vertex> sealed class ThreadedVertexBuffer<T> : IVertexBuffer<T> where T : struct
{ {
readonly ThreadedGraphicsContext device; readonly ThreadedGraphicsContext device;
readonly Action bind; readonly Action bind;
@@ -530,12 +546,24 @@ namespace OpenRA.Platforms.Default
readonly Func<object, object> setData3; readonly Func<object, object> setData3;
readonly Action dispose; readonly Action dispose;
public ThreadedVertexBuffer(ThreadedGraphicsContext device, IVertexBuffer<Vertex> vertexBuffer) public ThreadedVertexBuffer(ThreadedGraphicsContext device, IVertexBuffer<T> vertexBuffer)
{ {
this.device = device; this.device = device;
bind = vertexBuffer.Bind; bind = vertexBuffer.Bind;
setData1 = tuple => { var t = ((Vertex[], int))tuple; vertexBuffer.SetData(t.Item1, t.Item2); device.ReturnVertices(t.Item1); }; setData1 = tuple =>
setData2 = tuple => { var t = ((Vertex[], int, int, int))tuple; vertexBuffer.SetData(t.Item1, t.Item2, t.Item3, t.Item4); device.ReturnVertices(t.Item1); }; {
var t = ((T[], int))tuple;
vertexBuffer.SetData(t.Item1, t.Item2);
device.ReturnVertices(t.Item1);
};
setData2 = tuple =>
{
var t = ((T[], int, int, int))tuple;
vertexBuffer.SetData(t.Item1, t.Item2, t.Item3, t.Item4);
device.ReturnVertices(t.Item1);
};
setData3 = tuple => { setData2(tuple); return null; }; setData3 = tuple => { setData2(tuple); return null; };
dispose = vertexBuffer.Dispose; dispose = vertexBuffer.Dispose;
} }
@@ -545,9 +573,9 @@ namespace OpenRA.Platforms.Default
device.Post(bind); device.Post(bind);
} }
public void SetData(Vertex[] vertices, int length) public void SetData(T[] vertices, int length)
{ {
var buffer = device.GetVertices(length); var buffer = device.GetVertices<T>(length);
Array.Copy(vertices, buffer, length); Array.Copy(vertices, buffer, length);
device.Post(setData1, (buffer, length)); device.Post(setData1, (buffer, length));
} }
@@ -556,18 +584,18 @@ namespace OpenRA.Platforms.Default
/// PERF: The vertices array is passed without copying to the render thread. Upon return `vertices` may reference another /// PERF: The vertices array is passed without copying to the render thread. Upon return `vertices` may reference another
/// array object of at least the same size - containing random values. /// array object of at least the same size - containing random values.
/// </summary> /// </summary>
public void SetData(ref Vertex[] vertices, int length) public void SetData(ref T[] vertices, int length)
{ {
device.Post(setData1, (vertices, length)); device.Post(setData1, (vertices, length));
vertices = device.GetVertices(vertices.Length); vertices = device.GetVertices<T>(vertices.Length);
} }
public void SetData(Vertex[] vertices, int offset, int start, int length) public void SetData(T[] vertices, int offset, int start, int length)
{ {
if (length <= device.VertexBatchSize) if (length <= device.VertexBatchSize)
{ {
// If we are able to use a buffer without allocation, post a message to avoid blocking. // If we are able to use a buffer without allocation, post a message to avoid blocking.
var buffer = device.GetVertices(length); var buffer = device.GetVertices<T>(length);
Array.Copy(vertices, offset, buffer, 0, length); Array.Copy(vertices, offset, buffer, 0, length);
device.Post(setData2, (buffer, 0, start, length)); device.Post(setData2, (buffer, 0, start, length));
} }