From cdcfeb627644df560a67603cd541de07d3399438 Mon Sep 17 00:00:00 2001 From: Bob Date: Fri, 24 Sep 2010 14:55:28 +1200 Subject: [PATCH] render perf improvement: BufferSubData, and don't use the same buffer back-to-back --- .../Graphics/IGraphicsDevice.cs | 4 +-- OpenRA.Game/Graphics/LineRenderer.cs | 30 ++++++++---------- OpenRA.Game/Graphics/Renderer.cs | 31 ++++++++++++++++--- OpenRA.Game/Graphics/SpriteRenderer.cs | 30 ++++++++---------- OpenRA.Game/Graphics/TerrainRenderer.cs | 4 +-- OpenRA.Gl/IndexBuffer.cs | 18 ++++++++--- OpenRA.Gl/VertexBuffer.cs | 18 ++++++++--- 7 files changed, 83 insertions(+), 52 deletions(-) diff --git a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs index 5a64308033..2d3d9821ec 100755 --- a/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs +++ b/OpenRA.FileFormats/Graphics/IGraphicsDevice.cs @@ -52,13 +52,13 @@ namespace OpenRA.FileFormats.Graphics public interface IVertexBuffer { void Bind(); - void SetData( T[] vertices ); + void SetData( T[] vertices, int length ); } public interface IIndexBuffer { void Bind(); - void SetData( ushort[] indices ); + void SetData( ushort[] indices, int length ); } public interface IShader diff --git a/OpenRA.Game/Graphics/LineRenderer.cs b/OpenRA.Game/Graphics/LineRenderer.cs index 28479179c9..0738d7a125 100644 --- a/OpenRA.Game/Graphics/LineRenderer.cs +++ b/OpenRA.Game/Graphics/LineRenderer.cs @@ -16,42 +16,41 @@ namespace OpenRA.Graphics public class LineRenderer { Renderer renderer; - IVertexBuffer vertexBuffer; - IIndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */ - const int linesPerBatch = 1024; - - Vertex[] vertices = new Vertex[ 2 * linesPerBatch ]; - ushort[] indices = new ushort[ 2 * linesPerBatch ]; - int lines = 0; + Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ]; + ushort[] indices = new ushort[ Renderer.TempBufferSize ]; int nv = 0, ni = 0; public LineRenderer( Renderer renderer ) { this.renderer = renderer; - vertexBuffer = renderer.Device.CreateVertexBuffer(vertices.Length ); - indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length ); } public void Flush() { - if( lines > 0 ) + if( ni > 0 ) { renderer.LineShader.Render( () => { - vertexBuffer.SetData( vertices ); - indexBuffer.SetData( indices ); - renderer.DrawBatch( vertexBuffer, indexBuffer, + var vb = renderer.GetTempVertexBuffer(); + var ib = renderer.GetTempIndexBuffer(); + vb.SetData( vertices, nv ); + ib.SetData( indices, ni ); + renderer.DrawBatch( vb, ib, nv, ni / 2, PrimitiveType.LineList ); } ); nv = 0; ni = 0; - lines = 0; } } public void DrawLine( float2 start, float2 end, Color startColor, Color endColor ) { + if( ni + 2 > Renderer.TempBufferSize ) + Flush(); + if( nv + 2 > Renderer.TempBufferSize ) + Flush(); + indices[ ni++ ] = (ushort)nv; vertices[ nv++ ] = new Vertex( start, @@ -63,9 +62,6 @@ namespace OpenRA.Graphics vertices[ nv++ ] = new Vertex( end, new float2( endColor.R / 255.0f, endColor.G / 255.0f ), new float2( endColor.B / 255.0f, endColor.A / 255.0f ) ); - - if( ++lines >= linesPerBatch ) - Flush(); } public void FillRect( RectangleF r, Color color ) diff --git a/OpenRA.Game/Graphics/Renderer.cs b/OpenRA.Game/Graphics/Renderer.cs index 3998710e09..054b3d38b4 100644 --- a/OpenRA.Game/Graphics/Renderer.cs +++ b/OpenRA.Game/Graphics/Renderer.cs @@ -16,6 +16,7 @@ using OpenRA.FileFormats; using OpenRA.FileFormats.Graphics; using OpenRA.Support; using System.Windows.Forms; +using System.Collections.Generic; namespace OpenRA.Graphics { @@ -37,6 +38,12 @@ namespace OpenRA.Graphics public readonly SpriteFont RegularFont, BoldFont, TitleFont; + internal const int TempBufferSize = 8192; + const int TempBufferCount = 8; + + Queue> tempBuffersV = new Queue>(); + Queue tempBuffersI = new Queue(); + public Renderer() { SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx")); @@ -52,6 +59,12 @@ namespace OpenRA.Graphics RegularFont = new SpriteFont("FreeSans.ttf", 14); BoldFont = new SpriteFont("FreeSansBold.ttf", 14); TitleFont = new SpriteFont("titles.ttf", 48); + + for( int i = 0 ; i < TempBufferCount ; i++ ) + { + tempBuffersV.Enqueue( device.CreateVertexBuffer( TempBufferSize ) ); + tempBuffersI.Enqueue( device.CreateIndexBuffer( TempBufferSize ) ); + } } public IGraphicsDevice Device { get { return device; } } @@ -116,10 +129,6 @@ namespace OpenRA.Graphics LineRenderer.Flush(); } - - - - static IGraphicsDevice device; public static Size Resolution { get { return device.WindowSize; } } @@ -154,5 +163,19 @@ namespace OpenRA.Graphics } throw new NotImplementedException(); } + + internal IVertexBuffer GetTempVertexBuffer() + { + var ret = tempBuffersV.Dequeue(); + tempBuffersV.Enqueue( ret ); + return ret; + } + + internal IIndexBuffer GetTempIndexBuffer() + { + var ret = tempBuffersI.Dequeue(); + tempBuffersI.Enqueue( ret ); + return ret; + } } } diff --git a/OpenRA.Game/Graphics/SpriteRenderer.cs b/OpenRA.Game/Graphics/SpriteRenderer.cs index 74e0147640..d7f3c89f56 100644 --- a/OpenRA.Game/Graphics/SpriteRenderer.cs +++ b/OpenRA.Game/Graphics/SpriteRenderer.cs @@ -14,26 +14,18 @@ namespace OpenRA.Graphics { public class SpriteRenderer { - IVertexBuffer vertexBuffer; - IIndexBuffer indexBuffer; Renderer renderer; IShader shader; - const int spritesPerBatch = 1024; - - Vertex[] vertices = new Vertex[4 * spritesPerBatch]; - ushort[] indices = new ushort[6 * spritesPerBatch]; + Vertex[] vertices = new Vertex[Renderer.TempBufferSize]; + ushort[] indices = new ushort[Renderer.TempBufferSize]; Sheet currentSheet = null; - int sprites = 0; int nv = 0, ni = 0; public SpriteRenderer(Renderer renderer, IShader shader) { this.renderer = renderer; this.shader = shader; - - vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length ); - indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length ); } public SpriteRenderer(Renderer renderer) @@ -41,14 +33,16 @@ namespace OpenRA.Graphics public void Flush() { - if (sprites > 0) + if (ni > 0) { shader.SetValue( "DiffuseTexture", currentSheet.Texture ); shader.Render(() => { - vertexBuffer.SetData(vertices); - indexBuffer.SetData(indices); - renderer.DrawBatch(vertexBuffer, indexBuffer, + var vb = renderer.GetTempVertexBuffer(); + var ib = renderer.GetTempIndexBuffer(); + vb.SetData(vertices, nv); + ib.SetData(indices, ni); + renderer.DrawBatch(vb, ib, new Range(0, nv), new Range(0, ni), PrimitiveType.TriangleList, @@ -57,7 +51,6 @@ namespace OpenRA.Graphics nv = 0; ni = 0; currentSheet = null; - sprites = 0; } } @@ -76,11 +69,14 @@ namespace OpenRA.Graphics if (s.sheet != currentSheet) Flush(); + if( nv + 4 > Renderer.TempBufferSize ) + Flush(); + if( ni + 6 > Renderer.TempBufferSize ) + Flush(); + currentSheet = s.sheet; Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size); nv += 4; ni += 6; - if (++sprites >= spritesPerBatch) - Flush(); } diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index 6935554bb7..943f795648 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -56,10 +56,10 @@ namespace OpenRA.Graphics } vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length ); - vertexBuffer.SetData( vertices ); + vertexBuffer.SetData( vertices, nv ); indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length ); - indexBuffer.SetData( indices ); + indexBuffer.SetData( indices, ni ); } public void Draw( Viewport viewport ) diff --git a/OpenRA.Gl/IndexBuffer.cs b/OpenRA.Gl/IndexBuffer.cs index c8532157d9..f070daec47 100644 --- a/OpenRA.Gl/IndexBuffer.cs +++ b/OpenRA.Gl/IndexBuffer.cs @@ -22,13 +22,21 @@ namespace OpenRA.GlRenderer { Gl.glGenBuffers(1, out buffer); GraphicsDevice.CheckGlError(); - } - - public void SetData(ushort[] data) - { Bind(); Gl.glBufferData(Gl.GL_ELEMENT_ARRAY_BUFFER, - new IntPtr(2 * data.Length), data, Gl.GL_DYNAMIC_DRAW); + new IntPtr(2 * size), + new ushort[ size ], + Gl.GL_DYNAMIC_DRAW); + GraphicsDevice.CheckGlError(); + } + + public void SetData(ushort[] data, int length) + { + Bind(); + Gl.glBufferSubData(Gl.GL_ELEMENT_ARRAY_BUFFER, + IntPtr.Zero, + new IntPtr(2 * length), + data); GraphicsDevice.CheckGlError(); } diff --git a/OpenRA.Gl/VertexBuffer.cs b/OpenRA.Gl/VertexBuffer.cs index f08728ec7e..8ec8a7163d 100644 --- a/OpenRA.Gl/VertexBuffer.cs +++ b/OpenRA.Gl/VertexBuffer.cs @@ -24,13 +24,21 @@ namespace OpenRA.GlRenderer { Gl.glGenBuffers(1, out buffer); GraphicsDevice.CheckGlError(); - } - - public void SetData(T[] data) - { Bind(); Gl.glBufferData(Gl.GL_ARRAY_BUFFER, - new IntPtr(Marshal.SizeOf(typeof(T)) * data.Length), data, Gl.GL_DYNAMIC_DRAW); + new IntPtr(Marshal.SizeOf(typeof(T)) * size), + new T[ size ], + Gl.GL_DYNAMIC_DRAW); + GraphicsDevice.CheckGlError(); + } + + public void SetData(T[] data, int length) + { + Bind(); + Gl.glBufferSubData(Gl.GL_ARRAY_BUFFER, + IntPtr.Zero, + new IntPtr(Marshal.SizeOf(typeof(T)) * length), + data); GraphicsDevice.CheckGlError(); }