Reputation: 1647
I'm trying to draw to an offscreen bitmap using Direct2D. I need to use a ID2D1DeviceContext instead of ID2D1RenderTarget because I need to be able to set the blending mode. However, CreateBitmap is failing with error E_INVALIDARG ("The parameter is incorrect") and I can't figure out which parameter is incorrect. The src data is not required, the pixel format is what Direct2D needs, and is in other examples I have found. The docs say that the color context is optional. Actually, I suspect that some parameter to CreateBitmap is incompatible to how the Device or DeviceContext got created, but I can't see anything wrong. I would be grateful if someone could point me to where I'm going wrong, or at least give me some pointers on how to figure it out.
The following code works fine up until CreateBitmap, where it fails with 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,
NULL, // 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, 0,
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;
}
Upvotes: 0
Views: 776
Reputation: 138776
As Official D2D1_BITMAP_OPTIONS enumeration says:
D2D1_BITMAP_OPTIONS_CPU_READ means that the bitmap can be mapped by using ID2D1Bitmap1::Map. This flag requires D2D1_BITMAP_OPTIONS_CANNOT_DRAW and cannot be combined with any other flags. The bitmap must be updated with the CopyFromBitmap or CopyFromRenderTarget methods.
Upvotes: 1