Подтвердить что ты не робот

Является ли TDirect2DCanvas медленным, или я делаю что-то неправильно?

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

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

Итак, я думаю, что:
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 тыс. из них).

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

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

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

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

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

Дело в том, что GDI все еще быстрее, чем Direct2D, если я рисую растровое изображение, и после этого я вернул результат в форму, он рисует в ~ 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;
Кстати, даже если я использую предложение Chris о создании геометрии заранее, скорость примерно равна скорости GDI, но все же не быстрее.

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

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

4b9b3361

Ответ 1

Проблема заключается в том, что сглаживание включено. Отключить сглаживание и производительность 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;

Ответ 2

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

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

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

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

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

Ответ 3

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

Ответ 4

Что относительно скорости GDI +, в сравнении?

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

На практике производительность очень хорошая, а анти-алиаизация была... Мы используем это в нескольких проектах, рисуем содержимое регулярных компонентов в растровое изображение, а затем используем это растровое изображение для рисования содержимого формы на экране (это позволит избежать любой проблескивания). И с антиалиасингами, маркетинговые люди были довольны результатом, а другие программисты (используя С# или 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 установлен на ПК.