如何在本机桌面 Windows 应用程序中使用 Direct2D 呈现 child window?
How to render child window with Direct2D in native desktop Windows application?
我有一个桌面应用程序,其中所有 windows (HWND) 使用 Direct2D 1.1 呈现自身。我的问题是 如何更正确地做到这一点?
是否每个 window 都有自己的来自一个 Direct2D 设备的 Direct2D 设备上下文?在这种情况下,我无法在没有额外技巧的情况下在 child window 上呈现 transparent 内容(我必须在 parent window 的上下文中更改目标,将 parent window 渲染到 Direct2D 位图,然后在 child 的目标上绘制此位图。
也许拥有一个 Direct2D 设备上下文会更好,所有 windows 都在其中呈现自身?我相信 DirectComposition 以类似的方式工作。不幸的是,我无法使用它,因为我的目标是 Windows 7.
您提出的问题的答案非常 与应用程序相关。我建议避免尝试让 HWND 以相互透明的方式呈现的整个问题,尤其是当您将 Direct2D 混入其中时。在那个方向上有太多的痛苦。您支持的 Windows 的每个版本都会有不同的错误,您会不断遇到这些错误并找到解决方法。
例证:对于 Paint.NET 的 v4.0 版本,我将所有文本呈现转换为 DirectWrite,并且几乎所有 UI 控件都使用 Direct2D。 window(MDI 选择器)顶部的图像缩略图控件使用 Direct2D 进行渲染,但它还必须在其后面的内容之上进行合成。而且它必须在 Win7 上与玻璃兼容(虽然它看起来很棒!)。这方面的代码很糟糕、棘手、几乎无法维护,而且似乎在 Windows 的每个版本中都会遇到不同的渲染错误:7、7 SP1、8、8.1 和 10 的行为都略有不同!测试也很烦人;这是我必须为我支持的每个 Windows 版本设置和维护 VM 的唯一原因(安装程序和更新程序除外)。 Windows 7 工作正常,然后 7 SP1 添加了一个错误,需要对我填充 alpha 通道的方式进行一些调整。 Windows 调整 window 大小时,8 会闪烁,除非我做了一些修改,但 8.1 工作正常。如果使用软件渲染,10 就会有自己的闪烁错误。远程桌面以自己的方式打破了一切。然后你还得担心High Contrast,如果支持的话DWM是不是enabled/disabledWindows 7.它们的表现都不一样,真的很痛苦。
无论如何。您似乎真正需要的是像 WPF 或 XAML 这样的 UI 系统,它只使用顶级 HWND 容器。到那时,您将自定义渲染所有内容并进行自己的命中测试和输入路由(以及可访问性和各种其他事情),所以这不是一项小任务。
关于设备和设备上下文的 "how to do it more correctly" 问题和基数:您是否考虑过只使用 ID2D1Factory::CreateHWNDRenderTarget
或 ID2D1Factory::CreateDCRenderTarget
?它们 return ID2D1RenderTarget
但您可以调用 QueryInterface
将它们转换为 ID2D1DeviceContext
(文档中缺少这一事实,但显然也是有意的)。这应该可以大大简化 Direct2D 和 HWND 的使用。这就是我在 Paint.NET 中所做的:我仍然为每个控件使用一个 HWND,但是每个控件都使用它自己的 HWND 或 DC 渲染目标。如果您愿意使用 Reflector 或 ILSpy,请查看 Paint.NET DLL 中的 Direct2DControl
和 Direct2DControlHandler
。
另外,使用超过 1 个硬件加速 HWND 渲染目标时要小心。您不想进入每个基于 Direct2D UI 控件都在等待 VSync 的奇怪区域。在创建 HWND 渲染目标时使用 D2D1_PRESENT_OPTIONS_IMMEDIATELY
应该会有所帮助。 DWM 已经处理了 VSync,所以你应该告诉 Direct2D 忽略它,除非你正在用动画和计时器做一些相当具体的事情。
我有一个桌面应用程序,其中所有 windows (HWND) 使用 Direct2D 1.1 呈现自身。我的问题是 如何更正确地做到这一点?
是否每个 window 都有自己的来自一个 Direct2D 设备的 Direct2D 设备上下文?在这种情况下,我无法在没有额外技巧的情况下在 child window 上呈现 transparent 内容(我必须在 parent window 的上下文中更改目标,将 parent window 渲染到 Direct2D 位图,然后在 child 的目标上绘制此位图。
也许拥有一个 Direct2D 设备上下文会更好,所有 windows 都在其中呈现自身?我相信 DirectComposition 以类似的方式工作。不幸的是,我无法使用它,因为我的目标是 Windows 7.
您提出的问题的答案非常 与应用程序相关。我建议避免尝试让 HWND 以相互透明的方式呈现的整个问题,尤其是当您将 Direct2D 混入其中时。在那个方向上有太多的痛苦。您支持的 Windows 的每个版本都会有不同的错误,您会不断遇到这些错误并找到解决方法。
例证:对于 Paint.NET 的 v4.0 版本,我将所有文本呈现转换为 DirectWrite,并且几乎所有 UI 控件都使用 Direct2D。 window(MDI 选择器)顶部的图像缩略图控件使用 Direct2D 进行渲染,但它还必须在其后面的内容之上进行合成。而且它必须在 Win7 上与玻璃兼容(虽然它看起来很棒!)。这方面的代码很糟糕、棘手、几乎无法维护,而且似乎在 Windows 的每个版本中都会遇到不同的渲染错误:7、7 SP1、8、8.1 和 10 的行为都略有不同!测试也很烦人;这是我必须为我支持的每个 Windows 版本设置和维护 VM 的唯一原因(安装程序和更新程序除外)。 Windows 7 工作正常,然后 7 SP1 添加了一个错误,需要对我填充 alpha 通道的方式进行一些调整。 Windows 调整 window 大小时,8 会闪烁,除非我做了一些修改,但 8.1 工作正常。如果使用软件渲染,10 就会有自己的闪烁错误。远程桌面以自己的方式打破了一切。然后你还得担心High Contrast,如果支持的话DWM是不是enabled/disabledWindows 7.它们的表现都不一样,真的很痛苦。
无论如何。您似乎真正需要的是像 WPF 或 XAML 这样的 UI 系统,它只使用顶级 HWND 容器。到那时,您将自定义渲染所有内容并进行自己的命中测试和输入路由(以及可访问性和各种其他事情),所以这不是一项小任务。
关于设备和设备上下文的 "how to do it more correctly" 问题和基数:您是否考虑过只使用 ID2D1Factory::CreateHWNDRenderTarget
或 ID2D1Factory::CreateDCRenderTarget
?它们 return ID2D1RenderTarget
但您可以调用 QueryInterface
将它们转换为 ID2D1DeviceContext
(文档中缺少这一事实,但显然也是有意的)。这应该可以大大简化 Direct2D 和 HWND 的使用。这就是我在 Paint.NET 中所做的:我仍然为每个控件使用一个 HWND,但是每个控件都使用它自己的 HWND 或 DC 渲染目标。如果您愿意使用 Reflector 或 ILSpy,请查看 Paint.NET DLL 中的 Direct2DControl
和 Direct2DControlHandler
。
另外,使用超过 1 个硬件加速 HWND 渲染目标时要小心。您不想进入每个基于 Direct2D UI 控件都在等待 VSync 的奇怪区域。在创建 HWND 渲染目标时使用 D2D1_PRESENT_OPTIONS_IMMEDIATELY
应该会有所帮助。 DWM 已经处理了 VSync,所以你应该告诉 Direct2D 忽略它,除非你正在用动画和计时器做一些相当具体的事情。