Крайне медленное обращение к массиву
{ fore[a]=gamma[max(min(hdrb[a],4095),0)]; }
Без него прога работает вхолостую, выдавая где-то 320 кадров в секунду. С циклом на AthlonXP 2000+ выдает 90, хотя IMAGESIZE составляет всего-то 921600 (640*480*3), а действия в цикле - взятие числа, клиппинг и гамма-коррекция по байтовой таблице из 4096 значений. Есть еще один HDR-буфер для осуществления размытия картинки:
И даже функция memcpy, копируя каждый кадр чуть больше 3.5 мегов, сбрасывает fps до 40 с небольшим.
И есть алгоритм размытия. Я переписал его с VBшной проги на C++. Вариант, который копирует данные из hdrb2 в hdrb, размывая по пяти соседним пикселам, выдает около 17 кадров в секунду, а вариант без двойного буфера (и без memcpy) - 22, в то время как тот же алгоритм, написанный на VB, работает, выдавая 38 кадров, то есть, почти вдвое быстрее. Даже если учесть, что алгоритм не совсем оптимизирован, это довольно странно. Да и оптимизации в свойствах проекта включены. Из-за чего такое может происходить? Почему обращение к памяти даже при прямом построчном считывании занимает десятки каменных тактов, как будто у процессора нет кэш-памяти? Я уж думал, что в Си таких проблем не возникнет...
и напрасно.
В смысле, если я буду выводить битмап не в окно, а напрямую в память видеоадаптера, у меня все полетит? Это, конечно сократило бы издержки при выводе окончательного изображения, но я ведь не про это спрашивал...
Да мало ли в чем причина может быть. Код использует MMX?
По идее не использует, хотя фиг знает, что генерит компилятор. Может, у меня настройки компиляции какие-то левые?
В дебаггере нельзя зайти внутрь функции memcpy()?
Вообще трудно так дистанционно гадать по-экстрасенсовски что там у тебя по ходу откомпилировалось...
В режиме компиляции Debug заходит внутрь, в режиме Release - нет.
Может выложить сюда исходник? Глянь, может разберешься, в чем тут дело... он для нетовской версии...
[ATTACH]1271[/ATTACH]
00403895 mov ecx,dword ptr [IMAGESIZE (41AD6Ch)]
0040389B xor eax,eax
0040389D test ecx,ecx
0040389F mov dword ptr [esp+24h],0
004038A7 jle drawframe+7Bh (4038DBh)
}
004038A9 lea esp,[esp]
*(fore+a)=192; a++;
004038B0 mov ecx,dword ptr [fore (4136E8h)]
004038B6 mov byte ptr [ecx+eax],0C0h
*(fore+a)=192; a++;
004038BA mov edx,dword ptr [fore (4136E8h)]
004038C0 inc eax
004038C1 mov byte ptr [edx+eax],0C0h
*(fore+a)=192;
004038C5 mov ecx,dword ptr [fore (4136E8h)]
004038CB inc eax
004038CC mov byte ptr [ecx+eax],0C0h
004038D0 mov ecx,dword ptr [IMAGESIZE (41AD6Ch)]
004038D6 inc eax
004038D7 cmp eax,ecx
004038D9 jl drawframe+50h (4038B0h)
}
Сам цикл - это 12 последних инструкций. Только вот больно тяжело эти инструкции даются машине. Пробовал с циклом и без него - 180 и 320 кадров в секунду соответственно, хотя повторяется цикл всего-то 307200 раз. Что самое интересное, цикл, выполняющий билинейную интерполяцию трех компонент цвета (каждый угол экрана имеет свой цвет) выполняется практически с той же скоростью, что и простое заполнение! Походу, оно так сильно тормозит, что затмевает собой все вычисления...
{
// for(a=0;a<IMAGESIZE;a++) {
mov ecx,dword ptr [IMAGESIZE]
xor eax,eax
test ecx,ecx
mov dword ptr [esp+24h],0
jle l2
lea esp,[esp]
mov edx,dword ptr [IMAGESIZE]
mov ecx,dword ptr [fore]
add eax,ecx
add edx,ecx
// *(fore+a)=192; a++;
l1:
mov byte ptr [eax],0E0h
// *(fore+a)=192; a++;
inc eax
mov byte ptr [eax],0D0h
// *(fore+a)=192;
inc eax
mov byte ptr [eax],0C0h
inc eax
cmp eax,edx
js l1
l2:
}
По три обращения на каждый пиксел. Но запись будет (должна) производиться в L1 cache, а в оперативку скидываться только когда запишется полная кэш-линия. И никаких задержек быть не должно.