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

fcwjkofz  于 2023-10-24  发布在  其他
关注(0)|答案(4)|浏览(115)

我正在学习如何使用Direct 2D和DirectWrite。我写了一个示例应用程序,它使用这些库直接在主(顶级)窗口中呈现内容。它工作得很好。
现在我尝试在另一个应用程序中重写子窗口的绘画代码。原始代码使用GDI并且工作正常。但是当我将其转换为使用Direct 2D时,什么也没有出现(子窗口显示为黑色)。
我已经将绘制代码简化为简单地填充客户区。

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;
}

所有的Direct 2D调用都成功地使用了S_OK,所以我有点不知所措,不知道该在哪里寻找问题。在这一点上,我能看到的唯一显着差异,我的工作实验和这个程序之间的是,在这个程序中,我只在一个子窗口中使用Direct 2D。
所以我的问题是:在子窗口中使用Direct 2D时,是否有我遗漏的问题?有什么进一步调试的提示吗?

**更新:**为了避免混淆,我已经删除了静态。我完全设置并拆除了每个绘制的Direct 2D。只有一个绘制调用,具有真实的大小。

如果我切换到软件渲染(通过在渲染目标属性中使用D2D1_RENDER_TARGET_TYPE_SOFTWARE),问题就消失了--我得到了预期的米色填充。
这让我怀疑我的显卡驱动程序已经过时了。但是我现在已经更新了我的显卡驱动程序,它仍然以同样的方式失败。还有什么会导致硬件渲染失败,而软件渲染却能正常工作?

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

p1tboqfb

p1tboqfb1#

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

pdsfdshx

pdsfdshx2#

除了Rick建议将HWNDRenderTarget转换为永久对象之外,我建议调用BeginPaint()-EndPaint()(或创建一个本地CPaintDC对象,它会自动执行此操作),即使您不使用PAINTSTRUCT。参见MainWindow::OnPainthere
如果这没有帮助,您可以始终启用Direct2D Debug Layer以获取更多调试信息。

31moq8wy

31moq8wy3#

除了使用软件渲染之外,我仍然没有解决方案。我相当肯定这是一个图形驱动程序错误,具体来说,是一个竞争条件。
证据:

  • 大约十分之一的时间,它画得很好,所以这个问题是频繁的,但间歇性的,暗示了一个时间问题。
  • 这个问题只发生在启动应用程序后的第一次绘制。(是的,窗口的大小在那一点上是正确的。)后来重新绘制工作正常。幸运的是,我的应用程序每隔几分钟重新绘制一次窗口,所以它只在你启动它后的几分钟内保持黑色。这表明应用程序启动时存在计时问题。
  • 我还没能用一个小程序来重现这个问题,所以这个问题可能是对应用程序初始化所需的时间很敏感,也许驱动程序做了一些异步初始化,这些初始化并不总是及时完成来处理初始的绘制命令。
  • 它还没有发生在其他计算机上,我已经尝试使用不同的图形卡。
  • 当使用软件渲染时,绘画每次都能完美地工作。这表明错误不在我的代码中。

反证:

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

我把这篇文章作为一个“答案”贴出来,因为其他一些人也看到了类似的症状,问我是否找到了答案。我仍然愿意阅读其他的想法,并会支持好的答案。

z31licg0

z31licg04#

我建议使用相同的工厂和像素格式为你的子窗口或其他[共享]资源创建渲染目标。

ID2D1HwndRenderTarget *hwnd_tgt_main = nullptr;
ID2D1HwndRenderTarget *hwnd_tgt_child = nullptr;

HWND app_hwnd = nullptr;
HWND child_hwnd = nullptr;

D2D1_RENDER_TARGET_PROPERTIES my_goto_render_props = D2D1::RenderTargetProperty();

// render targets and bitmaps and other resources inherit from ID2D1Resource

static bool Create_HWND_Render_Tgt
(
HWND arg_hwnd, 
ID2D1Resource *arg_resource, 
ID2D1HwndRenderTarget **pp_hwnd_tgt, 
ID2D1_SIZE_U *arg_size_overide = nullptr,
D2D1_PRESENT_OPTIONS_NONE arg_pres_opt = D2D1_PRESENT_OPTIONS_NONE,
D2D1_RENDER_TARGET_PROPERTIES *arg_render_props = &my_goto_render_props
) 
{

bool func_msg_debug = true;
bool func_msg_success = false;

HRESULT hr = S_OK;

// scoped to this function
CComPtr<ID2D1Factory> ccptr_d2d_factory = nullptr; // = nullptr is not necessary

if (arg_resource)
{

hr = arg_resource->GetFactory(&ccptr_d2d_factory);

if (func_msg_debug) { /* using the same d2d factory...*/ }

}
else
{

hr = D2D1CreateFactory(&ccptr_d2d_factory);

if (func_msg_debug) { /* creating a new d2d factory... */ }

}

if (FAILED(hr)) 
{ 

if (fung_msg_bedug) { /* hr error message */ } 

return false;

}

// ommit this line if pp_hwnd_tgt is an external com ptr. releasing com ptrs throws errors
SafeRelease(pp_hwnd_tgt); 

// Resolve the hwnd render target properties here
D2D1_SIZE_U                        local_size = { 512, 512 }; // 512x512x4 = 1MB
D2D1_HWND_RENDER_TARGET_PROPERTIES local_hwnd_props;
D2D1_RENDER_TARGET_PROPERTIES      local_render_props = D2D1::RenderTargetPropeties();

local_hwnd_props.hwnd = arg_hwnd;
local_hwnd_props.pixelSize = local_size;
loacl_hwnd_props.presentOptions = arg_pres_opt;
if (arg_size_overide) { local_hwnd_props.pixelSize = *arg_size_overide; }

if (arg_props) { local_render_props = *arg_props; }

hr = ccptr_d2d_factory->CreateHwndRenderTarget
(
&local_hwnd_props,
&local_render_props, 
pp_hwnd_tgt
);

if (FAILED(hr)) 
{

if (fung_msg_bedug) { /* hr error message */ }

return false;
 
}

if (func_msg_success) { /* SUCCESS message */ }

return true;

} // all CComPtrs defined within this function go out of scope and are automatically released 

void Init(HWND arg_hwnd)
{
 

if (!Create_HWND_Render_Tgt(arg_hwnd, nullptr, &hwnd_tgt_main))
{
 /* error message*/

 // end the app
}

app_hwnd = arg_hwnd;

// Create the child hwnd

// use the same factory from the main window's render target to create the new render tgt

if (!Create_HWND_Render_Tgt(child_hwnd, hwnd_tgt_main, &hwnd_tgt_child))
{
/*error message*/
}

}

相关问题