传入设备依赖资源时,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回调中完成以下操作:
- 从
pDrawingEffect参数中QueryInterface取出之前存入的LinearGradientConfig对象。 - 使用当前有效的
ID2D1DeviceContext,根据配置参数重新创建ID2D1LinearGradientBrush实例。 - 使用新创建的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; }
设备丢失后的重建流程
- 检测设备丢失:通过
ID2D1DeviceContext::CheckDeviceState或捕获D2DERR_RECREATE_TARGET错误判断设备丢失。 - 清理失效资源:释放所有已创建的设备依赖brush(包括缓存中的)。
- 重建D2D设备栈:重新创建
ID2D1Device、ID2D1DeviceContext及相关渲染目标。 - 无需重建IDWriteTextLayout:因为它是设备无关的,仅需在后续渲染时,通过自定义渲染器重新生成对应的brush即可。
额外优化建议
- 维护一个brush缓存:根据配置参数的哈希值缓存已创建的brush,避免每次渲染都重新创建,提升性能;设备丢失时直接清空整个缓存。
- 确保配置对象的线程安全:如果多线程渲染,要保证配置对象的访问是线程安全的,或者每个线程维护独立的brush缓存。
内容的提问来源于stack exchange,提问作者user16501294
相关产品推荐
相关产品推荐

