// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. #pragma once #include "../../renderer/inc/RenderEngineBase.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include "CustomTextRenderer.h" #include "../../types/inc/Viewport.hpp" #include TRACELOGGING_DECLARE_PROVIDER(g_hDxRenderProvider); namespace Microsoft::Console::Render { class DxEngine final : public RenderEngineBase { public: DxEngine(); ~DxEngine(); DxEngine(const DxEngine&) = default; DxEngine(DxEngine&&) = default; DxEngine& operator=(const DxEngine&) = default; DxEngine& operator=(DxEngine&&) = default; // Used to release device resources so that another instance of // conhost can render to the screen (i.e. only one DirectX // application may control the screen at a time.) [[nodiscard]] HRESULT Enable() noexcept; [[nodiscard]] HRESULT Disable() noexcept; [[nodiscard]] HRESULT SetHwnd(const HWND hwnd) noexcept; [[nodiscard]] HRESULT SetWindowSize(const SIZE pixels) noexcept; void SetCallback(std::function pfn); void SetRetroTerminalEffects(bool enable) noexcept; ::Microsoft::WRL::ComPtr GetSwapChain(); // IRenderEngine Members [[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override; [[nodiscard]] HRESULT InvalidateCursor(const COORD* const pcoordCursor) noexcept override; [[nodiscard]] HRESULT InvalidateSystem(const RECT* const prcDirtyClient) noexcept override; [[nodiscard]] HRESULT InvalidateSelection(const std::vector& rectangles) noexcept override; [[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override; [[nodiscard]] HRESULT InvalidateAll() noexcept override; [[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override; [[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override; [[nodiscard]] HRESULT StartPaint() noexcept override; [[nodiscard]] HRESULT EndPaint() noexcept override; [[nodiscard]] HRESULT Present() noexcept override; [[nodiscard]] HRESULT ScrollFrame() noexcept override; [[nodiscard]] HRESULT PaintBackground() noexcept override; [[nodiscard]] HRESULT PaintBufferLine(std::basic_string_view const clusters, COORD const coord, bool const fTrimLeft, const bool lineWrapped) noexcept override; [[nodiscard]] HRESULT PaintBufferGridLines(GridLines const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override; [[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override; [[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override; [[nodiscard]] HRESULT UpdateDrawingBrushes(COLORREF const colorForeground, COLORREF const colorBackground, const WORD legacyColorAttribute, const ExtendedAttributes extendedAttrs, bool const isSettingDefaultBrushes) noexcept override; [[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept override; [[nodiscard]] HRESULT UpdateDpi(int const iDpi) noexcept override; [[nodiscard]] HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept override; [[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override; [[nodiscard]] std::vector GetDirtyArea() override; [[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override; [[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override; [[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInCharacters(const ::Microsoft::Console::Types::Viewport& viewInPixels) noexcept; float GetScaling() const noexcept; void SetSelectionBackground(const COLORREF color) noexcept; void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept; void SetDefaultTextBackgroundOpacity(const float opacity) noexcept; protected: [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring& newTitle) noexcept override; [[nodiscard]] HRESULT _PaintTerminalEffects() noexcept; private: enum class SwapChainMode { ForHwnd, ForComposition }; SwapChainMode _chainMode; HWND _hwndTarget; til::size _sizeTarget; int _dpi; float _scale; float _prevScale; std::function _pfn; bool _isEnabled; bool _isPainting; til::size _displaySizePixels; til::size _glyphCell; ::Microsoft::WRL::ComPtr _boxDrawingEffect; D2D1_COLOR_F _defaultForegroundColor; D2D1_COLOR_F _defaultBackgroundColor; D2D1_COLOR_F _foregroundColor; D2D1_COLOR_F _backgroundColor; D2D1_COLOR_F _selectionBackground; bool _firstFrame; bool _invalidateFullRows; til::bitmap _invalidMap; til::point _invalidScroll; bool _presentReady; std::vector _presentDirty; RECT _presentScroll; POINT _presentOffset; DXGI_PRESENT_PARAMETERS _presentParams; static std::atomic _tracelogCount; static const ULONG s_ulMinCursorHeightPercent = 25; static const ULONG s_ulMaxCursorHeightPercent = 100; // Device-Independent Resources ::Microsoft::WRL::ComPtr _d2dFactory; ::Microsoft::WRL::ComPtr _dwriteFactory; ::Microsoft::WRL::ComPtr _dwriteTextFormat; ::Microsoft::WRL::ComPtr _dwriteFontFace; ::Microsoft::WRL::ComPtr _dwriteTextAnalyzer; ::Microsoft::WRL::ComPtr _customRenderer; ::Microsoft::WRL::ComPtr _strokeStyle; // Device-Dependent Resources bool _haveDeviceResources; ::Microsoft::WRL::ComPtr _d3dDevice; ::Microsoft::WRL::ComPtr _d3dDeviceContext; ::Microsoft::WRL::ComPtr _dxgiFactory2; ::Microsoft::WRL::ComPtr _dxgiSurface; ::Microsoft::WRL::ComPtr _d2dRenderTarget; ::Microsoft::WRL::ComPtr _d2dBrushForeground; ::Microsoft::WRL::ComPtr _d2dBrushBackground; ::Microsoft::WRL::ComPtr _dxgiSwapChain; // Terminal effects resources. bool _retroTerminalEffects; ::Microsoft::WRL::ComPtr _renderTargetView; ::Microsoft::WRL::ComPtr _vertexShader; ::Microsoft::WRL::ComPtr _pixelShader; ::Microsoft::WRL::ComPtr _vertexLayout; ::Microsoft::WRL::ComPtr _screenQuadVertexBuffer; ::Microsoft::WRL::ComPtr _pixelShaderSettingsBuffer; ::Microsoft::WRL::ComPtr _samplerState; ::Microsoft::WRL::ComPtr _framebufferCapture; D2D1_TEXT_ANTIALIAS_MODE _antialiasingMode; float _defaultTextBackgroundOpacity; // DirectX constant buffers need to be a multiple of 16; align to pad the size. __declspec(align(16)) struct { float ScaledScanLinePeriod; float ScaledGaussianSigma; #pragma warning(suppress : 4324) // structure was padded due to __declspec(align()) } _pixelShaderSettings; [[nodiscard]] HRESULT _CreateDeviceResources(const bool createSwapChain) noexcept; HRESULT _SetupTerminalEffects(); void _ComputePixelShaderSettings() noexcept; [[nodiscard]] HRESULT _PrepareRenderTarget() noexcept; void _ReleaseDeviceResources() noexcept; [[nodiscard]] HRESULT _CreateTextLayout( _In_reads_(StringLength) PCWCHAR String, _In_ size_t StringLength, _Out_ IDWriteTextLayout** ppTextLayout) noexcept; [[nodiscard]] HRESULT _CopyFrontToBack() noexcept; [[nodiscard]] HRESULT _EnableDisplayAccess(const bool outputEnabled) noexcept; [[nodiscard]] ::Microsoft::WRL::ComPtr _ResolveFontFaceWithFallback(std::wstring& familyName, DWRITE_FONT_WEIGHT& weight, DWRITE_FONT_STRETCH& stretch, DWRITE_FONT_STYLE& style, std::wstring& localeName) const; [[nodiscard]] ::Microsoft::WRL::ComPtr _FindFontFace(std::wstring& familyName, DWRITE_FONT_WEIGHT& weight, DWRITE_FONT_STRETCH& stretch, DWRITE_FONT_STYLE& style, std::wstring& localeName) const; [[nodiscard]] std::wstring _GetLocaleName() const; [[nodiscard]] std::wstring _GetFontFamilyName(gsl::not_null const fontFamily, std::wstring& localeName) const; [[nodiscard]] HRESULT _GetProposedFont(const FontInfoDesired& desired, FontInfo& actual, const int dpi, ::Microsoft::WRL::ComPtr& textFormat, ::Microsoft::WRL::ComPtr& textAnalyzer, ::Microsoft::WRL::ComPtr& fontFace) const noexcept; [[nodiscard]] til::size _GetClientSize() const; void _InvalidateRectangle(const til::rectangle& rc); [[nodiscard]] D2D1_COLOR_F _ColorFFromColorRef(const COLORREF color) noexcept; // Routine Description: // - Helps convert a Direct2D ColorF into a DXGI RGBA // Arguments: // - color - Direct2D Color F // Return Value: // - DXGI RGBA [[nodiscard]] constexpr DXGI_RGBA s_RgbaFromColorF(const D2D1_COLOR_F color) noexcept { return { color.r, color.g, color.b, color.a }; } }; }