ID2D1DeviceContext::CreateBitmap 有什么参数错误?

问题描述

我正在尝试使用 Direct2D 绘制屏幕外位图。我需要使用 ID2D1DeviceContext 而不是 ID2D1rendertarget 因为我需要能够设置混合模式。但是, CreateBitmap 因错误 E_INVALIDARG(“参数不正确”)而失败,我无法确定哪个参数不正确。 src 数据不是必需的,像素格式是 Direct2D 需要的,并且在我发现的其他示例中。文档说颜色上下文是可选的。实际上,我怀疑 CreateBitmap 的某些参数与创建 Device 或 DeviceContext 的方式不兼容,但我看不出有什么问题。如果有人能指出我哪里出错了,或者至少给我一些有关如何解决问题的指示,我将不胜感激。

以下代码在 CreateBitmap 之前都可以正常工作,但它以 E_INVALIDARG 失败。

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <comdef.h>
#include <d2d1.h>
#include <d2d1_1.h>
#include <d3d11.h>

#include <iostream>
#include <string>

void printError(const std::string& msg,HRESULT err)
{
    std::cerr << "[ERROR] " << msg << ": " << _com_error(err).ErrorMessage() << std::endl;
    assert(false);
}

int main(int argc,char *argv[])
{
    ID2D1Factory1 *mD2DFactory = nullptr;
    ID3D11Device *mD3DDevice = nullptr;
    ID3D11DeviceContext* mD3DDeviceContext = nullptr;
    IdxgiDevice *mdxgiDevice = nullptr;
    ID2D1Device *mD2DDevice = nullptr;

    HRESULT err;

    // Create factories first; they don't depend on anything.
    err = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,__uuidof(ID2D1Factory1),// get a Direct2D 1.1 factory,(void**)&mD2DFactory);
    if (err != S_OK) {
        printError("fatal: Could not create Direct2D factory!",err);
        return 1;
    }

    // Initialize DirectX 11.1
    D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1 };
    err = D3D11CreateDevice(NULL,// first adapter
                            D3D_DRIVER_TYPE_HARDWARE,NULL,// software rasterizer DLL handle
                            D3D11_CREATE_DEVICE_SINGLETHREADED    // better performance
                              | D3D11_CREATE_DEVICE_BGRA_SUPPORT,// required for Direct2D
                            featureLevels,sizeof(featureLevels) / sizeof(D3D_FEATURE_LEVEL),D3D11_SDK_VERSION,// docs say use this
                            &mD3DDevice,// don't care what feature level we got
                            &mD3DDeviceContext);
    if (err != S_OK) {
        printError("fatal: Could not create a Direct3D 11.1 device",err);
        return 1;
    }

    err = mD3DDevice->QueryInterface(__uuidof(IdxgiDevice),(void**)&mdxgiDevice);
    if (err != S_OK) {
        printError("fatal: Direct3D device is not IdxgiDevice",err);
        return 1;
    }

    // Initialize Direct2D
    err = mD2DFactory->CreateDevice(mdxgiDevice,&mD2DDevice);
    if (err != S_OK) {
        printError("fatal: Could not create Direct2D device",err);
        return 1;
    }

    //---------------- Create the bitmap --------------------
    ID2D1DeviceContext *mDC = nullptr;
    ID2D1Bitmap1 *mBitmap = nullptr;
    int width = 13,height = 13;
    float dpi = 76.0f;

    err = mD2DDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE,&mDC);
    if (err) {
        printError("Could not create device context",err);
        return 1;
    }

    D2D1_BITMAP_PROPERTIES1 bitmapProps;
    bitmapProps.pixelFormat.format = dxgi_FORMAT_B8G8R8A8_UnorM;
    bitmapProps.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
    bitmapProps.dpiX = dpi;
    bitmapProps.dpiY = dpi;
    bitmapProps.bitmapOptions = D2D1_BITMAP_OPTIONS_TARGET |  // can use for SetTarget()
                                D2D1_BITMAP_OPTIONS_cpu_READ;
    bitmapProps.colorContext = nullptr;

    err = mDC->CreateBitmap({ UINT32(width),UINT32(height) },nullptr,bitmapProps,&mBitmap);
    if (err == S_OK) {
        mDC->SetTarget(mBitmap);
    } else {
        printError("Could not create bitmap (" + std::to_string(width) + "x" + std::to_string(height) + ")",err);
        return 1;
    }

    std::cout << "Success!" << std::endl;
    return 0;
}

解决方法

正如官方 D2D1_BITMAP_OPTIONS enumeration 所说:

D2D1_BITMAP_OPTIONS_CPU_READ 表示位图可以通过 使用 ID2D1Bitmap1::Map。这个标志需要 D2D1_BITMAP_OPTIONS_CANNOT_DRAW 并且不能与任何其他 标志。位图必须使用 CopyFromBitmap 或 CopyFromRenderTarget 方法。