The new sparse invariant is:

- Empty vector: every quad is Mask; use the existing single draw call.
  - Non-empty vector: the text contains subpixel glyphs; entries correspond to every quad.

  addGlyphQuad() therefore delays allocation until the first subpixel glyph. At that point it backfills earlier quads as Mask, records the current subpixel glyph, and tracks every subsequent quad.

  addLine() only appends Mask after tracking has started. A line before the first subpixel glyph will be included by the later backfill; a line after it must be appended to preserve the one-entry-per-quad mapping.

  This protects the common grayscale path from subpixel-related overhead while correctly handling mixed mask/subpixel text. It introduces no allocations until subpixel rendering is actually encountered.

  The critical fix versus the earlier broken version is that the first subpixel glyph is appended unconditionally. The old code accidentally skipped it when it was the first quad, causing the first character to be
  classified as Mask.
This commit is contained in:
Martín Lucas Golini
2026-07-25 20:41:35 -03:00
parent b71ef9522d
commit 5aeb0b1acf

View File

@@ -1732,8 +1732,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
return;
unsigned int numvert = mVertices.size();
const bool containsSubpixel = std::find( mRenderModes.begin(), mRenderModes.end(),
GlyphRenderMode::Subpixel ) != mRenderModes.end();
const bool containsSubpixel = !mRenderModes.empty();
const Float drawX = containsSubpixel && rotation == 0.f && scale == 1.f ? std::trunc( X ) : X;
const Float drawY = containsSubpixel && rotation == 0.f && scale == 1.f ? std::trunc( Y ) : Y;
@@ -2682,8 +2681,9 @@ void Text::setFillColor( const std::vector<Color>& colors ) {
// Add an underline or strikethrough line to the vertex array
void Text::addLine( std::vector<VertexCoords>& vertices, Float lineLength, Float lineTop,
Float offset, Float thickness, Float outlineThickness, Int32 centerDiffX ) {
( &vertices == &mOutlineVertices ? mOutlineRenderModes : mRenderModes )
.push_back( GlyphRenderMode::Mask );
auto& renderModes = &vertices == &mOutlineVertices ? mOutlineRenderModes : mRenderModes;
if ( !renderModes.empty() )
renderModes.push_back( GlyphRenderMode::Mask );
Float top = std::floor( lineTop + offset - ( thickness / 2 ) + 0.5f );
Float bottom = top + std::floor( thickness + 0.5f );
Float u1 = 0;
@@ -2759,8 +2759,14 @@ void Text::addLine( std::vector<VertexCoords>& vertices, Float lineLength, Float
void Text::addGlyphQuad( std::vector<VertexCoords>& vertices, Vector2f position,
const EE::Graphics::Glyph& glyph, Float italic, Float outlineThickness,
Int32 centerDiffX ) {
( &vertices == &mOutlineVertices ? mOutlineRenderModes : mRenderModes )
.push_back( glyph.renderMode );
auto& renderModes = &vertices == &mOutlineVertices ? mOutlineRenderModes : mRenderModes;
if ( glyph.renderMode == GlyphRenderMode::Subpixel ) {
if ( renderModes.empty() )
renderModes.resize( vertices.size() / GLi->quadVertex(), GlyphRenderMode::Mask );
renderModes.push_back( GlyphRenderMode::Subpixel );
} else if ( !renderModes.empty() ) {
renderModes.push_back( GlyphRenderMode::Mask );
}
if ( glyph.renderMode == GlyphRenderMode::Subpixel )
position = position.trunc();
Float padding = 1.0;