C ++ Direct3D9 GetFrontBufferData,16位颜色深度 [英] C++ Direct3D9 GetFrontBufferData with 16 bits color Depth

查看:431
本文介绍了C ++ Direct3D9 GetFrontBufferData,16位颜色深度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在开发一个小屏幕截图应用程序,将我的屏幕的桌面记录在一个文件中。不幸的是,当将屏幕颜色深度从32位改为16位时(执行一些测试),我们使用GetFrontBufferData()函数,它工作得很好。



< )我有一个坏的形象(改变分辨率的紫色图像),并且录制的屏幕截图质量很差:





有人知道是否有一个方法使用GetFrontBufferData



我的初始化direct3D:
ZeroMemory (& d3dPresentationParameters,sizeof(D3DPRESENT_PARAMETERS)); //用零填充一块内存。
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); //测试目的

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;
}
/ ** /




  • 代码完美地工作与32位颜色深度,但不是与16位。

  • 创建设备时,为两个屏幕(iScreenNber)创建2个设备。这也工作在32位(不是在16)。

  • 将捕获的屏幕截图保存为2个用于测试的bmp文件(16位)时,我有一个屏幕完全代表主显示屏,另一个屏幕是黑屏。

  • 当使用memcpy使用pData时,我有上面的屏幕截图紫色和差的解析



edit2:



我注意到以下内容:




    <离屏表面到BMP文件,我得到主显示器(在1.bmp上),每帧刷新(所以它工作正常)。对于第二个显示,我只是得到第一帧,然后没有更多。
  • 引用MSDN为 GetFrontBufferData pDestSurface 将以前缓冲区的表示形式填充,转换为每像素格式的标准32位 D3DFMT_A8R8G8B8

  • 第一个问题来自memcpy,它无法正确处理16位的颜色深度,我仍然在

  • 第二个问题是第二个显示不工作,我不知道为什么



我在这里做错了什么?我只是在我的桌面上得到一个黑色的图像N°xx.bmp文件



非常感谢您的帮助。

1)第二个监视器不工作,并且我没有工作,所以我找到一些答案我的问题。



这来自 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位转换)



感谢大家的有用的评论!


I am currently developing a little screenshot application which records both of my screen's desktop in a file. I am using the GetFrontBufferData() function and it is working great.

Unfortunately when changing the screen color depth from 32 to 16 bits (to perform some tests) I have a bad image (purple image with changed resolution) and the recorded screenshot has a very poor quality:

Does someone know if there is a way to use GetFrontBufferData() with a 16 bits screen ?

edit:

My 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;

The thread I use to capture screenshots:

    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;
    }   
/**/        

  • This code is perfectly working with 32 bits color depth but not with 16bits.
  • When creating the device I create 2 devices for both screens (iScreenNber). This is also working in 32bits (not in 16).
  • When saving the captured screenshot into 2 bmp files for testing (in 16 bits), I have one screen which represents the main display perfectly and the other screen is black.
  • When using memcpy to use pData, I have the above screenshot with purple color and bad resolution

edit2:

I noticed the following:

  • When saving Offscreen surface to a BMP file, I get the main display (on 1.bmp) which is refreshed each frame (so it is working just fine). For the second display, I just get the first frame then nothing more.
  • Quoting MSDN for GetFrontBufferData "The buffer pointed to by pDestSurface will be filled with a representation of the front buffer, converted to the standard 32 bits per pixel format D3DFMT_A8R8G8B8." I guess this is a problem for 16 bits color depth.
  • The first problem comes from the memcpy which does not handle properly the 16 bits color depth and I still don't know why ----> Help needed for this !!
  • Second problem is the second display which is not working and I don't why either

What am I doing wrong here ? I just get a black image on my Desktop N°xx.bmp file

Thank you very much for your help.

解决方案

So i found some answers to my problem.

1) Second monitor wasn't working and I was unable to capture screenshot from it in 16 bits

This comes from the memcpy(..) line in the code. Because I am working with a 16 bits monitor, when executing the memcpy, the surface memory is corrupt and this leads to a black screen.

I still didn't find the solution for this but I'm working on.

2) The colors of the screenshot are wrong

This is, without any surprise, due to the 16 bits color depth. Because I am using GetFrontBufferData, and I am quoting Microsoft: The buffer pointed to by pDestSurface will be filled with a representation of the front buffer, converted to the standard 32 bits per pixel format D3DFMT_A8R8G8B8. This means, if I want to use the pixel data from LockRect(...), I have to "re-convert" my data into 16 bits mode. Therefore, I need to convert my pData data from D3DFMT_A8R8G8B8 to D3DFMT_R5G6B5 which is pretty simple.

3) How to debug the application ?

Thanks to your comments, I've been told that I should analyze pScreeInfo->pData content when I was in 16bits (thanks to Niello). Therefore, I've created a simple method using raw data from pScreeInfo->pData and copying in a .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);

This piece of code allowed me to notice that pData data was correct and I could get a good .bmp file at the end which means that GetFrontBufferData(...) was correctly working and the problem comes from the memcpy(...)

4) Remaining problems

I am still trying to know how I can solve the memcpy issue to see where the problem comes from. This is the last problem since the colors are good now (thanks to the 32bits to 16 bits conversion)

Thank everybody for your helpful comments !

这篇关于C ++ Direct3D9 GetFrontBufferData,16位颜色深度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆