diff --git a/NOTICE.md b/NOTICE.md index 5c153f6ab63..5a44327592d 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -276,6 +276,41 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` +## xxHash + +**Source**: [https://github.com/Cyan4973/xxHash](https://github.com/Cyan4973/xxHash) + +### License + +``` +xxHash Library +Copyright (c) 2012-2020 Yann Collet +All rights reserved. + +BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` + ## ConEmu **Source**: [https://github.com/Maximus5/ConEmu](https://github.com/Maximus5/ConEmu) diff --git a/oss/xxhash/MAINTAINER_README.md b/oss/xxhash/MAINTAINER_README.md new file mode 100644 index 00000000000..00ecf4b065b --- /dev/null +++ b/oss/xxhash/MAINTAINER_README.md @@ -0,0 +1,3 @@ +### Notes for Future Maintainers + +At the time of writing xxHash (specifically XXH3) is only used in a modified form for the function `AtlasEngine::XXH3_len_32_64b`. diff --git a/oss/xxhash/cgmanifest.json b/oss/xxhash/cgmanifest.json new file mode 100644 index 00000000000..57b4514df07 --- /dev/null +++ b/oss/xxhash/cgmanifest.json @@ -0,0 +1,13 @@ +{"Registrations":[ + { + "component": { + "type": "git", + "git": { + "repositoryUrl": "hhttps://github.com/Cyan4973/xxHash", + "commitHash": "9058687747c533a2fea7215fd72346e756da2034" + } + } + } + ], + "Version": 1 +} diff --git a/src/cascadia/TerminalSettingsEditor/Profiles.xaml b/src/cascadia/TerminalSettingsEditor/Profiles.xaml index 46655ab1486..c860578aa2b 100644 --- a/src/cascadia/TerminalSettingsEditor/Profiles.xaml +++ b/src/cascadia/TerminalSettingsEditor/Profiles.xaml @@ -483,7 +483,7 @@ ClearSettingValue="{x:Bind State.Profile.ClearUseAtlasEngine}" HasSettingValue="{x:Bind State.Profile.HasUseAtlasEngine, Mode=OneWay}" SettingOverrideSource="{x:Bind State.Profile.UseAtlasEngineOverrideSource, Mode=OneWay}" - Visibility="{x:Bind State.Profile.EditableUnfocusedAppearance}"> + Visibility="{x:Bind State.Profile.AtlasEngineAvailable}"> diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h index 0d726318130..4d4686af368 100644 --- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h +++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h @@ -125,7 +125,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation INHERITABLE_SETTING(Model::TerminalSettings, hstring, FontFace, DEFAULT_FONT_FACE); INHERITABLE_SETTING(Model::TerminalSettings, int32_t, FontSize, DEFAULT_FONT_SIZE); - INHERITABLE_SETTING(Model::TerminalSettings, winrt::Windows::UI::Text::FontWeight, FontWeight, DEFAULT_FONT_WEIGHT); + INHERITABLE_SETTING(Model::TerminalSettings, winrt::Windows::UI::Text::FontWeight, FontWeight); INHERITABLE_SETTING(Model::TerminalSettings, IFontAxesMap, FontAxes); INHERITABLE_SETTING(Model::TerminalSettings, IFontFeatureMap, FontFeatures); diff --git a/src/host/exe/Host.EXE.vcxproj b/src/host/exe/Host.EXE.vcxproj index 60b6628197e..c21bb27c8a2 100644 --- a/src/host/exe/Host.EXE.vcxproj +++ b/src/host/exe/Host.EXE.vcxproj @@ -43,12 +43,12 @@ {af0a096a-8b3a-4949-81ef-7df8f0fee91f} - - {48d21369-3d7b-4431-9967-24e81292cf62} - {8222900C-8B6C-452A-91AC-BE95DB04B95F} + + {48d21369-3d7b-4431-9967-24e81292cf62} + {1c959542-bac2-4e55-9a6d-13251914cbb9} diff --git a/src/host/ft_fuzzer/Host.FuzzWrapper.vcxproj b/src/host/ft_fuzzer/Host.FuzzWrapper.vcxproj index e351317812f..8486a9e4894 100644 --- a/src/host/ft_fuzzer/Host.FuzzWrapper.vcxproj +++ b/src/host/ft_fuzzer/Host.FuzzWrapper.vcxproj @@ -38,6 +38,9 @@ {af0a096a-8b3a-4949-81ef-7df8f0fee91f} + + {8222900C-8B6C-452A-91AC-BE95DB04B95F} + {48d21369-3d7b-4431-9967-24e81292cf62} @@ -71,6 +74,7 @@ ..;%(AdditionalIncludeDirectories) + winmm.lib;%(AdditionalDependencies) Console diff --git a/src/host/ft_host/CJK_DbcsTests.cpp b/src/host/ft_host/CJK_DbcsTests.cpp index 4b86120042b..c6b150069bb 100644 --- a/src/host/ft_host/CJK_DbcsTests.cpp +++ b/src/host/ft_host/CJK_DbcsTests.cpp @@ -2320,9 +2320,6 @@ void ReadStringWithReadConsoleInputAHelper(HANDLE hIn, PCSTR pszExpectedText, si while (cchRead < cchExpectedText) { - // expected read is either the size of the buffer or the number of characters remaining, whichever is smaller. - DWORD const dwReadExpected = (DWORD)std::min(cbBuffer, cchExpectedText - cchRead); - DWORD dwRead; if (!VERIFY_WIN32_BOOL_SUCCEEDED(ReadConsoleInputA(hIn, irRead, (DWORD)cbBuffer, &dwRead), L"Attempt to read input into buffer.")) { diff --git a/src/host/getset.cpp b/src/host/getset.cpp index 6203aef0e54..5ee114e6d82 100644 --- a/src/host/getset.cpp +++ b/src/host/getset.cpp @@ -274,7 +274,8 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept const FontInfo& fontInfo = activeScreenInfo.GetCurrentFont(); consoleFontInfoEx.FontFamily = fontInfo.GetFamily(); consoleFontInfoEx.FontWeight = fontInfo.GetWeight(); - fontInfo.FillLegacyNameBuffer(consoleFontInfoEx.FaceName); + + RETURN_IF_FAILED(fontInfo.FillLegacyNameBuffer(gsl::make_span(consoleFontInfoEx.FaceName))); return S_OK; } diff --git a/src/host/selection.cpp b/src/host/selection.cpp index 90bb5668f3e..7814bfae9c9 100644 --- a/src/host/selection.cpp +++ b/src/host/selection.cpp @@ -255,14 +255,6 @@ void Selection::ExtendSelection(_In_ COORD coordBufferPos) srNewSelection.Top = _coordSelectionAnchor.Y; } - // This function is called on WM_MOUSEMOVE. - // Prevent triggering an invalidation just because the mouse moved - // in the same cell without changing the actual (visible) selection. - if (_srSelectionRect == srNewSelection) - { - return; - } - // call special update method to modify the displayed selection in-place // NOTE: Using HideSelection, editing the rectangle, then ShowSelection will cause flicker. //_PaintUpdateSelection(&srNewSelection); diff --git a/src/host/settings.cpp b/src/host/settings.cpp index 75b34a235c5..2d224af5813 100644 --- a/src/host/settings.cpp +++ b/src/host/settings.cpp @@ -815,7 +815,9 @@ void Settings::SetTerminalScrolling(const bool terminalScrollingEnabled) noexcep // - Determines whether our primary renderer should be DirectX or GDI. // - This is based on user preference and velocity hold back state. // Return Value: -// - True means use DirectX renderer. False means use GDI renderer. +// - case 1: DxEngine +// - case 2: AtlasEngine +// - default: GdiEngine DWORD Settings::GetUseDx() const noexcept { return _fUseDx; diff --git a/src/host/ut_host/Host.UnitTests.vcxproj b/src/host/ut_host/Host.UnitTests.vcxproj index 486965b2fb9..6b5bedf1b11 100644 --- a/src/host/ut_host/Host.UnitTests.vcxproj +++ b/src/host/ut_host/Host.UnitTests.vcxproj @@ -52,6 +52,9 @@ {ef3e32a7-5ff6-42b4-b6e2-96cd7d033f00} + + {8222900C-8B6C-452A-91AC-BE95DB04B95F} + {48d21369-3d7b-4431-9967-24e81292cf62} diff --git a/src/interactivity/win32/ut_interactivity_win32/Interactivity.Win32.UnitTests.vcxproj b/src/interactivity/win32/ut_interactivity_win32/Interactivity.Win32.UnitTests.vcxproj index 2330bee3aa6..fa2fa30b086 100644 --- a/src/interactivity/win32/ut_interactivity_win32/Interactivity.Win32.UnitTests.vcxproj +++ b/src/interactivity/win32/ut_interactivity_win32/Interactivity.Win32.UnitTests.vcxproj @@ -22,6 +22,9 @@ {ef3e32a7-5ff6-42b4-b6e2-96cd7d033f00} + + {8222900C-8B6C-452A-91AC-BE95DB04B95F} + {48d21369-3d7b-4431-9967-24e81292cf62} @@ -76,4 +79,4 @@ - \ No newline at end of file + diff --git a/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp b/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp index 99ae12628ab..518dc87473f 100644 --- a/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp +++ b/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp @@ -735,7 +735,6 @@ class UiaTextRangeTests TEST_METHOD(CanMoveByCharacter) { const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().RightInclusive(); - const SHORT bottomRow = gsl::narrow(_pTextBuffer->TotalRowCount() - 1); // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. @@ -824,7 +823,6 @@ class UiaTextRangeTests TEST_METHOD(CanMoveByLine) { const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; - const SHORT bottomRow = gsl::narrow(_pTextBuffer->TotalRowCount() - 1); // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. @@ -913,7 +911,6 @@ class UiaTextRangeTests TEST_METHOD(CanMoveEndpointByUnitCharacter) { const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; - const SHORT bottomRow = static_cast(_pTextBuffer->TotalRowCount() - 1); // GH#6986: This is used as the "end of the buffer" to help screen readers run faster // instead of parsing through thousands of empty lines of text. @@ -1197,7 +1194,6 @@ class UiaTextRangeTests TEST_METHOD(CanMoveEndpointByUnitDocument) { - const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; const SHORT bottomRow = gsl::narrow(_pTextBuffer->TotalRowCount() - 1); // GH#6986: This is used as the "end of the buffer" to help screen readers run faster diff --git a/src/interactivity/win32/window.cpp b/src/interactivity/win32/window.cpp index 48f93912c86..59db497a208 100644 --- a/src/interactivity/win32/window.cpp +++ b/src/interactivity/win32/window.cpp @@ -26,8 +26,10 @@ #include "../../renderer/base/renderer.hpp" #include "../../renderer/gdi/gdirenderer.hpp" -#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED +#if TIL_FEATURE_ATLASENGINE_ENABLED #include "../../renderer/atlas/AtlasEngine.h" +#endif +#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED #include "../../renderer/dx/DxRenderer.hpp" #endif @@ -211,6 +213,8 @@ void Window::_UpdateSystemMetrics() const GdiEngine* pGdiEngine = nullptr; #if TIL_FEATURE_CONHOSTDXENGINE_ENABLED DxEngine* pDxEngine = nullptr; +#endif +#if TIL_FEATURE_ATLASENGINE_ENABLED AtlasEngine* pAtlasEngine = nullptr; #endif try @@ -228,6 +232,8 @@ void Window::_UpdateSystemMetrics() const THROW_IF_FAILED(pDxEngine->SetHwnd(nullptr)); g.pRender->AddRenderEngine(pDxEngine); break; +#endif +#if TIL_FEATURE_ATLASENGINE_ENABLED case 2: pAtlasEngine = new AtlasEngine(); g.pRender->AddRenderEngine(pAtlasEngine); @@ -333,7 +339,10 @@ void Window::_UpdateSystemMetrics() const status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pDxEngine->Enable()))); } } - else if (pAtlasEngine) + else +#endif +#if TIL_FEATURE_ATLASENGINE_ENABLED + if (pAtlasEngine) { status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pAtlasEngine->SetHwnd(hWnd)))); } diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp index f8dc60341f2..b8a13fa231d 100644 --- a/src/renderer/atlas/AtlasEngine.api.cpp +++ b/src/renderer/atlas/AtlasEngine.api.cpp @@ -40,7 +40,7 @@ constexpr HRESULT vec2_narrow(U x, U y, AtlasEngine::vec2& out) noexcept [[nodiscard]] HRESULT AtlasEngine::Invalidate(const SMALL_RECT* const psrRegion) noexcept { - assert(psrRegion->Top <= psrRegion->Bottom && psrRegion->Top >= 0 && psrRegion->Bottom <= _api.cellCount.y); + assert(psrRegion->Top < psrRegion->Bottom && psrRegion->Top >= 0 && psrRegion->Bottom <= _api.cellCount.y); // BeginPaint() protects against invalid out of bounds numbers. _api.invalidatedRows.x = std::min(_api.invalidatedRows.x, gsl::narrow_cast(psrRegion->Top)); @@ -173,10 +173,24 @@ constexpr HRESULT vec2_narrow(U x, U y, AtlasEngine::vec2& out) noexcept [[nodiscard]] HRESULT AtlasEngine::GetProposedFont(const FontInfoDesired& fontInfoDesired, _Out_ FontInfo& fontInfo, const int dpi) noexcept try { - const auto& requestedFaceName = fontInfoDesired.GetFaceName(); + const wchar_t* requestedFaceName = fontInfoDesired.GetFaceName().data(); const auto requestedFamily = fontInfoDesired.GetFamily(); - const auto requestedWeight = fontInfoDesired.GetWeight(); - const auto requestedSize = fontInfoDesired.GetEngineSize(); + auto requestedWeight = fontInfoDesired.GetWeight(); + auto requestedSize = fontInfoDesired.GetEngineSize(); + + if (!requestedFaceName) + { + requestedFaceName = L"Consolas"; + } + if (!requestedWeight) + { + requestedWeight = DWRITE_FONT_WEIGHT_NORMAL; + } + if (!requestedSize.Y) + { + requestedSize = { 0, 16 }; + } + std::wstring faceNameBuffer; std::wstring_view resultingFaceName = requestedFaceName; COORD resultingCellSize{}; @@ -237,7 +251,7 @@ try #endif { wil::com_ptr textFormat; - THROW_IF_FAILED(_createTextFormat(requestedFaceName.c_str(), static_cast(requestedWeight), DWRITE_FONT_STYLE_NORMAL, requestedSize.Y, textFormat.addressof())); + THROW_IF_FAILED(_createTextFormat(requestedFaceName, static_cast(requestedWeight), DWRITE_FONT_STYLE_NORMAL, requestedSize.Y, textFormat.addressof())); wil::com_ptr textLayout; THROW_IF_FAILED(_sr.dwriteFactory->CreateTextLayout(L"M", 1, textFormat.get(), FLT_MAX, FLT_MAX, textLayout.addressof())); diff --git a/src/renderer/atlas/AtlasEngine.cpp b/src/renderer/atlas/AtlasEngine.cpp index 2ca384f9d6a..40aae390dfa 100644 --- a/src/renderer/atlas/AtlasEngine.cpp +++ b/src/renderer/atlas/AtlasEngine.cpp @@ -4,6 +4,7 @@ #include "pch.h" #include "AtlasEngine.h" +#include #include #include @@ -48,6 +49,17 @@ struct TextAnalyzer final : IDWriteTextAnalysisSource, IDWriteTextAnalysisSink Ensures(_text.size() <= UINT32_MAX); } +#ifndef NDEBUG +private: + ULONG _refCount = 1; + +public: + ~TextAnalyzer() + { + assert(_refCount == 1); + } +#endif + HRESULT __stdcall QueryInterface(const IID& riid, void** ppvObject) noexcept override { __assume(ppvObject != nullptr); @@ -64,14 +76,20 @@ struct TextAnalyzer final : IDWriteTextAnalysisSource, IDWriteTextAnalysisSink ULONG __stdcall AddRef() noexcept override { - assert(false); +#ifdef NDEBUG return 1; +#else + return ++_refCount; +#endif } ULONG __stdcall Release() noexcept override { - assert(false); +#ifdef NDEBUG return 1; +#else + return --_refCount; +#endif } HRESULT __stdcall GetTextAtPosition(UINT32 textPosition, const WCHAR** textString, UINT32* textLength) noexcept override @@ -209,18 +227,19 @@ try } WI_ClearAllFlags(_invalidations, InvalidationFlags::device | InvalidationFlags::size | InvalidationFlags::font | InvalidationFlags::settings); - std::ignore = InvalidateAll(); + _api.invalidatedRows = invalidatedRowsAll; } - // Clamp invalidation rects into valid value ranges. if (_api.invalidatedRows == invalidatedRowsAll) { + // Skip all the partial updates, since we redraw everything anyways. _api.invalidatedCursorArea = invalidatedAreaNone; _api.invalidatedRows = { 0, _api.cellCount.y }; _api.scrollOffset = 0; } else { + // Clamp invalidation rects into valid value ranges. { _api.invalidatedCursorArea.left = std::min(_api.invalidatedCursorArea.left, _api.cellCount.x); _api.invalidatedCursorArea.top = std::min(_api.invalidatedCursorArea.top, _api.cellCount.y); @@ -235,50 +254,50 @@ try const auto limit = gsl::narrow_cast(_api.cellCount.y & 0x7fff); _api.scrollOffset = clamp(_api.scrollOffset, -limit, limit); } - } - - // Scroll the buffer by the given offset and mark the newly uncovered rows as "invalid". - if (_api.scrollOffset != 0) - { - const auto data = _r.cells.data(); - auto count = _r.cells.size(); - const auto offset = static_cast(_api.scrollOffset) * _api.cellCount.x; - Cell* dst; - Cell* src; - if (_api.scrollOffset < 0) - { - // Scroll up (for instance when new text is being written at the end of the buffer). - dst = data; - src = data - offset; - count += offset; - _api.invalidatedRows.x = std::min(_api.invalidatedRows.x, _api.cellCount.y + _api.scrollOffset); - _api.invalidatedRows.y = _api.cellCount.y; - } - else + // Scroll the buffer by the given offset and mark the newly uncovered rows as "invalid". + if (_api.scrollOffset != 0) { - // Scroll down. - dst = data + offset; - src = data; - count -= offset; - _api.invalidatedRows.x = 0; - _api.invalidatedRows.y = std::max(_api.invalidatedRows.y, _api.scrollOffset); - } + const auto nothingInvalid = _api.invalidatedRows.x == _api.invalidatedRows.y; + const auto offset = static_cast(_api.scrollOffset) * _api.cellCount.x; + const auto data = _r.cells.data(); + auto count = _r.cells.size(); + Cell* dst; + Cell* src; + + if (_api.scrollOffset < 0) + { + // Scroll up (for instance when new text is being written at the end of the buffer). + dst = data; + src = data - offset; + count += offset; + + const u16 endRow = _api.cellCount.y + _api.scrollOffset; + _api.invalidatedRows.x = nothingInvalid ? endRow : std::min(_api.invalidatedRows.x, endRow); + _api.invalidatedRows.y = _api.cellCount.y; + } + else + { + // Scroll down. + dst = data + offset; + src = data; + count -= offset; - memmove(dst, src, count * sizeof(Cell)); - } + _api.invalidatedRows.x = 0; + _api.invalidatedRows.y = nothingInvalid ? _api.scrollOffset : std::max(_api.invalidatedRows.y, _api.scrollOffset); + } - { - // _api.dirtyRect is an inclusive rectangle, whereas _api.invalidatedRows is an exclusive range. - // --> We need to subtract 1 from the bottom row index. - // However .x could be equal to .y (for instance both could be 0), so we - // need to ensure top isn't greater than bottom after the subtraction. - const auto right = static_cast(_api.cellCount.x); - const auto bottom = static_cast(_api.invalidatedRows.y); - const auto top = static_cast(_api.invalidatedRows.x); - _api.dirtyRect = til::rectangle{ 0u, top, right, bottom }; + memmove(dst, src, count * sizeof(Cell)); + } } + _api.dirtyRect = til::rectangle{ + static_cast(0), + static_cast(_api.invalidatedRows.x), + static_cast(_api.cellCount.x), + static_cast(_api.invalidatedRows.y), + }; + return S_OK; } catch (const wil::ResultException& exception) @@ -411,7 +430,7 @@ try // # What do we want? // // Segment a line of text (_api.bufferLine) into unicode "clusters". - // Each cluster is one "whole" glyph with diacritics, ligatures, zero-width-joiners + // Each cluster is one "whole" glyph with diacritics, ligatures, zero width joiners // and whatever else, that should be cached as a whole in our texture atlas. // // # How do we get that? @@ -425,7 +444,7 @@ try // // ## The actual approach // - // DirectWrite has 2 APIs which can segment text properly (including ligatures and zero width joiner for instance): + // DirectWrite has 2 APIs which can segment text properly (including ligatures and zero width joiners): // * IDWriteTextAnalyzer1::GetTextComplexity // * IDWriteTextAnalyzer::GetGlyphs // @@ -619,57 +638,6 @@ CATCH_RETURN() #pragma endregion -#pragma region Helper classes - -// XXH3 for exactly 32 bytes. -uint64_t AtlasEngine::XXH3_len_32_64b(const void* data) noexcept -{ - static constexpr uint64_t dataSize = 32; - static constexpr auto XXH3_mul128_fold64 = [](uint64_t lhs, uint64_t rhs) noexcept { - uint64_t lo, hi; - -#if defined(_M_AMD64) - lo = _umul128(lhs, rhs, &hi); -#elif defined(_M_ARM64) - lo = lhs * rhs; - hi = __umulh(lhs, rhs); -#else - const uint64_t lo_lo = __emulu(lhs, rhs); - const uint64_t hi_lo = __emulu(lhs >> 32, rhs); - const uint64_t lo_hi = __emulu(lhs, rhs >> 32); - const uint64_t hi_hi = __emulu(lhs >> 32, rhs >> 32); - const uint64_t cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; - hi = (hi_lo >> 32) + (cross >> 32) + hi_hi; - lo = (cross << 32) | (lo_lo & 0xFFFFFFFF); -#endif - - return lo ^ hi; - }; - - // If executed on little endian CPUs these 4 numbers will - // equal the first 32 byte of the original XXH3_kSecret. - static constexpr uint64_t XXH3_kSecret[4] = { - UINT64_C(0xbe4ba423396cfeb8), - UINT64_C(0x1cad21f72c81017c), - UINT64_C(0xdb979083e96dd4de), - UINT64_C(0x1f67b3b7a4a44072), - }; - - uint64_t inputs[4]; - memcpy(&inputs[0], data, 32); - -#pragma warning(suppress : 26450) // Arithmetic overflow: '*' operation causes overflow at compile time. Use a wider type to store the operands (io.1). - uint64_t acc = dataSize * UINT64_C(0x9E3779B185EBCA87); - acc += XXH3_mul128_fold64(inputs[0] ^ XXH3_kSecret[0], inputs[1] ^ XXH3_kSecret[1]); - acc += XXH3_mul128_fold64(inputs[2] ^ XXH3_kSecret[2], inputs[3] ^ XXH3_kSecret[3]); - acc = acc ^ (acc >> 37); - acc *= UINT64_C(0x165667919E3779F9); - acc = acc ^ (acc >> 32); - return acc; -} - -#pragma endregion - [[nodiscard]] HRESULT AtlasEngine::_handleException(const wil::ResultException& exception) noexcept { const auto hr = exception.GetErrorCode(); @@ -696,21 +664,25 @@ void AtlasEngine::_createResources() #ifndef NDEBUG // DXGI debug messages + enabling D3D11_CREATE_DEVICE_DEBUG if the Windows SDK was installed. - if (const wil::unique_hmodule module{ LoadLibraryExW(L"dxgidebug.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) }) + if (const wil::unique_hmodule module{ LoadLibraryExW(L"dxgi.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) }) { deviceFlags |= D3D11_CREATE_DEVICE_DEBUG; - const auto DXGIGetDebugInterface = reinterpret_cast(GetProcAddress(module.get(), "DXGIGetDebugInterface")); - THROW_LAST_ERROR_IF(!DXGIGetDebugInterface); - - wil::com_ptr infoQueue; - if (SUCCEEDED(DXGIGetDebugInterface(IID_PPV_ARGS(infoQueue.addressof())))) + if (const auto DXGIGetDebugInterface1 = GetProcAddressByFunctionDeclaration(module.get(), DXGIGetDebugInterface1)) { - // I didn't want to link with dxguid.lib just for getting DXGI_DEBUG_ALL. This GUID is publicly documented. - static constexpr GUID dxgiDebguAll = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x8 } }; - for (const auto severity : std::array{ DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING }) + if (wil::com_ptr infoQueue; SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(infoQueue.addressof())))) + { + // I didn't want to link with dxguid.lib just for getting DXGI_DEBUG_ALL. This GUID is publicly documented. + static constexpr GUID dxgiDebugAll = { 0xe48ae283, 0xda80, 0x490b, { 0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x8 } }; + for (const auto severity : std::array{ DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING }) + { + infoQueue->SetBreakOnSeverity(dxgiDebugAll, severity, true); + } + } + + if (wil::com_ptr debug; SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(debug.addressof())))) { - infoQueue->SetBreakOnSeverity(dxgiDebguAll, severity, true); + debug->EnableLeakTrackingForThread(); } } } diff --git a/src/renderer/atlas/AtlasEngine.h b/src/renderer/atlas/AtlasEngine.h index 797a8fae8fb..4c24d16f1e5 100644 --- a/src/renderer/atlas/AtlasEngine.h +++ b/src/renderer/atlas/AtlasEngine.h @@ -105,6 +105,7 @@ namespace Microsoft::Console::Render constexpr vec2 operator/(const vec2& rhs) noexcept { + assert(rhs.x != 0 && rhs.y != 0); return { gsl::narrow_cast(x / rhs.x), gsl::narrow_cast(y / rhs.y) }; } }; @@ -409,7 +410,7 @@ namespace Microsoft::Console::Render wil::unique_process_heap_string fontName; // changes are flagged as InvalidationFlags::font|size u16 fontSize = 0; // changes are flagged as InvalidationFlags::font|size - u16 fontWeight = DWRITE_FONT_WEIGHT_NORMAL; // changes are flagged as InvalidationFlags::font + u16 fontWeight = 0; // changes are flagged as InvalidationFlags::font u16 dpi = USER_DEFAULT_SCREEN_DPI; // changes are flagged as InvalidationFlags::font|size u16 antialiasingMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; // changes are flagged as InvalidationFlags::font diff --git a/src/renderer/atlas/AtlasEngine.xxh.cpp b/src/renderer/atlas/AtlasEngine.xxh.cpp new file mode 100644 index 00000000000..44ef277b8e2 --- /dev/null +++ b/src/renderer/atlas/AtlasEngine.xxh.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "pch.h" +#include "AtlasEngine.h" + +using namespace Microsoft::Console::Render; + +// XXH3 for exactly 32 bytes. +uint64_t AtlasEngine::XXH3_len_32_64b(const void* data) noexcept +{ + static constexpr uint64_t dataSize = 32; + static constexpr auto XXH3_mul128_fold64 = [](uint64_t lhs, uint64_t rhs) noexcept { + uint64_t lo, hi; + +#if defined(_M_AMD64) + lo = _umul128(lhs, rhs, &hi); +#elif defined(_M_ARM64) + lo = lhs * rhs; + hi = __umulh(lhs, rhs); +#else +// Implemented as a macro as MSVC tends to call __allmul otherwise. +#define XXH_mult32to64(x, y) __emulu(gsl::narrow_cast(x), gsl::narrow_cast(y)) + const uint64_t lo_lo = XXH_mult32to64(lhs, rhs); + const uint64_t hi_lo = XXH_mult32to64(lhs >> 32, rhs); + const uint64_t lo_hi = XXH_mult32to64(lhs, rhs >> 32); + const uint64_t hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); + const uint64_t cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; + hi = (hi_lo >> 32) + (cross >> 32) + hi_hi; + lo = (cross << 32) | (lo_lo & 0xFFFFFFFF); +#undef XXH_mult32to64 +#endif + + return lo ^ hi; + }; + + // If executed on little endian CPUs these 4 numbers will + // equal the first 32 byte of the original XXH3_kSecret. + static constexpr uint64_t XXH3_kSecret[4] = { + UINT64_C(0xbe4ba423396cfeb8), + UINT64_C(0x1cad21f72c81017c), + UINT64_C(0xdb979083e96dd4de), + UINT64_C(0x1f67b3b7a4a44072), + }; + + uint64_t inputs[4]; + memcpy(&inputs[0], data, 32); + +#pragma warning(suppress : 26450) // Arithmetic overflow: '*' operation causes overflow at compile time. Use a wider type to store the operands (io.1). + uint64_t acc = dataSize * UINT64_C(0x9E3779B185EBCA87); + acc += XXH3_mul128_fold64(inputs[0] ^ XXH3_kSecret[0], inputs[1] ^ XXH3_kSecret[1]); + acc += XXH3_mul128_fold64(inputs[2] ^ XXH3_kSecret[2], inputs[3] ^ XXH3_kSecret[3]); + acc = acc ^ (acc >> 37); + acc *= UINT64_C(0x165667919E3779F9); + acc = acc ^ (acc >> 32); + return acc; +} diff --git a/src/renderer/atlas/atlas.vcxproj b/src/renderer/atlas/atlas.vcxproj index 1e51a34efbe..7b50a8888c7 100644 --- a/src/renderer/atlas/atlas.vcxproj +++ b/src/renderer/atlas/atlas.vcxproj @@ -12,6 +12,7 @@ + Create diff --git a/src/renderer/base/FontInfoBase.cpp b/src/renderer/base/FontInfoBase.cpp index d4ceb74e8a9..40891cf4940 100644 --- a/src/renderer/base/FontInfoBase.cpp +++ b/src/renderer/base/FontInfoBase.cpp @@ -43,7 +43,7 @@ FontInfoBase::~FontInfoBase() { } -unsigned char FontInfoBase::GetFamily() const noexcept +unsigned char FontInfoBase::GetFamily() const { return _family; } @@ -51,22 +51,22 @@ unsigned char FontInfoBase::GetFamily() const noexcept // When the default raster font is forced set from the engine, this is how we differentiate it from a simple apply. // Default raster font is internally represented as a blank face name and zeros for weight, family, and size. This is // the hint for the engine to use whatever comes back from GetStockObject(OEM_FIXED_FONT) (at least in the GDI world). -bool FontInfoBase::WasDefaultRasterSetFromEngine() const noexcept +bool FontInfoBase::WasDefaultRasterSetFromEngine() const { return _fDefaultRasterSetFromEngine; } -unsigned int FontInfoBase::GetWeight() const noexcept +unsigned int FontInfoBase::GetWeight() const { return _weight; } -const std::wstring& FontInfoBase::GetFaceName() const noexcept +const std::wstring_view FontInfoBase::GetFaceName() const noexcept { return _faceName; } -unsigned int FontInfoBase::GetCodePage() const noexcept +unsigned int FontInfoBase::GetCodePage() const { return _codePage; } @@ -77,7 +77,7 @@ unsigned int FontInfoBase::GetCodePage() const noexcept // Arguments: // - buffer: the buffer into which to copy characters // - size: the size of buffer -HRESULT FontInfoBase::FillLegacyNameBuffer(gsl::span buffer) const noexcept +HRESULT FontInfoBase::FillLegacyNameBuffer(gsl::span buffer) const try { auto toCopy = std::min(buffer.size() - 1, _faceName.size()); @@ -91,7 +91,7 @@ CATCH_RETURN(); void FontInfoBase::SetFromEngine(const std::wstring_view faceName, const unsigned char family, const unsigned int weight, - const bool fSetDefaultRasterFont) noexcept + const bool fSetDefaultRasterFont) { _faceName = faceName; _family = family; @@ -101,12 +101,12 @@ void FontInfoBase::SetFromEngine(const std::wstring_view faceName, // Internally, default raster font is represented by empty facename, and zeros for weight, family, and size. Since // FontInfoBase doesn't have sizing information, this helper checks everything else. -bool FontInfoBase::IsDefaultRasterFontNoSize() const noexcept +bool FontInfoBase::IsDefaultRasterFontNoSize() const { return (_weight == 0 && _family == 0 && _faceName.empty()); } -void FontInfoBase::ValidateFont() noexcept +void FontInfoBase::ValidateFont() { // If we were given a blank name, it meant raster fonts, which to us is always Terminal. if (!IsDefaultRasterFontNoSize() && s_pFontDefaultList != nullptr) @@ -128,7 +128,7 @@ void FontInfoBase::ValidateFont() noexcept } } -bool FontInfoBase::IsTrueTypeFont() const noexcept +bool FontInfoBase::IsTrueTypeFont() const { return WI_IsFlagSet(_family, TMPF_TRUETYPE); } diff --git a/src/renderer/base/FontInfoDesired.cpp b/src/renderer/base/FontInfoDesired.cpp index a3741bb4cf3..c293d141a40 100644 --- a/src/renderer/base/FontInfoDesired.cpp +++ b/src/renderer/base/FontInfoDesired.cpp @@ -11,7 +11,7 @@ bool operator==(const FontInfoDesired& a, const FontInfoDesired& b) a._coordSizeDesired == b._coordSizeDesired); } -COORD FontInfoDesired::GetEngineSize() const noexcept +COORD FontInfoDesired::GetEngineSize() const { COORD coordSize = _coordSizeDesired; if (IsTrueTypeFont()) @@ -41,7 +41,7 @@ FontInfoDesired::FontInfoDesired(const FontInfo& fiFont) : // This helper determines if this object represents the default raster font. This can either be because internally we're // using the empty facename and zeros for size, weight, and family, or it can be because we were given explicit // dimensions from the engine that were the result of loading the default raster font. See GdiEngine::_GetProposedFont(). -bool FontInfoDesired::IsDefaultRasterFont() const noexcept +bool FontInfoDesired::IsDefaultRasterFont() const { // Either the raster was set from the engine... // OR the face name is empty with a size of 0x0 or 8x12. diff --git a/src/renderer/base/fontinfo.cpp b/src/renderer/base/fontinfo.cpp index 55a113b4e19..ef3c37e8cda 100644 --- a/src/renderer/base/fontinfo.cpp +++ b/src/renderer/base/fontinfo.cpp @@ -33,12 +33,12 @@ FontInfo::FontInfo(const FontInfo& fiFont) : { } -COORD FontInfo::GetUnscaledSize() const noexcept +COORD FontInfo::GetUnscaledSize() const { return _coordSizeUnscaled; } -COORD FontInfo::GetSize() const noexcept +COORD FontInfo::GetSize() const { return _coordSize; } @@ -48,7 +48,7 @@ void FontInfo::SetFromEngine(const std::wstring_view faceName, const unsigned int weight, const bool fSetDefaultRasterFont, const COORD coordSize, - const COORD coordSizeUnscaled) noexcept + const COORD coordSizeUnscaled) { FontInfoBase::SetFromEngine(faceName, family, diff --git a/src/renderer/base/renderer.cpp b/src/renderer/base/renderer.cpp index 314800c5dea..13a72d4bade 100644 --- a/src/renderer/base/renderer.cpp +++ b/src/renderer/base/renderer.cpp @@ -1253,7 +1253,12 @@ std::vector Renderer::_GetSelectionRects() const const auto lineRendition = buffer.GetLineRendition(rect.Top()); rect = Viewport::FromInclusive(BufferToScreenLine(rect.ToInclusive(), lineRendition)); - auto sr = view.ConvertToOrigin(rect).ToExclusive(); + auto sr = view.ConvertToOrigin(rect).ToInclusive(); + + // hopefully temporary, we should be receiving the right selection sizes without correction. + sr.Right++; + sr.Bottom++; + result.emplace_back(sr); } diff --git a/src/renderer/dx/DxRenderer.cpp b/src/renderer/dx/DxRenderer.cpp index 6f17d2cec3e..1bc99e2f580 100644 --- a/src/renderer/dx/DxRenderer.cpp +++ b/src/renderer/dx/DxRenderer.cpp @@ -8,6 +8,7 @@ #include "../../interactivity/win32/CustomWindowMessages.h" #include "../../types/inc/Viewport.hpp" +#include "../../inc/unicode.hpp" #include "../../inc/DefaultSettings.h" #include @@ -15,12 +16,11 @@ #include "ScreenVertexShader.h" #include #include +#include using namespace DirectX; -using namespace Microsoft::Console::Render; -using namespace Microsoft::Console::Types; -std::atomic DxEngine::_tracelogCount{ 0 }; +std::atomic Microsoft::Console::Render::DxEngine::_tracelogCount{ 0 }; #pragma warning(suppress : 26477) // We don't control tracelogging macros TRACELOGGING_DEFINE_PROVIDER(g_hDxRenderProvider, "Microsoft.Windows.Terminal.Renderer.DirectX", @@ -49,6 +49,11 @@ D3D11_INPUT_ELEMENT_DESC _shaderInputLayout[] = { { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; +#pragma hdrstop + +using namespace Microsoft::Console::Render; +using namespace Microsoft::Console::Types; + // Routine Description: // - Constructs a DirectX-based renderer for console text // which primarily uses DirectWrite on a Direct2D surface diff --git a/src/renderer/inc/FontInfo.hpp b/src/renderer/inc/FontInfo.hpp index eedf13f7b24..56065881e59 100644 --- a/src/renderer/inc/FontInfo.hpp +++ b/src/renderer/inc/FontInfo.hpp @@ -37,15 +37,15 @@ class FontInfo : public FontInfoBase FontInfo(const FontInfo& fiFont); - COORD GetSize() const noexcept; - COORD GetUnscaledSize() const noexcept; + COORD GetSize() const; + COORD GetUnscaledSize() const; void SetFromEngine(const std::wstring_view faceName, const unsigned char family, const unsigned int weight, const bool fSetDefaultRasterFont, const COORD coordSize, - const COORD coordSizeUnscaled) noexcept; + const COORD coordSizeUnscaled); bool GetFallback() const noexcept; void SetFallback(const bool didFallback) noexcept; diff --git a/src/renderer/inc/FontInfoBase.hpp b/src/renderer/inc/FontInfoBase.hpp index 7d232356753..aa9f3cddbb6 100644 --- a/src/renderer/inc/FontInfoBase.hpp +++ b/src/renderer/inc/FontInfoBase.hpp @@ -36,22 +36,22 @@ class FontInfoBase ~FontInfoBase(); - unsigned char GetFamily() const noexcept; - unsigned int GetWeight() const noexcept; - const std::wstring& GetFaceName() const noexcept; - unsigned int GetCodePage() const noexcept; + unsigned char GetFamily() const; + unsigned int GetWeight() const; + const std::wstring_view GetFaceName() const noexcept; + unsigned int GetCodePage() const; - HRESULT FillLegacyNameBuffer(gsl::span buffer) const noexcept; + HRESULT FillLegacyNameBuffer(gsl::span buffer) const; - bool IsTrueTypeFont() const noexcept; + bool IsTrueTypeFont() const; void SetFromEngine(const std::wstring_view faceName, const unsigned char family, const unsigned int weight, - const bool fSetDefaultRasterFont) noexcept; + const bool fSetDefaultRasterFont); - bool WasDefaultRasterSetFromEngine() const noexcept; - void ValidateFont() noexcept; + bool WasDefaultRasterSetFromEngine() const; + void ValidateFont(); static Microsoft::Console::Render::IFontDefaultList* s_pFontDefaultList; static void s_SetFontDefaultList(_In_ Microsoft::Console::Render::IFontDefaultList* const pFontDefaultList); @@ -59,7 +59,7 @@ class FontInfoBase friend bool operator==(const FontInfoBase& a, const FontInfoBase& b); protected: - bool IsDefaultRasterFontNoSize() const noexcept; + bool IsDefaultRasterFontNoSize() const; private: std::wstring _faceName; diff --git a/src/renderer/inc/FontInfoDesired.hpp b/src/renderer/inc/FontInfoDesired.hpp index 8064f5466ce..a680f18561e 100644 --- a/src/renderer/inc/FontInfoDesired.hpp +++ b/src/renderer/inc/FontInfoDesired.hpp @@ -32,8 +32,8 @@ class FontInfoDesired : public FontInfoBase FontInfoDesired(const FontInfo& fiFont); - COORD GetEngineSize() const noexcept; - bool IsDefaultRasterFont() const noexcept; + COORD GetEngineSize() const; + bool IsDefaultRasterFont() const; friend bool operator==(const FontInfoDesired& a, const FontInfoDesired& b);