GDI versus Direct2D
GDI versus Direct2D
我目前正在编程模拟,我想将应用程序从使用GDI移植到使用Direct2D。但是我的Direct2D代码比我的GDI代码慢得多。
我在屏幕上渲染了很多椭圆。在我的GDI应用程序中,我绘制到存储设备上下文中,然后使用BITBLT在Windows设备上下文上绘制。使用Direct2D,我将其绘制到ID2D1HWNDRENDERTARGET上。
我的问题是,当使用GDI时,我可以轻松绘制400多个椭圆形,并且仍然有400 fps。当我使用Direct2D进行相同数量的椭圆时,我的FPS下降到30fps。
我已经关闭了抗血液,但这并没有真正的帮助。有趣的是,与GDI相比,Direct2D仅绘制几个椭圆的速度更快。我可以做些什么来提高Direct2D的性能,还是应该使用GDI保留应用程序?
这是我使用GDI的绘图代码:
VOID Begin() {
SelectObject(this->MemDeviceContext, this->MemoryBitmap);
this->BackgroundBrush = CreateSolidBrush(this->BackgroundColor);
HBRUSH OldBrush = (HBRUSH)SelectObject(this->MemDeviceContext, this->BackgroundBrush);
Rectangle(this->MemDeviceContext, -1, -1, 801, 601);
SelectObject(this->MemDeviceContext, OldBrush);
DeleteObject(this->BackgroundBrush);
SetViewportOrgEx(this->MemDeviceContext, 400, 300, &this->OldOrigin);
}
VOID End() {
SetViewportOrgEx(this->MemDeviceContext, this->OldOrigin.x, this->OldOrigin.y, 0);
BitBlt(this->DeviceContext, 0, 0, 800, 600, this->MemDeviceContext, 0, 0, SRCCOPY);
}
在我的开始功能和结束功能之间,我绘制椭圆形的标准GDI方式。
这是我使用Direct2D的开始和结束功能:
VOID BeginDrawing() {
this->RenderTarget->BeginDraw();
RenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::CornflowerBlue));
RenderTarget->SetTransform(this->ScalingMatrix * this->TranslateMatrix);
}
VOID EndDrawing() {
this->RenderTarget->EndDraw();
}
这是我设置Direct2D接口的方式。这一切都包裹在课堂上;这就是为什么我不能发布完整代码:
if(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &Direct2DFactory) != S_OK)
throw std::runtime_error("RENDERWINDOW::InitializeDirect2D: Failed to create a factory interface.");
RECT WindowRect;
memset(&WindowRect, 0, sizeof(RECT));
GetClientRect(this->WndHandle, &WindowRect);
D2D1_SIZE_U WindowSize = D2D1::SizeU(WindowRect.right, WindowRect.bottom);
Direct2DFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_HARDWARE),
D2D1::HwndRenderTargetProperties(this->WndHandle, WindowSize, D2D1_PRESENT_OPTIONS_IMMEDIATELY), &RenderTarget);
预先感谢您。
direct2D首次尝试的常见错误是开发人员没有正确地缓存D2D资源,而是创建和破坏资源太频繁。如果您的所有椭圆都相似,则应创建和缓存此椭圆对象一次。如果您有30种不同的尺寸/形状,请仅一次为所有30个尺寸/形状创建椭圆版本。这大大加速了Direct2D。矩形和所有其他原语的也是如此。如果存在太多的变化,则缩放缓存的对象与重复创建/破坏也是某些情况的解决方案,尽管对于原始构图,但使用本机大小的资源是理想的,并且存储卡具有很多存储器来存储您的资源。
gdi椭圆形看起来绝对可怕,直接使用Direct3D非常复杂,尤其是对于椭圆,大多边形和更高级别的原语。通过适当使用Direct2D,您应该能够获得良好的速度和高质量的渲染。
我拒绝了从GDI迁移渲染代码Direct2D由于性能低。我从Google了解到,Direct2D性能取决于驱动程序和硬件优化,您不应该期望在不同的硬件上具有相同的速度。GDI很老,几乎到处都可以工作。
必须说,我已经尝试使用它来绘制简单的几何原始图,而direct2d似乎更强大,并且也许在复杂方案上可能会提高性能,但这不是我的情况。
如果您需要质量更高的GDI性能 - 尝试直接使用OpenGL或Direct3D。
这是一个相关的问题:Tdirect2dcanvas是慢还是我做错了什么?
我正在从事D2D。基本上,如果您留在基本图纸上,它比GDI快2倍或3倍。图线,矩形,椭圆形,例如rendertarget-> drawline。在全球范围内,直接在渲染目标上绘制比GDI快2x 3倍。另外,不要忘记绘制D2D backuffer而不是HWND。这与使用GDI位图背板完全相同,但使用Direct2D资源。
如果要使用高级D2D对象,例如几何,这是另一回事。
示例,如果不创建该矩形的转换几何形状的实例,就无法移动矩形。
d2d资源是不可药品的,尽管它们是在CPU级别进行管理的,但您无法修改源形状并绘制它。您必须为每次翻译创建此形状的副本,旋转...
如果您使用诸如PAINT之类的应用图绘图,这不是一个大问题...但是,如果您想使用一些形状,鼠标命中测试,缩放,滚动等...然后...然后...然后
在我的测试中,我(在调试模式下)需要0.5秒(在调试模式下)进行1000000次转换/转换源几何形状。
代码测试示例:
void TestGeometryPerf() { //1000000 = 0.35s/0.45s (in msvc 2019 debug mode)
ID2D1RectangleGeometry *r;
ID2D1TransformedGeometry *t;
D2D1_RECT_F rect = D2D1::RectF(0, 0, 1, 1);
D2D1::Matrix3x2F matrix = D2D1::Matrix3x2F::Translation(10,10);
//create geometry source
m_factory->CreateRectangleGeometry(rect, &r);
for(int x = 0; x < 1000000; x++) {
//create a transformed geometry from geometry source
m_factory->CreateTransformedGeometry(r, matrix, &t);
if( t->Release() != 0) {
throw;
}
}
if( r->Release() != 0) {
throw;
}
}
当然,正如其他海报所述,在硬件加速图形中,重要的是缓存资源,尽管有复杂的情况。
我编写了一些解决方案,这些解决方案用一些填充物绘制矩形,并填充屏幕。在1980x1080上,大约有300个矩形,大约有40 fps。
最重要的是, direct2d似乎不是最快的解决方案,至少是因为Direct2D只是D3D11上的包装器(或12)。如果您通过间谍 检查Chromium(至少边缘)渲染窗口,您会注意到,它的类称为"中间D3D窗口"。
我确定(虽然是开源的),即使诸如绘制图形之类的东西闪烁的图形(Skia似乎是),也可以使用恰好使用D3D而不是Direct2D编写。以及UWP应用程序。
- 如何在 Direct2D 窗口中正确初始化 Directwrite IDWriteTextLayout
- 没有专用显卡的 Direct2D 与 GDI+
- 如何在 direct2d 中使用随其窗口重新缩放的效果绘制图像
- Direct2D 如何打开共享纹理
- 使用 Direct2D 绘制 SVG 路径:无法绘制椭圆弧
- 最接近Direct2D/DirectWrite的跨平台替代方案?
- 遵循官方 Direct2D 示例,但出现访问冲突错误
- Direct2D 错误 - d2d1_1.h 充满了错误
- 在 Direct2D 绘图中,调整窗口大小后尺寸会更改
- 启动时不显示 Direct2D DC 上下文呈现的图像
- 将DirectX 11后缓冲区渲染到Direct2D
- C++ Direct2D - 从笔记本电脑移动正弦文件后出现链接器错误 2019
- 在 Direct2D 中使用单位矩阵乘法 - 为什么?
- C Direct2D径向梯度刷
- 创建独立控件Direct2D的好策略
- 在Windows中平滑调整窗口大小(使用Direct2D 1.1)
- 在Direct2D应用程序中处理HRESULT
- GDI versus Direct2D
- C++ Direct2D ID2D1HwndRenderTarget 的父 IUnknown 类的_vfptr变量变为 null
- 调整DXGI交换链绑定到Direct2D渲染目标