我今天实施了 D2D + WIC 例程。测试结果真的很好。
在我之前的 GDIStretchDIBits
版本中,将 1280x640 DDB 绘制到 1920x1080 窗口需要 20 ~ 60ms 的时间。切换到 Direct2D + WIC 后,通常需要 5ms 以下,而且画质看起来更好。
我将 ID2D1HwndRenderTarget 与 WicBitmapRenderTarget 一起使用,因为我需要读取/写入原始像素数据。
HWndRenderTarget 仅用于屏幕绘制 (WM_PAINT)。
HWndRenderTarget 的主要优点是目标窗口大小不会影响绘图性能。
WicBitmapRenderTarget 用作临时绘图画布(作为 GDI 绘图中的 Memory DC)。我们可以使用 WIC 位图对象(如 GDI DIBSection)创建 WicBitmapRenderTarget。我们可以随时从/向该 WIC 位图读取/写入原始像素数据。它也非常快。附带说明一下,有点类似的 D3DGetFrontBufferData
调用真的很慢。
实际的像素 I/O 是通过 IWICBitmap 和 IWICBitmapLock 接口完成的。
写作:
IWICBitmapPtr m_wicRemote;
...
const uint8* image = ...;
...
WICRect rcLock = { 0, 0, width, height };
IWICBitmapLockPtr wicLock;
hr = m_wicRemote->Lock(&rcLock, WICBitmapLockWrite, &wicLock);
if (SUCCEEDED(hr))
{
UINT cbBufferSize = 0;
BYTE *pv = NULL;
hr = wicLock->GetDataPointer(&cbBufferSize, &pv);
if (SUCCEEDED(hr))
{
memcpy(pv, image, cbBufferSize);
}
}
m_wicRenderTarget->BeginDraw();
m_wicRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
ID2D1BitmapPtr d2dBitmap;
hr = m_wicRenderTarget->CreateBitmapFromWicBitmap(m_wicRemote, &d2dBitmap.GetInterfacePtr());
if (SUCCEEDED(hr))
{
float cw = (renderTargetSize.width / 2);
float ch = renderTargetSize.height;
float x, y, w, h;
FitFrameToCenter(cw, ch, (float)width, (float)height, x, y, w, h);
m_wicRenderTarget->DrawBitmap(d2dBitmap, D2D1::RectF(x, y, x + w, y + h));
}
m_wicRenderTarget->EndDraw();
阅读:
IWICBitmapPtr m_wicCanvas;
IWICBitmapLockPtr m_wicLockedData;
...
UINT width, height;
HRESULT hr = m_wicCanvas->GetSize(&width, &height);
if (SUCCEEDED(hr))
{
WICRect rcLock = { 0, 0, width, height };
hr = m_wicCanvas->Lock(&rcLock, WICBitmapLockRead, &m_wicLockedData);
if (SUCCEEDED(hr))
{
UINT cbBufferSize = 0;
BYTE *pv = NULL;
hr = m_wicLockedData->GetDataPointer(&cbBufferSize, &pv);
if (SUCCEEDED(hr))
{
return pv; // return data pointer
// need to Release m_wicLockedData after reading is done
}
}
}
绘画:
ID2D1HwndRenderTargetPtr m_renderTarget;
....
D2D1_SIZE_F renderTargetSize = m_renderTarget->GetSize();
m_renderTarget->BeginDraw();
m_renderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
m_renderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black));
ID2D1BitmapPtr d2dBitmap;
hr = m_renderTarget->CreateBitmapFromWicBitmap(m_wicCanvas, &d2dBitmap.GetInterfacePtr());
if (SUCCEEDED(hr))
{
UINT width, height;
hr = m_wicCanvas->GetSize(&width, &height);
if (SUCCEEDED(hr))
{
float x, y, w, h;
FitFrameToCenter(renderTargetSize.width, renderTargetSize.height, (float)width, (float)height, x, y, w, h);
m_renderTarget->DrawBitmap(d2dBitmap, D2D1::RectF(x, y, x + w, y + h));
}
}
m_renderTarget->EndDraw();
在我看来,GDI Stretch..
API 在 Windows 7+ 设置中完全没用(对于性能敏感的应用程序)。
另请注意,与 Direct3D 不同的是,在 Direct2D 中,基本的图形操作(如文本绘制、ling 绘制)非常简单。