Skip to content

Commit

Permalink
Initialize rows lazily
Browse files Browse the repository at this point in the history
  • Loading branch information
lhecker committed Jun 2, 2023
1 parent 3cb78a4 commit cc14db2
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 35 deletions.
45 changes: 27 additions & 18 deletions src/buffer/out/Row.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ ROW::ROW(wchar_t* charsBuffer, uint16_t* charOffsetsBuffer, uint16_t rowWidth, c
_attr{ rowWidth, fillAttribute },
_columnCount{ rowWidth }
{
if (_chars.data())
{
_init();
}
}

void ROW::SetWrapForced(const bool wrap) noexcept
Expand Down Expand Up @@ -118,13 +114,32 @@ LineRendition ROW::GetLineRendition() const noexcept
return _lineRendition;
}

// Routine Description:
// - Sets all properties of the ROW to default values
// Arguments:
// - Attr - The default attribute (color) to fill
// Return Value:
// - <none>
void ROW::Reset(const TextAttribute& attr)
bool ROW::IsValid() const noexcept
{
return _valid;
}

void ROW::Discard() noexcept
{
_charsHeap.reset();
_valid = false;
}

void ROW::Reset(const TextAttribute& attr) noexcept
{
_init(attr);
std::fill_n(_chars.begin(), _columnCount, UNICODE_SPACE);
std::iota(_charOffsets.begin(), _charOffsets.end(), uint16_t{ 0 });
}

void ROW::Reset(const ROW& whitespaceRow, const TextAttribute& attr) noexcept
{
_init(attr);
memcpy(_chars.data(), whitespaceRow._chars.data(), std::min(whitespaceRow._chars.size(), _chars.size()) * 2);
memcpy(_charOffsets.data(), whitespaceRow._charOffsets.data(), std::min(whitespaceRow._charOffsets.size(), _charOffsets.size()) * 2);
}

void ROW::_init(const TextAttribute& attr) noexcept
{
_charsHeap.reset();
_chars = { _charsBuffer, _columnCount };
Expand All @@ -134,13 +149,7 @@ void ROW::Reset(const TextAttribute& attr)
_lineRendition = LineRendition::SingleWidth;
_wrapForced = false;
_doubleBytePadded = false;
_init();
}

void ROW::_init() noexcept
{
std::fill_n(_chars.begin(), _columnCount, UNICODE_SPACE);
std::iota(_charOffsets.begin(), _charOffsets.end(), uint16_t{ 0 });
_valid = true;
}

void ROW::TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& attr, til::CoordType newWidth)
Expand Down
8 changes: 6 additions & 2 deletions src/buffer/out/Row.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ class ROW final
void SetLineRendition(const LineRendition lineRendition) noexcept;
LineRendition GetLineRendition() const noexcept;

void Reset(const TextAttribute& attr);
bool IsValid() const noexcept;
void Discard() noexcept;
void Reset(const TextAttribute& attr) noexcept;
void Reset(const ROW& whitespaceRow, const TextAttribute& attr) noexcept;
void TransferAttributes(const til::small_rle<TextAttribute, uint16_t, 1>& attr, til::CoordType newWidth);

til::CoordType NavigateToPrevious(til::CoordType column) const noexcept;
Expand Down Expand Up @@ -179,7 +182,7 @@ class ROW final
uint16_t _uncheckedCharOffset(size_t col) const noexcept;
bool _uncheckedIsTrailer(size_t col) const noexcept;

void _init() noexcept;
void _init(const TextAttribute& attr) noexcept;
void _resizeChars(uint16_t colEndDirty, uint16_t chBegDirty, size_t chEndDirty, uint16_t chEndDirtyOld);

// These fields are a bit "wasteful", but it makes all this a bit more robust against
Expand Down Expand Up @@ -233,6 +236,7 @@ class ROW final
bool _wrapForced = false;
// Occurs when the user runs out of text to support a double byte character and we're forced to the next line
bool _doubleBytePadded = false;
bool _valid = false;
};

#ifdef UNIT_TESTING
Expand Down
44 changes: 32 additions & 12 deletions src/buffer/out/textBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ TextBuffer::TextBuffer(til::size screenBufferSize,
// Guard against resizing the text buffer to 0 columns/rows, which would break being able to insert text.
screenBufferSize.width = std::max(screenBufferSize.width, 1);
screenBufferSize.height = std::max(screenBufferSize.height, 1);
_charBuffer = _allocateBuffer(screenBufferSize, _currentAttributes, _storage);
_buffer = _allocateBuffer(screenBufferSize, _currentAttributes, _whitespaceRow, _storage);
_UpdateSize();
}

Expand Down Expand Up @@ -80,7 +80,8 @@ const ROW& TextBuffer::GetRowByOffset(const til::CoordType index) const noexcept
{
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const auto offsetIndex = gsl::narrow_cast<size_t>(_firstRow + index) % _storage.size();
return til::at(_storage, offsetIndex);
const auto& row = til::at(_storage, offsetIndex);
return row.IsValid() ? row : _whitespaceRow;
}

// Routine Description:
Expand All @@ -94,7 +95,14 @@ ROW& TextBuffer::GetRowByOffset(const til::CoordType index) noexcept
{
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const auto offsetIndex = gsl::narrow_cast<size_t>(_firstRow + index) % _storage.size();
return til::at(_storage, offsetIndex);
auto& row = til::at(_storage, offsetIndex);

if (!row.IsValid())
{
row.Reset(_whitespaceRow, _currentAttributes);
}

return row;
}

// Routine Description:
Expand Down Expand Up @@ -592,7 +600,7 @@ bool TextBuffer::IncrementCircularBuffer(const bool inVtMode)
// the current background color, but with no meta attributes set.
fillAttributes.SetStandardErase();
}
GetRowByOffset(0).Reset(fillAttributes);
GetRowByOffset(0).Discard();
{
// Now proceed to increment.
// Incrementing it will cause the next line down to become the new "top" of the window (the new "0" in logical coordinates)
Expand Down Expand Up @@ -693,7 +701,7 @@ const Viewport TextBuffer::GetSize() const noexcept
return _size;
}

wil::unique_virtualalloc_ptr<std::byte> TextBuffer::_allocateBuffer(til::size sz, const TextAttribute& attributes, std::vector<ROW>& rows)
TextBuffer::VirtualAllocation TextBuffer::_allocateBuffer(til::size sz, const TextAttribute& attributes, ROW& whitespaceRow, std::vector<ROW>& rows)
{
const auto w = gsl::narrow<uint16_t>(sz.width);
const auto h = gsl::narrow<uint16_t>(sz.height);
Expand All @@ -705,13 +713,21 @@ wil::unique_virtualalloc_ptr<std::byte> TextBuffer::_allocateBuffer(til::size sz
const auto rowStride = charsBytes + indicesBytes;
// 65535*65535 cells would result in a charsAreaSize of 8GiB.
// --> Use uint64_t so that we can safely do our calculations even on x86.
const auto allocSize = gsl::narrow<size_t>(::base::strict_cast<uint64_t>(rowStride) * ::base::strict_cast<uint64_t>(h));
const auto rowCount = ::base::strict_cast<uint64_t>(h) + 1;
const auto allocSize = gsl::narrow<size_t>(rowStride * rowCount);

auto buffer = wil::unique_virtualalloc_ptr<std::byte>{ static_cast<std::byte*>(VirtualAlloc(nullptr, allocSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)) };
THROW_IF_NULL_ALLOC(buffer);

auto data = std::span{ buffer.get(), allocSize }.begin();

{
const auto chars = til::bit_cast<wchar_t*>(&*data);
const auto indices = til::bit_cast<uint16_t*>(&*(data + charsBytes));
whitespaceRow = { chars, indices, w, attributes };
data += rowStride;
}

rows.resize(h);
for (auto& row : rows)
{
Expand All @@ -721,7 +737,8 @@ wil::unique_virtualalloc_ptr<std::byte> TextBuffer::_allocateBuffer(til::size sz
data += rowStride;
}

return buffer;
whitespaceRow.Reset(attributes);
return { std::move(buffer), allocSize };
}

void TextBuffer::_UpdateSize()
Expand Down Expand Up @@ -928,12 +945,13 @@ til::point TextBuffer::BufferToScreenPosition(const til::point position) const n
// and the default current color attributes
void TextBuffer::Reset()
{
const auto attr = GetCurrentAttributes();

for (auto& row : _storage)
{
row.Reset(attr);
row.Discard();
}

VirtualAlloc(_buffer.ptr.get(), _buffer.size, MEM_RESET, PAGE_READWRITE);
_whitespaceRow.Reset(_currentAttributes);
}

// Routine Description:
Expand All @@ -957,8 +975,9 @@ void TextBuffer::Reset()
}
const auto TopRowIndex = gsl::narrow_cast<size_t>(_firstRow + TopRow) % _storage.size();

ROW whitespaceRow;
std::vector<ROW> newStorage;
auto newBuffer = _allocateBuffer(newSize, _currentAttributes, newStorage);
auto newBuffer = _allocateBuffer(newSize, _currentAttributes, whitespaceRow, newStorage);

// This basically imitates a std::rotate_copy(first, mid, last), but uses ROW::CopyRangeFrom() to do the copying.
{
Expand Down Expand Up @@ -994,7 +1013,8 @@ void TextBuffer::Reset()
}
}

_charBuffer = std::move(newBuffer);
_buffer = std::move(newBuffer);
_whitespaceRow = std::move(whitespaceRow);
_storage = std::move(newStorage);

_SetFirstRowIndex(0);
Expand Down
11 changes: 9 additions & 2 deletions src/buffer/out/textBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,13 @@ class TextBuffer final
interval_tree::IntervalTree<til::point, size_t> GetPatterns(const til::CoordType firstRow, const til::CoordType lastRow) const;

private:
static wil::unique_virtualalloc_ptr<std::byte> _allocateBuffer(til::size sz, const TextAttribute& attributes, std::vector<ROW>& rows);
struct VirtualAllocation
{
wil::unique_virtualalloc_ptr<std::byte> ptr;
size_t size = 0;
};

static VirtualAllocation _allocateBuffer(til::size sz, const TextAttribute& attributes, ROW& whitespaceRow, std::vector<ROW>& rows);

void _UpdateSize();
void _SetFirstRowIndex(const til::CoordType FirstRowIndex) noexcept;
Expand Down Expand Up @@ -249,7 +255,8 @@ class TextBuffer final
std::unordered_map<size_t, std::wstring> _idsAndPatterns;
size_t _currentPatternId = 0;

wil::unique_virtualalloc_ptr<std::byte> _charBuffer;
VirtualAllocation _buffer;
ROW _whitespaceRow;
std::vector<ROW> _storage;
TextAttribute _currentAttributes;
til::CoordType _firstRow = 0; // indexes top row (not necessarily 0)
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2436,7 +2436,7 @@ void AdaptDispatch::_DoLineFeed(TextBuffer& textBuffer, const bool withReturn, c
{
auto eraseAttributes = textBuffer.GetCurrentAttributes();
eraseAttributes.SetStandardErase();
textBuffer.GetRowByOffset(newPosition.y).Reset(eraseAttributes);
textBuffer.GetRowByOffset(newPosition.y).Discard();
}
}
else
Expand Down

0 comments on commit cc14db2

Please sign in to comment.