diff --git a/OpenRA.Game/Graphics/PlatformInterfaces.cs b/OpenRA.Game/Graphics/PlatformInterfaces.cs index fd31b6409a..37876ae506 100644 --- a/OpenRA.Game/Graphics/PlatformInterfaces.cs +++ b/OpenRA.Game/Graphics/PlatformInterfaces.cs @@ -83,7 +83,8 @@ namespace OpenRA public interface IGraphicsContext : IDisposable { - IVertexBuffer CreateVertexBuffer(int size) where T : struct; + IVertexBuffer CreateEmptyVertexBuffer(int size) where T : struct; + IVertexBuffer CreateVertexBuffer(T[] data, bool dynamic = true) where T : struct; T[] CreateVertices(int size) where T : struct; IIndexBuffer CreateIndexBuffer(uint[] indices); ITexture CreateTexture(); diff --git a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs index 9efc2d65e9..aef71e7a43 100644 --- a/OpenRA.Game/Graphics/TerrainSpriteLayer.cs +++ b/OpenRA.Game/Graphics/TerrainSpriteLayer.cs @@ -51,7 +51,7 @@ namespace OpenRA.Graphics vertexRowStride = 4 * map.MapSize.X; vertices = new Vertex[vertexRowStride * map.MapSize.Y]; - vertexBuffer = Game.Renderer.Context.CreateVertexBuffer(vertices.Length); + vertexBuffer = Game.Renderer.Context.CreateEmptyVertexBuffer(vertices.Length); indexRowStride = 6 * map.MapSize.X; lock (IndexBuffers) diff --git a/OpenRA.Game/Renderer.cs b/OpenRA.Game/Renderer.cs index 864fd912db..ffb18a7a15 100644 --- a/OpenRA.Game/Renderer.cs +++ b/OpenRA.Game/Renderer.cs @@ -107,7 +107,7 @@ namespace OpenRA RgbaSpriteRenderer = new RgbaSpriteRenderer(SpriteRenderer); RgbaColorRenderer = new RgbaColorRenderer(SpriteRenderer); - tempVertexBuffer = Context.CreateVertexBuffer(TempVertexBufferSize); + tempVertexBuffer = Context.CreateEmptyVertexBuffer(TempVertexBufferSize); quadIndexBuffer = Context.CreateIndexBuffer(Util.CreateQuadIndices(TempIndexBufferSize / 6)); worldBufferSnapshot = Context.CreateTexture(); } @@ -406,9 +406,9 @@ namespace OpenRA return Context.CreateShader(bindings); } - public IVertexBuffer CreateVertexBuffer(int length) where T : struct + public IVertexBuffer CreateVertexBuffer(T[] data, bool dynamic) where T : struct { - return Context.CreateVertexBuffer(length); + return Context.CreateVertexBuffer(data, dynamic); } public void EnableScissor(Rectangle rect) diff --git a/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs b/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs index 20e1b6b524..5e7738e7c1 100644 --- a/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs +++ b/OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs @@ -195,8 +195,7 @@ namespace OpenRA.Mods.Cnc.Graphics public void RefreshBuffer() { vertexBuffer?.Dispose(); - vertexBuffer = Game.Renderer.CreateVertexBuffer(totalVertexCount); - vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount); + vertexBuffer = Game.Renderer.CreateVertexBuffer(vertices.SelectMany(v => v).ToArray(), false); cachedVertexCount = totalVertexCount; } diff --git a/OpenRA.Mods.Cnc/Traits/World/ChronoVortexRenderer.cs b/OpenRA.Mods.Cnc/Traits/World/ChronoVortexRenderer.cs index 12b576865d..c6ae904301 100644 --- a/OpenRA.Mods.Cnc/Traits/World/ChronoVortexRenderer.cs +++ b/OpenRA.Mods.Cnc/Traits/World/ChronoVortexRenderer.cs @@ -37,7 +37,6 @@ namespace OpenRA.Mods.Cnc.Traits shader = renderer.CreateShader(new RenderPostProcessPassTexturedShaderBindings("vortex")); vortexSheet = new Sheet(SheetType.BGRA, new Size(512, 512)); - vortexBuffer = renderer.CreateVertexBuffer(288); var vertices = new RenderPostProcessPassTexturedVertex[288]; var data = vortexSheet.GetData(); @@ -72,7 +71,7 @@ namespace OpenRA.Mods.Cnc.Traits vertices[j++] = new RenderPostProcessPassTexturedVertex(-32, -32, tl.X, tl.Y); } - vortexBuffer.SetData(ref vertices, 288); + vortexBuffer = renderer.CreateVertexBuffer(vertices, false); vortexSheet.CommitBufferedData(); } diff --git a/OpenRA.Mods.Common/Traits/World/RenderPostProcessPassBase.cs b/OpenRA.Mods.Common/Traits/World/RenderPostProcessPassBase.cs index cce3f315d7..d66ebae669 100644 --- a/OpenRA.Mods.Common/Traits/World/RenderPostProcessPassBase.cs +++ b/OpenRA.Mods.Common/Traits/World/RenderPostProcessPassBase.cs @@ -36,8 +36,7 @@ namespace OpenRA.Mods.Common.Traits new(-1, -1) }; - buffer = renderer.CreateVertexBuffer(6); - buffer.SetData(ref vertices, 6); + buffer = renderer.CreateVertexBuffer(vertices, false); } PostProcessPassType IRenderPostProcessPass.Type => type; diff --git a/OpenRA.Mods.D2k/Traits/World/SonicBlastRenderer.cs b/OpenRA.Mods.D2k/Traits/World/SonicBlastRenderer.cs index 1bc3288180..4189b61a37 100644 --- a/OpenRA.Mods.D2k/Traits/World/SonicBlastRenderer.cs +++ b/OpenRA.Mods.D2k/Traits/World/SonicBlastRenderer.cs @@ -42,7 +42,6 @@ namespace OpenRA.Mods.D2k.Traits Info = info; renderer = Game.Renderer; shader = renderer.CreateShader(new RenderPostProcessPassTexturedShaderBindings("sonic")); - buffer = renderer.CreateVertexBuffer(6); var r = 0.5f * info.Size; shader.SetVec("Scale", r * (1f / info.Zoom - 1)); @@ -56,7 +55,7 @@ namespace OpenRA.Mods.D2k.Traits new(-r, -r, -1, -1) }; - buffer.SetData(ref vertices, 6); + buffer = renderer.CreateVertexBuffer(vertices, false); } public void Draw(float3 pos) diff --git a/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs b/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs index 43bea04b86..2bec50b422 100644 --- a/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs +++ b/OpenRA.Platforms.Default/Sdl2GraphicsContext.cs @@ -49,12 +49,18 @@ namespace OpenRA.Platforms.Default OpenGL.CheckGLError(); } - public IVertexBuffer CreateVertexBuffer(int size) where T : struct + public IVertexBuffer CreateEmptyVertexBuffer(int size) where T : struct { VerifyThreadAffinity(); return new VertexBuffer(size); } + public IVertexBuffer CreateVertexBuffer(T[] data, bool dynamic = true) where T : struct + { + VerifyThreadAffinity(); + return new VertexBuffer(data, dynamic); + } + public IIndexBuffer CreateIndexBuffer(uint[] indices) { VerifyThreadAffinity(); diff --git a/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs b/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs index 2d5cbf5494..8279293277 100644 --- a/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs +++ b/OpenRA.Platforms.Default/ThreadedGraphicsContext.cs @@ -45,6 +45,7 @@ namespace OpenRA.Platforms.Default Func getCreateTexture; Func getCreateFrameBuffer; Func getCreateShader; + Func getCreateEmptyVertexBuffer; Func getCreateVertexBuffer; Func getCreateIndexBuffer; Action doDrawPrimitives; @@ -96,11 +97,25 @@ namespace OpenRA.Platforms.Default context.CreateFrameBuffer(t.Item1, (ITextureInternal)CreateTexture(), t.Item2)); }; getCreateShader = bindings => new ThreadedShader(this, context.CreateShader((IShaderBindings)bindings)); - getCreateVertexBuffer = + getCreateEmptyVertexBuffer = tuple => { (object t, var type) = ((int, Type))tuple; - var vertexBuffer = context.GetType().GetMethod(nameof(CreateVertexBuffer)).MakeGenericMethod(type).Invoke(context, [t]); + var vertexBuffer = context.GetType() + .GetMethod(nameof(CreateEmptyVertexBuffer)) + .MakeGenericMethod(type) + .Invoke(context, [t]); + + return typeof(ThreadedVertexBuffer<>).MakeGenericType(type).GetConstructors()[0].Invoke([this, vertexBuffer]); + }; + getCreateVertexBuffer = + tuple => + { + var (array, dynamic, type) = ((object, bool, Type))tuple; + var vertexBuffer = context.GetType() + .GetMethod(nameof(CreateVertexBuffer)) + .MakeGenericMethod(type) + .Invoke(context, [array, dynamic]); return typeof(ThreadedVertexBuffer<>).MakeGenericType(type).GetConstructors()[0].Invoke([this, vertexBuffer]); }; getCreateIndexBuffer = indices => new ThreadedIndexBuffer(this, context.CreateIndexBuffer((uint[])indices)); @@ -426,9 +441,14 @@ namespace OpenRA.Platforms.Default return Send(getCreateTexture); } - public IVertexBuffer CreateVertexBuffer(int size) where T : struct + public IVertexBuffer CreateEmptyVertexBuffer(int size) where T : struct { - return (IVertexBuffer)Send(getCreateVertexBuffer, (size, typeof(T))); + return (IVertexBuffer)Send(getCreateEmptyVertexBuffer, (size, typeof(T))); + } + + public IVertexBuffer CreateVertexBuffer(T[] data, bool dynamic = true) where T : struct + { + return (IVertexBuffer)Send(getCreateVertexBuffer, ((object)data, dynamic, typeof(T))); } public IIndexBuffer CreateIndexBuffer(uint[] indices) diff --git a/OpenRA.Platforms.Default/VertexBuffer.cs b/OpenRA.Platforms.Default/VertexBuffer.cs index 183cbe8be6..b0fd39241b 100644 --- a/OpenRA.Platforms.Default/VertexBuffer.cs +++ b/OpenRA.Platforms.Default/VertexBuffer.cs @@ -55,6 +55,28 @@ namespace OpenRA.Platforms.Default } } + public VertexBuffer(T[] data, bool dynamic = true) + { + OpenGL.glGenBuffers(1, out buffer); + OpenGL.CheckGLError(); + Bind(); + + var ptr = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + OpenGL.glBufferData(OpenGL.GL_ARRAY_BUFFER, + new IntPtr(VertexSize * data.Length), + ptr.AddrOfPinnedObject(), + dynamic ? OpenGL.GL_DYNAMIC_DRAW : OpenGL.GL_STATIC_DRAW); + } + finally + { + ptr.Free(); + } + + OpenGL.CheckGLError(); + } + public void SetData(T[] data, int length) { SetData(data, 0, 0, length);