0

I'm implementing a custom cursor in DirectX/C++ that is drawn on a transparent window on top of the desktop.

I have stripped it down to a basic example. The magic of executing Direct3D on the DWM is based on this article on Code Project

The problem is that when using a very big window (e.g. 2560x1440) as a base for the DirectX rendering, it will give up to 40% GPU Load according to GPU-Z. Even if the only thing I am displaying is a static 128x128 sprite, or nothing at all. If I use an area like 256x256, the GPU Load is around 1-3%.

Basically this loop would make the GPU go crazy on a big window while it's smooth sailing on a small window:

while(true) {
    g_pD3DDevice->PresentEx(NULL, NULL, NULL, NULL, NULL);
    Sleep(10);
}

So it seems like it re-renders the whole screen whether anything changes or not, am I right? Can I tell Direct3D to only re-render specific parts that needs to be updated?

EDIT: I have found a way to tell Direct3D to render a specific part by providing RGNDATA Dirty region information to PresentEx. It is now 1% GPU Load instead of 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);

But it's something I do not understand. It will only give 1% GPU Load if I add the following

    SetLayeredWindowAttributes(hWnd, 0, 180, LWA_ALPHA);

I want it transparent anyway so it's good, but instead I get some weird tearing effects after a while. It is more noticeable the faster I move the cursor. What does that come from? It looks like image provided. I am sure I have set the dirty rects perfectly accurate.

tearing

The above tearing seem to differ from computer to computer.

Simphax
  • 35
  • 8
  • Set the scissor area and enable ScissorTest. – Brandon Aug 07 '14 at 23:32
  • @Brandon I got it to render only the specified scissor area but it will still give the same amount of GPU Load "/ – Simphax Aug 08 '14 at 00:07
  • What happens if you remove the WS_EX_COMPOSITED style? The fact that you don't have a message loop is suspicious, you might want try adding one. – Ross Ridge Aug 08 '14 at 06:21
  • @RossRidge Removing WS_EX_COMPOSITED makes the d3d content disappear but the GPU load still the same. Adding a message loop made no difference – Simphax Aug 09 '14 at 23:11

0 Answers0