Конференция "Прочее" » Быстрый tiling
 
  • tesseract © (28.03.08 20:12) [0]
    Использую тупо циклы for + draw в buffer.  paint перерисовывает буфер только при изменении размеров control.  В моём случае что-то дофига умножений выходит, как можно ускорить ?  Не горит, но интересно.
  • Игорь Шевченко © (28.03.08 20:20) [1]
    а зачем умножать ? tiling, насколько я понимаю, это заполнение шаблоном ?
  • tesseract © (28.03.08 20:25) [2]

    >  tiling, насколько я понимаю, это заполнение шаблоном ?


    ага заполнение изображения нужным количеством копий по размеру отображения, нужно перерисовка в runtime  и быстрая.

    ЗЫ: наследник TCustom Panel все работает быстро кроме этого тайлинга при изменении размера формы.
  • Игорь Шевченко © (28.03.08 20:29) [3]
    tesseract ©   (28.03.08 20:25) [2]

    DoubleBuffered ?

    А вообще код давай (с)
  • antonn © (28.03.08 20:30) [4]
    а не надо draw, попробуй canvas.copyrect()/bltbtn
  • tesseract © (28.03.08 20:35) [5]

    >  canvas.copyrect()


    Copyrect медленне Draw кстати. Он Resize  делает.  


    > DoubleBuffered ?


    Tripple выходит :-)

    Там просто через For идёт заполнение backbuffer - сам буффер меняеться только при изменении размера или параметров картинки.
  • antonn © (28.03.08 20:39) [6]

    > Copyrect медленне Draw кстати

    а попробывать? :) он почти такой же по скорости, как и BitBlt, я на нем игры пишу :) а вот draw, не знаю, что там проиходит внутрях, но тормозит немеряно...
  • antonn © (28.03.08 20:40) [7]
    кстати, блитятся картинки одной pixelformat?
  • tesseract © (28.03.08 20:41) [8]

    >  вот draw, не знаю, что там проиходит внутрях, но тормозит
    > немеряно...


    У меня другие результаты. Возможно потому, что не игры. Внутрях он может вызывать преобразование Tgraphic в HBitmap, но как правило так не делает.
  • tesseract © (28.03.08 20:42) [9]

    > кстати, блитятся картинки одной pixelformat?


    Задача размножить картинку на весь Canvas, с вычислением обрезки по краям.
  • antonn © (28.03.08 20:58) [10]
    покажи код, плиз
  • tesseract © (28.03.08 21:02) [11]
    Он в разработке. Говорю пока выходит сильно фиговый.



    // простая заливка
       ttSimpleTile: begin
                       WidthDiff := (ClRect.Right  -ClRect.Left-xCount*FullImageWidth);
                       HeightDiff:= (ClRect.Bottom -ClRect.Top- yCount*FullImageHeight);

                       tX:=ClRect.Right-WidthDiff;
                       tY:=ClRect.Left-HeightDiff;
                      for cX:= 0 to xCount-1 do
                       begin
                       for cY := 0 to yCount - 1 do
                         begin
                         // основной вывод
                           TileRec:=Rect(cX*FullImageWidth+fTileBorderWidth+ClRect.Left,cY*FullImageHeight+fTileBorderWidth+clRect.Top,0,0);
                             fBackBuffer.Canvas.Draw(TileRec.left,TileRec.top,FPicture.Bitmap);
                           TileRec:=Rect(tx,cY*FullImageHeight+fTileBorderWidth+ClRect.Top,ClRect.Right,cY*FullImageHeight+fTileBorderWidth+ClRect.Top+HeightDiff);
                             fBackBuffer.Canvas.Draw(TileRec.Left,TileRec.Top,FPicture.Bitmap);
                          end;
                          // край по y-ку

                       end;
                         //вывод оконцовки
                      //   TileRec:=Rect(xCount*FullImageWidth+fTileBorderWidth+clRect.Left,yCount*FullImageHeight+fTileBorderWidth+ClRect.Top,WidthDiff+ClREct.Left,HeightDiff+clRect.Top);
                      //   fBackBuffer.Canvas.CopyRect(TileRec,FPicture.Bitmap.Canvas,FbmpRect);
                    end;


  • homm © (28.03.08 21:13) [12]
    > [9] tesseract ©   (28.03.08 20:42)
    > > кстати, блитятся картинки одной pixelformat?
    > Задача размножить картинку на весь Canvas, с вычислением
    > обрезки по краям.

    Ответ не соответствует вопросу.
  • antonn © (28.03.08 21:16) [13]
    так, щас будет много корявого кода :)
    procedure FillTexturka2canvas( Acanvas:Tcanvas; _Texturka:Tbitmap; _R:Trect; _x,_y:integer);
    var i,ii,xtmp,ytmp,ww,hh:integer;
    begin
    ww:=_Texturka.Width;
    hh:=_Texturka.Height;
    xtmp:=(_x-(_x div ww)*ww);
    ytmp:=(_y-(_y div _Texturka.Height)*_Texturka.Height);
    for i:=-1 to ((_R.Right-_R.Left) div ww) do
    for ii:=-1 to ((_R.Bottom-_R.top) div hh) do
    Acanvas.CopyRect(rect(i*ww+xtmp,ii*hh+ytmp,(i+1)*ww+xtmp,(ii+1)*hh+ytmp), _Texturka.Canvas ,rect(0,0,ww,hh));
    end;

    procedure FillTexturka2canvas2( Acanvas:Tcanvas; _Texturka:Tbitmap; _R:Trect; _x,_y:integer);
    var i,ii,xtmp,ytmp,ww,hh:integer;
    begin
    ww:=_Texturka.Width;
    hh:=_Texturka.Height;
    xtmp:=(_x-(_x div ww)*ww);
    ytmp:=(_y-(_y div _Texturka.Height)*_Texturka.Height);
    for i:=-1 to ((_R.Right-_R.Left) div ww) do
    for ii:=-1 to ((_R.Bottom-_R.top) div hh) do
    Acanvas.Draw(i*ww+xtmp,ii*hh+ytmp,_Texturka);
    end;

    procedure FillTexturka2canvas3( Acanvas:Tcanvas; _Texturka:Tbitmap; _R:Trect; _x,_y:integer);
    var i,ii,xtmp,ytmp,ww,hh:integer;
    begin
    ww:=_Texturka.Width;
    hh:=_Texturka.Height;
    xtmp:=(_x-(_x div ww)*ww);
    ytmp:=(_y-(_y div _Texturka.Height)*_Texturka.Height);
    for i:=-1 to ((_R.Right-_R.Left) div ww) do
    for ii:=-1 to ((_R.Bottom-_R.top) div hh) do
    BitBlt(ACanvas.Handle,i*ww+xtmp,ii*hh+ytmp,(i+1)*ww+xtmp,(ii+1)*hh+ytmp,_Texturka.Canvas.Handle,0,0,SRCCOPY);
    end;



    Тест для трех процедурок, первая canvas.copyrect(), вторая canvas.draw, третья BitBlt(). В тесте на картнку 1600*1200пикселей копировалась битмапка 48*48 в цикле 1000 раз.
    FillTexturka2canvas: 5,36519529716766
    FillTexturka2canvas2: 5,53980799235657
    FillTexturka2canvas3: 5,13526998543111
  • antonn © (28.03.08 21:17) [14]
    и кстати, более чем уверен, что это из-за моего коре дуо результаты так мало расходятся, хотелось бы проверить на атлоне, щас напишу тестик :)
  • tesseract © (28.03.08 21:21) [15]

    > и кстати, более чем уверен, что это из-за моего коре дуо
    > результаты так мало расходятся, хотелось бы проверить на
    > атлоне, щас напишу тестик :)


    Всегда считал что bitblt видеокартой выполняеться.
  • antonn © (28.03.08 21:25) [16]
    вот и проверим...
    http://desksoft.ru/index.php?downloads=attachments&id=71 (208Кб, zip)
    запустить и написать сюда, мой кора:
    canvas.CopyRect: 5,28903645575066
    canvas.Draw: 5,5305635213414
    BitBlt: 5,10156989226284

    хотелось бы увидеть именно атлоны, они в прошлый раз моего теста нехорошо себя показали :)
  • tesseract © (28.03.08 21:31) [17]
    гляну завтра - но умножений всё равно перебор. Алгоритм работает даже в потоке, но подмигивает. +/- 10 миллисекунд неколышет.  BackBuffer перерисовываеться только при изменении размера формы или параметров отрисовки - т.е примерно раз в полгода (именно так софт 24/7) :-).
  • tesseract © (28.03.08 21:33) [18]

    > вот и проверим...


    VgaSafe поставь.  И так потесть. На процессор ведь дрова видюхи влиять не могут ?
  • antonn © (28.03.08 21:37) [19]

    > VgaSafe поставь.  И так потесть.

    у меня правило - работает - не трожь :) особенно это косается драйверов и администрирования :)
  • tesseract © (28.03.08 21:45) [20]
    Твой код от моего, только читаемостью отличаеться. Умножений много + обрезки ещё выводить.

    Вообще там просто в рабочий проект требуеться добавить скины к TPanel и TGridPanel. Поэтому и тайлинг - нужно поддёвку к TControlCollection добавлять.
  • antonn © (28.03.08 21:49) [21]
    ну открыть у панели канвас, BitBlt'у хватит :)
  • antonn © (28.03.08 21:52) [22]
    а может там просто фон перерисовывается и своим морганием вводит в заблуждение? :)
  • tesseract © (28.03.08 21:56) [23]

    > а может там просто фон перерисовывается и своим морганием
    > вводит в заблуждение? :)


    В других режимах не моргает :-)  В коде есть часть Case - он и выбирает часть прорисовки. Код не тормозит, просто хотелось получить наиболее грматоное решение.
  • antonn © (28.03.08 22:04) [24]
    а draw вроде бы умеет копировать с учетом прозрачного ключа, может из-за этого как то тормозит? или я что то путаю...
  • tesseract © (28.03.08 22:06) [25]

    >  может из-за этого как то тормозит? или я что то путаю..
    > .


    F8  разъяснит. Draw вызывает нужную функцию GDI и всё. Почему он у тебя тормозит - сам не понимаю.
  • Игорь Шевченко © (28.03.08 22:08) [26]
    Посмотри в JVCL JvBackgrounds.pas
  • tesseract © (28.03.08 22:10) [27]

    > Посмотри в JVCL JvBackgrounds.pas


    Гляну, только jvcl как то ожирел, аш перебор. Но функцию глянуть не проблема. Спасибо всем.
  • GrayFace © (29.03.08 01:57) [28]
    По-моему, не нужны лишние буфферы, лечше битмапку выводить сразу на канвас, если она не сильно маленькая. А если маленькая, заранее объединить в битмапки побольше. Экономия на лишнем выводе буфера и на том, что вне обновившейся области не рисуется. А вместо умножения складывать. Как-то так:
    var
     BmpRect: TRect;
    begin
      BmpRect:= bmp.Canvas.ClipRect;
      w:= Width;
      h:= Height;
      y:= 0;
      repeat
        x:= 0;
        repeat
          BitBlt(...);
          inc(x, BmpRect.Right);
        until x >= w;

        inc(y, BmpRect.Bottom);
      until y >= h;
    end;

  • tesseract © (29.03.08 15:38) [29]

    > По-моему, не нужны лишние буфферы,


    Буффер необходим. Потому как идёт пересчёт бордюра + бэка. Пересчёт буффера происходит только при изменении размеров контрола, что снижает нагрузку на перерисовку в 10-15 раз. А вообще почитай ветку про DoubleBuffered или сначала пойми , почему мне нужен именно потомок TWinControl, а не TGraphicControl.


    >  BmpRect:= bmp.Canvas.ClipRect


    Уже ошибка. См VCL.
  • GrayFace © (29.03.08 22:15) [30]
    tesseract ©   (29.03.08 15:38) [29]
    Буффер необходим. Потому как идёт пересчёт бордюра + бэка. Пересчёт буффера происходит только при изменении размеров контрола, что снижает нагрузку на перерисовку в 10-15 раз.

    Ну тогда его лучше сделать содержащим целое размножающихся картинок.

    tesseract ©   (29.03.08 15:38) [29]
    А вообще почитай ветку про DoubleBuffered или сначала пойми , почему мне нужен именно потомок TWinControl, а не TGraphicControl.

    Забавно выходит, когда ламеры говорят в стиле Юрия Шевченко.
    Не знаю, почему тебе нужен TWinControl какиб боком это относится к тому, что я писал, но раз у так, то CS_VREDRAW и CS_HREDRAW не забываешь убрать?

    tesseract ©   (29.03.08 15:38) [29]
    Уже ошибка. См VCL.

    Вряд ли. Что смотреть? (хотя BmpRect вообще не нужен, это я для CopyRect хотел написать пример)
  • tesseract © (30.03.08 17:14) [31]

    > Вряд ли. Что смотреть? (хотя BmpRect вообще не нужен, это
    > я для CopyRect хотел написать пример)


    Нет, тут ты как раз прав. Сам его использую, только он ClientRect после отрисовки border-а. в VCL и WinAPI есть функции как раз для работы с определением координат отрисовки.


    > Ну тогда его лучше сделать содержащим целое размножающихся
    > картинок.


    Буфер перериcовываеться, только если размеры контрола  поменяли. При перерисовке моргает зараза, при перемещениии окна всё ок.


    > то CS_VREDRAW


    Он не влияет на скорость, так как отсекаю в paint.
  • GrayFace © (31.03.08 00:51) [32]
    Хотел сказать: "Ну тогда его лучше сделать содержащим целое число размножающихся картинок." Чтобы его каждый раз не дергать.
    А моргает только при расширении и только та область, на которую он увеличился?

    tesseract ©   (30.03.08 17:14) [31]
    Он не влияет на скорость, так как отсекаю в paint.

    Как? В WM_PAINT уже ничего не сделать, моргание происходит из-за приходящего WM_ERASEBKGND - разве что в нем как-то Validate'ить старую область. Не представляю.
  • Slym © (31.03.08 04:28) [33]
    GrayFace ©   (29.03.08 1:57) [28]
    +1 хоть и tesseract ©   (29.03.08 15:38) [29] Уже ошибка. См VCL.

    Зачем умножать когда можно складывать?
    inc(x, BmpRect.Right);

  • Slym © (31.03.08 05:21) [34]
    procedure TileBitmap(Canvas:TCanvas;Img:TBitmap);
    var
     ImgWidth,ImgHeight,x,y:integer;
     ClipRect:TRect;
    begin
     ImgWidth:=Img.Width;
     ImgHeight:=Img.Height;
     ClipRect:=Canvas.ClipRect;
     y:=ClipRect.Top;
     while y<ClipRect.Bottom do
     begin
       x:=ClipRect.Left;
       while x<ClipRect.Right do
       begin
         Canvas.Draw(x,y,Img);
         inc(x,ImgHeight);
       end;
       inc(y,ImgHeight);
     end;
    end;

    procedure TileRectBitmap(Canvas:TCanvas;Rect:TRect;Img:TBitmap);
    var MyRgn:HRGN;
    begin
     MyRgn := CreateRectRgn(Rect.Left,Rect.Top,Rect.Right,Rect.Bottom);
     try
       SelectClipRgn(Canvas.Handle,MyRgn);
       TileBitmap(Canvas,Img);
     finally
       SelectClipRgn(Canvas.Handle,0);
       DeleteObject(MyRgn);
     end;
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     Bitmap:TBitmap;
     R:TRect;
     i,c:dword;
    begin
     Bitmap:=TBitmap.Create;
     try
       ImageList1.GetBitmap(0,Bitmap);
       R:=Rect(200,100,300,200);
       c:=GetTickCount;
       for i:=0 to 1000 do
         TileRectBitmap(Canvas,R,Bitmap);
       Caption:=IntToStr(GetTickCount-c)+'мс/1000ит';
     finally
       Bitmap.Free;
     end;
    end;

  • Slym © (31.03.08 05:44) [35]
    замена
    Canvas.Draw(x,y,Img);

    на
    BitBlt(Canvas.Handle,X,Y,ImgWidth,ImgHeight,ImgCanvas,0,0,SRCCOPY);


    дает незначительные 10% скорости
  • Slym © (31.03.08 06:26) [36]
    тесты:
    CeleronM430 1.73MHz
    Dest 1600*1200 Source 48*48  1000раз
    BitBlt: 8,046секов
  • tesseract © (31.03.08 10:05) [37]

    > Зачем умножать когда можно складывать? inc(x, BmpRect.Right);


    Ну так примерно в итоге и сделано.
Есть новые Нет новых   [134433   +22][b:0][p:0.004]