OSDev

для всех
Текущее время: 18 апр 2024, 12:17

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 14 ]  На страницу 1, 2  След.
Автор Сообщение
СообщениеДобавлено: 08 янв 2016, 15:24 

Зарегистрирован: 08 янв 2016, 15:11
Сообщения: 5
Доброго времени суток!
Начитался статей про написание хоби-ОС.
Пишу вывод текста через framebuffer. Когда текст достигает нижней границы экрана, надо с ним что-то делать. Я решил перемещать изображение вверх, и на освободившемся месте рисовать строку текста.
Код:
void fb_set_pix(int x,int y,uint32_t color)
{
  unsigned where = x*(fbbpp/8) + y*fbpitch;
  framebuffer[where + 0] = color;              // BLUE
    framebuffer[where + 1] = (color >> 8);   // GREEN
    framebuffer[where + 2] = (color >> 16);  // RED
}

uint32_t fb_get_pix(int x,int y){
  unsigned where = x*(fbbpp/8) + y*fbpitch;
  uint32_t color=0;
  color = framebuffer[where + 0] + (framebuffer[where + 1] << 8) + (framebuffer[where + 1] << 16);
  return color;
}

void fb_scroll_y(int numpix, uint32_t color) {
  int i,j;
  // смещаем верх
  for(i=numpix; i<768; i++){ // height
    for(j=0; j<1024; j++){ // width
      fb_set_pix(j,i-numpix,fb_get_pix(j,i));
    }
  }
  // красим низ
  for(i=fb_screenH-numpix; i<768; i++){ // height
    for(j=0; j<1024; j++){ // width
      fb_set_pix(j,i,color);
    }
  }
}


Однако приведённый пример работает слишком медленно - экран обновляется чуть больше чем за секунду.
Как можно ускорить прокрутку, или может есть более правильная её реализация?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 08 янв 2016, 17:44 

Зарегистрирован: 26 мар 2012, 17:32
Сообщения: 209
Характерное правило: _никогда не читать из видеопамяти_, ну и писать по-возможности последовательно. Соотв. обычно всё что нужно делается в обычной памяти, а потом копируется в видеопамять, при этом лучше копировать только изменившиеся области (при прокрутке всего экрана, впрочем, это будет весь экран, но если не страдать полноэкранной консолью, то это редкий случай).

Это в общих чертах, так-то есть ещё нюансы, но до них ещё дожить надо. Один из первых нюансов - включение для видеопамяти WC (Write Combination, а не то что можно было подумать) кеширования вместо UC (UnCached), делается через MTRR и атрибуты в таблицах страниц (при их наличии).

Upd1: И да, если приведённый код компилируется без оптимизаций (впрочем, не факт что оптимизации помогут, ибо ещё важно чем и с какими флагами компилировать), то накладные расходы на вызов функции на каждый пиксель будут огромными при работе с большой областью. Не надо так делать, нужно иметь дополнительно функции которые заливают сразу прямоугольник и, как частный случай, горизонтальные и вертикальные линии, как минимум.

Upd2: к исходному вопросу это отношения не имеет, но упомянуть стоит: с таким качеством кода жить тяжело. Те же магические константы - вообще не есть хорошо, забыл поменять где-нибудь и лови потом совершенно непонятные баги (хорошо если только одни сутки). "Делать надо сразу хорошо, плохо само получится", как говорится.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 08 янв 2016, 21:15 
Аватара пользователя

Зарегистрирован: 16 май 2007, 23:46
Сообщения: 1126
Просто подумай-те как сделать наиболее оптимально.
Для реализации графической библиотеке используют следующий трюк.
Все примитивы рисуются не про помощи пикселей, а при помощи горизонтальных линий. Все методы использующие работу с линиями относятся к роду ScanLine.
Код линии делают так что-бы он не содержал лишних операций.

Код:
{Рисуем горизонтальную линию}
procedure HLinePut(const Buf:PAColor; const Len_1:Integer; const Color:TColor);
var x:Integer;
begin
for x:=0 to Len_1 do
 Buf^[x]:=Color;
end;

{Копируем линию}
procedure HLineMov(const Dest, Scr:PAColor; const Len_1:Integer);
var x:Integer;
begin
for x:=0 to Len_1 do
 Dest^[x]:=Scr^[x];
end;



AGG я уже рекламировал. Ещё раз по рекламирую.
http://vector-agg.cvs.sourceforge.net/viewvc/vector-agg/agg-2.4/include/agg_pixfmt_rgb.h?view=markup
Код:
        AGG_INLINE void copy_hline(int x, int y,
                                   unsigned len,
                                   const color_type& c)
        {
            value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + x + x + x;
            do
            {
                p[order_type::R] = c.r;
                p[order_type::G] = c.g;
                p[order_type::B] = c.b;
                p += 3;
            }
            while(--len);
        }


Последний раз редактировалось pavia 08 янв 2016, 22:13, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 08 янв 2016, 21:58 
Аватара пользователя

Зарегистрирован: 16 май 2007, 23:46
Сообщения: 1126
Примеры приведённые выше не самые производительные. В них убраны лишнии операции, но их можно сделать быстрее. В них всё ещё присутсвуют пиксели. Но стоит трактовать картинку или линию как набор бит или байт. То скорость можно будет повысить.

К примеру если для картинке RGB_24 нам приходиться выполнять 3 инструкции копирования на пиксель, то копируя за раз 4 байта (3 байта одного пикселя и 1 другого) Можно увеличить скорость более чем в 3 раза.

Интел назвала такую технологию "bit blt" (BIT BLock Transfer.) Не думаю что интел был первым, но других незнаю. В последствии майкрософт подхватила название. И сейчас операция известна как блитинг.

Работа с картинками условно можно поделить на те операции где нужно преобразовывать формат пикселя к примеру из RGB_24 в RGB_32 и в те которые ненужно.
Если отказаться от пиксельного представления, а трактовать как набор байт, то возможно использовать MMX, SSE. Благодаря большим регистрам 64 бита и 128, против 32 бит в предыдущих примерах, возможно увеличить скорость в 4-8 раз.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 09 янв 2016, 15:31 

Зарегистрирован: 08 янв 2016, 15:11
Сообщения: 5
Провёл кое-какую оптимизацию:
Создал буфер для хранения "картинки" в оперативе:
Код:
uint32_t membuf[1024][768];

При инициализации он забивается нулями (чёрным цветом)
Модифицировал функцию для вывода:
Код:
void fb_set_pix(int x,int y,uint32_t color)
{
   membuf[x][y]=color;
   unsigned where = x*(fbbpp/8) + y*fbpitch;
   framebuffer[where + 0] = color;              // BLUE
    framebuffer[where + 1] = (color >> 8);   // GREEN
    framebuffer[where + 2] = (color >> 16);  // RED
}


Ну и функция прокрутки:
Код:
void fb_scroll_y(int numpix, uint32_t color) {
   int i,j;
   int where = 0;
   int xoffset = fbbpp/8;
   // смещаем верх
   for(i=numpix; i<768; i++){
      for(j=0; j<1024; j++){
         membuf[j][i-numpix] = membuf[j][i];
            framebuffer[where] = membuf[j][i];              // BLUE
             framebuffer[where + 1] = (membuf[j][i] >> 8);   // GREEN
             framebuffer[where + 2] = (membuf[j][i] >> 16);  // RED
            where += xoffset;
      }
      where += fbpitch;
   }
   // красим низ
   for(i=fb_screenH-numpix; i<768; i++){ // height
      for(j=0; j<1024; j++){ // width
         fb_set_pix(j,i,color);
      }
   }
}

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


Вложения:
Снимок-2.png
Снимок-2.png [ 120.55 КБ | Просмотров: 12264 ]
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 09 янв 2016, 16:39 

Зарегистрирован: 26 мар 2012, 17:32
Сообщения: 209
Это же C, а не Fortran.
Поэтому если и оптимизировать, то "uint32_t membuf[height][width]", membuf[y][x] и т.д. И да, как объявлена переменная framebuffer?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 09 янв 2016, 17:08 

Зарегистрирован: 08 янв 2016, 15:11
Сообщения: 5
Код:
uint8_t *framebuffer;
...
typedef unsigned char      uint8_t;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 09 янв 2016, 19:06 

Зарегистрирован: 26 мар 2012, 17:32
Сообщения: 209
А вот это зачем: "where += fbpitch" ? И откуда берётся fbpitch?

Upd: судя по старому коду, это длина строки в видеопамяти, ок. Но тогда нужно или прибавлять (fbpitch - 1024*3), либо на каждом шаге обращаться к [where + j*3 + 0,1,2] и убрать "where += 3". Иначе два раза прибавляется длина строки, вот и происходит растяжение. В общем, немного внимательности.

Note: длина строки в видеопамяти может быть больше, чем (ширина_экрана * байт_на_пиксель) в силу всяких выравниваний. Поэтому никто не гарантирует что (fbpitch - width*3) будет нулём.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 09 янв 2016, 20:23 

Зарегистрирован: 08 янв 2016, 15:11
Сообщения: 5
Вот, теперь работает, спасибо.
Добавил -O3 при сборке - вообще летать начало.
Спасибо всем, кто откликнулся.

Upd: Правильнее будет так:
Код:
int xoffset = multiboot->framebuffer_bpp/8;
...
where += ( fbpitch - 1024*xoffset );


Upd2: почему-то на qemu оно работает быстрее, чем на реальном железе. (qemu-system-i386 + linux mint x64 и просто загрузка с флешки на одном и том же железе. В обоих случаях всё работает быстро, обновления экрана не заметны, но в первом случае успевает выводиться больше строк за единицу времени чем во втором)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: 09 янв 2016, 22:01 
Аватара пользователя

Зарегистрирован: 16 май 2007, 23:46
Сообщения: 1126
thunderstruck писал(а):
Upd2: почему-то на qemu оно работает быстрее, чем на реальном железе. (qemu-system-i386 + linux mint x64 и просто загрузка с флешки на одном и том же железе. В обоих случаях всё работает быстро, обновления экрана не заметны, но в первом случае успевает выводиться больше строк за единицу времени чем во втором)

Разработчики БИОС лениться и оставляют на откуп разработчикам ОС.
Надо настроить систему кэша в соответствии с
http://download.intel.com/design/pentiu ... 442201.pdf
Уже обсуждалось надо включить для видепамяти режим кэша Write Combining (WC)
viewtopic.php?f=5&t=1014&hilit=MTRRs&start=10


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 14 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
cron
Создано на основе phpBB® Forum Software © phpBB Group
Русская поддержка phpBB