Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Формат bitmap [D7, WinXP]


Страницы:   1 2

Woolen ©   (2005-12-21 17:43:00) 

Помогите разобраться в формате, пожалуйста. Не могу понять, что лежит между строк и какого оно размера.
GetPixel - это слишком медленно (знают все), но и обрабатывать в через ScanLine тоже, мягко говоря, не быстро.
Написал по другому:
procedure BitmapDarkness6(Bmp: TBitmap);
var
 PixelCicle: Cardinal;
 FirstClr,SecClr,ThirdClr: PByte;
 LinePtr: PByteArray;
 WinBmp: Windows.TBitmap;
begin
if GetObject(Bmp.Handle,SizeOf(WinBmp),@WinBmp) > 0 then
 begin
 LinePtr := WinBmp.bmBits;
 for PixelCicle := 0 to WinBmp.bmWidth * WinBmp.bmHeight - 1
   do
   begin
   FirstClr := Pointer(Cardinal(LinePtr) + PixelCicle * 3);
   SecClr := Pointer(Cardinal(FirstClr) + 1);
   ThirdClr := Pointer(Cardinal(FirstClr) + 2);
   FirstClr^ := FirstClr^ div 2;
   SecClr^ := SecClr^ div 2;
   ThirdClr^ := ThirdClr^ div 2;
   end;
 end;
end;

Время работы такой процедуры составила менее 39% от варианта со ScanLine, но некоторое количество пикселей не закрашивается. Цикл завершается раньше. То есть, строки, как я понял, лежат не вплотную. Видимо я корежу какую-то служебную информацию между ними, в то время как через ее надо "перешагивать". Поправьте, если я не прав, и помогите разобраться с форматом, пожалуйста. Что там лежит и для чего оно нужно? Спасибо
P.S. Битмап - 24 бита, RGB.


MBo   (2005-12-29 15:23:00) [1]

>_Lucky_   (29.12.05 14:21) [28]

Да


_Lucky_   (2005-12-29 14:21:00) [2]

А что действительно это так: "по стандарту Паскаля значение переменной цикла после выхода не определено"?


_Lucky_   (2005-12-29 13:37:00) [3]


> Woolen ©   (28.12.05 15:23) [23]


Ну дак в сях все циклы с условием, т.е. там вычисляется некоторое выражение, и соответственно делает вывод true/false и т.д.

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


> А цикл сначала начинать? Или что с ним делать? А еще, видимо,
>  неправильно, что адресация с 0, и что битов в байте 8,
> а не 10. :-)

м.б. и смешно, но циклы типа
while (bEnd) do
begin
bEnd := ....
end;

вопросов начинать ли сначала или пересчитывать не вызывают?
Что еще не правильно решать Вам.


Sapersky   (2005-12-28 16:21:00) [4]

Если есть вызов метода - вызывает на каждой итерации

Это автор в статье утверждал.
Но до меня уже дошло, что он действительно не прав :(
Забыл, что в ассемблерном листинге for пишется два раза (проверка в начале и jump в конце), посмотрел на первый - ага, call в "теле цикла" есть, ну и решил, что зря на человека наезжаете.


MBo   (2005-12-28 15:56:00) [5]

>Если есть вызов метода - вызывает на каждой итерации

???

Поясни


Sapersky   (2005-12-28 15:49:00) [6]

очень жаль, что допущена такая ошибка.

Никакой ошибки нет.
Если есть вызов метода - вызывает на каждой итерации. Если нет - считает один раз. В [12] bmWidth и bmHeight - это поля записи, а не свойства объекта...


Woolen   (2005-12-28 15:23:00) [7]


> я пишу на сях

А в них циклы пересчитываются на лету?

> ассемблер ваше не причем

При понимании того, что выдает компилятор и при написании вставок на ассемблере. Короче, при производительности. Не при чем, это если ты под виртуальную машину пишешь. Почти во всех остальных случаях, очень даже причем.

> раз переменные, то должны пересчитываться

А цикл сначала начинать? Или что с ним делать? А еще, видимо, неправильно, что адресация с 0, и что битов в байте 8, а не 10. :-)


_Lucky_   (2005-12-28 13:53:00) [8]


> Anton_K ©   (27.12.05 18:43) [19]


Да действительно - это не то что я ожидал.


> MBo ©   (27.12.05 20:44) [20]


> Woolen ©   (27.12.05 23:34) [21]


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

http://www.delphimaster.ru/articles/optimization.html- очень жаль, что допущена такая ошибка.


Woolen   (2005-12-27 23:34:00) [9]


> Лично я думаю, что как раз таки на оборот, значения пересчитываются
> каждый раз, да это и логично, там же ведь переменные стоят,
>  т.е. в теле цикла любая из них молга изменится, а если
> цикл был инициализирова - как вы утверждаете, то изменения
> не учтутся

Да, представляешь, они действительно не учтутся! Даже, если ты сделаешь цикл до переменной, а не до выражения и будешь ее в цикле менять, не учтутся!!! Даже если сделать так:
for Cicle := 0 to A do
 Inc(A);

А еще я тебя удивлю: в Delphi даже циклы to компилируются с прокруткой в обратную сторону - по типу downto. То есть в вышеуказанном случае будет крутиться от A до 0. А если написать так:
for Cicle := 0 to A do
 B := Cicle;

то опять же будет крутиться обратно, но для переменной Cicle тебе компилятор специально будет крутить одно число (отдельно) вперед, на увеличение, чтоб ты мог использовать значение своей переменной.
Короче, будешь читать буквари - узнаешь много нового.
Рекомендую для начала: Зубков - Ассемблер для DOS,Windows и UNIX; Delphi Help; ассемблерный отладчик.

> смотри оптимизацию циклов

Смотри, что компилирует Delphi


MBo   (2005-12-27 20:44:00) [10]

>_Lucky_   (27.12.05 18:30) [18]

>Лично я думаю, что как раз таки на оборот, значения пересчитываются каждый раз, да это и логично

Читай описание языка

>смотри оптимизацию циклов
> http://www.delphimaster.ru/articles/optimization.html

А этого "добра" лучше не читать ;)


Anton_K   (2005-12-27 18:43:00) [11]


> _Lucky_


Сколько раз выполнится тело цикла?

var i,n:Integer;
...
n:=2;
for i:=1 to n do n:=n+10;
...


_Lucky_   (2005-12-27 18:30:00) [12]


> Какой именно каждый? В коде, приведенном в 12 и 13 постах,
>  он вычисляется 1 раз. При инициализации цикла.


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

смотри оптимизацию циклов
http://www.delphimaster.ru/articles/optimization.html


Woolen   (2005-12-27 14:45:00) [13]


> а зачем ваще такие вещи каждый раз вычислять?

Какой именно каждый? В коде, приведенном в 12 и 13 постах, он вычисляется 1 раз. При инициализации цикла.


Woolen   (2005-12-27 14:45:00) [14]


> а зачем ваще такие вещи каждый раз вычислять?

Какой именно каждый? В коде, приведенном в 12 и 13 постах, он вычисляется 1 раз. При инициализации цикла.


_Lucky_   (2005-12-27 13:49:00) [15]

WinBmp.bmWidth * WinBmp.bmHeight * 3 div 8 - 1
а зачем ваще такие вещи каждый раз вычислять?


Woolen   (2005-12-27 12:28:00) [16]


> если использовать оптимизацию под две трубы и еще раскрыть
> цикл на 2 итерации (итого в каждой итерации чтение и запись
> 4 регистров MMX), ускорение будет сильнее, +50% должно быть
> точно

При развертке цикла в 2 раза (с использованием разных регистров) прибавки в скорости, почему-то, не видно. Может что-то не так делаю?
procedure BitmapDarkness11(Bmp: TBitmap);
var
 PixelCicle: Cardinal;
 WinBmp: Windows.TBitmap;
 Mask: Int64;
 PMask: PInt64;
begin
if GetObject(Bmp.Handle,SizeOf(WinBmp),@WinBmp) > 0 then
 begin
 Mask := $FEFEFEFEFEFEFEFE;
 PMask := @Mask;
 PixelCicle := WinBmp.bmWidth * WinBmp.bmHeight * 3 div 16;
   asm
     mov eax,PMask
     movq mm1,[eax]
     movq mm3,mm1
     mov eax,WinBmp.bmBits
     lea edx,[eax+8]
     mov ecx,PixelCicle
   @@LoopBegin:
     movq mm0,[eax]
     pand mm0,mm1
     psrlq mm0,1
     movq [eax],mm0
     movq mm2,[edx]
     pand mm2,mm3
     psrlq mm2,1
     movq [edx],mm2
     add eax,$10
     add edx,$10
     loop @@LoopBegin
     emms
   end;
 end;
end;


Woolen   (2005-12-23 17:17:00) [17]

procedure BitmapDarkness9(Bmp: TBitmap);
var
 PixelCicle: Cardinal;
 FirstDWORD: PInt64;
 WinBmp: Windows.TBitmap;
begin
if GetObject(Bmp.Handle,SizeOf(WinBmp),@WinBmp) > 0 then
 begin
 FirstDWORD := WinBmp.bmBits;
 for PixelCicle := 0 to WinBmp.bmWidth * WinBmp.bmHeight * 3 div 8 - 1 do
   begin
   FirstDWORD^ := (FirstDWORD^ and $FEFEFEFEFEFEFEFE) shr 1;
   Inc(FirstDWORD);
   end;
 end;
end;

И так тоже не быстрее. Хотя тут это можно объяснить зависимостью.
shrd eax,edx,1 - зависимость явная. Из-за этой команды проц точно ничего не разбросает по разным пайпам.


Woolen   (2005-12-23 17:06:00) [18]


> если использовать оптимизацию под две трубы и еще раскрыть
> цикл на 2 итерации (итого в каждой итерации чтение и запись
> 4 регистров MMX), ускорение будет сильнее, +50% должно быть
> точно

Попробовал без MMX. Видимо, я чего-то недопонимаю. Вот вариант (растр должен иметь ширину, кратную 4):
if GetObject(Bmp.Handle,SizeOf(WinBmp),@WinBmp) > 0 then
 begin
 FirstDWORD := WinBmp.bmBits;
 SecDWORD := Pointer(Cardinal(FirstDWORD) + 4);
 for PixelCicle := 0 to WinBmp.bmWidth * WinBmp.bmHeight * 3 div 8 - 1 do
   begin
   FirstDWORD^ := (FirstDWORD^ and $FEFEFEFE) div 2;
   Inc(FirstDWORD,2);
   SecDWORD^ := (SecDWORD^ and $FEFEFEFE) div 2;
   Inc(SecDWORD,2);
   end;
 end;

По сравнению с обработкой в один DWORD за цикл прироста практически нет. Даже небольшое замедление. Хотя рагистры использует разные и зависимости между командами я не нашел. То есть, теоретически FirstDWORD и SecDWORD должны обрабатываться разными конвейрами. Но этого, судя по скорости, не происходит.


MBo   (2005-12-23 10:08:00) [19]

>miek ©   (23.12.05 09:51) [10]
Пример есть? Я не сталкивался с оптимизацией под пайпы, а интересно было бы посмотреть, например, простенькую обработку массива Int64.

З.Ы. Приведенный в [9] код обрабатывает массив 400К за 0.7 мс на AthlonXP1900, память PC2700(333 мгц), т.е. 560 мег в секунду. Поэтому я и склонен считать, что узкое место - доступ к памяти, а не арифметика. Может, конечно, префетчинг поможет.


miek   (2005-12-23 09:51:00) [20]

если использовать оптимизацию под две трубы и еще раскрыть цикл на 2 итерации (итого в каждой итерации чтение и запись 4 регистров MMX), ускорение будет сильнее, +50% должно быть точно


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо