D2D调试错误:设备资源关联错误ID2D1Device问题求助
问题描述
尝试从位图提取二进制数据时,调用DrawBitmap将ID2D1Bitmap绘制到ID2D1RenderTarget时触发D2D调试错误:
An operation failed because a device-dependent resource is associated with the wrong ID2D1Device (resource domain)
已确认_D2dDeviceContext5由_D2dFactory6间接创建,但对DirectX资源管理不熟悉,不敢修改资源创建顺序,怕引发其他初始化失败。
错误原因
你创建的ID2D1Bitmap是设备依赖资源,绑定在通过_D3dDevice5创建的_D2dDevice5设备上;但调用_D2dFactory6->CreateWicBitmapRenderTarget时,没有指定关联的D2D设备,系统会默认创建一个全新的独立D2D设备,导致两个资源属于不同的设备域,跨设备绘制就会触发这个错误。
解决方案
有两种可行的修复方式:
方式1:让WIC渲染目标和原Bitmap使用同一D2D设备
创建WIC位图渲染目标时,不要直接用Factory的方法,而是通过已有的_D2dDevice5创建关联的设备上下文,再绑定到WIC位图上,确保资源在同一设备域内。
方式2:直接从D2D Bitmap映射内存(更高效)
既然目标是提取像素数据,不需要通过绘制到WIC位图的方式,直接利用ID2D1Bitmap的Map方法获取内存指针,步骤更简洁高效。
修改后的代码示例
方式1:修复原绘制逻辑
#include <Windows.h> #include <d3dcompiler.h> #include <dxgi1_5.h> #include <d3d11.h> #include <d3d11_4.h> #include <d2d1.h> #include <d2d1_3.h> #include <d2d1_3helper.h> #include <wincodec.h> #include <tchar.h> #include <atlbase.h> #pragma comment (lib, "d3dcompiler") #pragma comment (lib, "D2d1") #pragma comment (lib, "dxguid") #pragma comment (lib, "d3d11") #pragma comment (lib, "dxgi") int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR pszCmdLine, _In_ int iCmdShow) { CComPtr<ID2D1Device5> _D2dDevice5; CComPtr<ID2D1Factory> _D2dFactory; CComPtr<ID2D1Factory6> _D2dFactory6; CComPtr<ID2D1DeviceContext5> _D2dDeviceContext5; CComPtr<ID3D11Device> _D3dDevice; CComPtr<ID3D11Device5> _D3dDevice5; CComPtr<ID3D11DeviceContext> _D3dDeviceContext; CComPtr<IDXGIDevice4> _D3d_DXGI_D2d_; CComPtr<IWICImagingFactory2> _IWICFactory2; D3D_FEATURE_LEVEL featureLevelSupported; CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY); D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_BGRA_SUPPORT, NULL, 0, D3D11_SDK_VERSION, &_D3dDevice, &featureLevelSupported, &_D3dDeviceContext); _D3dDevice->QueryInterface(__uuidof(ID3D11Device5), reinterpret_cast<void**>(&_D3dDevice5)); //D2dFactory D2D1_FACTORY_OPTIONS const d2dDeviceoptions = { D2D1_DEBUG_LEVEL_INFORMATION }; D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, d2dDeviceoptions, &_D2dFactory); _D2dFactory->QueryInterface(__uuidof(ID2D1Factory6), reinterpret_cast<void**>(&_D2dFactory6)); //D2dDevice _D3dDevice5->QueryInterface(&_D3d_DXGI_D2d_); _D2dFactory6->CreateDevice(_D3d_DXGI_D2d_, &_D2dDevice5); //D2dDeviceContext _D2dDevice5->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, &_D2dDeviceContext5); //IWICFactory CoCreateInstance(CLSID_WICImagingFactory2, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_IWICFactory2)); // LPCWSTR pngPath = _T("C:\\Img1.png"); // CComPtr<IWICStream> stream; _IWICFactory2->CreateStream(&stream); stream->InitializeFromFilename(pngPath, GENERIC_READ); CComPtr<IWICBitmapDecoder> decoder; _IWICFactory2->CreateDecoderFromStream(stream, NULL, WICDecodeMetadataCacheOnLoad, &decoder); CComPtr<IWICBitmapFrameDecode> frameDecode; decoder->GetFrame(0, &frameDecode); CComPtr<IWICFormatConverter> converter; _IWICFactory2->CreateFormatConverter(&converter); converter->Initialize( frameDecode, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0, WICBitmapPaletteTypeCustom ); CComPtr<ID2D1Bitmap> bitmap; _D2dDeviceContext5->CreateBitmapFromWicBitmap(converter, NULL, &bitmap); // CopyBitmapToCPU char* data = nullptr; // 修正原指针错误,避免非法内存访问 size_t dataSize = 0; D2D1_SIZE_U bitmapSize = bitmap->GetPixelSize(); CComPtr<IWICBitmap> wicBitmap; _IWICFactory2->CreateBitmap(bitmapSize.width, bitmapSize.height, GUID_WICPixelFormat32bppPBGRA, WICBitmapCacheOnLoad, &wicBitmap); // 关键修改:通过已有_D2dDevice5创建绑定到WIC位图的设备上下文 CComPtr<ID2D1DeviceContext> targetContext; _D2dDevice5->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, &targetContext); // 将WIC位图转换为D2D位图并设置为渲染目标 CComPtr<ID2D1Bitmap1> wicD2dBitmap; targetContext->CreateBitmapFromWicBitmap(wicBitmap, nullptr, &wicD2dBitmap); targetContext->SetTarget(wicD2dBitmap); targetContext->BeginDraw(); targetContext->DrawBitmap(bitmap); // 设备域匹配,不再报错 targetContext->EndDraw(); WICRect rcLock = { 0,0,static_cast<INT>(bitmapSize.width), static_cast<INT>(bitmapSize.height) }; CComPtr<IWICBitmapLock> lock; wicBitmap->Lock(&rcLock, WICBitmapLockRead, &lock); UINT bufferSize = 0; unsigned char* tempTargetData = nullptr; lock->GetDataPointer(&bufferSize, &tempTargetData); if (tempTargetData != NULL) { data = new char[bufferSize]; memcpy(data, tempTargetData, bufferSize); dataSize = static_cast<size_t>(bufferSize); } // 释放内存 if (data) delete[] data; return 0; }
方式2:直接映射D2D Bitmap内存(更高效)
// 前面初始化部分和原代码一致,省略重复代码 CComPtr<ID2D1Bitmap> bitmap; _D2dDeviceContext5->CreateBitmapFromWicBitmap(converter, NULL, &bitmap); // CopyBitmapToCPU - 直接映射D2D Bitmap获取像素数据 char* data = nullptr; size_t dataSize = 0; D2D1_SIZE_U bitmapSize = bitmap->GetPixelSize(); // 将Bitmap映射到CPU内存 D2D1_MAPPED_RECT mappedRect; HRESULT hr = bitmap->Map(D2D1_MAP_OPTIONS_READ, &mappedRect); if (SUCCEEDED(hr)) { UINT pixelBytes = 4; // 32bpp格式,每个像素4字节 UINT bufferSize = bitmapSize.width * bitmapSize.height * pixelBytes; data = new char[bufferSize]; // 按行复制,处理内存对齐问题 for (UINT y = 0; y < bitmapSize.height; y++) { memcpy( data + y * bitmapSize.width * pixelBytes, reinterpret_cast<char*>(mappedRect.bits) + y * mappedRect.pitch, bitmapSize.width * pixelBytes ); } dataSize = bufferSize; bitmap->Unmap(); } // 释放内存 if (data) delete[] data; return 0; }
额外说明
- 原代码中
char** data = nullptr;存在错误,会导致memcpy写入非法地址,已修正为char* data = nullptr; - 方式2无需依赖WIC渲染目标,直接从D2D Bitmap获取像素数据,性能更高、步骤更简洁,推荐优先使用
内容的提问来源于stack exchange,提问作者feng lei
相关产品推荐
相关产品推荐

