render perf improvement: BufferSubData, and don't use the same buffer back-to-back
This commit is contained in:
@@ -52,13 +52,13 @@ namespace OpenRA.FileFormats.Graphics
|
||||
public interface IVertexBuffer<T>
|
||||
{
|
||||
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
|
||||
|
||||
@@ -16,42 +16,41 @@ namespace OpenRA.Graphics
|
||||
public class LineRenderer
|
||||
{
|
||||
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[ 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 )
|
||||
|
||||
@@ -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<IVertexBuffer<Vertex>> tempBuffersV = new Queue<IVertexBuffer<Vertex>>();
|
||||
Queue<IIndexBuffer> tempBuffersI = new Queue<IIndexBuffer>();
|
||||
|
||||
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<Vertex> GetTempVertexBuffer()
|
||||
{
|
||||
var ret = tempBuffersV.Dequeue();
|
||||
tempBuffersV.Enqueue( ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal IIndexBuffer GetTempIndexBuffer()
|
||||
{
|
||||
var ret = tempBuffersI.Dequeue();
|
||||
tempBuffersI.Enqueue( ret );
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,26 +14,18 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
public class SpriteRenderer
|
||||
{
|
||||
IVertexBuffer<Vertex> 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<int>(0, nv),
|
||||
new Range<int>(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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user