From d160c267f2ce38de3865fd6f7685d2aa146783e0 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 22 Jan 2016 14:21:30 +1000 Subject: [PATCH] Fix a number of issues relating to pixel accuracy. There's a lot of work to be done here still, but this is a good number of fixes to push. --- src/batch.rs | 25 ++++-- src/batch_builder.rs | 175 ++++++++++++++++++++++++++++-------------- src/frame.rs | 3 + src/internal_types.rs | 145 +++++++++++++++++++++------------- src/node_compiler.rs | 2 +- src/renderer.rs | 32 ++++---- src/resource_list.rs | 60 ++++++++------- src/tessellator.rs | 6 ++ src/texture_cache.rs | 40 +++++++--- src/util.rs | 42 +--------- 10 files changed, 320 insertions(+), 210 deletions(-) diff --git a/src/batch.rs b/src/batch.rs index bbb00115ea..5ea2cc8a2f 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -1,11 +1,9 @@ use device::{ProgramId, TextureId}; use euclid::{Point2D, Rect, Size2D}; use internal_types::{MAX_RECT, AxisDirection, PackedVertexColorMode, PackedVertexForQuad}; -use internal_types::{PackedVertexForTextureCacheUpdate, RectUv}; +use internal_types::{PackedVertexForTextureCacheUpdate, RectUv, DevicePixel}; use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; -use std::sync::Arc; -use std::u16; use webrender_traits::{ColorF, ComplexClipRegion}; pub const MAX_MATRICES_PER_BATCH: usize = 32; @@ -221,10 +219,13 @@ pub struct BatchBuilder<'a> { // TODO(gw): Support nested complex clip regions! pub complex_clip: Option, + + pub device_pixel_ratio: f32, } impl<'a> BatchBuilder<'a> { - pub fn new(vertex_buffer: &mut VertexBuffer) -> BatchBuilder { + pub fn new(vertex_buffer: &mut VertexBuffer, + device_pixel_ratio: f32) -> BatchBuilder { BatchBuilder { vertex_buffer: vertex_buffer, batches: Vec::new(), @@ -234,6 +235,7 @@ impl<'a> BatchBuilder<'a> { clip_out_rect: None, complex_clip: None, clip_offset: Point2D::zero(), + device_pixel_ratio: device_pixel_ratio, } } @@ -301,11 +303,22 @@ impl<'a> BatchBuilder<'a> { color_texture_id: TextureId, mask_texture_id: TextureId, pos_rect: &Rect, - uv_rect: &RectUv, - muv_rect: &RectUv, + uv_rect: &RectUv, + muv_rect: &RectUv, colors: &[ColorF; 4], color_mode: PackedVertexColorMode, tile_params: Option) { + // TODO(gw): Move this to the VS? + let snapped_origin = Point2D::new((pos_rect.origin.x * self.device_pixel_ratio).round() / self.device_pixel_ratio, + (pos_rect.origin.y * self.device_pixel_ratio).round() / self.device_pixel_ratio); + + let pos_rect = &Rect::new(snapped_origin, pos_rect.size); + + //debug_assert!((pos_rect.origin.x * self.device_pixel_ratio).fract() == 0.0); + //debug_assert!((pos_rect.origin.y * self.device_pixel_ratio).fract() == 0.0); + //debug_assert!((pos_rect.size.width * self.device_pixel_ratio).fract() == 0.0); + //debug_assert!((pos_rect.size.height * self.device_pixel_ratio).fract() == 0.0); + let (tile_params_index, clip_in_rect_index, clip_out_rect_index) = match self.cached_clip_in_rect { diff --git a/src/batch_builder.rs b/src/batch_builder.rs index 72d77dfcb1..e26720b55c 100644 --- a/src/batch_builder.rs +++ b/src/batch_builder.rs @@ -5,14 +5,15 @@ use euclid::{Rect, Point2D, Size2D}; use fnv::FnvHasher; use internal_types::{AxisDirection, BasicRotationAngle, BorderRadiusRasterOp, BoxShadowRasterOp}; use internal_types::{GlyphKey, PackedVertexColorMode, RasterItem, RectColors, RectPolygon}; -use internal_types::{RectSide, RectUv}; +use internal_types::{RectSide, RectUv, DevicePixel}; use renderer::BLUR_INFLATION_FACTOR; use resource_cache::ResourceCache; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_state::DefaultState; use std::f32; -use tessellator::{self, BorderCornerTessellation}; +use std::num::Zero; +//use tessellator::{self, BorderCornerTessellation}; use texture_cache::{TextureCacheItem}; use util; use util::RectVaryings; @@ -35,9 +36,9 @@ impl<'a> BatchBuilder<'a> { pub fn add_simple_rectangle(&mut self, color_texture_id: TextureId, pos_rect: &Rect, - uv_rect: &RectUv, + uv_rect: &RectUv, mask_texture_id: TextureId, - muv_rect: &RectUv, + muv_rect: &RectUv, colors: &[ColorF; 4], tile_params: Option) { if pos_rect.size.width == 0.0 || pos_rect.size.height == 0.0 { @@ -54,11 +55,31 @@ impl<'a> BatchBuilder<'a> { tile_params); } + #[inline] + fn snap_value_to_device_pixel(&self, value: &mut f32) { + *value = (*value * self.device_pixel_ratio).round() / self.device_pixel_ratio; + } + + #[inline] + fn snap_rect_to_device_pixel(&self, + rect: &mut Rect) { + let mut x1 = rect.origin.x + rect.size.width; + let mut y1 = rect.origin.y + rect.size.height; + self.snap_value_to_device_pixel(&mut x1); + self.snap_value_to_device_pixel(&mut y1); + + self.snap_value_to_device_pixel(&mut rect.origin.x); + self.snap_value_to_device_pixel(&mut rect.origin.y); + + rect.size.width = x1 - rect.origin.x; + rect.size.height = y1 - rect.origin.y; + } + // Colors are in the order: top left, top right, bottom right, bottom left. pub fn add_complex_clipped_rectangle(&mut self, color_texture_id: TextureId, pos_rect: &Rect, - uv_rect: &RectUv, + uv_rect: &RectUv, colors: &[ColorF; 4], tile_params: Option, resource_cache: &ResourceCache) { @@ -68,7 +89,6 @@ impl<'a> BatchBuilder<'a> { match self.complex_clip { Some(complex_clip) => { - let tl_x0 = complex_clip.rect.origin.x; let tl_y0 = complex_clip.rect.origin.y; @@ -81,10 +101,15 @@ impl<'a> BatchBuilder<'a> { let br_x0 = complex_clip.rect.origin.x + complex_clip.rect.size.width - complex_clip.radii.bottom_right.width; let br_y0 = complex_clip.rect.origin.y + complex_clip.rect.size.height - complex_clip.radii.bottom_right.height; - let tl_clip = Rect::new(Point2D::new(tl_x0, tl_y0), complex_clip.radii.top_left); - let tr_clip = Rect::new(Point2D::new(tr_x0, tr_y0), complex_clip.radii.top_right); - let bl_clip = Rect::new(Point2D::new(bl_x0, bl_y0), complex_clip.radii.bottom_left); - let br_clip = Rect::new(Point2D::new(br_x0, br_y0), complex_clip.radii.bottom_right); + let mut tl_clip = Rect::new(Point2D::new(tl_x0, tl_y0), complex_clip.radii.top_left); + let mut tr_clip = Rect::new(Point2D::new(tr_x0, tr_y0), complex_clip.radii.top_right); + let mut bl_clip = Rect::new(Point2D::new(bl_x0, bl_y0), complex_clip.radii.bottom_left); + let mut br_clip = Rect::new(Point2D::new(br_x0, br_y0), complex_clip.radii.bottom_right); + + self.snap_rect_to_device_pixel(&mut tl_clip); + self.snap_rect_to_device_pixel(&mut tr_clip); + self.snap_rect_to_device_pixel(&mut bl_clip); + self.snap_rect_to_device_pixel(&mut br_clip); // gen all vertices for each line let mut x_points = [ @@ -115,17 +140,24 @@ impl<'a> BatchBuilder<'a> { for xi in 0..x_points.len()-1 { for yi in 0..y_points.len()-1 { - let x0 = complex_clip.rect.origin.x + x_points[xi+0]; - let y0 = complex_clip.rect.origin.y + y_points[yi+0]; - let x1 = complex_clip.rect.origin.x + x_points[xi+1]; - let y1 = complex_clip.rect.origin.y + y_points[yi+1]; + let mut x0 = complex_clip.rect.origin.x + x_points[xi+0]; + let mut y0 = complex_clip.rect.origin.y + y_points[yi+0]; + let mut x1 = complex_clip.rect.origin.x + x_points[xi+1]; + let mut y1 = complex_clip.rect.origin.y + y_points[yi+1]; + + self.snap_value_to_device_pixel(&mut x0); + self.snap_value_to_device_pixel(&mut y0); + self.snap_value_to_device_pixel(&mut x1); + self.snap_value_to_device_pixel(&mut y1); if x0 != x1 && y0 != y1 { let sub_clip_rect = Rect::new(Point2D::new(x0, y0), Size2D::new(x1-x0, y1-y0)); - if let Some(clipped_pos_rect) = sub_clip_rect.intersection(&pos_rect) { + if let Some(mut clipped_pos_rect) = sub_clip_rect.intersection(&pos_rect) { + self.snap_rect_to_device_pixel(&mut clipped_pos_rect); + // TODO(gw): There must be a more efficient way to to // this (classifying which clip mask we need). let (mask_info, angle) = if sub_clip_rect.intersects(&tl_clip) { @@ -143,10 +175,10 @@ impl<'a> BatchBuilder<'a> { let (mask_texture_id, muv_rect) = match mask_info { Some(clip_rect) => { let mask_image = resource_cache.get_raster(&RasterItem::BorderRadius(BorderRadiusRasterOp { - outer_radius_x: Au::from_f32_px(clip_rect.size.width), - outer_radius_y: Au::from_f32_px(clip_rect.size.height), - inner_radius_x: Au(0), - inner_radius_y: Au(0), + outer_radius_x: DevicePixel::new(clip_rect.size.width, self.device_pixel_ratio), + outer_radius_y: DevicePixel::new(clip_rect.size.height, self.device_pixel_ratio), + inner_radius_x: DevicePixel::zero(), + inner_radius_y: DevicePixel::zero(), inverted: false, index: None, image_format: ImageFormat::A8, @@ -175,10 +207,10 @@ impl<'a> BatchBuilder<'a> { } } - let mu0 = mask_image.uv_rect.top_left.x; - let mu1 = mask_image.uv_rect.top_right.x; - let mv0 = mask_image.uv_rect.top_left.y; - let mv1 = mask_image.uv_rect.bottom_left.y; + let mu0 = mask_image.pixel_rect.top_left.x.as_f32(); + let mu1 = mask_image.pixel_rect.top_right.x.as_f32(); + let mv0 = mask_image.pixel_rect.top_left.y.as_f32(); + let mv1 = mask_image.pixel_rect.bottom_left.y.as_f32(); let mu_size = mu1 - mu0; let mv_size = mv1 - mv0; @@ -187,6 +219,11 @@ impl<'a> BatchBuilder<'a> { let mv1 = mv0 + y1_f * mv_size; let mv0 = mv0 + y0_f * mv_size; + let mu0 = DevicePixel::from_f32(mu0); + let mv0 = DevicePixel::from_f32(mv0); + let mu1 = DevicePixel::from_f32(mu1); + let mv1 = DevicePixel::from_f32(mv1); + let muv_rect = RectUv { top_left: Point2D::new(mu0, mv0), top_right: Point2D::new(mu1, mv0), @@ -198,7 +235,7 @@ impl<'a> BatchBuilder<'a> { } None => { let mask_image = resource_cache.get_dummy_mask_image(); - (mask_image.texture_id, mask_image.uv_rect) + (mask_image.texture_id, mask_image.pixel_rect) } }; @@ -235,7 +272,7 @@ impl<'a> BatchBuilder<'a> { pos_rect, uv_rect, dummy_mask_image.texture_id, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, colors, tile_params); } @@ -335,7 +372,7 @@ impl<'a> BatchBuilder<'a> { let blur_offset = blur_radius.to_f32_px() * (BLUR_INFLATION_FACTOR as f32) / 2.0; let mut text_batches: HashMap>, + Vec>>, DefaultState> = HashMap::with_hash_state(Default::default()); @@ -343,8 +380,12 @@ impl<'a> BatchBuilder<'a> { glyph_key.index = glyph.index; let image_info = resource_cache.get_glyph(&glyph_key); if let Some(image_info) = image_info { - let x = glyph.x + image_info.user_data.x0 as f32 / device_pixel_ratio - blur_offset; - let y = glyph.y - image_info.user_data.y0 as f32 / device_pixel_ratio - blur_offset; + let mut x = (glyph.x * device_pixel_ratio + image_info.user_data.x0 as f32).round() / device_pixel_ratio; + let mut y = (glyph.y * device_pixel_ratio - image_info.user_data.y0 as f32).round() / device_pixel_ratio; + + x -= blur_offset; + y -= blur_offset; + let width = image_info.requested_rect.size.width as f32 / device_pixel_ratio; let height = image_info.requested_rect.size.height as f32 / device_pixel_ratio; @@ -369,7 +410,7 @@ impl<'a> BatchBuilder<'a> { dummy_mask_image.texture_id, &rect.pos, &rect.varyings, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, &[*color, *color, *color, *color], PackedVertexColorMode::Gradient, None); @@ -479,19 +520,19 @@ impl<'a> BatchBuilder<'a> { let start_x = start_point.x + stop0.offset * (end_point.x - start_point.x); let start_y = start_point.y + stop0.offset * (end_point.y - start_point.y); - let end_x = start_point.x + stop1.offset * (end_point.x - start_point.x); - let end_y = start_point.y + stop1.offset * (end_point.y - start_point.y); + //let end_x = start_point.x + stop1.offset * (end_point.x - start_point.x); + //let end_y = start_point.y + stop1.offset * (end_point.y - start_point.y); let len_scale = 1000.0; // todo: determine this properly!! let x0 = start_x - perp_xn * len_scale; let y0 = start_y - perp_yn * len_scale; - let x1 = end_x - perp_xn * len_scale; - let y1 = end_y - perp_yn * len_scale; + //let x1 = end_x - perp_xn * len_scale; + //let y1 = end_y - perp_yn * len_scale; - let x2 = end_x + perp_xn * len_scale; - let y2 = end_y + perp_yn * len_scale; + //let x2 = end_x + perp_xn * len_scale; + //let y2 = end_y + perp_yn * len_scale; let x3 = start_x + perp_xn * len_scale; let y3 = start_y + perp_yn * len_scale; @@ -506,7 +547,7 @@ impl<'a> BatchBuilder<'a> { dummy_mask_image.texture_id, &rect, &white_image.uv_rect, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, &[*color0, *color1, *color0, *color1], PackedVertexColorMode::Gradient, None); @@ -929,9 +970,13 @@ impl<'a> BatchBuilder<'a> { } }; + let mask_radius = DevicePixel::new(mask_radius, self.device_pixel_ratio); + let raster_op = - BorderRadiusRasterOp::create(&Size2D::new(mask_radius, mask_radius), - &Size2D::new(0.0, 0.0), + BorderRadiusRasterOp::create(mask_radius, + mask_radius, + DevicePixel::zero(), + DevicePixel::zero(), false, None, ImageFormat::RGBA8).expect( @@ -946,7 +991,7 @@ impl<'a> BatchBuilder<'a> { dot_rect.size.height / 2.0)), &color_image.uv_rect, dummy_mask_image.texture_id, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, &colors, None); @@ -957,7 +1002,7 @@ impl<'a> BatchBuilder<'a> { dot_rect.size.height / 2.0)), &color_image.uv_rect, dummy_mask_image.texture_id, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, &colors, None); @@ -968,7 +1013,7 @@ impl<'a> BatchBuilder<'a> { -dot_rect.size.height / 2.0)), &color_image.uv_rect, dummy_mask_image.texture_id, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, &colors, None); @@ -979,7 +1024,7 @@ impl<'a> BatchBuilder<'a> { -dot_rect.size.height / 2.0)), &color_image.uv_rect, dummy_mask_image.texture_id, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, &colors, None); @@ -1258,7 +1303,7 @@ impl<'a> BatchBuilder<'a> { inner_radius: &Size2D, resource_cache: &ResourceCache, rotation_angle: BasicRotationAngle, - device_pixel_ratio: f32) { + _device_pixel_ratio: f32) { // TODO: Check for zero width/height borders! // FIXME(pcwalton): It's kind of messy to be matching on the rotation angle here to pick // the right rect to draw the rounded corner in. Is there a more elegant way to do this? @@ -1268,17 +1313,25 @@ impl<'a> BatchBuilder<'a> { let dummy_mask_image = resource_cache.get_dummy_mask_image(); // Draw the rounded part of the corner. - for rect_index in 0..tessellator::quad_count_for_border_corner(outer_radius, - device_pixel_ratio) { - let tessellated_rect = outer_corner_rect.tessellate_border_corner(outer_radius, - inner_radius, - device_pixel_ratio, - rotation_angle, - rect_index); - let mask_image = match BorderRadiusRasterOp::create(outer_radius, - inner_radius, + //for rect_index in 0..tessellator::quad_count_for_border_corner(outer_radius, + // device_pixel_ratio) { + let tessellated_rect = outer_corner_rect;//.tessellate_border_corner(outer_radius, + // inner_radius, + // device_pixel_ratio, + // rotation_angle, + // rect_index); + + let outer_radius_x = DevicePixel::new(outer_radius.width, self.device_pixel_ratio); + let outer_radius_y = DevicePixel::new(outer_radius.height, self.device_pixel_ratio); + let inner_radius_x = DevicePixel::new(inner_radius.width, self.device_pixel_ratio); + let inner_radius_y = DevicePixel::new(inner_radius.height, self.device_pixel_ratio); + + let mask_image = match BorderRadiusRasterOp::create(outer_radius_x, + outer_radius_y, + inner_radius_x, + inner_radius_y, false, - Some(rect_index), + None,//Some(rect_index), ImageFormat::A8) { Some(raster_item) => { resource_cache.get_raster(&RasterItem::BorderRadius(raster_item)) @@ -1288,7 +1341,10 @@ impl<'a> BatchBuilder<'a> { // FIXME(pcwalton): Either use RGBA8 textures instead of alpha masks here, or implement // a mask combiner. - let mask_uv = RectUv::from_image_and_rotation_angle(mask_image, rotation_angle, true); + let mask_uv = RectUv::from_uv_rect_rotation_angle(&mask_image.pixel_rect, + rotation_angle, + true); + let tessellated_rect = RectPolygon { pos: tessellated_rect, varyings: mask_uv, @@ -1300,7 +1356,7 @@ impl<'a> BatchBuilder<'a> { color1, resource_cache, rotation_angle); - } + //} // Draw the inner rect. self.add_border_corner_piece(RectPolygon { @@ -1328,7 +1384,7 @@ impl<'a> BatchBuilder<'a> { /// Draws one rectangle making up a border corner. fn add_border_corner_piece(&mut self, - rect_pos_uv: RectPolygon, + rect_pos_uv: RectPolygon>, mask_image: &TextureCacheItem, color0: &ColorF, color1: &ColorF, @@ -1409,7 +1465,10 @@ impl<'a> BatchBuilder<'a> { } let vertices_rect = Rect::new(*v0, Size2D::new(v1.x - v0.x, v1.y - v0.y)); - let color_uv = RectUv::from_image_and_rotation_angle(color_image, rotation_angle, false); + + let color_uv = RectUv::from_uv_rect_rotation_angle(&color_image.uv_rect, + rotation_angle, + false); let dummy_mask_image = resource_cache.get_dummy_mask_image(); @@ -1417,7 +1476,7 @@ impl<'a> BatchBuilder<'a> { &vertices_rect, &color_uv, dummy_mask_image.texture_id, - &dummy_mask_image.uv_rect, + &dummy_mask_image.pixel_rect, &[*color0, *color0, *color1, *color1], None); } diff --git a/src/frame.rs b/src/frame.rs index cc428bc1a1..7ad445bb32 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -643,6 +643,9 @@ impl Frame { layer.scroll_offset.y = layer.scroll_offset.y.min(0.0); layer.scroll_offset.y = layer.scroll_offset.y.max(-layer.layer_size.height + layer.viewport_size.height); } + + layer.scroll_offset.x = layer.scroll_offset.x.round(); + layer.scroll_offset.y = layer.scroll_offset.y.round(); } } } diff --git a/src/internal_types.rs b/src/internal_types.rs index e55575eb17..a58074c35f 100644 --- a/src/internal_types.rs +++ b/src/internal_types.rs @@ -7,13 +7,65 @@ use freelist::{FreeListItem, FreeListItemId}; use profiler::BackendProfileCounters; use std::collections::HashMap; use std::collections::hash_state::DefaultState; +use std::num::Zero; +use std::ops::Add; use std::path::PathBuf; use std::sync::Arc; -use texture_cache::TextureCacheItem; use util::{self, RectVaryings}; use webrender_traits::{FontKey, Epoch, ColorF, PipelineId}; use webrender_traits::{ImageFormat, MixBlendMode, NativeFontHandle, DisplayItem}; +#[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] +pub struct DevicePixel(i32); + +impl DevicePixel { + pub fn from_u32(value: u32) -> DevicePixel { + DevicePixel(value as i32) + } + + pub fn from_f32(value: f32) -> DevicePixel { + debug_assert!(value.fract() == 0.0); + DevicePixel(value as i32) + } + + pub fn new(value: f32, device_pixel_ratio: f32) -> DevicePixel { + DevicePixel((value * device_pixel_ratio).round() as i32) + } + + // TODO(gw): Remove eventually... + pub fn as_u16(&self) -> u16 { + let DevicePixel(value) = *self; + value as u16 + } + + // TODO(gw): Remove eventually... + pub fn as_u32(&self) -> u32 { + let DevicePixel(value) = *self; + value as u32 + } + + // TODO(gw): Remove eventually... + pub fn as_f32(&self) -> f32 { + let DevicePixel(value) = *self; + value as f32 + } +} + +impl Add for DevicePixel { + type Output = DevicePixel; + + #[inline] + fn add(self, other: DevicePixel) -> DevicePixel { + DevicePixel(self.0 + other.0) + } +} + +impl Zero for DevicePixel { + fn zero() -> DevicePixel { + DevicePixel(0) + } +} + const UV_FLOAT_TO_FIXED: f32 = 65535.0; const COLOR_FLOAT_TO_FIXED: f32 = 255.0; pub const ANGLE_FLOAT_TO_FIXED: f32 = 65535.0; @@ -174,8 +226,8 @@ pub struct PackedVertexForQuad { impl PackedVertexForQuad { pub fn new(position: &Rect, colors: &[ColorF; 4], - uv: &RectUv, - muv: &RectUv, + uv: &RectUv, + muv: &RectUv, color_mode: PackedVertexColorMode) -> PackedVertexForQuad { return PackedVertexForQuad { @@ -195,14 +247,14 @@ impl PackedVertexForQuad { v_bl: uv.bottom_left.y, u_br: uv.bottom_right.x, v_br: uv.bottom_right.y, - mu_tl: scale_muv_value(muv.top_left.x), - mv_tl: scale_muv_value(muv.top_left.y), - mu_tr: scale_muv_value(muv.top_right.x), - mv_tr: scale_muv_value(muv.top_right.y), - mu_bl: scale_muv_value(muv.bottom_left.x), - mv_bl: scale_muv_value(muv.bottom_left.y), - mu_br: scale_muv_value(muv.bottom_right.x), - mv_br: scale_muv_value(muv.bottom_right.y), + mu_tl: muv.top_left.x.as_u16(), + mv_tl: muv.top_left.y.as_u16(), + mu_tr: muv.top_right.x.as_u16(), + mv_tr: muv.top_right.y.as_u16(), + mu_bl: muv.bottom_left.x.as_u16(), + mv_bl: muv.bottom_left.y.as_u16(), + mu_br: muv.bottom_right.x.as_u16(), + mv_br: muv.bottom_right.y.as_u16(), matrix_index: 0, clip_in_rect_index: 0, clip_out_rect_index: 0, @@ -211,10 +263,6 @@ impl PackedVertexForQuad { PackedVertexColorMode::BorderCorner => 0x80, }, }; - - fn scale_muv_value(value: f32) -> u16 { - (value * UV_FLOAT_TO_FIXED) as u16 - } } } @@ -331,7 +379,7 @@ pub enum TextureUpdateDetails { Blit(Vec), Blur(Vec, Size2D, Au, TextureImage, TextureImage), /// All four corners, the tessellation index, and whether inverted, respectively. - BorderRadius(Au, Au, Au, Au, Option, bool), + BorderRadius(DevicePixel, DevicePixel, DevicePixel, DevicePixel, Option, bool), /// Blur radius, border radius, box rect, raster origin, and whether inverted, respectively. BoxShadow(Au, Au, Rect, Point2D, bool), } @@ -604,12 +652,6 @@ impl RectPolygon { } } -#[derive(Clone, Copy, Debug)] -pub struct RectColorsUv { - pub colors: RectColors, - pub uv: RectUv, -} - #[derive(Clone, Copy, Debug)] pub struct RectColors { pub top_left: ColorF, @@ -619,26 +661,26 @@ pub struct RectColors { } #[derive(Clone, Copy, Debug)] -pub struct RectUv { - pub top_left: Point2D, - pub top_right: Point2D, - pub bottom_left: Point2D, - pub bottom_right: Point2D, +pub struct RectUv { + pub top_left: Point2D, + pub top_right: Point2D, + pub bottom_left: Point2D, + pub bottom_right: Point2D, } -impl RectUv { - pub fn zero() -> RectUv { +impl RectUv { + pub fn zero() -> RectUv { RectUv { - top_left: Point2D::new(0.0, 0.0), - top_right: Point2D::new(0.0, 0.0), - bottom_left: Point2D::new(0.0, 0.0), - bottom_right: Point2D::new(0.0, 0.0), + top_left: Point2D::zero(), + top_right: Point2D::zero(), + bottom_left: Point2D::zero(), + bottom_right: Point2D::zero(), } } - pub fn from_uv_rect_rotation_angle(uv_rect: &RectUv, + pub fn from_uv_rect_rotation_angle(uv_rect: &RectUv, rotation_angle: BasicRotationAngle, - flip_90_degree_rotations: bool) -> RectUv { + flip_90_degree_rotations: bool) -> RectUv { match (rotation_angle, flip_90_degree_rotations) { (BasicRotationAngle::Upright, _) => { RectUv { @@ -690,15 +732,6 @@ impl RectUv { } } } - - pub fn from_image_and_rotation_angle(image: &TextureCacheItem, - rotation_angle: BasicRotationAngle, - flip_90_degree_rotations: bool) - -> RectUv { - RectUv::from_uv_rect_rotation_angle(&image.uv_rect, - rotation_angle, - flip_90_degree_rotations) - } } #[derive(Clone, Debug)] @@ -792,28 +825,30 @@ impl PackedVertexForTextureCacheUpdate { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct BorderRadiusRasterOp { - pub outer_radius_x: Au, - pub outer_radius_y: Au, - pub inner_radius_x: Au, - pub inner_radius_y: Au, + pub outer_radius_x: DevicePixel, + pub outer_radius_y: DevicePixel, + pub inner_radius_x: DevicePixel, + pub inner_radius_y: DevicePixel, pub index: Option, pub image_format: ImageFormat, pub inverted: bool, } impl BorderRadiusRasterOp { - pub fn create(outer_radius: &Size2D, - inner_radius: &Size2D, + pub fn create(outer_radius_x: DevicePixel, + outer_radius_y: DevicePixel, + inner_radius_x: DevicePixel, + inner_radius_y: DevicePixel, inverted: bool, index: Option, image_format: ImageFormat) -> Option { - if outer_radius.width > 0.0 || outer_radius.height > 0.0 { + if outer_radius_x > DevicePixel::zero() || outer_radius_y > DevicePixel::zero() { Some(BorderRadiusRasterOp { - outer_radius_x: Au::from_f32_px(outer_radius.width), - outer_radius_y: Au::from_f32_px(outer_radius.height), - inner_radius_x: Au::from_f32_px(inner_radius.width), - inner_radius_y: Au::from_f32_px(inner_radius.height), + outer_radius_x: outer_radius_x, + outer_radius_y: outer_radius_y, + inner_radius_x: inner_radius_x, + inner_radius_y: inner_radius_y, index: index, inverted: inverted, image_format: image_format, diff --git a/src/node_compiler.rs b/src/node_compiler.rs index 5b2c52cd28..338a715582 100644 --- a/src/node_compiler.rs +++ b/src/node_compiler.rs @@ -28,7 +28,7 @@ impl NodeCompiler for AABBTreeNode { let mut vertex_buffer = VertexBuffer::new(); for draw_list_group_segment in &self.draw_list_group_segments { - let mut builder = BatchBuilder::new(&mut vertex_buffer); + let mut builder = BatchBuilder::new(&mut vertex_buffer, device_pixel_ratio); // TODO(gw): This is a HACK to fix matrix palette index offsets - there needs to // be no holes in this array to match the draw group matrix palette. It's diff --git a/src/renderer.rs b/src/renderer.rs index ce11f26382..faf9925dfb 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -7,7 +7,7 @@ use fnv::FnvHasher; use gleam::gl; use internal_types::{RendererFrame, ResultMsg, TextureUpdateOp, BatchUpdateOp, BatchUpdateList}; use internal_types::{TextureUpdateDetails, TextureUpdateList, PackedVertex, RenderTargetMode}; -use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, BasicRotationAngle}; +use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE}; use internal_types::{PackedVertexForTextureCacheUpdate, CompositionOp, RenderTargetIndex}; use internal_types::{AxisDirection, LowLevelFilterOp, DrawCommand, DrawLayer, ANGLE_FLOAT_TO_FIXED}; use ipc_channel::ipc; @@ -22,7 +22,7 @@ use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; -use tessellator::BorderCornerTessellation; +//use tessellator::BorderCornerTessellation; use texture_cache::{BorderType, TextureCache, TextureInsertOp}; use time::precise_time_ns; use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier}; @@ -601,28 +601,32 @@ impl Renderer { inverted) => { let x = x as f32; let y = y as f32; - let device_pixel_ratio = self.device_pixel_ratio; + //let device_pixel_ratio = self.device_pixel_ratio; - let inner_rx = inner_rx.to_f32_px(); - let inner_ry = inner_ry.to_f32_px(); - let outer_rx = outer_rx.to_f32_px(); - let outer_ry = outer_ry.to_f32_px(); + //let inner_rx = inner_rx.to_f32_px(); + //let inner_ry = inner_ry.to_f32_px(); + //let outer_rx = outer_rx.to_f32_px(); + //let outer_ry = outer_ry.to_f32_px(); let tessellated_rect = - Rect::new(Point2D::new(0.0, 0.0), + Rect::new(Point2D::zero(), Size2D::new(outer_rx, outer_ry)); let tessellated_rect = match index { None => tessellated_rect, - Some(index) => { + Some(_index) => { + panic!("todo - re-enable border tesselation"); + /* tessellated_rect.tessellate_border_corner( &Size2D::new(outer_rx, outer_ry), &Size2D::new(inner_rx, inner_ry), device_pixel_ratio, BasicRotationAngle::Upright, index) + */ } }; // From here on out everything is in device coordinates. + /* let tessellated_rect = Rect::new( Point2D::new(tessellated_rect.origin.x * device_pixel_ratio, tessellated_rect.origin.y * device_pixel_ratio), @@ -635,6 +639,8 @@ impl Renderer { let outer_rx = outer_rx * device_pixel_ratio; let outer_ry = outer_ry * device_pixel_ratio; +*/ + let border_program_id = self.border_program_id; let color = if inverted { ColorF::new(0.0, 0.0, 0.0, 1.0) @@ -642,12 +648,12 @@ impl Renderer { ColorF::new(1.0, 1.0, 1.0, 1.0) }; - let border_radii_outer = Point2D::new(outer_rx, outer_ry); - let border_radii_inner = Point2D::new(inner_rx, inner_ry); + let border_radii_outer = Point2D::new(outer_rx.as_f32(), outer_ry.as_f32()); + let border_radii_inner = Point2D::new(inner_rx.as_f32(), inner_ry.as_f32()); let border_position = - Point2D::new(x - tessellated_rect.origin.x + outer_rx, - y - tessellated_rect.origin.y + outer_ry); + Point2D::new(x - tessellated_rect.origin.x.as_f32() + outer_rx.as_f32(), + y - tessellated_rect.origin.y.as_f32() + outer_ry.as_f32()); let zero_point = Point2D::new(0.0, 0.0); let zero_size = Size2D::new(0.0, 0.0); diff --git a/src/resource_list.rs b/src/resource_list.rs index 025fbdd057..f951368e0d 100644 --- a/src/resource_list.rs +++ b/src/resource_list.rs @@ -4,12 +4,12 @@ use batch_builder; use euclid::{Rect, Size2D}; use fnv::FnvHasher; use internal_types::{BorderRadiusRasterOp, BoxShadowRasterOp, DrawListItemIndex}; -use internal_types::{Glyph, GlyphKey, RasterItem}; +use internal_types::{Glyph, GlyphKey, RasterItem, DevicePixel}; use resource_cache::ResourceCache; use std::collections::{HashMap, HashSet}; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::collections::hash_state::DefaultState; -use tessellator; +//use tessellator; use webrender_traits::{BorderRadius, BorderStyle, BoxShadowClipMode, ImageRendering}; use webrender_traits::{FontKey, ImageFormat, ImageKey, SpecificDisplayItem}; @@ -21,14 +21,16 @@ pub struct ResourceList { required_images: RequiredImageSet, required_glyphs: RequiredGlyphMap, required_rasters: RequiredRasterSet, + device_pixel_ratio: f32, } impl ResourceList { - pub fn new() -> ResourceList { + pub fn new(device_pixel_ratio: f32) -> ResourceList { ResourceList { required_glyphs: HashMap::with_hash_state(Default::default()), required_images: HashSet::with_hash_state(Default::default()), required_rasters: HashSet::with_hash_state(Default::default()), + device_pixel_ratio: device_pixel_ratio, } } @@ -57,8 +59,14 @@ impl ResourceList { inverted: bool, index: Option, image_format: ImageFormat) { - if let Some(raster_item) = BorderRadiusRasterOp::create(outer_radius, - inner_radius, + let outer_radius_x = DevicePixel::new(outer_radius.width, self.device_pixel_ratio); + let outer_radius_y = DevicePixel::new(outer_radius.height, self.device_pixel_ratio); + let inner_radius_x = DevicePixel::new(inner_radius.width, self.device_pixel_ratio); + let inner_radius_y = DevicePixel::new(inner_radius.height, self.device_pixel_ratio); + if let Some(raster_item) = BorderRadiusRasterOp::create(outer_radius_x, + outer_radius_y, + inner_radius_x, + inner_radius_y, inverted, index, image_format) { @@ -135,7 +143,7 @@ pub trait BuildRequiredResources { impl BuildRequiredResources for AABBTreeNode { fn build_resource_list(&mut self, resource_cache: &ResourceCache) { //let _pf = util::ProfileScope::new(" build_resource_list"); - let mut resource_list = ResourceList::new(); + let mut resource_list = ResourceList::new(resource_cache.device_pixel_ratio()); for group in &self.draw_list_group_segments { for draw_list_index_buffer in &group.index_buffers { @@ -190,42 +198,42 @@ impl BuildRequiredResources for AABBTreeNode { } } SpecificDisplayItem::Border(ref info) => { - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.top_left, - resource_cache.device_pixel_ratio()) { + //for rect_index in 0..tessellator::quad_count_for_border_corner( + // &info.radius.top_left, + // resource_cache.device_pixel_ratio()) { resource_list.add_radius_raster(&info.radius.top_left, &info.top_left_inner_radius(), false, - Some(rect_index), + None,//Some(rect_index), ImageFormat::A8); - } - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.top_right, - resource_cache.device_pixel_ratio()) { + //} + //for rect_index in 0..tessellator::quad_count_for_border_corner( + // &info.radius.top_right, + // resource_cache.device_pixel_ratio()) { resource_list.add_radius_raster(&info.radius.top_right, &info.top_right_inner_radius(), false, - Some(rect_index), + None,//Some(rect_index), ImageFormat::A8); - } - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.bottom_left, - resource_cache.device_pixel_ratio()) { + //} + //for rect_index in 0..tessellator::quad_count_for_border_corner( + // &info.radius.bottom_left, + // resource_cache.device_pixel_ratio()) { resource_list.add_radius_raster(&info.radius.bottom_left, &info.bottom_left_inner_radius(), false, - Some(rect_index), + None,//Some(rect_index), ImageFormat::A8); - } - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.bottom_right, - resource_cache.device_pixel_ratio()) { + //} + //for rect_index in 0..tessellator::quad_count_for_border_corner( + // &info.radius.bottom_right, + // resource_cache.device_pixel_ratio()) { resource_list.add_radius_raster(&info.radius.bottom_right, &info.bottom_right_inner_radius(), false, - Some(rect_index), + None,//Some(rect_index), ImageFormat::A8); - } + //} if info.top.style == BorderStyle::Dotted { resource_list.add_radius_raster(&Size2D::new(info.top.width / 2.0, diff --git a/src/tessellator.rs b/src/tessellator.rs index 7d98fab793..9655969d00 100644 --- a/src/tessellator.rs +++ b/src/tessellator.rs @@ -1,3 +1,8 @@ +// TODO(gw): This code seems broken - e.g. the border_radius_shorthand reftest +// is drawn incorrectly if border tesselation is enabled. +// TODO(gw): Revisit this border tesselation code and make it work again. + +/* use euclid::{Point2D, Rect, Size2D}; use internal_types::BasicRotationAngle; @@ -104,3 +109,4 @@ fn ellipse_y_coordinate(x: f32, radius: &Size2D) -> f32 { } } +*/ diff --git a/src/texture_cache.rs b/src/texture_cache.rs index a7a66792de..18e5365a6f 100644 --- a/src/texture_cache.rs +++ b/src/texture_cache.rs @@ -5,14 +5,14 @@ use fnv::FnvHasher; use freelist::{FreeList, FreeListItem, FreeListItemId}; use internal_types::{TextureUpdate, TextureUpdateOp, TextureUpdateDetails}; use internal_types::{RasterItem, RenderTargetMode, TextureImage, TextureUpdateList}; -use internal_types::{BasicRotationAngle, RectUv}; +use internal_types::{RectUv, DevicePixel}; use std::cmp::Ordering; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::collections::hash_state::DefaultState; use std::mem; use std::slice::Iter; -use tessellator::BorderCornerTessellation; +//use tessellator::BorderCornerTessellation; use util; use webrender_traits::{ImageFormat}; @@ -407,7 +407,8 @@ pub struct TextureCacheItem { pub user_data: TextureCacheItemUserData, // The texture coordinates for this item - pub uv_rect: RectUv, + pub uv_rect: RectUv, + pub pixel_rect: RectUv, // The size of the entire texture (not just the allocated rectangle) pub texture_size: Size2D, @@ -453,12 +454,22 @@ impl TextureCacheItem { allocated_rect: Rect, requested_rect: Rect, texture_size: &Size2D, - uv_rect: RectUv) + uv_rect: RectUv) -> TextureCacheItem { TextureCacheItem { texture_id: texture_id, texture_size: *texture_size, uv_rect: uv_rect, + pixel_rect: RectUv { + top_left: Point2D::new(DevicePixel::from_u32(requested_rect.origin.x), + DevicePixel::from_u32(requested_rect.origin.y)), + top_right: Point2D::new(DevicePixel::from_u32(requested_rect.origin.x + requested_rect.size.width), + DevicePixel::from_u32(requested_rect.origin.y)), + bottom_left: Point2D::new(DevicePixel::from_u32(requested_rect.origin.x), + DevicePixel::from_u32(requested_rect.origin.y + requested_rect.size.height)), + bottom_right: Point2D::new(DevicePixel::from_u32(requested_rect.origin.x + requested_rect.size.width), + DevicePixel::from_u32(requested_rect.origin.y + requested_rect.size.height)) + }, user_data: TextureCacheItemUserData { x0: user_x0, y0: user_y0, @@ -562,6 +573,12 @@ impl TextureCache { x0: 0, y0: 0, }, + pixel_rect: RectUv { + top_left: Point2D::zero(), + top_right: Point2D::zero(), + bottom_left: Point2D::zero(), + bottom_right: Point2D::zero(), + }, allocated_rect: Rect::zero(), requested_rect: Rect::zero(), texture_size: Size2D::zero(), @@ -758,11 +775,13 @@ impl TextureCache { let update_op = match item { &RasterItem::BorderRadius(ref op) => { let rect = - Rect::new(Point2D::new(0.0, 0.0), - Size2D::new(op.outer_radius_x.to_f32_px(), - op.outer_radius_y.to_f32_px())); + Rect::new(Point2D::zero(), + Size2D::new(op.outer_radius_x, + op.outer_radius_y)); let tessellated_rect = match op.index { - Some(index) => { + Some(_index) => { + panic!("todo - re-enable border tesselation"); + /* rect.tessellate_border_corner( &Size2D::new(op.outer_radius_x.to_f32_px(), op.outer_radius_y.to_f32_px()), @@ -771,12 +790,13 @@ impl TextureCache { device_pixel_ratio, BasicRotationAngle::Upright, index) + */ } None => rect, }; - let width = (tessellated_rect.size.width.round() * device_pixel_ratio) as u32; - let height = (tessellated_rect.size.height.round() * device_pixel_ratio) as u32; + let width = tessellated_rect.size.width.as_u32();//.round() * device_pixel_ratio) as u32; + let height = tessellated_rect.size.height.as_u32();//.round() * device_pixel_ratio) as u32; let allocation = self.allocate(image_id, 0, diff --git a/src/util.rs b/src/util.rs index 5d43103adb..60871e31bb 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,5 @@ use euclid::{Matrix4, Point2D, Rect, Size2D}; -use internal_types::{RectColors, RectColorsUv, RectUv}; +use internal_types::{RectColors}; use std::num::Zero; use time::precise_time_ns; use webrender_traits::ColorF; @@ -97,22 +97,6 @@ pub trait RectVaryings { fn from_elements(elements: &[Self::Element; 4]) -> Self; } -impl RectVaryings for RectUv { - type Element = Point2D; - fn top_left(&self) -> Point2D { self.top_left } - fn top_right(&self) -> Point2D { self.top_right } - fn bottom_right(&self) -> Point2D { self.bottom_right } - fn bottom_left(&self) -> Point2D { self.bottom_left } - fn from_elements(elements: &[Point2D; 4]) -> RectUv { - RectUv { - top_left: elements[0], - top_right: elements[1], - bottom_right: elements[2], - bottom_left: elements[3], - } - } -} - impl RectVaryings for RectColors { type Element = ColorF; fn top_left(&self) -> ColorF { self.top_left } @@ -129,30 +113,6 @@ impl RectVaryings for RectColors { } } -impl RectVaryings for RectColorsUv { - type Element = (ColorF, Point2D); - fn top_left(&self) -> (ColorF, Point2D) { - (self.colors.top_left, self.uv.top_left) - } - fn top_right(&self) -> (ColorF, Point2D) { - (self.colors.top_right, self.uv.top_right) - } - fn bottom_left(&self) -> (ColorF, Point2D) { - (self.colors.bottom_left, self.uv.bottom_left) - } - fn bottom_right(&self) -> (ColorF, Point2D) { - (self.colors.bottom_right, self.uv.bottom_right) - } - fn from_elements(elements: &[(ColorF, Point2D); 4]) -> RectColorsUv { - let colors = [elements[0].0, elements[1].0, elements[2].0, elements[3].0]; - let uv = [elements[0].1, elements[1].1, elements[2].1, elements[3].1]; - RectColorsUv { - colors: RectColors::from_elements(&colors), - uv: RectUv::from_elements(&uv), - } - } -} - pub trait VaryingElement : Sized { fn scale(&self, factor: f32) -> Self; fn accumulate(values: &[Self; 4]) -> Self;