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

问题描述 投票:0回答:4

我正在学习如何使用 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;
}

所有 Direct2D 调用都成功,并显示

S_OK
,所以我有点不知道在哪里寻找问题。此时,我可以看到我的工作实验与该程序之间唯一显着的区别是,在这个实验中,我仅在一个子窗口中使用 Direct2D。

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

更新:我删除了静态以避免混淆。我在每次绘制时都完全设置和拆除 Direct2D。恰好有一个油漆调用,具有真实尺寸。

如果我切换到软件渲染(通过在渲染目标属性中使用

D2D1_RENDER_TARGET_TYPE_SOFTWARE
),问题就会消失——我会按预期得到米色填充。

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

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

debugging winapi direct2d
4个回答
2
投票

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


0
投票

除了 Rick 建议将 HWNDRenderTarget 转换为永久对象之外,我建议调用

BeginPaint()
-
EndPaint()
(或创建一个自动执行此操作的本地
CPaintDC
对象),即使您不这样做使用
PAINTSTRUCT
。请参阅
MainWindow::OnPaint
此处

如果这没有帮助,您可以随时启用 Direct2D 调试层 以获取更多调试信息。


0
投票

除了使用软件渲染我还是没有办法。我相当确定这是一个图形驱动程序错误,特别是竞争条件。

证据:

  • 大约十分之一的情况下,它画得很好,因此问题是频繁但间歇性的,表明存在时序问题。
  • 该问题仅发生在启动应用程序后第一次绘制时。 (是的,此时窗口的大小是正确的。)稍后的重新绘制工作正常。幸运的是,我的应用程序每隔几分钟重新绘制窗口,因此在启动它后它仅在几分钟内保持黑色。这表明应用程序启动时存在计时问题。
  • 我无法使用小程序进行重现,因此问题可能对应用程序初始化所需的时间敏感。也许驱动程序会执行一些异步初始化,但这些初始化并不总是及时完成以处理初始绘制命令。
  • 在我尝试过的使用不同显卡的其他计算机上没有发生这种情况。
  • 使用软件渲染时,绘画效果每次都很完美。这表明该错误不在我的代码中。

反证:

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

我将其发布为“答案”,因为其他一些人也看到了类似的症状并问我是否找到了答案。我仍然愿意阅读其他想法,并会投票赞成好的答案。


0
投票

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

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*/
}

}
© www.soinside.com 2019 - 2024. All rights reserved.