Improve VtRenderer performance
This commit is contained in:
parent
806a2feb22
commit
7dd2079404
|
@ -81,8 +81,7 @@ using namespace Microsoft::Console::Render;
|
|||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_EraseCharacter(const short chars) noexcept
|
||||
{
|
||||
static const std::string format = "\x1b[%dX";
|
||||
return _WriteFormattedString(&format, chars);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[{}X"), chars);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -93,8 +92,7 @@ using namespace Microsoft::Console::Render;
|
|||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_CursorForward(const short chars) noexcept
|
||||
{
|
||||
static const std::string format = "\x1b[%dC";
|
||||
return _WriteFormattedString(&format, chars);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[{}C"), chars);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -132,9 +130,8 @@ using namespace Microsoft::Console::Render;
|
|||
{
|
||||
return _Write(fInsertLine ? "\x1b[L" : "\x1b[M");
|
||||
}
|
||||
const std::string format = fInsertLine ? "\x1b[%dL" : "\x1b[%dM";
|
||||
|
||||
return _WriteFormattedString(&format, sLines);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[{}{}"), sLines, fInsertLine ? 'L' : 'M');
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -171,14 +168,7 @@ using namespace Microsoft::Console::Render;
|
|||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_CursorPosition(const COORD coord) noexcept
|
||||
{
|
||||
static const std::string cursorFormat = "\x1b[%d;%dH";
|
||||
|
||||
// VT coords start at 1,1
|
||||
COORD coordVt = coord;
|
||||
coordVt.X++;
|
||||
coordVt.Y++;
|
||||
|
||||
return _WriteFormattedString(&cursorFormat, coordVt.Y, coordVt.X);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[{};{}H"), coord.Y + 1, coord.X + 1);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -232,8 +222,7 @@ using namespace Microsoft::Console::Render;
|
|||
(WI_IsFlagSet(wAttr, FOREGROUND_GREEN) ? 2 : 0) +
|
||||
(WI_IsFlagSet(wAttr, FOREGROUND_BLUE) ? 4 : 0);
|
||||
|
||||
auto s = fmt::format(FMT_COMPILE("\x1b[{}m"), vtIndex);
|
||||
return _Write(s);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[{}m"), vtIndex);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -247,8 +236,7 @@ using namespace Microsoft::Console::Render;
|
|||
[[nodiscard]] HRESULT VtEngine::_SetGraphicsRendition256Color(const WORD index,
|
||||
const bool fIsForeground) noexcept
|
||||
{
|
||||
auto s = fmt::format(FMT_COMPILE("\x1b[{};5;{}m"), fIsForeground ? 38 : 48, ::Xterm256ToWindowsIndex(index));
|
||||
return _Write(s);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[{}8;5;{}m"), fIsForeground ? '3' : '4', ::Xterm256ToWindowsIndex(index));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -262,15 +250,10 @@ using namespace Microsoft::Console::Render;
|
|||
[[nodiscard]] HRESULT VtEngine::_SetGraphicsRenditionRGBColor(const COLORREF color,
|
||||
const bool fIsForeground) noexcept
|
||||
{
|
||||
DWORD const r = GetRValue(color);
|
||||
DWORD const g = GetGValue(color);
|
||||
DWORD const b = GetBValue(color);
|
||||
|
||||
// Worst case scenario: "\x1b[38;2;128;128;128m", which has length = 19 + \0.
|
||||
// Use small_vector as MSVC's SSO only buffers up to 15 characters.
|
||||
boost::container::small_vector<char, 20u> buf;
|
||||
const auto end = fmt::format_to(std::back_inserter(buf), FMT_COMPILE("\x1b[{};2;{};{};{}m"), fIsForeground ? 38 : 48, r, g, b);
|
||||
return _Write({ buf.data(), buf.size() });
|
||||
const uint8_t r = GetRValue(color);
|
||||
const uint8_t g = GetGValue(color);
|
||||
const uint8_t b = GetBValue(color);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[{}8;2;{};{};{}m"), fIsForeground ? '3' : '4', r, g, b);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -282,9 +265,7 @@ using namespace Microsoft::Console::Render;
|
|||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_SetGraphicsRenditionDefaultColor(const bool fIsForeground) noexcept
|
||||
{
|
||||
const std::string_view fmt = fIsForeground ? ("\x1b[39m") : ("\x1b[49m");
|
||||
|
||||
return _Write(fmt);
|
||||
return _Write(fIsForeground ? ("\x1b[39m") : ("\x1b[49m"));
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -296,13 +277,12 @@ using namespace Microsoft::Console::Render;
|
|||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_ResizeWindow(const short sWidth, const short sHeight) noexcept
|
||||
{
|
||||
static const std::string resizeFormat = "\x1b[8;%d;%dt";
|
||||
if (sWidth < 0 || sHeight < 0)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
return _WriteFormattedString(&resizeFormat, sHeight, sWidth);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b[8;{};{}t"), sHeight, sWidth);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -325,8 +305,7 @@ using namespace Microsoft::Console::Render;
|
|||
// - S_OK if we succeeded, else an appropriate HRESULT for failing to allocate or write.
|
||||
[[nodiscard]] HRESULT VtEngine::_ChangeTitle(_In_ const std::string& title) noexcept
|
||||
{
|
||||
const std::string titleFormat = "\x1b]0;" + title + "\x7";
|
||||
return _Write(titleFormat);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b]0;{}\x7"), title);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -468,19 +447,17 @@ using namespace Microsoft::Console::Render;
|
|||
// send the auto-assigned ID, prefixed with the PID of this session
|
||||
// (we do this so different conpty sessions do not overwrite each other's hyperlinks)
|
||||
const auto sessionID = GetCurrentProcessId();
|
||||
const std::string uri_str{ til::u16u8(uri) };
|
||||
auto s = fmt::format(FMT_COMPILE("\x1b]8;id={}-{};{}\x1b\\"), sessionID, numberId, uri_str);
|
||||
return _Write(s);
|
||||
const auto uriStr = til::u16u8(uri);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b]8;id={}-{};{}\x1b\\"), sessionID, numberId, uriStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the case of user-defined IDs:
|
||||
// send the user-defined ID, prefixed with a "u"
|
||||
// (we do this so no application can accidentally override a user defined ID)
|
||||
const std::string uri_str{ til::u16u8(uri) };
|
||||
const std::string customId_str{ til::u16u8(customId) };
|
||||
auto s = fmt::format(FMT_COMPILE("\x1b]8;id=u-{};{}\x1b\\"), customId_str, uri_str);
|
||||
return _Write(s);
|
||||
const auto uriStr = til::u16u8(uri);
|
||||
const auto customIdStr = til::u16u8(customId);
|
||||
return _WriteFormatted(FMT_COMPILE("\x1b]8;id=u-{};{}\x1b\\"), customIdStr, uriStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
|||
|
||||
if (!_pipeBroken)
|
||||
{
|
||||
bool fSuccess = !!WriteFile(_hFile.get(), _buffer.data(), static_cast<DWORD>(_buffer.size()), nullptr, nullptr);
|
||||
bool fSuccess = !!WriteFile(_hFile.get(), _buffer.data(), gsl::narrow_cast<DWORD>(_buffer.size()), nullptr, nullptr);
|
||||
_buffer.clear();
|
||||
if (!fSuccess)
|
||||
{
|
||||
|
@ -178,71 +178,6 @@ VtEngine::VtEngine(_In_ wil::unique_hfile pipe,
|
|||
return _Write(needed);
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Helper for calling _Write with a string for formatting a sequence. Used
|
||||
// extensively by VtSequences.cpp
|
||||
// Arguments:
|
||||
// - pFormat: pointer to format string to write to the pipe
|
||||
// - ...: a va_list of args to format the string with.
|
||||
// Return Value:
|
||||
// - S_OK, E_INVALIDARG for a invalid format string, or suitable HRESULT error
|
||||
// from writing pipe.
|
||||
[[nodiscard]] HRESULT VtEngine::_WriteFormattedString(const std::string* const pFormat, ...) noexcept
|
||||
try
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, pFormat);
|
||||
|
||||
// NOTE: pFormat is a pointer because varargs refuses to operate with a ref in that position
|
||||
// NOTE: We're not using string_view because it doesn't guarantee null (which will be needed
|
||||
// later in the formatting method).
|
||||
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
// We're going to hold onto our format string space across calls because
|
||||
// the VT renderer will be formatting a LOT of strings and alloc/freeing them
|
||||
// over and over is going to be way worse for perf than just holding some extra
|
||||
// memory for formatting purposes.
|
||||
// See _formatBuffer for its location.
|
||||
|
||||
// First, plow ahead using our pre-reserved string space.
|
||||
LPSTR destEnd = nullptr;
|
||||
size_t destRemaining = 0;
|
||||
if (SUCCEEDED(StringCchVPrintfExA(_formatBuffer.data(),
|
||||
_formatBuffer.size(),
|
||||
&destEnd,
|
||||
&destRemaining,
|
||||
STRSAFE_NO_TRUNCATION,
|
||||
pFormat->c_str(),
|
||||
args)))
|
||||
{
|
||||
return _Write({ _formatBuffer.data(), _formatBuffer.size() - destRemaining });
|
||||
}
|
||||
|
||||
// If we didn't succeed at filling/using the existing space, then
|
||||
// we're going to take the long way by counting the space required and resizing up to that
|
||||
// space and formatting.
|
||||
|
||||
const auto needed = _scprintf(pFormat->c_str(), args);
|
||||
// -1 is the _scprintf error case https://msdn.microsoft.com/en-us/library/t32cf9tb.aspx
|
||||
if (needed > -1)
|
||||
{
|
||||
_formatBuffer.resize(static_cast<size_t>(needed) + 1);
|
||||
|
||||
const auto written = _vsnprintf_s(_formatBuffer.data(), _formatBuffer.size(), needed, pFormat->c_str(), args);
|
||||
hr = _Write({ _formatBuffer.data(), gsl::narrow<size_t>(written) });
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
return hr;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
// Method Description:
|
||||
// - This method will update the active font on the current device context
|
||||
// Does nothing for vt, the font is handed by the terminal.
|
||||
|
|
|
@ -154,9 +154,17 @@ namespace Microsoft::Console::Render
|
|||
std::optional<TextColor> _newBottomLineBG{ std::nullopt };
|
||||
|
||||
[[nodiscard]] HRESULT _Write(std::string_view const str) noexcept;
|
||||
[[nodiscard]] HRESULT _WriteFormattedString(const std::string* const pFormat, ...) noexcept;
|
||||
[[nodiscard]] HRESULT _Flush() noexcept;
|
||||
|
||||
template<typename S, typename... Args>
|
||||
[[nodiscard]] HRESULT _WriteFormatted(S&& format, Args&&... args)
|
||||
try
|
||||
{
|
||||
fmt::format_to(std::back_inserter(_buffer), std::forward<S>(format), std::forward<Args>(args)...);
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN()
|
||||
|
||||
void _OrRect(_Inout_ SMALL_RECT* const pRectExisting, const SMALL_RECT* const pRectToOr) const;
|
||||
bool _AllIsInvalid() const;
|
||||
|
||||
|
|
|
@ -1848,7 +1848,7 @@ void StateMachine::ProcessString(const std::wstring_view string)
|
|||
if (_processingIndividually)
|
||||
{
|
||||
// If we're processing characters individually, send it to the state machine.
|
||||
ProcessCharacter(string.at(current));
|
||||
ProcessCharacter(til::at(string, current));
|
||||
++current;
|
||||
if (_state == VTStates::Ground) // Then check if we're back at ground. If we are, the next character (pwchCurr)
|
||||
{ // is the start of the next run of characters that might be printable.
|
||||
|
@ -1858,7 +1858,7 @@ void StateMachine::ProcessString(const std::wstring_view string)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (_isActionableFromGround(string.at(current))) // If the current char is the start of an escape sequence, or should be executed in ground state...
|
||||
if (_isActionableFromGround(til::at(string, current))) // If the current char is the start of an escape sequence, or should be executed in ground state...
|
||||
{
|
||||
if (!_run.empty())
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue