Created
July 19, 2016 21:45
-
-
Save pcwalton/d7b55143a409d4910983c94a9ae868a0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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