terminal/src/renderer/base/renderer.hpp

152 lines
6 KiB
C++
Raw Normal View History

/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- Renderer.hpp
Abstract:
- This is the definition of our renderer.
- It provides interfaces for the console application to notify when various portions of the console state have changed and need to be redrawn.
- It requires a data interface to fetch relevant console structures required for drawing and a drawing engine target for output.
Author(s):
- Michael Niksa (MiNiksa) 17-Nov-2015
--*/
#pragma once
#include "../inc/IRenderer.hpp"
#include "../inc/IRenderEngine.hpp"
#include "../inc/IRenderData.hpp"
#include "thread.hpp"
#include "../../buffer/out/textBuffer.hpp"
#include "../../buffer/out/CharRow.hpp"
namespace Microsoft::Console::Render
{
class Renderer sealed : public IRenderer
{
public:
Renderer(IRenderData* pData,
_In_reads_(cEngines) IRenderEngine** const pEngine,
const size_t cEngines,
std::unique_ptr<IRenderThread> thread);
[[nodiscard]] static HRESULT s_CreateInstance(IRenderData* pData,
_In_reads_(cEngines) IRenderEngine** const rgpEngines,
const size_t cEngines,
_Outptr_result_nullonfailure_ Renderer** const ppRenderer);
[[nodiscard]] static HRESULT s_CreateInstance(IRenderData* pData,
_Outptr_result_nullonfailure_ Renderer** const ppRenderer);
virtual ~Renderer() override;
[[nodiscard]] HRESULT PaintFrame();
void TriggerSystemRedraw(const RECT* const prcDirtyClient) override;
void TriggerRedraw(const Microsoft::Console::Types::Viewport& region) override;
void TriggerRedraw(const COORD* const pcoord) override;
void TriggerRedrawCursor(const COORD* const pcoord) override;
void TriggerRedrawAll() override;
void TriggerTeardown() override;
void TriggerSelection() override;
void TriggerScroll() override;
void TriggerScroll(const COORD* const pcoordDelta) override;
void TriggerCircling() override;
void TriggerTitleChange() override;
void TriggerFontChange(const int iDpi,
const FontInfoDesired& FontInfoDesired,
_Out_ FontInfo& FontInfo) override;
[[nodiscard]] HRESULT GetProposedFont(const int iDpi,
const FontInfoDesired& FontInfoDesired,
_Out_ FontInfo& FontInfo) override;
bool IsGlyphWideByFont(const std::wstring_view glyph) override;
void EnablePainting() override;
void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) override;
void WaitUntilCanRender() override;
void AddRenderEngine(_In_ IRenderEngine* const pEngine) override;
void SetRendererEnteredErrorStateCallback(std::function<void()> pfn);
void ResetErrorStateAndResume();
void UpdateLastHoveredInterval(const std::optional<interval_tree::IntervalTree<til::point, size_t>::interval>& newInterval);
private:
std::deque<IRenderEngine*> _rgpEngines;
IRenderData* _pData; // Non-ownership pointer
std::unique_ptr<IRenderThread> _pThread;
bool _destructing = false;
std::optional<interval_tree::IntervalTree<til::point, size_t>::interval> _hoveredInterval;
void _NotifyPaintFrame();
[[nodiscard]] HRESULT _PaintFrameForEngine(_In_ IRenderEngine* const pEngine) noexcept;
bool _CheckViewportAndScroll();
[[nodiscard]] HRESULT _PaintBackground(_In_ IRenderEngine* const pEngine);
void _PaintBufferOutput(_In_ IRenderEngine* const pEngine);
void _PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
TextBufferCellIterator it,
Make Conpty emit wrapped lines as actually wrapped lines (#4415) ## Summary of the Pull Request Changes how conpty emits text to preserve line-wrap state, and additionally adds rudimentary support to the Windows Terminal for wrapped lines. ## References * Does _not_ fix (!) #3088, but that might be lower down in conhost. This makes wt behave like conhost, so at least there's that * Still needs a proper deferred EOL wrap implementation in #780, which is left as a todo * #4200 is the mega bucket with all this work * MSFT:16485846 was the first attempt at this task, which caused the regression MSFT:18123777 so we backed it out. * #4403 - I made sure this worked with that PR before I even sent #4403 ## PR Checklist * [x] Closes #405 * [x] Closes #3367 * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments I started with the following implementation: When conpty is about to write the last column, note that we wrapped this line here. If the next character the vt renderer is told to paint get is supposed to be at the start of the following line, then we know that the previous line had wrapped, so we _won't_ emit the usual `\r\n` here, and we'll just continue emitting text. However, this isn't _exactly_ right - if someone fills the row _exactly_ with text, the information that's available to the vt renderer isn't enough to know for sure if this line broke or not. It is possible for the client to write a full line of text, with a `\n` at the end, to manually break the line. So, I had to also add the `lineWrapped` param to the `IRenderEngine` interface, which is about half the files in this changelist. ## Validation Steps Performed * Ran tests * Checked how the Windows Terminal behaves with these changes * Made sure that conhost/inception and gnome-terminal both act as you'd expect with wrapped lines from conpty
2020-02-27 17:40:11 +01:00
const COORD target,
const bool lineWrapped);
static IRenderEngine::GridLines s_GetGridlines(const TextAttribute& textAttribute) noexcept;
void _PaintBufferOutputGridLineHelper(_In_ IRenderEngine* const pEngine,
const TextAttribute textAttribute,
const size_t cchLine,
const COORD coordTarget);
void _PaintSelection(_In_ IRenderEngine* const pEngine);
void _PaintCursor(_In_ IRenderEngine* const pEngine);
void _PaintOverlays(_In_ IRenderEngine* const pEngine);
void _PaintOverlay(IRenderEngine& engine, const RenderOverlay& overlay);
[[nodiscard]] HRESULT _UpdateDrawingBrushes(_In_ IRenderEngine* const pEngine, const TextAttribute attr, const bool isSettingDefaultBrushes);
[[nodiscard]] HRESULT _PerformScrolling(_In_ IRenderEngine* const pEngine);
Microsoft::Console::Types::Viewport _viewport;
Improve perf by avoiding vector reallocation in renderer clusters and VT output graphics options (#6420) ## Summary of the Pull Request Caches vectors in the class and uses a new helper to opportunistically shrink/grow as viewport sizes change in order to save performance on alloc/free of commonly used vectors. ## PR Checklist * [x] Scratches a perf itch. * [x] I work here. * [x] wil tests added * [x] No add'l doc. * [x] Am core contributor. ## Detailed Description of the Pull Request / Additional comments Two fixes: 1. For outputting lots of text, the base renderer class spent a lot of time allocating and freeing and reallocating the `Cluster` vector that adapts the text buffer information into render clusters. I've now cached this vector in the base render class itself and I shrink/grow it based on the viewport update that happens at the top of every frame. To prevent too much thrashing in the downward/shrink direction, I wrote the `til::manage_vector` helper that contains a threshold to only shrink if it asks for small enough of a size relative to the existing one. I used 80% of the existing size as the threshold for this one. 2. For outputting lots of changing colors, the VT graphics output engine spent a bunch of time allocating and reallocating the vector for `GraphicsOptions`. This one doesn't really have a predictable size, but I never expect it to get extremely big. So I just held it in the base class. ## Validation Steps Performed * [x] Ran the til unit test * [x] Checked render cluster vector time before/after against `big.txt` from #1064 * [x] Checked VT graphics output vector time before/after against `cacafire` Case | Before | After ---|---|---| `big.txt` | ![image](https://user-images.githubusercontent.com/18221333/84088632-cbaa8400-a9a1-11ea-8932-04b2e12a0477.png) | ![image](https://user-images.githubusercontent.com/18221333/84088996-b6822500-a9a2-11ea-837c-5e32a110156e.png) `cacafire` | ![image](https://user-images.githubusercontent.com/18221333/84089153-22648d80-a9a3-11ea-8567-c3d80efa16a6.png) | ![image](https://user-images.githubusercontent.com/18221333/84089190-34463080-a9a3-11ea-98e5-a236b12330d6.png)
2020-06-11 00:02:05 +02:00
static constexpr float _shrinkThreshold = 0.8f;
std::vector<Cluster> _clusterBuffer;
std::vector<SMALL_RECT> _GetSelectionRects() const;
Render row-by-row instead of invalidating entire screen (#5185) ## Summary of the Pull Request Adjusts DirectX renderer to use `til::bitmap` to track invalidation regions. Uses special modification to invalidate a row-at-a-time to ensure ligatures and NxM glyphs continue to work. ## References Likely helps #1064 ## PR Checklist * [x] Closes #778 * [x] I work here. * [x] Manual testing performed. See Performance traces in #778. * [x] Automated tests for `til` changes. * [x] Am core contributor. And discussed with @DHowett-MSFT. ## Detailed Description of the Pull Request / Additional comments - Applies `til::bitmap` as the new invalidation scheme inside the DirectX renderer and updates all entrypoints for collecting invalidation data to coalesce into this structure. - Semi-permanently routes all invalidations through a helper method `_InvalidateRectangle` that will expand any invalidation to cover the entire line. This ensures that ligatures and NxM glyphs will continue to render appropriately while still allowing us to dramatically reduce the number of lines drawn overall. In the future, we may come up with a tighter solution than line-by-line invalidation and can modify this helper method appropriately at that later date to further scope the invalid region. - Ensures that the `experimental.retroTerminalEffects` feature continues to invalidate the entire display on start of frame as the shader is applied at the end of the frame composition and will stack on itself in an amusing fashion when we only redraw part of the display. - Moves many member variables inside the DirectX renderer into the new `til::size`, `til::point`, and `til::rectangle` methods to facilitate easier management and mathematical operations. Consequently adds `try/catch` blocks around many of the already-existing `noexcept` methods to deal with mathematical or casting failures now detected by using the support classes. - Corrects `TerminalCore` redraw triggers to appropriately communicate scrolling circumstances to the renderer so it can optimize the draw regions appropriately. - Fixes an issue in the base `Renderer` that was causing overlapping scroll regions due to behavior of `Viewport::TrimToViewport` modifying the local. This fix is "good enough" for now and should go away when `Viewport` is fully migrated to `til::rectangle`. - Adds multiplication and division operators to `til::rectangle` and supporting tests. These operates will help scale back and forth between a cell-based rectangle and a pixel-based rectangle. They take special care to ensure that a pixel rectangle being divided downward back to cells will expand (with the ceiling division methods) to cover a full cell when even one pixel inside the cell is touched (as is how a redraw would have to occur). - Blocks off trace logging of invalid regions if no one is listening to optimize performance. - Restores full usage of `IDXGISwapChain1::Present1` to accurately and fully communicate dirty and scroll regions to the underlying DirectX framework. This additional information allows the framework to optimize drawing between frames by eliminating data transfer of regions that aren't modified and shuffling frames in place. See [Remarks](https://docs.microsoft.com/en-us/windows/win32/api/dxgi1_2/nf-dxgi1_2-idxgiswapchain1-present1#remarks) for more details. - Updates `til::bitmap` set methods to use more optimized versions of the setters on the `dynamic_bitset<>` that can bulk fill bits as the existing algorithm was noticeably slow after applying the "expand-to-row" helper to the DirectX renderer invalidation. - All `til` import hierarchy is now handled in the parent `til.h` file and not in the child files to prevent circular imports from happening. We don't expect the import of any individual library file, only the base one. So this should be OK for now. ## Validation Steps Performed - Ran `cmatrix`, `cmatrix -u0`, and `cacafire` after changes were made. - Made a bunch of ligatures with `Cascadia Code` in the Terminal before/after the changes and confirmed they still ligate. - Ran `dir` in Powershell and fixed the scrolling issues - Clicked all over the place and dragged to make sure selection works. - Checked retro terminal effect manually with Powershell.
2020-04-13 22:09:02 +02:00
void _ScrollPreviousSelection(const til::point delta);
std::vector<SMALL_RECT> _previousSelection;
[[nodiscard]] HRESULT _PaintTitle(IRenderEngine* const pEngine);
[[nodiscard]] std::optional<CursorOptions> _GetCursorInfo();
[[nodiscard]] HRESULT _PrepareRenderInfo(_In_ IRenderEngine* const pEngine);
// Helper functions to diagnose issues with painting and layout.
// These are only actually effective/on in Debug builds when the flag is set using an attached debugger.
bool _fDebug = false;
Create tests that roundtrip output through a conpty to a Terminal (#4213) ## Summary of the Pull Request This PR adds two tests: * First, I started by writing a test where I could write output to the console host and inspect what output came out of conpty. This is the `ConptyOutputTests` in the host unit tests. * Then I got crazy and thought _"what if I could take that output and dump it straight into the `Terminal`"_? Hence, the `ConptyRoundtripTests` were born, into the TerminalCore unit tests. ## References Done in pursuit of #4200, but I felt this warranted it's own atomic PR ## PR Checklist * [x] Doesn't close anything on it's own. * [x] I work here * [x] you better believe this adds tests * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments From the comment in `ConptyRoundtripTests`: > This test class creates an in-proc conpty host as well as a Terminal, to > validate that strings written to the conpty create the same resopnse on the > terminal end. Tests can be written that validate both the contents of the > host buffer as well as the terminal buffer. Everytime that > `renderer.PaintFrame()` is called, the tests will validate the expected > output, and then flush the output of the VtEngine straight to th Also, some other bits had to be updated: * The renderer needed to be able to survive without a thread, so I hadded a simple check that it actually had a thread before calling `pThread->NotifyPaint` * Bits in `CommonState` used `NTSTATUS_FROM_HRESULT` which did _not_ work outside the host project. Since the `NTSTATUS` didn't seem that important, I replaced that with a `HRESULT` * `CommonState` likes to initialize the console to some _weird_ defaults. I added an optional param to let us just use the defaults.
2020-01-17 17:40:12 +01:00
std::function<void()> _pfnRendererEnteredErrorState;
Create tests that roundtrip output through a conpty to a Terminal (#4213) ## Summary of the Pull Request This PR adds two tests: * First, I started by writing a test where I could write output to the console host and inspect what output came out of conpty. This is the `ConptyOutputTests` in the host unit tests. * Then I got crazy and thought _"what if I could take that output and dump it straight into the `Terminal`"_? Hence, the `ConptyRoundtripTests` were born, into the TerminalCore unit tests. ## References Done in pursuit of #4200, but I felt this warranted it's own atomic PR ## PR Checklist * [x] Doesn't close anything on it's own. * [x] I work here * [x] you better believe this adds tests * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments From the comment in `ConptyRoundtripTests`: > This test class creates an in-proc conpty host as well as a Terminal, to > validate that strings written to the conpty create the same resopnse on the > terminal end. Tests can be written that validate both the contents of the > host buffer as well as the terminal buffer. Everytime that > `renderer.PaintFrame()` is called, the tests will validate the expected > output, and then flush the output of the VtEngine straight to th Also, some other bits had to be updated: * The renderer needed to be able to survive without a thread, so I hadded a simple check that it actually had a thread before calling `pThread->NotifyPaint` * Bits in `CommonState` used `NTSTATUS_FROM_HRESULT` which did _not_ work outside the host project. Since the `NTSTATUS` didn't seem that important, I replaced that with a `HRESULT` * `CommonState` likes to initialize the console to some _weird_ defaults. I added an optional param to let us just use the defaults.
2020-01-17 17:40:12 +01:00
#ifdef UNIT_TESTING
friend class ConptyOutputTests;
#endif
};
}