Another underline fix, but this time use the bitmap; consider moving underline production into PaintBufferLine itself

This commit is contained in:
Dustin L. Howett 2025-12-20 16:17:40 -06:00
parent a79078924a
commit c2b5cd275b
4 changed files with 56 additions and 35 deletions

View File

@ -203,7 +203,7 @@ try
auto dst = _p.colorBitmap.data() + dstOffset;
const auto bytes = count * sizeof(u32);
for (size_t i = 0; i < 2; ++i)
for (size_t i = 0; i < 3; ++i)
{
// Avoid bumping the colorBitmapGeneration unless necessary. This approx. further halves
// the (already small) GPU load. This could easily be replaced with some custom SIMD
@ -353,7 +353,7 @@ CATCH_RETURN()
return S_OK;
}
void AtlasEngine::_fillColorBitmap(const size_t y, const size_t x1, const size_t x2, const u32 fgColor, const u32 bgColor) noexcept
void AtlasEngine::_fillColorBitmap(const size_t y, const size_t x1, const size_t x2, const u32 fgColor, const u32 bgColor, const u32 ulColor) noexcept
{
const auto bitmap = _p.colorBitmap.begin() + _p.colorBitmapRowStride * y;
const auto shift = gsl::narrow_cast<u8>(_p.rows[y]->lineRendition != LineRendition::SingleWidth);
@ -363,10 +363,11 @@ void AtlasEngine::_fillColorBitmap(const size_t y, const size_t x1, const size_t
const u32 colors[] = {
u32ColorPremultiply(bgColor),
fgColor,
ulColor,
};
// This fills the color in the background bitmap, and then in the foreground bitmap.
for (size_t i = 0; i < 2; ++i)
for (size_t i = 0; i < 3; ++i)
{
const auto color = colors[i];
@ -428,7 +429,7 @@ try
{
const auto isFinalRow = y == hiEnd.y;
const auto end = isFinalRow ? std::min(hiEnd.x, x2) : x2;
_fillColorBitmap(row, x1, end, fgColor, bgColor);
_fillColorBitmap(row, x1, end, fgColor, bgColor, fgColor);
// Return early if we couldn't paint the whole region (either this was not the last row, or
// it was the last row but the highlight ends outside of our x range.)
@ -451,7 +452,7 @@ try
const auto isEndInside = y == hiEnd.y && hiEnd.x <= x2;
if (isStartInside && isEndInside)
{
_fillColorBitmap(row, hiStart.x, static_cast<size_t>(hiEnd.x), fgColor, bgColor);
_fillColorBitmap(row, hiStart.x, static_cast<size_t>(hiEnd.x), fgColor, bgColor, fgColor);
++it;
}
else
@ -460,7 +461,7 @@ try
if (isStartInside)
{
const auto start = std::max(x1, hiStart.x);
_fillColorBitmap(y, start, x2, fgColor, bgColor);
_fillColorBitmap(y, start, x2, fgColor, bgColor, fgColor);
}
break;
@ -517,7 +518,7 @@ try
}
// Apply the current foreground and background colors to the cells
_fillColorBitmap(y, x, columnEnd, _api.currentForeground, _api.currentBackground);
_fillColorBitmap(y, x, columnEnd, _api.currentForeground, _api.currentBackground, 0xfffa7720u);
// Apply the highlighting colors to the highlighted cells
RETURN_IF_FAILED(_drawHighlighted(_api.searchHighlights, y, x, columnEnd, highlightFg, highlightBg));
@ -532,13 +533,15 @@ CATCH_RETURN()
[[nodiscard]] HRESULT AtlasEngine::PaintBufferGridLines(const GridLineSet lines, const COLORREF gridlineColor, const COLORREF underlineColor, const size_t cchLine, const til::point coordTarget) noexcept
try
{
UNREFERENCED_PARAMETER(gridlineColor);
UNREFERENCED_PARAMETER(underlineColor);
const auto shift = gsl::narrow_cast<u8>(_api.lineRendition != LineRendition::SingleWidth);
const auto x = std::max(0, coordTarget.x - (_api.viewportOffset.x >> shift));
const auto y = gsl::narrow_cast<u16>(clamp<til::CoordType>(coordTarget.y, 0, _p.s->viewportCellCount.y - 1));
const auto from = gsl::narrow_cast<u16>(clamp<til::CoordType>(x << shift, 0, _p.s->viewportCellCount.x - 1));
const auto to = gsl::narrow_cast<u16>(clamp<size_t>((x + cchLine) << shift, from, _p.s->viewportCellCount.x));
const auto glColor = gsl::narrow_cast<u32>(gridlineColor) | 0xff000000;
const auto ulColor = gsl::narrow_cast<u32>(underlineColor) | 0xff000000;
const auto glColor = 0xffff0000U; //gsl::narrow_cast<u32>(gridlineColor) | 0xff000000;
const auto ulColor = 0xff00ff00U; //gsl::narrow_cast<u32>(underlineColor) | 0xff000000;
_p.rows[y]->gridLineRanges.emplace_back(lines, glColor, ulColor, from, to);
return S_OK;
}
@ -791,9 +794,10 @@ void AtlasEngine::_recreateCellCountDependentResources()
// so we round up to multiple of 8 because 8 * sizeof(u32) == 32.
_p.colorBitmapRowStride = alignForward<size_t>(_p.s->viewportCellCount.x, 8);
_p.colorBitmapDepthStride = _p.colorBitmapRowStride * _p.s->viewportCellCount.y;
_p.colorBitmap = Buffer<u32, 32>(_p.colorBitmapDepthStride * 2);
_p.colorBitmap = Buffer<u32, 32>(_p.colorBitmapDepthStride * 3);
_p.backgroundBitmap = { _p.colorBitmap.data(), _p.colorBitmapDepthStride };
_p.foregroundBitmap = { _p.colorBitmap.data() + _p.colorBitmapDepthStride, _p.colorBitmapDepthStride };
_p.underlineBitmap = { _p.colorBitmap.data() + (_p.colorBitmapDepthStride << 1), _p.colorBitmapDepthStride };
memset(_p.colorBitmap.data(), 0, _p.colorBitmap.size() * sizeof(u32));

View File

@ -89,7 +89,7 @@ namespace Microsoft::Console::Render::Atlas
void _mapCharacters(const wchar_t* text, u32 textLength, u32* mappedLength, IDWriteFontFace2** mappedFontFace) const;
void _mapComplex(IDWriteFontFace2* mappedFontFace, u32 idx, u32 length, ShapedRow& row);
ATLAS_ATTR_COLD void _mapReplacementCharacter(u32 from, u32 to, ShapedRow& row);
void _fillColorBitmap(const size_t y, const size_t x1, const size_t x2, const u32 fgColor, const u32 bgColor) noexcept;
void _fillColorBitmap(const size_t y, const size_t x1, const size_t x2, const u32 fgColor, const u32 bgColor, const u32 ulColor) noexcept;
[[nodiscard]] HRESULT _drawHighlighted(std::span<const til::point_span>& highlights, const u16 row, const u16 begX, const u16 endX, const u32 fgColor, const u32 bgColor) noexcept;
// AtlasEngine.api.cpp

View File

@ -678,12 +678,12 @@ void BackendD3D::_debugUpdateShaders(const RenderingPayload& p) noexcept
struct FileVS
{
std::wstring_view filename;
wil::com_ptr<ID3D11VertexShader> BackendD3D::*target;
wil::com_ptr<ID3D11VertexShader> BackendD3D::* target;
};
struct FilePS
{
std::wstring_view filename;
wil::com_ptr<ID3D11PixelShader> BackendD3D::*target;
wil::com_ptr<ID3D11PixelShader> BackendD3D::* target;
};
static constexpr std::array filesVS{
@ -1784,37 +1784,51 @@ void BackendD3D::_drawGridlines(const RenderingPayload& p, u16 y)
auto posX = r.from * cellSize.x + offset;
const auto end = r.to * cellSize.x;
const auto colors = &p.foregroundBitmap[p.colorBitmapRowStride * y];
for (; posX < end; posX += textCellWidth)
{
_appendQuad() = {
.shadingType = static_cast<u16>(ShadingType::SolidLine),
.position = { static_cast<i16>(posX), rowTop },
.size = { width, p.s->font->cellSize.y },
.color = r.gridlineColor,
.color = colors[r.from],
};
}
};
const auto appendHorizontalLine = [&](const GridLineRange& r, FontDecorationPosition pos, ShadingType shadingType, const u32 color) {
const auto appendHorizontalLine = [&](const GridLineRange& r, FontDecorationPosition pos, ShadingType shadingType, const std::span<const u32>& colorBitmap) {
const auto offset = pos.position << verticalShift;
const auto height = static_cast<u16>(pos.height << verticalShift);
const auto left = static_cast<i16>(r.from * cellSize.x);
const auto width = static_cast<u16>((r.to - r.from) * cellSize.x);
i32 rt = textCellTop + offset;
i32 rb = rt + height;
rt = clamp(rt, clipTop, clipBottom);
rb = clamp(rb, clipTop, clipBottom);
const auto colors = &colorBitmap[p.colorBitmapRowStride * y];
if (rt < rb)
{
_appendQuad() = {
.shadingType = static_cast<u16>(shadingType),
.renditionScale = { static_cast<u8>(1 << horizontalShift), static_cast<u8>(1 << verticalShift) },
.position = { left, static_cast<i16>(rt) },
.size = { width, static_cast<u16>(rb - rt) },
.color = color,
};
for (auto from = r.from; from < r.to;)
{
const auto start = colors[from];
u16 w = 1u;
for (; colors[from + w] == start && w < (r.to - r.from); ++w)
;
const auto left = static_cast<i16>(from * cellSize.x);
const auto width = static_cast<u16>(w * cellSize.x);
_appendQuad() = {
.shadingType = static_cast<u16>(shadingType),
.renditionScale = { static_cast<u8>(1 << horizontalShift), static_cast<u8>(1 << verticalShift) },
.position = { left, static_cast<i16>(rt) },
.size = { width, static_cast<u16>(rb - rt) },
.color = start,
};
from += w;
}
}
};
@ -1833,38 +1847,38 @@ void BackendD3D::_drawGridlines(const RenderingPayload& p, u16 y)
}
if (r.lines.test(GridLines::Top))
{
appendHorizontalLine(r, p.s->font->gridTop, ShadingType::SolidLine, r.gridlineColor);
appendHorizontalLine(r, p.s->font->gridTop, ShadingType::SolidLine, p.foregroundBitmap);
}
if (r.lines.test(GridLines::Bottom))
{
appendHorizontalLine(r, p.s->font->gridBottom, ShadingType::SolidLine, r.gridlineColor);
appendHorizontalLine(r, p.s->font->gridBottom, ShadingType::SolidLine, p.foregroundBitmap);
}
if (r.lines.test(GridLines::Strikethrough))
{
appendHorizontalLine(r, p.s->font->strikethrough, ShadingType::SolidLine, r.gridlineColor);
appendHorizontalLine(r, p.s->font->strikethrough, ShadingType::SolidLine, p.foregroundBitmap);
}
if (r.lines.test(GridLines::Underline))
{
appendHorizontalLine(r, p.s->font->underline, ShadingType::SolidLine, r.underlineColor);
appendHorizontalLine(r, p.s->font->underline, ShadingType::SolidLine, p.underlineBitmap);
}
else if (r.lines.any(GridLines::DottedUnderline, GridLines::HyperlinkUnderline))
{
appendHorizontalLine(r, p.s->font->underline, ShadingType::DottedLine, r.underlineColor);
appendHorizontalLine(r, p.s->font->underline, ShadingType::DottedLine, p.underlineBitmap);
}
else if (r.lines.test(GridLines::DashedUnderline))
{
appendHorizontalLine(r, p.s->font->underline, ShadingType::DashedLine, r.underlineColor);
appendHorizontalLine(r, p.s->font->underline, ShadingType::DashedLine, p.underlineBitmap);
}
else if (r.lines.test(GridLines::CurlyUnderline))
{
appendHorizontalLine(r, _curlyUnderline, ShadingType::CurlyLine, r.underlineColor);
appendHorizontalLine(r, _curlyUnderline, ShadingType::CurlyLine, p.underlineBitmap);
}
else if (r.lines.test(GridLines::DoubleUnderline))
{
for (const auto pos : p.s->font->doubleUnderline)
{
appendHorizontalLine(r, pos, ShadingType::SolidLine, r.underlineColor);
appendHorizontalLine(r, pos, ShadingType::SolidLine, p.underlineBitmap);
}
}
}

View File

@ -562,14 +562,17 @@ namespace Microsoft::Console::Render::Atlas
// This exists as a convenience access to colorBitmap and
// contains a view into the foreground color bitmap.
std::span<u32> foregroundBitmap;
// This exists as a convenience access to colorBitmap and
// contains a view into the underline color bitmap.
std::span<u32> underlineBitmap;
// This stride of the colorBitmap is a "count" of u32 and not in bytes.
size_t colorBitmapRowStride = 0;
// FYI depth refers to the `colorBitmapRowStride * height` size of each bitmap contained
// in colorBitmap. colorBitmap contains 2 bitmaps (background and foreground colors).
// in colorBitmap. colorBitmap contains 3 bitmaps (background, foreground and underline colors).
size_t colorBitmapDepthStride = 0;
// A generation of 1 ensures that the backends redraw the background on the first Present().
// The 1st entry in this array corresponds to the background and the 2nd to the foreground bitmap.
std::array<til::generation_t, 2> colorBitmapGenerations{ 1, 1 };
std::array<til::generation_t, 3> colorBitmapGenerations{ 1, 1, 1 };
// In columns/rows.
til::rect cursorRect;
// The viewport/SwapChain area to be presented. In pixel.