如何在大窗口(DWM)上直接渲染Direct3D/C++的小精灵?

如何在大窗口(DWM)上直接渲染Direct3D/C++的小精灵?,c++,directx,direct3d,directx-9,dwm,C++,Directx,Direct3d,Directx 9,Dwm,我正在DirectX/C++中实现一个自定义光标,它绘制在桌面顶部的透明窗口上 我已经把它精简到一个新的层次。在DWM上执行Direct3D的神奇之处就在于此 问题是,当使用一个非常大的窗口(例如2560x1440)作为DirectX渲染的基础时,根据GPU-Z,它将放弃高达40%的GPU负载。即使我只显示一个静态128x128精灵,或者什么都没有。如果我使用256x256这样的区域,GPU负载大约为1-3% 基本上,这个循环会让GPU在大窗口上疯狂,而在小窗口上却一帆风顺: while(tru

我正在DirectX/C++中实现一个自定义光标,它绘制在桌面顶部的透明窗口上

我已经把它精简到一个新的层次。在DWM上执行Direct3D的神奇之处就在于此

问题是,当使用一个非常大的窗口(例如2560x1440)作为DirectX渲染的基础时,根据GPU-Z,它将放弃高达40%的GPU负载。即使我只显示一个静态128x128精灵,或者什么都没有。如果我使用256x256这样的区域,GPU负载大约为1-3%

基本上,这个循环会让GPU在大窗口上疯狂,而在小窗口上却一帆风顺:

while(true) {
    g_pD3DDevice->PresentEx(NULL, NULL, NULL, NULL, NULL);
    Sleep(10);
}
所以它似乎重新呈现了整个屏幕,无论是否有任何变化,对吗?我可以告诉Direct3D只重新渲染需要更新的特定零件吗

编辑: 我找到了一种方法,通过向PresentEx提供RGNDATA脏区域信息,告诉Direct3D渲染特定零件。它现在是1%的GPU负载,而不是20-40%

    std::vector<RECT> dirtyRects;

    //Fill dirtyRects with previous and new cursor boundaries

    DWORD size = dirtyRects.size() * sizeof(RECT)+sizeof(RGNDATAHEADER);

    RGNDATA *rgndata = NULL;

    rgndata = (RGNDATA *)HeapAlloc(GetProcessHeap(), 0, size);


    RECT* pRectInitial = (RECT*)rgndata->Buffer;
    RECT rectBounding = dirtyRects[0];

    for (int i = 0; i < dirtyRects.size(); i++)
    {
        RECT rectCurrent = dirtyRects[i];
        rectBounding.left = min(rectBounding.left, rectCurrent.left);
        rectBounding.right = max(rectBounding.right, rectCurrent.right);
        rectBounding.top = min(rectBounding.top, rectCurrent.top);
        rectBounding.bottom = max(rectBounding.bottom, rectCurrent.bottom);

        *pRectInitial = dirtyRects[i];
        pRectInitial++;
    }

    //preparing rgndata header
    RGNDATAHEADER  header;
    header.dwSize = sizeof(RGNDATAHEADER);
    header.iType = RDH_RECTANGLES;
    header.nCount = dirtyRects.size();
    header.nRgnSize = dirtyRects.size() * sizeof(RECT);
    header.rcBound.left = rectBounding.left;
    header.rcBound.top = rectBounding.top;
    header.rcBound.right = rectBounding.right;
    header.rcBound.bottom = rectBounding.bottom;

    rgndata->rdh = header;

    // Update display
    g_pD3DDevice->PresentEx(NULL, NULL, NULL, rgndata, 0);
我希望它是透明的,所以它是好的,但我得到一些奇怪的撕裂效果后,一段时间。我移动光标的速度越快,它就越明显。那是怎么来的?看起来像是提供了图像。我确信我已将脏矩形设置得非常准确


上述撕裂似乎因计算机而异。

设置剪刀区域并启用剪刀测试。@Brandon我让它只渲染指定的剪刀区域,但它仍会提供相同数量的GPU负载/如果删除WS_EX_合成样式会发生什么?您没有消息循环的事实是可疑的,您可能希望尝试添加一个。@RossRidge删除WS_EX_COMPOSITED会使d3d内容消失,但GPU负载仍然相同。添加消息循环没有任何区别
    SetLayeredWindowAttributes(hWnd, 0, 180, LWA_ALPHA);