servo: Merge #7527 - Use SIMD in fast path for advance_for_char_range (from bjwbell:simd_advance_for_char_range); r=metajack

In advance_for_char_range add a fast SIMD code path for the the common
case where there are no detailed glyphs.


r? @mbrubeck

Source-Repo: https://github.com/servo/servo
Source-Revision: c83825938346f794790bcd1343b7375e9e34f443
This commit is contained in:
Bryan Bell 2015-09-09 16:55:16 -06:00
parent a7948af624
commit 6a96bf0eb9
4 changed files with 94 additions and 1 deletions

View File

@ -103,3 +103,18 @@ git = "https://github.com/servo/rust-freetype"
[target.x86_64-apple-darwin.dependencies.core-text]
git = "https://github.com/servo/core-text-rs"
[target.x86_64-unknown-linux-gnu.dependencies.simd]
git = "https://github.com/huonw/simd"
[target.x86_64-apple-darwin.dependencies.simd]
git = "https://github.com/huonw/simd"
[target.aarch64-unknown-linux-gnu.dependencies.simd]
git = "https://github.com/huonw/simd"
[target.x86_64-pc-windows-gnu.dependencies.simd]
git = "https://github.com/huonw/simd"
[target.x86_64-pc-windows-msvc.dependencies.simd]
git = "https://github.com/huonw/simd"

View File

@ -5,6 +5,10 @@
#![feature(arc_weak)]
#![feature(box_raw)]
#![feature(box_syntax)]
// For simd (currently x86_64/aarch64)
#![cfg_attr(any(target_arch = "x86_64", target_arch = "aarch64"), feature(convert))]
#![feature(custom_attribute)]
#![feature(custom_derive)]
#![feature(hashmap_hasher)]
@ -40,6 +44,10 @@ extern crate net_traits;
extern crate util;
extern crate msg;
extern crate rand;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
extern crate simd;
extern crate smallvec;
extern crate string_cache;
extern crate style;

View File

@ -3,6 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use euclid::point::Point2D;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use simd::u32x4;
use std::cmp::{Ordering, PartialOrd};
use std::mem;
use std::u16;
@ -406,12 +410,16 @@ pub struct GlyphStore {
// TODO(pcwalton): Allocation of this buffer is expensive. Consider a small-vector
// optimization.
/// A buffer of glyphs within the text run, in the order in which they
/// appear in the input text
/// appear in the input text.
/// Any changes will also need to be reflected in
/// transmute_entry_buffer_to_u32_buffer().
entry_buffer: Vec<GlyphEntry>,
/// A store of the detailed glyph data. Detailed glyphs contained in the
/// `entry_buffer` point to locations in this data structure.
detail_store: DetailedGlyphStore,
/// Used to check if fast path should be used in glyph iteration.
has_detailed_glyphs: bool,
is_whitespace: bool,
is_rtl: bool,
}
@ -434,6 +442,7 @@ impl<'a> GlyphStore {
GlyphStore {
entry_buffer: vec![GlyphEntry::initial(); length],
detail_store: DetailedGlyphStore::new(),
has_detailed_glyphs: false,
is_whitespace: is_whitespace,
is_rtl: is_rtl,
}
@ -472,6 +481,7 @@ impl<'a> GlyphStore {
(false, true) => GlyphEntry::simple(data.id, data.advance),
(false, false) => {
let glyph = &[DetailedGlyph::new(data.id, data.advance, data.offset)];
self.has_detailed_glyphs = true;
self.detail_store.add_detailed_glyphs_for_entry(i, glyph);
GlyphEntry::complex(data.cluster_start, data.ligature_start, 1)
}
@ -500,6 +510,7 @@ impl<'a> GlyphStore {
data_for_glyphs[i].offset)
}).collect();
self.has_detailed_glyphs = true;
self.detail_store.add_detailed_glyphs_for_entry(i, &glyphs_vec);
GlyphEntry::complex(first_glyph_data.cluster_start,
first_glyph_data.ligature_start,
@ -541,10 +552,63 @@ impl<'a> GlyphStore {
#[inline]
pub fn advance_for_char_range(&self, rang: &Range<CharIndex>) -> Au {
if !self.has_detailed_glyphs {
self.advance_for_char_range_simple_glyphs(rang)
} else {
self.advance_for_char_range_slow_path(rang)
}
}
#[inline]
pub fn advance_for_char_range_slow_path(&self, rang: &Range<CharIndex>) -> Au {
self.iter_glyphs_for_char_range(rang)
.fold(Au(0), |advance, (_, glyph)| advance + glyph.advance())
}
#[inline]
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
fn advance_for_char_range_simple_glyphs(&self, rang: &Range<CharIndex>) -> Au {
let mask = u32x4::splat(GLYPH_ADVANCE_MASK);
let mut simd_advance = u32x4::splat(0);
let begin = rang.begin().to_usize();
let len = rang.length().to_usize();
let num_simd_iterations = len / 4;
let leftover_entries = rang.end().to_usize() - (len - num_simd_iterations * 4);
let buf = self.transmute_entry_buffer_to_u32_buffer();
for i in 0..num_simd_iterations {
let mut v = u32x4::load(buf, begin + i * 4);
v = v & mask;
v = v >> GLYPH_ADVANCE_SHIFT;
simd_advance = simd_advance + v;
}
let advance =
(simd_advance.extract(0) +
simd_advance.extract(1) +
simd_advance.extract(2) +
simd_advance.extract(3)) as i32;
let mut leftover = Au(0);
for i in leftover_entries..rang.end().to_usize() {
leftover = leftover + self.entry_buffer[i].advance();
}
Au(advance) + leftover
}
/// When SIMD isn't available (non-x86_x64/aarch64), fallback to the slow path.
#[inline]
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
fn advance_for_char_range_simple_glyphs(&self, rang: &Range<CharIndex>) -> Au {
self.advance_for_char_range_slow_path(rang)
}
/// Used for SIMD.
#[inline]
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
fn transmute_entry_buffer_to_u32_buffer(&self) -> &[u32] {
unsafe { mem::transmute(self.entry_buffer.as_slice()) }
}
pub fn char_is_space(&self, i: CharIndex) -> bool {
assert!(i < self.char_len());
self.entry_buffer[i.to_usize()].char_is_space()

View File

@ -605,6 +605,7 @@ dependencies = [
"script_traits 0.0.1",
"serde 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_macros 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"simd 0.1.0 (git+https://github.com/huonw/simd)",
"skia 0.0.20130412 (git+https://github.com/servo/skia)",
"smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1534,6 +1535,11 @@ dependencies = [
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "simd"
version = "0.1.0"
source = "git+https://github.com/huonw/simd#d9ad79d86eab50a8f36d45fe17aa9e3a533389ee"
[[package]]
name = "skia"
version = "0.0.20130412"