DirectX如何复制指针图像数据到已有D2D1Bitmap并排查绘制失败问题
D2D 位图内存复制后绘制失败的问题排查
你的代码存在以下几处明确疏漏,会直接导致CopyFromMemory或后续绘制操作失败:
- 目标复制矩形参数错误:
CopyFromMemory要求传入的目标矩形是无符号整数类型(D2D1_RECT_U),且矩形范围不能超出目标位图自身的像素尺寸。你在代码中调用m_d2dTargetBitmap->GetSize()拿到的是浮点数类型的DIP尺寸,不是位图的实际像素尺寸,同时你错误使用了渲染目标位图的尺寸作为待更新bitmap的复制区域,没有校验当前bitmap的实际像素宽高与传入的width/height是否匹配。如果两者尺寸不一致、或者浮点数转无符号整数时出现截断,CopyFromMemory会直接返回E_INVALIDARG或区域越界错误。 - 返回值校验缺失:你仅对
CreateBitmap的执行结果做了失败判断,完全没有校验CopyFromMemory的hr返回值。一旦复制操作因为参数错误、内存越界、资源失效执行失败,你仍然直接进入绘制流程,此时位图内部数据无效,DrawBitmap必然执行异常。 - 步长与格式匹配风险:你创建位图时硬编码使用
DXGI_FORMAT_B8G8R8A8_UNORM格式、width*4作为行步长,但代码中保留了NV12格式的注释分支,如果你传入的buffer实际是NV12等其他格式,或者图像字节数组的行步长做了硬件对齐(比如按64字节/128字节对齐,而非严格等于像素宽度*每像素字节数),写死的步长参数会导致内存读取越界、图像数据错位。你提到有4组同分辨率的图像数组,还要确认每次传入的buffer->Data对应的单帧数据长度和步长是否和位图格式匹配,不要把多帧数据的指针直接传入。 - 资源有效性未校验:如果D2D设备因为设备丢失、重建等原因失效,之前创建的
bitmap资源会变为无效状态,你没有判断现有bitmap的资源有效性,直接对失效资源执行复制和绘制操作,会返回资源相关的错误码。另外DrawBitmap调用时没有显式指定目标绘制矩形、混合模式,若当前上下文DPI和位图DPI不匹配,也可能出现绘制异常。
修正参考代码
if (bitmap == nullptr) { // 提前确认buffer格式、步长与创建参数一致 hr = m_d2dContext->CreateBitmap( D2D1::SizeU(width, height), buffer->Data, width * 4, // 此处步长必须与输入buffer的实际行步长完全一致 D2D1::BitmapProperties( D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE) ), &bitmap ); if (FAILED(hr)) { return; } } else { // 先获取目标bitmap自身的像素尺寸,不要用渲染目标的尺寸 D2D1_SIZE_U bitmapSize = bitmap->GetPixelSize(); // 校验尺寸匹配,避免越界 if (bitmapSize.width != width || bitmapSize.height != height) { // 尺寸不匹配时释放旧位图重新创建,不要直接复制 bitmap->Release(); bitmap = nullptr; // 重新走创建逻辑即可 return; } D2D1_RECT_U dstRect = D2D1::RectU(0, 0, width, height); hr = bitmap->CopyFromMemory(&dstRect, buffer->Data, width * 4); // 必须校验复制结果 if (FAILED(hr)) { return; } } m_d2dContext->BeginDraw(); // 显式指定目标矩形,适配渲染目标尺寸 m_d2dContext->DrawBitmap( bitmap, D2D1::RectF(0, 0, static_cast<FLOAT>(width), static_cast<FLOAT>(height)) ); hr = m_d2dContext->EndDraw(); // 处理EndDraw可能返回的设备丢失错误 if (hr == D2DERR_RECREATE_TARGET) { // 在此处添加资源重建逻辑,释放所有旧位图、重建渲染目标 }
内容的提问来源于stack exchange,提问作者Karthik
相关产品推荐
相关产品推荐

