BitBlt работает медленно при захвате с одним качеством и...
От: Doctor M  
Дата: 31.10.03 08:49
Оценка:
День добрый всем.

Необоходимо захватить содержимое экрана и преобразовать его в 24-битовый bmp. BitBlt работает медленно если color quality не соответствует 24 битам. Что можно предпринять?

Заранее благодарен за ответ (кидайте и почтой).

Док.
Re: BitBlt работает медленно при захвате с одним качеством и
От: AndreyFedotov Россия  
Дата: 31.10.03 09:48
Оценка:
Здравствуйте, Doctor M, Вы писали:

DM>День добрый всем.


DM>Необоходимо захватить содержимое экрана и преобразовать его в 24-битовый bmp. BitBlt работает медленно если color quality не соответствует 24 битам. Что можно предпринять?


DM>Заранее благодарен за ответ (кидайте и почтой).


DM>Док.


Насколько мне известно BitBlt работает довольно быстро. Если цветовые форматы источника и приёмника совпадают то работает она на лету. Если цветовой формат источника и приёмника различаются, то работа идёт медленее, но всё равно достаточно быстро. Единственная проблема возникает при приобразовании Truecolor => Indexed, что связано с подбором оптимального индекса цвета. Однако проблему, коли уж она возникла, можно решить, захватив картинку в Compatible контекст, а затем преобразовав её оттуда в 24 бита.
Кстати по-моему подобные преобразования в GDI+ работают заметно быстрее.
С Уважением, Андрей
Re[2]: BitBlt работает медленно при захвате с одним качество
От: Doctor M  
Дата: 31.10.03 10:08
Оценка:
Здравствуйте, AndreyFedotov, Вы писали:

AF>Здравствуйте, Doctor M, Вы писали:


DM>>День добрый всем.


DM>>Необоходимо захватить содержимое экрана и преобразовать его в 24-битовый bmp. BitBlt работает медленно если color quality не соответствует 24 битам. Что можно предпринять?


DM>>Заранее благодарен за ответ (кидайте и почтой).


DM>>Док.


AF>Насколько мне известно BitBlt работает довольно быстро. Если цветовые форматы источника и приёмника совпадают то работает она на лету. Если цветовой формат источника и приёмника различаются, то работа идёт медленее, но всё равно достаточно быстро. Единственная проблема возникает при приобразовании Truecolor => Indexed, что связано с подбором оптимального индекса цвета. Однако проблему, коли уж она возникла, можно решить, захватив картинку в Compatible контекст, а затем преобразовав её оттуда в 24 бита.

AF> Кстати по-моему подобные преобразования в GDI+ работают заметно быстрее.
AF> С Уважением, Андрей


У меня это выглядит так (и занимает 1.5 секунды если экран 32-битный):
// Что стоит изменить?

void FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp )
{
assert( bmi && width > 0 && height > 0 &&
(bpp == 8 || bpp == 24 || bpp == 32) );

BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);

memset( bmih, 0, sizeof(*bmih));
bmih->biSize = sizeof(BITMAPINFOHEADER);
bmih->biWidth = width;
bmih->biHeight = -abs(height);
bmih->biPlanes = 1;
bmih->biBitCount = bpp;
bmih->biCompression = BI_RGB;

if( bpp == 8 )
{
RGBQUAD* palette = bmi->bmiColors;
int i;
for( i = 0; i < 256; i++ )
{
palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
palette[i].rgbReserved = 0;
}
}
}

HDC CreateBMP( int w, int h, int bpp, HGDIOBJ& old )
{
char buffer[sizeof(BITMAPINFOHEADER) + 1024];
BITMAPINFO* bmi = (BITMAPINFO*)buffer;
void* data = 0;

assert( bpp == 8 || bpp == 24 || bpp == 32 );
HDC memDC = CreateCompatibleDC(0);
FillBitmapInfo( bmi, w, h, bpp );

HBITMAP hbmp = CreateDIBSection( memDC, bmi, DIB_RGB_COLORS, &data, 0, 0 );

if( !hbmp )
{
DeleteDC( memDC );
memDC = 0;
}
else
old = SelectObject( memDC, hbmp );

return memDC;
}

int main
{
// Create device context for the display driver
HDC hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL);
if (!hdcScreen) return 1;

// creates a memory device context compatible with the hdcScreen
HGDIOBJ old;
int w = GetDeviceCaps(hdcScreen, HORZRES), h = GetDeviceCaps(hdcScreen, VERTRES);
HDC hdcDest = CreateBMP( w, h, 24, old);
BITMAP bmp;

if (!hdcDest)
{
DeleteDC(hdcScreen);
return 1;
}

BitBlt(hdcDest, 0, 0, w, h, hdcScreen, 0,0, SRCCOPY);
GetObject( GetCurrentObject( hdcDest, OBJ_BITMAP ), sizeof(bmp), &bmp );

// process bmp with 24 bits for own goals....

DeleteObject( SelectObject( hdcDest, old ) );
DeleteDC(hdcDest);
DeleteDC(hdcScreen);
return 0;
}
Re[3]: BitBlt работает медленно при захвате с одним качество
От: AndreyFedotov Россия  
Дата: 31.10.03 10:24
Оценка:
Здравствуйте, Doctor M, Вы писали:

У тебя происходит прямое преобразование изображения при чтении его из контекста экрана в контекст в памяти. Вот тут-то скорее всего и проблема. Дело в том, что если карточка такой режим не поддерживает (а поддерживают его не многие карточки), то обработка идёт програмно, а если ещё и карточка стоит на медленной шине, то тут совсем медленно всё работает.
Я бы попробовал двойную буферизацию. Сначала захватывать изображение в совместимый с дисплеем контекст в памяти (это должно работать очень быстро), а затем преобразовать картинку в другой контекст в памяти. Тут все должно работать гораздо быстрее. Хотя памяти требуется больше.
С Уважением, Андрей
Re[4]: BitBlt работает медленно при захвате с одним качество
От: Doctor M  
Дата: 31.10.03 10:35
Оценка:
Здравствуйте, AndreyFedotov, Вы писали:

AF>Здравствуйте, Doctor M, Вы писали:


AF>У тебя происходит прямое преобразование изображения при чтении его из контекста экрана в контекст в памяти. Вот тут-то скорее всего и проблема. Дело в том, что если карточка такой режим не поддерживает (а поддерживают его не многие карточки), то обработка идёт програмно, а если ещё и карточка стоит на медленной шине, то тут совсем медленно всё работает.

AF> Я бы попробовал двойную буферизацию. Сначала захватывать изображение в совместимый с дисплеем контекст в памяти (это должно работать очень быстро), а затем преобразовать картинку в другой контекст в памяти. Тут все должно работать гораздо быстрее. Хотя памяти требуется больше.
AF> С Уважением, Андрей

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

Идея ясна, но как это кодом воплотить? Просто я в таких задачах не спец, а желание делать "правильно" убить в себе не могу. Код который я прислал, насколько мне кажется, довольно "правилен" (не идеал конечно .

Мне достаточно псевдокода с необходимыми методами, а то буду черзе "нечто" делать — потом самому противно станет... Как говорят, необходим "развернутый дирекшен", а воплотить и вес прочекать — мы уж тут навалимся...

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

Заранее спасибо за ответ,
Денис
Re[5]: BitBlt работает медленно при захвате с одним качество
От: AndreyFedotov Россия  
Дата: 31.10.03 12:18
Оценка:
Здравствуйте, Doctor M, Вы писали:

DM>Насчет карточки и шины — это я уже с товарищами уже обсуждал — вполне вероятно. Но это кул, что если трабла в этом. Не рулес, если это летает лишь при указанных условиях — кому такое надо...

Увы... Мы часто забываем — что всего лишь обслуга при бурбуляторе с несколькими регистрами и массивами памяти...
Частенько архитектура и возможности кода определяются именно железом, хотя и в скрытой форме...

DM>Идея ясна, но как это кодом воплотить? Просто я в таких задачах не спец, а желание делать "правильно" убить в себе не могу. Код который я прислал, насколько мне кажется, довольно "правилен" (не идеал конечно .


Код мне понравился. Насколько хорош — путь гуру разбираются. Идея проста (тем паче, что в коде у тебя всё есть).

DM>Мне достаточно псевдокода с необходимыми методами, а то буду черзе "нечто" делать — потом самому противно станет... Как говорят, необходим "развернутый дирекшен", а воплотить и вес прочекать — мы уж тут навалимся...


Для портирования в совместимый контекст в совместимом режиме, вместо CreateDIBSection используешь CreateCompatibleBitmap — что бы получить изображение в формате контекста отображения.
После чего создаёшь второй контекст в памяти (как это у тебя уже сделано, только лучше вместо 0 указать первый контекст) и твоим же кодом перекидываешь в него изображение из первого контекста в памяти.

Получается:
DisplayDC => Compatible (DDB) Bitmap (in MemDC1) — быстро
Compatible (DDB) Bitmap (in MemDC1) => DIB Bitmap (in MemDC2) — быстро

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

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

DM>Заранее спасибо за ответ,

DM>Денис

С Уважением, Андрей
Re[6]: BitBlt работает медленно при захвате с одним качество
От: Doctor M  
Дата: 31.10.03 14:24
Оценка:
Здравствуйте, AndreyFedotov, Вы писали:

AF>Здравствуйте, Doctor M, Вы писали:


DM>>Насчет карточки и шины — это я уже с товарищами уже обсуждал — вполне вероятно. Но это кул, что если трабла в этом. Не рулес, если это летает лишь при указанных условиях — кому такое надо...

AF>Увы... Мы часто забываем — что всего лишь обслуга при бурбуляторе с несколькими регистрами и массивами памяти...
AF>Частенько архитектура и возможности кода определяются именно железом, хотя и в скрытой форме...

DM>>Идея ясна, но как это кодом воплотить? Просто я в таких задачах не спец, а желание делать "правильно" убить в себе не могу. Код который я прислал, насколько мне кажется, довольно "правилен" (не идеал конечно .


AF>Код мне понравился. Насколько хорош — путь гуру разбираются. Идея проста (тем паче, что в коде у тебя всё есть).


DM>>Мне достаточно псевдокода с необходимыми методами, а то буду черзе "нечто" делать — потом самому противно станет... Как говорят, необходим "развернутый дирекшен", а воплотить и вес прочекать — мы уж тут навалимся...


AF> Для портирования в совместимый контекст в совместимом режиме, вместо CreateDIBSection используешь CreateCompatibleBitmap — что бы получить изображение в формате контекста отображения.

AF> После чего создаёшь второй контекст в памяти (как это у тебя уже сделано, только лучше вместо 0 указать первый контекст) и твоим же кодом перекидываешь в него изображение из первого контекста в памяти.

AF>Получается:

AF> DisplayDC => Compatible (DDB) Bitmap (in MemDC1) — быстро
AF> Compatible (DDB) Bitmap (in MemDC1) => DIB Bitmap (in MemDC2) — быстро

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

AF> Вот тут подозреваю, что может быть как раз наоборот. По идее так должно было бы быть, но в реальности под Linux по-моему всё будет проще. Впрочем это вопрос к Linuxoidam...

DM>>Заранее спасибо за ответ,

DM>>Денис

AF>С Уважением, Андрей


Привет снова,

На Linux все реализовали — там все кул и все летает...

На винде еще не пробовал, но о результате сообщу. Если уж будут траблы, то также поделюсь.... %-)

Удачи,
Денис
Re[6]: BitBlt работает медленно при захвате с одним качество
От: Doctor M  
Дата: 03.11.03 10:45
Оценка:
Здравствуйте, AndreyFedotov, Вы писали:

AF>Здравствуйте, Doctor M, Вы писали:


DM>>Насчет карточки и шины — это я уже с товарищами уже обсуждал — вполне вероятно. Но это кул, что если трабла в этом. Не рулес, если это летает лишь при указанных условиях — кому такое надо...

AF>Увы... Мы часто забываем — что всего лишь обслуга при бурбуляторе с несколькими регистрами и массивами памяти...
AF>Частенько архитектура и возможности кода определяются именно железом, хотя и в скрытой форме...

DM>>Идея ясна, но как это кодом воплотить? Просто я в таких задачах не спец, а желание делать "правильно" убить в себе не могу. Код который я прислал, насколько мне кажется, довольно "правилен" (не идеал конечно .


AF>Код мне понравился. Насколько хорош — путь гуру разбираются. Идея проста (тем паче, что в коде у тебя всё есть).


DM>>Мне достаточно псевдокода с необходимыми методами, а то буду черзе "нечто" делать — потом самому противно станет... Как говорят, необходим "развернутый дирекшен", а воплотить и вес прочекать — мы уж тут навалимся...


AF> Для портирования в совместимый контекст в совместимом режиме, вместо CreateDIBSection используешь CreateCompatibleBitmap — что бы получить изображение в формате контекста отображения.

AF> После чего создаёшь второй контекст в памяти (как это у тебя уже сделано, только лучше вместо 0 указать первый контекст) и твоим же кодом перекидываешь в него изображение из первого контекста в памяти.

AF>Получается:

AF> DisplayDC => Compatible (DDB) Bitmap (in MemDC1) — быстро
AF> Compatible (DDB) Bitmap (in MemDC1) => DIB Bitmap (in MemDC2) — быстро

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

AF> Вот тут подозреваю, что может быть как раз наоборот. По идее так должно было бы быть, но в реальности под Linux по-моему всё будет проще. Впрочем это вопрос к Linuxoidam...

DM>>Заранее спасибо за ответ,

DM>>Денис

AF>С Уважением, Андрей



Привет, Андрей,

Что — то я намудрил на виндах — методы усе возвращают, но результата нет... Глянь, пожалуйста, верно ли я реализовал то, о чем ты писал.

С уважением, Денис


void  FillBitmapInfo( BITMAPINFO* bmi, int width, int height, int bpp )
{
  assert(bmi && width > 0 && height > 0 &&
           (bpp == 8 || bpp == 24 || bpp == 32));

  BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);

  memset(bmih, 0, sizeof(*bmih));
  bmih->biSize   = sizeof(BITMAPINFOHEADER); 
  bmih->biWidth  = width;
  bmih->biHeight = -abs(height);
  bmih->biPlanes = 1; 
  bmih->biBitCount = bpp;
  bmih->biCompression = BI_RGB;

  if(bpp == 8)
  {
    RGBQUAD* palette = bmi->bmiColors;
    int i;
    for( i = 0; i < 256; i++ )
    {
      palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
      palette[i].rgbReserved = 0;
    }
  }
}

HDC CreateBMP(int w, int h, int bpp, HGDIOBJ& old)
{
  assert(bpp == 8 || bpp == 24 || bpp == 32);

  HDC memDC = CreateCompatibleDC(0);
  HBITMAP hbmp = CreateCompatibleBitmap (memDC, w, h);

  if(!hbmp)
  {
    DeleteDC(memDC);
    return 0;
  }
  else
    old = SelectObject(memDC, hbmp);
    
  HDC memDC2 = CreateCompatibleDC(memDC);
  char buffer[sizeof(BITMAPINFOHEADER) + 1024];
  BITMAPINFO* bmi = (BITMAPINFO*)buffer;
  FillBitmapInfo(bmi, w, h, bpp);
  void* data = 0;

  HBITMAP hbmp2 = CreateDIBSection(memDC2, bmi, DIB_RGB_COLORS, &data, 0, 0);
  DeleteObject(SelectObject(memDC, old));

  if(!hbmp2)
  {
    DeleteDC(memDC2);
    memDC = 0;
  }
  else
    old = SelectObject(memDC2, hbmp);

  return memDC2;
}

main (void)
{
  // Create device context for the display driver
  HDC hdcScreen = CreateDC("DISPLAY", NULL, NULL, NULL);
  if (!hdcScreen)
    return NULL;

  // creates a memory device context compatible with the hdcScreen
  int w = GetDeviceCaps(hdcScreen, HORZRES), h = GetDeviceCaps(hdcScreen, VERTRES);

  HGDIOBJ old;    
  HDC hdcDest = CreateBMP(w, h, 24, old);

  if (!hdcDest)
  {
    DeleteDC(hdcScreen);
    return 0;
  }

  BitBlt(hdcDest, 0, 0, w, h, hdcScreen, 0,0, SRCCOPY);

  BITMAP bmp;
  GetObject(GetCurrentObject( hdcDest, OBJ_BITMAP ), sizeof(bmp), &bmp);

// bmp processing...

  DeleteObject(SelectObject(hdcDest, old));
  DeleteDC(hdcDest);
  DeleteDC(hdcScreen);
  return 0;
}
Re[6]: BitBlt работает медленно при захвате с одним качество
От: Doctor M  
Дата: 03.11.03 10:50
Оценка:
Нашел!

Необходимо сделать

HDC CreateBMP( int w, int h, int bpp, HGDIOBJ& old )
{
//...
if( !hbmp2 )
{
DeleteDC( memDC2 );
return 0;
}
else
old = SelectObject( memDC2, hbmp2 );

return memDC2;
}

Но! работает также медленно! ПАЧЕМУ?!!!
Re[7]: BitBlt работает медленно при захвате с одним качество
От: AndreyFedotov Россия  
Дата: 04.11.03 07:47
Оценка:
Здравствуйте, Doctor M, Вы писали:

DM>Но! работает также медленно! ПАЧЕМУ?!!!


Привет Денис. Проболел тут в понедельник, так что посмотрел всё только сегодня.
Причина вот в чём:
У тебя контекст получатель:
hdcDest <=> memDC2
В который ты копируешь изображение:
BitBlt(hdcDest, 0, 0, w, h, hdcScreen, 0,0, SRCCOPY);

То есть твоя программа работает так:
1. Создать контекст экрана hdcScreen
2. Создать memDC — контекст совместимый с экраном
3. Создать DDB картинку, совместимую с memDC и выбрать её в контекст memDC
4. Создать memDC2 — контекст совместимый с экраном
5. Создать DIB картинку, совместимую с memDC2 и выбрать её в контекст memDC2
6. Скопировать экран (BitBlt) из конекста экрана в контекст memDC2
7. Обесчестить картинку...
8. Освободить ресурсы

Вопрос — зачем вообще нужны шаги 2 и 3? Такой вариант будет работать даже медленее, чем твой исходный.

Правильно должно было бы быть так:
1. Создать контекст экрана hdcScreen
2. Создать memDC — контекст совместимый с экраном
3. Создать DDB картинку, совместимую с memDC и выбрать её в контекст memDC
4. Создать memDC2 — контекст совместимый с экраном
5. Создать DIB картинку, совместимую с memDC2 и выбрать её в контекст memDC2
6. Скопировать экран (BitBlt) из конекста экрана в контекст memDC
7. Скопировать картинку (BitBlt) из конекста в памяти memDC в контекст memDC2
8. Обесчестить картинку...
9. Освободить ресурсы

С Уважением, Андрей
Re[8]: BitBlt работает медленно при захвате с одним качество
От: Andrew S Россия http://alchemy-lab.com
Дата: 06.11.03 21:01
Оценка:
AF>Вопрос — зачем вообще нужны шаги 2 и 3? Такой вариант будет работать даже медленее, чем твой исходный.

AF>Правильно должно было бы быть так:

AF>1. Создать контекст экрана hdcScreen
AF>2. Создать memDC — контекст совместимый с экраном
AF>3. Создать DDB картинку, совместимую с memDC и выбрать её в контекст memDC
AF>4. Создать memDC2 — контекст совместимый с экраном
AF>5. Создать DIB картинку, совместимую с memDC2 и выбрать её в контекст memDC2
AF>6. Скопировать экран (BitBlt) из конекста экрана в контекст memDC
AF>7. Скопировать картинку (BitBlt) из конекста в памяти memDC в контекст memDC2
AF>8. Обесчестить картинку...
AF>9. Освободить ресурсы

Быстрее, чем просто создавать DIB секцию и копировать в нее из экрана, не будет.

Причины
1. Совместимый контекст для gdi managed биттмапов вполне может быть реализован в видеопамяти — используется аппаратное копирование. В таком случае шаг 6 просто переливает из пустого в порожнее, 7 в результате все равно будет копировать из видеопамяти
2. Посмотрим, что происходит без использования доп. шагов, и с ними.

Без них.
1. Считываем пиксел.
2. Конвертируем его в нужный формат
3. Пишем в DIB секцию


С ними
1. Считываем пиксел.
2. Пишем его в gdi managed битмап.
3. Читаем пиксел из gdi managed битмап
4. Конвертируем его в нужный формат
5. Пишем в DIB секцию

Итак, производительность шага 2-3 методы (1) и (4-5) метода (2) очевидно равны — это выполняет тот же самый код (либо EngCopyBits, либо DrvCopyBits, если формат поверхности драйвера несовместима по формату со стандартными). Лишние шаги 2-3 метода (2) очевидно будут снижать производительность. В худшем случае, если не поддерживается аппаратное копирование в gdi managed bitmap — в 2 раза.
Вопрос — кому это надо?
Успехов.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[9]: BitBlt работает медленно при захвате с одним качество
От: AndreyFedotov Россия  
Дата: 10.11.03 08:36
Оценка:
Здравствуйте, Andrew S, Вы писали:

AF>>Вопрос — зачем вообще нужны шаги 2 и 3? Такой вариант будет работать даже медленее, чем твой исходный.


AF>>Правильно должно было бы быть так:

AF>>1. Создать контекст экрана hdcScreen
AF>>2. Создать memDC — контекст совместимый с экраном
AF>>3. Создать DDB картинку, совместимую с memDC и выбрать её в контекст memDC
AF>>4. Создать memDC2 — контекст совместимый с экраном
AF>>5. Создать DIB картинку, совместимую с memDC2 и выбрать её в контекст memDC2
AF>>6. Скопировать экран (BitBlt) из конекста экрана в контекст memDC
AF>>7. Скопировать картинку (BitBlt) из конекста в памяти memDC в контекст memDC2
AF>>8. Обесчестить картинку...
AF>>9. Освободить ресурсы

AS>Быстрее, чем просто создавать DIB секцию и копировать в нее из экрана, не будет.


AS>Причины

AS>1. Совместимый контекст для gdi managed биттмапов вполне может быть реализован в видеопамяти — используется аппаратное копирование. В таком случае шаг 6 просто переливает из пустого в порожнее, 7 в результате все равно будет копировать из видеопамяти
AS>2. Посмотрим, что происходит без использования доп. шагов, и с ними.

AS>Без них.

AS>1. Считываем пиксел.
AS>2. Конвертируем его в нужный формат
AS>3. Пишем в DIB секцию


AS>С ними

AS>1. Считываем пиксел.
AS>2. Пишем его в gdi managed битмап.
AS>3. Читаем пиксел из gdi managed битмап
AS>4. Конвертируем его в нужный формат
AS>5. Пишем в DIB секцию

AS>Итак, производительность шага 2-3 методы (1) и (4-5) метода (2) очевидно равны — это выполняет тот же самый код (либо EngCopyBits, либо DrvCopyBits, если формат поверхности драйвера несовместима по формату со стандартными). Лишние шаги 2-3 метода (2) очевидно будут снижать производительность. В худшем случае, если не поддерживается аппаратное копирование в gdi managed bitmap — в 2 раза.

AS>Вопрос — кому это надо?
AS>Успехов.

Самое забавное — что в реальности ускорение ПРОИСХОДИТ. Напиши код и посмтори сам...
С Уважением, Андрей
Re[10]: BitBlt работает медленно при захвате с одним качеств
От: Andrew S Россия http://alchemy-lab.com
Дата: 10.11.03 11:32
Оценка:
AF>Самое забавное — что в реальности ускорение ПРОИСХОДИТ. Напиши код и посмтори сам...

Написал код, посмотрел:

    HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);
    
//  Create dib section
    HDC hMemoryDC1 = CreateCompatibleDC(hScreenDC);
    DWORD dwWidth = GetDeviceCaps(hScreenDC, HORZRES);
    DWORD dwHeight = GetDeviceCaps(hScreenDC, VERTRES);
    DWORD dwBpp = 32;
    BITMAPINFO theBitInfo;
    theBitInfo.bmiHeader.biSize             = sizeof(BITMAPINFOHEADER);
    theBitInfo.bmiHeader.biHeight         = -(LONG)dwHeight;
    theBitInfo.bmiHeader.biWidth         = dwWidth;
    theBitInfo.bmiHeader.biBitCount      = dwBpp;
    theBitInfo.bmiHeader.biPlanes         = 1;
    theBitInfo.bmiHeader.biCompression     = BI_RGB;
    theBitInfo.bmiHeader.biSizeImage     = 0;
    theBitInfo.bmiHeader.biClrImportant  = 0;
    theBitInfo.bmiHeader.biClrUsed         = 0;
    theBitInfo.bmiHeader.biXPelsPerMeter = 0;
    theBitInfo.bmiHeader.biYPelsPerMeter = 0;
    void *pBuffer;
    HBITMAP hBitmap1 = ::CreateDIBSection(
                                            hScreenDC,
                                            &theBitInfo,
                                            DIB_RGB_COLORS,
                                            &pBuffer,
                                            0,
                                            0
                                        ); 
    ::SelectObject(hMemoryDC1, hBitmap1);
    
    HDC hMemoryDC2 = CreateCompatibleDC(hScreenDC);
    HBITMAP hBitmap2 = CreateCompatibleBitmap(hScreenDC, dwWidth, dwHeight);
    ::SelectObject(hMemoryDC2, hBitmap2);
    
    __int64  qTime = GetCycleCount();
    int i;
    for(i = 0; i < 20; ++i)
        BitBlt(hMemoryDC1, 0,0, dwWidth, dwHeight, hScreenDC, 0, 0, SRCCOPY);
    __int64  qTime1 = GetCycleCount();
    
    for(i = 0; i < 20; ++i)
    {
        BitBlt(hMemoryDC2, 0,0, dwWidth, dwHeight, hScreenDC, 0, 0, SRCCOPY);
        BitBlt(hMemoryDC1, 0,0, dwWidth, dwHeight, hMemoryDC2, 0, 0, SRCCOPY);
    }
    __int64  qTime2 = GetCycleCount();
    printf("direct copy: %I64d\ndouble copy: %I64d", qTime1  - qTime, qTime2 - qTime1);

    return 0;


// 32bpp->32bpp
direct copy: 1033530580
double copy: 1082694190
// 8bpp->32bpp
direct copy: 7694427100
double copy: 7655239570


Вопрос — и где обещаное "ускорение"?
Разницу в 3-м знаке надо считать погрешностью измерения.
И это при том, что видеокарта аппаратно ускоряет все что только можно для 2d. Если не будет — представьте оверхед для метода 2 и ужаснитесь
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[11]: BitBlt работает медленно при захвате с одним качеств
От: AndreyFedotov Россия  
Дата: 10.11.03 12:40
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Вопрос — и где обещаное "ускорение"?

AS>Разницу в 3-м знаке надо считать погрешностью измерения.
AS>И это при том, что видеокарта аппаратно ускоряет все что только можно для 2d. Если не будет — представьте оверхед для метода 2 и ужаснитесь

Всё верно. А теперь попробуй вместо 8 => 32 преобразование 32 => 24, 32 => 16, 24 => 16. 32 => 8, вот тут то и должно проявиться ускорение. Если этого не произошло, то поздравляю — у тебя очень продвинутая карточка. Для неё, то что ты писал — верно. И такой способ будет лишь притормаживать систему.

С Уважением, Андрей
Re[12]: BitBlt работает медленно при захвате с одним качеств
От: Andrew S Россия http://alchemy-lab.com
Дата: 10.11.03 12:53
Оценка:
Здравствуйте, AndreyFedotov, Вы писали:

AF>Здравствуйте, Andrew S, Вы писали:


AS>>Вопрос — и где обещаное "ускорение"?

AS>>Разницу в 3-м знаке надо считать погрешностью измерения.
AS>>И это при том, что видеокарта аппаратно ускоряет все что только можно для 2d. Если не будет — представьте оверхед для метода 2 и ужаснитесь

AF>Всё верно. А теперь попробуй вместо 8 => 32 преобразование 32 => 24, 32 => 16, 24 => 16. 32 => 8, вот тут то и должно проявиться ускорение. Если этого не произошло, то поздравляю — у тебя очень продвинутая карточка. Для неё, то что ты писал — верно. И такой способ будет лишь притормаживать систему.


Попробовал:


32->24
direct copy: 7447393906
double copy: 7330032545

8->24
direct copy: 7556293729
double copy: 7538200010

32->16
direct copy: 23481917621
double copy: 22960878343

8->16
direct copy: 7503734374
double copy: 7466075920


И? Ускорения опять нет. Только лишние траты памяти. Вы у себя то попробуйте для интереса
А насчет 32->24 и прочего — а почему бы, собственно, если они _на самом деле не быстрее_ bitblt xxx->32, не использовать всегда 32бит back bufer, что, очевидно, вполне возможно исходя из первоначального вопроса?
PS
Видеокарта у меня отнюдь не продвинутая и гораздо слабее среднестатистической. G-Force2 MX400, со старенькими драйверами 23.11 от NVidia. Так что выводы по крайней мере для меня пока что очевидны.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[13]: BitBlt работает медленно при захвате с одним качеств
От: AndreyFedotov Россия  
Дата: 10.11.03 13:19
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Попробовал:



AS>
32->>24
AS>direct copy: 7447393906
AS>double copy: 7330032545

8->>24
AS>direct copy: 7556293729
AS>double copy: 7538200010

32->>16
AS>direct copy: 23481917621
AS>double copy: 22960878343

8->>16
AS>direct copy: 7503734374
AS>double copy: 7466075920
AS>


AS>И? Ускорения опять нет. Только лишние траты памяти. Вы у себя то попробуйте для интереса

AS>А насчет 32->24 и прочего — а почему бы, собственно, если они _на самом деле не быстрее_ bitblt xxx->32, не использовать всегда 32бит back bufer, что, очевидно, вполне возможно исходя из первоначального вопроса?
AS>PS
AS>Видеокарта у меня отнюдь не продвинутая и гораздо слабее среднестатистической. G-Force2 MX400, со старенькими драйверами 23.11 от NVidia. Так что выводы по крайней мере для меня пока что очевидны.

Интересно. У меня карточка была другая, там ускорение было при 32 => 16 примерно в 2 раза. В других комбинациях — меньше...
Кроме того, посмтори: здесь
Автор: Doctor M
Дата: 04.11.03


В Любом случае спасибо за интересную информацию. Надо будет попробовать ещё на нескольких карточках.

С Уважением, Андрей
Re[14]: BitBlt работает медленно при захвате с одним качеств
От: Andrew S Россия http://alchemy-lab.com
Дата: 10.11.03 14:13
Оценка:
AF>Интересно. У меня карточка была другая, там ускорение было при 32 => 16 примерно в 2 раза. В других комбинациях — меньше...
AF>Кроме того, посмтори: здесь
Автор: Doctor M
Дата: 04.11.03


Ага, там используется в качестве промежуточного буфера тоже DIB секция.
Что ж, тогда это все объясняет.
Вот результаты такого теста.

32->24
direct copy: 7476437631
double copy: 1441937255
16->24
direct copy: 8118793578
double copy: 4284605608

(!!)
Но что самое интересное, в таком случае делать полный offscreen битмап совсем не обязательно — достаточно лишь одной линии:

    HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);
    
//  Create dib section
    HDC hMemoryDC1 = CreateCompatibleDC(hScreenDC);
    DWORD dwWidth = GetDeviceCaps(hScreenDC, HORZRES);
    DWORD dwHeight = GetDeviceCaps(hScreenDC, VERTRES);
    DWORD dwBpp = 24;
    BITMAPINFO theBitInfo;
    theBitInfo.bmiHeader.biSize             = sizeof(BITMAPINFOHEADER);
    theBitInfo.bmiHeader.biHeight         = -(LONG)dwHeight;
    theBitInfo.bmiHeader.biWidth         = dwWidth;
    theBitInfo.bmiHeader.biBitCount      = dwBpp;
    theBitInfo.bmiHeader.biPlanes         = 1;
    theBitInfo.bmiHeader.biCompression     = BI_RGB;
    theBitInfo.bmiHeader.biSizeImage     = 0;
    theBitInfo.bmiHeader.biClrImportant  = 0;
    theBitInfo.bmiHeader.biClrUsed         = 0;
    theBitInfo.bmiHeader.biXPelsPerMeter = 0;
    theBitInfo.bmiHeader.biYPelsPerMeter = 0;
    void *pBuffer;
    HBITMAP hBitmap1 = ::CreateDIBSection(
                                            hScreenDC,
                                            &theBitInfo,
                                            DIB_RGB_COLORS,
                                            &pBuffer,
                                            0,
                                            0
                                        ); 
    ::SelectObject(hMemoryDC1, hBitmap1);
    
    HDC hMemoryDC2 = CreateCompatibleDC(hScreenDC);
//    HBITMAP hBitmap2 = CreateCompatibleBitmap(hScreenDC, dwWidth, dwHeight);
//    HBITMAP hBitmap2 = CreateCompatibleBitmap(hScreenDC, dwWidth, dwHeight);
    theBitInfo.bmiHeader.biBitCount = GetDeviceCaps(hScreenDC, BITSPIXEL);
    theBitInfo.bmiHeader.biHeight         = -1;
    HBITMAP hBitmap2 = ::CreateDIBSection(
                                            hScreenDC,
                                            &theBitInfo,
                                            DIB_RGB_COLORS,
                                            &pBuffer,
                                            0,
                                            0
                                        ); 
    ::SelectObject(hMemoryDC2, hBitmap2);
    
    __int64  qTime = GetCycleCount();
    int i;
    for(i = 0; i < 20; ++i)
        BitBlt(hMemoryDC1, 0,0, dwWidth, dwHeight, hScreenDC, 0, 0, SRCCOPY);
    __int64  qTime1 = GetCycleCount();
    
    for(i = 0; i < 20; ++i)
        for (int j = 0; j < dwHeight; ++j)
        {
            BitBlt(hMemoryDC2, 0,0, dwWidth, dwHeight, hScreenDC, 0, j, SRCCOPY);
            BitBlt(hMemoryDC1, 0,j, dwWidth, 1, hMemoryDC2, 0, 0, SRCCOPY);
        }
    __int64  qTime2 = GetCycleCount();
    printf("direct copy: %I64d\ndouble copy: %I64d", qTime1  - qTime, qTime2 - qTime1);

Вот результаты:

32->24
direct copy: 7428372514
double copy: 1017241379
16->24
direct copy: 8132659472
double copy: 4313731908


В общем, они примерно те же.
Т.о. — действительно, имеет место быть рост производительности при использовании в качестве промежуточного буфера dib секции с такой же глубиной цвета, как и у экрана.
Мыслей, почему _так_ происходит, у меня на самом деле особо нет. Скорее всего, дело в том, что при копировании с gdi managed битмап (как было в пред. версиях) gdi использует (если драйвер не заявил о совместимой поверхности) функции драйвера DrvBitBlt. Вероятно, дело в низкой оптимизации этих функций либо еще в чем то, что можно понять, разобрав по кусочкам драйвер от NVidia. Скорее всего, при копировании на такой же по глубине цвета dib используется быстрая реализация драйвера, при копировании на другую цветовую глубину драйвер либо отдает это gdi (EngBitBlt), которая почему то (!) работает при этом суммарно в 3 раза медленнее, чем при совершении аналогичной операции,причем ровно этой же функцией, но над dib секцией (хотя, очевидно, этого быть не дОлжно — скорость должна быть ровно такой же или даже выше, т.к. тут нет лишнего копирования в промежуточную dib секцию), либо это делает сам драйвер, но тогда непонятно, почему он так плохо оптимизирован. В общем, странно.
Что то здесь не так, а что, и главное, где — непонятно. Хорошо бы понять, почему дела обстоят именно так. Есть мысли?

AF> В Любом случае спасибо за интересную информацию. Надо будет попробовать ещё на нескольких карточках.


AF> С Уважением, Андрей
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[15]: BitBlt работает медленно при захвате с одним качеств
От: AndreyFedotov Россия  
Дата: 10.11.03 14:29
Оценка:
Здравствуйте, Andrew S, Вы писали:

AF>>Интересно. У меня карточка была другая, там ускорение было при 32 => 16 примерно в 2 раза. В других комбинациях — меньше...

AF>>Кроме того, посмтори: здесь
Автор: Doctor M
Дата: 04.11.03


AS>Ага, там используется в качестве промежуточного буфера тоже DIB секция.

AS>Что ж, тогда это все объясняет.
AS>Вот результаты такого теста.

AS>
32->>24
AS>direct copy: 7476437631
AS>double copy: 1441937255
16->>24
AS>direct copy: 8118793578
AS>double copy: 4284605608
AS>

AS>(!!)
AS>Но что самое интересное, в таком случае делать полный offscreen битмап совсем не обязательно — достаточно лишь одной линии:

А вот это действительно интересно. То, что достаточно одной линии — это безусловно плюс.

AS>Вот результаты:


AS>
32->>24
AS>direct copy: 7428372514
AS>double copy: 1017241379
16->>24
AS>direct copy: 8132659472
AS>double copy: 4313731908
AS>


AS>В общем, они примерно те же.

AS>Т.о. — действительно, имеет место быть рост производительности при использовании в качестве промежуточного буфера dib секции с такой же глубиной цвета, как и у экрана.
AS>Мыслей, почему _так_ происходит, у меня на самом деле особо нет. Скорее всего, дело в том, что при копировании с gdi managed битмап (как было в пред. версиях) gdi использует (если драйвер не заявил о совместимой поверхности) функции драйвера DrvBitBlt. Вероятно, дело в низкой оптимизации этих функций либо еще в чем то, что можно понять, разобрав по кусочкам драйвер от NVidia. Скорее всего, при копировании на такой же по глубине цвета dib используется быстрая реализация драйвера, при копировании на другую цветовую глубину драйвер либо отдает это gdi (EngBitBlt), которая почему то (!) работает при этом суммарно в 3 раза медленнее, чем при совершении аналогичной операции,причем ровно этой же функцией, но над dib секцией (хотя, очевидно, этого быть не дОлжно — скорость должна быть ровно такой же или даже выше, т.к. тут нет лишнего копирования в промежуточную dib секцию), либо это делает сам драйвер, но тогда непонятно, почему он так плохо оптимизирован. В общем, странно.
AS>Что то здесь не так, а что, и главное, где — непонятно. Хорошо бы понять, почему дела обстоят именно так. Есть мысли?
Есть. Я в общем-то их уже излагал. Смысл такой:
Если у карточки нет аппаратной поддержки таких преобразований (а кроме Matrox'a я такой карточки и не знаю, хотя они должны быть), то в случае Bit-compatible bitmap используется встроеное почти в каждую карточку аппаратное копирование при максимальной скорости, на какую способна аппаратура. А в случае, когда происходит копирование не Bit-Compatible Bitmap'ов то: используется программная работа с шиной, что медленее, так как работа ведётся через окно в памяти, и перед копированием данных Pixel'а требуется установить адрес самого окна. И всё по шине, которая работает медленее, чем шина памяти в 2-8 раз как минимум...

С Уважением, Андрей
Re[16]: BitBlt работает медленно при захвате с одним качеств
От: Andrew S Россия http://alchemy-lab.com
Дата: 10.11.03 14:53
Оценка:
AS>>Что то здесь не так, а что, и главное, где — непонятно. Хорошо бы понять, почему дела обстоят именно так. Есть мысли?
AF>Есть. Я в общем-то их уже излагал. Смысл такой:
AF> Если у карточки нет аппаратной поддержки таких преобразований (а кроме Matrox'a я такой карточки и не знаю, хотя они должны быть), то в случае Bit-compatible bitmap используется встроеное почти в каждую карточку аппаратное копирование при максимальной скорости, на какую способна аппаратура. А в случае, когда происходит копирование не Bit-Compatible Bitmap'ов то: используется программная работа с шиной, что медленее, так как работа ведётся через окно в памяти, и перед копированием данных Pixel'а требуется установить адрес самого окна. И всё по шине, которая работает медленее, чем шина памяти в 2-8 раз как минимум...

В смысле через окно? Поподробнее можно? Насколько я знаю, все карты уже давно имеют flat frame buffer, доступный напрямую, а для тех, которые не имеют, gdi это эмулирует путем exceptions.
На самом деле, на уровне вызовов gdi я не вижу _никаких_ отличий для обоих методов.
Для конверсии и там, и там достаточно:
1. Считать пиксел из src
2. Отконвертить его в нужный формат
3. Записать его в dst

Операция (1) в методе с буферизацией разбивается на 3 дополнительных. При этом все, что делается в методе с буферизацией, должно привести наоборот к падению производительности.
Вы знакомы с интерфейсом ddi? Может, тогда попробовать объяснять на этом уровне, т.к. очевидно, что в любом случае сводится именно к нему? Единственный вариант, который я вижу — gdi создает для копирования буфер в формате, совместимом с форматом экрана, и использует аппаратный bitblt на эту поверхность. Но тогда непонятно, почему это медленнее, чем при копировании по линиям, если только gdi не использует буфер меньшего размера.
В общем, все непонятно.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[17]: BitBlt работает медленно при захвате с одним качеств
От: AndreyFedotov Россия  
Дата: 10.11.03 15:07
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>В смысле через окно? Поподробнее можно? Насколько я знаю, все карты уже давно имеют flat frame buffer, доступный напрямую, а для тех, которые не имеют, gdi это эмулирует путем exceptions.

Правильно, однако отмечу, что Exceptions — очень медленно.

AS>На самом деле, на уровне вызовов gdi я не вижу _никаких_ отличий для обоих методов.

AS>Для конверсии и там, и там достаточно:
AS>1. Считать пиксел из src
AS>2. Отконвертить его в нужный формат
AS>3. Записать его в dst
Здесь вместо пиксел скорее надо говорить "строка" или окно. Различие в производительности получается как раз из-за того, что операция 1 в случае аппаратного копирования (что возможно при одинаковом цветовом разрешении) и 2 (при работе с картинкой в памяти) идут ГОРАЗДО быстрее... (Вспомним, что кэш для видеопамяти обычно отключон).

AS>Операция (1) в методе с буферизацией разбивается на 3 дополнительных. При этом все, что делается в методе с буферизацией, должно привести наоборот к падению производительности.

Только на первый взгляд. Реально — наоборот.
AS>Вы знакомы с интерфейсом ddi?
Да знаком.
AS> Может, тогда попробовать объяснять на этом уровне, т.к. очевидно, что в любом случае сводится именно к нему? Единственный вариант, который я вижу — gdi создает для копирования буфер в формате, совместимом с форматом экрана, и использует аппаратный bitblt на эту поверхность. Но тогда непонятно, почему это медленнее, чем при копировании по линиям, если только gdi не использует буфер меньшего размера.
Думаю проблема как раз из-за того, что GDI не создаёт буфера. И осуществляет копирование программно, с преобразованием цвета на лету. Что и приводит к проблемам...
AS>В общем, все непонятно.
Согласен.

С Уважением, Андрей
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.