render perf improvement: BufferSubData, and don't use the same buffer back-to-back

This commit is contained in:
Bob
2010-09-24 14:55:28 +12:00
parent c77c63a380
commit cdcfeb6276
7 changed files with 83 additions and 52 deletions

View File

@@ -52,13 +52,13 @@ namespace OpenRA.FileFormats.Graphics
public interface IVertexBuffer<T> public interface IVertexBuffer<T>
{ {
void Bind(); void Bind();
void SetData( T[] vertices ); void SetData( T[] vertices, int length );
} }
public interface IIndexBuffer public interface IIndexBuffer
{ {
void Bind(); void Bind();
void SetData( ushort[] indices ); void SetData( ushort[] indices, int length );
} }
public interface IShader public interface IShader

View File

@@ -16,42 +16,41 @@ namespace OpenRA.Graphics
public class LineRenderer public class LineRenderer
{ {
Renderer renderer; Renderer renderer;
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer; /* kindof a waste of space, but the GPU likes indexing, oh well */
const int linesPerBatch = 1024; Vertex[] vertices = new Vertex[ Renderer.TempBufferSize ];
ushort[] indices = new ushort[ Renderer.TempBufferSize ];
Vertex[] vertices = new Vertex[ 2 * linesPerBatch ];
ushort[] indices = new ushort[ 2 * linesPerBatch ];
int lines = 0;
int nv = 0, ni = 0; int nv = 0, ni = 0;
public LineRenderer( Renderer renderer ) public LineRenderer( Renderer renderer )
{ {
this.renderer = renderer; this.renderer = renderer;
vertexBuffer = renderer.Device.CreateVertexBuffer(vertices.Length );
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
} }
public void Flush() public void Flush()
{ {
if( lines > 0 ) if( ni > 0 )
{ {
renderer.LineShader.Render( () => renderer.LineShader.Render( () =>
{ {
vertexBuffer.SetData( vertices ); var vb = renderer.GetTempVertexBuffer();
indexBuffer.SetData( indices ); var ib = renderer.GetTempIndexBuffer();
renderer.DrawBatch( vertexBuffer, indexBuffer, vb.SetData( vertices, nv );
ib.SetData( indices, ni );
renderer.DrawBatch( vb, ib,
nv, ni / 2, PrimitiveType.LineList ); nv, ni / 2, PrimitiveType.LineList );
} ); } );
nv = 0; ni = 0; nv = 0; ni = 0;
lines = 0;
} }
} }
public void DrawLine( float2 start, float2 end, Color startColor, Color endColor ) 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; indices[ ni++ ] = (ushort)nv;
vertices[ nv++ ] = new Vertex( start, vertices[ nv++ ] = new Vertex( start,
@@ -63,9 +62,6 @@ namespace OpenRA.Graphics
vertices[ nv++ ] = new Vertex( end, vertices[ nv++ ] = new Vertex( end,
new float2( endColor.R / 255.0f, endColor.G / 255.0f ), new float2( endColor.R / 255.0f, endColor.G / 255.0f ),
new float2( endColor.B / 255.0f, endColor.A / 255.0f ) ); new float2( endColor.B / 255.0f, endColor.A / 255.0f ) );
if( ++lines >= linesPerBatch )
Flush();
} }
public void FillRect( RectangleF r, Color color ) public void FillRect( RectangleF r, Color color )

View File

@@ -16,6 +16,7 @@ using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics; using OpenRA.FileFormats.Graphics;
using OpenRA.Support; using OpenRA.Support;
using System.Windows.Forms; using System.Windows.Forms;
using System.Collections.Generic;
namespace OpenRA.Graphics namespace OpenRA.Graphics
{ {
@@ -37,6 +38,12 @@ namespace OpenRA.Graphics
public readonly SpriteFont RegularFont, BoldFont, TitleFont; public readonly SpriteFont RegularFont, BoldFont, TitleFont;
internal const int TempBufferSize = 8192;
const int TempBufferCount = 8;
Queue<IVertexBuffer<Vertex>> tempBuffersV = new Queue<IVertexBuffer<Vertex>>();
Queue<IIndexBuffer> tempBuffersI = new Queue<IIndexBuffer>();
public Renderer() public Renderer()
{ {
SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx")); SpriteShader = device.CreateShader(FileSystem.Open("shaders/world-shp.fx"));
@@ -52,6 +59,12 @@ namespace OpenRA.Graphics
RegularFont = new SpriteFont("FreeSans.ttf", 14); RegularFont = new SpriteFont("FreeSans.ttf", 14);
BoldFont = new SpriteFont("FreeSansBold.ttf", 14); BoldFont = new SpriteFont("FreeSansBold.ttf", 14);
TitleFont = new SpriteFont("titles.ttf", 48); 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; } } public IGraphicsDevice Device { get { return device; } }
@@ -116,10 +129,6 @@ namespace OpenRA.Graphics
LineRenderer.Flush(); LineRenderer.Flush();
} }
static IGraphicsDevice device; static IGraphicsDevice device;
public static Size Resolution { get { return device.WindowSize; } } public static Size Resolution { get { return device.WindowSize; } }
@@ -154,5 +163,19 @@ namespace OpenRA.Graphics
} }
throw new NotImplementedException(); throw new NotImplementedException();
} }
internal IVertexBuffer<Vertex> GetTempVertexBuffer()
{
var ret = tempBuffersV.Dequeue();
tempBuffersV.Enqueue( ret );
return ret;
}
internal IIndexBuffer GetTempIndexBuffer()
{
var ret = tempBuffersI.Dequeue();
tempBuffersI.Enqueue( ret );
return ret;
}
} }
} }

View File

@@ -14,26 +14,18 @@ namespace OpenRA.Graphics
{ {
public class SpriteRenderer public class SpriteRenderer
{ {
IVertexBuffer<Vertex> vertexBuffer;
IIndexBuffer indexBuffer;
Renderer renderer; Renderer renderer;
IShader shader; IShader shader;
const int spritesPerBatch = 1024; Vertex[] vertices = new Vertex[Renderer.TempBufferSize];
ushort[] indices = new ushort[Renderer.TempBufferSize];
Vertex[] vertices = new Vertex[4 * spritesPerBatch];
ushort[] indices = new ushort[6 * spritesPerBatch];
Sheet currentSheet = null; Sheet currentSheet = null;
int sprites = 0;
int nv = 0, ni = 0; int nv = 0, ni = 0;
public SpriteRenderer(Renderer renderer, IShader shader) public SpriteRenderer(Renderer renderer, IShader shader)
{ {
this.renderer = renderer; this.renderer = renderer;
this.shader = shader; this.shader = shader;
vertexBuffer = renderer.Device.CreateVertexBuffer( vertices.Length );
indexBuffer = renderer.Device.CreateIndexBuffer( indices.Length );
} }
public SpriteRenderer(Renderer renderer) public SpriteRenderer(Renderer renderer)
@@ -41,14 +33,16 @@ namespace OpenRA.Graphics
public void Flush() public void Flush()
{ {
if (sprites > 0) if (ni > 0)
{ {
shader.SetValue( "DiffuseTexture", currentSheet.Texture ); shader.SetValue( "DiffuseTexture", currentSheet.Texture );
shader.Render(() => shader.Render(() =>
{ {
vertexBuffer.SetData(vertices); var vb = renderer.GetTempVertexBuffer();
indexBuffer.SetData(indices); var ib = renderer.GetTempIndexBuffer();
renderer.DrawBatch(vertexBuffer, indexBuffer, vb.SetData(vertices, nv);
ib.SetData(indices, ni);
renderer.DrawBatch(vb, ib,
new Range<int>(0, nv), new Range<int>(0, nv),
new Range<int>(0, ni), new Range<int>(0, ni),
PrimitiveType.TriangleList, PrimitiveType.TriangleList,
@@ -57,7 +51,6 @@ namespace OpenRA.Graphics
nv = 0; ni = 0; nv = 0; ni = 0;
currentSheet = null; currentSheet = null;
sprites = 0;
} }
} }
@@ -76,11 +69,14 @@ namespace OpenRA.Graphics
if (s.sheet != currentSheet) if (s.sheet != currentSheet)
Flush(); Flush();
if( nv + 4 > Renderer.TempBufferSize )
Flush();
if( ni + 6 > Renderer.TempBufferSize )
Flush();
currentSheet = s.sheet; currentSheet = s.sheet;
Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size); Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, paletteIndex, nv, ni, size);
nv += 4; ni += 6; nv += 4; ni += 6;
if (++sprites >= spritesPerBatch)
Flush();
} }

View File

@@ -56,10 +56,10 @@ namespace OpenRA.Graphics
} }
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length ); vertexBuffer = Game.Renderer.Device.CreateVertexBuffer( vertices.Length );
vertexBuffer.SetData( vertices ); vertexBuffer.SetData( vertices, nv );
indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length ); indexBuffer = Game.Renderer.Device.CreateIndexBuffer( indices.Length );
indexBuffer.SetData( indices ); indexBuffer.SetData( indices, ni );
} }
public void Draw( Viewport viewport ) public void Draw( Viewport viewport )

View File

@@ -22,13 +22,21 @@ namespace OpenRA.GlRenderer
{ {
Gl.glGenBuffers(1, out buffer); Gl.glGenBuffers(1, out buffer);
GraphicsDevice.CheckGlError(); GraphicsDevice.CheckGlError();
}
public void SetData(ushort[] data)
{
Bind(); Bind();
Gl.glBufferData(Gl.GL_ELEMENT_ARRAY_BUFFER, 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(); GraphicsDevice.CheckGlError();
} }

View File

@@ -24,13 +24,21 @@ namespace OpenRA.GlRenderer
{ {
Gl.glGenBuffers(1, out buffer); Gl.glGenBuffers(1, out buffer);
GraphicsDevice.CheckGlError(); GraphicsDevice.CheckGlError();
}
public void SetData(T[] data)
{
Bind(); Bind();
Gl.glBufferData(Gl.GL_ARRAY_BUFFER, 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(); GraphicsDevice.CheckGlError();
} }