Возможное размышление об оптимизации GDI + DrawLines - PullRequest
4 голосов
/ 07 ноября 2010

Я пытаюсь повысить производительность с помощью функции c # GDI + DrawLines. Когда я запускаю профилировщик для кода, я вижу, что почти половина времени, проводимого в функции DrawLines, готовит массив точек для отправки в нативный GDI + dll. Это похоже на большие накладные расходы, и мне интересно, мог бы кто-нибудь придумать более эффективный способ взаимодействия с функцией DrawLines, чем собственная реализация функции DrawLines в System.Drawing

Вот родные функции Systemm.Drawing:

public void DrawLines(Pen pen, PointF[] points)
{
    if (pen == null)
    {
        throw new ArgumentNullException("pen");
    }
    if (points == null)
    {
        throw new ArgumentNullException("points");
    }
    IntPtr handle = SafeNativeMethods.Gdip.ConvertPointToMemory(points);
    int status = SafeNativeMethods.Gdip.GdipDrawLines(new HandleRef(this,this.NativeGraphics), new HandleRef(pen, pen.NativePen), new   HandleRef(this, handle),     points.Length);
Marshal.FreeHGlobal(handle);
    this.CheckErrorStatus(status);

}

internal static IntPtr ConvertPointToMemory(PointF[] points)
{
    if (points == null)
    {
        throw new ArgumentNullException("points");
    }
    int num2 = Marshal.SizeOf(new GPPOINTF().GetType());
    int length = points.Length;
    IntPtr ptr = Marshal.AllocHGlobal((int) (length * num2));
    for (int i = 0; i < length; i++)
    {
        Marshal.StructureToPtr(new GPPOINTF(points[i]), (IntPtr) (((long) ptr) + (i * num2)), false);
    }
    return ptr;
}

Ответы [ 2 ]

4 голосов
/ 28 ноября 2010

Этот метод "DrawLines" несколько неудачен (а также несколько других методов в .NET-GDI + -API). Прежде всего, это просто массив, что означает, что количество точек должно точно соответствовать размеру массива; Если вы не уверены, сколько очков у вас будет при подготовке, вам нужно вызвать Array.Resize, чтобы скопировать данные. Во-вторых, первым действием в DrawLine-методе является копирование точек - почему бы не передать исходные данные в GDI +? Фактически данные копируются дважды, прежде чем они попадают в GDI +.
Что можно с этим сделать:

  • Используйте GDI + Flat API из C # (с использованием P / Invoke).
  • Используйте (родной) C ++ API] (например, используйте C ++ / CLI для взаимодействия с C #).

Первая идея может выглядеть примерно так:

public void DrawLines(System.Drawing.Color color, ref System.Drawing.Point[] points, int pointsCount)
    {
        IntPtr pen = IntPtr.Zero;
        int status = GdipCreatePen1(
                                color.ToArgb(),
                                1,
                                (int)GraphicsUnit.World,
                                out pen);
        unsafe
        {
            fixed (Point* pointerPoints = points)
            {
                status = GdipDrawLinesI(new HandleRef(this, this.handleGraphics), new HandleRef(this, pen), (IntPtr)pointerPoints, pointsCount);
            }
        }

        status = GdipDeletePen(new HandleRef(this, pen));
    }

    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true, CharSet = System.Runtime.InteropServices.CharSet.Unicode)] 
    private static extern int GdipDrawLinesI(HandleRef graphics, HandleRef pen, IntPtr points, int count);        
    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true)]
    private static extern int GdipDeletePen(HandleRef pen);
    [DllImport(GDIPlusDll, SetLastError = true, ExactSpelling = true)]
    private static extern int GdipCreatePen1(int argb, float width, int unit, out IntPtr pen);

Кстати - можно получить доступ к собственным дескрипторам в объектах .NET-GDI + с помощью отражения (конечно, это недокументировано, вам нужен доступ к закрытому методу). Для объекта System.Drawing.Font это будет выглядеть примерно так:

Type type = typeof(System.Drawing.Font);
System.Reflection.PropertyInfo propInfoNativeFontHandle = type.GetProperty("NativeFont", System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
System.Drawing.Font font = ...
IntPtr nativeHandle = propInfoNativeFontHandle.GetValue(font, null)
0 голосов
/ 07 ноября 2010

Если вы пытаетесь улучшить производительность операций 2D-рисования в C # в Windows, вам следует рассмотреть Direct 2D # .

...