TDirect2DCanvas работает медленно или я что-то не так делаю? - PullRequest
22 голосов
/ 30 октября 2010

При поиске альтернатив для замены GDI я пытался протестировать производительность Delphi 2010 TDirect2DCanvas в Windows 7.

Я протестировал ее, нарисовав огромную ломаную линию с использованием Direct2D, и в результате получилосьабсурдно медленный, даже с объемом данных в 500 раз меньшим, чем тот, который я выполнил в том же тесте с использованием GDI (и я даже не использовал растровое изображение в качестве backbuffer в GDI, я просто обратился непосредственно к холсту формы).

Итак, я думаю, либо:
a) Direct2D медленнее, чем GDI;
b) TDirect2DCanvas медленный;
c) Я делаю что-то не так
и, надеюсь, это с).

Код теста, который я написал:

unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Direct2D, D2D1;

type
  TForm2 = class(TForm)
  private
    { Private declarations }
    FD2DCanvas: TDirect2DCanvas;
    FData: array[0..50000] of TPoint;
  public
    procedure CreateWnd; override;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;


    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

uses utils;

{$R *.dfm}

procedure TForm2.CreateWnd;
var
  i: Integer;
begin
  inherited;
  FD2DCanvas := TDirect2DCanvas.Create(Handle);

  for i := 0 to High(FData) do begin
    FData[i].X := Random(Self.ClientWidth  div 2);
    FData[i].Y := Random(Self.ClientHeight);
  end;
end;

procedure TForm2.WMPaint(var Message: TWMPaint);
var
  PaintStruct: TPaintStruct;
begin
  BeginPaint(Handle, PaintStruct);
  try
    FD2DCanvas.BeginDraw;

    try
      FD2DCanvas.Polyline(FData);
    finally
      FD2DCanvas.EndDraw;
    end;

  finally
    EndPaint(Handle, PaintStruct);
  end;

end;

procedure TForm2.WMSize(var Message: TWMSize);
begin
  if Assigned(FD2DCanvas) then begin
    ID2D1HwndRenderTarget(FD2DCanvas.RenderTarget).Resize(D2D1SizeU(ClientWidth, ClientHeight));
  end;
end;

end.

Кроме того, я действительно хочу рисовать длинные полилинии в реальномкод, как система, над которой я работаю, нужно нарисовать много ~ 2500 точек полилиний (по крайней мере, 10 000 из них).

Обновлено (2010-11-06)

Ранее я обнаружил, что Direct2D, похоже, не любит полилинии, он рисуется быстрее, если вы используетемного одиночных линий (2 точки полилинии).

Благодаря Крису Бенсену Я обнаружил, что медлительность была с большими полилиниями при использовании сглаживания .Поэтому я отключил сглаживание, как предложил Крис, и производительность рисовалась с ~ 6000 мс до ~ 3500 мс для рисования линий по 50 000.

Все еще можно улучшить, поскольку Direct2D просто не справляется с полилиниями при использованиисглаживание .С отключенным сглаживанием все наоборот.

Теперь время рисования с Direct2D линий 50k, если я рисую большую полилинию без сглаживания, составляет ~ 50 мс.Прекрасно, ах!

Дело в том, что GDI все еще быстрее, чем Direct2D , если я рисую в растровое изображение и после того, как это сделано, я BitBlt результат обратно в форму, он рисует ~ 35 мс и с тем же качеством графики.Кроме того, Direct2D, похоже, уже использует backbuffer (он просто рисует, когда вызывается EndDraw()).

Итак, можно ли это как-то улучшить, чтобы использование Direct2D стоило по скорости?

Вот обновленный код:

type
  TArray = array[0..1] of TPoint;
  PArray = ^TArray;

procedure TForm2.WMPaint(var Message: TWMPaint);
var
  PaintStruct: TPaintStruct;
begin
  FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
  BeginPaint(Handle, PaintStruct);
  try
    FD2DCanvas.BeginDraw;
    try
      FD2DCanvas.Pen.Color := clRed;
      FD2DCanvas.Polyline(FData);
    finally
      FD2DCanvas.EndDraw;
    end;   
  finally
    EndPaint(Handle, PaintStruct);
  end;
end;

Кстати, даже если я использую Крис 'предложение о создании геометрии заранее, скорость примерно равна той же скоростикак GDI, но все же не быстрее.

Мой компьютер нормально работает с приложениями Direct3D и OpenGL, и вот вывод dxDiag: http://mydxdiag.pastebin.com/mfagLWnZ

Я буду рад, если кто-нибудь сможет объяснить мне, почему этомедленность.Пример кода очень ценится.

Ответы [ 4 ]

26 голосов
/ 05 ноября 2010

Проблема в том, что сглаживание включено. Отключите сглаживание, и производительность Direct2D будет на уровне или выше, чем у GDI. Чтобы сделать это после создания TDirect2DCanvas, выполните этот вызов:


  FD2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

TDirect2DCanvas совместим с интерфейсом, где это возможно, с TCanvas, поэтому его можно заменить на TCanvas, поэтому некоторые процедуры рисования немного неэффективны. Например, Polyline создает геометрию каждый раз, когда она вызывается, и выбрасывает ее. Для повышения производительности сохраняя геометрию вокруг.

Взгляните на реализацию TDirect2DCanvas.Polyline и добавьте это в ваше приложение для чего-то вроде этого:


procedure TForm2.CreateWnd;
var
  i: Integer;
  HR: HRESULT;
  Sink: ID2D1GeometrySink;
begin
...
  D2DFactory.CreatePathGeometry(FGeometry);
  HR := FGeometry.Open(Sink);
  try
    Sink.BeginFigure(D2D1PointF(FData[0].X + 0.5, FData[0].Y + 0.5), 
      D2D1_FIGURE_BEGIN_HOLLOW);
    try
      for I := Low(FData) + 1 to High(FData) - 1 do
        Sink.AddLine(D2D1PointF(FData[I].X + 0.5, FData[I].Y + 0.5));
    finally
      Sink.EndFigure(D2D1_FIGURE_END_OPEN);
    end;
  finally
    hr := Sink.Close;
  end;

А затем нарисуйте это так:


procedure TForm2.WMPaint(var Message: TWMPaint);
begin
  FD2DCanvas.BeginDraw;
  FD2DCanvas.Pen.Color := clRed;
  FD2DCanvas.RenderTarget.DrawGeometry(FGeometry, FD2DCanvas.Pen.Brush.Handle);
  FD2DCanvas.EndDraw;
end;
3 голосов
/ 16 ноября 2012

Во всех моих тестах производительности OpenGL (с сглаживанием MSAA и без него) работает быстрее, чем GDI, GDI + или Direct2D, для конкретного случая рисования 2D-элементов, таких как многоугольники, линии, прямоугольники и т. Д.

3 голосов
/ 08 ноября 2010

Direct2D опирается на реализацию драйвера и аппаратного обеспечения, поэтому вы обязательно будете испытывать сбои в производительности в зависимости от аппаратного обеспечения и драйвера, на котором работаете (тот же пакет проблем, с которым сталкиваются движки 3D рендеринга).

Например, в вопросе рендеринга линий вы, вероятно, столкнетесь с некоторыми (скрытыми) проблемами аппаратного буфера: при задании аппаратного + драйвера при рисовании ломаной линии, если базовый размер данных ниже определенного порога, производительность может быть высокой, с полным аппаратным ускорением.Выше этого порога вы можете откатиться к частично программному или неоптимизированному пути, и производительность упадет.Порог будет зависеть от аппаратного обеспечения, драйвера и параметров кисти / чертежа, может быть там или нет.

Это те же проблемы, что и при рендеринге 2D или 3D с помощью OpenGL или обычного DirectX, если вы уходите за пределы скважины.пробитые пути рендеринга, все не так радужно.

Что касается рендеринга не сглаженной графики, мой совет - придерживаться GDI, реализации надежны с широко распространенной аппаратной поддержкой.

Для сглаженной графики, GDI +, Graphics32, AGG и в целом программные решения предпочтительнее IME всякий раз, когда у вас нет контроля над оборудованием конечного пользователя.В противном случае подготовьтесь к проблемам с поддержкой клиентов.

1 голос
/ 07 ноября 2010

А как насчет скорости GDI +, в сравнении?

Мы написали бесплатный модуль с открытым исходным кодом, способный отображать любой контент VCL TCanvas (используя TMetaFile) с использованием механизма GDI +.

На практике производительность очень хорошая, и сглаживание было ... Мы используем это в нескольких проектах, рисуем содержимое обычных компонентов в растровое изображение, а затем используем это растровое изображение для отображения содержимого формы на экране (это позволит избежать проблем с мерцанием). А благодаря сглаживанию маркетологи были довольны результатом, а другие программисты (использующие C # или WPF) задались вопросом, как он работает: рисование очень быстрое, а приложения реагируют (как хорошо построенные приложения Delphi), используют очень мало памяти, и результат на экране выглядит современно (особенно если вы используете Calibri или такие шрифты, если они есть в вашей системе).

См. http://synopse.info/forum/viewtopic.php?id=10

Он будет работать с любой версией Delphi (от Delphi 6 до Delphi XE) и работать на любой версии Windows (XP, Vista, Seven - необходимо развернуть стандартную версию gdiplus.dll с предыдущей ОС).

Наше устройство использует паскаль-код для преобразования GDI в GDI + в XP и встроенный скрытый API Microsoft под Vista, Seven или если на компьютере установлен Office 2003/2007.

...