Windows StretchBlt API performance

前端 未结 1 1246
长情又很酷
长情又很酷 2020-12-18 12:17

I timed a DDB drawing operation which uses multiple StretchBlt and StretchDIBits calls.

And I found that, time to complete is increase/decr

相关标签:
1条回答
  • 2020-12-18 12:49

    I've implemented D2D + WIC routine today. Test results are really good.

    With my previous GDI StretchDIBits version, it took 20 ~ 60ms time for drawing 1280x640 DDB into a 1920x1080 window. After switching to Direct2D + WIC, it usually takes under 5ms, also picture quality looks better.

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

    HWndRenderTarget is only used for screen painting (WM_PAINT).
    The main advantage of HWndRenderTarget is that the destination window size doesn't affect drawing performance.

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

    Actual pixel I/O is done through IWICBitmap and IWICBitmapLock interface.

    Writing:

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

    Drawing:

    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 Stretch.. APIs are totally useless in Windows 7+ setup (for performance sensitive applications).

    Also note that, unlike Direct3D, basic graphics operations such as text drawing, ling drawing are really simple in Direct2D.

    0 讨论(0)
提交回复
热议问题