From c174ba6a5690acc397eca572eb046c6aa6dec3da Mon Sep 17 00:00:00 2001 From: Michael Niksa Date: Fri, 18 Dec 2020 15:57:37 -0800 Subject: [PATCH 1/3] Use PMR allocator with a memory pool for PolyTextOut data since we're just going to use it again and again. --- src/inc/LibraryIncludes.h | 1 + src/renderer/gdi/gdirenderer.hpp | 7 +++++ src/renderer/gdi/paint.cpp | 45 ++++++++++++-------------------- src/renderer/gdi/state.cpp | 5 +++- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/inc/LibraryIncludes.h b/src/inc/LibraryIncludes.h index 1e2510f0690..d8eee81b734 100644 --- a/src/inc/LibraryIncludes.h +++ b/src/inc/LibraryIncludes.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/src/renderer/gdi/gdirenderer.hpp b/src/renderer/gdi/gdirenderer.hpp index 28f745039cd..3be272c185d 100644 --- a/src/renderer/gdi/gdirenderer.hpp +++ b/src/renderer/gdi/gdirenderer.hpp @@ -125,6 +125,13 @@ namespace Microsoft::Console::Render COLORREF _lastBg; bool _lastFontItalic; + // Memory pooling to save alloc/free work to the OS for things + // frequently created and dropped. + // It's important the pool is first so it can be given to the others on construction. + std::pmr::unsynchronized_pool_resource _pool; + std::pmr::vector _polyStrings; + std::pmr::vector> _polyWidths; + [[nodiscard]] HRESULT _InvalidCombine(const RECT* const prc) noexcept; [[nodiscard]] HRESULT _InvalidOffset(const POINT* const ppt) noexcept; [[nodiscard]] HRESULT _InvalidRestrict() noexcept; diff --git a/src/renderer/gdi/paint.cpp b/src/renderer/gdi/paint.cpp index 1e07be9521f..74e0dd7bab8 100644 --- a/src/renderer/gdi/paint.cpp +++ b/src/renderer/gdi/paint.cpp @@ -298,6 +298,7 @@ using namespace Microsoft::Console::Render; { try { + const auto cchLine = clusters.size(); // Exit early if there are no lines to draw. @@ -308,14 +309,12 @@ using namespace Microsoft::Console::Render; const auto pPolyTextLine = &_pPolyText[_cPolyText]; - auto pwsPoly = std::make_unique(cchLine); - RETURN_IF_NULL_ALLOC(pwsPoly); + auto& polyString = _polyStrings.emplace_back(cchLine, UNICODE_NULL); COORD const coordFontSize = _GetFontSize(); - auto rgdxPoly = std::make_unique(cchLine); - RETURN_IF_NULL_ALLOC(rgdxPoly); - + auto& polyWidth = _polyWidths.emplace_back(cchLine, 0); + // Sum up the total widths the entire line/run is expected to take while // copying the pixel widths into a structure to direct GDI how many pixels to use per character. size_t cchCharWidths = 0; @@ -327,9 +326,9 @@ using namespace Microsoft::Console::Render; // Our GDI renderer hasn't and isn't going to handle things above U+FFFF or sequences. // So replace anything complicated with a replacement character for drawing purposes. - pwsPoly[i] = cluster.GetTextAsSingle(); - rgdxPoly[i] = gsl::narrow(cluster.GetColumns()) * coordFontSize.X; - cchCharWidths += rgdxPoly[i]; + polyString[i] = cluster.GetTextAsSingle(); + polyWidth[i] = gsl::narrow(cluster.GetColumns()) * coordFontSize.X; + cchCharWidths += polyWidth[i]; } // Detect and convert for raster font... @@ -338,7 +337,7 @@ using namespace Microsoft::Console::Render; // dispatch conversion into our codepage // Find out the bytes required - int const cbRequired = WideCharToMultiByte(_fontCodepage, 0, pwsPoly.get(), (int)cchLine, nullptr, 0, nullptr, nullptr); + int const cbRequired = WideCharToMultiByte(_fontCodepage, 0, polyString.data(), (int)cchLine, nullptr, 0, nullptr, nullptr); if (cbRequired != 0) { @@ -346,7 +345,7 @@ using namespace Microsoft::Console::Render; auto psConverted = std::make_unique(cbRequired); // Attempt conversion to current codepage - int const cbConverted = WideCharToMultiByte(_fontCodepage, 0, pwsPoly.get(), (int)cchLine, psConverted.get(), cbRequired, nullptr, nullptr); + int const cbConverted = WideCharToMultiByte(_fontCodepage, 0, polyString.data(), (int)cchLine, psConverted.get(), cbRequired, nullptr, nullptr); // If successful... if (cbConverted != 0) @@ -356,22 +355,22 @@ using namespace Microsoft::Console::Render; if (cchRequired != 0) { - auto pwsConvert = std::make_unique(cchRequired); + std::pmr::wstring polyConvert(cchRequired, UNICODE_NULL, &_pool); // Then do the actual conversion. - int const cchConverted = MultiByteToWideChar(CP_ACP, 0, psConverted.get(), cbRequired, pwsConvert.get(), cchRequired); + int const cchConverted = MultiByteToWideChar(CP_ACP, 0, psConverted.get(), cbRequired, polyConvert.data(), cchRequired); if (cchConverted != 0) { // If all successful, use this instead. - pwsPoly.swap(pwsConvert); + polyString.swap(polyConvert); } } } } } - pPolyTextLine->lpstr = pwsPoly.release(); + pPolyTextLine->lpstr = polyString.data(); pPolyTextLine->n = gsl::narrow(clusters.size()); pPolyTextLine->x = ptDraw.x; pPolyTextLine->y = ptDraw.y; @@ -380,7 +379,7 @@ using namespace Microsoft::Console::Render; pPolyTextLine->rcl.top = pPolyTextLine->y; pPolyTextLine->rcl.right = pPolyTextLine->rcl.left + ((SHORT)cchCharWidths * coordFontSize.X); pPolyTextLine->rcl.bottom = pPolyTextLine->rcl.top + coordFontSize.Y; - pPolyTextLine->pdx = rgdxPoly.release(); + pPolyTextLine->pdx = polyWidth.data(); if (trimLeft) { @@ -417,20 +416,10 @@ using namespace Microsoft::Console::Render; hr = E_FAIL; } - for (size_t iPoly = 0; iPoly < _cPolyText; iPoly++) - { - if (nullptr != _pPolyText[iPoly].lpstr) - { - delete[] _pPolyText[iPoly].lpstr; - _pPolyText[iPoly].lpstr = nullptr; - } + _polyStrings.clear(); + _polyWidths.clear(); - if (nullptr != _pPolyText[iPoly].pdx) - { - delete[] _pPolyText[iPoly].pdx; - _pPolyText[iPoly].pdx = nullptr; - } - } + ZeroMemory(_pPolyText, sizeof(_pPolyText)); _cPolyText = 0; } diff --git a/src/renderer/gdi/state.cpp b/src/renderer/gdi/state.cpp index fd03bb45ad4..807c503256b 100644 --- a/src/renderer/gdi/state.cpp +++ b/src/renderer/gdi/state.cpp @@ -32,7 +32,10 @@ GdiEngine::GdiEngine() : _lastFontItalic(false), _fPaintStarted(false), _hfont(nullptr), - _hfontItalic(nullptr) + _hfontItalic(nullptr), + _pool{}, // It's important the pool is first so it can be given to the others on construction. + _polyStrings{&_pool}, + _polyWidths{&_pool} { ZeroMemory(_pPolyText, sizeof(POLYTEXTW) * s_cPolyTextCache); _rcInvalid = { 0 }; From a580c2f7004e7175b5868583422876e10c0d464d Mon Sep 17 00:00:00 2001 From: Michael Niksa Date: Fri, 18 Dec 2020 16:31:24 -0800 Subject: [PATCH 2/3] PMR is an API in the STL. Add to spellcheck. --- .github/actions/spell-check/dictionary/apis.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spell-check/dictionary/apis.txt b/.github/actions/spell-check/dictionary/apis.txt index 627ddbf0875..bed8cb26ead 100644 --- a/.github/actions/spell-check/dictionary/apis.txt +++ b/.github/actions/spell-check/dictionary/apis.txt @@ -56,6 +56,7 @@ otms OUTLINETEXTMETRICW overridable PAGESCROLL +pmr RETURNCMD rfind roundf From 725f441f346adc58587dd0b09e3e1ed905d4944f Mon Sep 17 00:00:00 2001 From: Michael Niksa Date: Fri, 18 Dec 2020 16:40:03 -0800 Subject: [PATCH 3/3] Code format! --- src/renderer/gdi/paint.cpp | 3 +-- src/renderer/gdi/state.cpp | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/renderer/gdi/paint.cpp b/src/renderer/gdi/paint.cpp index 74e0dd7bab8..0885b975572 100644 --- a/src/renderer/gdi/paint.cpp +++ b/src/renderer/gdi/paint.cpp @@ -298,7 +298,6 @@ using namespace Microsoft::Console::Render; { try { - const auto cchLine = clusters.size(); // Exit early if there are no lines to draw. @@ -314,7 +313,7 @@ using namespace Microsoft::Console::Render; COORD const coordFontSize = _GetFontSize(); auto& polyWidth = _polyWidths.emplace_back(cchLine, 0); - + // Sum up the total widths the entire line/run is expected to take while // copying the pixel widths into a structure to direct GDI how many pixels to use per character. size_t cchCharWidths = 0; diff --git a/src/renderer/gdi/state.cpp b/src/renderer/gdi/state.cpp index 807c503256b..30268b47fa9 100644 --- a/src/renderer/gdi/state.cpp +++ b/src/renderer/gdi/state.cpp @@ -34,8 +34,8 @@ GdiEngine::GdiEngine() : _hfont(nullptr), _hfontItalic(nullptr), _pool{}, // It's important the pool is first so it can be given to the others on construction. - _polyStrings{&_pool}, - _polyWidths{&_pool} + _polyStrings{ &_pool }, + _polyWidths{ &_pool } { ZeroMemory(_pPolyText, sizeof(POLYTEXTW) * s_cPolyTextCache); _rcInvalid = { 0 };