繁体   English   中英

具有16位颜色深度的C ++ Direct3D9 GetFrontBufferData

[英]C++ Direct3D9 GetFrontBufferData with 16 bits color Depth

我目前正在开发一个小的屏幕截图应用程序,该程序将屏幕的两个桌面都记录在一个文件中。 我正在使用GetFrontBufferData()函数,并且运行良好。

不幸的是,当将屏幕颜色深度从32位更改为16位(以执行一些测试)时,我的图像质量很差(分辨率更改后的紫色图像),并且录制的屏幕截图的质量很差:

在此处输入图片说明

有人知道是否可以通过16位屏幕使用GetFrontBufferData()吗?

编辑:

我的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;
    }   
/**/        
  • 此代码与32位色深完美配合,但不适用于16位。
  • 创建设备时,我为两个屏幕(iScreenNber)创建了2个设备。 它也以32位(不是16位)工作。
  • 当将捕获的屏幕截图保存到2个bmp文件中进行测试(以16位为单位)时,我有一个屏幕完美代表了主屏幕,另一个屏幕为黑色。
  • 当使用memcpy来使用pData时,上面的屏幕截图带有紫色和较差的分辨率

EDIT2:

我注意到以下内容:

  • 当将屏幕外表面保存到BMP文件时,我得到主显示(在1.bmp上),每帧刷新一次(因此工作正常)。 对于第二个显示器,我只得到第一帧,仅此而已。
  • 引用MSDN为GetFrontBufferData “缓冲指向pDestSurface将与前缓冲器的表示被填充,换算成每像素格式的标准32位D3DFMT_A8R8G8B8 ”。 我猜这是16位色深的问题。
  • 第一个问题来自不能正确处理16位色深的memcpy,我仍然不知道为什么---->为此需要帮助!
  • 第二个问题是第二个显示器不工作,我也不为什么

我在这里做错了什么? 我在我的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获取交换链的宽度,高度和格式。 捕获前缓冲区后可以执行的所有大小调整和格式转换操作。 另外,据我所知,显示格式不支持alpha通道,因此通常是D3DFMT_X8R8G8B8 ,而不是D3DFMT_A8R8G8B8

更新:实际上,您尝试使用d3d设备捕获整个屏幕,而不渲染任何内容。 d3d / opengl的目的是创建或处理图像,并进行GPU加速。 截屏只是复制一些视频内存,它并没有使用所有的GPU功能。 因此,使用任何GPU API都不会带来太大收益。 此外,您会看到,当捕获不是由您自己渲染的前端缓冲区时,就会发生奇怪的事情。 要扩展您的应用程序,您可以通过GDI捕获图像,然后将其加载到纹理中并进行任何GPU后处理。

所以我找到了解决我问题的答案。

1)第二个监视器无法正常工作,我无法从它捕获16位屏幕截图

这来自代码中的memcpy(..)行。 因为我使用的是16位监视器,所以在执行memcpy ,表面内存已损坏,这会导致黑屏。

我仍然没有找到解决方案,但我正在努力。

2)屏幕截图的颜色错误

毫无疑问,这归功于16位色深。 因为我使用的是GetFrontBufferData ,而且我引用的是Microsoft: pDestSurface指向的缓冲区将填充前缓冲区的表示形式,转换为标准的每像素32位D3DFMT_A8R8G8B8 这意味着,如果要使用LockRect(...)的像素数据,则必须将数据“重新转换”为16位模式。 因此,我需要将pData数据从D3DFMT_A8R8G8B8转换为D3DFMT_R5G6B5 ,这非常简单。

3)如何调试应用程序?

感谢您的评论,有人告诉我,当我使用16bit时,应该分析pScreeInfo->pData内容(这要感谢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位的转换)

谢谢大家的宝贵意见!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM