Windows StretchBlt API performance

I have timed a DDB draw operation that uses multiple calls to StretchBlt

and StretchDIBits

.

And I found that completion time increases / decreases in proportion to the size of the destination window.
A 900x600 window takes about 5ms, but at 1920x1080 it reaches 55ms (the original image is 1280x640).

It seems that Stretch .. APIs do not use hardware acceleration features.

The original image (actually a temporary painting) is created using CreateDIBSection

because I need the resulting (stretched and merged) bitmap image data for each framed frame .

Let's assume Windows GDI is hopeless. Then what is the promising alternative?

I was looking at D3D, D2D with WIC method (write to WIC bitmap and draw with D2D, then read pixel data from WIC bitmap).
I was planning to try D2D with the WIC method because I would soon need to use the advanced text drawing feature.

But it seems like WIC isn't all that promising: What is the most efficient pixel format to handle the WIC bitmap?

+3


source to share


1 answer


I have implemented D2D + WIC today. The test results are really good.

With my previous version of GDI, StretchDIBits

it took 20 ~ 60ms to draw a 1280x640 DDB in a 1920x1080 window. After switching to Direct2D + WIC, it usually takes less than 5ms and the image quality looks better.

I used ID2D1HwndRenderTarget with WicBitmapRenderTarget because I need to read / write raw pixel data.

HWndRenderTarget is only used to draw the screen (WM_PAINT).
The main advantage of HWndRenderTarget is that the size of the target window does not affect drawing performance.

WicBitmapRenderTarget is used as a temporary canvas for drawing (like a DC DC in GDI drawing). We can create a WicBitmapRenderTarget with a WIC bitmap object (like a GDI DIBSection). We can read / write raw pixel data from / to this WIC bitmap at any time. And it's very fast. For a side note, a somewhat similar D3D call is GetFrontBufferData

very slow.

The actual pixel I / O is done through the IWICBitmap and IWICBitmapLock interface.

Record:



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();

      

Reading:

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
        }
    }
}

      

Picture:

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();

      

In my opinion, GDI APIs are Stretch..

absolutely useless in Windows 7+ settings (for high sensitivity applications).

Also note that unlike Direct3D, basic graphics operations such as drawing text, drawing lines are very easy in Direct2D.

+5


source







All Articles