You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 10:27:18