Compare commits

...

8 Commits

Author SHA1 Message Date
Dustin L. Howett
0963bfe4c2 Atlas: oh, think about the gutters too... 2025-08-03 20:37:59 -05:00
Dustin L. Howett
03afcfd7e8 TC: wow i hate this (propagate padding in like 9 places) 2025-08-03 20:37:42 -05:00
Dustin L. Howett
2dac785e1a TC: actually, we don't want to calculate panel size without padding 2025-08-03 20:19:12 -05:00
Dustin L. Howett
b67fb19f7c Yeet the padding in through TermControl and try to fix up everywhere it might break
IT IS STILL BROKEN when scrolling for example as it doesn't clear the gutters
2025-08-03 20:09:40 -05:00
Dustin L. Howett
85c2628808 make it viewport, in tex coords, and fix the build 2025-08-01 20:24:30 -05:00
Dustin Howett
e89b17e562 TopLeft -> full Padding (to pass to the user shader!) 2025-07-29 14:35:58 -05:00
Leonard Hecker
2a58b001bf Offset background texture and use Sample() instead of Load() 2025-07-29 14:35:58 -05:00
Dustin L. Howett
eec8dbd6d7 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
2025-07-29 14:35:58 -05:00
15 changed files with 184 additions and 88 deletions

View File

@@ -361,6 +361,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// and react accordingly.
_updateFont();
const auto padding = StringToXamlThickness(_settings->Padding());
auto padx = gsl::narrow_cast<til::CoordType>(lrint((padding.Left + padding.Right) * _compositionScale));
auto pady = gsl::narrow_cast<til::CoordType>(lrint((padding.Top + padding.Bottom) * _compositionScale));
const til::size windowSize{ til::math::rounding, windowWidth, windowHeight };
// First set up the dx engine with the window size in pixels.
@@ -369,7 +373,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto viewInPixels = Viewport::FromDimensions({ 0, 0 }, windowSize);
LOG_IF_FAILED(_renderEngine->SetWindowSize({ viewInPixels.Width(), viewInPixels.Height() }));
const auto vp = _renderEngine->GetViewportInCharacters(viewInPixels);
const auto vp = _renderEngine->GetViewportInCharacters(Viewport::FromDimensions({ 0, 0 }, { viewInPixels.Width() - padx, viewInPixels.Height() - pady }));
const auto width = vp.Width();
const auto height = vp.Height();
@@ -399,6 +403,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_renderEngineSwapChainChanged(handle);
});
_renderEngine->SetPadding(static_cast<float>(padding.Left),
static_cast<float>(padding.Top),
static_cast<float>(padding.Right),
static_cast<float>(padding.Bottom));
_renderEngine->SetRetroTerminalEffect(_settings->RetroTerminalEffect());
_renderEngine->SetPixelShaderPath(_settings->PixelShaderPath());
_renderEngine->SetPixelShaderImagePath(_settings->PixelShaderImagePath());
@@ -900,6 +908,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// Inform the renderer of our opacity
_renderEngine->EnableTransparentBackground(_isBackgroundTransparent());
const auto padding = StringToXamlThickness(_settings->Padding());
_renderEngine->SetPadding(static_cast<float>(padding.Left),
static_cast<float>(padding.Top),
static_cast<float>(padding.Right),
static_cast<float>(padding.Bottom));
// Trigger a redraw to repaint the window background and tab colors.
_renderer->TriggerRedrawAll(true, true);
@@ -1115,6 +1129,12 @@ namespace winrt::Microsoft::Terminal::Control::implementation
auto cx = gsl::narrow_cast<til::CoordType>(lrint(_panelWidth * _compositionScale));
auto cy = gsl::narrow_cast<til::CoordType>(lrint(_panelHeight * _compositionScale));
const auto padding = StringToXamlThickness(_settings->Padding());
auto padx = gsl::narrow_cast<til::CoordType>(lrint((padding.Left + padding.Right) * _compositionScale));
auto pady = gsl::narrow_cast<til::CoordType>(lrint((padding.Top + padding.Bottom) * _compositionScale));
cx -= padx;
cy -= pady;
// Don't actually resize so small that a single character wouldn't fit
// in either dimension. The buffer really doesn't like being size 0.
@@ -1128,7 +1148,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_terminal->ClearSelection();
// Tell the dx engine that our window is now the new size.
THROW_IF_FAILED(_renderEngine->SetWindowSize({ cx, cy }));
THROW_IF_FAILED(_renderEngine->SetWindowSize({ cx + padx, cy + pady }));
// Invalidate everything
_renderer->TriggerRedrawAll();

View File

@@ -214,7 +214,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto scaleFactor = static_cast<float>(DisplayInformation::GetForCurrentView().RawPixelsPerViewPixel());
const auto localOrigin = _termControl->TransformToVisual(nullptr).TransformPoint({});
const auto padding = _termControl->GetPadding();
const auto& padding = _termControl->_contentPadding;
const auto cursorPosition = core->CursorPosition();
const auto fontSize = core->FontSize();
@@ -928,9 +928,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// settings might be out-of-proc in the future
auto settings{ _core.Settings() };
// Apply padding as swapChainPanel's margin
const auto newMargin = StringToXamlThickness(settings.Padding());
SwapChainPanel().Margin(newMargin);
// Store the padding for UI calculations
_contentPadding = StringToXamlThickness(settings.Padding());
// Apply settings for scrollbar
if (settings.ScrollState() == ScrollbarState::Hidden)
@@ -957,10 +956,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_automationPeer)
{
_automationPeer.SetControlPadding(Core::Padding{
static_cast<float>(newMargin.Left),
static_cast<float>(newMargin.Top),
static_cast<float>(newMargin.Right),
static_cast<float>(newMargin.Bottom),
static_cast<float>(_contentPadding.Left),
static_cast<float>(_contentPadding.Top),
static_cast<float>(_contentPadding.Right),
static_cast<float>(_contentPadding.Bottom),
});
}
@@ -1234,12 +1233,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// (https://docs.microsoft.com/en-us/windows/uwp/design/accessibility/custom-automation-peers)
if (const auto& interactivityAutoPeer{ _interactivity.OnCreateAutomationPeer() })
{
const auto margins{ SwapChainPanel().Margin() };
const Core::Padding padding{
static_cast<float>(margins.Left),
static_cast<float>(margins.Top),
static_cast<float>(margins.Right),
static_cast<float>(margins.Bottom),
static_cast<float>(_contentPadding.Left),
static_cast<float>(_contentPadding.Top),
static_cast<float>(_contentPadding.Right),
static_cast<float>(_contentPadding.Bottom),
};
_automationPeer = winrt::make<implementation::TermControlAutomationPeer>(get_strong(), padding, interactivityAutoPeer);
return _automationPeer;
@@ -1255,11 +1253,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
return _core.FontSize();
}
const Windows::UI::Xaml::Thickness TermControl::GetPadding()
{
return SwapChainPanel().Margin();
}
TerminalConnection::ConnectionState TermControl::ConnectionState() const
{
return _core.ConnectionState();
@@ -1452,12 +1445,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
if (_automationPeer)
{
_automationPeer.UpdateControlBounds();
const auto margins{ GetPadding() };
_automationPeer.SetControlPadding(Core::Padding{
static_cast<float>(margins.Left),
static_cast<float>(margins.Top),
static_cast<float>(margins.Right),
static_cast<float>(margins.Bottom),
static_cast<float>(_contentPadding.Left),
static_cast<float>(_contentPadding.Top),
static_cast<float>(_contentPadding.Right),
static_cast<float>(_contentPadding.Bottom),
});
}
@@ -2063,8 +2055,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// SwapChainPanel, not the entire control. If they drag out of
// the bounds of the text, into the padding, we still what that
// to auto-scroll
const auto cursorBelowBottomDist = cursorPosition.Y - SwapChainPanel().Margin().Top - SwapChainPanel().ActualHeight();
const auto cursorAboveTopDist = -1 * cursorPosition.Y + SwapChainPanel().Margin().Top;
const auto cursorBelowBottomDist = cursorPosition.Y - _contentPadding.Top - SwapChainPanel().ActualHeight();
const auto cursorAboveTopDist = -1 * cursorPosition.Y + _contentPadding.Top;
constexpr auto MinAutoScrollDist = 2.0; // Arbitrary value
auto newAutoScrollVelocity = 0.0;
@@ -2964,9 +2956,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// Account for the size of any padding
const auto padding = GetPadding();
width += static_cast<float>(padding.Left + padding.Right);
height += static_cast<float>(padding.Top + padding.Bottom);
width += static_cast<float>(_contentPadding.Left + _contentPadding.Right);
height += static_cast<float>(_contentPadding.Top + _contentPadding.Bottom);
return { width, height };
}
@@ -2991,10 +2982,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
const auto fontSize = _core.FontSizeInDips();
const auto fontDimension = widthOrHeight ? fontSize.Width : fontSize.Height;
const auto padding = GetPadding();
auto nonTerminalArea = gsl::narrow_cast<float>(widthOrHeight ?
padding.Left + padding.Right :
padding.Top + padding.Bottom);
_contentPadding.Left + _contentPadding.Right :
_contentPadding.Top + _contentPadding.Bottom);
if (widthOrHeight && _core.Settings().ScrollState() != ScrollbarState::Hidden)
{
@@ -3088,12 +3078,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::Foundation::Point TermControl::_toControlOrigin(const til::point terminalPos)
{
const auto fontSize{ CharacterDimensions() };
auto padding{ GetPadding() };
// Convert text buffer cursor position to client coordinate position within the window.
return {
terminalPos.x * fontSize.Width + static_cast<float>(padding.Left),
terminalPos.y * fontSize.Height + static_cast<float>(padding.Top),
terminalPos.x * fontSize.Width + static_cast<float>(_contentPadding.Left),
terminalPos.y * fontSize.Height + static_cast<float>(_contentPadding.Top),
};
}
@@ -3107,12 +3096,9 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// - the corresponding viewport terminal position (in pixels) for the given Point parameter
Core::Point TermControl::_toTerminalOrigin(winrt::Windows::Foundation::Point cursorPosition)
{
// cursorPosition is DIPs, relative to SwapChainPanel origin
const auto padding = GetPadding();
// This point is the location of the cursor within the actual grid of characters, in DIPs
const auto relativeToMarginInDIPsX = cursorPosition.X - static_cast<float>(padding.Left);
const auto relativeToMarginInDIPsY = cursorPosition.Y - static_cast<float>(padding.Top);
const auto relativeToMarginInDIPsX = cursorPosition.X - static_cast<float>(_contentPadding.Left);
const auto relativeToMarginInDIPsY = cursorPosition.Y - static_cast<float>(_contentPadding.Top);
// Convert it to pixels
const auto scale = SwapChainPanel().CompositionScaleX();
@@ -3668,11 +3654,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
winrt::Windows::Foundation::Point TermControl::_toPosInDips(const Core::Point terminalCellPos)
{
const auto marginsInDips{ GetPadding() };
const auto fontSize{ _core.FontSizeInDips() };
return {
terminalCellPos.X * fontSize.Width + static_cast<float>(marginsInDips.Left),
terminalCellPos.Y * fontSize.Height + static_cast<float>(marginsInDips.Top),
terminalCellPos.X * fontSize.Width + static_cast<float>(_contentPadding.Left),
terminalCellPos.Y * fontSize.Height + static_cast<float>(_contentPadding.Top),
};
}
@@ -3950,14 +3935,11 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// CharacterDimensions returns a font size in pixels.
const auto fontSize{ CharacterDimensions() };
// Account for the margins, which are in DIPs
auto padding{ GetPadding() };
// Convert text buffer cursor position to client coordinate position
// within the window. This point is in _pixels_
return {
cursorPos.X * fontSize.Width + static_cast<float>(padding.Left),
cursorPos.Y * fontSize.Height + static_cast<float>(padding.Top),
cursorPos.X * fontSize.Width + static_cast<float>(_contentPadding.Left),
cursorPos.Y * fontSize.Height + static_cast<float>(_contentPadding.Top),
};
}
@@ -3965,11 +3947,10 @@ namespace winrt::Microsoft::Terminal::Control::implementation
Control::ContextMenuRequestedEventArgs args)
{
const auto inverseScale = 1.0f / static_cast<float>(XamlRoot().RasterizationScale());
const auto padding = GetPadding();
const auto pos = args.Position();
_showContextMenuAt({
pos.X * inverseScale + static_cast<float>(padding.Left),
pos.Y * inverseScale + static_cast<float>(padding.Top),
pos.X * inverseScale + static_cast<float>(_contentPadding.Left),
pos.Y * inverseScale + static_cast<float>(_contentPadding.Top),
});
}
@@ -4012,7 +3993,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
double TermControl::QuickFixButtonWidth()
{
const auto leftPadding = GetPadding().Left;
const auto leftPadding = _contentPadding.Left;
if (_quickFixButtonCollapsible)
{
const auto cellWidth = CharacterDimensions().Width;
@@ -4027,7 +4008,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
double TermControl::QuickFixButtonCollapsedWidth()
{
return std::max(CharacterDimensions().Width * 2.0 / 3.0, GetPadding().Left);
return std::max(CharacterDimensions().Width * 2.0 / 3.0, _contentPadding.Left);
}
bool TermControl::OpenQuickFixMenu()
@@ -4064,10 +4045,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
}
// If the gutter is narrow, display the collapsed version
const auto& termPadding = GetPadding();
// Make sure to update _quickFixButtonCollapsible and QuickFix button widths BEFORE updating the VisualState
_quickFixButtonCollapsible = termPadding.Left < CharacterDimensions().Width;
_quickFixButtonCollapsible = _contentPadding.Left < CharacterDimensions().Width;
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"QuickFixButtonWidth" });
PropertyChanged.raise(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"QuickFixButtonCollapsedWidth" });
VisualStateManager::GoToState(*this, !_quickFixButtonCollapsible ? StateNormal : StateCollapsed, false);
@@ -4084,8 +4063,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation
// draw the button in the gutter
const auto& quickFixBtnPosInDips = _toPosInDips({ 0, _quickFixBufferPos });
Controls::Canvas::SetLeft(quickFixBtn, -termPadding.Left);
Controls::Canvas::SetTop(quickFixBtn, quickFixBtnPosInDips.Y - termPadding.Top);
Controls::Canvas::SetLeft(quickFixBtn, -_contentPadding.Left);
Controls::Canvas::SetTop(quickFixBtn, quickFixBtnPosInDips.Y - _contentPadding.Top);
quickFixBtn.Visibility(Visibility::Visible);
if (auto automationPeer{ FrameworkElementAutomationPeer::FromElement(*this) })

View File

@@ -152,7 +152,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
~TermControl();
Windows::UI::Xaml::Automation::Peers::AutomationPeer OnCreateAutomationPeer();
const Windows::UI::Xaml::Thickness GetPadding();
static Windows::Foundation::Size GetProposedDimensions(const IControlSettings& settings,
const uint32_t dpi,
@@ -283,6 +282,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
bool _quickFixButtonCollapsible{ false };
bool _quickFixesAvailable{ false };
til::CoordType _quickFixBufferPos{};
Windows::UI::Xaml::Thickness _contentPadding{ 0.f };
std::shared_ptr<ThrottledFuncLeading> _playWarningBell;

View File

@@ -194,6 +194,12 @@ void AtlasEngine::_invalidateSpans(std::span<const til::point_span> spans, const
if (_api.s->font->dpi != newDPI)
{
_api.s.write()->font.write()->dpi = newDPI;
_api.s.write()->misc.write()->padding = {
.x = _api.paddingInDip.x * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.y = _api.paddingInDip.y * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.z = _api.paddingInDip.z * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.w = _api.paddingInDip.w * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
};
}
return S_OK;
@@ -900,3 +906,18 @@ void AtlasEngine::_resolveFontMetrics(const FontInfoDesired& fontInfoDesired, Fo
_api.s.write()->font.write()->fontCollection = std::move(collection);
return true;
}
void AtlasEngine::SetPadding(float left, float top, float right, float bottom) noexcept
{
f32x4 newPadding{ left, top, right, bottom };
if (_api.paddingInDip != newPadding)
{
_api.paddingInDip = newPadding;
_api.s.write()->misc.write()->padding = {
.x = _api.paddingInDip.x * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.y = _api.paddingInDip.y * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.z = _api.paddingInDip.z * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
.w = _api.paddingInDip.w * (_api.s->font->dpi / USER_DEFAULT_SCREEN_DPI),
};
}
}

View File

@@ -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 left, float top, float right, float bottom) 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()
f32x4 paddingInDip{ 0.f, 0.f, 0.f, 0.f };
} _api;
};
}

View File

@@ -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<f32>(p.s->targetSize.x), static_cast<f32>(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->padding.x,
.dy = p.s->misc->padding.y,
};
}
TIL_FAST_MATH_END

View File

@@ -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<ID2D1DeviceContext> _renderTarget;
wil::com_ptr<ID2D1DeviceContext4> _renderTarget4; // Optional. Supported since Windows 10 14393.
wil::com_ptr<ID2D1StrokeStyle> _dottedStrokeStyle;

View File

@@ -571,18 +571,30 @@ void BackendD3D::_recreateBackgroundColorBitmap(const RenderingPayload& p)
_backgroundBitmapGeneration = {};
}
void BackendD3D::_recreateConstBuffer(const RenderingPayload& p) const
void BackendD3D::_recreateConstBuffer(const RenderingPayload& p)
{
{
VSConstBuffer data{};
data.positionScale = { 2.0f / p.s->targetSize.x, -2.0f / p.s->targetSize.y };
data.positionScale = {
2.0f / p.s->targetSize.x,
-2.0f / p.s->targetSize.y,
};
data.positionOffset = {
data.positionScale.x * p.s->misc->padding.x - 1.0f,
data.positionScale.y * p.s->misc->padding.y + 1.0f,
};
p.deviceContext->UpdateSubresource(_vsConstantBuffer.get(), 0, nullptr, &data, 0, 0);
}
{
PSConstBuffer data{};
data.backgroundColor = colorFromU32Premultiply<f32x4>(p.s->misc->backgroundColor);
data.backgroundCellSize = { static_cast<f32>(p.s->font->cellSize.x), static_cast<f32>(p.s->font->cellSize.y) };
data.backgroundCellCount = { static_cast<f32>(p.s->viewportCellCount.x), static_cast<f32>(p.s->viewportCellCount.y) };
data.backgroundScale = {
1.0f / (p.s->font->cellSize.x * p.s->viewportCellCount.x),
1.0f / (p.s->font->cellSize.y * p.s->viewportCellCount.y),
};
data.backgroundOffset = {
data.backgroundScale.x * -p.s->misc->padding.x,
data.backgroundScale.y * -p.s->misc->padding.y,
};
DWrite_GetGammaRatios(_gamma, data.gammaRatios);
data.enhancedContrast = p.s->font->antialiasingMode == AntialiasingMode::ClearType ? _cleartypeEnhancedContrast : _grayscaleEnhancedContrast;
data.underlineWidth = p.s->font->underline.height;
@@ -594,6 +606,23 @@ void BackendD3D::_recreateConstBuffer(const RenderingPayload& p) const
data.shadedGlyphDotSize = std::max(1.0f, std::roundf(std::max(p.s->font->cellSize.x / 12.0f, p.s->font->cellSize.y / 24.0f)));
p.deviceContext->UpdateSubresource(_psConstantBuffer.get(), 0, nullptr, &data, 0, 0);
}
{
const auto color = colorFromU32Premultiply<f32x4>(p.s->misc->backgroundColor);
const D3D11_SAMPLER_DESC desc{
.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT,
.AddressU = D3D11_TEXTURE_ADDRESS_BORDER,
.AddressV = D3D11_TEXTURE_ADDRESS_BORDER,
.AddressW = D3D11_TEXTURE_ADDRESS_BORDER,
.MipLODBias = 0,
.MaxAnisotropy = 1,
.ComparisonFunc = D3D11_COMPARISON_NEVER,
.BorderColor = { color.x, color.y, color.z, color.w },
//.BorderColor = { 1.0f, 0.2f, 0.2f, 1.0f },
.MinLOD = -FLT_MAX,
.MaxLOD = FLT_MAX,
};
THROW_IF_FAILED(p.device->CreateSamplerState(&desc, _backgroundSampler.put()));
}
}
void BackendD3D::_setupDeviceContextState(const RenderingPayload& p)
@@ -622,6 +651,7 @@ void BackendD3D::_setupDeviceContextState(const RenderingPayload& p)
p.deviceContext->PSSetShader(_pixelShader.get(), nullptr, 0);
p.deviceContext->PSSetConstantBuffers(0, 1, _psConstantBuffer.addressof());
p.deviceContext->PSSetShaderResources(0, 2, &resources[0]);
p.deviceContext->PSSetSamplers(0, 1, _backgroundSampler.addressof());
// OM: Output Merger
p.deviceContext->OMSetBlendState(_blendState.get(), nullptr, 0xffffffff);
@@ -1072,6 +1102,10 @@ void BackendD3D::_drawBackground(const RenderingPayload& p)
_appendQuad() = {
.shadingType = static_cast<u16>(ShadingType::Background),
.position = {
static_cast<i16>(lrintf(-p.s->misc->padding.x)),
static_cast<i16>(lrintf(-p.s->misc->padding.x)),
},
.size = p.s->targetSize,
};
}
@@ -2306,14 +2340,30 @@ void BackendD3D::_executeCustomShader(RenderingPayload& p)
const auto now = queryPerfCount();
const auto time = static_cast<int>(now % _customShaderPerfTickMod) * _customShaderSecsPerPerfTick;
const f32x2 scale = {
1.0f / p.s->targetSize.x,
1.0f / p.s->targetSize.y,
};
const f32x2 physicalVpSize = {
p.s->viewportCellCount.x * p.s->font->cellSize.x,
p.s->viewportCellCount.y * p.s->font->cellSize.y,
};
const CustomConstBuffer data{
.time = time,
.scale = static_cast<f32>(p.s->font->dpi) / static_cast<f32>(USER_DEFAULT_SCREEN_DPI),
.resolution = {
static_cast<f32>(_viewportCellCount.x * p.s->font->cellSize.x),
static_cast<f32>(_viewportCellCount.y * p.s->font->cellSize.y),
static_cast<f32>(p.s->targetSize.x),
static_cast<f32>(p.s->targetSize.y),
},
.background = colorFromU32Premultiply<f32x4>(p.s->misc->backgroundColor),
.viewport = {
static_cast<f32>(p.s->misc->padding.x) * scale.x,
static_cast<f32>(p.s->misc->padding.y) * scale.y,
static_cast<f32>(p.s->misc->padding.x + physicalVpSize.x) * scale.x,
static_cast<f32>(p.s->misc->padding.y + physicalVpSize.y) * scale.y,
}
};
D3D11_MAPPED_SUBRESOURCE mapped{};
@@ -2372,7 +2422,7 @@ void BackendD3D::_executeCustomShader(RenderingPayload& p)
p.deviceContext->PSSetShader(_pixelShader.get(), nullptr, 0);
p.deviceContext->PSSetConstantBuffers(0, 1, _psConstantBuffer.addressof());
p.deviceContext->PSSetShaderResources(0, 2, &resources[0]);
p.deviceContext->PSSetSamplers(0, 0, nullptr);
p.deviceContext->PSSetSamplers(0, 1, _backgroundSampler.addressof());
// OM: Output Merger
p.deviceContext->OMSetBlendState(_blendState.get(), nullptr, 0xffffffff);

View File

@@ -30,15 +30,15 @@ namespace Microsoft::Console::Render::Atlas
// * bool will probably not work the way you want it to,
// because HLSL uses 32-bit bools and C++ doesn't.
alignas(sizeof(f32x2)) f32x2 positionScale;
alignas(sizeof(f32x2)) f32x2 positionOffset;
#pragma warning(suppress : 4324) // 'VSConstBuffer': structure was padded due to alignment specifier
};
// WARNING: Same rules as for VSConstBuffer above apply.
struct alignas(16) PSConstBuffer
{
alignas(sizeof(f32x4)) f32x4 backgroundColor;
alignas(sizeof(f32x2)) f32x2 backgroundCellSize;
alignas(sizeof(f32x2)) f32x2 backgroundCellCount;
alignas(sizeof(f32x2)) f32x2 backgroundScale;
alignas(sizeof(f32x2)) f32x2 backgroundOffset;
alignas(sizeof(f32x4)) f32 gammaRatios[4]{};
alignas(sizeof(f32)) f32 enhancedContrast = 0;
alignas(sizeof(f32)) f32 underlineWidth = 0;
@@ -55,6 +55,7 @@ namespace Microsoft::Console::Render::Atlas
alignas(sizeof(f32)) f32 scale = 0;
alignas(sizeof(f32x2)) f32x2 resolution;
alignas(sizeof(f32x4)) f32x4 background;
alignas(sizeof(f32x4)) f32x4 viewport;
#pragma warning(suppress : 4324) // 'CustomConstBuffer': structure was padded due to alignment specifier
};
@@ -230,7 +231,7 @@ namespace Microsoft::Console::Render::Atlas
void _recreateCustomShader(const RenderingPayload& p);
void _recreateCustomRenderTargetView(const RenderingPayload& p);
void _recreateBackgroundColorBitmap(const RenderingPayload& p);
void _recreateConstBuffer(const RenderingPayload& p) const;
void _recreateConstBuffer(const RenderingPayload& p);
void _setupDeviceContextState(const RenderingPayload& p);
void _debugUpdateShaders(const RenderingPayload& p) noexcept;
void _debugShowDirty(const RenderingPayload& p);
@@ -291,6 +292,7 @@ namespace Microsoft::Console::Render::Atlas
wil::com_ptr<ID3D11Texture2D> _backgroundBitmap;
wil::com_ptr<ID3D11ShaderResourceView> _backgroundBitmapView;
wil::com_ptr<ID3D11SamplerState> _backgroundSampler;
til::generation_t _backgroundBitmapGeneration;
wil::com_ptr<ID3D11Texture2D> _glyphAtlas;

View File

@@ -399,6 +399,7 @@ namespace Microsoft::Console::Render::Atlas
std::wstring customPixelShaderPath;
std::wstring customPixelShaderImagePath;
bool useRetroTerminalEffect = false;
f32x4 padding{ 0.f, 0.f, 0.f, 0.f };
};
struct Settings

View File

@@ -6,9 +6,8 @@
cbuffer ConstBuffer : register(b0)
{
float4 backgroundColor;
float2 backgroundCellSize;
float2 backgroundCellCount;
float2 backgroundScale;
float2 backgroundOffset;
float4 gammaRatios;
float enhancedContrast;
float underlineWidth;
@@ -17,6 +16,7 @@ cbuffer ConstBuffer : register(b0)
float shadedGlyphDotSize;
}
SamplerState backgroundSampler;
Texture2D<float4> background : register(t0);
Texture2D<float4> glyphAtlas : register(t1);
@@ -37,8 +37,7 @@ Output main(PSData data) : SV_Target
{
case SHADING_TYPE_TEXT_BACKGROUND:
{
float2 cell = data.position.xy / backgroundCellSize;
color = all(cell < backgroundCellCount) ? background[cell] : backgroundColor;
color = background.Sample(backgroundSampler, data.position.xy * backgroundScale + backgroundOffset);
weights = float4(1, 1, 1, 1);
break;
}

View File

@@ -6,6 +6,7 @@
cbuffer ConstBuffer : register(b0)
{
float2 positionScale;
float2 positionOffset;
}
// clang-format off
@@ -18,8 +19,8 @@ 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 = (data.vertex * data.size + data.position) * positionScale + positionOffset;
output.position.zw = float2(0, 1);
output.texcoord = data.texcoord + data.vertex.xy * data.size;
output.texcoord = data.vertex * data.size + data.texcoord;
return output;
}

View File

@@ -97,3 +97,7 @@ void RenderEngineBase::WaitUntilCanRender() noexcept
void RenderEngineBase::UpdateHyperlinkHoveredId(const uint16_t /*hoveredId*/) noexcept
{
}
void RenderEngineBase::SetPadding(float, float, float, float) noexcept
{
}

View File

@@ -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 left, float top, float right, float bottom) noexcept = 0;
};
}
#pragma warning(pop)

View File

@@ -51,6 +51,7 @@ namespace Microsoft::Console::Render
void WaitUntilCanRender() noexcept override;
void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept override;
void SetPadding(float left, float top, float right, float bottom) noexcept override;
protected:
[[nodiscard]] virtual HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept = 0;