Войти
ПрограммированиеФорумГрафика

BitBlt как увеличить скорость?

Страницы: 1 2 Следующая »
#0
1:10, 30 янв. 2010

Здравствуйте! Помогите ускорить захват данных с экрана с помошью GDI. У меня скорость получается 47 милисек (1280х800х32 1.6GHz GMA945). Как сделать быстрей? Вот код.

void Init()
{
    data = new unsigned char[m_iWidth * m_iHeight * 4];//память где будут лежать данные захвата экрана

    hDesktopWnd=GetDesktopWindow();
    hDesktopDC=GetDC(hDesktopWnd);
    hDesktopCompatibleDC=CreateCompatibleDC(hDesktopDC);

    //Init GDI
    BITMAPINFO  bmpInfo;
    ZeroMemory(&bmpInfo,sizeof(BITMAPINFO));
    bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
    bmpInfo.bmiHeader.biBitCount=GetDeviceCaps(hDesktopDC,BITSPIXEL);
    bmpInfo.bmiHeader.biCompression = BI_RGB;
    bmpInfo.bmiHeader.biWidth=GetSystemMetrics(SM_CXSCREEN);
    bmpInfo.bmiHeader.biHeight=-GetSystemMetrics(SM_CYSCREEN);
    bmpInfo.bmiHeader.biPlanes=1;
    bmpInfo.bmiHeader.biSizeImage=abs(bmpInfo.bmiHeader.biHeight)*bmpInfo.bmiHeader.biWidth*bmpInfo.bmiHeader.biBitCount/8;

  
    hDesktopCompatibleBitmap=CreateDIBSection(hDesktopDC,&bmpInfo,DIB_RGB_COLORS,&pBits,NULL,0);
    SelectObject(hDesktopCompatibleDC,hDesktopCompatibleBitmap);
}
void Capture()
{
  BitBlt(hDesktopCompatibleDC,0,0,m_iWidth,m_iHeight,hDesktopDC,0,0,SRCCOPY);//сам захват
  
  memcpy(data,pBits,m_iWidth * m_iHeight * 4);//копируем данные из видео памяти в системную память
}


#1
3:29, 30 янв. 2010

bmpInfo.bmiHeader.biBitCount=32
bmpInfo.bmiHeader.biHeight=+GetSystemMetrics(SM_CYSCREEN);

#2
9:25, 30 янв. 2010

d.m.k
На скорость захвата не повлияет, так как это код инициализации, выполняется один раз.
lebron
Попробуй выставить для экрана не 1280х800х32, а 1280х800х24, ну и соответственно bmpInfo.bmiHeader.biBitCount=24.

#3
11:09, 30 янв. 2010

d.m.k
bmpInfo.bmiHeader.biHeight=-GetSystemMetrics(SM_CYSCREEN);
минус для того чтобы получать скриншот не перевернутый по вертикали
SergK
Если я ставлю 24 то скорость становиться 150 мс вместо 47, потому что  BitBlt конвертирует из 32 битт в 24 бита.

#4
11:18, 30 янв. 2010

lebron
BitBlt не будет работать быстрее чем идет копирование памяти.
1280*800*4 = 4 мегабайта

если я верно понимаю как битблит работает то он там как минимум 1 раз копипастит контент в HDC а потом ты memcpy делаешь. итого как минимум 2 раза. тоест где то 8 мегабайт. по логике вещей цифпа смешная.

ЗЫ GDI+ пробовал заюзать? он вроде как по возможности использует аппаратное ускорение.
ЗЗЫ вообще у меня была ситуация в игре ( года 4 назад ) когда BitBlt  из одного HDC 800х600  на экран 800х600 блитил за 1 миллисекунду.

оч рекомендую почитать Фень Юань "Программирование графики для Windows"


а так вроде у тебя все оптимально.

#5
11:23, 30 янв. 2010

lebron
Ну, можно еще попробовать создать CompatibleBitmap и сперва копировать в него, а уж потом копировать в DIBSection. Возможно с внеэкранным буфером чтонибудь да ускорится.

progman
> GDI+ пробовал заюзать? он вроде как по возможности использует аппаратное ускорение.
Оно вобще походу ничего не использует, безобразно медленное даже для очевидных вещей.

#6
11:32, 30 янв. 2010

progman
Да, ты прав, упирается все это именно в скорость копирования из видео памяти в системную.
Как с помошью GDI+ сделать скриншот экрана?
800x600 за одну мс потому что это было копирования и видео памяти в видео память.

#7
11:48, 30 янв. 2010

doc.
>Ну, можно еще попробовать создать CompatibleBitmap и сперва копировать в него, а уж потом копировать в DIBSection. Возможно с внеэкранным буфером >чтонибудь да ускорится.

Попробовал так, скорость таже :(

#8
13:35, 30 янв. 2010

Думаю эту проблему может решить

bmpInfo.bmiHeader.biCompression = BI_PNG;
или
bmpInfo.bmiHeader.biCompression = BI_JPEG;
но у меня получается черный экран в сохраненном изображении..
Подскажите, кто сталкивался?

#9
14:49, 30 янв. 2010

lebron
я под DX анимацию флешовую делал 100-120 фпс 640х480. и это был предел по фпс для такого разрешения. увеличивал размерность фпс тоолько пдала.
там было два действия - флеша рисовала в мой HDC, а уже из памяти этого HDC я копировал в залоченную текстуру IDirect3DTexture8*.

640х480*4 = 117,1875 мегабайт в секунду где то.
или примерно 2 метра в миллисекунду.

вот код:

int sx = MAXTEXTURE_WIDTH;
    int sy = MAXTEXTURE_HEIGHT;

    BITMAPINFO bi;  
    ZeroMemory(&bi, sizeof(bi));
    bi.bmiHeader.biSize      = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biCompression  = BI_RGB;
    bi.bmiHeader.biBitCount    = 32;
    bi.bmiHeader.biPlanes    = 1;
    bi.bmiHeader.biWidth    = sx;
    bi.bmiHeader.biHeight    = sy;
    bi.bmiHeader.biSizeImage  = sx * sy * 4;

    dc        = ::GetDC( m_hwndFlashPlayerControl );
    mem_bitmap_bg  = ::CreateDIBSection(dc, &bi, DIB_RGB_COLORS, (void**)&dest_buff, NULL, 0);
    dest_dc      = ::CreateCompatibleDC(dc);
    dest_obj    = ::SelectObject(dest_dc, mem_bitmap_bg);  

копирование:

RECTL aRect = {0, 0, d3dsd.Width, d3dsd.Height};
    HRGN aRgn = CreateRectRgn(invRect.left, invRect.top, invRect.right, invRect.bottom);
    SelectClipRgn(dest_dc, aRgn);
    DeleteObject(aRgn);

    g_pTexture->LockRect(0, &rcLockedRect, &rc, D3DLOCK_DISCARD);
    
    aViewObject->Draw(DVASPECT_CONTENT, 1, NULL, NULL, NULL, dest_dc, &aRect, &invRect, NULL, 0);    
    aViewObject->Release();
    

    int m_invwidth = invRect.right - invRect.left;
    int m_invhight = invRect.bottom - invRect.top;

    BYTE* m_sprptr =  (BYTE*)rcLockedRect.pBits;
    BYTE* m_dcptr  =  (BYTE*)dest_buff;

    int biSizeImage  = 4*d3dsd.Width;
    
    for(int y = int(d3dsd.Height-invRect.bottom); y < int(d3dsd.Height - invRect.top); y++)
    {
      BYTE* src_ptr  = &m_sprptr[ biSizeImage*(d3dsd.Height - y - 1 ) + 4*invRect.left ];
      BYTE* dest_ptr  = &m_dcptr[ biSizeImage* y + 4*invRect.left];
      memcpy( src_ptr, dest_ptr, 4*m_invwidth );
    }

    g_pTexture->UnlockRect(0);

#10
14:56, 30 янв. 2010

Но это ты копируеш в текстуру, мне же нужно в памяти системной получить эти данные.. я пробовал делать скриншот с помошью DX, копировал FrontBuffer а данные, но это занимало в 3 раза больше времени чем BitBlt в GDI

#11
15:10, 30 янв. 2010

>>я пробовал делать скриншот с помошью DX
подрубай DirectDraw и локай PrimarySurface, и будет тебе счастие в SYSMEM =)
тока он как то локается странно, к примеру если писать по залоканому указателю - результат сразу виден на экране
если ты сохраняеш картинку в файл то сразу кидай этот указатель куда надо - копировать не надо ничего )

#12
15:59, 30 янв. 2010

Asteraceae
А можно подробней.. как сделать PrimarySurface с помошью DDraw? если можно пример кода или исходник.

#13
16:50, 30 янв. 2010

lebron

#include <ddraw.h>

// инициализируем DiectDaw

    HRESULT ddrval;

    ddrval = DirectDrawCreate( NULL, &lpDD, NULL );
    if( ddrval != DD_OK )
    {
        return(false);
    }

    LPDIRECTDRAW lpDD;
    ddrval = lpDD->SetCooperativeLevel( hwnd, DDSCL_NORMAL );
    if( ddrval != DD_OK )
    {
        lpDD->Release();
        return(false);
    }


// создаем primary surface

    LPDIRECTDRAWSURFACE lpDDSPrimary;
    DDSURFACEDESC ddsd;

    memset( &ddsd, 0, sizeof(ddsd) );
    ddsd.dwSize = sizeof( ddsd );

    ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;

    ddrval = lpDD->CreateSurface( &ddsd, &lpDDSPrimary, NULL );
    if( ddrval != DD_OK )
    {
        lpDD->Release();
        return(false);
    }


// локаем сурфейс

    memset( &ddsd, 0, sizeof(ddsd) );
    ddsd.dwSize = sizeof( ddsd );

    ddrval = lpPrimarySurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
    if( ddrval != DD_OK ) return(false);

   // радуемся указателю ddsd.lpSurface, и размерам ddsd.dwWidth, ddsd.dwHeight, еще полезно потрогать ddsd.lPitch


// анлокаем сурфейс

    lpPrimarySurface->Unlock (ddsd.lpSurface);


// удаляем все не нужное

    lpPrimarySurface->Release();
    lpDD->Release();
хинты:
раз: http://www.citforum.ru/programming/cpp/directdraw.shtml
два: http://www.gamedev.net/reference/articles/article608.asp
возможно придется погуглить ddraw.lib и ddraw.h ибо они в DX8 SDK были
#14
17:23, 30 янв. 2010

Спасибо! Сделал так как ты привел пример, по времени Lock занимает 15 мс а memcpy из ddsd.lpSurface в свой указатель на память занимает теже 47 мс что и BitBlt в GDI.

Страницы: 1 2 Следующая »
ПрограммированиеФорумГрафика

Тема в архиве.