Direct2D CreateHwndRenderTarget 和 CreateDCRenderTarget

前段时间稍微看了点Direct3D, 觉得挺有意思的,但是想着要有3D得先从2D开始。故开始了D2D旅行。

如标题所示,CreateHwndRenderTarget 是在用来创建一个渲染到窗口的渲染目标。

创建渲染目标并且可以使用硬件加速时,可以在计算机的GPU上分配资源。通过一次创建渲染目标并保留尽可能长的时间,您可以获得性能上的好处。您的应用程序应一次创建渲染目标,并在应用程序的生命周期内或在收到D2DERR_RECREATE_TARGET错误之前将其保留。收到此错误时,您需要重新创建渲染目标(及其创建的所有资源)。

它与CreateDCRenderTarget最大的区别,也就是GDI的绘图技巧与D2D的区别了。

我的个人理解是,前者是自己在GPU上创建渲染目标,并停留一段时间用来绘制,不用我们操心上下文的环境了。 而后者的作用是

创建一个绘制目标,以绘制到Windows图形设备接口(GDI)设备上下文。

很显然它是用来充当D2D与GDI的交互的。

这篇文档是介绍这个作用的, Direct2D and GDI Interoperability Overview

在代码上使用肯定也是有区别的。

前者的使用,可以先看D2D入门的代码,下面的代码是用来将图片绘制到窗口上,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Windows.h>
#include <d2d1.h>
#include <d2d1_1.h>

#include <wincodec.h>

#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "Windowscodecs.lib")

#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}


extern "C" ID2D1Bitmap * mybitmapcreate(ID2D1DCRenderTarget*);
float left = 5;
float top = 10;
float Bottom = 10;
float Right = 30;
ID2D1Bitmap* pBitmap = NULL;
IWICImagingFactory* pIWICFactory = NULL;
HWND hWnd;
ID2D1HwndRenderTarget* m_pRenderTarget;

void initize();
void draw();
D2D1_RECT_F myrect = D2D1::RectF(left, top, Bottom, Right);
ID2D1Bitmap* mybitmap;
ID2D1Factory* l;
REFIID x = __uuidof(ID2D1Factory);

HRESULT LoadBitmapFromFile(
    ID2D1RenderTarget* pRenderTarget,
    IWICImagingFactory* pIWICFactory,
    PCWSTR uri,
    UINT destinationWidth,
    UINT destinationHeight
)
{
    HRESULT hr = S_OK;

    IWICBitmapDecoder* pDecoder = NULL;
    IWICBitmapFrameDecode* pSource = NULL;
    IWICStream* pStream = NULL;
    IWICFormatConverter* pConverter = NULL;
    IWICBitmapScaler* pScaler = NULL;


    hr = pIWICFactory->CreateDecoderFromFilename(
        uri,
        NULL,
        GENERIC_READ,
        WICDecodeMetadataCacheOnLoad,
        &pDecoder
    );
    if (SUCCEEDED(hr))
    {

        // Create the initial frame.
        hr = pDecoder->GetFrame(0, &pSource);
    }
    if (SUCCEEDED(hr))
    {
        hr = pIWICFactory->CreateFormatConverter(&pConverter);
    }
    // If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
    if (destinationWidth != 0 || destinationHeight != 0)
    {
        UINT originalWidth, originalHeight;
        hr = pSource->GetSize(&originalWidth, &originalHeight);
        if (SUCCEEDED(hr))
        {
            if (destinationWidth == 0)
            {
                FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
                destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
            }
            else if (destinationHeight == 0)
            {
                FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
                destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
            }

            hr = pIWICFactory->CreateBitmapScaler(&pScaler);
            if (SUCCEEDED(hr))
            {
                hr = pScaler->Initialize(
                    pSource,
                    destinationWidth,
                    destinationHeight,
                    WICBitmapInterpolationModeCubic
                );
            }
            if (SUCCEEDED(hr))
            {
                hr = pConverter->Initialize(
                    pScaler,
                    GUID_WICPixelFormat32bppPBGRA,
                    WICBitmapDitherTypeNone,
                    NULL,
                    0.f,
                    WICBitmapPaletteTypeMedianCut
                );
            }
        }
    }
    if (SUCCEEDED(hr))
    {
        // Create a Direct2D bitmap from the WIC bitmap.
        hr = pRenderTarget->CreateBitmapFromWicBitmap(
            pConverter,
            NULL,
            &pBitmap
        );
    }

    SAFE_RELEASE(pDecoder);
    SAFE_RELEASE(pSource);
    SAFE_RELEASE(pStream);
    SAFE_RELEASE(pConverter);
    SAFE_RELEASE(pScaler);

    return TRUE;
}

LRESULT CALLBACK WndProcFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    RECT rc;
    switch (message)
    {
    case WM_PAINT:
    {
        draw();
    }
    break;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}
int main(int argc, char* argv[])
{
    WNDCLASS wc{};
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProcFunc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.lpszClassName = L"Class_Name";
    wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
    RegisterClass(&wc);

    hWnd = CreateWindow(L"Class_Name", L"Test", WS_OVERLAPPEDWINDOW, 100, 100, 1000, 500, NULL, NULL, GetModuleHandle(NULL), NULL);
    initize();

    ShowWindow(hWnd, 1);
    UpdateWindow(hWnd);

    MSG Msg;
    while (GetMessage(&Msg, NULL, 0, 0))
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    return 0;
}

void initize()
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void**>(&pIWICFactory));

    HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &l);

    RECT rc;
    GetClientRect(hWnd, &rc);

    D2D1_SIZE_U size = D2D1::SizeU(
        rc.right - rc.left,
        rc.bottom - rc.top
    );

    // Create a Direct2D render target.
    hr = l->CreateHwndRenderTarget(
        D2D1::RenderTargetProperties(),
        D2D1::HwndRenderTargetProperties(hWnd, size),
        &m_pRenderTarget
    );

}

void draw()
{

    LoadBitmapFromFile(m_pRenderTarget, pIWICFactory, L"timg.bmp", 650, 400);


    m_pRenderTarget->BeginDraw();

    m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));

    D2D1_SIZE_F size = pBitmap->GetSize();
    D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f);

    // Draw bitmap
    m_pRenderTarget->DrawBitmap(
        pBitmap,
        D2D1::RectF(
            upperLeftCorner.x,
            upperLeftCorner.y,
            upperLeftCorner.x + size.width,
            upperLeftCorner.y + size.height)
    );
    m_pRenderTarget->EndDraw();

}

后者则是需要使用ID2D1DCRenderTarget::BindDC 将渲染目标绑定到向其发出绘图命令的设备上下文。

需要更改的代码部分,

//创建DC的渲染目标
ID2D1DCRenderTarget* pow;
...

void initize()
{
    CoInitializeEx(NULL, COINIT_MULTITHREADED);
    CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void**>(&pIWICFactory));

    HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &l);

    D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
        D2D1_RENDER_TARGET_TYPE_DEFAULT,
        D2D1::PixelFormat(
            DXGI_FORMAT_B8G8R8A8_UNORM,
            D2D1_ALPHA_MODE_IGNORE),
        0,
        0,
        D2D1_RENDER_TARGET_USAGE_NONE,
        D2D1_FEATURE_LEVEL_DEFAULT
    );   
    l->CreateDCRenderTarget(&props, &pow);

}
void draw()
{

    LoadBitmapFromFile(m_pRenderTarget, pIWICFactory, L"timg.bmp", 650, 400);


    pow->BeginDraw();

    pow->Clear(D2D1::ColorF(D2D1::ColorF::White));

    D2D1_SIZE_F size = pBitmap->GetSize();
    D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f);

    // Draw bitmap
    pow->DrawBitmap(
        pBitmap,
        D2D1::RectF(
            upperLeftCorner.x,
            upperLeftCorner.y,
            upperLeftCorner.x + size.width,
            upperLeftCorner.y + size.height)
    );
    pow->EndDraw();

}

case WM_PAINT:
{
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rc);
        pow->BindDC(ps.hdc, &rc);
        draw();
        EndPaint(hwnd, &ps);
}
break;
...
原文地址:https://www.cnblogs.com/strive-sun/p/14282000.html