Bug 1452603 - Update webrender to commit 6f997974cec5772b1797725f4a7942d742e7d7ff. r=jrmuizel

MozReview-Commit-ID: 1Gq3I7Z2Dd2

--HG--
extra : rebase_source : 00049966e37dab234cae5b13e7683a608609f2e5
This commit is contained in:
Kartikaya Gupta 2018-04-12 11:04:46 -04:00
parent aaf89f2684
commit 651d96be0a
23 changed files with 329 additions and 221 deletions

View File

@ -22,7 +22,7 @@ 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"

View File

@ -142,6 +142,7 @@ pub fn main_wrapper<E: Example>(
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())
};

View File

@ -975,23 +975,17 @@ impl AlphaBatchBuilder {
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 => {}
@ -1018,12 +1012,22 @@ impl AlphaBatchBuilder {
}
}
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));
}
}
}
}

View File

@ -103,134 +103,116 @@ pub enum BorderEdgeKind {
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);
}
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 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)
}
// 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)
}
// 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),
// 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_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;
}
fn get_edge(&self, edge: &BorderSide, width: f32) -> (BorderEdgeKind, f32) {
if width == 0.0 {
return (BorderEdgeKind::None, 0.0);
// 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
}
match edge.style {
BorderStyle::None | BorderStyle::Hidden => (BorderEdgeKind::None, 0.0),
// 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)
}
BorderStyle::Solid | BorderStyle::Inset | BorderStyle::Outset => {
(BorderEdgeKind::Solid, width)
// 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)
}
BorderStyle::Double |
BorderStyle::Groove |
BorderStyle::Ridge |
BorderStyle::Dashed |
BorderStyle::Dotted => (BorderEdgeKind::Clip, width),
}
// 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,
),
// 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),
}
}
fn get_edge(edge: &BorderSide, width: f32, height: f32) -> (BorderEdgeKind, f32) {
if width == 0.0 || height <= 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)
}
BorderStyle::Double |
BorderStyle::Groove |
BorderStyle::Ridge |
BorderStyle::Dashed |
BorderStyle::Dotted => (BorderEdgeKind::Clip, width),
}
}
@ -431,7 +413,7 @@ impl<'a> DisplayListFlattener<'a> {
}
let corners = [
border.get_corner(
get_corner(
left,
widths.left,
top,
@ -440,7 +422,7 @@ impl<'a> DisplayListFlattener<'a> {
BorderCorner::TopLeft,
&info.rect,
),
border.get_corner(
get_corner(
right,
widths.right,
top,
@ -449,7 +431,7 @@ impl<'a> DisplayListFlattener<'a> {
BorderCorner::TopRight,
&info.rect,
),
border.get_corner(
get_corner(
right,
widths.right,
bottom,
@ -458,7 +440,7 @@ impl<'a> DisplayListFlattener<'a> {
BorderCorner::BottomRight,
&info.rect,
),
border.get_corner(
get_corner(
left,
widths.left,
bottom,
@ -469,10 +451,14 @@ impl<'a> DisplayListFlattener<'a> {
),
];
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];

View File

@ -63,7 +63,7 @@ impl ws::Handler for Server {
"fetch_clip_scroll_tree" => DebugCommand::FetchClipScrollTree,
"fetch_render_tasks" => DebugCommand::FetchRenderTasks,
msg => {
println!("unknown msg {}", msg);
error!("unknown msg {}", msg);
return Ok(());
}
};
@ -105,9 +105,9 @@ impl DebugServer {
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).");
}
}));

View File

@ -11,6 +11,7 @@ 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;
@ -787,7 +788,7 @@ impl Device {
_ => return,
};
for (line, prefix) in source.lines().skip(base_line_number).zip(&["|",">","|"]) {
println!("{}\t{}", prefix, line);
error!("{}\t{}", prefix, line);
}
}
@ -803,13 +804,13 @@ impl Device {
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)
}
@ -1380,7 +1381,7 @@ impl Device {
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,
@ -1442,7 +1443,7 @@ impl Device {
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
@ -2103,6 +2104,31 @@ impl Device {
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 {

View File

@ -570,7 +570,11 @@ impl<'a> DisplayListFlattener<'a> {
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);

View File

@ -90,6 +90,12 @@ impl<T> FreeList<T> {
}
}
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>) -> &T {
self.slots[id.index as usize].value.as_ref().unwrap()

View File

@ -8,6 +8,8 @@ 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"))]
@ -128,12 +130,12 @@ impl FontTransform {
)
}
#[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 {
@ -145,7 +147,7 @@ impl FontTransform {
}
}
#[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,
@ -155,7 +157,7 @@ impl FontTransform {
)
}
#[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)
}
@ -453,6 +455,7 @@ impl GlyphRasterizer {
#[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);
}
@ -861,10 +864,10 @@ 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)))
}
}
}
@ -1067,3 +1070,6 @@ fn request_render_task_from_pathfinder(glyph_key: &GlyphKey,
Ok((root_task_id, false))
}
#[cfg(feature = "pathfinder")]
pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle);

View File

@ -28,6 +28,8 @@ 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};
@ -729,3 +731,10 @@ impl FontContext {
})
}
}
#[cfg(feature = "pathfinder")]
impl<'a> Into<CGFont> for NativeFontHandleWrapper<'a> {
fn into(self) -> CGFont {
(self.0).0.clone()
}
}

View File

@ -19,7 +19,11 @@ use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING, FT_LOAD_VERTICAL
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;
@ -192,7 +196,7 @@ impl FontContext {
},
);
} else {
println!("WARN: webrender failed to load font");
warn!("WARN: webrender failed to load font");
debug!("font={:?}", font_key);
}
}
@ -219,7 +223,7 @@ impl FontContext {
},
);
} else {
println!("WARN: webrender failed to load font");
warn!("WARN: webrender failed to load font");
debug!("font={:?}, path={:?}", font_key, pathname);
}
}
@ -788,3 +792,11 @@ impl Drop for FontContext {
}
}
}
#[cfg(feature = "pathfinder")]
impl<'a> Into<pf_freetype::FontDescriptor> 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)
}
}

View File

@ -666,6 +666,10 @@ impl RenderBackend {
doc.dynamic_properties.set_properties(property_bindings);
DocumentOps::render()
}
FrameMsg::AppendDynamicProperties(property_bindings) => {
doc.dynamic_properties.add_properties(property_bindings);
DocumentOps::render()
}
}
}

View File

@ -11,6 +11,7 @@ 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};
@ -866,8 +867,8 @@ pub struct RenderTaskCacheKey {
#[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
@ -875,18 +876,21 @@ struct RenderTaskCacheEntry {
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderTaskCache {
entries: FastHashMap<RenderTaskCacheKey, RenderTaskCacheEntry>,
map: FastHashMap<RenderTaskCacheKey, FreeListHandle<RenderTaskCacheEntry>>,
cache_entries: FreeList<RenderTaskCacheEntry>,
}
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(
@ -906,9 +910,19 @@ impl RenderTaskCache {
// 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<F>(
@ -923,11 +937,16 @@ impl RenderTaskCache {
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) {
@ -1000,7 +1019,8 @@ impl RenderTaskCache {
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)
}
@ -1009,7 +1029,8 @@ impl RenderTaskCache {
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)
}
}

View File

@ -255,6 +255,7 @@ bitflags! {
const DISABLE_BATCHING = 1 << 5;
const EPOCHS = 1 << 6;
const COMPACT_PROFILER = 1 << 7;
const ECHO_DRIVER_MESSAGES = 1 << 8;
}
}
@ -1257,6 +1258,12 @@ impl LazyInitializedDebugRenderer {
}
}
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 {
@ -1287,9 +1294,7 @@ pub struct Renderer {
last_time: u64,
pub gpu_profile: GpuProfiler<GpuProfileTag>,
prim_vao: VAO,
blur_vao: VAO,
clip_vao: VAO,
vaos: RendererVAOs,
node_data_texture: VertexDataTexture,
local_clip_rects_texture: VertexDataTexture,
@ -1412,7 +1417,7 @@ impl Renderer {
// 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
);
@ -1689,9 +1694,11 @@ impl Renderer {
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,
@ -2298,6 +2305,10 @@ impl Renderer {
}
}
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();
@ -2512,11 +2523,7 @@ impl Renderer {
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);
@ -3920,9 +3927,9 @@ impl Renderer {
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")]
{
@ -4488,19 +4495,15 @@ impl Renderer {
}
}
// 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,
}
@ -4508,15 +4511,13 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
#[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!(),
}
}

View File

@ -4,7 +4,7 @@
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};
@ -482,7 +482,8 @@ impl ResourceCache {
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);

View File

@ -31,7 +31,11 @@ impl SceneProperties {
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);

View File

@ -474,6 +474,15 @@ impl Shaders {
gl_type: GlType,
options: &RendererOptions,
) -> Result<Self, ShaderError> {
// 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,
@ -681,6 +690,10 @@ impl Shaders {
options.precache_shaders,
)?;
if let Some(vao) = dummy_vao {
device.delete_custom_vao(vao);
}
Ok(Shaders {
cs_blur_a8,
cs_blur_rgba8,

View File

@ -18,8 +18,8 @@ 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"

View File

@ -324,6 +324,14 @@ impl Transaction {
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) {
@ -486,6 +494,7 @@ pub enum FrameMsg {
ScrollNodeWithId(LayoutPoint, ExternalScrollId, ScrollClamping),
GetScrollNodeState(MsgSender<Vec<ScrollNodeState>>),
UpdateDynamicProperties(DynamicProperties),
AppendDynamicProperties(DynamicProperties),
}
impl fmt::Debug for SceneMsg {
@ -513,6 +522,7 @@ impl fmt::Debug for FrameMsg {
FrameMsg::GetScrollNodeState(..) => "FrameMsg::GetScrollNodeState",
FrameMsg::EnableFrameOutput(..) => "FrameMsg::EnableFrameOutput",
FrameMsg::UpdateDynamicProperties(..) => "FrameMsg::UpdateDynamicProperties",
FrameMsg::AppendDynamicProperties(..) => "FrameMsg::AppendDynamicProperties",
})
}
}

View File

@ -9,7 +9,7 @@ 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]

View File

@ -1 +1 @@
092ada1154b72fe71d2f227a5df0239586d2323a
6f997974cec5772b1797725f4a7942d742e7d7ff

View File

@ -24,7 +24,7 @@ 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"] }

View File

@ -197,7 +197,7 @@ impl Wrench {
)) as Box<webrender::ApiRecordingReceiver>,
});
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()));