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

传入设备依赖资源时,IDWriteTextLayout::SetDrawingEffect设备丢失处理最佳实践

处理DirectWrite中绑定设备依赖Brush时的设备丢失问题最佳实践

由于IDWriteTextLayout是设备无关资源,但ID2D1LinearGradientBrush等属于设备依赖资源(绑定到特定D2D设备/上下文,设备丢失后会直接失效),直接将其传入IDWriteTextLayout::SetDrawingEffect会导致设备丢失后渲染失败,以下是核心解决思路和实践:

核心原则:分离设备无关配置与设备依赖资源

绝对不要让设备无关的IDWriteTextLayout持有任何设备依赖对象。取而代之的是:

  • 定义设备无关的brush配置数据结构,存储渐变的起止颜色、渐变方向、坐标映射规则等所有重建brush需要的信息。
  • 让这个配置结构实现IUnknown接口(因为SetDrawingEffect要求传入IUnknown*类型参数),将其作为SetDrawingEffect的参数传入IDWriteTextLayout。

示例配置结构(伪代码):

class LinearGradientConfig : public IUnknown
{
public:
    // IUnknown 接口实现
    STDMETHOD(QueryInterface)(REFIID riid, void** ppvObject) override;
    STDMETHOD_(ULONG, AddRef)() override;
    STDMETHOD_(ULONG, Release)() override;

    // 渐变配置参数
    D2D1_COLOR_F startColor;
    D2D1_COLOR_F endColor;
    D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES gradientProps;
    D2D1_MATRIX_3X2_F transform;
};

自定义IDWriteTextRenderer处理渲染逻辑

实现自定义的IDWriteTextRenderer,在DrawGlyphRun回调中完成以下操作:

  1. 从pDrawingEffect参数中QueryInterface取出之前存入的LinearGradientConfig对象。
  2. 使用当前有效的ID2D1DeviceContext,根据配置参数重新创建ID2D1LinearGradientBrush实例。
  3. 使用新创建的brush渲染字形,渲染完成后立即释放该brush(或者维护一个brush缓存,设备丢失时清空缓存)。

关键代码片段(伪代码):

STDMETHODIMP CustomTextRenderer::DrawGlyphRun(
    void* clientDrawingContext,
    FLOAT baselineOriginX,
    FLOAT baselineOriginY,
    DWRITE_MEASURING_MODE measuringMode,
    const DWRITE_GLYPH_RUN* glyphRun,
    const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription,
    IUnknown* pDrawingEffect
)
{
    auto dc = static_cast<ID2D1DeviceContext*>(clientDrawingContext);
    LinearGradientConfig* config = nullptr;
    if (pDrawingEffect)
    {
        pDrawingEffect->QueryInterface(IID_PPV_ARGS(&config));
    }

    if (config)
    {
        ID2D1LinearGradientBrush* brush = nullptr;
        dc->CreateLinearGradientBrush(
            &config->gradientProps,
            nullptr,
            &brush
        );
        brush->SetColorInterpolationGamma(D2D1_GAMMA_2_2);
        brush->SetTransform(config->transform);

        // 使用brush渲染字形
        dc->DrawGlyphRun(
            D2D1_POINT_2F{baselineOriginX, baselineOriginY},
            glyphRun,
            brush,
            measuringMode
        );

        brush->Release();
        config->Release();
    }
    return S_OK;
}

设备丢失后的重建流程

  1. 检测设备丢失:通过ID2D1DeviceContext::CheckDeviceState或捕获D2DERR_RECREATE_TARGET错误判断设备丢失。
  2. 清理失效资源:释放所有已创建的设备依赖brush(包括缓存中的)。
  3. 重建D2D设备栈:重新创建ID2D1Device、ID2D1DeviceContext及相关渲染目标。
  4. 无需重建IDWriteTextLayout:因为它是设备无关的,仅需在后续渲染时,通过自定义渲染器重新生成对应的brush即可。

额外优化建议

  • 维护一个brush缓存:根据配置参数的哈希值缓存已创建的brush,避免每次渲染都重新创建,提升性能;设备丢失时直接清空整个缓存。
  • 确保配置对象的线程安全:如果多线程渲染,要保证配置对象的访问是线程安全的,或者每个线程维护独立的brush缓存。

内容的提问来源于stack exchange,提问作者user16501294

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:50:25