В настоящее время я разрабатываю небольшое приложение для скриншотов, которое записывает оба рабочего стола моего экрана в файл.
Я использую функцию GetFrontBufferData (), и она прекрасно работает.
К сожалению, при изменении глубины цвета экрана от 32 до 16 бит (для выполнения некоторых тестов) у меня плохое изображение (фиолетовое изображение с измененным разрешением), и записанный снимок экрана имеет очень низкое качество:
Кто-нибудь знает, есть ли способ использовать GetFrontBufferData () с 16-битным экраном?
редактировать:
Мой init Direct3D:
ZeroMemory(&d3dPresentationParameters,sizeof(D3DPRESENT_PARAMETERS));//Fills a block of memory with zeros.
d3dPresentationParameters.Windowed = TRUE;
d3dPresentationParameters.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dPresentationParameters.BackBufferFormat = d3dFormat;//d3dDisplayMode.Format;//D3DFMT_A8R8G8B8;
d3dPresentationParameters.BackBufferCount = 1;
d3dPresentationParameters.BackBufferHeight = gScreenRect.bottom = uiHeight;
d3dPresentationParameters.BackBufferWidth = gScreenRect.right = uiWidth;
d3dPresentationParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dPresentationParameters.MultiSampleQuality = 0;
d3dPresentationParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dPresentationParameters.hDeviceWindow = hWnd;
d3dPresentationParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
d3dPresentationParameters.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
Поток, который я использую для захвата скриншотов:
CreateOffscreenPlainSurface(uiWidth, uiHeight, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, pBackBuffer, NULL)) != D3D_OK )
{
DBG("Error: CreateOffscreenPlainSurface failed = 0x%x", iRes);
break;
}
GetFrontBufferData(0, pCaptureSurface)) != D3D_OK)
{
DBG("Error: GetFrontBufferData failed = 0x%x", iRes);
break;
}
//D3DXSaveSurfaceToFile("Desktop.bmp", D3DXIFF_BMP, pBackBuffer,NULL, NULL); //Test purposes
ZeroMemory(lockedRect, sizeof(D3DLOCKED_RECT));
LockRect(lockedRect, NULL, D3DLOCK_READONLY)) != D3D_OK )
{
DBG("Error: LockRect failed = 0x%x", iRes);
break;
}
if( (iRes = UnlockRect()) != D3D_OK )
{
DBG("Error: UnlockRect failed = 0x%x", iRes);
break;
}
/**/
edit2:
Я заметил следующее:
GetFrontBufferData
«Буфер, на который указывает pDestSurface
будет заполнено представлением переднего буфера, преобразованного в стандартный формат 32 бита на пиксель D3DFMT_A8R8G8B8
«. Я думаю, что это проблема для 16-битной глубины цвета.Что я здесь не так делаю? Я просто получаю черное изображение в моем файле Desktop N ° xx.bmp
Большое спасибо за Вашу помощь.
Вот как я создаю поверхность для захвата скриншотов:
IDirect3DSurface9* pCaptureSurface = NULL;
HRESULT hr = pD3DDevice->CreateOffscreenPlainSurface(
D3DPresentParams.BackBufferWidth,
D3DPresentParams.BackBufferHeight,
D3DPresentParams.BackBufferFormat,
D3DPOOL_SYSTEMMEM,
&pCaptureSurface,
NULL);
pD3DDevice->GetFrontBufferData(0, pCaptureSurface);
Если вы не хранили D3DPresentParams
где угодно, вы можете использовать IDirect3DDevice9::GetDisplayMode
чтобы получить ширину, высоту и формат вашей цепочки обмена. Все операции изменения размера и преобразования формата вы можете выполнить после захвата переднего буфера. Кроме того, как я знаю, формат отображения не поддерживает альфа-канал, поэтому обычно D3DFMT_X8R8G8B8
не D3DFMT_A8R8G8B8
,
Обновить:
На самом деле, вы пытаетесь захватить весь экран с помощью устройства d3d, ничего не рендерив. Цель d3d / opengl — создавать или обрабатывать образы и делать это с GPU-ускорением. Снимок экрана — это просто копирование некоторой видеопамяти, он не использует всю мощность графического процессора. Таким образом, использование любого API-интерфейса графического процессора не дает существенного преимущества. Более того, когда вы захватываете передний буфер, созданный не вами, происходят странные вещи. Чтобы расширить свое приложение, вы можете захватить изображение с помощью GDI, а затем загрузить его в текстуру и выполнить любую постобработку на графическом процессоре.
Так что я нашел несколько ответов на мою проблему.
1) Второй монитор не работал, и я не смог сделать снимок экрана с него в 16 битах
Это исходит от memcpy(..)
строка в коде. Потому что я работаю с 16-битным монитором, при выполнении memcpy
Поверхностная память повреждена, и это приводит к черному экрану.
Я до сих пор не нашел решения для этого, но я работаю над этим.
2) цвета скриншота неправильные
Это, без удивления, связано с глубиной цвета 16 бит. Потому что я использую GetFrontBufferData
и я цитирую Microsoft: Буфер, на который указывает pDestSurface
будет заполнено представлением переднего буфера, преобразованного в стандартный формат 32 бита на пиксель D3DFMT_A8R8G8B8
. Это означает, что если я хочу использовать данные пикселей из LockRect(...)
Я должен «преобразовать» мои данные в 16-битный режим. Поэтому мне нужно конвертировать мои данные pData из D3DFMT_A8R8G8B8
в D3DFMT_R5G6B5
что довольно просто.
3) Как отладить приложение?
Благодаря вашим комментариям мне сказали, что я должен проанализировать pScreeInfo->pData
содержание, когда я был в 16 битах (спасибо Niello). Поэтому я создал простой метод, используя необработанные данные из pScreeInfo->pData
и копирование в .bmp:
HRESULT hr;
DWORD dwBytesRead;
UINT uiSize = 1920 * 1080 * 4;
HANDLE hFile;
hFile = CreateFile(TEXT("data.raw"), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
BOOL bOk = ReadFile(hFile, pData, uiSize, &dwBytesRead, NULL);
if(!bOk)
exit(0);
pTexture = NULL;
hr = pScreenInfo->g_pD3DDevice->CreateTexture(width, height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &pTexture, NULL);
D3DLOCKED_RECT lockedRect;
hr = pTexture->LockRect(0, &lockedRect, NULL, D3DLOCK_READONLY);
memcpy(lockedRect.pBits, pData, lockedRect.Pitch * height);
hr = pTexture->UnlockRect(0);
hr = D3DXSaveTextureToFile(test, D3DXIFF_BMP, pTexture,NULL);
bOk = CloseHandle(hFile);
SAFE_RELEASE(pTexture);
Этот фрагмент кода позволил мне заметить, что данные pData были правильными, и в конце я смог получить хороший файл .bmp, что означает, что GetFrontBufferData(...)
правильно работал, и проблема исходит от memcpy(...)
4) Остальные проблемы
Я все еще пытаюсь узнать, как я могу решить проблему memcpy, чтобы увидеть, откуда возникла проблема. Это последняя проблема, так как цвета сейчас хороши (благодаря преобразованию 32 бит в 16 бит)
Спасибо всем за ваши полезные комментарии!