Skip to content

Instantly share code, notes, and snippets.

@pcwalton
Created July 19, 2016 21:45
Show Gist options
  • Save pcwalton/d7b55143a409d4910983c94a9ae868a0 to your computer and use it in GitHub Desktop.
Save pcwalton/d7b55143a409d4910983c94a9ae868a0 to your computer and use it in GitHub Desktop.
diff --git a/src/device.rs b/src/device.rs
index eb93dd3..3a79800 100644
--- a/src/device.rs
+++ b/src/device.rs
@@ -510,7 +510,10 @@ impl Program {
gl::link_program(self.id);
if gl::get_program_iv(self.id, gl::LINK_STATUS) == (0 as gl::GLint) {
- println!("Failed to link shader program: {}", gl::get_program_info_log(self.id));
+ println!("Failed to link shader program `{:?}`/`{:?}`: {}",
+ self.vs_path,
+ self.fs_path,
+ gl::get_program_info_log(self.id));
gl::detach_shader(self.id, vs_id);
gl::detach_shader(self.id, fs_id);
if panic_on_fail {
@@ -1110,6 +1113,7 @@ impl Device {
texture_id.bind();
self.set_texture_parameters(filter);
+ println!("uploading texture {}/{}", width, height);
self.upload_texture_image(width, height,
internal_format,
gl_format,
diff --git a/src/renderer.rs b/src/renderer.rs
index a63b941..34ac47a 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -96,7 +96,7 @@ fn get_ubo_max_len<T>(max_ubo_size: usize) -> usize {
// seem to go very slow when you have high
// constants for array lengths. Investigate
// whether this clamping actually hurts performance!
- cmp::min(max_items, 512)
+ cmp::min(max_items, 256)
}
fn create_composite_shader(name: &'static str,
@@ -1201,10 +1201,11 @@ impl Renderer {
self.device.bind_layer_texture(i, cache_texture);
}
+ println!("render target is framebuffer? {:?}", render_target.is_some());
let projection = match render_target {
Some(..) => {
// todo(gw): remove me!
- gl::clear_color(1.0, 1.0, 1.0, 0.0);
+ gl::clear_color(0.0, 0.0, 1.0, 0.0);
Matrix4D::ortho(0.0,
target_size.width as f32,
@@ -1215,7 +1216,7 @@ impl Renderer {
}
None => {
// todo(gw): remove me!
- gl::clear_color(1.0, 1.0, 1.0, 1.0);
+ gl::clear_color(0.0, 0.0, 1.0, 1.0);
Matrix4D::ortho(0.0,
target_size.width as f32,
@@ -1259,6 +1260,7 @@ impl Renderer {
self.device.bind_vao(self.quad_vao_id);
for chunk in ubo_data.chunks(self.max_prim_rectangles) {
+ println!("drawing {} rectangle(s)", chunk.len());
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
@@ -1278,6 +1280,7 @@ impl Renderer {
self.device.bind_vao(self.quad_vao_id);
for chunk in ubo_data.chunks(self.max_prim_rectangles_clip) {
+ println!("drawing {} rectangle clip(s)", chunk.len());
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
@@ -1302,6 +1305,7 @@ impl Renderer {
self.device.bind_color_texture(batch.color_texture_id);
for chunk in ubo_data.chunks(self.max_prim_images) {
+ println!("drawing {} image(s)", chunk.len());
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
@@ -1321,6 +1325,7 @@ impl Renderer {
self.device.bind_vao(self.quad_vao_id);
for chunk in ubo_data.chunks(self.max_prim_borders) {
+ println!("drawing {} border(s)", chunk.len());
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
@@ -1340,6 +1345,7 @@ impl Renderer {
self.device.bind_vao(self.quad_vao_id);
for chunk in ubo_data.chunks(self.max_prim_box_shadows) {
+ println!("drawing {} box shadow(s)", chunk.len());
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
@@ -1360,6 +1366,11 @@ impl Renderer {
self.device.bind_color_texture(batch.color_texture_id);
for chunk in ubo_data.chunks(self.max_prim_texts) {
+ println!("drawing {} glyph(s):", chunk.len());
+ for (i, datum) in chunk.iter().enumerate() {
+ println!("{}: {:?}", i, datum);
+ }
+
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
@@ -1379,6 +1390,7 @@ impl Renderer {
self.device.bind_vao(self.quad_vao_id);
for chunk in ubo_data.chunks(self.max_prim_gradients) {
+ println!("drawing {} gradient(s)", chunk.len());
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
@@ -1400,11 +1412,13 @@ impl Renderer {
gl::delete_buffers(&misc_ubos);
}
+ println!("composite batch count: {:?}", target.composite_batches.len());
for (key, tiles) in &target.composite_batches {
let shader = self.composite_shaders[key.shader as usize];
self.device.bind_program(shader, &projection);
for batch in tiles.chunks(self.max_composite_tiles) {
+ println!("drawing {} composite batch(s)", batch.len());
let ubos = gl::gen_buffers(1);
let ubo = ubos[0];
diff --git a/src/resource_cache.rs b/src/resource_cache.rs
index 4187a04..46c3534 100644
--- a/src/resource_cache.rs
+++ b/src/resource_cache.rs
@@ -372,6 +372,7 @@ impl ResourceCache {
#[inline]
pub fn get_glyph(&self, glyph_key: &GlyphKey, frame_id: FrameId) -> Option<&TextureCacheItem> {
+ println!("getting glyph with key: {:?}", glyph_key);
let image_id = self.cached_glyphs.get(glyph_key, frame_id);
image_id.map(|image_id| self.texture_cache.get(image_id))
}
diff --git a/src/tiling.rs b/src/tiling.rs
index cfb3a78..9339f23 100644
--- a/src/tiling.rs
+++ b/src/tiling.rs
@@ -25,6 +25,8 @@ use webrender_traits::{ColorF, FontKey, ImageKey, ImageRendering, ComplexClipReg
use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderRadius};
use webrender_traits::{BoxShadowClipMode, PipelineId, ScrollLayerId};
+const PRIMITIVES_PER_BUFFER: u8 = 16;
+
struct RenderTargetContext<'a> {
layers: &'a Vec<StackingContext>,
resource_cache: &'a ResourceCache,
@@ -97,7 +99,10 @@ impl AlphaBatchRenderTask {
None
}
- fn build(&mut self, ctx: &RenderTargetContext) {
+ fn build(&mut self,
+ ctx: &RenderTargetContext,
+ frame_primitives: &mut FramePackedPrimList,
+ screen_tiles: &ScreenTileMap) {
debug_assert!(self.layer_ubo.len() <= ctx.alpha_batch_max_layers);
debug_assert!(self.tile_ubo.len() <= ctx.alpha_batch_max_tiles);
@@ -110,70 +115,115 @@ impl AlphaBatchRenderTask {
for (screen_tile_layer_index, screen_tile_layer) in self.screen_tile_layers
.iter_mut()
- .enumerate() {
- if let Some(next_prim_index) = screen_tile_layer.prim_indices.pop() {
+ .enumerate() {
+ println!("screen tile layer {:?}: {:?} sample index/indices",
+ screen_tile_layer_index,
+ screen_tile_layer.last_prim_sample_index -
+ screen_tile_layer.first_prim_sample_index);
+ if screen_tile_layer.first_prim_sample_index ==
+ screen_tile_layer.last_prim_sample_index {
+ continue
+ }
+
+ let tile_location = screen_tile_layer.tile_location();
+ let prim_sample_index = screen_tile_layer.last_prim_sample_index - 1;
+ let prim_range_index = screen_tiles.primitive_indices(&tile_location)
+ .skip(prim_sample_index as usize)
+ .next()
+ .expect("Prim sample index out of bounds!");
+ let mut packed_primitive_range = frame_primitives.ranges_mut(
+ prim_range_index.class())[prim_range_index.class_specific_index().0 as usize];
+ while packed_primitive_range.end != packed_primitive_range.start {
+ packed_primitive_range.end.dec();
+ let packed_primitive_index = packed_primitive_range.end;
+ debug_assert!(packed_primitive_range.start <= packed_primitive_range.end);
+ // FIXME(pcwalton): Don't clone?
+ let packed_primitive =
+ frame_primitives.clone_packed_primitive(prim_range_index.class(),
+ packed_primitive_index);
+ // FIXME(pcwalton): Use the real transformed rect kind!
+ let transform_kind = TransformedRectKind::AxisAligned;
+ let mut new_batch = PrimitiveBatch::new(&packed_primitive, transform_kind);
+ new_batch.data.push(packed_primitive);
+
let StackingContextIndex(si) = screen_tile_layer.layer_index;
let layer = &ctx.layers[si];
- let PrimitiveIndex(pi) = next_prim_index;
+ /*let PrimitiveIndex(pi) = next_prim_index;
let prim = &layer.primitives[pi];
let transform_kind = layer.xf_rect.as_ref().unwrap().kind;
let mut new_batch = PrimitiveBatch::new(prim, transform_kind);
let layer_index_in_ubo = self.layer_to_ubo_map[si].unwrap() as u32;
- let tile_index_in_ubo = screen_tile_layer_index as u32;
- let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id)
- .expect("No auxiliary lists?!");
- let ok = prim.pack(&mut new_batch,
- layer_index_in_ubo,
- tile_index_in_ubo,
- auxiliary_lists,
- transform_kind,
- ctx);
+ let tile_index_in_ubo = screen_tile_layer_index as u32;*/
+ let auxiliary_lists = ctx.pipeline_auxiliary_lists
+ .get(&layer.pipeline_id)
+ .expect("No auxiliary lists?!");
+ let ok = new_batch.push_item_if_possible(packed_primitive_index,
+ frame_primitives,
+ auxiliary_lists,
+ transform_kind,
+ ctx);
debug_assert!(ok);
batch = Some(new_batch);
break;
}
+
+ frame_primitives.ranges_mut(prim_range_index.class())[
+ prim_range_index.class_specific_index().0 as usize] = packed_primitive_range
}
- match batch {
- Some(mut batch) => {
- for (screen_tile_layer_index, screen_tile_layer) in self.screen_tile_layers
- .iter_mut()
- .enumerate() {
- loop {
- match screen_tile_layer.prim_indices.pop() {
- Some(next_prim_index) => {
- let StackingContextIndex(si) = screen_tile_layer.layer_index;
- let layer = &ctx.layers[si];
- let PrimitiveIndex(pi) = next_prim_index;
- let next_prim = &layer.primitives[pi];
- let layer_index_in_ubo = self.layer_to_ubo_map[si].unwrap() as u32;
- let tile_index_in_ubo = screen_tile_layer_index as u32;
- let transform_kind = layer.xf_rect.as_ref().unwrap().kind;
- let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id)
- .expect("No auxiliary lists?!");
- if !next_prim.pack(&mut batch,
- layer_index_in_ubo,
- tile_index_in_ubo,
- auxiliary_lists,
- transform_kind,
- ctx) {
- screen_tile_layer.prim_indices.push(next_prim_index);
- break;
- }
- }
- None => {
- break;
- }
- }
+ let mut batch = match batch {
+ Some(batch) => batch,
+ None => break,
+ };
+
+ for (screen_tile_layer_index, screen_tile_layer) in self.screen_tile_layers
+ .iter_mut()
+ .enumerate() {
+ let tile_location = screen_tile_layer.tile_location();
+ let mut prim_sample_index = screen_tile_layer.last_prim_sample_index;
+ while screen_tile_layer.first_prim_sample_index != prim_sample_index {
+ prim_sample_index -= 1;
+ let prim_range_index = screen_tiles.primitive_indices(&tile_location)
+ .skip(prim_sample_index as usize)
+ .next()
+ .expect("Prim sample index out of bounds!");
+ if prim_range_index.class() != batch.class() {
+ break
+ }
+
+ let mut packed_primitive_range = frame_primitives.ranges_mut(
+ prim_range_index.class())[prim_range_index.class_specific_index()
+ .0 as usize];
+ debug_assert!(prim_range_index.class() == batch.class());
+ while packed_primitive_range.end != packed_primitive_range.start {
+ packed_primitive_range.end.dec();
+ let packed_primitive_index = packed_primitive_range.end;
+
+ let StackingContextIndex(si) = screen_tile_layer.layer_index;
+ let layer = &ctx.layers[si];
+ let layer_index_in_ubo = self.layer_to_ubo_map[si].unwrap() as u32;
+ let tile_index_in_ubo = screen_tile_layer_index as u32;
+ let transform_kind = layer.xf_rect.as_ref().unwrap().kind;
+ let auxiliary_lists = ctx.pipeline_auxiliary_lists
+ .get(&layer.pipeline_id)
+ .expect("No auxiliary lists?!");
+ if !batch.push_item_if_possible(packed_primitive_index,
+ frame_primitives,
+ auxiliary_lists,
+ transform_kind,
+ ctx) {
+ break
}
}
- self.batches.push(batch);
- }
- None => {
- break;
+ frame_primitives.ranges_mut(prim_range_index.class())[
+ prim_range_index.class_specific_index()
+ .0 as usize] = packed_primitive_range
}
+ screen_tile_layer.last_prim_sample_index = prim_sample_index
}
+
+ self.batches.push(batch);
}
}
}
@@ -205,7 +255,10 @@ impl RenderTarget {
self.tasks.push(task);
}
- fn build(&mut self, ctx: &RenderTargetContext) {
+ fn build(&mut self,
+ ctx: &RenderTargetContext,
+ frame_primitives: &mut FramePackedPrimList,
+ screen_tiles: &ScreenTileMap) {
// Step through each task, adding to batches as appropriate.
let mut alpha_batch_tasks = Vec::new();
let mut current_alpha_batch_task = AlphaBatchRenderTask::new(ctx);
@@ -259,7 +312,7 @@ impl RenderTarget {
alpha_batch_tasks.push(current_alpha_batch_task);
}
for task in &mut alpha_batch_tasks {
- task.build(ctx);
+ task.build(ctx, frame_primitives, screen_tiles);
}
self.alpha_batch_tasks = alpha_batch_tasks;
}
@@ -297,9 +350,12 @@ impl RenderPhase {
}
}
- fn build(&mut self, ctx: &RenderTargetContext) {
+ fn build(&mut self,
+ ctx: &RenderTargetContext,
+ frame_primitives: &mut FramePackedPrimList,
+ screen_tiles: &ScreenTileMap) {
for target in &mut self.targets {
- target.build(ctx);
+ target.build(ctx, frame_primitives, screen_tiles);
}
}
}
@@ -666,6 +722,151 @@ struct PackedPrimList {
primitives: Vec<PackedPrimitive>,
}
+#[derive(Copy, Clone, Debug)]
+struct PackedPrimitiveRange {
+ start: ClassSpecificPackedPrimitiveIndex,
+ end: ClassSpecificPackedPrimitiveIndex,
+ class: PrimitiveClass,
+}
+
+impl PackedPrimitiveRange {
+ fn new(start: PackedPrimitiveIndex, end: PackedPrimitiveIndex) -> PackedPrimitiveRange {
+ debug_assert!(start.class() == end.class());
+ PackedPrimitiveRange {
+ start: start.class_specific_index(),
+ end: end.class_specific_index(),
+ class: start.class(),
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+struct LayerPackedPrimitiveRangeStartOffsets {
+ rectangles: usize,
+ rectangles_clip: usize,
+ borders: usize,
+ box_shadows: usize,
+ text: usize,
+ images: usize,
+ gradients: usize,
+}
+
+struct FramePackedDataForPrimitive<PrimitiveType> {
+ data: Vec<PrimitiveType>,
+ ranges: Vec<PackedPrimitiveRange>,
+ layer_range_start_offsets: Vec<usize>,
+}
+
+impl<PrimitiveType> FramePackedDataForPrimitive<PrimitiveType> {
+ fn new() -> FramePackedDataForPrimitive<PrimitiveType> {
+ FramePackedDataForPrimitive {
+ data: vec![],
+ ranges: vec![],
+ layer_range_start_offsets: vec![],
+ }
+ }
+
+ fn packed_primitives_ranges_for_layer(&self, layer_index: StackingContextIndex)
+ -> &[PackedPrimitiveRange] {
+ debug_assert!(layer_index.0 < self.layer_range_start_offsets.len());
+ let start = self.layer_range_start_offsets[layer_index.0];
+ let end = if layer_index.0 == self.layer_range_start_offsets.len() - 1 {
+ self.layer_range_start_offsets.len()
+ } else {
+ self.layer_range_start_offsets[layer_index.0 + 1]
+ };
+ &self.ranges[start..end]
+ }
+
+ fn record_new_layer(&mut self) {
+ self.layer_range_start_offsets.push(self.ranges.len());
+ }
+}
+
+struct FramePackedPrimList {
+ color_texture_id: TextureId,
+ rectangles: FramePackedDataForPrimitive<PackedRectanglePrimitive>,
+ rectangles_clip: FramePackedDataForPrimitive<PackedRectanglePrimitiveClip>,
+ glyphs: FramePackedDataForPrimitive<PackedGlyphPrimitive>,
+ images: FramePackedDataForPrimitive<PackedImagePrimitive>,
+ borders: FramePackedDataForPrimitive<PackedBorderPrimitive>,
+ box_shadows: FramePackedDataForPrimitive<PackedBoxShadowPrimitive>,
+ gradients: FramePackedDataForPrimitive<PackedGradientPrimitive>,
+}
+
+impl FramePackedPrimList {
+ fn new() -> FramePackedPrimList {
+ FramePackedPrimList {
+ color_texture_id: TextureId(0),
+ rectangles: FramePackedDataForPrimitive::new(),
+ rectangles_clip: FramePackedDataForPrimitive::new(),
+ glyphs: FramePackedDataForPrimitive::new(),
+ images: FramePackedDataForPrimitive::new(),
+ borders: FramePackedDataForPrimitive::new(),
+ box_shadows: FramePackedDataForPrimitive::new(),
+ gradients: FramePackedDataForPrimitive::new(),
+ }
+ }
+
+ fn ranges_mut(&mut self, class: PrimitiveClass) -> &mut Vec<PackedPrimitiveRange> {
+ match class {
+ PrimitiveClass::Rectangle => &mut self.rectangles.ranges,
+ PrimitiveClass::RectangleClip => &mut self.rectangles_clip.ranges,
+ PrimitiveClass::Border => &mut self.borders.ranges,
+ PrimitiveClass::BoxShadow => &mut self.box_shadows.ranges,
+ PrimitiveClass::Text => &mut self.glyphs.ranges,
+ PrimitiveClass::Image => &mut self.images.ranges,
+ PrimitiveClass::Gradient => &mut self.gradients.ranges,
+ }
+ }
+
+ // FIXME(pcwalton): Don't clone?
+ fn clone_packed_primitive(&self,
+ class: PrimitiveClass,
+ index: ClassSpecificPackedPrimitiveIndex)
+ -> PackedPrimitive {
+ match class {
+ PrimitiveClass::Rectangle => {
+ PackedPrimitive::Rectangle(self.rectangles.data[index.0 as usize].clone())
+ }
+ PrimitiveClass::RectangleClip => {
+ PackedPrimitive::RectangleClip(self.rectangles_clip.data[index.0 as usize].clone())
+ }
+ PrimitiveClass::Border => {
+ PackedPrimitive::Border(self.borders.data[index.0 as usize].clone())
+ }
+ PrimitiveClass::BoxShadow => {
+ PackedPrimitive::BoxShadow(self.box_shadows.data[index.0 as usize].clone())
+ }
+ PrimitiveClass::Text => {
+ PackedPrimitive::Glyph(self.glyphs.data[index.0 as usize].clone())
+ }
+ PrimitiveClass::Image => {
+ PackedPrimitive::Image(self.images.data[index.0 as usize].clone())
+ }
+ PrimitiveClass::Gradient => {
+ PackedPrimitive::Gradient(self.gradients.data[index.0 as usize].clone())
+ }
+ }
+ }
+}
+
+struct TilePackedPrimList {
+ tile_index: u32,
+ layer_index: u32,
+ primitives: Vec<PackedPrimitiveRange>,
+}
+
+impl TilePackedPrimList {
+ fn new(tile_index: u32, layer_index: u32) -> TilePackedPrimList {
+ TilePackedPrimList {
+ tile_index: tile_index,
+ layer_index: layer_index,
+ primitives: vec![],
+ }
+ }
+}
+
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PrimitiveIndex(usize);
@@ -689,79 +890,74 @@ impl Primitive {
}
}
+ #[inline(never)]
fn pack(&self,
- batch: &mut PrimitiveBatch,
- layer_index_in_ubo: u32,
- tile_index_in_ubo: u32,
+ batch: &mut FramePackedPrimList,
auxiliary_lists: &AuxiliaryLists,
transform_kind: TransformedRectKind,
- ctx: &RenderTargetContext) -> bool {
- if transform_kind != batch.transform_kind {
+ ctx: &RenderTargetContext) {
+ /*if transform_kind != batch.transform_kind {
return false;
- }
+ }*/
- match (&mut batch.data, &self.details) {
- (&mut PrimitiveBatchData::Rectangles(ref mut data), &PrimitiveDetails::Rectangle(ref details)) => {
+ match self.details {
+ PrimitiveDetails::Rectangle(ref details) => {
match self.clip_index {
Some(clip_index) => {
- false
- }
- None => {
- data.push(PackedRectanglePrimitive {
+ let start_index =
+ PackedPrimitiveIndex(batch.rectangles_clip.data.len() as u16);
+
+ let ClipIndex(clip_index) = clip_index;
+ batch.rectangles_clip.data.push(PackedRectanglePrimitiveClip {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Invalid,
},
local_rect: self.rect,
color: details.color,
+ clip: ctx.clips[clip_index].clone(),
});
- true
+
+ let end_index =
+ PackedPrimitiveIndex(batch.rectangles_clip.data.len() as u16);
+ batch.rectangles_clip.ranges.push(PackedPrimitiveRange::new(start_index,
+ end_index))
}
- }
- }
- (&mut PrimitiveBatchData::Rectangles(..), _) => false,
- (&mut PrimitiveBatchData::RectanglesClip(ref mut data), &PrimitiveDetails::Rectangle(ref details)) => {
- match self.clip_index {
- Some(clip_index) => {
- let ClipIndex(clip_index) = clip_index;
- data.push(PackedRectanglePrimitiveClip {
+ None => {
+ let start_index = PackedPrimitiveIndex(batch.rectangles.data.len() as u16);
+
+ batch.rectangles.data.push(PackedRectanglePrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Invalid,
},
local_rect: self.rect,
color: details.color,
- clip: ctx.clips[clip_index].clone(),
});
- true
- }
- None => {
- false
+ let end_index = PackedPrimitiveIndex(batch.rectangles.data.len() as u16);
+ batch.rectangles.ranges.push(PackedPrimitiveRange::new(start_index,
+ end_index))
}
}
}
- (&mut PrimitiveBatchData::RectanglesClip(..), _) => false,
- (&mut PrimitiveBatchData::Image(ref mut data), &PrimitiveDetails::Image(ref details)) => {
+ PrimitiveDetails::Image(ref details) => {
+ let start_index = PackedPrimitiveIndex(batch.images.data.len() as u16);
+
let image_info = ctx.resource_cache.get_image(details.image_key,
details.image_rendering,
ctx.frame_id);
let uv_rect = image_info.uv_rect();
- // TODO(gw): Need a general solution to handle multiple texture pages per tile in WR2!
+ // TODO(gw): Need a general solution to handle multiple texture pages per tile in
+ // WR2!
assert!(batch.color_texture_id == TextureId(0) ||
batch.color_texture_id == image_info.texture_id);
batch.color_texture_id = image_info.texture_id;
- data.push(PackedImagePrimitive {
+ batch.images.data.push(PackedImagePrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Invalid,
},
local_rect: self.rect,
@@ -769,30 +965,31 @@ impl Primitive {
st1: uv_rect.bottom_right,
});
- true
+ let end_index = PackedPrimitiveIndex(batch.images.data.len() as u16);
+ batch.images.ranges.push(PackedPrimitiveRange::new(start_index, end_index))
}
- (&mut PrimitiveBatchData::Image(..), _) => false,
- (&mut PrimitiveBatchData::Borders(ref mut data), &PrimitiveDetails::Border(ref details)) => {
+ PrimitiveDetails::Border(ref details) => {
+ let start_index = PackedPrimitiveIndex(batch.borders.data.len() as u16);
+
+ let (left_width, right_width) = (details.left_width, details.right_width);
let inner_radius = BorderRadius {
- top_left: Size2D::new(details.radius.top_left.width - details.left_width,
- details.radius.top_left.width - details.left_width),
- top_right: Size2D::new(details.radius.top_right.width - details.right_width,
- details.radius.top_right.width - details.right_width),
- bottom_left: Size2D::new(details.radius.bottom_left.width - details.left_width,
- details.radius.bottom_left.width - details.left_width),
- bottom_right: Size2D::new(details.radius.bottom_right.width - details.right_width,
- details.radius.bottom_right.width - details.right_width),
+ top_left: Size2D::new(details.radius.top_left.width - left_width,
+ details.radius.top_left.width - left_width),
+ top_right: Size2D::new(details.radius.top_right.width - right_width,
+ details.radius.top_right.width - right_width),
+ bottom_left: Size2D::new(details.radius.bottom_left.width - left_width,
+ details.radius.bottom_left.width - left_width),
+ bottom_right: Size2D::new(details.radius.bottom_right.width - right_width,
+ details.radius.bottom_right.width - right_width),
};
let clip = Clip::from_border_radius(&self.rect,
&details.radius,
&inner_radius);
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::TopLeft,
},
local_rect: rect_from_points_f(details.tl_outer.x,
@@ -807,11 +1004,9 @@ impl Primitive {
inner_radius_y: inner_radius.top_left.height,
});
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::TopRight,
},
local_rect: rect_from_points_f(details.tr_inner.x,
@@ -826,11 +1021,9 @@ impl Primitive {
inner_radius_y: inner_radius.top_right.height,
});
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::BottomLeft,
},
local_rect: rect_from_points_f(details.bl_outer.x,
@@ -845,11 +1038,9 @@ impl Primitive {
inner_radius_y: inner_radius.bottom_left.height,
});
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::BottomRight,
},
local_rect: rect_from_points_f(details.br_inner.x,
@@ -864,11 +1055,9 @@ impl Primitive {
inner_radius_y: inner_radius.bottom_right.height,
});
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Left,
},
local_rect: rect_from_points_f(details.tl_outer.x,
@@ -883,11 +1072,9 @@ impl Primitive {
inner_radius_y: 0.0,
});
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Right,
},
local_rect: rect_from_points_f(details.tr_outer.x - details.right_width,
@@ -902,11 +1089,9 @@ impl Primitive {
inner_radius_y: 0.0,
});
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Top,
},
local_rect: rect_from_points_f(details.tl_inner.x,
@@ -921,11 +1106,9 @@ impl Primitive {
inner_radius_y: 0.0,
});
- data.push(PackedBorderPrimitive {
+ batch.borders.data.push(PackedBorderPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Bottom,
},
local_rect: rect_from_points_f(details.bl_inner.x,
@@ -940,10 +1123,12 @@ impl Primitive {
inner_radius_y: 0.0,
});
- true
+ let end_index = PackedPrimitiveIndex(batch.borders.data.len() as u16);
+ batch.borders.ranges.push(PackedPrimitiveRange::new(start_index, end_index))
}
- (&mut PrimitiveBatchData::Borders(..), _) => false,
- (&mut PrimitiveBatchData::Gradient(ref mut data), &PrimitiveDetails::Gradient(ref details)) => {
+ PrimitiveDetails::Gradient(ref details) => {
+ let start_index = PackedPrimitiveIndex(batch.gradients.data.len() as u16);
+
let stops = auxiliary_lists.gradient_stops(&details.stops_range);
for i in 0..(stops.len() - 1) {
let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]);
@@ -966,11 +1151,9 @@ impl Primitive {
let piece_rect = Rect::new(piece_origin, piece_size);
- data.push(PackedGradientPrimitive {
+ batch.gradients.data.push(PackedGradientPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Bottom,
},
local_rect: piece_rect,
@@ -981,19 +1164,19 @@ impl Primitive {
});
}
- true
+ let end_index = PackedPrimitiveIndex(batch.gradients.data.len() as u16);
+ batch.gradients.ranges.push(PackedPrimitiveRange::new(start_index, end_index))
}
- (&mut PrimitiveBatchData::Gradient(..), _) => false,
- (&mut PrimitiveBatchData::BoxShadows(ref mut data), &PrimitiveDetails::BoxShadow(ref details)) => {
+ PrimitiveDetails::BoxShadow(ref details) => {
+ let start_index = PackedPrimitiveIndex(batch.box_shadows.data.len() as u16);
+
let mut rects = Vec::new();
subtract_rect(&self.rect, &details.src_rect, &mut rects);
for rect in rects {
- data.push(PackedBoxShadowPrimitive {
+ batch.box_shadows.data.push(PackedBoxShadowPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Invalid,
},
local_rect: rect,
@@ -1007,10 +1190,12 @@ impl Primitive {
});
}
- true
+ let end_index = PackedPrimitiveIndex(batch.box_shadows.data.len() as u16);
+ batch.box_shadows.ranges.push(PackedPrimitiveRange::new(start_index, end_index))
}
- (&mut PrimitiveBatchData::BoxShadows(..), _) => false,
- (&mut PrimitiveBatchData::Text(ref mut data), &PrimitiveDetails::Text(ref details)) => {
+ PrimitiveDetails::Text(ref details) => {
+ let start_index = PackedPrimitiveIndex(batch.glyphs.data.len() as u16);
+
let src_glyphs = auxiliary_lists.glyph_instances(&details.glyph_range);
let mut glyph_key = GlyphKey::new(details.font_key,
details.size,
@@ -1022,24 +1207,27 @@ impl Primitive {
glyph_key.index = glyph.index;
let image_info = ctx.resource_cache.get_glyph(&glyph_key, ctx.frame_id);
if let Some(image_info) = image_info {
- // TODO(gw): Need a general solution to handle multiple texture pages per tile in WR2!
+ // TODO(gw): Need a general solution to handle multiple texture pages per
+ // tile in WR2!
assert!(batch.color_texture_id == TextureId(0) ||
batch.color_texture_id == image_info.texture_id);
batch.color_texture_id = image_info.texture_id;
- let x = glyph.x + image_info.user_data.x0 as f32 / ctx.device_pixel_ratio - blur_offset;
- let y = glyph.y - image_info.user_data.y0 as f32 / ctx.device_pixel_ratio - blur_offset;
+ let x = glyph.x + image_info.user_data.x0 as f32 / ctx.device_pixel_ratio -
+ blur_offset;
+ let y = glyph.y - image_info.user_data.y0 as f32 / ctx.device_pixel_ratio -
+ blur_offset;
- let width = image_info.requested_rect.size.width as f32 / ctx.device_pixel_ratio;
- let height = image_info.requested_rect.size.height as f32 / ctx.device_pixel_ratio;
+ let width = image_info.requested_rect.size.width as f32 /
+ ctx.device_pixel_ratio;
+ let height = image_info.requested_rect.size.height as f32 /
+ ctx.device_pixel_ratio;
let uv_rect = image_info.uv_rect();
- data.push(PackedGlyphPrimitive {
+ batch.glyphs.data.push(PackedGlyphPrimitive {
common: PackedPrimitiveInfo {
padding: 0,
- tile_index: tile_index_in_ubo,
- layer_index: layer_index_in_ubo,
part: PrimitivePart::Invalid,
},
local_rect: Rect::new(Point2D::new(x, y),
@@ -1051,9 +1239,20 @@ impl Primitive {
}
}
- true
+ let end_index = PackedPrimitiveIndex(batch.glyphs.data.len() as u16);
+ batch.glyphs.ranges.push(PackedPrimitiveRange::new(start_index, end_index))
}
- (&mut PrimitiveBatchData::Text(..), _) => false,
+ }
+ }
+
+ fn class(&self) -> PrimitiveClass {
+ match self.details {
+ PrimitiveDetails::Rectangle(_) => PrimitiveClass::Rectangle,
+ PrimitiveDetails::Border(_) => PrimitiveClass::Border,
+ PrimitiveDetails::BoxShadow(_) => PrimitiveClass::BoxShadow,
+ PrimitiveDetails::Text(_) => PrimitiveClass::Text,
+ PrimitiveDetails::Image(_) => PrimitiveClass::Image,
+ PrimitiveDetails::Gradient(_) => PrimitiveClass::Gradient,
}
}
}
@@ -1135,8 +1334,6 @@ pub struct PackedRenderable {
#[derive(Debug, Clone)]
pub struct PackedPrimitiveInfo {
- layer_index: u32,
- tile_index: u32,
part: PrimitivePart,
padding: u32,
}
@@ -1163,6 +1360,24 @@ pub struct PackedRectanglePrimitive {
}
#[derive(Debug, Clone)]
+#[repr(C)]
+pub struct TilePackedPrimitive<P> {
+ layer_index: u32,
+ tile_index: u32,
+ primitive: P,
+}
+
+impl<P> TilePackedPrimitive<P> {
+ fn new(layer_index: u32, tile_index: u32, primitive: P) -> TilePackedPrimitive<P> {
+ TilePackedPrimitive {
+ layer_index: layer_index,
+ tile_index: tile_index,
+ primitive: primitive,
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
pub struct PackedGlyphPrimitive {
common: PackedPrimitiveInfo,
local_rect: Rect<f32>,
@@ -1213,6 +1428,40 @@ pub struct PackedBoxShadowPrimitive {
src_rect: Rect<f32>,
}
+/// Top 3 bits: primitive batch type; bottom 13 bits: class-specific index.
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub struct PackedPrimitiveIndex(u16);
+
+impl PackedPrimitiveIndex {
+ fn new(class: PrimitiveClass, index: ClassSpecificPackedPrimitiveIndex)
+ -> PackedPrimitiveIndex {
+ debug_assert!(index.0 < (1 << 13));
+ PackedPrimitiveIndex(((class as u16) << 13) | (index.0 as u16))
+ }
+
+ fn from_primitive(index: ClassSpecificPackedPrimitiveIndex, primitive: &Primitive)
+ -> PackedPrimitiveIndex {
+ PackedPrimitiveIndex::new(primitive.class(), index)
+ }
+
+ fn class(self) -> PrimitiveClass {
+ PrimitiveClass::from((self.0 >> 13) as u8)
+ }
+
+ fn class_specific_index(self) -> ClassSpecificPackedPrimitiveIndex {
+ ClassSpecificPackedPrimitiveIndex(self.0 & !(7 << 13))
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
+pub struct ClassSpecificPackedPrimitiveIndex(u16);
+
+impl ClassSpecificPackedPrimitiveIndex {
+ fn dec(&mut self) {
+ *self = ClassSpecificPackedPrimitiveIndex(self.0 - 1)
+ }
+}
+
#[derive(Debug)]
pub enum PrimitiveBatchData {
Rectangles(Vec<PackedRectanglePrimitive>),
@@ -1224,46 +1473,167 @@ pub enum PrimitiveBatchData {
Gradient(Vec<PackedGradientPrimitive>),
}
-#[derive(Debug)]
-pub struct PrimitiveBatch {
- pub transform_kind: TransformedRectKind,
- pub color_texture_id: TextureId, // TODO(gw): Expand to sampler array to handle all glyphs!
- pub data: PrimitiveBatchData,
+#[repr(u8)]
+#[derive(Clone, Copy, PartialEq, Debug)]
+pub enum PrimitiveClass {
+ Rectangle = 0,
+ RectangleClip = 1,
+ Border = 2,
+ BoxShadow = 3,
+ Text = 4,
+ Image = 5,
+ Gradient = 6,
+}
+
+impl PrimitiveClass {
+ fn from(n: u8) -> PrimitiveClass {
+ match n {
+ 0 => PrimitiveClass::Rectangle,
+ 1 => PrimitiveClass::RectangleClip,
+ 2 => PrimitiveClass::Border,
+ 3 => PrimitiveClass::BoxShadow,
+ 4 => PrimitiveClass::Text,
+ 5 => PrimitiveClass::Image,
+ 6 => PrimitiveClass::Gradient,
+ _ => panic!("Not a valid primitive class number!"),
+ }
+ }
}
-impl PrimitiveBatch {
- fn new(prim: &Primitive, transform_kind: TransformedRectKind) -> PrimitiveBatch {
- let data = match prim.details {
- PrimitiveDetails::Rectangle(..) => {
- match prim.clip_index {
- Some(..) => PrimitiveBatchData::RectanglesClip(Vec::new()),
- None => PrimitiveBatchData::Rectangles(Vec::new()),
+impl PrimitiveBatchData {
+ /// Returns true if the primitive was successfully added and false otherwise.
+ pub fn push(&mut self, packed_primitive: PackedPrimitive) -> bool {
+ match *self {
+ PrimitiveBatchData::Rectangles(ref mut primitives) => {
+ match packed_primitive {
+ PackedPrimitive::Rectangle(primitive) => primitives.push(primitive),
+ _ => return false,
+ }
+ }
+ PrimitiveBatchData::RectanglesClip(ref mut primitives) => {
+ match packed_primitive {
+ PackedPrimitive::RectangleClip(primitive) => primitives.push(primitive),
+ _ => return false,
}
}
- PrimitiveDetails::Border(..) => {
- PrimitiveBatchData::Borders(Vec::new())
+ PrimitiveBatchData::Borders(ref mut primitives) => {
+ match packed_primitive {
+ PackedPrimitive::Border(primitive) => primitives.push(primitive),
+ _ => return false,
+ }
}
- PrimitiveDetails::BoxShadow(..) => {
- PrimitiveBatchData::BoxShadows(Vec::new())
+ PrimitiveBatchData::BoxShadows(ref mut primitives) => {
+ match packed_primitive {
+ PackedPrimitive::BoxShadow(primitive) => primitives.push(primitive),
+ _ => return false,
+ }
}
- PrimitiveDetails::Text(..) => {
- PrimitiveBatchData::Text(Vec::new())
+ PrimitiveBatchData::Text(ref mut primitives) => {
+ match packed_primitive {
+ PackedPrimitive::Glyph(primitive) => primitives.push(primitive),
+ _ => return false,
+ }
}
- PrimitiveDetails::Image(..) => {
- PrimitiveBatchData::Image(Vec::new())
+ PrimitiveBatchData::Image(ref mut primitives) => {
+ match packed_primitive {
+ PackedPrimitive::Image(primitive) => primitives.push(primitive),
+ _ => return false,
+ }
}
- PrimitiveDetails::Gradient(..) => {
- PrimitiveBatchData::Gradient(Vec::new())
+ PrimitiveBatchData::Gradient(ref mut primitives) => {
+ match packed_primitive {
+ PackedPrimitive::Gradient(primitive) => primitives.push(primitive),
+ _ => return false,
+ }
}
+ }
+ true
+ }
+}
+
+#[derive(Debug)]
+pub struct PrimitiveBatch {
+ pub transform_kind: TransformedRectKind,
+ pub color_texture_id: TextureId, // TODO(gw): Expand to sampler array to handle all glyphs!
+ pub data: PrimitiveBatchData,
+}
+
+impl PrimitiveBatch {
+ fn new(prim: &PackedPrimitive, transform_kind: TransformedRectKind) -> PrimitiveBatch {
+ let data = match *prim {
+ PackedPrimitive::Rectangle(..) => PrimitiveBatchData::Rectangles(vec![]),
+ PackedPrimitive::RectangleClip(..) => PrimitiveBatchData::RectanglesClip(vec![]),
+ PackedPrimitive::Border(..) => PrimitiveBatchData::Borders(vec![]),
+ PackedPrimitive::BoxShadow(..) => PrimitiveBatchData::BoxShadows(vec![]),
+ PackedPrimitive::Glyph(..) => PrimitiveBatchData::Text(vec![]),
+ PackedPrimitive::Image(..) => PrimitiveBatchData::Image(vec![]),
+ PackedPrimitive::Gradient(..) => PrimitiveBatchData::Gradient(vec![]),
};
- let mut this = PrimitiveBatch {
+ PrimitiveBatch {
color_texture_id: TextureId(0),
transform_kind: transform_kind,
data: data,
- };
+ }
+ }
- this
+ fn push_item_if_possible(&mut self,
+ packed_primitive_index: ClassSpecificPackedPrimitiveIndex,
+ frame_primitives: &FramePackedPrimList,
+ auxiliary_lists: &AuxiliaryLists,
+ transform_kind: TransformedRectKind,
+ context: &RenderTargetContext)
+ -> bool {
+ println!("pushing item");
+ // FIXME(pcwalton): Stop cloning?
+ match self.data {
+ PrimitiveBatchData::Rectangles(ref mut primitives) => {
+ /*primitives.push(frame_primitives.rectangles
+ .data[packed_primitive_index.0 as usize]
+ .clone())*/
+ }
+ PrimitiveBatchData::RectanglesClip(ref mut primitives) => {
+ /*primitives.push(frame_primitives.rectangles_clip
+ .data[packed_primitive_index.0 as usize]
+ .clone())*/
+ }
+ PrimitiveBatchData::Borders(ref mut primitives) => {
+ /*primitives.push(frame_primitives.borders.data[packed_primitive_index.0 as usize]
+ .clone())*/
+ }
+ PrimitiveBatchData::BoxShadows(ref mut primitives) => {
+ /*primitives.push(frame_primitives.box_shadows
+ .data[packed_primitive_index.0 as usize]
+ .clone())*/
+ }
+ PrimitiveBatchData::Text(ref mut primitives) => {
+ let glyphs = frame_primitives.glyphs.data[packed_primitive_index.0 as usize]
+ .clone();
+ println!("pushing glyphs: {:?}", glyphs);
+ primitives.push(glyphs)
+ }
+ PrimitiveBatchData::Image(ref mut primitives) => {
+ /*primitives.push(frame_primitives.images.data[packed_primitive_index.0 as usize]
+ .clone())*/
+ }
+ PrimitiveBatchData::Gradient(ref mut primitives) => {
+ /*primitives.push(frame_primitives.gradients.data[packed_primitive_index.0 as usize]
+ .clone())*/
+ }
+ }
+ true
+ }
+
+ fn class(&self) -> PrimitiveClass {
+ match self.data {
+ PrimitiveBatchData::Rectangles(_) |
+ PrimitiveBatchData::RectanglesClip(_) => PrimitiveClass::Rectangle,
+ PrimitiveBatchData::Borders(_) => PrimitiveClass::Border,
+ PrimitiveBatchData::BoxShadows(_) => PrimitiveClass::BoxShadow,
+ PrimitiveBatchData::Text(_) => PrimitiveClass::Text,
+ PrimitiveBatchData::Image(_) => PrimitiveClass::Image,
+ PrimitiveBatchData::Gradient(_) => PrimitiveClass::Gradient,
+ }
}
}
@@ -1290,6 +1660,8 @@ impl StackingContext {
resource_list: &mut ResourceList,
//index_buffer: &Vec<PrimitiveIndex>,
auxiliary_lists: &AuxiliaryLists) {
+ println!("StackingContext::build_resource_list(self.primitives.len={:?})",
+ self.primitives.len());
// for prim_index in index_buffer {
// let PrimitiveIndex(prim_index) = *prim_index;
// let prim = &self.primitives[prim_index];
@@ -1469,20 +1841,38 @@ struct CompositeTileInfo {
#[derive(Debug)]
struct ScreenTileLayer {
actual_rect: Rect<DevicePixel>,
+ tile_index: u32,
layer_index: StackingContextIndex,
- prim_indices: Vec<PrimitiveIndex>, // todo(gw): pre-build these into parts to save duplicated cpu time?
+ /// First primitive index in the screen tile map for this tile.
+ first_prim_sample_index: u8,
+ /// Last primitive index in the screen tile map for this tile.
+ last_prim_sample_index: u8,
layer_opacity: f32,
is_opaque: bool,
}
impl ScreenTileLayer {
+ fn tile_location(&self) -> Point2D<u32> {
+ Point2D {
+ x: ((self.actual_rect.origin.x.0 as usize) / SCREEN_TILE_SIZE) as u32,
+ y: ((self.actual_rect.origin.y.0 as usize) / SCREEN_TILE_SIZE) as u32,
+ }
+ }
+
+ fn prim_count(&self) -> u8 {
+ self.last_prim_sample_index - self.first_prim_sample_index
+ }
+
fn compile(&mut self,
layer: &StackingContext,
+ tile_prim_indices: PrimitiveIndices,
screen_rect: &Rect<DevicePixel>) {
+ // FIXME(pcwalton)
+ /*
self.prim_indices.sort_by(|a, b| {
b.cmp(&a)
});
- self.prim_indices.dedup();
+ self.prim_indices.dedup();*/
/*
// Intra-layer occlusion
@@ -1498,14 +1888,15 @@ impl ScreenTileLayer {
*/
// Inter-layer occlusion
- let PrimitiveIndex(pi) = *self.prim_indices.last().unwrap();
+ // TODO(pcwalton): Port this over.
+ /*let PrimitiveIndex(pi) = *self.prim_indices.last().unwrap();
let last_prim = &layer.primitives[pi];
if self.layer_opacity == 1.0 &&
last_prim.is_opaque() &&
rect_contains_rect(&last_prim.xf_rect.as_ref().unwrap().bounding_rect,
screen_rect) {
self.is_opaque = true;
- }
+ }*/
}
}
@@ -1554,7 +1945,8 @@ impl ScreenTile {
self.layers.len()
}
- fn compile(mut self) -> Option<CompiledScreenTile> {
+ fn compile(&mut self) -> Option<CompiledScreenTile> {
+ println!("compiling screen tile; rect={:?} layer size={:?}", self.rect, self.layers.len());
if self.layers.len() == 0 {
return None;
}
@@ -1902,82 +2294,105 @@ impl FrameBuilder {
}
}
- fn create_screen_tiles(&self) -> Vec<ScreenTile> {
- let dp_size = Size2D::new(DevicePixel::new(self.screen_rect.size.width as f32,
- self.device_pixel_ratio),
- DevicePixel::new(self.screen_rect.size.height as f32,
- self.device_pixel_ratio));
-
- let x_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32);
- let y_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32);
- let x_tile_count = (dp_size.width + x_tile_size - DevicePixel(1)).0 / x_tile_size.0;
- let y_tile_count = (dp_size.height + y_tile_size - DevicePixel(1)).0 / y_tile_size.0;
-
- // Build screen space tiles, which are individual BSP trees.
- let mut screen_tiles = Vec::new();
- for y in 0..y_tile_count {
- let y0 = DevicePixel(y * y_tile_size.0);
- let y1 = y0 + y_tile_size;
-
- for x in 0..x_tile_count {
- let x0 = DevicePixel(x * x_tile_size.0);
- let x1 = x0 + x_tile_size;
-
- let tile_rect = rect_from_points(x0, y0, x1, y1);
-
- screen_tiles.push(ScreenTile::new(tile_rect));
+ fn pack_primitives(&self,
+ pipeline_auxiliary_lists: &HashMap<PipelineId,
+ AuxiliaryLists,
+ BuildHasherDefault<FnvHasher>>,
+ ctx: &RenderTargetContext)
+ -> FramePackedPrimList {
+ let mut packed_prim_list = FramePackedPrimList::new();
+ //println!("layer count={:?}", self.layers.len());
+ for (layer_index, layer) in self.layers.iter().enumerate() {
+ //println!("layer has {:?} primitive(s)", layer.primitives.len());
+ packed_prim_list.rectangles.record_new_layer();
+ packed_prim_list.rectangles_clip.record_new_layer();
+ packed_prim_list.borders.record_new_layer();
+ packed_prim_list.box_shadows.record_new_layer();
+ packed_prim_list.glyphs.record_new_layer();
+ packed_prim_list.images.record_new_layer();
+ packed_prim_list.gradients.record_new_layer();
+
+ for (prim_index, prim) in layer.primitives.iter().enumerate() {
+ prim.pack(&mut packed_prim_list,
+ &pipeline_auxiliary_lists[&layer.pipeline_id],
+ layer.xf_rect.as_ref().unwrap().kind,
+ ctx)
}
}
-
- screen_tiles
+ packed_prim_list
}
fn assign_prims_to_screen_tiles(&self,
- screen_tiles: &mut Vec<ScreenTile>,
+ screen_tiles: &mut ScreenTileMap,
debug_rects: &mut Vec<DebugRect>) { //-> usize {
//let mut pass_count = 0;
// TODO(gw): This can be made much faster - calculate tile indices and
// assign in a loop.
- for screen_tile in screen_tiles {
- let mut prim_count = 0;
- for (layer_index, layer) in self.layers
- .iter()
- .enumerate() {
- let layer_index = StackingContextIndex(layer_index);
- let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect;
-
- if layer_rect.intersects(&screen_tile.rect) {
+ println!("assign_prims_to_screen_tiles()");
+ for y in 0..screen_tiles.tile_size.height {
+ for x in 0..screen_tiles.tile_size.width {
+ // FIXME(pcwalton): Is this right?
+ let tile_index = y * screen_tiles.tile_size.width + x;
+ let tile_location = Point2D::new(x, y);
+ let tile_rect = screen_tiles.tile_metadata(&tile_location).rect;
+ let mut prim_count = 0;
+ for (layer_index, layer) in self.layers.iter().enumerate() {
+ let layer_index = StackingContextIndex(layer_index);
+ let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect;
+ if !layer_rect.intersects(&tile_rect) {
+ continue
+ }
+
let mut tile_layer = ScreenTileLayer {
- actual_rect: screen_tile.rect,
+ actual_rect: tile_rect,
layer_index: layer_index,
- prim_indices: Vec::new(),
+ tile_index: tile_index,
+ first_prim_sample_index: screen_tiles.primitive_count(&tile_location),
+ last_prim_sample_index: screen_tiles.primitive_count(&tile_location),
layer_opacity: layer.opacity,
is_opaque: false,
};
- for (prim_index, prim) in layer.primitives.iter().enumerate() {
+
+ for (prim_index, prim) in layer.primitives.iter().enumerate().rev() {
let prim_rect = &prim.xf_rect.as_ref().unwrap().bounding_rect;
- if prim_rect.intersects(&screen_tile.rect) {
- prim_count += 1;
- tile_layer.prim_indices.push(PrimitiveIndex(prim_index));
+ if !prim_rect.intersects(&tile_rect) {
+ continue
}
+
+ prim_count += 1;
+ tile_layer.last_prim_sample_index += 1;
+
+ // FIXME(pcwalton): Is that right?
+ let prim_index = PackedPrimitiveIndex::new(
+ prim.class(),
+ ClassSpecificPackedPrimitiveIndex(prim_index as u16));
+ screen_tiles.add_prim_index(&tile_location, prim_index)
}
- if tile_layer.prim_indices.len() > 0 {
- tile_layer.compile(layer, &screen_tile.rect);
- if tile_layer.is_opaque {
- screen_tile.layers.clear();
- }
- screen_tile.layers.push(tile_layer);
+
+ if tile_layer.prim_count() == 0 {
+ continue
+ }
+
+ tile_layer.compile(layer,
+ screen_tiles.primitive_indices(&tile_location),
+ &screen_tiles.tile_metadata(&tile_location).rect);
+
+ let tile_metadata = screen_tiles.tile_metadata_mut(&tile_location);
+ if tile_layer.is_opaque {
+ tile_metadata.layers.clear()
}
+ tile_metadata.layers.push(tile_layer)
}
- }
- if self.debug {
- debug_rects.push(DebugRect {
- label: format!("{}|{}", screen_tile.layer_count(), prim_count),
- color: ColorF::new(1.0, 0.0, 0.0, 1.0),
- rect: screen_tile.rect,
- })
+ if self.debug {
+ let tile_metadata = screen_tiles.tile_metadata(&tile_location);
+ debug_rects.push(DebugRect {
+ label: format!("{}|{}", tile_metadata.layer_count(), prim_count),
+ color: ColorF::new(1.0, 0.0, 0.0, 1.0),
+ rect: tile_metadata.rect,
+ })
+ }
}
}
@@ -2006,11 +2421,33 @@ impl FrameBuilder {
resource_cache.raster_pending_glyphs(frame_id);
}
+ fn create_context<'a>(&'a self,
+ resource_cache: &'a ResourceCache,
+ frame_id: FrameId,
+ pipeline_auxiliary_lists: &'a HashMap<PipelineId,
+ AuxiliaryLists,
+ BuildHasherDefault<FnvHasher>>)
+ -> RenderTargetContext<'a> {
+ RenderTargetContext {
+ layers: &self.layers,
+ resource_cache: resource_cache,
+ device_pixel_ratio: self.device_pixel_ratio,
+ frame_id: frame_id,
+ pipeline_auxiliary_lists: pipeline_auxiliary_lists,
+ clips: &self.clips,
+ alpha_batch_max_layers: self.config.max_prim_layers,
+ alpha_batch_max_tiles: self.config.max_prim_tiles,
+ }
+ }
+
pub fn build(&mut self,
resource_cache: &mut ResourceCache,
frame_id: FrameId,
- pipeline_auxiliary_lists: &HashMap<PipelineId, AuxiliaryLists, BuildHasherDefault<FnvHasher>>,
- layer_map: &HashMap<ScrollLayerId, Layer, BuildHasherDefault<FnvHasher>>) -> Frame {
+ pipeline_auxiliary_lists: &HashMap<PipelineId,
+ AuxiliaryLists,
+ BuildHasherDefault<FnvHasher>>,
+ layer_map: &HashMap<ScrollLayerId, Layer, BuildHasherDefault<FnvHasher>>)
+ -> Frame {
let screen_rect = Rect::new(Point2D::zero(),
Size2D::new(DevicePixel::new(self.screen_rect.size.width as f32, self.device_pixel_ratio),
DevicePixel::new(self.screen_rect.size.height as f32, self.device_pixel_ratio)));
@@ -2018,21 +2455,23 @@ impl FrameBuilder {
self.cull_layers(&screen_rect, layer_map);
let mut debug_rects = Vec::new();
- let mut screen_tiles = self.create_screen_tiles();
+ let mut screen_tiles = ScreenTileMap::new(&self.screen_rect, self.device_pixel_ratio);
+
+ self.build_resource_list(resource_cache, frame_id, pipeline_auxiliary_lists);
- self.assign_prims_to_screen_tiles(&mut screen_tiles,
- &mut debug_rects);
+ let mut frame_packed_prim_list = {
+ let ctx = self.create_context(resource_cache, frame_id, pipeline_auxiliary_lists);
+ self.pack_primitives(pipeline_auxiliary_lists, &ctx)
+ };
- self.build_resource_list(resource_cache,
- frame_id,
- pipeline_auxiliary_lists);
+ self.assign_prims_to_screen_tiles(&mut screen_tiles, &mut debug_rects);
let mut clear_tiles = Vec::new();
// Build list of passes, target allocs that each tile needs.
let mut compiled_screen_tiles = Vec::new();
- for screen_tile in screen_tiles {
- let rect = screen_tile.rect; // TODO(gw): Remove clone here
+ for screen_tile in &mut screen_tiles.tile_metadata {
+ let rect = screen_tile.rect;
match screen_tile.compile() {
Some(compiled_screen_tile) => {
compiled_screen_tiles.push(compiled_screen_tile);
@@ -2047,6 +2486,8 @@ impl FrameBuilder {
let mut phases = Vec::new();
+ println!("--- starting frame ---");
+ let ctx = self.create_context(resource_cache, frame_id, pipeline_auxiliary_lists);
if !compiled_screen_tiles.is_empty() {
// Sort by pass count to minimize render target switches.
compiled_screen_tiles.sort_by(|a, b| {
@@ -2073,21 +2514,11 @@ impl FrameBuilder {
phases.push(current_phase);
- let ctx = RenderTargetContext {
- layers: &self.layers,
- resource_cache: resource_cache,
- device_pixel_ratio: self.device_pixel_ratio,
- frame_id: frame_id,
- pipeline_auxiliary_lists: pipeline_auxiliary_lists,
- clips: &self.clips,
- alpha_batch_max_layers: self.config.max_prim_layers,
- alpha_batch_max_tiles: self.config.max_prim_tiles,
- };
-
for phase in &mut phases {
- phase.build(&ctx);
+ phase.build(&ctx, &mut frame_packed_prim_list, &screen_tiles);
}
}
+ println!("--- ending frame ---");
Frame {
debug_rects: debug_rects,
@@ -2097,7 +2528,6 @@ impl FrameBuilder {
RENDERABLE_CACHE_SIZE.0 as f32),
}
}
-
}
fn compute_box_shadow_rect(box_bounds: &Rect<f32>,
@@ -2109,3 +2539,138 @@ fn compute_box_shadow_rect(box_bounds: &Rect<f32>,
rect.origin.y += box_offset.y;
rect.inflate(spread_radius, spread_radius)
}
+
+pub struct ScreenPrimitiveIndexBuffer {
+ index_buffer: Vec<PackedPrimitiveIndex>,
+}
+
+impl ScreenPrimitiveIndexBuffer {
+ fn new(tile_size: &Size2D<u32>) -> ScreenPrimitiveIndexBuffer {
+ let length = tile_size.height * tile_size.width * (PRIMITIVES_PER_BUFFER as u32);
+ ScreenPrimitiveIndexBuffer {
+ index_buffer: vec![PackedPrimitiveIndex(0); length as usize],
+ }
+ }
+}
+
+pub struct ScreenTileMap {
+ index_buffers: Vec<ScreenPrimitiveIndexBuffer>,
+ primitive_count_buffer: Vec<u8>,
+ tile_metadata: Vec<ScreenTile>,
+ tile_size: Size2D<u32>,
+}
+
+impl ScreenTileMap {
+ pub fn new(screen_rect: &Rect<i32>, device_pixel_ratio: f32) -> ScreenTileMap {
+ let dp_size = Size2D::new(DevicePixel::new(screen_rect.size.width as f32,
+ device_pixel_ratio),
+ DevicePixel::new(screen_rect.size.height as f32,
+ device_pixel_ratio));
+
+ let x_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32);
+ let y_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32);
+ let x_tile_count = (dp_size.width + x_tile_size - DevicePixel(1)).0 / x_tile_size.0;
+ let y_tile_count = (dp_size.height + y_tile_size - DevicePixel(1)).0 / y_tile_size.0;
+
+ // Build screen space tiles.
+ let mut screen_tiles = Vec::new();
+ for y in 0..y_tile_count {
+ let y0 = DevicePixel(y * y_tile_size.0);
+ let y1 = y0 + y_tile_size;
+
+ for x in 0..x_tile_count {
+ let x0 = DevicePixel(x * x_tile_size.0);
+ let x1 = x0 + x_tile_size;
+
+ let tile_rect = rect_from_points(x0, y0, x1, y1);
+
+ screen_tiles.push(ScreenTile::new(tile_rect));
+ }
+ }
+
+ ScreenTileMap {
+ index_buffers: vec![],
+ primitive_count_buffer: vec![0; (y_tile_count as usize) * (x_tile_count as usize)],
+ tile_metadata: screen_tiles,
+ tile_size: Size2D::new(x_tile_count as u32, y_tile_count as u32),
+ }
+ }
+
+ fn primitive_indices<'a,'b>(&'a self, tile_location: &'b Point2D<u32>)
+ -> PrimitiveIndices<'a> {
+ PrimitiveIndices {
+ primitive_depth: 0,
+ primitive_count: self.primitive_count(tile_location),
+ tile_index: self.tile_index(tile_location),
+ tile_map: self,
+ }
+ }
+
+ fn primitive_count(&self, tile_location: &Point2D<u32>) -> u8 {
+ self.primitive_count_buffer[self.tile_index(tile_location) as usize]
+ }
+
+ fn tile_index(&self, tile_location: &Point2D<u32>) -> u32 {
+ tile_location.y * self.tile_size.width + tile_location.x
+ }
+
+ fn tile_metadata(&self, tile_location: &Point2D<u32>) -> &ScreenTile {
+ &self.tile_metadata[self.tile_index(tile_location) as usize]
+ }
+
+ fn tile_metadata_mut<'a,'b>(&'a mut self, tile_location: &'b Point2D<u32>)
+ -> &'a mut ScreenTile {
+ let tile_index = self.tile_index(tile_location);
+ &mut self.tile_metadata[tile_index as usize]
+ }
+
+ fn add_prim_index(&mut self,
+ tile_location: &Point2D<u32>,
+ primitive_index: PackedPrimitiveIndex) {
+ let tile_index = self.tile_index(tile_location);
+ let primitive_count = self.primitive_count(tile_location);
+ let (buffer_index, index_in_buffer) =
+ self.buffer_index_and_index_in_buffer(tile_index, primitive_count);
+ while self.index_buffers.len() <= buffer_index {
+ self.index_buffers.push(ScreenPrimitiveIndexBuffer::new(&self.tile_size))
+ }
+ self.index_buffers[buffer_index].index_buffer[index_in_buffer] = primitive_index;
+ self.primitive_count_buffer[tile_index as usize] += 1
+ }
+
+ fn buffer_index_and_index_in_buffer(&self, tile_index: u32, primitive_depth: u8)
+ -> (usize, usize) {
+ let primitives_per_buffer = PRIMITIVES_PER_BUFFER as u32;
+ let primitive_depth = primitive_depth as u32;
+ let buffer_index = primitive_depth / primitives_per_buffer;
+ let index_in_buffer = tile_index * primitives_per_buffer + primitive_depth %
+ primitives_per_buffer;
+ (buffer_index as usize, index_in_buffer as usize)
+ }
+}
+
+pub struct PrimitiveIndices<'a> {
+ primitive_depth: u8,
+ primitive_count: u8,
+ tile_index: u32,
+ tile_map: &'a ScreenTileMap,
+}
+
+impl<'a> Iterator for PrimitiveIndices<'a> {
+ type Item = PackedPrimitiveIndex;
+
+ fn next(&mut self) -> Option<PackedPrimitiveIndex> {
+ if self.primitive_depth == self.primitive_count {
+ return None
+ }
+
+ let (buffer_index, index_in_buffer) =
+ self.tile_map.buffer_index_and_index_in_buffer(self.tile_index, self.primitive_depth);
+ let primitive_index = self.tile_map
+ .index_buffers[buffer_index]
+ .index_buffer[index_in_buffer];
+ self.primitive_depth += 1;
+ Some(primitive_index)
+ }
+}
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment