我實現D2D + WIC今天常規。測試結果非常好。
在我之前的GDI StretchDIBits
版本中,將1280x640的DDB拖入1920x1080窗口需要20〜60ms的時間。切換到Direct2D + WIC後,通常需要5ms以下,畫面質量也會更好。
我使用ID2D1HwndRenderTarget和WicBitmapRenderTarget,因爲我需要讀取/寫入原始像素數據。
HWndRenderTarget僅用於屏幕繪製(WM_PAINT)。
HWndRenderTarget的主要優點是目標窗口大小不會影響繪圖性能。
WicBitmapRenderTarget用作臨時繪圖畫布(作爲GDI繪圖中的內存DC)。我們可以使用WIC位圖對象(如GDI DIBSection)創建WicBitmapRenderTarget。我們可以隨時讀取/寫入此WIC位圖的原始像素數據。而且速度非常快。對於附註,有些類似的D3D GetFrontBufferData
調用非常緩慢。
實際像素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中非常簡單。
是的,StretchBlt真的很慢。如果您想要更高的質量(例如使用HALFTONE選項),則無法實時渲染。無論如何,你的軟件瞄準什麼操作系統? – 2014-10-02 07:16:57
@AntonAngelov目標操作系統是Windows 7+。目前我的筆記本電腦可以順利地(通過GDI)做900x600 @ 20fps,我的目標是1920x1080 @ 30fps。如果我在下週後得到結果,我可能會問另一個問題:) – 9dan 2014-10-02 08:37:31
好吧。但是,你能更準確地提出你的問題嗎?(例如,一個問題)? – 2014-10-02 08:53:59