Skip to content

Commit 275e8d1

Browse files
lheckerDHowett
authored andcommitted
Properly fix ConPTY buffer corking (#16793)
I've found that #16079 was never properly addressed (it still randomly occurred after even after PR #16349), which later led to the issues described in #16769 (nushell flickering due to too many flushes). The crux of the fix is that this brings back the `_noFlushOnEnd` flag that was removed in PR #15991. This is then combined with a change to the cork API: An `uncork` on `VtEngine` now only flushes if `_Flush` got called while it was corked in the first place. `_noFlushOnEnd` prevents us from flushing in between two "unknown" VT sequences (like soft fonts or FTCS) which prevents them from being corrupted. The corking prevents the remaining cases of flushing too often. Long-term, a proper fix would be to pass through VT unmodified. Closes #16769 (cherry picked from commit 1ede023) Service-Card-Id: 91965217 Service-Version: 1.20
1 parent a50eba1 commit 275e8d1

File tree

4 files changed

+36
-3
lines changed

4 files changed

+36
-3
lines changed

src/renderer/vt/invalidate.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ CATCH_RETURN();
112112
// end paint to specifically handle this.
113113
_circled = circled;
114114

115+
// If we flushed for any reason other than circling (i.e, a sequence that we
116+
// didn't understand), we don't need to push the buffer out on EndPaint.
117+
_noFlushOnEnd = !circled;
118+
115119
_trace.TraceTriggerCircling(*pForcePaint);
116120
return S_OK;
117121
}

src/renderer/vt/paint.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,19 @@ using namespace Microsoft::Console::Types;
9494
RETURN_IF_FAILED(_MoveCursor(_deferredCursorPos));
9595
}
9696

97-
_Flush();
97+
// If this frame was triggered because we encountered a VT sequence which
98+
// required the buffered state to get printed, we don't want to flush this
99+
// frame to the pipe. That might result in us rendering half the output of a
100+
// particular frame (as emitted by the client).
101+
//
102+
// Instead, we'll leave this frame in _buffer, and just keep appending to
103+
// it as needed.
104+
if (!_noFlushOnEnd)
105+
{
106+
_Flush();
107+
}
108+
109+
_noFlushOnEnd = false;
98110
return S_OK;
99111
}
100112

src/renderer/vt/state.cpp

+17-2
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,19 @@ CATCH_RETURN();
136136

137137
void VtEngine::_Flush() noexcept
138138
{
139-
if (!_corked && !_buffer.empty())
139+
if (_buffer.empty())
140+
{
141+
return;
142+
}
143+
144+
if (!_corked)
140145
{
141146
_flushImpl();
147+
return;
142148
}
149+
150+
// Defer the flush until someone calls Cork(false).
151+
_flushRequested = true;
143152
}
144153

145154
// _corked is often true and separating _flushImpl() out allows _flush() to be inlined.
@@ -167,7 +176,13 @@ void VtEngine::_flushImpl() noexcept
167176
void VtEngine::Cork(bool corked) noexcept
168177
{
169178
_corked = corked;
170-
_Flush();
179+
180+
// Now do the deferred flush from a previous call to _Flush().
181+
if (!corked && _flushRequested)
182+
{
183+
_flushRequested = false;
184+
_flushImpl();
185+
}
171186
}
172187

173188
// Method Description:

src/renderer/vt/vtrenderer.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ namespace Microsoft::Console::Render
138138

139139
bool _resizeQuirk{ false };
140140
bool _passthrough{ false };
141+
bool _noFlushOnEnd{ false };
141142
bool _corked{ false };
143+
bool _flushRequested{ false };
142144
std::optional<TextColor> _newBottomLineBG{ std::nullopt };
143145

144146
[[nodiscard]] HRESULT _WriteFill(const size_t n, const char c) noexcept;

0 commit comments

Comments
 (0)