Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cascadia/TerminalControl/ControlCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// the UIA Engine to the renderer. This prevents us from signaling changes to the cursor or buffer.
{
// Now create the renderer and initialize the render thread.
const auto& renderSettings = _terminal->GetRenderSettings();
auto& renderSettings = _terminal->GetRenderSettings();
_renderer = std::make_unique<::Microsoft::Console::Render::Renderer>(renderSettings, _terminal.get());

_renderer->SetBackgroundColorChangedCallback([this]() { _rendererBackgroundColorChanged(); });
Expand Down
54 changes: 30 additions & 24 deletions src/renderer/base/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ static constexpr auto renderBackoffBaseTimeMilliseconds{ 150 };
// - pData - The interface to console data structures required for rendering
// Return Value:
// - An instance of a Renderer.
Renderer::Renderer(const RenderSettings& renderSettings, IRenderData* pData) :
Renderer::Renderer(RenderSettings& renderSettings, IRenderData* pData) :
_renderSettings(renderSettings),
_pData(pData)
{
Expand Down Expand Up @@ -187,31 +187,36 @@ void Renderer::NotifyPaintFrame() noexcept
}

// NOTE: You must be holding the console lock when calling this function.
void Renderer::SynchronizedOutputBegin() noexcept
void Renderer::SynchronizedOutputChanged() noexcept
{
// Kick the render thread into calling `_synchronizeWithOutput()`.
_isSynchronizingOutput = true;
}
const auto so = _renderSettings.GetRenderMode(RenderSettings::Mode::SynchronizedOutput);
if (_isSynchronizingOutput == so)
{
return;
}

// NOTE: You must be holding the console lock when calling this function.
void Renderer::SynchronizedOutputEnd() noexcept
{
// Unblock `_synchronizeWithOutput()` from the `WaitOnAddress` call.
_isSynchronizingOutput = false;
WakeByAddressSingle(&_isSynchronizingOutput);

// It's crucial to give the render thread at least a chance to gain the lock.
// Otherwise, a VT application could continuously spam DECSET 2026 (Synchronized Output) and
// essentially drop our renderer to 10 FPS, because `_isSynchronizingOutput` is always true.
//
// Obviously calling LockConsole/UnlockConsole here is an awful, ugly hack,
// since there's no guarantee that this is the same lock as the one the VT parser uses.
// But the alternative is Denial-Of-Service of the render thread.
//
// Note that this causes raw throughput of DECSET 2026 to be comparatively low, but that's fine.
// Apps that use DECSET 2026 don't produce that sequence continuously, but rather at a fixed rate.
_pData->UnlockConsole();
_pData->LockConsole();
// If `_isSynchronizingOutput` is true, it'll kick the
// render thread into calling `_synchronizeWithOutput()`...
_isSynchronizingOutput = so;

if (!_isSynchronizingOutput)
{
// ...otherwise, unblock `_synchronizeWithOutput()` from the `WaitOnAddress` call.
WakeByAddressSingle(&_isSynchronizingOutput);

// It's crucial to give the render thread at least a chance to gain the lock.
// Otherwise, a VT application could continuously spam DECSET 2026 (Synchronized Output) and
// essentially drop our renderer to 10 FPS, because `_isSynchronizingOutput` is always true.
//
// Obviously calling LockConsole/UnlockConsole here is an awful, ugly hack,
// since there's no guarantee that this is the same lock as the one the VT parser uses.
// But the alternative is Denial-Of-Service of the render thread.
//
// Note that this causes raw throughput of DECSET 2026 to be comparatively low, but that's fine.
// Apps that use DECSET 2026 don't produce that sequence continuously, but rather at a fixed rate.
_pData->UnlockConsole();
_pData->LockConsole();
}
}

void Renderer::_synchronizeWithOutput() noexcept
Expand Down Expand Up @@ -249,6 +254,7 @@ void Renderer::_synchronizeWithOutput() noexcept
// If a timeout occurred, `_isSynchronizingOutput` may still be true.
// Set it to false now to skip calling `_synchronizeWithOutput()` on the next frame.
_isSynchronizingOutput = false;
_renderSettings.SetRenderMode(RenderSettings::Mode::SynchronizedOutput, false);
}

// Routine Description:
Expand Down
7 changes: 3 additions & 4 deletions src/renderer/base/renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@ namespace Microsoft::Console::Render
class Renderer
{
public:
Renderer(const RenderSettings& renderSettings, IRenderData* pData);
Renderer(RenderSettings& renderSettings, IRenderData* pData);

IRenderData* GetRenderData() const noexcept;

[[nodiscard]] HRESULT PaintFrame();

void NotifyPaintFrame() noexcept;
void SynchronizedOutputBegin() noexcept;
void SynchronizedOutputEnd() noexcept;
void SynchronizedOutputChanged() noexcept;
void TriggerSystemRedraw(const til::rect* const prcDirtyClient);
void TriggerRedraw(const Microsoft::Console::Types::Viewport& region);
void TriggerRedraw(const til::point* const pcoord);
Expand Down Expand Up @@ -113,7 +112,7 @@ namespace Microsoft::Console::Render
void _prepareNewComposition();
[[nodiscard]] HRESULT _PrepareRenderInfo(_In_ IRenderEngine* const pEngine);

const RenderSettings& _renderSettings;
RenderSettings& _renderSettings;
std::array<IRenderEngine*, 2> _engines{};
IRenderData* _pData = nullptr; // Non-ownership pointer
static constexpr size_t _firstSoftFontChar = 0xEF20;
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/inc/RenderSettings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ namespace Microsoft::Console::Render
AlwaysDistinguishableColors,
IntenseIsBold,
IntenseIsBright,
ScreenReversed
ScreenReversed,
SynchronizedOutput,
};

RenderSettings() noexcept;
Expand Down
13 changes: 5 additions & 8 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1915,16 +1915,10 @@ void AdaptDispatch::_ModeParamsHelper(const DispatchTypes::ModeParams param, con
_api.SetSystemMode(ITerminalApi::Mode::BracketedPaste, enable);
break;
case DispatchTypes::ModeParams::SO_SynchronizedOutput:
_renderSettings.SetRenderMode(RenderSettings::Mode::SynchronizedOutput, enable);
if (_renderer)
{
if (enable)
{
_renderer->SynchronizedOutputBegin();
}
else
{
_renderer->SynchronizedOutputEnd();
}
_renderer->SynchronizedOutputChanged();
}
break;
case DispatchTypes::ModeParams::GCM_GraphemeClusterMode:
Expand Down Expand Up @@ -2065,6 +2059,9 @@ void AdaptDispatch::RequestMode(const DispatchTypes::ModeParams param)
case DispatchTypes::ModeParams::XTERM_BracketedPasteMode:
state = mapTemp(_api.GetSystemMode(ITerminalApi::Mode::BracketedPaste));
break;
case DispatchTypes::ModeParams::SO_SynchronizedOutput:
state = mapTemp(_renderSettings.GetRenderMode(RenderSettings::Mode::SynchronizedOutput));
break;
case DispatchTypes::ModeParams::GCM_GraphemeClusterMode:
state = mapPerm(CodepointWidthDetector::Singleton().GetMode() == TextMeasurementMode::Graphemes);
break;
Expand Down