From eec8dbd6d7179cfef9968fdc388434e062c3f191 Mon Sep 17 00:00:00 2001 From: "Dustin L. Howett" Date: Fri, 11 Aug 2023 10:32:34 -0500 Subject: [PATCH] WIP: Put padding in the atlas engine TODO: - [ ] the background texture gets rendered in the wrong place - [ ] clean up the weird "updatedpi" thing - [ ] handle Leonard's request to move the add after the M to get FMA - [ ] actually use it in TermControl lel --- src/renderer/atlas/AtlasEngine.api.cpp | 16 +++++++++++++++ src/renderer/atlas/AtlasEngine.h | 4 ++++ src/renderer/atlas/BackendD2D.cpp | 27 ++++++++++++++++++-------- src/renderer/atlas/BackendD2D.h | 4 +++- src/renderer/atlas/BackendD3D.cpp | 1 + src/renderer/atlas/BackendD3D.h | 1 + src/renderer/atlas/common.h | 1 + src/renderer/atlas/shader_vs.hlsl | 3 ++- src/renderer/inc/IRenderEngine.hpp | 1 + 9 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp index 10cf2e3a40..c4019e000d 100644 --- a/src/renderer/atlas/AtlasEngine.api.cpp +++ b/src/renderer/atlas/AtlasEngine.api.cpp @@ -194,6 +194,10 @@ void AtlasEngine::_invalidateSpans(std::span spans, const if (_api.s->font->dpi != newDPI) { _api.s.write()->font.write()->dpi = newDPI; + _api.s.write()->misc.write()->topLeftOffset = { + .x = _api.topLeftOffsetInDip.x * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI), + .y = _api.topLeftOffsetInDip.y * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI), + }; } return S_OK; @@ -900,3 +904,15 @@ void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, Fo _api.s.write()->font.write()->fontCollection = std::move(collection); return true; } + +void AtlasEngine::SetPadding(float x, float y) noexcept +{ + if (_api.topLeftOffsetInDip.x != x || _api.topLeftOffsetInDip.y != y) + { + _api.topLeftOffsetInDip = { x, y }; + _api.s.write()->misc.write()->topLeftOffset = { + .x = _api.topLeftOffsetInDip.x * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI), + .y = _api.topLeftOffsetInDip.y * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI), + }; + } +} diff --git a/src/renderer/atlas/AtlasEngine.h b/src/renderer/atlas/AtlasEngine.h index af77dcfe69..55394b8994 100644 --- a/src/renderer/atlas/AtlasEngine.h +++ b/src/renderer/atlas/AtlasEngine.h @@ -57,6 +57,7 @@ namespace Microsoft::Console::Render::Atlas [[nodiscard]] HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept override; [[nodiscard]] HRESULT UpdateTitle(std::wstring_view newTitle) noexcept override; void UpdateHyperlinkHoveredId(uint16_t hoveredId) noexcept override; + void SetPadding(float x, float y) noexcept override; // getter [[nodiscard]] std::wstring_view GetPixelShaderPath() noexcept; @@ -181,6 +182,9 @@ namespace Microsoft::Console::Render::Atlas // The position of the viewport inside the text buffer (in cells). u16x2 viewportOffset{ 0, 0 }; + + // SetPadding() + f32x2 topLeftOffsetInDip{ 0.f, 0.f }; } _api; }; } diff --git a/src/renderer/atlas/BackendD2D.cpp b/src/renderer/atlas/BackendD2D.cpp index c05dd1f21e..f0a56787f5 100644 --- a/src/renderer/atlas/BackendD2D.cpp +++ b/src/renderer/atlas/BackendD2D.cpp @@ -40,6 +40,8 @@ void BackendD2D::Render(RenderingPayload& p) _handleSettingsUpdate(p); } + const D2D1_MATRIX_3X2_F worldTransform{ _getDefaultTransform(p) }; + _renderTarget->BeginDraw(); try { @@ -48,6 +50,7 @@ void BackendD2D::Render(RenderingPayload& p) _renderTarget->Clear(); #endif _drawBackground(p); + _renderTarget->SetTransform(&worldTransform); _drawCursorPart1(p); _drawText(p); _drawCursorPart2(p); @@ -318,7 +321,7 @@ void BackendD2D::_drawText(RenderingPayload& p) if (row->lineRendition != LineRendition::SingleWidth) { - _drawTextResetLineRendition(row); + _drawTextResetLineRendition(p, row); } if (row->bitmap.revision != 0) @@ -505,17 +508,15 @@ void BackendD2D::_flushBuiltinGlyphs() f32 BackendD2D::_drawTextPrepareLineRendition(const RenderingPayload& p, const ShapedRow* row, f32 baselineY) const noexcept { const auto lineRendition = row->lineRendition; - D2D1_MATRIX_3X2_F transform{ - .m11 = 2.0f, - .m22 = 1.0f, - }; + D2D1_MATRIX_3X2_F transform{ _getDefaultTransform(p) }; + transform.m11 = 2.0f; // scale horizontally by 2.0 if (lineRendition >= LineRendition::DoubleHeightTop) { D2D1_RECT_F clipRect{ 0, 0, static_cast(p.s->targetSize.x), static_cast(p.s->targetSize.y) }; transform.m22 = 2.0f; - transform.dy = -1.0f * (baselineY + p.s->font->descender); + transform.dy += -1.0f * (baselineY + p.s->font->descender); // If you print the top half of a double height row (DECDHL), the expectation is that only // the top half is visible, which requires us to keep the clip rect at the bottom of the row. @@ -539,9 +540,9 @@ f32 BackendD2D::_drawTextPrepareLineRendition(const RenderingPayload& p, const S return baselineY; } -void BackendD2D::_drawTextResetLineRendition(const ShapedRow* row) const noexcept +void BackendD2D::_drawTextResetLineRendition(const RenderingPayload& p, const ShapedRow* row) const noexcept { - static constexpr D2D1_MATRIX_3X2_F identity{ .m11 = 1, .m22 = 1 }; + const auto identity{ _getDefaultTransform(p) }; _renderTarget->SetTransform(&identity); if (row->lineRendition >= LineRendition::DoubleHeightTop) @@ -1005,4 +1006,14 @@ void BackendD2D::_fillRectangle(const D2D1_RECT_F& rect, u32 color) _renderTarget->FillRectangle(&rect, brush); } +D2D_MATRIX_3X2_F BackendD2D::_getDefaultTransform(const RenderingPayload& p) const noexcept +{ + return { + .m11 = 1.f, + .m22 = 1.f, + .dx = p.s->misc->topLeftOffset.x, + .dy = p.s->misc->topLeftOffset.y, + }; +} + TIL_FAST_MATH_END diff --git a/src/renderer/atlas/BackendD2D.h b/src/renderer/atlas/BackendD2D.h index da4991bc41..3e7e257dbe 100644 --- a/src/renderer/atlas/BackendD2D.h +++ b/src/renderer/atlas/BackendD2D.h @@ -25,7 +25,7 @@ namespace Microsoft::Console::Render::Atlas D2D1_RECT_U _prepareBuiltinGlyph(const RenderingPayload& p, char32_t ch, u32 off); void _flushBuiltinGlyphs(); ATLAS_ATTR_COLD f32 _drawTextPrepareLineRendition(const RenderingPayload& p, const ShapedRow* row, f32 baselineY) const noexcept; - ATLAS_ATTR_COLD void _drawTextResetLineRendition(const ShapedRow* row) const noexcept; + ATLAS_ATTR_COLD void _drawTextResetLineRendition(const RenderingPayload& p, const ShapedRow* row) const noexcept; ATLAS_ATTR_COLD f32r _getGlyphRunDesignBounds(const DWRITE_GLYPH_RUN& glyphRun, f32 baselineX, f32 baselineY); ATLAS_ATTR_COLD void _drawGridlineRow(const RenderingPayload& p, const ShapedRow* row, u16 y); ATLAS_ATTR_COLD void _drawBitmap(const RenderingPayload& p, const ShapedRow* row, u16 y) const; @@ -40,6 +40,8 @@ namespace Microsoft::Console::Render::Atlas ATLAS_ATTR_COLD ID2D1SolidColorBrush* _brushWithColorUpdate(u32 color); void _fillRectangle(const D2D1_RECT_F& rect, u32 color); + D2D_MATRIX_3X2_F _getDefaultTransform(const RenderingPayload& p) const noexcept; + wil::com_ptr _renderTarget; wil::com_ptr _renderTarget4; // Optional. Supported since Windows 10 14393. wil::com_ptr _dottedStrokeStyle; diff --git a/src/renderer/atlas/BackendD3D.cpp b/src/renderer/atlas/BackendD3D.cpp index 60ee6aaf1d..51fabcf5be 100644 --- a/src/renderer/atlas/BackendD3D.cpp +++ b/src/renderer/atlas/BackendD3D.cpp @@ -576,6 +576,7 @@ void BackendD3D::_recreateConstBuffer(const RenderingPayload& p) const { VSConstBuffer data{}; data.positionScale = { 2.0f / p.s->targetSize.x, -2.0f / p.s->targetSize.y }; + data.padding = { p.s->misc->topLeftOffset.x, p.s->misc->topLeftOffset.y, 0.f, 0.f }; p.deviceContext->UpdateSubresource(_vsConstantBuffer.get(), 0, nullptr, &data, 0, 0); } { diff --git a/src/renderer/atlas/BackendD3D.h b/src/renderer/atlas/BackendD3D.h index 962d691b01..6eb23f4faa 100644 --- a/src/renderer/atlas/BackendD3D.h +++ b/src/renderer/atlas/BackendD3D.h @@ -29,6 +29,7 @@ namespace Microsoft::Console::Render::Atlas // padding so that it is {u32; u32; u32; <4 byte padding>; u32x2}. // * bool will probably not work the way you want it to, // because HLSL uses 32-bit bools and C++ doesn't. + alignas(sizeof(f32x4)) f32x4 padding; alignas(sizeof(f32x2)) f32x2 positionScale; #pragma warning(suppress : 4324) // 'VSConstBuffer': structure was padded due to alignment specifier }; diff --git a/src/renderer/atlas/common.h b/src/renderer/atlas/common.h index 6668e2ce3c..9b8416c521 100644 --- a/src/renderer/atlas/common.h +++ b/src/renderer/atlas/common.h @@ -399,6 +399,7 @@ namespace Microsoft::Console::Render::Atlas std::wstring customPixelShaderPath; std::wstring customPixelShaderImagePath; bool useRetroTerminalEffect = false; + f32x2 topLeftOffset{ 0.f, 0.f }; }; struct Settings diff --git a/src/renderer/atlas/shader_vs.hlsl b/src/renderer/atlas/shader_vs.hlsl index eb96fcf0e4..50ba9871f7 100644 --- a/src/renderer/atlas/shader_vs.hlsl +++ b/src/renderer/atlas/shader_vs.hlsl @@ -5,6 +5,7 @@ cbuffer ConstBuffer : register(b0) { + float4 padding; float2 positionScale; } @@ -18,7 +19,7 @@ PSData main(VSData data) output.renditionScale = data.renditionScale; // positionScale is expected to be float2(2.0f / sizeInPixel.x, -2.0f / sizeInPixel.y). Together with the // addition below this will transform our "position" from pixel into normalized device coordinate (NDC) space. - output.position.xy = (data.position + data.vertex.xy * data.size) * positionScale + float2(-1.0f, 1.0f); + output.position.xy = (padding.xy + data.position + data.vertex.xy * data.size) * positionScale + float2(-1.0f, 1.0f); output.position.zw = float2(0, 1); output.texcoord = data.texcoord + data.vertex.xy * data.size; return output; diff --git a/src/renderer/inc/IRenderEngine.hpp b/src/renderer/inc/IRenderEngine.hpp index a2cc944f29..d4028e7a56 100644 --- a/src/renderer/inc/IRenderEngine.hpp +++ b/src/renderer/inc/IRenderEngine.hpp @@ -94,6 +94,7 @@ namespace Microsoft::Console::Render [[nodiscard]] virtual HRESULT IsGlyphWideByFont(std::wstring_view glyph, _Out_ bool* pResult) noexcept = 0; [[nodiscard]] virtual HRESULT UpdateTitle(std::wstring_view newTitle) noexcept = 0; virtual void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept = 0; + virtual void SetPadding(float x, float y) noexcept = 0; }; } #pragma warning(pop)