From e5100d9a9fa6b76dfab1dd767a8ec645d4678fce Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Thu, 28 Mar 2013 15:51:12 +0200 Subject: [PATCH] Gfx: Make text rendering with D2D more efficient by reusing layout --- Common/Gfx/CanvasD2D.cpp | 20 ++++++------------ Common/Gfx/TextFormatD2D.cpp | 41 ++++++++++++++++++++++++++++++++++++ Common/Gfx/TextFormatD2D.h | 9 ++++++++ 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Common/Gfx/CanvasD2D.cpp b/Common/Gfx/CanvasD2D.cpp index 80a3fbc9..20770035 100644 --- a/Common/Gfx/CanvasD2D.cpp +++ b/Common/Gfx/CanvasD2D.cpp @@ -278,21 +278,15 @@ void CanvasD2D::DrawTextW(const WCHAR* str, UINT strLen, const TextFormat& forma HRESULT hr = m_Target->CreateSolidColorBrush(ToColorF(color), &solidBrush); if (SUCCEEDED(hr)) { - const bool right = ((TextFormatD2D&)format).GetHorizontalAlignment() == Gfx::HorizontalAlignment::Right; + TextFormatD2D& formatD2D = (TextFormatD2D&)format; + const bool right = formatD2D.GetHorizontalAlignment() == Gfx::HorizontalAlignment::Right; - // TODO: Draw cached layout? - //m_Target->DrawTextLayout( - // D2D1::Point2F(right ? rect.X - 2 : rect.X + 2.0f, rect.Y - 1.0f), - // textLayout, - // solidBrush); + formatD2D.CreateLayout(str, strLen, rect.Width, rect.Height); - auto dst = D2D1::RectF( - right ? rect.X - 2 : rect.X + 2.0f, - rect.Y - 1.0f, - (right ? rect.X - 2 : rect.X + 2.0f) + rect.Width, - rect.Y + rect.Height - 1.0f); - - m_Target->DrawTextW(str, strLen, ((TextFormatD2D&)format).m_TextFormat, dst, solidBrush); + m_Target->DrawTextLayout( + D2D1::Point2F(right ? rect.X - 2 : rect.X + 2.0f, rect.Y - 1.0f), + formatD2D.m_TextLayout, + solidBrush); solidBrush->Release(); } diff --git a/Common/Gfx/TextFormatD2D.cpp b/Common/Gfx/TextFormatD2D.cpp index 04d4d40c..2dae6375 100644 --- a/Common/Gfx/TextFormatD2D.cpp +++ b/Common/Gfx/TextFormatD2D.cpp @@ -23,6 +23,7 @@ namespace Gfx { TextFormatD2D::TextFormatD2D() : m_TextFormat(), + m_TextLayout(), m_InlineEllipsis() { } @@ -40,6 +41,12 @@ void TextFormatD2D::Dispose() m_TextFormat = nullptr; } + if (m_TextLayout) + { + m_TextLayout->Release(); + m_TextLayout = nullptr; + } + if (m_InlineEllipsis) { m_InlineEllipsis->Release(); @@ -47,6 +54,40 @@ void TextFormatD2D::Dispose() } } +void TextFormatD2D::CreateLayout(const WCHAR* str, UINT strLen, float maxW, float maxH) +{ + bool strChanged = false; + if (strLen != m_LastString.length() || + memcmp(str, m_LastString.c_str(), (strLen + 1) * sizeof(WCHAR)) != 0) + { + strChanged = true; + m_LastString.assign(str, strLen); + } + + if (m_TextLayout && !strChanged) + { + if (maxW != m_TextLayout->GetMaxWidth()) + { + m_TextLayout->SetMaxWidth(maxW); + } + + if (maxH != m_TextLayout->GetMaxHeight()) + { + m_TextLayout->SetMaxWidth(maxH); + } + } + else + { + if (m_TextLayout) + { + m_TextLayout->Release(); + m_TextLayout = nullptr; + } + + CanvasD2D::c_DW->CreateTextLayout(str, strLen, m_TextFormat, maxW, maxH, &m_TextLayout); + } +} + void TextFormatD2D::SetProperties(const WCHAR* fontFamily, int size, bool bold, bool italic, Gdiplus::PrivateFontCollection* fontCollection) { Dispose(); diff --git a/Common/Gfx/TextFormatD2D.h b/Common/Gfx/TextFormatD2D.h index 10a0d769..7e44bf39 100644 --- a/Common/Gfx/TextFormatD2D.h +++ b/Common/Gfx/TextFormatD2D.h @@ -20,6 +20,7 @@ #define RM_GFX_TEXTFORMATD2D_H_ #include "TextFormat.h" +#include #include namespace Gfx { @@ -44,8 +45,16 @@ private: void Dispose(); + // Creates a new DirectWrite text layout if |str| has changed since last call. Since creating + // the layout is costly, it is more efficient to keep reusing the text layout until the text + // changes. + void CreateLayout(const WCHAR* str, UINT strLen, float maxW, float maxH); + IDWriteTextFormat* m_TextFormat; + IDWriteTextLayout* m_TextLayout; IDWriteInlineObject* m_InlineEllipsis; + + std::wstring m_LastString; }; } // namespace Gfx