Модераторы: Snowy, Alexeis, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Наиболее быстрый вывод изображения во весь экран. Выводим изображение из массива на весь э 
:(
    Опции темы
sgi1981
Дата 3.4.2006, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 16.3.2006

Репутация: нет
Всего: 10



Здравствуйте, ребята.

Мне нужно наиболее быстро выводить изображение из массива на экран во весь экран.
Насколько я знаю, быстрым способом может быть применение API-функции SetDIBitsToDevice.
Описание таково.

Функция SetDIBitsToDevice

Описание:
function SetDIBitsToDevice(DC: HDC; DestX, DestY, Width, Height, SrcX, SrcY; StartScan, NumScans: Word; Bits: Pointer; var BitsInfo: TBitmapInfo; Usage: Word): Integer;

Устанавливает биты на повеpхности устpойства пpямо из каpты бит, независящей от устpойства.

Паpаметpы:
DC: Контекст устpойства.
DestX, DestY: Начало пpямоугольника назначения в устpойстве.
Width: Экстент по X пpямоугольника DIB.
Height: Экстент по Y пpямоугольника DIB.
SrcX, SrcY: Исходное положение DIB.
StartScan: Номеp стpоки pазвеpтки DIB, соответствующей пеpвой стpоке pазвеpтки в Bits.
NumScans: Число стpок pазвеpтки DIB в Bits.
Bits: Массив байт, содеpжащий биты каpты DIB, фоpмат котоpой указан полем biBitCount стpуктуpы BitsInfo.
BitsInfo: Стpуктуpа TBitmapInfo, содеpжащая инфоpмацию о каpте DIB.
Usage: Описывает содеpжимое полей bmiColors стpуктуpы BitsInfo.
Одна из констант DIB_RGB_Colors или DIB_Pal_Colors. См. pаздел "Идентификатоpы таблицы цветов, DIB_" в главе 1.

Возвpащаемое значение:
Число установленных стpок pазвеpтки.

функция находится в файле gdi32.dll

Этой функцией я добивался вывода на своем компьютере 150 полноэкранных кадров в секунду, хотя частота мигания экрана и того меньше - 100 Гц.

Контекст дисплея создавал так
Код

HDC DC1;
DC1=CreateDC("DISPLAY", 0, 0, 0);

Такое устройство хорошо выводит на экран изображение и быстро. И даже все окна может зарисовать. А при постоянном выводе изображения никакие окна так нормально и не появятся, даже диспетчер задач не появится нормально. smile smile smile

Я сейчас предоставлю код на C++ Builder демо-программы. На самом деле он составлен в большинстве на встроенном ассемблере. Можете проверить - нажмите кнопку мыши и в течении нескольких секунд пронаблюдайте за картиной. В конце нажмите Alt-F4.

Код

#include <vcl.h>
#pragma hdrstop

#include "Unit1effectSetDIBitsToDevice.h"
#include "math.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
unsigned int masim[4000000];
tagBITMAPINFO* bi= new tagBITMAPINFO;
void* p;
int i;
int pr;
unsigned int  DestX1, DestY1, Width1, Height1, SrcX1, SrcY1, StartScan, NumScans,
  X1,X2,Y1,Y2;
HDC D;
HINSTANCE HDLL;
FARPROC Addrf1;
unsigned int mas1ht[4];
unsigned int mas2Yj[4];
unsigned int mas3i[4];
unsigned int mas4_4[4];
unsigned int mas5m[4];
tagRECT r11;
tagRECT r12;
HRGN RG,RG1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{

}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormClick(TObject *Sender)
{
//int i,fy,j,k;
//SetDIBitsToDevice(D,DestX1,DestY1,Width1,Height1,SrcX1,SrcY1,StartScan,NumScans,p,bi,0);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::FormCreate(TObject *Sender)
{
bi->bmiHeader.biSize=sizeof(bi->bmiHeader);
bi->bmiHeader.biWidth=1024;
bi->bmiHeader.biHeight=768;
bi->bmiHeader.biPlanes=1;
bi->bmiHeader.biCompression=0;
bi->bmiHeader.biBitCount=32;
bi->bmiHeader.biSizeImage=1024*768*4;
DestX1=0;
DestY1=0;
Width1=1024;
Height1=768;
SrcX1=0;
SrcY1=0;
StartScan=0;
NumScans=1024;
p=masim;
D=CreateDC("DISPLAY",0,0,0);
HDLL=LoadLibrary("gdi32.dll");
//Addrf1=GetProcAddress(HDLL,"SetDIBitsToDevice");
Form1->Hide();
mas4_4[0]=4;
mas4_4[1]=4;
mas4_4[2]=4;
mas4_4[3]=4;
/*RG=CreateRectRgn(200,200,1024,768);
RG1=SelectObject(D,RG);*/
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
      int X, int Y)
{
unsigned int x,y,i,j,c,r,Yj;
/*c=0;
for (j=768;j>0;j--)
for (i=0;i<1024;i++)
{r=abs(X-i)*abs(X-i)+abs(Y-j)*abs(Y-j);
masim[c]=r*256;
c++;}*/
SrcY1=0;
DestY1=0;
asm{
mov esi,X;
mov edi,Y;
mov ecx,0;
mov j,768;
@c2:cmp j,0;
jz @2;
mov i,0;
mov eax,edi;
sub eax,j;
imul eax;
mov Yj,eax;
@c1:cmp i,1024;
jz @3;
mov eax,esi;
sub eax,i;
imul eax;
add eax,Yj;
shl eax,8;
mov masim+ecx*4,eax;
inc ecx;
inc i;
jmp @c1;
@3:dec j;
jmp @c2;
@2:
};
SetDIBitsToDevice(D,DestX1,DestY1,Width1,Height1,SrcX1,SrcY1,StartScan,NumScans,p,bi,0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseUp(TObject *Sender, TMouseButton Button,
      TShiftState Shift, int X, int Y)
{
unsigned int x,y,i,j,c,r,ht,ht1,c1,Yj,b1,ecx1;
unsigned int v1000=6;
tagPOINT tp1;
ht=0;
asm
{
mov c1,0;
@c3:cmp c1,5000;//счетчик
jz @1;
}
GetCursorPos(&tp1);
asm{
mov esi,dword ptr tp1;
mov edi,dword ptr tp1+4;
inc ht;
mov eax,ht;
mul eax;
imul v1000;
mov ht1,eax;
mov mas1ht,eax;//??? XMM
mov mas1ht+4,eax;
mov mas1ht+8,eax;
mov mas1ht+12,eax;
mov mas5m,esi;
mov mas5m+4,esi;
mov mas5m+8,esi;
mov mas5m+12,esi;
mov ecx,0;
mov j,768;
mov b1,0;
mov SrcY1,0;
mov DestY1,0;
//XMM
movdqu xmm7,dqword ptr mas1ht;
movdqu xmm4,dqword ptr mas5m;
movdqu xmm3,dqword ptr mas4_4;
mov StartScan,0;
@c2:cmp b1,24;
jz @22;
cmp j,0;
jz @2;
mov i,0;
mov eax,edi;
sub eax,j;
imul eax;
mov Yj,eax;
mov mas2Yj,eax;// XMM
mov mas2Yj+4,eax;
mov mas2Yj+8,eax;
mov mas2Yj+12,eax;
mov mas3i,0;
mov mas3i+4,1;
mov mas3i+8,2;
mov mas3i+12,3;
//XMM
movdqu xmm6,dqword ptr mas2Yj;
movdqu xmm5,dqword ptr mas3i;
@c1:cmp i,256;//1024;
jz @3;
/*mov eax,esi;
sub eax,i;
imul eax;
add eax,Yj;
sub eax,ht1;
shl eax,8;
mov masim+ecx*4,eax;
inc ecx;*/
movdqa xmm0,xmm4;
psubd xmm0,xmm5;
pmaddwd xmm0,xmm0;
paddd xmm0, xmm6;
psubd xmm0,xmm7;
pslld xmm0,8;
movdqu dqword ptr masim+ecx,xmm0;
add ecx,16;
paddd xmm5,xmm3;
inc i;
jmp @c1;
@3:dec j;
inc b1;
jmp @c2;
@22:mov b1,0;
push DIB_RGB_COLORS;
push dword ptr bi;
push dword ptr p;
push dword ptr 24;//NumScans;
push dword ptr StartScan;
push dword ptr SrcY1;
push dword ptr SrcX1;
push dword ptr Height1;
push dword ptr Width1;
push dword ptr DestY1;
push dword ptr DestX1;
push dword ptr D;
call SetDIBitsToDevice;

mov ecx,0;
//sub DestY1,24;
add StartScan,24;
jmp @c2;
@2:inc c1;
jmp @c3;
@1:mov StartScan,0;
};
/*for (c1=0;c1<100;c1++){ht++;c=0;
for (j=768;j>0;j--)
for (i=0;i<1024;i++)
{r=abs(X-i)*abs(X-i)+abs(Y-j)*abs(Y-j)-ht*ht*1000;
masim[c]=r*256;
c++;}
SetDIBitsToDevice(D,DestX1,DestY1,Width1,Height1,SrcX1,SrcY1,StartScan,NumScans,p,bi,0);
}*/
}


Проблема заключается в следующем.
Перед тем как вывести массив на экран в виде растрового изображения - нужно этот массив оформить, то есть рассчитать цвет каждого пиксела, что означает рассчитать значение каждого элемента массива. Рассчитанные значения само собой нужно сохранять в самом массиве. Но размер массива при разрешении экрана 1024*768 точек и цвета TrueColor равен приблизительно 3 МБ и в кэш-память второго уровня не помещается при записи всех элементов.
Процессору приходится сохранять массив в оперативную память. Но скорость записи в оперативную память всего 640 МБ / секунда. Это в 30 раз меньше чем скорость записи в кэш-память. Значит при этом теряется время. Избежать лишней записи массива в кэш-память можно поэтапным выводом изображения порциями. В таком случае организуется массив, который бы полностью поместился в кэш-памяти и хранил только 24 строки развертки (прикиньте, у меня на Celeron 4 всего то 128 кб кэша). Этот массив выводится через определенное время на разные учатки экрана той же функцией SetDIBitsToDevice. И тогда эта API-функция не обращается к оперативной памяти за массивом а читает его прямо из кэша. И процессор не будет лишний раз гонять данные в модули памяти и назад.
Но в таком случае получается резание изображения.
И это хорошо видно при работе демо-программы. Если сразу за один вызов функции выводить все полноэкранное изображение, то резания изображения не происходит.
Почему в данном случае изображение режется я в принципе знаю.
Но мне нужно избежать этого вредного эффекта и в то же время экономно использовать время ЦП.
Я знаю, что есть такой прием.
В видеоадаптере организуется как минимум 2 области видеопамяти. А вывод информации происходин на экран только из одной из них, в то время как запись со стороны центрального процессора идет в другую область видеопамяти. Затем, когда процессор запишет в эту другую область памяти изображение, видеоадаптер переключается программно на отображение вновь записанной области видеопамяти, а ЦП теперь начинает писать в первую область видеопамяти. И так повторяется от кадра до кадра. Но я работаю через функцию API. И если созданное для дисплея устройство обрабатывает только одноэкранную матрицу бит, то никак я не могу записать в теневую область данные, поскольку её просто нет в таком случае. Если бы БИТМАП устройства дисплея созданного (устройства) функцией CreateDC("DISPLAY", 0, 0, 0) был больше размера пиксельной матрицы, можно было бы прокручивать изображение функцией ScrollDC. Я пробовал так делать, но результат прокручивания показал, что за границами дисплея битмапа уже не существует.
Теперь я не нахожу выхода.



--------------------
Тело в нашем пространстве - есть часть пространства, в которой пространство обладает дисторсией относительно внешнего пространства.
PM MAIL   Вверх
Alexeis
Дата 3.4.2006, 14:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 55
Всего: 459



sgi1981, Если нужна такая большая скорость, может воспользоваться OpenGl?


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Snowy
Дата 3.4.2006, 15:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 18
Всего: 484



DirectDraw.
Загоняем изображение, как текстуру в видеопамять.
Никакой кэш и оперативка нам более не интересны.
Даем комманду - рисуй и все.
PM MAIL   Вверх
sgi1981
Дата 3.4.2006, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 16.3.2006

Репутация: нет
Всего: 10



Цитата
sgi1981, Если нужна такая большая скорость, может воспользоваться OpenGl?


Покажи пример вывода массива двойных слов в видеопамять на OpenGl.
Добавлено @ 17:43
Цитата
Никакой кэш и оперативка нам более не интересны.


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

P. S. Никогда не бери пример с дураков, которыми легче управлять.

Цитата
DirectDraw.
Загоняем изображение, как текстуру в видеопамять...
...Даем комманду - рисуй и все.


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

КАК МНЕ ЭТО СДЕЛАТЬ.

Это сообщение отредактировал(а) sgi1981 - 3.4.2006, 17:44


--------------------
Тело в нашем пространстве - есть часть пространства, в которой пространство обладает дисторсией относительно внешнего пространства.
PM MAIL   Вверх
bems
Дата 3.4.2006, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 1
Всего: 88



100 кадров в секунду - это (для большинства) предел восприятия. И ни кеш, ни оперативка, ни замена селерона на пентиум не смогут застваить твоего юзера заметить разницу. Зачем тебе 150?


--------------------
Обижено школьников: 8
PM MAIL   Вверх
sgi1981
Дата 3.4.2006, 19:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 284
Регистрация: 16.3.2006

Репутация: нет
Всего: 10



Цитата(bems @ 3.4.2006, 18:11)
100 кадров в секунду - это (для большинства) предел восприятия. И ни кеш, ни оперативка, ни замена селерона на пентиум не смогут застваить твоего юзера заметить разницу. Зачем тебе 150?

Ребят, я понимаю что вы читаете и хотите понять...
Но FPS=150 мне вовсе не нужно.
А про FPS=150 я писал потому, что учитывал скорость вывода уже сформированного массива в видеопамять. В действительности кроме процедуры вывода готового массива должно выполняться формирование массива. Само формирование массива заключается в вычислении значений цвета пикселов.
Я должен оценить общее быстродействие. Но общее быстродействие зависит не только от скорости вычисления цветов пикселов, но и от скорости вывода готового массива в видеопамять !
А скорость записи в видеопамять я как раз и оцениваю по скорости копирования кадров без их формирования.
Ещё раз поясну другим путем.
Я хочу добиться максимальной скорости вывода кадров (максимального FPS) изменяющегося изображения виртуального пространства.
Эта скорость зависит от двух составляющих
1) Скорость вычисления элементов массива изображения
2) Скорость вывода этого массива на экран

Значит я стремлюсь добиться максимума обеих скоростей.
В первом сообщении, где я писал про FPS=150 я оценивал быстродействие второй составляющей общей задачи. То бишь чтобы оценить то насколько быстро копируется готовое изображение на экран, нужно отбросить первую составляющую задачи, чтобы формирование массива не влияло на оценку общей скорости и тогда мы можем принять, что общая скорость равна скорости копирования в видеопамять. Для этого просто многократно копируем один и тот же массив на экран. Тогда мы можем сделать вывод по быстродействию второй составляющей задачи.

Теперь понятно ?

А теперь кто-нибудь объясните мне, пожалуйста, какие есть функции OpenGL или DirectX для вывода изображения по частям из массива так, чтобы все полноэкранное изображение обновлялось только по моей команде после того как все части его будут выведены, чтобы не происходило "разрезание" изображения. То есть чтобы не было так, что в то время как луч ЭЛТ монитора выводит старый кадр копируется в видеопамять новый, и таким образом часть изображения получится от старого кадра, а остальная часть - от нового.


--------------------
Тело в нашем пространстве - есть часть пространства, в которой пространство обладает дисторсией относительно внешнего пространства.
PM MAIL   Вверх
Alexeis
Дата 5.4.2006, 09:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 55
Всего: 459



Ну я думаю без учебника здесь точно не разобраться. А последовательность действй примрно такая.
1)Получение контекста окна.
2)инициализация формата пиксела со свойствами двойной буферизации и режимом - полный экран
3)Установка параметров экрана
3)Подготовка битовой карты - просто перечисляются цвета пикселов слева напаво, сверху вниз.
4)Загрузка текстуры LoadTexture2D (размеры соотв размерам экрана)
5)Рисоватие квадрата с координатами левой нижней и правой верхней (-1,-1), (1,1) с выводом текстуры.
SwapBuffers(dc); перересует весь экран

p.s. способ Snowy может быть быстрее(я не знаком с DirectDraw)


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
mes
Дата 11.5.2006, 14:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: нет
Всего: 250





Цитата(sgi1981 @  3.4.2006,  14:24 Найти цитируемый пост)
 Если бы БИТМАП устройства дисплея созданного (устройства) функцией CreateDC("DISPLAY", 0, 0, 0) был больше размера пиксельной матрицы, можно было бы прокручивать изображение функцией ScrollDC. Я пробовал так делать, но результат прокручивания показал, что за границами дисплея битмапа уже не существует. 
Теперь я не нахожу выхода.


Определи что у твоего контекста два буффера и меняй их.

(посмотри описание: SetPixelFormat , PIXELFORMATDESCRIPTOR, SwapBuffers) 


--------------------
PM MAIL WWW   Вверх
p0s0l
Дата 11.5.2006, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Г-н Посол
****


Профиль
Группа: Экс. модератор
Сообщений: 3668
Регистрация: 13.7.2003
Где: 58°38' с.ш. 4 9°41' в.д.

Репутация: 16
Всего: 112



Если я правильно понял - у тебя каждый пиксел вычисляется по какой-то формуле. Если сможешь это оформить в виде шейдеров, то вычислениями будет заниматься уже видяха, а не проц + не надо перекидывать данные:
http://forum.vingrad.ru/index.php?showtopic=73464

Если же все вычисления сводятся лишь к тому, что надо просто вывести определенный кусок сгенерированной статичной текстуры, то проще их заранее сгенерить и выводить, как сказал Snowy...
 


--------------------
С уважением, г-н Посол.
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Звук, графика и видео"
Girder
Snowy
Alexeis

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи
  • По вопросам разработки игр стоит заглянуть сюда

FAQ раздела лежит здесь!


Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Girder, Snowy.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Звук, графика и видео | Следующая тема »


 




[ Время генерации скрипта: 0.0618 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.