Skip to content

Commit bab4731

Browse files
committed
Add basic subpixel AA text support on Linux.
This is some preliminary support for subpixel AA. Specifically: * Only on Linux for now. * No gamma correction. * Disabled by default (use -Z subpixel-aa to test). * Doesn't deal with rotations, subpixel positioning etc.
1 parent 8cc8574 commit bab4731

File tree

12 files changed

+176
-64
lines changed

12 files changed

+176
-64
lines changed

replay/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ fn main() {
9999
precache_shaders: false,
100100
renderer_kind: webrender_traits::RendererKind::Native,
101101
debug: false,
102+
enable_subpixel_aa: false,
102103
};
103104

104105
let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);

sample/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ fn main() {
140140
debug: true,
141141
precache_shaders: false,
142142
renderer_kind: RendererKind::Native,
143+
enable_subpixel_aa: false,
143144
};
144145

145146
let (mut renderer, sender) = webrender::renderer::Renderer::new(opts);

webrender/res/ps_text_run.fs.glsl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
void main(void) {
6+
#ifdef WR_FEATURE_SUBPIXEL_AA
7+
oFragColor = texture(sDiffuse, vUv);
8+
#else
69
float a = texture(sDiffuse, vUv).a;
710
#ifdef WR_FEATURE_TRANSFORM
811
float alpha = 0.0;
912
init_transform_fs(vLocalPos, vLocalRect, alpha);
1013
a *= alpha;
1114
#endif
1215
oFragColor = vec4(vColor.rgb, vColor.a * a);
16+
#endif
1317
}

webrender/src/device.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::path::PathBuf;
1717
use std::mem;
1818
//use std::sync::mpsc::{channel, Sender};
1919
//use std::thread;
20-
use webrender_traits::ImageFormat;
20+
use webrender_traits::{ColorF, ImageFormat};
2121

2222
#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
2323
const GL_FORMAT_A: gl::GLuint = gl::RED;
@@ -1813,6 +1813,11 @@ impl Device {
18131813
gl::ONE, gl::ONE);
18141814
gl::blend_equation(gl::FUNC_ADD);
18151815
}
1816+
1817+
pub fn set_blend_mode_subpixel(&self, color: ColorF) {
1818+
gl::blend_color(color.r, color.g, color.b, color.a);
1819+
gl::blend_func(gl::CONSTANT_COLOR, gl::ONE_MINUS_SRC_COLOR);
1820+
}
18161821
}
18171822

18181823
impl Drop for Device {

webrender/src/internal_types.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@ use webrender_traits::{Epoch, ColorF, PipelineId};
2424
use webrender_traits::{ImageFormat, MixBlendMode, NativeFontHandle, DisplayItem};
2525
use webrender_traits::{ScrollLayerId, WebGLCommand};
2626

27-
#[allow(dead_code)] // TODO(gw): Make use of the subpixel render mode!
28-
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
29-
pub enum FontRenderMode {
30-
Mono,
31-
Alpha,
32-
Subpixel,
33-
}
34-
3527
pub enum GLContextHandleWrapper {
3628
Native(NativeGLContextHandle),
3729
OSMesa(OSMesaContextHandle),

webrender/src/platform/macos/font.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ use core_graphics::geometry::CGPoint;
1212
use core_text::font::CTFont;
1313
use core_text::font_descriptor::kCTFontDefaultOrientation;
1414
use core_text;
15-
use internal_types::FontRenderMode;
1615
use std::collections::HashMap;
1716
use std::collections::hash_map::Entry;
18-
use webrender_traits::{FontKey, GlyphDimensions};
17+
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};
1918

2019
pub type NativeFontHandle = CGFont;
2120

webrender/src/platform/unix/font.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
use app_units::Au;
6-
use internal_types::FontRenderMode;
7-
use webrender_traits::{FontKey, GlyphDimensions, NativeFontHandle};
6+
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions, NativeFontHandle};
87

98
use freetype::freetype::{FTErrorMethods, FT_PIXEL_MODE_GRAY, FT_PIXEL_MODE_MONO, FT_PIXEL_MODE_LCD};
109
use freetype::freetype::{FT_Done_FreeType, FT_RENDER_MODE_LCD, FT_Library_SetLcdFilter};
@@ -49,7 +48,10 @@ impl FontContext {
4948
if !result.succeeded() { panic!("Unable to initialize FreeType library {}", result); }
5049

5150
// TODO(gw): Check result of this to determine if freetype build supports subpixel.
52-
FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
51+
let result = FT_Library_SetLcdFilter(lib, FT_LcdFilter::FT_LCD_FILTER_DEFAULT);
52+
if !result.succeeded() {
53+
println!("WARN: Initializing a FreeType library build without subpixel AA enabled!");
54+
}
5355
}
5456

5557
FontContext {
@@ -156,7 +158,7 @@ impl FontContext {
156158
let bitmap_mode = bitmap.pixel_mode as u32;
157159

158160
let metrics = &(*slot).metrics;
159-
let glyph_width = (metrics.width >> 6) as i32;
161+
let mut glyph_width = (metrics.width >> 6) as i32;
160162
let glyph_height = (metrics.height >> 6) as i32;
161163
let mut final_buffer = Vec::with_capacity(glyph_width as usize *
162164
glyph_height as usize *
@@ -215,6 +217,9 @@ impl FontContext {
215217
}
216218
}
217219
FT_PIXEL_MODE_LCD => {
220+
// Extra subpixel on each side of the glyph.
221+
glyph_width += 2;
222+
218223
for y in 0..bitmap.rows {
219224
for x in 0..(bitmap.width / 3) {
220225
let index = (y * bitmap.pitch) + (x * 3);

webrender/src/prim_store.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use std::mem;
1313
use std::usize;
1414
use texture_cache::TextureCacheItem;
1515
use util::TransformedRect;
16-
use webrender_traits::{AuxiliaryLists, ColorF, ImageKey, ImageRendering, WebGLContextId};
16+
use webrender_traits::{AuxiliaryLists, ColorF, ImageKey, ImageRendering};
17+
use webrender_traits::{FontRenderMode, WebGLContextId};
1718
use webrender_traits::{ClipRegion, FontKey, ItemRange, ComplexClipRegion, GlyphKey};
1819

1920
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
@@ -186,6 +187,8 @@ pub struct TextRunPrimitiveCpu {
186187
// TODO(gw): Maybe make this an Arc for sharing with resource cache
187188
pub glyph_indices: Vec<u32>,
188189
pub color_texture_id: TextureId,
190+
pub color: ColorF,
191+
pub render_mode: FontRenderMode,
189192
}
190193

191194
#[derive(Debug, Clone)]
@@ -583,7 +586,8 @@ impl PrimitiveStore {
583586
let texture_id = resource_cache.get_glyphs(text.font_key,
584587
text.font_size,
585588
text.blur_radius,
586-
&text.glyph_indices, |index, uv0, uv1| {
589+
&text.glyph_indices,
590+
text.render_mode, |index, uv0, uv1| {
587591
let dest_glyph = &mut dest_glyphs[index];
588592
let dest: &mut GlyphPrimitive = unsafe {
589593
mem::transmute(dest_glyph)
@@ -785,7 +789,8 @@ impl PrimitiveStore {
785789
resource_cache.request_glyphs(text.font_key,
786790
text.font_size,
787791
text.blur_radius,
788-
&text.glyph_indices);
792+
&text.glyph_indices,
793+
text.render_mode);
789794
}
790795
PrimitiveKind::Image => {
791796
let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0];

webrender/src/renderer.rs

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ const GPU_TAG_PRIM_BORDER: GpuProfileTag = GpuProfileTag { label: "Border", colo
9292
pub enum BlendMode {
9393
None,
9494
Alpha,
95+
// Use the color of the text itself as a constant color blend factor.
96+
Subpixel(ColorF),
9597
}
9698

9799
struct VertexDataTexture {
@@ -140,7 +142,8 @@ impl VertexDataTexture {
140142
}
141143
}
142144

143-
const TRANSFORM_FEATURE: &'static [&'static str] = &["TRANSFORM"];
145+
const TRANSFORM_FEATURE: &'static str = "TRANSFORM";
146+
const SUBPIXEL_AA_FEATURE: &'static str = "SUBPIXEL_AA";
144147

145148
enum ShaderKind {
146149
Primitive,
@@ -153,22 +156,22 @@ struct LazilyCompiledShader {
153156
name: &'static str,
154157
kind: ShaderKind,
155158
max_ubo_vectors: usize,
156-
features: &'static [&'static str],
159+
features: Vec<&'static str>,
157160
}
158161

159162
impl LazilyCompiledShader {
160163
fn new(kind: ShaderKind,
161164
name: &'static str,
162165
max_ubo_vectors: usize,
163-
features: &'static [&'static str],
166+
features: &[&'static str],
164167
device: &mut Device,
165168
precache: bool) -> LazilyCompiledShader {
166169
let mut shader = LazilyCompiledShader {
167170
id: None,
168171
name: name,
169172
kind: kind,
170173
max_ubo_vectors: max_ubo_vectors,
171-
features: features,
174+
features: features.to_vec(),
172175
};
173176

174177
if precache {
@@ -190,7 +193,7 @@ impl LazilyCompiledShader {
190193
create_prim_shader(self.name,
191194
device,
192195
self.max_ubo_vectors,
193-
self.features)
196+
&self.features)
194197
}
195198
};
196199
self.id = Some(id);
@@ -235,18 +238,22 @@ impl PrimitiveShader {
235238
max_ubo_vectors: usize,
236239
max_prim_items: usize,
237240
device: &mut Device,
241+
features: &[&'static str],
238242
precache: bool) -> PrimitiveShader {
239243
let simple = LazilyCompiledShader::new(ShaderKind::Primitive,
240244
name,
241245
max_ubo_vectors,
242-
&[],
246+
features,
243247
device,
244248
precache);
245249

250+
let mut transform_features = features.to_vec();
251+
transform_features.push(TRANSFORM_FEATURE);
252+
246253
let transform = LazilyCompiledShader::new(ShaderKind::Primitive,
247254
name,
248255
max_ubo_vectors,
249-
TRANSFORM_FEATURE,
256+
&transform_features,
250257
device,
251258
precache);
252259

@@ -335,6 +342,7 @@ pub struct Renderer {
335342

336343
ps_rectangle: PrimitiveShader,
337344
ps_text_run: PrimitiveShader,
345+
ps_text_run_subpixel: PrimitiveShader,
338346
ps_image: PrimitiveShader,
339347
ps_border: PrimitiveShader,
340348
ps_gradient: PrimitiveShader,
@@ -443,53 +451,69 @@ impl Renderer {
443451
max_ubo_vectors,
444452
max_prim_instances,
445453
&mut device,
454+
&[],
446455
options.precache_shaders);
447456
let ps_text_run = PrimitiveShader::new("ps_text_run",
448457
max_ubo_vectors,
449458
max_prim_instances,
450459
&mut device,
460+
&[],
451461
options.precache_shaders);
462+
let ps_text_run_subpixel = PrimitiveShader::new("ps_text_run",
463+
max_ubo_vectors,
464+
max_prim_instances,
465+
&mut device,
466+
&[ SUBPIXEL_AA_FEATURE ],
467+
options.precache_shaders);
452468
let ps_image = PrimitiveShader::new("ps_image",
453469
max_ubo_vectors,
454470
max_prim_instances,
455471
&mut device,
472+
&[],
456473
options.precache_shaders);
457474
let ps_border = PrimitiveShader::new("ps_border",
458475
max_ubo_vectors,
459476
max_prim_instances,
460477
&mut device,
478+
&[],
461479
options.precache_shaders);
462480
let ps_rectangle_clip = PrimitiveShader::new("ps_rectangle_clip",
463481
max_ubo_vectors,
464482
max_prim_instances,
465483
&mut device,
484+
&[],
466485
options.precache_shaders);
467486
let ps_image_clip = PrimitiveShader::new("ps_image_clip",
468487
max_ubo_vectors,
469488
max_prim_instances,
470489
&mut device,
490+
&[],
471491
options.precache_shaders);
472492

473493
let ps_box_shadow = PrimitiveShader::new("ps_box_shadow",
474494
max_ubo_vectors,
475495
max_prim_instances,
476496
&mut device,
497+
&[],
477498
options.precache_shaders);
478499

479500
let ps_gradient = PrimitiveShader::new("ps_gradient",
480501
max_ubo_vectors,
481502
max_prim_instances,
482503
&mut device,
504+
&[],
483505
options.precache_shaders);
484506
let ps_gradient_clip = PrimitiveShader::new("ps_gradient_clip",
485507
max_ubo_vectors,
486508
max_prim_instances,
487509
&mut device,
510+
&[],
488511
options.precache_shaders);
489512
let ps_angle_gradient = PrimitiveShader::new("ps_angle_gradient",
490513
max_ubo_vectors,
491514
max_prim_instances,
492515
&mut device,
516+
&[],
493517
options.precache_shaders);
494518

495519
let ps_blend = LazilyCompiledShader::new(ShaderKind::Primitive,
@@ -619,7 +643,8 @@ impl Renderer {
619643
RendererKind::OSMesa => GLContextHandleWrapper::current_osmesa_handle(),
620644
};
621645

622-
let config = FrameBuilderConfig::new(options.enable_scrollbars);
646+
let config = FrameBuilderConfig::new(options.enable_scrollbars,
647+
options.enable_subpixel_aa);
623648

624649
let debug = options.debug;
625650
let (device_pixel_ratio, enable_aa) = (options.device_pixel_ratio, options.enable_aa);
@@ -657,6 +682,7 @@ impl Renderer {
657682
cs_box_shadow: cs_box_shadow,
658683
ps_rectangle: ps_rectangle,
659684
ps_text_run: ps_text_run,
685+
ps_text_run_subpixel: ps_text_run_subpixel,
660686
ps_image: ps_image,
661687
ps_border: ps_border,
662688
ps_rectangle_clip: ps_rectangle_clip,
@@ -1405,9 +1431,13 @@ impl Renderer {
14051431

14061432
if batch.key.blend_mode != prev_blend_mode {
14071433
match batch.key.blend_mode {
1408-
// TODO(gw): More blend modes to come with subpixel aa work.
14091434
BlendMode::None | BlendMode::Alpha => {
14101435
self.device.set_blend(batch.key.blend_mode == BlendMode::Alpha);
1436+
self.device.set_blend_mode_alpha();
1437+
}
1438+
BlendMode::Subpixel(color) => {
1439+
self.device.set_blend(true);
1440+
self.device.set_blend_mode_subpixel(color);
14111441
}
14121442
}
14131443
prev_blend_mode = batch.key.blend_mode;
@@ -1502,7 +1532,10 @@ impl Renderer {
15021532
}
15031533
&PrimitiveBatchData::TextRun(ref ubo_data) => {
15041534
self.gpu_profile.add_marker(GPU_TAG_PRIM_TEXT_RUN);
1505-
let (shader, max_prim_items) = self.ps_text_run.get(&mut self.device, transform_kind);
1535+
let (shader, max_prim_items) = match batch.key.blend_mode {
1536+
BlendMode::Subpixel(..) => self.ps_text_run_subpixel.get(&mut self.device, transform_kind),
1537+
BlendMode::Alpha | BlendMode::None => self.ps_text_run.get(&mut self.device, transform_kind),
1538+
};
15061539
self.draw_ubo_batch(ubo_data,
15071540
shader,
15081541
1,
@@ -1686,4 +1719,5 @@ pub struct RendererOptions {
16861719
pub enable_scrollbars: bool,
16871720
pub precache_shaders: bool,
16881721
pub renderer_kind: RendererKind,
1722+
pub enable_subpixel_aa: bool,
16891723
}

0 commit comments

Comments
 (0)