Конференция "Игры" » Как ускорить ход? [Delphi, Windows]
 
  • XNA (04.03.13 14:30) [0]
    Есть стандартный код, где нужно пройти по всем пикселям
    изображения и сделать что-нибудь с ними.

    Как его ускорить, оптимизировать, развернуть циклы и т.д.?
    Если изображение 32-bpp?


    procedure DummyFX(Bmp: TBitmap);
    var
     P   : PRGBA;     // Или TRGBQuad.
     X, Y: LongInt;
    begin
     For Y:= 0 to Bmp.Height - 1 do
     begin
       P:= Bmp.Scanline[Y];
       For X:= 0 to Bmp.Width - 1 do
       begin
         P.R:= 255; // Что-то делаем.
         P.G:= 0;
         P.B:= 30;
         P.A:= 30;

         Inc(P);
       end;
     end;
    end;

  • XNA (04.03.13 14:34) [1]
    * Как ускорить ход?

    Как ускорить код обработки всех пикселей?
  • MBo © (04.03.13 14:40) [2]
    Например, использовать SSE/MMX + проверить, эффективно ли будет развернуть циклы
  • RWolf © (04.03.13 14:49) [3]
    распараллелить на несколько потоков.
  • MBo © (04.03.13 16:43) [4]
    Ещё применение CUDA/ OpenCL можно рассмотреть
  • XNA (05.03.13 04:11) [5]
    > MBo ©   (04.03.13 14:40) [2]

    Может еще есть какие варианты?
  • MBo © (05.03.13 05:36) [6]
    Зависит от:
    // Что-то делаем.
  • XNA (05.03.13 14:02) [7]
    > MBo ©   (05.03.13 05:36) [6]
    > Зависит от:

    Т.е. сам перебор всех пикселей не оптимизировать?
    Может ещё тормозить TBitmap, знаю внутри он не оптимален.
  • MBo © (05.03.13 15:43) [8]
    >Может ещё тормозить TBitmap, знаю внутри он не оптимален.
    Небольшое время расходуется на получение ScanLine, но на фоне времени обработки самой строки им обычно можно пренебречь. Если очень хочется, то можно получить адрес первой строки и смещение строк (оно обычно отрицательное) и работать как с обычным куском памяти.
  • Павиа (06.03.13 16:18) [9]
    Bmp.Width - обращается к методу, что тормозит вложенный цикл. Заменяем на локальную переменную.
    P:= Bmp.Scanline[Y]; - хотя тоже тормозит, но вызывается в Bmp.Width раз меньше.

    For заменяем на repeat until.
    Раскрутка цикла.  
    Но обычно это всё копейки ,так как то что внутри занимает раз в 10-100 больше времени.  Остаётся только распараллеливание задачи.
  • MBo © (06.03.13 16:35) [10]
    >Bmp.Width - обращается к методу, что тормозит вложенный цикл. Заменяем на локальную переменную.

    Не нужно
  • XNA (12.03.13 06:54) [11]
    GetScanline - неимоверно тяжелая функция!

    DIBNeeded, где CopyBitmap.
    GDIFlush.
    Высчитывает BytesPerScanline, который можно рассчитать заранее.

    Закоментил первые и ничего не вылетало и продолжает работать!
    Но как сделать без правки VCL?
    В потомке нельзя перекрыть метод GetScanline.

    Как быть?
  • MBo © (12.03.13 08:19) [12]
    >GetScanline - неимоверно тяжелая функция!
    Она что, тратит время, сравнимое с обработкой строки?

    Вот библиотека попиксельного доступа:
    http://www.delphimaster.ru/articles/pixels/index.html
    Однако она на каждом шаге вычисляет адрес пикселов. При произвольных обращениях к разным местам картинки QPixels работает быстрее сканлайна. При последовательной обработке строк чуть быстрее сканлайн.
  • RWolf © (12.03.13 09:33) [13]

    > Как быть?

    не вызывать GetScanline, вычислять указатели самостоятельно.
  • Павиа (12.03.13 13:41) [14]
    Я использую такой вот код
    procedure Loop2D_3(var r:TBitMap; bm1,bm2:TBitMap; proc1:TProcLoop2d_1;proc2:TProcLoop2d_2); Overload;
    var i,j,k,p:Integer;
    LL,uf:Integer;
    p1,p2,p3:PAByte;
    begin
      LL:=DWord(bm1.ScanLine[1])-DWord(bm1.ScanLine[0]);
      LL:=LL-1;
      p1:=r.ScanLine[0];
      p2:=bm1.ScanLine[0];
      p3:=bm2.ScanLine[0];
      j:=bm1.Height;
      repeat
        Proc1(LL,p1,p2,p3);
        Inc(PByte(p1),LL);
        Inc(PByte(p2),LL);
        Inc(PByte(p3),LL);
        dec(j);
      until j=0;
    end;



    Накладные расходы этого кода составляют 1% точность измерения 0,001 или 0,1%.
  • XNA (12.03.13 17:17) [15]

    > MBo ©   (12.03.13 08:19) [12]
    >
    > >GetScanline - неимоверно тяжелая функция!
    > Она что, тратит время, сравнимое с обработкой строки?
    >
    > Вот библиотека попиксельного доступа:
    > http://www.delphimaster.ru/articles/pixels/index.html
    > Однако она на каждом шаге вычисляет адрес пикселов. При
    > произвольных обращениях к разным местам картинки QPixels
    > работает быстрее сканлайна. При последовательной обработке
    > строк чуть быстрее сканлайн.


    Попиксельно не надо.


    > RWolf ©   (12.03.13 09:33) [13]
    >
    >
    > > Как быть?
    >
    > не вызывать GetScanline, вычислять указатели самостоятельно.
    >

    Да, думаю сделать методы Lock(), Unlock.
    Побыстрее будет.



    > Павиа   (12.03.13 13:41) [14]
    >
    > Я использую такой вот код


    А что это такое, не понял.
    Что в цикле? Эффект?
  • Sapersky (12.03.13 17:43) [16]
    Тут уже была по крайней мере одна мега-ветка про оптимизацию софтвера:
    http://pda.delphimaster.net/?id=1186325580&n=9
    хотя, конечно, извлечь из неё что-то полезное непросто... в общем-то, и здесь основное уже сказали.
  • костыль (15.11.13 11:18) [17]
    Считай на ГПУ, скорость в разы увеличится.
  • имя (20.10.15 19:25) [18]
    Удалено модератором
  • Сергей (29.11.16 18:13) [19]
    вообще по сокращению кода может ни чего не сделать, а вот по скорости можно. Если сократить количество циклов повторяющихся, если известно что количество циклов положительно, то разложить в цикле на два, если делится на 4, то разложить на 4 и т. д.
 
Конференция "Игры" » Как ускорить ход? [Delphi, Windows]
Есть новые Нет новых   [118452   +47][b:0][p:0.002]