# HG changeset patch # User Kartikaya Gupta # Date 1523545486 14400 # Node ID 50c382ab757af549ace2f6dc1d839e3d15112d60 # Parent dd895ca139dce7de2c851385b4ce70d8eb7e3dd4 Bug 1452603 - Update webrender to commit 6f997974cec5772b1797725f4a7942d742e7d7ff. r=jrmuizel MozReview-Commit-ID: 1Gq3I7Z2Dd2 diff --git a/gfx/webrender/Cargo.toml b/gfx/webrender/Cargo.toml --- a/gfx/webrender/Cargo.toml +++ b/gfx/webrender/Cargo.toml @@ -17,17 +17,17 @@ debug_renderer = [] pathfinder = ["pathfinder_font_renderer", "pathfinder_gfx_utils", "pathfinder_partitioner", "pathfinder_path_utils"] [dependencies] app_units = "0.6" byteorder = "1.0" bincode = "1.0" euclid = "0.17" fxhash = "0.2.1" -gleam = "0.4.20" +gleam = "0.4.32" lazy_static = "1" log = "0.4" num-traits = "0.1.43" time = "0.1" rayon = "1" webrender_api = {path = "../webrender_api"} bitflags = "1.0" thread_profiler = "0.1.1" diff --git a/gfx/webrender/examples/common/boilerplate.rs b/gfx/webrender/examples/common/boilerplate.rs --- a/gfx/webrender/examples/common/boilerplate.rs +++ b/gfx/webrender/examples/common/boilerplate.rs @@ -137,16 +137,17 @@ pub fn main_wrapper( println!("Loading shaders..."); let opts = webrender::RendererOptions { resource_override_path: res_path, precache_shaders: E::PRECACHE_SHADERS, device_pixel_ratio, clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)), //scatter_gpu_cache_updates: false, + debug_flags: webrender::DebugFlags::ECHO_DRIVER_MESSAGES, ..options.unwrap_or(webrender::RendererOptions::default()) }; let framebuffer_size = { let (width, height) = window.get_inner_size().unwrap(); DeviceUintSize::new(width, height) }; let notifier = Box::new(Notifier::new(events_loop.create_proxy())); diff --git a/gfx/webrender/src/batch.rs b/gfx/webrender/src/batch.rs --- a/gfx/webrender/src/batch.rs +++ b/gfx/webrender/src/batch.rs @@ -970,33 +970,27 @@ impl AlphaBatchBuilder { } } } } PrimitiveKind::Border => { let border_cpu = &ctx.prim_store.cpu_borders[prim_metadata.cpu_prim_index.0]; // TODO(gw): Select correct blend mode for edges and corners!! - let corner_kind = BatchKind::Transformable( - transform_kind, - TransformBatchKind::BorderCorner, - ); - let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures); - let edge_kind = BatchKind::Transformable( - transform_kind, - TransformBatchKind::BorderEdge, - ); - let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures); - // Work around borrow ck on borrowing batch_list twice. - { - let batch = - self.batch_list.get_suitable_batch(corner_key, &task_relative_bounding_rect); - for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate() - { + if border_cpu.corner_instances.iter().any(|&kind| kind != BorderCornerInstance::None) { + let corner_kind = BatchKind::Transformable( + transform_kind, + TransformBatchKind::BorderCorner, + ); + let corner_key = BatchKey::new(corner_kind, non_segmented_blend_mode, no_textures); + let batch = self.batch_list + .get_suitable_batch(corner_key, &task_relative_bounding_rect); + + for (i, instance_kind) in border_cpu.corner_instances.iter().enumerate() { let sub_index = i as i32; match *instance_kind { BorderCornerInstance::None => {} BorderCornerInstance::Single => { batch.push(base_instance.build( sub_index, BorderCornerSide::Both as i32, 0, @@ -1013,22 +1007,32 @@ impl AlphaBatchBuilder { BorderCornerSide::Second as i32, 0, )); } } } } - let batch = self.batch_list.get_suitable_batch(edge_key, &task_relative_bounding_rect); - for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() { - match *instance_kind { - BorderEdgeKind::None => {}, - _ => { - batch.push(base_instance.build(border_segment as i32, 0, 0)); + if border_cpu.edges.iter().any(|&kind| kind != BorderEdgeKind::None) { + let edge_kind = BatchKind::Transformable( + transform_kind, + TransformBatchKind::BorderEdge, + ); + let edge_key = BatchKey::new(edge_kind, non_segmented_blend_mode, no_textures); + let batch = self.batch_list + .get_suitable_batch(edge_key, &task_relative_bounding_rect); + + for (border_segment, instance_kind) in border_cpu.edges.iter().enumerate() { + match *instance_kind { + BorderEdgeKind::None => {}, + BorderEdgeKind::Solid | + BorderEdgeKind::Clip => { + batch.push(base_instance.build(border_segment as i32, 0, 0)); + } } } } } PrimitiveKind::Image => { let image_cpu = &ctx.prim_store.cpu_images[prim_metadata.cpu_prim_index.0]; let cache_item = match image_cpu.source { diff --git a/gfx/webrender/src/border.rs b/gfx/webrender/src/border.rs --- a/gfx/webrender/src/border.rs +++ b/gfx/webrender/src/border.rs @@ -98,144 +98,126 @@ impl BorderCornerKind { #[derive(Copy, Clone, Debug, PartialEq)] pub enum BorderEdgeKind { None, Solid, Clip, } -trait NormalBorderHelpers { - fn get_corner( - &self, - edge0: &BorderSide, - width0: f32, - edge1: &BorderSide, - width1: f32, - radius: &LayerSize, - corner: BorderCorner, - border_rect: &LayerRect, - ) -> BorderCornerKind; - - fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32); -} +fn get_corner( + edge0: &BorderSide, + width0: f32, + edge1: &BorderSide, + width1: f32, + radius: &LayerSize, + corner: BorderCorner, + border_rect: &LayerRect, +) -> BorderCornerKind { + // If both widths are zero, a corner isn't formed. + if width0 == 0.0 && width1 == 0.0 { + return BorderCornerKind::None; + } -impl NormalBorderHelpers for NormalBorder { - fn get_corner( - &self, - edge0: &BorderSide, - width0: f32, - edge1: &BorderSide, - width1: f32, - radius: &LayerSize, - corner: BorderCorner, - border_rect: &LayerRect, - ) -> BorderCornerKind { - // If both widths are zero, a corner isn't formed. - if width0 == 0.0 && width1 == 0.0 { - return BorderCornerKind::None; + // If both edges are transparent, no corner is formed. + if edge0.color.a == 0.0 && edge1.color.a == 0.0 { + return BorderCornerKind::None; + } + + match (edge0.style, edge1.style) { + // If both edges are none or hidden, no corner is needed. + (BorderStyle::None, BorderStyle::None) | + (BorderStyle::None, BorderStyle::Hidden) | + (BorderStyle::Hidden, BorderStyle::None) | + (BorderStyle::Hidden, BorderStyle::Hidden) => { + BorderCornerKind::None } - // If both edges are transparent, no corner is formed. - if edge0.color.a == 0.0 && edge1.color.a == 0.0 { - return BorderCornerKind::None; + // If one of the edges is none or hidden, we just draw one style. + (BorderStyle::None, _) | + (_, BorderStyle::None) | + (BorderStyle::Hidden, _) | + (_, BorderStyle::Hidden) => { + BorderCornerKind::Clip(BorderCornerInstance::Single) } - match (edge0.style, edge1.style) { - // If both edges are none or hidden, no corner is needed. - (BorderStyle::None, BorderStyle::None) | - (BorderStyle::None, BorderStyle::Hidden) | - (BorderStyle::Hidden, BorderStyle::None) | - (BorderStyle::Hidden, BorderStyle::Hidden) => { - BorderCornerKind::None - } - - // If one of the edges is none or hidden, we just draw one style. - (BorderStyle::None, _) | - (_, BorderStyle::None) | - (BorderStyle::Hidden, _) | - (_, BorderStyle::Hidden) => { + // If both borders are solid, we can draw them with a simple rectangle if + // both the colors match and there is no radius. + (BorderStyle::Solid, BorderStyle::Solid) => { + if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 { + BorderCornerKind::Solid + } else { BorderCornerKind::Clip(BorderCornerInstance::Single) } + } - // If both borders are solid, we can draw them with a simple rectangle if - // both the colors match and there is no radius. - (BorderStyle::Solid, BorderStyle::Solid) => { - if edge0.color == edge1.color && radius.width == 0.0 && radius.height == 0.0 { - BorderCornerKind::Solid - } else { - BorderCornerKind::Clip(BorderCornerInstance::Single) - } - } - - // Inset / outset borders just modify the color of edges, so can be - // drawn with the normal border corner shader. - (BorderStyle::Outset, BorderStyle::Outset) | - (BorderStyle::Inset, BorderStyle::Inset) | - (BorderStyle::Double, BorderStyle::Double) | - (BorderStyle::Groove, BorderStyle::Groove) | - (BorderStyle::Ridge, BorderStyle::Ridge) => { - BorderCornerKind::Clip(BorderCornerInstance::Single) - } + // Inset / outset borders just modify the color of edges, so can be + // drawn with the normal border corner shader. + (BorderStyle::Outset, BorderStyle::Outset) | + (BorderStyle::Inset, BorderStyle::Inset) | + (BorderStyle::Double, BorderStyle::Double) | + (BorderStyle::Groove, BorderStyle::Groove) | + (BorderStyle::Ridge, BorderStyle::Ridge) => { + BorderCornerKind::Clip(BorderCornerInstance::Single) + } - // Dashed and dotted border corners get drawn into a clip mask. - (BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask( - BorderCornerClipKind::Dash, - width0, - width1, - corner, - *radius, - *border_rect, - ), - (BorderStyle::Dotted, BorderStyle::Dotted) => BorderCornerKind::new_mask( - BorderCornerClipKind::Dot, - width0, - width1, - corner, - *radius, - *border_rect, - ), + // Dashed and dotted border corners get drawn into a clip mask. + (BorderStyle::Dashed, BorderStyle::Dashed) => BorderCornerKind::new_mask( + BorderCornerClipKind::Dash, + width0, + width1, + corner, + *radius, + *border_rect, + ), + (BorderStyle::Dotted, BorderStyle::Dotted) => BorderCornerKind::new_mask( + BorderCornerClipKind::Dot, + width0, + width1, + corner, + *radius, + *border_rect, + ), - // Draw border transitions with dots and/or dashes as - // solid segments. The old border path didn't support - // this anyway, so we might as well start using the new - // border path here, since the dashing in the edges is - // much higher quality anyway. - (BorderStyle::Dotted, _) | - (_, BorderStyle::Dotted) | - (BorderStyle::Dashed, _) | - (_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single), + // Draw border transitions with dots and/or dashes as + // solid segments. The old border path didn't support + // this anyway, so we might as well start using the new + // border path here, since the dashing in the edges is + // much higher quality anyway. + (BorderStyle::Dotted, _) | + (_, BorderStyle::Dotted) | + (BorderStyle::Dashed, _) | + (_, BorderStyle::Dashed) => BorderCornerKind::Clip(BorderCornerInstance::Single), - // Everything else can be handled by drawing the corner twice, - // where the shader outputs zero alpha for the side it's not - // drawing. This is somewhat inefficient in terms of pixels - // written, but it's a fairly rare case, and we can optimize - // this case later. - _ => BorderCornerKind::Clip(BorderCornerInstance::Double), - } + // Everything else can be handled by drawing the corner twice, + // where the shader outputs zero alpha for the side it's not + // drawing. This is somewhat inefficient in terms of pixels + // written, but it's a fairly rare case, and we can optimize + // this case later. + _ => BorderCornerKind::Clip(BorderCornerInstance::Double), + } +} + +fn get_edge(edge: &BorderSide, width: f32, height: f32) -> (BorderEdgeKind, f32) { + if width == 0.0 || height <= 0.0 { + return (BorderEdgeKind::None, 0.0); } - fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32) { - if width == 0.0 { - return (BorderEdgeKind::None, 0.0); + match edge.style { + BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0), + + BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => { + (BorderEdgeKind::Solid, width) } - match edge.style { - BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0), - - BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => { - (BorderEdgeKind::Solid, width) - } - - BorderStyle::Double | - BorderStyle::Groove | - BorderStyle::Ridge | - BorderStyle::Dashed | - BorderStyle::Dotted => (BorderEdgeKind::Clip, width), - } + BorderStyle::Double | + BorderStyle::Groove | + BorderStyle::Ridge | + BorderStyle::Dashed | + BorderStyle::Dotted => (BorderEdgeKind::Clip, width), } } pub fn ensure_no_corner_overlap( radius: &mut BorderRadius, rect: &LayerRect, ) { let mut ratio = 1.0; @@ -426,58 +408,62 @@ impl<'a> DisplayListFlattener<'a> { None, extra_clips, ); return; } let corners = [ - border.get_corner( + get_corner( left, widths.left, top, widths.top, &radius.top_left, BorderCorner::TopLeft, &info.rect, ), - border.get_corner( + get_corner( right, widths.right, top, widths.top, &radius.top_right, BorderCorner::TopRight, &info.rect, ), - border.get_corner( + get_corner( right, widths.right, bottom, widths.bottom, &radius.bottom_right, BorderCorner::BottomRight, &info.rect, ), - border.get_corner( + get_corner( left, widths.left, bottom, widths.bottom, &radius.bottom_left, BorderCorner::BottomLeft, &info.rect, ), ]; - let (left_edge, left_len) = border.get_edge(left, widths.left); - let (top_edge, top_len) = border.get_edge(top, widths.top); - let (right_edge, right_len) = border.get_edge(right, widths.right); - let (bottom_edge, bottom_len) = border.get_edge(bottom, widths.bottom); + let (left_edge, left_len) = get_edge(left, widths.left, + info.rect.size.height - radius.top_left.height - radius.bottom_left.height); + let (top_edge, top_len) = get_edge(top, widths.top, + info.rect.size.width - radius.top_left.width - radius.top_right.width); + let (right_edge, right_len) = get_edge(right, widths.right, + info.rect.size.height - radius.top_right.height - radius.bottom_right.height); + let (bottom_edge, bottom_len) = get_edge(bottom, widths.bottom, + info.rect.size.width - radius.bottom_right.width - radius.bottom_left.width); let edges = [left_edge, top_edge, right_edge, bottom_edge]; // Use a simple rectangle case when all edges and corners are either // solid or none. let all_corners_simple = corners.iter().all(|c| { *c == BorderCornerKind::Solid || *c == BorderCornerKind::None }); diff --git a/gfx/webrender/src/debug_server.rs b/gfx/webrender/src/debug_server.rs --- a/gfx/webrender/src/debug_server.rs +++ b/gfx/webrender/src/debug_server.rs @@ -58,17 +58,17 @@ impl ws::Handler for Server { "enable_gpu_sample_queries" => DebugCommand::EnableGpuSampleQueries(true), "disable_gpu_sample_queries" => DebugCommand::EnableGpuSampleQueries(false), "fetch_passes" => DebugCommand::FetchPasses, "fetch_screenshot" => DebugCommand::FetchScreenshot, "fetch_documents" => DebugCommand::FetchDocuments, "fetch_clip_scroll_tree" => DebugCommand::FetchClipScrollTree, "fetch_render_tasks" => DebugCommand::FetchRenderTasks, msg => { - println!("unknown msg {}", msg); + error!("unknown msg {}", msg); return Ok(()); } }; let msg = ApiMsg::DebugCommand(cmd); self.api_tx.send(msg).unwrap(); } ws::Message::Binary(..) => {} @@ -100,19 +100,19 @@ impl DebugServer { } }) .unwrap(); let broadcaster = socket.broadcaster(); let join_handle = Some(thread::spawn(move || { let address = "127.0.0.1:3583"; - println!("WebRender debug server started: {}", address); + debug!("WebRender debug server started: {}", address); if let Err(..) = socket.listen(address) { - println!("ERROR: Unable to bind debugger websocket (port may be in use)."); + error!("ERROR: Unable to bind debugger websocket (port may be in use)."); } })); DebugServer { join_handle, broadcaster, debug_rx, senders: Vec::new(), diff --git a/gfx/webrender/src/device.rs b/gfx/webrender/src/device.rs --- a/gfx/webrender/src/device.rs +++ b/gfx/webrender/src/device.rs @@ -6,16 +6,17 @@ use super::shader_source; use api::{ColorF, ImageFormat}; use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize}; use api::TextureTarget; #[cfg(any(feature = "debug_renderer", feature="capture"))] use api::ImageDescriptor; use euclid::Transform3D; use gleam::gl; use internal_types::{FastHashMap, RenderTargetInfo}; +use log::Level; use smallvec::SmallVec; use std::cell::RefCell; use std::fs::File; use std::io::Read; use std::marker::PhantomData; use std::mem; use std::ops::Add; use std::path::PathBuf; @@ -782,39 +783,39 @@ impl Device { Some(pos) => 2 + pos, None => return, }; let base_line_number = match log[2 .. end_pos].parse::() { Ok(number) if number >= 2 => number - 2, _ => return, }; for (line, prefix) in source.lines().skip(base_line_number).zip(&["|",">","|"]) { - println!("{}\t{}", prefix, line); + error!("{}\t{}", prefix, line); } } pub fn compile_shader( gl: &gl::Gl, name: &str, shader_type: gl::GLenum, source: &String, ) -> Result { debug!("compile {}", name); let id = gl.create_shader(shader_type); gl.shader_source(id, &[source.as_bytes()]); gl.compile_shader(id); let log = gl.get_shader_info_log(id); if gl.get_shader_iv(id, gl::COMPILE_STATUS) == (0 as gl::GLint) { - println!("Failed to compile shader: {}\n{}", name, log); + error!("Failed to compile shader: {}\n{}", name, log); #[cfg(debug_assertions)] Self::print_shader_errors(source, &log); Err(ShaderError::Compilation(name.to_string(), log)) } else { if !log.is_empty() { - println!("Warnings detected on shader: {}\n{}", name, log); + warn!("Warnings detected on shader: {}\n{}", name, log); } Ok(id) } } pub fn begin_frame(&mut self) -> FrameId { debug_assert!(!self.inside_frame); self.inside_frame = true; @@ -1375,17 +1376,17 @@ impl Device { if let Some(ref cached_programs) = self.cached_programs { if let Some(binary) = cached_programs.binaries.borrow().get(&sources) { self.gl.program_binary(pid, binary.format, &binary.binary); if self.gl.get_program_iv(pid, gl::LINK_STATUS) == (0 as gl::GLint) { let error_log = self.gl.get_program_info_log(pid); - println!( + error!( "Failed to load a program object with a program binary: {} renderer {}\n{}", base_filename, self.renderer_name, error_log ); } else { loaded = true; } @@ -1437,17 +1438,17 @@ impl Device { // to free any memory associated with the parsing and compilation. self.gl.detach_shader(pid, vs_id); self.gl.detach_shader(pid, fs_id); self.gl.delete_shader(vs_id); self.gl.delete_shader(fs_id); if self.gl.get_program_iv(pid, gl::LINK_STATUS) == (0 as gl::GLint) { let error_log = self.gl.get_program_info_log(pid); - println!( + error!( "Failed to link shader program: {}\n{}", base_filename, error_log ); self.gl.delete_program(pid); return Err(ShaderError::Link(base_filename.to_string(), error_log)); } } @@ -2098,16 +2099,41 @@ impl Device { pub fn set_blend_mode_subpixel_dual_source(&self) { self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC1_COLOR); self.gl.blend_equation(gl::FUNC_ADD); } pub fn supports_extension(&self, extension: &str) -> bool { self.extensions.iter().any(|s| s == extension) } + + pub fn echo_driver_messages(&self) { + for msg in self.gl.get_debug_messages() { + let level = match msg.severity { + gl::DEBUG_SEVERITY_HIGH => Level::Error, + gl::DEBUG_SEVERITY_MEDIUM => Level::Warn, + gl::DEBUG_SEVERITY_LOW => Level::Info, + gl::DEBUG_SEVERITY_NOTIFICATION => Level::Debug, + _ => Level::Trace, + }; + let ty = match msg.ty { + gl::DEBUG_TYPE_ERROR => "error", + gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "deprecated", + gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "undefined", + gl::DEBUG_TYPE_PORTABILITY => "portability", + gl::DEBUG_TYPE_PERFORMANCE => "perf", + gl::DEBUG_TYPE_MARKER => "marker", + gl::DEBUG_TYPE_PUSH_GROUP => "group push", + gl::DEBUG_TYPE_POP_GROUP => "group pop", + gl::DEBUG_TYPE_OTHER => "other", + _ => "?", + }; + log!(level, "({}) {}", ty, msg.message); + } + } } struct FormatDesc { internal: gl::GLint, external: gl::GLuint, pixel_type: gl::GLuint, } diff --git a/gfx/webrender/src/display_list_flattener.rs b/gfx/webrender/src/display_list_flattener.rs --- a/gfx/webrender/src/display_list_flattener.rs +++ b/gfx/webrender/src/display_list_flattener.rs @@ -565,17 +565,21 @@ impl<'a> DisplayListFlattener<'a> { item: &DisplayItemRef, info: &IframeDisplayItem, clip_and_scroll_ids: &ClipAndScrollInfo, reference_frame_relative_offset: &LayerVector2D, ) { let iframe_pipeline_id = info.pipeline_id; let pipeline = match self.scene.pipelines.get(&iframe_pipeline_id) { Some(pipeline) => pipeline, - None => return, + None => { + //TODO: assert/debug_assert? + error!("Unknown pipeline used for iframe {:?}", info); + return + }, }; self.id_to_index_mapper.initialize_for_pipeline(pipeline); self.add_clip_node( info.clip_id, clip_and_scroll_ids.scroll_node_id, ClipRegion::create_for_clip_node_with_local_clip( diff --git a/gfx/webrender/src/freelist.rs b/gfx/webrender/src/freelist.rs --- a/gfx/webrender/src/freelist.rs +++ b/gfx/webrender/src/freelist.rs @@ -85,16 +85,22 @@ impl FreeList { pub fn recycle(self) -> FreeList { FreeList { slots: recycle_vec(self.slots), free_list_head: None, active_count: 0, } } + pub fn clear(&mut self) { + self.slots.clear(); + self.free_list_head = None; + self.active_count = 0; + } + #[allow(dead_code)] pub fn get(&self, id: &FreeListHandle) -> &T { self.slots[id.index as usize].value.as_ref().unwrap() } #[allow(dead_code)] pub fn get_mut(&mut self, id: &FreeListHandle) -> &mut T { self.slots[id.index as usize].value.as_mut().unwrap() diff --git a/gfx/webrender/src/glyph_rasterizer.rs b/gfx/webrender/src/glyph_rasterizer.rs --- a/gfx/webrender/src/glyph_rasterizer.rs +++ b/gfx/webrender/src/glyph_rasterizer.rs @@ -3,16 +3,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #[cfg(test)] use api::{IdNamespace, LayoutPoint}; use api::{ColorF, ColorU}; use api::{FontInstanceFlags, FontInstancePlatformOptions}; use api::{FontKey, FontRenderMode, FontTemplate, FontVariation}; use api::{GlyphDimensions, GlyphKey, LayerToWorldTransform, SubpixelDirection}; +#[cfg(feature = "pathfinder")] +use api::NativeFontHandle; #[cfg(any(test, feature = "pathfinder"))] use api::DeviceIntSize; #[cfg(not(feature = "pathfinder"))] use api::{ImageData, ImageDescriptor, ImageFormat}; use app_units::Au; #[cfg(not(feature = "pathfinder"))] use device::TextureFilter; #[cfg(feature = "pathfinder")] @@ -123,44 +125,44 @@ impl FontTransform { FontTransform::new( (self.scale_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, (self.skew_x * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, (self.skew_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, (self.scale_y * Self::QUANTIZE_SCALE).round() / Self::QUANTIZE_SCALE, ) } - #[cfg(not(feature = "pathfinder"))] + #[allow(dead_code)] pub fn determinant(&self) -> f64 { self.scale_x as f64 * self.scale_y as f64 - self.skew_y as f64 * self.skew_x as f64 } - #[cfg(not(feature = "pathfinder"))] + #[allow(dead_code)] pub fn compute_scale(&self) -> Option<(f64, f64)> { let det = self.determinant(); if det != 0.0 { let x_scale = (self.scale_x as f64).hypot(self.skew_y as f64); let y_scale = det.abs() / x_scale; Some((x_scale, y_scale)) } else { None } } - #[cfg(not(feature = "pathfinder"))] + #[allow(dead_code)] pub fn pre_scale(&self, scale_x: f32, scale_y: f32) -> Self { FontTransform::new( self.scale_x * scale_x, self.skew_x * scale_y, self.skew_y * scale_x, self.scale_y * scale_y, ) } - #[cfg(not(feature = "pathfinder"))] + #[allow(dead_code)] pub fn invert_scale(&self, x_scale: f64, y_scale: f64) -> Self { self.pre_scale(x_scale.recip() as f32, y_scale.recip() as f32) } pub fn synthesize_italics(&self, skew_factor: f32) -> Self { FontTransform::new( self.scale_x, self.skew_x - self.scale_x * skew_factor, @@ -448,16 +450,17 @@ impl GlyphRasterizer { } self.add_font_to_pathfinder(&font_key, &template); } #[cfg(feature = "pathfinder")] fn add_font_to_pathfinder(&mut self, font_key: &FontKey, template: &FontTemplate) { let font_contexts = Arc::clone(&self.font_contexts); + debug!("add_font_to_pathfinder({:?})", font_key); font_contexts.lock_pathfinder_context().add_font(&font_key, &template); } #[cfg(not(feature = "pathfinder"))] fn add_font_to_pathfinder(&mut self, _: &FontKey, _: &FontTemplate) {} pub fn delete_font(&mut self, font_key: FontKey) { self.fonts_to_remove.push(font_key); @@ -856,20 +859,20 @@ impl AddFont for FontContext { } } #[cfg(feature = "pathfinder")] impl AddFont for PathfinderFontContext { fn add_font(&mut self, font_key: &FontKey, template: &FontTemplate) { match *template { FontTemplate::Raw(ref bytes, index) => { - drop(self.add_font_from_memory(font_key, bytes.clone(), index)); + drop(self.add_font_from_memory(&font_key, bytes.clone(), index)) } FontTemplate::Native(ref native_font_handle) => { - drop(self.add_native_font(font_key, (*native_font_handle).clone().0)); + drop(self.add_native_font(&font_key, NativeFontHandleWrapper(native_font_handle))) } } } } #[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -1062,8 +1065,11 @@ fn request_render_task_from_pathfinder(g let render_pass = match render_mode { FontRenderMode::Mono | FontRenderMode::Alpha => &mut render_passes.alpha_glyph_pass, FontRenderMode::Subpixel => &mut render_passes.color_glyph_pass, }; render_pass.add_render_task(root_task_id, *glyph_size, RenderTargetKind::Color); Ok((root_task_id, false)) } + +#[cfg(feature = "pathfinder")] +pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle); diff --git a/gfx/webrender/src/platform/macos/font.rs b/gfx/webrender/src/platform/macos/font.rs --- a/gfx/webrender/src/platform/macos/font.rs +++ b/gfx/webrender/src/platform/macos/font.rs @@ -23,16 +23,18 @@ use core_graphics::font::{CGFont, CGGlyp use core_graphics::geometry::{CGAffineTransform, CGPoint, CGSize}; #[cfg(not(feature = "pathfinder"))] use core_graphics::geometry::CGRect; use core_text; use core_text::font::{CTFont, CTFontRef}; use core_text::font_descriptor::{kCTFontDefaultOrientation, kCTFontColorGlyphsTrait}; use gamma_lut::{ColorLut, GammaLut}; use glyph_rasterizer::{FontInstance, FontTransform}; +#[cfg(feature = "pathfinder")] +use glyph_rasterizer::NativeFontHandleWrapper; #[cfg(not(feature = "pathfinder"))] use glyph_rasterizer::{GlyphFormat, GlyphRasterResult, RasterizedGlyph}; use internal_types::{FastHashMap, ResourceCacheError}; use std::collections::hash_map::Entry; use std::sync::Arc; pub struct FontContext { cg_fonts: FastHashMap, @@ -724,8 +726,15 @@ impl FontContext { width: metrics.rasterized_width, height: metrics.rasterized_height, scale: if bitmap { y_scale.recip() as f32 } else { 1.0 }, format: if bitmap { GlyphFormat::ColorBitmap } else { font.get_glyph_format() }, bytes: rasterized_pixels, }) } } + +#[cfg(feature = "pathfinder")] +impl<'a> Into for NativeFontHandleWrapper<'a> { + fn into(self) -> CGFont { + (self.0).0.clone() + } +} diff --git a/gfx/webrender/src/platform/unix/font.rs b/gfx/webrender/src/platform/unix/font.rs --- a/gfx/webrender/src/platform/unix/font.rs +++ b/gfx/webrender/src/platform/unix/font.rs @@ -14,17 +14,21 @@ use freetype::freetype::{FT_Init_FreeTyp use freetype::freetype::{FT_Library, FT_Outline_Get_CBox, FT_Set_Char_Size, FT_Select_Size}; use freetype::freetype::{FT_Fixed, FT_Matrix, FT_Set_Transform}; use freetype::freetype::{FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_FORCE_AUTOHINT}; use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHINT}; use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING, FT_LOAD_VERTICAL_LAYOUT}; use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES}; use freetype::succeeded; use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphRasterResult, RasterizedGlyph}; +#[cfg(feature = "pathfinder")] +use glyph_rasterizer::NativeFontHandleWrapper; use internal_types::{FastHashMap, ResourceCacheError}; +#[cfg(feature = "pathfinder")] +use pathfinder_font_renderer::freetype as pf_freetype; use std::{cmp, mem, ptr, slice}; use std::cmp::max; use std::ffi::CString; use std::sync::Arc; // These constants are not present in the freetype // bindings due to bindgen not handling the way // the macros are defined. @@ -187,17 +191,17 @@ impl FontContext { self.faces.insert( *font_key, Face { face, _bytes: Some(bytes), }, ); } else { - println!("WARN: webrender failed to load font"); + warn!("WARN: webrender failed to load font"); debug!("font={:?}", font_key); } } } pub fn add_native_font(&mut self, font_key: &FontKey, native_font_handle: NativeFontHandle) { if !self.faces.contains_key(&font_key) { let mut face: FT_Face = ptr::null_mut(); @@ -214,17 +218,17 @@ impl FontContext { self.faces.insert( *font_key, Face { face, _bytes: None, }, ); } else { - println!("WARN: webrender failed to load font"); + warn!("WARN: webrender failed to load font"); debug!("font={:?}, path={:?}", font_key, pathname); } } } pub fn delete_font(&mut self, font_key: &FontKey) { if let Some(face) = self.faces.remove(font_key) { let result = unsafe { FT_Done_Face(face.face) }; @@ -783,8 +787,16 @@ impl FontContext { impl Drop for FontContext { fn drop(&mut self) { unsafe { FT_Done_FreeType(self.lib); } } } + +#[cfg(feature = "pathfinder")] +impl<'a> Into for NativeFontHandleWrapper<'a> { + fn into(self) -> pf_freetype::FontDescriptor { + let NativeFontHandleWrapper(font_handle) = self; + pf_freetype::FontDescriptor::new(font_handle.pathname.clone().into(), font_handle.index) + } +} diff --git a/gfx/webrender/src/render_backend.rs b/gfx/webrender/src/render_backend.rs --- a/gfx/webrender/src/render_backend.rs +++ b/gfx/webrender/src/render_backend.rs @@ -661,16 +661,20 @@ impl RenderBackend { profile_scope!("GetScrollNodeState"); tx.send(doc.get_scroll_node_state()).unwrap(); DocumentOps::nop() } FrameMsg::UpdateDynamicProperties(property_bindings) => { doc.dynamic_properties.set_properties(property_bindings); DocumentOps::render() } + FrameMsg::AppendDynamicProperties(property_bindings) => { + doc.dynamic_properties.add_properties(property_bindings); + DocumentOps::render() + } } } fn next_namespace_id(&self) -> IdNamespace { IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32) } pub fn run(&mut self, mut profile_counters: BackendProfileCounters) { diff --git a/gfx/webrender/src/render_task.rs b/gfx/webrender/src/render_task.rs --- a/gfx/webrender/src/render_task.rs +++ b/gfx/webrender/src/render_task.rs @@ -6,16 +6,17 @@ use api::{DeviceIntPoint, DeviceIntRect, #[cfg(feature = "pathfinder")] use api::FontRenderMode; use box_shadow::{BoxShadowCacheKey}; use clip::{ClipSource, ClipStore, ClipWorkItem}; use clip_scroll_tree::CoordinateSystemId; use device::TextureFilter; #[cfg(feature = "pathfinder")] use euclid::{TypedPoint2D, TypedVector2D}; +use freelist::{FreeList, FreeListHandle}; use glyph_rasterizer::GpuGlyphCacheKey; use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use gpu_types::{ImageSource, RasterizationSpace}; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; #[cfg(feature = "pathfinder")] use pathfinder_partitioner::mesh::Mesh; use prim_store::{PrimitiveIndex, ImageCacheKey}; #[cfg(feature = "debugger")] @@ -861,37 +862,40 @@ pub enum RenderTaskCacheKeyKind { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct RenderTaskCacheKey { pub size: DeviceIntSize, pub kind: RenderTaskCacheKeyKind, } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -struct RenderTaskCacheEntry { - handle: TextureCacheHandle, +pub struct RenderTaskCacheEntry { + pub handle: TextureCacheHandle, } // A cache of render tasks that are stored in the texture // cache for usage across frames. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct RenderTaskCache { - entries: FastHashMap, + map: FastHashMap>, + cache_entries: FreeList, } impl RenderTaskCache { pub fn new() -> Self { RenderTaskCache { - entries: FastHashMap::default(), + map: FastHashMap::default(), + cache_entries: FreeList::new(), } } pub fn clear(&mut self) { - self.entries.clear(); + self.map.clear(); + self.cache_entries.clear(); } pub fn begin_frame( &mut self, texture_cache: &mut TextureCache, ) { // Drop any items from the cache that have been // evicted from the texture cache. @@ -901,38 +905,53 @@ impl RenderTaskCache { // It will evict render tasks as required, since // the access time in the texture cache entry will // be stale if this task hasn't been requested // for a while. // // Nonetheless, we should remove stale entries // from here so that this hash map doesn't // grow indefinitely! - self.entries.retain(|_, value| { - texture_cache.is_allocated(&value.handle) - }); + let mut keys_to_remove = Vec::new(); + + for (key, handle) in &self.map { + let entry = self.cache_entries.get(handle); + if !texture_cache.is_allocated(&entry.handle) { + keys_to_remove.push(key.clone()) + } + } + + for key in &keys_to_remove { + let handle = self.map.remove(key).unwrap(); + self.cache_entries.free(handle); + } } pub fn request_render_task( &mut self, key: RenderTaskCacheKey, texture_cache: &mut TextureCache, gpu_cache: &mut GpuCache, render_tasks: &mut RenderTaskTree, user_data: Option<[f32; 3]>, mut f: F, ) -> Result where F: FnMut(&mut RenderTaskTree) -> Result<(RenderTaskId, bool), ()> { // Get the texture cache handle for this cache key, // or create one. - let cache_entry = self.entries - .entry(key) - .or_insert(RenderTaskCacheEntry { - handle: TextureCacheHandle::new(), - }); + let cache_entries = &mut self.cache_entries; + let entry_handle = self.map + .entry(key) + .or_insert_with(|| { + let entry = RenderTaskCacheEntry { + handle: TextureCacheHandle::new(), + }; + cache_entries.insert(entry) + }); + let cache_entry = cache_entries.get_mut(entry_handle); // Check if this texture cache handle is valid. if texture_cache.request(&cache_entry.handle, gpu_cache) { // Invoke user closure to get render task chain // to draw this into the texture cache. let (render_task_id, is_opaque) = try!(f(render_tasks)); let render_task = &mut render_tasks[render_task_id]; @@ -995,26 +1014,28 @@ impl RenderTaskCache { } #[allow(dead_code)] pub fn get_cache_item_for_render_task(&self, texture_cache: &TextureCache, key: &RenderTaskCacheKey) -> CacheItem { // Get the texture cache handle for this cache key. - let cache_entry = self.entries.get(key).unwrap(); + let handle = self.map.get(key).unwrap(); + let cache_entry = self.cache_entries.get(handle); texture_cache.get(&cache_entry.handle) } #[allow(dead_code)] pub fn cache_item_is_allocated_for_render_task(&self, texture_cache: &TextureCache, key: &RenderTaskCacheKey) -> bool { - let cache_entry = self.entries.get(key).unwrap(); + let handle = self.map.get(key).unwrap(); + let cache_entry = self.cache_entries.get(handle); texture_cache.is_allocated(&cache_entry.handle) } } // TODO(gw): Rounding the content rect here to device pixels is not // technically correct. Ideally we should ceil() here, and ensure that // the extra part pixel in the case of fractional sizes is correctly // handled. For now, just use rounding which passes the existing diff --git a/gfx/webrender/src/renderer.rs b/gfx/webrender/src/renderer.rs --- a/gfx/webrender/src/renderer.rs +++ b/gfx/webrender/src/renderer.rs @@ -250,16 +250,17 @@ bitflags! { const PROFILER_DBG = 1 << 0; const RENDER_TARGET_DBG = 1 << 1; const TEXTURE_CACHE_DBG = 1 << 2; const GPU_TIME_QUERIES = 1 << 3; const GPU_SAMPLE_QUERIES= 1 << 4; const DISABLE_BATCHING = 1 << 5; const EPOCHS = 1 << 6; const COMPACT_PROFILER = 1 << 7; + const ECHO_DRIVER_MESSAGES = 1 << 8; } } fn flag_changed(before: DebugFlags, after: DebugFlags, select: DebugFlags) -> Option { if before & select != after & select { Some(after.contains(select)) } else { None @@ -1252,16 +1253,22 @@ impl LazyInitializedDebugRenderer { pub fn deinit(self, device: &mut Device) { if let Some(debug_renderer) = self.debug_renderer { debug_renderer.deinit(device); } } } +pub struct RendererVAOs { + prim_vao: VAO, + blur_vao: VAO, + clip_vao: VAO, +} + /// The renderer is responsible for submitting to the GPU the work prepared by the /// RenderBackend. pub struct Renderer { result_rx: Receiver, debug_server: DebugServer, pub device: Device, pending_texture_updates: Vec, pending_gpu_cache_updates: Vec, @@ -1282,19 +1289,17 @@ pub struct Renderer { debug_flags: DebugFlags, backend_profile_counters: BackendProfileCounters, profile_counters: RendererProfileCounters, #[cfg(feature = "debug_renderer")] profiler: Profiler, last_time: u64, pub gpu_profile: GpuProfiler, - prim_vao: VAO, - blur_vao: VAO, - clip_vao: VAO, + vaos: RendererVAOs, node_data_texture: VertexDataTexture, local_clip_rects_texture: VertexDataTexture, render_task_texture: VertexDataTexture, gpu_cache_texture: CacheTexture, gpu_cache_frame_id: FrameId, gpu_cache_overflow: bool, @@ -1407,17 +1412,17 @@ impl Renderer { device.supports_extension("GL_ARB_blend_func_extended"); let device_max_size = device.max_texture_size(); // 512 is the minimum that the texture cache can work with. // Broken GL contexts can return a max texture size of zero (See #1260). Better to // gracefully fail now than panic as soon as a texture is allocated. let min_texture_size = 512; if device_max_size < min_texture_size { - println!( + error!( "Device reporting insufficient max texture size ({})", device_max_size ); return Err(RendererError::MaxTextureSize); } let max_device_size = cmp::max( cmp::min( device_max_size, @@ -1684,19 +1689,21 @@ impl Renderer { profiler: Profiler::new(), max_texture_size: max_device_size, max_recorded_profiles: options.max_recorded_profiles, clear_color: options.clear_color, enable_clear_scissor: options.enable_clear_scissor, last_time: 0, gpu_profile, gpu_glyph_renderer, - prim_vao, - blur_vao, - clip_vao, + vaos: RendererVAOs { + prim_vao, + blur_vao, + clip_vao, + }, node_data_texture, local_clip_rects_texture, render_task_texture, pipeline_info: PipelineInfo::default(), dither_matrix_texture, external_image_handler: None, output_image_handler: None, output_targets: FastHashMap::default(), @@ -2293,16 +2300,20 @@ impl Renderer { screen_fraction, self.debug.get_mut(&mut self.device), self.debug_flags.contains(DebugFlags::COMPACT_PROFILER), ); } } } + if self.debug_flags.contains(DebugFlags::ECHO_DRIVER_MESSAGES) { + self.device.echo_driver_messages(); + } + self.backend_profile_counters.reset(); self.profile_counters.reset(); self.profile_counters.frame_counter.inc(); profile_timers.cpu_time.profile(|| { let _gm = self.gpu_profile.start_marker("end frame"); self.gpu_profile.end_frame(); #[cfg(feature = "debug_renderer")] @@ -2507,21 +2518,17 @@ impl Renderer { } pub(crate) fn draw_instanced_batch_with_previously_bound_textures( &mut self, data: &[T], vertex_array_kind: VertexArrayKind, stats: &mut RendererStats, ) { - let vao = get_vao(vertex_array_kind, - &self.prim_vao, - &self.clip_vao, - &self.blur_vao, - &self.gpu_glyph_renderer); + let vao = get_vao(vertex_array_kind, &self.vaos, &self.gpu_glyph_renderer); self.device.bind_vao(vao); let batched = !self.debug_flags.contains(DebugFlags::DISABLE_BATCHING); if batched { self.device .update_vao_instances(vao, data, VertexUsageHint::Stream); @@ -3915,19 +3922,19 @@ impl Renderer { if let Some(dither_matrix_texture) = self.dither_matrix_texture { self.device.delete_texture(dither_matrix_texture); } self.node_data_texture.deinit(&mut self.device); self.local_clip_rects_texture.deinit(&mut self.device); self.render_task_texture.deinit(&mut self.device); self.device.delete_pbo(self.texture_cache_upload_pbo); self.texture_resolver.deinit(&mut self.device); - self.device.delete_vao(self.prim_vao); - self.device.delete_vao(self.clip_vao); - self.device.delete_vao(self.blur_vao); + self.device.delete_vao(self.vaos.prim_vao); + self.device.delete_vao(self.vaos.clip_vao); + self.device.delete_vao(self.vaos.blur_vao); #[cfg(feature = "debug_renderer")] { self.debug.deinit(&mut self.device); } for (_, target) in self.output_targets { self.device.delete_fbo(target.fbo_id); @@ -4483,40 +4490,34 @@ impl Renderer { } self.output_image_handler = Some(Box::new(()) as Box<_>); self.external_image_handler = Some(Box::new(image_handler) as Box<_>); info!("done."); } } -// FIXME(pcwalton): We should really gather up all the VAOs into a separate structure so that they -// don't have to be passed in as parameters here. #[cfg(feature = "pathfinder")] fn get_vao<'a>(vertex_array_kind: VertexArrayKind, - prim_vao: &'a VAO, - clip_vao: &'a VAO, - blur_vao: &'a VAO, + vaos: &'a RendererVAOs, gpu_glyph_renderer: &'a GpuGlyphRenderer) -> &'a VAO { match vertex_array_kind { - VertexArrayKind::Primitive => prim_vao, - VertexArrayKind::Clip => clip_vao, - VertexArrayKind::Blur => blur_vao, + VertexArrayKind::Primitive => &vaos.prim_vao, + VertexArrayKind::Clip => &vaos.clip_vao, + VertexArrayKind::Blur => &vaos.blur_vao, VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao, VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao, } } #[cfg(not(feature = "pathfinder"))] fn get_vao<'a>(vertex_array_kind: VertexArrayKind, - prim_vao: &'a VAO, - clip_vao: &'a VAO, - blur_vao: &'a VAO, + vaos: &'a RendererVAOs, _: &'a GpuGlyphRenderer) -> &'a VAO { match vertex_array_kind { - VertexArrayKind::Primitive => prim_vao, - VertexArrayKind::Clip => clip_vao, - VertexArrayKind::Blur => blur_vao, + VertexArrayKind::Primitive => &vaos.prim_vao, + VertexArrayKind::Clip => &vaos.clip_vao, + VertexArrayKind::Blur => &vaos.blur_vao, VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(), } } diff --git a/gfx/webrender/src/resource_cache.rs b/gfx/webrender/src/resource_cache.rs --- a/gfx/webrender/src/resource_cache.rs +++ b/gfx/webrender/src/resource_cache.rs @@ -1,15 +1,15 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{AddFont, BlobImageData, BlobImageResources, ResourceUpdate, ResourceUpdates}; use api::{BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest}; -use api::{ClearCache, ColorF, DevicePoint, DeviceUintRect, DeviceUintSize}; +use api::{ClearCache, ColorF, DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize}; use api::{Epoch, FontInstanceKey, FontKey, FontTemplate}; use api::{ExternalImageData, ExternalImageType}; use api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation}; use api::{GlyphDimensions, GlyphKey, IdNamespace}; use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering}; use api::{TileOffset, TileSize}; use app_units::Au; #[cfg(feature = "capture")] @@ -477,17 +477,18 @@ impl ResourceCache { ); } let resource = ImageResource { descriptor, data, epoch: Epoch(0), tiling, - dirty_rect: None, + dirty_rect: Some(DeviceUintRect::new(DeviceUintPoint::zero(), + DeviceUintSize::new(descriptor.width, descriptor.height))), }; self.resources.image_templates.insert(image_key, resource); } pub fn update_image_template( &mut self, image_key: ImageKey, diff --git a/gfx/webrender/src/scene.rs b/gfx/webrender/src/scene.rs --- a/gfx/webrender/src/scene.rs +++ b/gfx/webrender/src/scene.rs @@ -26,17 +26,21 @@ impl SceneProperties { float_properties: FastHashMap::default(), } } /// Set the current property list for this display list. pub fn set_properties(&mut self, properties: DynamicProperties) { self.transform_properties.clear(); self.float_properties.clear(); + self.add_properties(properties); + } + /// Add to the current property list for this display list. + pub fn add_properties(&mut self, properties: DynamicProperties) { for property in properties.transforms { self.transform_properties .insert(property.key.id, property.value); } for property in properties.floats { self.float_properties .insert(property.key.id, property.value); diff --git a/gfx/webrender/src/shade.rs b/gfx/webrender/src/shade.rs --- a/gfx/webrender/src/shade.rs +++ b/gfx/webrender/src/shade.rs @@ -469,16 +469,25 @@ pub struct Shaders { } impl Shaders { pub fn new( device: &mut Device, gl_type: GlType, options: &RendererOptions, ) -> Result { + // needed for the precache fake draws + let dummy_vao = if options.precache_shaders { + let vao = device.create_custom_vao(&[]); + device.bind_custom_vao(&vao); + Some(vao) + } else { + None + }; + let brush_solid = BrushShader::new( "brush_solid", device, &[], options.precache_shaders, )?; let brush_blend = BrushShader::new( @@ -676,16 +685,20 @@ impl Shaders { let ps_split_composite = LazilyCompiledShader::new( ShaderKind::Primitive, "ps_split_composite", &[], device, options.precache_shaders, )?; + if let Some(vao) = dummy_vao { + device.delete_custom_vao(vao); + } + Ok(Shaders { cs_blur_a8, cs_blur_rgba8, brush_solid, brush_image, brush_blend, brush_mix_blend, brush_yuv_image, diff --git a/gfx/webrender_api/Cargo.toml b/gfx/webrender_api/Cargo.toml --- a/gfx/webrender_api/Cargo.toml +++ b/gfx/webrender_api/Cargo.toml @@ -13,18 +13,18 @@ deserialize = [] [dependencies] app_units = "0.6" bincode = "1.0" bitflags = "1.0" byteorder = "1.2.1" ipc-channel = {version = "0.10.0", optional = true} euclid = { version = "0.17", features = ["serde"] } -serde = { version = "=1.0.35", features = ["rc"] } -serde_derive = { version = "=1.0.35", features = ["deserialize_in_place"] } +serde = { version = "=1.0.37", features = ["rc"] } +serde_derive = { version = "=1.0.37", features = ["deserialize_in_place"] } serde_bytes = "0.10" time = "0.1" [target.'cfg(target_os = "macos")'.dependencies] core-foundation = "0.5" core-graphics = "0.13" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/gfx/webrender_api/src/api.rs b/gfx/webrender_api/src/api.rs --- a/gfx/webrender_api/src/api.rs +++ b/gfx/webrender_api/src/api.rs @@ -319,16 +319,24 @@ impl Transaction { } /// Supply a list of animated property bindings that should be used to resolve /// bindings in the current display list. pub fn update_dynamic_properties(&mut self, properties: DynamicProperties) { self.frame_ops.push(FrameMsg::UpdateDynamicProperties(properties)); } + /// Add to the list of animated property bindings that should be used to + /// resolve bindings in the current display list. This is a convenience method + /// so the caller doesn't have to figure out all the dynamic properties before + /// setting them on the transaction but can do them incrementally. + pub fn append_dynamic_properties(&mut self, properties: DynamicProperties) { + self.frame_ops.push(FrameMsg::AppendDynamicProperties(properties)); + } + /// Enable copying of the output of this pipeline id to /// an external texture for callers to consume. pub fn enable_frame_output(&mut self, pipeline_id: PipelineId, enable: bool) { self.frame_ops.push(FrameMsg::EnableFrameOutput(pipeline_id, enable)); } fn finalize(self) -> (TransactionMsg, Vec) { ( @@ -481,16 +489,17 @@ pub enum FrameMsg { UpdateEpoch(PipelineId, Epoch), HitTest(Option, WorldPoint, HitTestFlags, MsgSender), SetPan(DeviceIntPoint), EnableFrameOutput(PipelineId, bool), Scroll(ScrollLocation, WorldPoint), ScrollNodeWithId(LayoutPoint, ExternalScrollId, ScrollClamping), GetScrollNodeState(MsgSender>), UpdateDynamicProperties(DynamicProperties), + AppendDynamicProperties(DynamicProperties), } impl fmt::Debug for SceneMsg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match *self { SceneMsg::UpdateEpoch(..) => "SceneMsg::UpdateEpoch", SceneMsg::SetDisplayList { .. } => "SceneMsg::SetDisplayList", SceneMsg::SetPageZoom(..) => "SceneMsg::SetPageZoom", @@ -508,16 +517,17 @@ impl fmt::Debug for FrameMsg { FrameMsg::UpdateEpoch(..) => "FrameMsg::UpdateEpoch", FrameMsg::HitTest(..) => "FrameMsg::HitTest", FrameMsg::SetPan(..) => "FrameMsg::SetPan", FrameMsg::Scroll(..) => "FrameMsg::Scroll", FrameMsg::ScrollNodeWithId(..) => "FrameMsg::ScrollNodeWithId", FrameMsg::GetScrollNodeState(..) => "FrameMsg::GetScrollNodeState", FrameMsg::EnableFrameOutput(..) => "FrameMsg::EnableFrameOutput", FrameMsg::UpdateDynamicProperties(..) => "FrameMsg::UpdateDynamicProperties", + FrameMsg::AppendDynamicProperties(..) => "FrameMsg::AppendDynamicProperties", }) } } bitflags!{ /// Bit flags for WR stages to store in a capture. // Note: capturing `FRAME` without `SCENE` is not currently supported. #[derive(Deserialize, Serialize)] diff --git a/gfx/webrender_bindings/Cargo.toml b/gfx/webrender_bindings/Cargo.toml --- a/gfx/webrender_bindings/Cargo.toml +++ b/gfx/webrender_bindings/Cargo.toml @@ -4,17 +4,17 @@ version = "0.1.0" authors = ["The Mozilla Project Developers"] license = "MPL-2.0" [dependencies] rayon = "1" thread_profiler = "0.1.1" euclid = { version = "0.17", features = ["serde"] } app_units = "0.6" -gleam = "0.4.20" +gleam = "0.4.32" log = "0.4" [dependencies.webrender] path = "../webrender" version = "0.57.2" default-features = false features = ["capture"] diff --git a/gfx/webrender_bindings/revision.txt b/gfx/webrender_bindings/revision.txt --- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1,1 +1,1 @@ -092ada1154b72fe71d2f227a5df0239586d2323a +6f997974cec5772b1797725f4a7942d742e7d7ff diff --git a/gfx/wrench/Cargo.toml b/gfx/wrench/Cargo.toml --- a/gfx/wrench/Cargo.toml +++ b/gfx/wrench/Cargo.toml @@ -19,17 +19,17 @@ clap = { version = "2", features = ["yam lazy_static = "1" log = "0.4" yaml-rust = { git = "https://github.com/vvuk/yaml-rust", features = ["preserve_order"] } serde_json = "1.0" ron = "0.1.5" time = "0.1" crossbeam = "0.2" osmesa-sys = { version = "0.1.2", optional = true } -osmesa-src = { git = "https://github.com/servo/osmesa-src", optional = true } +osmesa-src = { git = "https://github.com/jrmuizel/osmesa-src", optional = true, branch = "serialize" } webrender = {path = "../webrender", features=["capture","replay","debugger","png","profiler"]} webrender_api = {path = "../webrender_api", features=["serialize","deserialize"]} serde = {version = "1.0", features = ["derive"] } [target.'cfg(target_os = "macos")'.dependencies] core-graphics = "0.13" core-foundation = "0.5" diff --git a/gfx/wrench/src/wrench.rs b/gfx/wrench/src/wrench.rs --- a/gfx/wrench/src/wrench.rs +++ b/gfx/wrench/src/wrench.rs @@ -192,17 +192,17 @@ impl Wrench { Box, SaveType::Ron => Box::new(RonFrameWriter::new(&PathBuf::from("ron_frames"))) as Box, SaveType::Binary => Box::new(webrender::BinaryRecorder::new( &PathBuf::from("wr-record.bin"), )) as Box, }); - let mut debug_flags = DebugFlags::default(); + let mut debug_flags = DebugFlags::ECHO_DRIVER_MESSAGES; debug_flags.set(DebugFlags::DISABLE_BATCHING, no_batch); let callbacks = Arc::new(Mutex::new(blob::BlobCallbacks::new())); let opts = webrender::RendererOptions { device_pixel_ratio: dp_ratio, resource_override_path: shader_override_path, recorder, enable_subpixel_aa: !no_subpixel_aa,