我在DirectX / C ++中实现自定义光标,该游标在桌面顶部的透明窗口上绘制。
我已将其剥离为basic example。在DWM上执行Direct3D的魔力基于此article on Code Project
问题在于,当使用非常大的窗口(例如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 Dirty区域信息来告诉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);
但这是我不明白的事情。如果我添加以下
,它将只提供1%的GPU负载 SetLayeredWindowAttributes(hWnd, 0, 180, LWA_ALPHA);
我还是希望它透明,所以它很好,但过了一段时间我会得到一些奇怪的撕裂效果。我移动光标的速度越快越明显。那是什么来的?它看起来像提供的图像。我确信我已经完全准确地设置了脏物。
上述撕裂似乎因计算机而异。