我的任务是绘制一个包含超过500,000个节点和边的巨大图形,具有移动节点,选择它们,移除等功能。
我正在使用C#.Net 4.6 winform applicatoin
我正在使用sharpdx(.net的directx包装器),但我有性能问题,每个渲染循环需要750ms~1.3 fps,这是不可接受的!我的GPU负载也不到10%,所以看起来我并没有完全使用我的GPU。我正在使用Direct2D,我为每个节点和边缘调用Draw方法(我认为这是主要问题!)。
我的问题是如何以合理的性能完成这项任务?
或者我如何减少平局调用。像批量抽奖这样的东西?
这是我的代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.Windows;
namespace SharpD2D
{
public partial class Form1 : Form
{
List<Geometry> lstGeoms;
public Factory Factory2D { get; private set; }
public SharpDX.DirectWrite.Factory FactoryDWrite { get; private set; }
public RenderTarget RenderTarget2D { get; private set; }
public RenderControl renderControl { get; private set; }
public Form1()
{
InitializeComponent();
InitRendererControl(this.Size);
InitDirect2DAndDirectWrite();
lstGeoms = Generator.GeomGenerator.getGeoms(Factory2D);
}
private void InitRendererControl(System.Drawing.Size? renderSize = null)
{
// create instance
renderControl = new RenderControl();
// renderControl.BackColor = System.Drawing.Color.Transparent;
if (renderSize.HasValue)
renderControl.Size = renderControl.ClientSize = renderSize.Value;
//events
renderControl.Paint += renderControl_Paint;
this.Controls.Add(renderControl);
}
private void renderControl_Paint(object sender, PaintEventArgs e)
{
renderBoard();
}
private void InitDirect2DAndDirectWrite()
{
Factory2D = new SharpDX.Direct2D1.Factory(FactoryType.MultiThreaded);
FactoryDWrite = new SharpDX.DirectWrite.Factory(SharpDX.DirectWrite.FactoryType.Shared);
var properties = new HwndRenderTargetProperties();
properties.Hwnd = renderControl.Handle;
properties.PixelSize = new Size2(renderControl.ClientSize.Width, renderControl.ClientSize.Height);
properties.PresentOptions = PresentOptions.RetainContents;
RenderTarget2D = new WindowRenderTarget(Factory2D, new RenderTargetProperties(new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.Unknown, AlphaMode.Premultiplied)), properties);
RenderTarget2D.AntialiasMode = AntialiasMode.Aliased;
RenderTarget2D.TextAntialiasMode = TextAntialiasMode.Aliased;
}
private void renderBoard()
{
RenderTarget2D.AntialiasMode = AntialiasMode.Aliased;
Stopwatch sw = new Stopwatch();
var brush = new SharpDX.Direct2D1.SolidColorBrush(RenderTarget2D, new Color4(0.3f, 0.5f, 0.9f, 1f));
RenderLoop.Run(renderControl, () =>
{
sw.Restart();
RenderTarget2D.BeginDraw();
RenderTarget2D.Clear(new Color4(0f, 0f, 0f, 1f));
foreach (var item in lstGeoms)
{
RenderTarget2D.FillGeometry(item, brush);
}
RenderTarget2D.Flush();
RenderTarget2D.EndDraw();
sw.Stop();
var totalElappsed = sw.ElapsedMilliseconds;
var fps = 1000 / (totalElappsed == 0 ? 0.000001 : totalElappsed);
Console.WriteLine($"Count: {lstGeoms.Count} : {totalElappsed.ToString()} , {fps}");
});
}
}
}
GeomGenerator类产生500k随机椭圆:
using SharpDX;
using SharpDX.Direct2D1;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Generator
{
public class GeomGenerator
{
[StructLayout(LayoutKind.Sequential)]
public struct Vertex
{
public Vector4 Position;
public SharpDX.ColorBGRA Color;
}
public static List<Geometry> getGeoms(SharpDX.Direct2D1.Factory d2dFactory)
{
var lstGeoms = new List<Geometry>();
int count = 500 * 1000;
Random r = new Random();
var bound = 650;
var lowerBound = 0;
var upperBound = bound;
for (int i = 0; i < count; i++)
{
var location = new Point(r.Next(lowerBound, upperBound), r.Next(lowerBound, upperBound));
var center = new SharpDX.Mathematics.Interop.RawVector2() { X = location.X, Y = location.Y };
var ellipse = new SharpDX.Direct2D1.Ellipse(center, 1, 1);
var mainGeo = new EllipseGeometry(d2dFactory, ellipse);
lstGeoms.Add(mainGeo);
}
return lstGeoms;
}
}
}
提前致谢。