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>
|
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
|
||||||
|
|||||||
@@ -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 )
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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 )
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user