سؤال

I'm learning how to use Direct2D and DirectWrite. I wrote a sample application that uses these libraries to render content directly in the main (top-level) window. It works fine.

Now I'm trying to rewrite the painting code for a child window in another application. The original code uses GDI and works fine. But when I convert it to use Direct2D, nothing appears at all (the child window appears black).

I've simplified the painting code down to a simple fill of the client area.

LRESULT PlotWnd::OnPaint(UINT, WPARAM, LPARAM, BOOL &) {
    ATL::CComPtr<ID2D1Factory> pD2DFactory;
    HRESULT hr = ::D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
    assert(SUCCEEDED(hr));
    ATL::CComPtr<ID2D1HwndRenderTarget> pRT;
    RECT rc;
    GetClientRect(&rc);
    D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
    hr = pD2DFactory->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(/* D2D1_RENDER_TARGET_TYPE_SOFTWARE */),
        D2D1::HwndRenderTargetProperties(m_hWnd, size), &pRT);
    assert(SUCCEEDED(hr));

    pRT->BeginDraw();
    pRT->Clear(D2D1::ColorF(D2D1::ColorF::Beige));
    hr = pRT->EndDraw();
    assert(SUCCEEDED(hr));
    ValidateRect(nullptr);

    return 0;
}

All of the Direct2D calls succeed with S_OK, so I'm kind of at a loss as to where to look for the problem. At this point, the only significant difference I can see between my working experiment and this program is that in this one, I'm only using Direct2D in one child window.

So my questions are: Is there an issue that I'm missing when using Direct2D in a child window? Any tips for debugging this further?

Update: I've removed statics to avoid confusion. I'm completely setting up and tearing down Direct2D with each paint. There is exactly one paint call, with a real size.

If I switch to software rendering (by using D2D1_RENDER_TARGET_TYPE_SOFTWARE in the render target properties), the problem goes away--I get the beige fill as expected.

This led me to suspect my graphics driver, which was out of date. But I've now updated my graphics driver, and it still fails in the same manner. What else could cause hardware rendering to fail when software rendering works as expected?

Update 2: I'm still trying to reproduce this is a small, self-contained example. In the mean time, I noticed that simply starting Spy++ will sometimes cause the window to actually render to the screen (one time).

هل كانت مفيدة؟

المحلول 3

I still have no solution other than to use software rendering. I'm fairly certain it's a graphics driver bug, specifically, a race condition.

Evidence:

  • About one time in ten, it paints fine, so the problem is frequent but intermittent, suggestive of a timing issue.
  • The problem happens only with the first paint after launching the application. (Yes, the size of the window is correct at that point.) Later repaints work fine. Fortunately, my application repaints the window every few minutes, so it remains black only for a few minutes after you launch it. This suggests a timing issue on application start.
  • I haven't been able to reproduce with a tiny program, so the problem may be sensitive to the time necessary for the application to initialize. Perhaps the driver does some asynchronous initialization that doesn't always complete in time to handle the initial paint commands.
  • It hasn't happened on other computers I've tried that use different graphics cards.
  • When using software rendering, the painting works perfectly every time. This suggests that the bug isn't in my code.

Counter Evidence:

  • Several rounds of driver updates over the past year have not made any difference in the behavior.

I'm posting this as an "answer" because a few others have seen similar symptoms and asked me if I ever found an answer. I'm still open to reading other ideas and will upvote good answers.

نصائح أخرى

Well, for starters, you're supposed to create the factory at application start, and the render target with the window (HWND). Those are not supposed to be "temporary" objects that only live as long as your OnPaint (WM_PAINT) is executing.

In addition to Rick's recommendation to convert HWNDRenderTarget to the permanent object I suggest to call BeginPaint()-EndPaint() (or create a local CPaintDC object which does it automatically) even if you don't use the PAINTSTRUCT. See MainWindow::OnPaint here.

If this doesn't help you can always enable the Direct2D Debug Layer for more debugging info.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top