Page 4 of 7
Re: Векторные функции
Posted: Sun Oct 04, 2009 6:44 pm
by andrew_programmer
ты имееш ввиду libGUI ? В каком файле код ?
Да. Код в файле draw_controls.inc Только код полностью на C. Если написать на ассемблере, то быстрее будет работать. Реализовать функцию рисующую и на экране и в буфере можно по разному. У меня реализовано так:
Code: Select all
void DrawPixel(int x,int y,DWORD color)
{
char r,g,b;
char *ptr;
DWORD *ptr2;
if (x>screen.size_x-1) {x=screen.size_x-1;}
if (y>screen.size_y-1) {y=screen.size_y-1;}
if (x<0) {x=0;}
if (y<0) {y=0;}
switch(screen.draw_output)
{
case DRAW_OUTPUT_SCREEN:
{
x+=screen.x;
y+=screen.y;
gui_ksys_put_pixel_window(x,y,color);
break;
}
case DRAW_OUTPUT_BUFFER:
{
ptr=screen.buffer;
switch(screen.bits_per_pixel)
{
case 24:
{
ptr=ptr+(y*screen.size_x+x)*3;
b=color & 0xff;
color=color >>8;
g=color & 0xff;
color=color >>8;
r=color & 0xff;
ptr[0]=b;
ptr[1]=g;
ptr[2]=r;
break;
}
case 32:
{
ptr2=(DWORD*)ptr+y*screen.size_x+x;
*ptr2=color;
break;
}
default: break;
}
break;
}
}
}
Функций, непосредственно работающих с экраном/буффером 4: DrawPixel(),DrawHorizontalLine(),DrawVerticalLine(),DrawImage(). Все остальные функции рисования используют эти 4. В результате можно рисовать как на экране, так и в буффере.
Re: Векторные функции
Posted: Mon Oct 05, 2009 6:46 am
by Albom
andrew_programmer
Я бы в начале функции проверку на выход за границы изменил бы на такую:
Code: Select all
if ( (x>screen.size_x-1) || (y>screen.size_y-1) || (x<0) || (y<0) )
return;
Re: Векторные функции
Posted: Mon Oct 05, 2009 2:51 pm
by andrew_programmer
Да, для отдельных пикселей лучше так.
Эта проверка границ у меня взята из вывода геометрических примитивов. Там просто так отсекать вывод по границам нельзя. Видимо забыл поменять код. Когда дело дойдёт до полной оптимизации функций рисования, то я всеми этими вещами займусь.
Re: Векторные функции
Posted: Mon Oct 05, 2009 11:06 pm
by IgorA
что-бы не мигало и быстрее выводило при прорисовке добавил возможность вывода через буфер. Появилось 5 функций для работы с буфером (создание, удаление, очистка, вывод на экран, установка активного буфера). Пока поддерживается только 1 буфер, но в будущем можно будет расширить их число.
Старый вариант работы, с выводом на экран тоже возможен. В архиве 2 программы используют буфер, остальные рисуют напрямую в экран.
Шрифт вроде стал работать быстрее.
Re: Векторные функции
Posted: Mon Oct 05, 2009 11:39 pm
by IgorA
переделал еще 1 пример под буфер, точно быстрее выводит
Re: Векторные функции
Posted: Tue Oct 06, 2009 12:02 am
by Gluk
вообще супер! =)
Re: Векторные функции
Posted: Tue Oct 06, 2009 1:07 am
by andrew_programmer
В коде попиксельного рисования в буфере желательно заменить вот это:
Code: Select all
drawpixel_buf:
bt bx,15
jc @f
bt cx,15
jc @f
cmp bx,word[active_buffer_w]
jge @f
cmp cx,word[active_buffer_h]
jge @f
push edi esi
mov edi,dword[active_buffer] ;ptr - pointer to buffer
mov esi,ebx ;esi=coord x
imul esi,3 ;x*3
add edi,esi ;ptr+x*3
xor esi,esi
mov si,word[active_buffer_w] ;size x
imul esi,ecx ;size_x*y
imul esi,3 ;size_x*y*3
add edi,esi ;ptr+x*3+size_x*y*3
mov word[edi],dx ;
ror edx,16
mov byte[edi+2],dl
ror edx,16
pop esi edi
@@:
ret
хотя бы на это
Code: Select all
drawpixel_buf:
bt bx,15
jc @f
bt cx,15
jc @f
cmp bx,word[active_buffer_w]
jge @f
cmp cx,word[active_buffer_h]
jge @f
push esi
xor esi,esi
mov si,word[active_buffer_w] ;size x
imul esi,ecx ;size_x*y
add esi,ebx ;size_x*y+x
lea esi,[esi+esi*2] ;(size_x*y+x)*3
add esi,dword[active_buffer] ;ptr+(size_x*y+x)*3
mov word[esi],dx ;
ror edx,16
mov byte[esi+2],dl
ror edx,16
pop esi
@@:
ret
Небольшие рекомендации.
В коде попиксельного рисования отдельного вида кривой желательно сделать как можно меньше обращений к системной памяти. То есть желательно отказаться от push/pop для функции попиксельного рисования. Перед вызовом drawpixel_buf необходимые параметры поместить в регистры(указатель на буфер, его ширина и высота). Если последовательно рисуется множество точек одной кривой, то заранее размещённые в регистрах параметры дадут очень существенное ускорение работы. Скорость работы регистровой памяти значительно выше, чем системной.
Re: Векторные функции
Posted: Tue Oct 06, 2009 10:08 am
by Mario
Добавлю пять копеек:
1) Если условно разбить буфер на знакоместа определенного размера (например, 50х50 пикселов) и дополнительно использовав область для хранения признака обновления знакоместа, можно немного ускорить вывод обновляя только те знакоместа, в которые производился вывод. Конечно при вызове перерисовки окна нужно перерисовывать весь буфер, но потом достаточно только перерисовывать изменения. Особенно заметна будет разница в скорости на полноэкранных приложениях, при обновлении небольших участков.
2) Имеет смысл сделать буфер чуть большим отображаемого куска на экране, иначе у жучары части пропадают в некоторых ракурсах.
Re: Векторные функции
Posted: Tue Oct 06, 2009 1:21 pm
by IgorA
andrew_programmer согласен что не оптимально, перекомпилировал, работает. Только не пойму как вместо умножения на 3 написано:
Code: Select all
lea esi,[esi+esi*2] ;(size_x*y+x)*3
почему не так:
или так:
Re: Векторные функции
Posted: Tue Oct 06, 2009 1:57 pm
by Mario
IgorA wrote:
почему не так:
или так:
1. Потому что IMUL теоретически медленней.
2. Потому что Зубков.
Code: Select all
Команда LEA
LEA можно использовать (кроме прямого назначения — вычисления адреса сложно адресуемой переменной) для следующих двух ситуаций:
быстрое умножение
lea еах,[еах*2] ; ЕАХ = ЕАХ * 2 (shl eax,1 лучше)
lea еах,[еах+еах*2] ; ЕАХ = ЕАХ * 3
lea еах,[еах*4] ; ЕАХ = ЕАХ * 4 (shl eax,2 лучше)
lea еах,[еах+еах*4] ; ЕАХ = ЕАХ * 5
lea еах,[еах+еах*8] ; ЕАХ = ЕАХ * 9
трехоперандное сложение
lea ecx,[eax+ebx] ; ЕСХ = ЕАХ * ЕВХ
Единственный недостаток LEA — увеличивается вероятность AGI с предыдущей командой (см. ниже).
Re: Векторные функции
Posted: Tue Oct 06, 2009 2:18 pm
by andrew_programmer
почему не так:
imul esi,3
Потому что так на умножение уйдёт минимум 10 тактов. А при помощи команды
lea esi,[esi+2*esi] всего 2-3 такта.
почему не так:
imul esi,3
или так:
lea esi,[esi*3] ;(size_x*y+x)*3
С учётом того, что команда lea может выполняться одновременно с другой командой в любом конвеере, получается, что по скорости кода lea esi,[esi*3] =imul esi,3
Для процессора умножение на 2 в степени n - это просто сдвиг на n бит влево. Операция сложения, также как и команда lea тоже может выполняться в любом конвеере. В общем вычисление адреса вместе с занесением его в ESI занимает минимум 2-3 такта, против минимум 10 в случае с imul.
Re: Векторные функции
Posted: Wed Oct 07, 2009 2:41 pm
by IgorA
Сделал 3 изменения:
1) исправил функцию рисования точки в буфере, как сказал andrew_programmer
2) доработал алгоритм отсечения кривых, когда они попадают на верхнюю и на левую границу окна
3) можно использовать несколько отдельных буферов (номера принимают функции на входе, максимум 8 буферов, хотя при необходимости можно добавить)
Дописал справку, под новые функции.
Re: Векторные функции
Posted: Wed Oct 07, 2009 3:49 pm
by Albom
в документации опечаточка. нужно исправить "длинна" на "длина"
Re: Векторные функции
Posted: Wed Oct 07, 2009 7:35 pm
by Ghost
IgorA
Делай больше коментариев в коде, и перед каждой функцией желатьельно, полез посмотреть - все равно что в IDA посмотрел, найдется мало желающих помогать в разработке.
Re: Векторные функции
Posted: Wed Oct 07, 2009 7:52 pm
by IgorA
Albom
Исправлю
Ghost
Я более подробно пробовал писать в документации. Но могу и в коде больше коментов написать. Если писать комментарии в коде, то в какой кодировке лучше OEM или ANSI?
Ghost wrote:больше коментариев в коде, и перед каждой функцией желатьельно
Имеешь в виду саму библиотеку или ее использование. Или и то и другое?