optimize 2D renderer: try to avoid splitting render commands, try to use single pass if blending is unneeded (i.e. alpha is always 0xFF)

This commit is contained in:
CasualPokePlayer 2024-09-20 01:24:04 -07:00
parent a2ddc1b4cd
commit e720650085
1 changed files with 31 additions and 113 deletions

View File

@ -55,6 +55,8 @@ namespace BizHawk.Bizware.Graphics
private readonly HashSet<GCHandle> _gcHandles = [ ];
private ITexture2D _stringTexture;
private IRenderTarget _pass1RenderTarget;
private bool _splitNextCmd;
private bool _needBlending;
protected virtual float RenderThickness => 1;
@ -140,6 +142,8 @@ namespace BizHawk.Bizware.Graphics
_imGuiDrawList._ResetForNewFrame();
_imGuiDrawList.Flags |= ImDrawListFlags.AllowVtxOffset;
_hasDrawStringCommand = false;
_splitNextCmd = false;
_needBlending = false;
EnableBlending = _pendingBlendEnable;
}
@ -169,7 +173,7 @@ namespace BizHawk.Bizware.Graphics
private void PerformPasses(ImDrawCmdPtr cmd)
{
if (EnableBlending)
if (EnableBlending && _needBlending)
{
_pass1RenderTarget.Bind();
_resourceCache.SetBlendingParamters(_pass2RenderTarget, false);
@ -373,23 +377,31 @@ namespace BizHawk.Bizware.Graphics
case true when value == CompositingMode.SourceCopy:
_imGuiDrawList.AddCallback((IntPtr)DrawCallbackId.DisableBlending, IntPtr.Zero);
_pendingBlendEnable = false;
_splitNextCmd = false;
break;
// CompositingMode.SourceOver means enable blending
case false when value == CompositingMode.SourceOver:
_imGuiDrawList.AddCallback((IntPtr)DrawCallbackId.EnableBlending, IntPtr.Zero);
_pendingBlendEnable = true;
_splitNextCmd = false;
break;
}
}
}
public void DrawBezier(Color color, Point pt1, Point pt2, Point pt3, Point pt4)
private void CheckAlpha(Color color)
{
if (color.A != 0xFF)
if (color.A != 0xFF || _splitNextCmd)
{
_imGuiDrawList.AddDrawCmd();
_splitNextCmd = color.A != 0xFF;
_needBlending = true;
}
}
public void DrawBezier(Color color, Point pt1, Point pt2, Point pt3, Point pt4)
{
CheckAlpha(color);
_imGuiDrawList.AddBezierCubic(
p1: pt1.ToVector(),
p2: pt2.ToVector(),
@ -397,11 +409,6 @@ namespace BizHawk.Bizware.Graphics
p4: pt4.ToVector(),
col: (uint)color.ToArgb(),
thickness: RenderThickness);
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public void DrawBeziers(Color color, Point[] points)
@ -411,15 +418,11 @@ namespace BizHawk.Bizware.Graphics
throw new InvalidOperationException("Invalid number of points");
}
CheckAlpha(color);
var startPt = points[0];
var col = (uint)color.ToArgb();
for (var i = 1; i < points.Length; i += 3)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
_imGuiDrawList.AddBezierCubic(
p1: startPt.ToVector(),
p2: points[i + 0].ToVector(),
@ -428,20 +431,12 @@ namespace BizHawk.Bizware.Graphics
col: col,
thickness: RenderThickness);
startPt = points[i + 2];
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
}
public void DrawRectangle(Color color, int x, int y, int width, int height)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
CheckAlpha(color);
// we don't use AddRect as we want to avoid double drawing at the corners
// as that produces artifacts with alpha blending
@ -455,12 +450,6 @@ namespace BizHawk.Bizware.Graphics
{
// width or height of 1 is just a single line
DrawLineInternal(color, x, y, right, bottom);
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
return;
}
@ -472,38 +461,20 @@ namespace BizHawk.Bizware.Graphics
DrawLineInternal(color, right - 1, bottom, x, bottom);
// bottom left (and 1 pixel up) to top left (and 1 pixel down)
DrawLineInternal(color, x, bottom - 1, x, y + 1);
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public void FillRectangle(Color color, int x, int y, int width, int height)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
CheckAlpha(color);
_imGuiDrawList.AddRectFilled(
p_min: new(x, y),
p_max: new(x + width, y + height),
col: (uint)color.ToArgb());
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public void DrawEllipse(Color color, int x, int y, int width, int height)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
CheckAlpha(color);
var radius = new Vector2(width / 2.0f, height / 2.0f);
_imGuiDrawList.AddEllipse(
center: new(x + radius.X, y + radius.Y),
@ -512,34 +483,22 @@ namespace BizHawk.Bizware.Graphics
rot: 0,
num_segments: 0,
RenderThickness);
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public void FillEllipse(Color color, int x, int y, int width, int height)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
CheckAlpha(color);
var radius = new Vector2(width / 2.0f, height / 2.0f);
_imGuiDrawList.AddEllipseFilled(
center: new(x + radius.X, y + radius.Y),
radius: radius,
col: (uint)color.ToArgb());
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public void DrawImage(Bitmap image, int x, int y)
{
_splitNextCmd = false;
_needBlending = true;
var texture = new ImGuiUserTexture { Bitmap = image, WantCache = false };
var handle = GCHandle.Alloc(texture, GCHandleType.Normal);
_gcHandles.Add(handle);
@ -551,6 +510,8 @@ namespace BizHawk.Bizware.Graphics
public void DrawImage(Bitmap image, Rectangle destRect, int srcX, int srcY, int srcWidth, int srcHeight, bool cache)
{
_splitNextCmd = false;
_needBlending = true;
var texture = new ImGuiUserTexture { Bitmap = image, WantCache = cache };
var handle = GCHandle.Alloc(texture, GCHandleType.Normal);
_gcHandles.Add(handle);
@ -600,26 +561,13 @@ namespace BizHawk.Bizware.Graphics
public void DrawLine(Color color, int x1, int y1, int x2, int y2)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
CheckAlpha(color);
DrawLineInternal(color, x1, y1, x2, y2);
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public void DrawPie(Color color, int x, int y, int width, int height, int startAngle, int sweepAngle)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
CheckAlpha(color);
var radius = new Vector2(width / 2.0f, height / 2.0f);
var center = new Vector2(x + radius.X, y + radius.Y);
var aMin = (float)(Math.PI / 180 * startAngle);
@ -627,20 +575,11 @@ namespace BizHawk.Bizware.Graphics
_imGuiDrawList.PathEllipticalArcTo(center, radius, 0, aMin, aMax);
_imGuiDrawList.PathLineTo(center);
_imGuiDrawList.PathStroke((uint)color.ToArgb(), ImDrawFlags.Closed, RenderThickness);
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public void FillPie(Color color, int x, int y, int width, int height, int startAngle, int sweepAngle)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
CheckAlpha(color);
var radius = new Vector2(width / 2.0f, height / 2.0f);
var center = new Vector2(x + radius.X, y + radius.Y);
var aMin = (float)(Math.PI / 180 * startAngle);
@ -648,61 +587,40 @@ namespace BizHawk.Bizware.Graphics
_imGuiDrawList.PathEllipticalArcTo(center, radius, 0, aMin, aMax);
_imGuiDrawList.PathLineTo(center);
_imGuiDrawList.PathFillConvex((uint)color.ToArgb());
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
public unsafe void DrawPolygon(Color color, Point[] points)
{
CheckAlpha(color);
var vectorPoints = Array.ConvertAll(points, static p => new Vector2(p.X + 0.5f, p.Y + 0.5f));
fixed (Vector2* p = vectorPoints)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
_imGuiDrawList.AddPolyline(
points: ref *p,
num_points: vectorPoints.Length,
col: (uint)color.ToArgb(),
flags: ImDrawFlags.Closed,
thickness: RenderThickness);
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
}
public unsafe void FillPolygon(Color color, Point[] points)
{
CheckAlpha(color);
var vectorPoints = Array.ConvertAll(points, static p => new Vector2(p.X + 0.5f, p.Y + 0.5f));
fixed (Vector2* p = vectorPoints)
{
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
_imGuiDrawList.AddConcavePolyFilled(
points: ref *p,
num_points: vectorPoints.Length,
col: (uint)color.ToArgb());
if (color.A != 0xFF)
{
_imGuiDrawList.AddDrawCmd();
}
}
}
public void DrawString(string s, Font font, Color color, float x, float y, StringFormat format, TextRenderingHint textRenderingHint)
{
_splitNextCmd = false;
_needBlending |= color.A != 0xFF;
var stringArgs = new DrawStringArgs { Str = s, Font = font, Color = color, X = x, Y = y, Format = format, TextRenderingHint = textRenderingHint };
var handle = GCHandle.Alloc(stringArgs, GCHandleType.Normal);
_gcHandles.Add(handle);