Debugging Direct2D在主窗口中渲染,但不在子窗口中渲染

Debugging Direct2D在主窗口中渲染,但不在子窗口中渲染,debugging,winapi,direct2d,Debugging,Winapi,Direct2d,我正在学习如何使用Direct2D和DirectWrite。我编写了一个示例应用程序,它使用这些库直接在主(顶级)窗口中呈现内容。它很好用 现在我正试图在另一个应用程序中重写子窗口的绘制代码。原始代码使用GDI,工作正常。但是当我将其转换为使用Direct2D时,什么也没有显示(子窗口显示为黑色) 我已经将绘制代码简化为对客户端区域的简单填充 LRESULT PlotWnd::OnPaint(UINT, WPARAM, LPARAM, BOOL &) { ATL::CComPtr

我正在学习如何使用Direct2D和DirectWrite。我编写了一个示例应用程序,它使用这些库直接在主(顶级)窗口中呈现内容。它很好用

现在我正试图在另一个应用程序中重写子窗口的绘制代码。原始代码使用GDI,工作正常。但是当我将其转换为使用Direct2D时,什么也没有显示(子窗口显示为黑色)

我已经将绘制代码简化为对客户端区域的简单填充

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;
}
LRESULT PlotWnd::OnPaint(UINT、WPARAM、LPARAM、BOOL&){
ATL::CComPtr pD2DFactory;
HRESULT hr=::D2D1CreateFactory(D2D1工厂类型单线程和pD2DFactory);
断言(成功(hr));
ATL::CComPtr pRT;
RECT-rc;
GetClientRect&rc;
D2D1_SIZE_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,大小)和pRT);
断言(成功(hr));
pRT->BeginDraw();
pRT->Clear(D2D1::ColorF(D2D1::ColorF::米色));
hr=pRT->EndDraw();
断言(成功(hr));
验证(nullptr);
返回0;
}
所有Direct2D调用都通过
S_OK
成功,因此我有点不知所措,不知从何处查找问题。在这一点上,我能看到的工作实验和这个程序之间的唯一显著区别是,在这个实验中,我只在一个子窗口中使用Direct2D

所以我的问题是:在子窗口中使用Direct2D时,是否有我遗漏的问题?有没有进一步调试的技巧

更新:为了避免混淆,我删除了静态。我正在用每种颜料完全设置和拆除Direct2D。只有一个油漆调用,具有真实尺寸

如果我切换到软件渲染(通过在渲染目标属性中使用
D2D1_RENDER_TARGET_TYPE_software
),问题就会消失——我得到了预期的米色填充

这让我怀疑我的图形驱动程序已经过时了。但是我现在已经更新了我的图形驱动程序,它仍然以同样的方式失败。当软件渲染按预期工作时,还有什么会导致硬件渲染失败


更新2:我仍在尝试重现这是一个小的、独立的示例。同时,我注意到,简单地启动Spy++有时会导致窗口实际渲染到屏幕上(一次)。

对于初学者,您应该在应用程序启动时创建工厂,并使用窗口(HWND)创建渲染目标。这些不应该是“临时”对象,它们只在OnPaint(WM_PAINT)执行时存在。

除了Rick建议将HwnRenderTarget转换为永久对象之外,我建议调用(或创建一个自动执行的本地对象),即使您不使用
PAINTSTRUCT
。请参见
main窗口::OnPaint


如果这没有帮助,您可以始终启用以获取更多调试信息。

除了使用软件渲染,我仍然没有其他解决方案。我相当肯定这是一个图形驱动程序错误,特别是一个比赛条件

证据:

  • 大约十分之一的时间,它的画质很好,所以这个问题经常出现,但断断续续,暗示着时间问题
  • 问题只会在启动应用程序后的第一个油漆上发生。(是的,此时窗口的大小正确。)稍后重新绘制效果良好。幸运的是,我的应用程序每隔几分钟重新绘制一次窗口,因此在启动它之后,它只会在几分钟内保持黑色。这表明应用程序启动时存在时间问题
  • 我无法用一个小程序进行复制,因此问题可能对应用程序初始化所需的时间很敏感。也许驱动程序执行了一些异步初始化,但这些初始化并不总是及时完成以处理初始绘制命令
  • 这在我尝试过的其他使用不同图形卡的计算机上没有发生过
  • 使用软件渲染时,每次都能完美地进行绘制。这表明错误不在我的代码中
反证据:

  • 在过去的一年中,几轮驱动程序更新并没有对行为产生任何影响

我将此作为一个“答案”发布,因为其他一些人也看到了类似的症状,并问我是否找到了答案。我仍然愿意阅读其他观点,并会给出好的答案。

您是否覆盖了
WM_ERASKBKGND
处理程序,这样它就不会一直关闭您的窗口?@Roger Rowland:是的,我的WM_ERASKBKGND处理程序什么都不做。如果我用任意颜色填充它,那么我看到的是那种颜色,而不是Direct2D Clear命令所期望的米色填充。好的,只是运行一些“明显”的东西-父窗口是否有
WS_CLIPCHILDREN
样式集?是的,两个祖先都有WS_CLIPCHILDREN(用Spy++确认)。您是否验证了
OnPaint
第一次使用非零大小调用?只是认为调用您的
GetClientRect
可能太早了(例如,如果您使用虚拟大小创建,然后移动/调整子窗口的大小)。这就是我最初开始的方式,但当它不起作用时,我将代码简化为这样,以便能够在一个位置显示所有内容。如果我按需创建这些对象,应该没有什么区别,特别是因为只调用了一次绘制处理程序。事实上,在WM_PAINT handler中完成这一切在我构建的原始示例中效果很好(我使用Direct2D绘制主窗口)。如果发布HwnRenderTarget导致绘制问题,我不会感到惊讶。引用自:您的应用程序应该创建一次渲染目标,并在应用程序的生命周期中保持它们