我现在正在编写一个仿真程序,我想把我的应用程序从使用GDI移植到使用Direct2D。但是我的Direct2D代码比我的GDI代码慢很多。
我在屏幕上渲染了很多椭圆。在我的GDI应用程序中,我绘制到一个内存设备上下文,然后使用BitBlt绘制到windows设备上下文。使用Direct2D,我画到ID2D1HwndRenderTarget上。
我的问题是,当使用GDI时,我可以轻松地绘制400多个椭圆,并且仍然有400 FPS。当我用Direct2D画同样数量的椭圆时,我的FPS降到了30FPS。
我已经关闭了抗锯齿,但这并没有什么帮助。有趣的是,在Direct2D中画几个椭圆比GDI快。我有什么办法可以提高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);
}
在Begin和End函数之间,我用标准的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);
先谢谢你。
前段时间由于性能低下,我拒绝将渲染代码从GDI迁移到Direct2D。据我从google上了解,Direct2D的性能取决于驱动和硬件优化,你不应该期望在不同的硬件上有同样的速度。GDI已经很老了,几乎在任何地方都能同样工作。
不得不说,我曾尝试用它来绘制简单的几何基元,而Direct2D似乎是更强大的库,也许在复杂的情况下会有性能提升,但这不是我的情况。
如果你需要GDI性能和更好的质量--尝试直接使用OpenGL或Direct3D。
这是一个相关的问题。是TDirect2DCanvas慢还是我做错了什么?
初次尝试Direct2D的一个常见错误是开发者没有正确地缓存D2D资源,而是过于频繁地创建和销毁资源。 如果你所有的椭圆大小相似,你应该创建并缓存一次这个椭圆对象。 如果你有30个不同大小的形状,那么只需要为所有30个大小的形状创建一次椭圆版本。 这样可以显著提高Direct2D的速度。 矩形和所有其他基元也是如此。如果一个基元存在太多的变化,那么缩放缓存对象与重复创建销毁也是某些情况下的解决方案,不过使用资源的原生尺寸是最理想的,内存卡有相当多的内存来存储你的资源。
Gdi椭圆看起来绝对糟糕,直接使用Direct3D相当复杂,特别是对于椭圆、大型多边形和更高级别的基元。如果适当使用Direct2D,你应该可以获得良好的速度和高质量的渲染。
我正在研究d2d。基本上它的速度是gdi的2倍或3倍左右,如果你停留在基本的绘图上。绘制线条,矩形,椭圆,......比如RenderTarget->DrawLine。在全球范围内,直接在渲染目标上绘制比gdi快2倍3倍。另外,别忘了在d2d后置缓冲区上绘制,而不是在hwnd上绘制。这和使用gdi位图回缓冲区的过程完全一样,但使用的是direct2d资源。
如果你想使用高级的d2d对象,比如几何体,这是另外一回事。
举个例子,如果不创建一个这个矩形的变换几何体的实例,你就不能移动一个矩形。
D2D资源是不可变的,尽管它们是在cpu级别上管理的,你不能修改源形状并直接绘制它。你必须为每一次平移、旋转创建一个这个形状的副本。
如果你使用像paint这样的应用程序绘图,这不是一个大问题......。但如果你想使用一个实时系统,有大量的形状,鼠标点击测试,缩放,滚动等......。那就会在性能上出现漏洞。
在我的测试中,它需要我(在调试模式下)约0.5s的转化源几何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;
}
}