mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-27 12:50:09 +00:00
Bug 1374730 - Update webrender to cset 519e51986308fc11d6ba6771f1c11ea6a3133921. r=jrmuizel
MozReview-Commit-ID: 81YYW87APLn --HG-- rename : gfx/webrender_traits/src/channel_ipc.rs => gfx/webrender_api/src/channel_ipc.rs rename : gfx/webrender_traits/src/channel_mpsc.rs => gfx/webrender_api/src/channel_mpsc.rs rename : gfx/webrender_traits/src/lib.rs => gfx/webrender_api/src/lib.rs extra : rebase_source : 4f3a7bbda59241979fdafbbfb4a5e30c0375f8e6
This commit is contained in:
parent
95251ef8fc
commit
d56daf3647
@ -79,4 +79,4 @@ to make sure that mozjs_sys also has its Cargo.lock file updated if needed, henc
|
||||
the need to run the cargo update command in js/src as well. Hopefully this will
|
||||
be resolved soon.
|
||||
|
||||
Latest Commit: 1d6348023a4a4fdd89dce038640c5da906005acc
|
||||
Latest Commit: 519e51986308fc11d6ba6771f1c11ea6a3133921
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "webrender"
|
||||
version = "0.43.0"
|
||||
version = "0.47.0"
|
||||
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/servo/webrender"
|
||||
@ -10,24 +10,24 @@ build = "build.rs"
|
||||
default = ["freetype-lib", "webgl"]
|
||||
freetype-lib = ["freetype/servo-freetype-sys"]
|
||||
profiler = ["thread_profiler/thread_profiler"]
|
||||
webgl = ["offscreen_gl_context", "webrender_traits/webgl"]
|
||||
webgl = ["offscreen_gl_context", "webrender_api/webgl"]
|
||||
|
||||
[dependencies]
|
||||
app_units = "0.5"
|
||||
bincode = "0.8"
|
||||
bit-set = "0.4"
|
||||
byteorder = "1.0"
|
||||
euclid = "0.15"
|
||||
euclid = "0.15.1"
|
||||
fnv = "1.0"
|
||||
gleam = "0.4.3"
|
||||
gleam = "0.4.7"
|
||||
lazy_static = "0.2"
|
||||
log = "0.3"
|
||||
num-traits = "0.1.32"
|
||||
offscreen_gl_context = {version = "0.11", features = ["serde", "osmesa"], optional = true}
|
||||
time = "0.1"
|
||||
rayon = "0.8"
|
||||
webrender_traits = {path = "../webrender_traits"}
|
||||
bitflags = "0.7"
|
||||
webrender_api = {path = "../webrender_api"}
|
||||
bitflags = "0.9"
|
||||
gamma-lut = "0.2"
|
||||
thread_profiler = "0.1.1"
|
||||
plane-split = "0.6"
|
||||
@ -45,4 +45,4 @@ dwrote = "0.4"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
core-graphics = "0.8.0"
|
||||
core-text = { version = "5.0.1", features = ["lion"] }
|
||||
core-text = { version = "6.1", default-features = false }
|
||||
|
@ -3,12 +3,11 @@
|
||||
extern crate rand;
|
||||
extern crate test;
|
||||
extern crate webrender;
|
||||
extern crate webrender_traits;
|
||||
|
||||
use rand::Rng;
|
||||
use test::Bencher;
|
||||
use webrender::TexturePage;
|
||||
use webrender_traits::{DeviceUintSize as Size};
|
||||
use webrender::api::{DeviceUintSize as Size};
|
||||
|
||||
#[bench]
|
||||
fn bench_coalesce(b: &mut Bencher) {
|
||||
|
@ -5,7 +5,6 @@
|
||||
extern crate gleam;
|
||||
extern crate glutin;
|
||||
extern crate webrender;
|
||||
extern crate webrender_traits;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
@ -15,7 +14,7 @@ mod boilerplate;
|
||||
|
||||
use boilerplate::HandyDandyRectBuilder;
|
||||
use std::sync::Mutex;
|
||||
use webrender_traits::*;
|
||||
use webrender::api::*;
|
||||
|
||||
// This example creates a 100x100 white rect and allows the user to move it
|
||||
// around by using the arrow keys. It does this by using the animation API.
|
||||
@ -23,25 +22,21 @@ use webrender_traits::*;
|
||||
fn body(_api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_pipeline_id: &PipelineId,
|
||||
_layout_size: &LayoutSize)
|
||||
{
|
||||
_layout_size: &LayoutSize) {
|
||||
// Create a 100x100 stacking context with an animatable transform property.
|
||||
// Note the magic "42" we use as the animation key. That is used to update
|
||||
// the transform in the keyboard event handler code.
|
||||
let bounds = (0,0).to(100, 100);
|
||||
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
|
||||
builder.push_stacking_context(ScrollPolicy::Scrollable,
|
||||
bounds,
|
||||
Some(PropertyBinding::Binding(PropertyBindingKey::new(42))),
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
webrender_traits::MixBlendMode::Normal,
|
||||
MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
|
||||
// Fill it with a white rect
|
||||
let clip = builder.push_clip_region(&bounds, vec![], None);
|
||||
builder.push_rect(bounds,
|
||||
clip,
|
||||
ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
builder.push_rect(bounds, None, ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
|
||||
builder.pop_stacking_context();
|
||||
}
|
||||
|
@ -7,21 +7,22 @@ extern crate euclid;
|
||||
extern crate gleam;
|
||||
extern crate glutin;
|
||||
extern crate webrender;
|
||||
extern crate webrender_traits;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
#[path="common/boilerplate.rs"]
|
||||
mod boilerplate;
|
||||
|
||||
use app_units::Au;
|
||||
use gleam::gl;
|
||||
use boilerplate::HandyDandyRectBuilder;
|
||||
use euclid::vec2;
|
||||
use glutin::TouchPhase;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use webrender_traits::{ClipRegionToken, ColorF, DisplayListBuilder, Epoch, GlyphInstance};
|
||||
use webrender_traits::{DeviceIntPoint, DeviceUintSize, LayoutPoint, LayoutRect, LayoutSize};
|
||||
use webrender_traits::{ImageData, ImageDescriptor, ImageFormat};
|
||||
use webrender_traits::{PipelineId, RenderApi, TransformStyle, BoxShadowClipMode};
|
||||
use euclid::vec2;
|
||||
use std::sync::Mutex;
|
||||
use webrender::api::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Gesture {
|
||||
@ -168,145 +169,62 @@ fn load_file(name: &str) -> Vec<u8> {
|
||||
buffer
|
||||
}
|
||||
|
||||
struct Notifier {
|
||||
window_proxy: glutin::WindowProxy,
|
||||
}
|
||||
|
||||
impl Notifier {
|
||||
fn new(window_proxy: glutin::WindowProxy) -> Notifier {
|
||||
Notifier {
|
||||
window_proxy: window_proxy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl webrender_traits::RenderNotifier for Notifier {
|
||||
fn new_frame_ready(&mut self) {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
self.window_proxy.wakeup_event_loop();
|
||||
}
|
||||
|
||||
fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
self.window_proxy.wakeup_event_loop();
|
||||
}
|
||||
}
|
||||
|
||||
fn push_sub_clip(api: &RenderApi, builder: &mut DisplayListBuilder, bounds: &LayoutRect)
|
||||
-> ClipRegionToken {
|
||||
let mask_image = api.generate_image_key();
|
||||
api.add_image(mask_image,
|
||||
ImageDescriptor::new(2, 2, ImageFormat::A8, true),
|
||||
ImageData::new(vec![0, 80, 180, 255]),
|
||||
None);
|
||||
let mask = webrender_traits::ImageMask {
|
||||
image: mask_image,
|
||||
rect: LayoutRect::new(LayoutPoint::new(75.0, 75.0), LayoutSize::new(100.0, 100.0)),
|
||||
repeat: false,
|
||||
};
|
||||
let complex = webrender_traits::ComplexClipRegion::new(
|
||||
LayoutRect::new(LayoutPoint::new(50.0, 50.0), LayoutSize::new(100.0, 100.0)),
|
||||
webrender_traits::BorderRadius::uniform(20.0));
|
||||
|
||||
builder.push_clip_region(bounds, vec![complex], Some(mask))
|
||||
}
|
||||
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let res_path = if args.len() > 1 {
|
||||
Some(PathBuf::from(&args[1]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
boilerplate::main_wrapper(body, event_handler, None);
|
||||
}
|
||||
|
||||
let window = glutin::WindowBuilder::new()
|
||||
.with_title("WebRender Sample")
|
||||
.with_multitouch()
|
||||
.with_gl(glutin::GlRequest::GlThenGles {
|
||||
opengl_version: (3, 2),
|
||||
opengles_version: (3, 0)
|
||||
})
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
unsafe {
|
||||
window.make_current().ok();
|
||||
}
|
||||
|
||||
let gl = match gl::GlType::default() {
|
||||
gl::GlType::Gl => unsafe { gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
|
||||
gl::GlType::Gles => unsafe { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
|
||||
};
|
||||
|
||||
println!("OpenGL version {}", gl.get_string(gl::VERSION));
|
||||
println!("Shader resource path: {:?}", res_path);
|
||||
|
||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
||||
|
||||
let opts = webrender::RendererOptions {
|
||||
resource_override_path: res_path,
|
||||
debug: true,
|
||||
precache_shaders: true,
|
||||
device_pixel_ratio: window.hidpi_factor(),
|
||||
.. Default::default()
|
||||
};
|
||||
|
||||
let size = DeviceUintSize::new(width, height);
|
||||
let (mut renderer, sender) = webrender::renderer::Renderer::new(gl, opts, size).unwrap();
|
||||
let api = sender.create_api();
|
||||
|
||||
let notifier = Box::new(Notifier::new(window.create_window_proxy()));
|
||||
renderer.set_render_notifier(notifier);
|
||||
|
||||
let epoch = Epoch(0);
|
||||
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
|
||||
|
||||
let pipeline_id = PipelineId(0, 0);
|
||||
let layout_size = LayoutSize::new(width as f32, height as f32);
|
||||
let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id, layout_size);
|
||||
|
||||
let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
|
||||
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
|
||||
fn body(api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_pipeline_id: &PipelineId,
|
||||
layout_size: &LayoutSize) {
|
||||
let bounds = LayoutRect::new(LayoutPoint::zero(), *layout_size);
|
||||
builder.push_stacking_context(ScrollPolicy::Scrollable,
|
||||
bounds,
|
||||
None,
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
webrender_traits::MixBlendMode::Normal,
|
||||
MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
|
||||
let clip = push_sub_clip(&api, &mut builder, &bounds);
|
||||
builder.push_rect(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
|
||||
clip,
|
||||
ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
|
||||
let clip = push_sub_clip(&api, &mut builder, &bounds);
|
||||
builder.push_rect(LayoutRect::new(LayoutPoint::new(250.0, 100.0), LayoutSize::new(100.0, 100.0)),
|
||||
clip,
|
||||
ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
let border_side = webrender_traits::BorderSide {
|
||||
color: ColorF::new(0.0, 0.0, 1.0, 1.0),
|
||||
style: webrender_traits::BorderStyle::Groove,
|
||||
let image_mask_key = api.generate_image_key();
|
||||
api.add_image(image_mask_key,
|
||||
ImageDescriptor::new(2, 2, ImageFormat::A8, true),
|
||||
ImageData::new(vec![0, 80, 180, 255]),
|
||||
None);
|
||||
let mask = ImageMask {
|
||||
image: image_mask_key,
|
||||
rect: (75, 75).by(100, 100),
|
||||
repeat: false,
|
||||
};
|
||||
let border_widths = webrender_traits::BorderWidths {
|
||||
let complex = ComplexClipRegion::new((50, 50).to(150, 150), BorderRadius::uniform(20.0));
|
||||
let id = builder.define_clip(None, bounds, vec![complex], Some(mask));
|
||||
builder.push_clip_id(id);
|
||||
|
||||
let bounds = (100, 100).to(200, 200);
|
||||
builder.push_rect(bounds, None, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
|
||||
let bounds = (250, 100).to(350, 200);
|
||||
builder.push_rect(bounds, None, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
let border_side = BorderSide {
|
||||
color: ColorF::new(0.0, 0.0, 1.0, 1.0),
|
||||
style: BorderStyle::Groove,
|
||||
};
|
||||
let border_widths = BorderWidths {
|
||||
top: 10.0,
|
||||
left: 10.0,
|
||||
bottom: 10.0,
|
||||
right: 10.0,
|
||||
};
|
||||
let border_details = webrender_traits::BorderDetails::Normal(webrender_traits::NormalBorder {
|
||||
let border_details = BorderDetails::Normal(NormalBorder {
|
||||
top: border_side,
|
||||
right: border_side,
|
||||
bottom: border_side,
|
||||
left: border_side,
|
||||
radius: webrender_traits::BorderRadius::uniform(20.0),
|
||||
radius: BorderRadius::uniform(20.0),
|
||||
});
|
||||
|
||||
let clip = push_sub_clip(&api, &mut builder, &bounds);
|
||||
builder.push_border(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
|
||||
clip,
|
||||
border_widths,
|
||||
border_details);
|
||||
let bounds = (100, 100).to(200, 200);
|
||||
builder.push_border(bounds, None, border_widths, border_details);
|
||||
|
||||
|
||||
if false { // draw text?
|
||||
@ -314,8 +232,7 @@ fn main() {
|
||||
let font_bytes = load_file("res/FreeSans.ttf");
|
||||
api.add_raw_font(font_key, font_bytes, 0);
|
||||
|
||||
let text_bounds = LayoutRect::new(LayoutPoint::new(100.0, 200.0), LayoutSize::new(700.0, 300.0));
|
||||
|
||||
let text_bounds = (100, 200).by(700, 300);
|
||||
let glyphs = vec![
|
||||
GlyphInstance {
|
||||
index: 48,
|
||||
@ -367,9 +284,8 @@ fn main() {
|
||||
},
|
||||
];
|
||||
|
||||
let clip = builder.push_clip_region(&bounds, Vec::new(), None);
|
||||
builder.push_text(text_bounds,
|
||||
clip,
|
||||
None,
|
||||
&glyphs,
|
||||
font_key,
|
||||
ColorF::new(1.0, 1.0, 0.0, 1.0),
|
||||
@ -379,19 +295,17 @@ fn main() {
|
||||
}
|
||||
|
||||
if false { // draw box shadow?
|
||||
let rect = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(0.0, 0.0));
|
||||
let simple_box_bounds = LayoutRect::new(LayoutPoint::new(20.0, 200.0),
|
||||
LayoutSize::new(50.0, 50.0));
|
||||
let rect = LayoutRect::zero();
|
||||
let simple_box_bounds = (20, 200).by(50, 50);
|
||||
let offset = vec2(10.0, 10.0);
|
||||
let color = ColorF::new(1.0, 1.0, 1.0, 1.0);
|
||||
let blur_radius = 0.0;
|
||||
let spread_radius = 0.0;
|
||||
let simple_border_radius = 8.0;
|
||||
let box_shadow_type = BoxShadowClipMode::Inset;
|
||||
let full_screen_clip = builder.push_clip_region(&bounds, Vec::new(), None);
|
||||
|
||||
builder.push_box_shadow(rect,
|
||||
full_screen_clip,
|
||||
Some(LocalClip::from(bounds)),
|
||||
simple_box_bounds,
|
||||
offset,
|
||||
color,
|
||||
@ -401,57 +315,29 @@ fn main() {
|
||||
box_shadow_type);
|
||||
}
|
||||
|
||||
builder.pop_clip_id();
|
||||
builder.pop_stacking_context();
|
||||
}
|
||||
|
||||
api.set_display_list(
|
||||
Some(root_background_color),
|
||||
epoch,
|
||||
LayoutSize::new(width as f32, height as f32),
|
||||
builder.finalize(),
|
||||
true);
|
||||
api.set_root_pipeline(pipeline_id);
|
||||
api.generate_frame(None);
|
||||
lazy_static! {
|
||||
static ref TOUCH_STATE: Mutex<TouchState> = Mutex::new(TouchState::new());
|
||||
}
|
||||
|
||||
let mut touch_state = TouchState::new();
|
||||
|
||||
'outer: for event in window.wait_events() {
|
||||
let mut events = Vec::new();
|
||||
events.push(event);
|
||||
|
||||
for event in window.poll_events() {
|
||||
events.push(event);
|
||||
}
|
||||
|
||||
for event in events {
|
||||
match event {
|
||||
glutin::Event::Closed |
|
||||
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
|
||||
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break 'outer,
|
||||
glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
|
||||
_, Some(glutin::VirtualKeyCode::P)) => {
|
||||
let enable_profiler = !renderer.get_profiler_enabled();
|
||||
renderer.set_profiler_enabled(enable_profiler);
|
||||
fn event_handler(event: &glutin::Event, api: &RenderApi) {
|
||||
match *event {
|
||||
glutin::Event::Touch(touch) => {
|
||||
match TOUCH_STATE.lock().unwrap().handle_event(touch) {
|
||||
TouchResult::Pan(pan) => {
|
||||
api.set_pan(pan);
|
||||
api.generate_frame(None);
|
||||
}
|
||||
glutin::Event::Touch(touch) => {
|
||||
match touch_state.handle_event(touch) {
|
||||
TouchResult::Pan(pan) => {
|
||||
api.set_pan(pan);
|
||||
api.generate_frame(None);
|
||||
}
|
||||
TouchResult::Zoom(zoom) => {
|
||||
api.set_pinch_zoom(webrender_traits::ZoomFactor::new(zoom));
|
||||
api.generate_frame(None);
|
||||
}
|
||||
TouchResult::None => {}
|
||||
}
|
||||
TouchResult::Zoom(zoom) => {
|
||||
api.set_pinch_zoom(ZoomFactor::new(zoom));
|
||||
api.generate_frame(None);
|
||||
}
|
||||
_ => ()
|
||||
TouchResult::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
renderer.update();
|
||||
renderer.render(DeviceUintSize::new(width, height));
|
||||
window.swap_buffers().ok();
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ extern crate euclid;
|
||||
extern crate gleam;
|
||||
extern crate glutin;
|
||||
extern crate webrender;
|
||||
extern crate webrender_traits;
|
||||
extern crate rayon;
|
||||
|
||||
#[path="common/boilerplate.rs"]
|
||||
@ -20,26 +19,26 @@ use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||
use webrender_traits as wt;
|
||||
use webrender::api;
|
||||
|
||||
// This example shows how to implement a very basic BlobImageRenderer that can only render
|
||||
// a checkerboard pattern.
|
||||
|
||||
// The deserialized command list internally used by this example is just a color.
|
||||
type ImageRenderingCommands = wt::ColorU;
|
||||
type ImageRenderingCommands = api::ColorU;
|
||||
|
||||
// Serialize/deserialze the blob.
|
||||
// Ror real usecases you should probably use serde rather than doing it by hand.
|
||||
|
||||
fn serialize_blob(color: wt::ColorU) -> Vec<u8> {
|
||||
fn serialize_blob(color: api::ColorU) -> Vec<u8> {
|
||||
vec![color.r, color.g, color.b, color.a]
|
||||
}
|
||||
|
||||
fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> {
|
||||
let mut iter = blob.iter();
|
||||
return match (iter.next(), iter.next(), iter.next(), iter.next()) {
|
||||
(Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(wt::ColorU::new(r, g, b, a)),
|
||||
(Some(&a), None, None, None) => Ok(wt::ColorU::new(a, a, a, a)),
|
||||
(Some(&r), Some(&g), Some(&b), Some(&a)) => Ok(api::ColorU::new(r, g, b, a)),
|
||||
(Some(&a), None, None, None) => Ok(api::ColorU::new(a, a, a, a)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@ -48,9 +47,9 @@ fn deserialize_blob(blob: &[u8]) -> Result<ImageRenderingCommands, ()> {
|
||||
// actual image data.
|
||||
fn render_blob(
|
||||
commands: Arc<ImageRenderingCommands>,
|
||||
descriptor: &wt::BlobImageDescriptor,
|
||||
tile: Option<wt::TileOffset>,
|
||||
) -> wt::BlobImageResult {
|
||||
descriptor: &api::BlobImageDescriptor,
|
||||
tile: Option<api::TileOffset>
|
||||
) -> api::BlobImageResult {
|
||||
let color = *commands;
|
||||
|
||||
// Allocate storage for the result. Right now the resource cache expects the
|
||||
@ -77,17 +76,17 @@ fn render_blob(
|
||||
let tc = if tile_checker { 0 } else { (1 - checker) * 40 };
|
||||
|
||||
match descriptor.format {
|
||||
wt::ImageFormat::BGRA8 => {
|
||||
api::ImageFormat::BGRA8 => {
|
||||
texels.push(color.b * checker + tc);
|
||||
texels.push(color.g * checker + tc);
|
||||
texels.push(color.r * checker + tc);
|
||||
texels.push(color.a * checker + tc);
|
||||
}
|
||||
wt::ImageFormat::A8 => {
|
||||
api::ImageFormat::A8 => {
|
||||
texels.push(color.a * checker + tc);
|
||||
}
|
||||
_ => {
|
||||
return Err(wt::BlobImageError::Other(format!(
|
||||
return Err(api::BlobImageError::Other(format!(
|
||||
"Usupported image format {:?}",
|
||||
descriptor.format
|
||||
)));
|
||||
@ -96,7 +95,7 @@ fn render_blob(
|
||||
}
|
||||
}
|
||||
|
||||
Ok(wt::RasterizedBlobImage {
|
||||
Ok(api::RasterizedBlobImage {
|
||||
data: texels,
|
||||
width: descriptor.width,
|
||||
height: descriptor.height,
|
||||
@ -111,18 +110,18 @@ struct CheckerboardRenderer {
|
||||
workers: Arc<ThreadPool>,
|
||||
|
||||
// the workers will use an mpsc channel to communicate the result.
|
||||
tx: Sender<(wt::BlobImageRequest, wt::BlobImageResult)>,
|
||||
rx: Receiver<(wt::BlobImageRequest, wt::BlobImageResult)>,
|
||||
tx: Sender<(api::BlobImageRequest, api::BlobImageResult)>,
|
||||
rx: Receiver<(api::BlobImageRequest, api::BlobImageResult)>,
|
||||
|
||||
// The deserialized drawing commands.
|
||||
// In this example we store them in Arcs. This isn't necessary since in this simplified
|
||||
// case the command list is a simple 32 bits value and would be cheap to clone before sending
|
||||
// to the workers. But in a more realistic scenario the commands would typically be bigger
|
||||
// and more expensive to clone, so let's pretend it is also the case here.
|
||||
image_cmds: HashMap<wt::ImageKey, Arc<ImageRenderingCommands>>,
|
||||
image_cmds: HashMap<api::ImageKey, Arc<ImageRenderingCommands>>,
|
||||
|
||||
// The images rendered in the current frame (not kept here between frames).
|
||||
rendered_images: HashMap<wt::BlobImageRequest, Option<wt::BlobImageResult>>,
|
||||
rendered_images: HashMap<api::BlobImageRequest, Option<api::BlobImageResult>>,
|
||||
}
|
||||
|
||||
impl CheckerboardRenderer {
|
||||
@ -131,33 +130,33 @@ impl CheckerboardRenderer {
|
||||
CheckerboardRenderer {
|
||||
image_cmds: HashMap::new(),
|
||||
rendered_images: HashMap::new(),
|
||||
workers: workers,
|
||||
tx: tx,
|
||||
rx: rx,
|
||||
workers,
|
||||
tx,
|
||||
rx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl wt::BlobImageRenderer for CheckerboardRenderer {
|
||||
fn add(&mut self, key: wt::ImageKey, cmds: wt::BlobImageData, _: Option<wt::TileSize>) {
|
||||
impl api::BlobImageRenderer for CheckerboardRenderer {
|
||||
fn add(&mut self, key: api::ImageKey, cmds: api::BlobImageData, _: Option<api::TileSize>) {
|
||||
self.image_cmds.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
|
||||
}
|
||||
|
||||
fn update(&mut self, key: wt::ImageKey, cmds: wt::BlobImageData) {
|
||||
fn update(&mut self, key: api::ImageKey, cmds: api::BlobImageData) {
|
||||
// Here, updating is just replacing the current version of the commands with
|
||||
// the new one (no incremental updates).
|
||||
self.image_cmds.insert(key, Arc::new(deserialize_blob(&cmds[..]).unwrap()));
|
||||
}
|
||||
|
||||
fn delete(&mut self, key: wt::ImageKey) {
|
||||
fn delete(&mut self, key: api::ImageKey) {
|
||||
self.image_cmds.remove(&key);
|
||||
}
|
||||
|
||||
fn request(&mut self,
|
||||
resources: &wt::BlobImageResources,
|
||||
request: wt::BlobImageRequest,
|
||||
descriptor: &wt::BlobImageDescriptor,
|
||||
_dirty_rect: Option<wt::DeviceUintRect>) {
|
||||
_resources: &api::BlobImageResources,
|
||||
request: api::BlobImageRequest,
|
||||
descriptor: &api::BlobImageDescriptor,
|
||||
_dirty_rect: Option<api::DeviceUintRect>) {
|
||||
// This method is where we kick off our rendering jobs.
|
||||
// It should avoid doing work on the calling thread as much as possible.
|
||||
// In this example we will use the thread pool to render individual tiles.
|
||||
@ -179,7 +178,7 @@ impl wt::BlobImageRenderer for CheckerboardRenderer {
|
||||
self.rendered_images.insert(request, None);
|
||||
}
|
||||
|
||||
fn resolve(&mut self, request: wt::BlobImageRequest) -> wt::BlobImageResult {
|
||||
fn resolve(&mut self, request: api::BlobImageRequest) -> api::BlobImageResult {
|
||||
// In this method we wait until the work is complete on the worker threads and
|
||||
// gather the results.
|
||||
|
||||
@ -187,7 +186,7 @@ impl wt::BlobImageRenderer for CheckerboardRenderer {
|
||||
// that we are looking for.
|
||||
match self.rendered_images.entry(request) {
|
||||
Entry::Vacant(_) => {
|
||||
return Err(wt::BlobImageError::InvalidKey);
|
||||
return Err(api::BlobImageError::InvalidKey);
|
||||
}
|
||||
Entry::Occupied(entry) => {
|
||||
// None means we haven't yet received the result.
|
||||
@ -208,58 +207,55 @@ impl wt::BlobImageRenderer for CheckerboardRenderer {
|
||||
}
|
||||
|
||||
// If we break out of the loop above it means the channel closed unexpectedly.
|
||||
Err(wt::BlobImageError::Other("Channel closed".into()))
|
||||
Err(api::BlobImageError::Other("Channel closed".into()))
|
||||
}
|
||||
fn delete_font(&mut self, font: wt::FontKey) {}
|
||||
fn delete_font(&mut self, _font: api::FontKey) { }
|
||||
}
|
||||
|
||||
fn body(api: &wt::RenderApi,
|
||||
builder: &mut wt::DisplayListBuilder,
|
||||
_pipeline_id: &wt::PipelineId,
|
||||
layout_size: &wt::LayoutSize)
|
||||
{
|
||||
fn body(api: &api::RenderApi,
|
||||
builder: &mut api::DisplayListBuilder,
|
||||
_pipeline_id: &api::PipelineId,
|
||||
layout_size: &api::LayoutSize) {
|
||||
let blob_img1 = api.generate_image_key();
|
||||
api.add_image(
|
||||
blob_img1,
|
||||
wt::ImageDescriptor::new(500, 500, wt::ImageFormat::BGRA8, true),
|
||||
wt::ImageData::new_blob_image(serialize_blob(wt::ColorU::new(50, 50, 150, 255))),
|
||||
api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true),
|
||||
api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 50, 150, 255))),
|
||||
Some(128),
|
||||
);
|
||||
|
||||
let blob_img2 = api.generate_image_key();
|
||||
api.add_image(
|
||||
blob_img2,
|
||||
wt::ImageDescriptor::new(200, 200, wt::ImageFormat::BGRA8, true),
|
||||
wt::ImageData::new_blob_image(serialize_blob(wt::ColorU::new(50, 150, 50, 255))),
|
||||
api::ImageDescriptor::new(200, 200, api::ImageFormat::BGRA8, true),
|
||||
api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 150, 50, 255))),
|
||||
None,
|
||||
);
|
||||
|
||||
let bounds = wt::LayoutRect::new(wt::LayoutPoint::zero(), *layout_size);
|
||||
builder.push_stacking_context(wt::ScrollPolicy::Scrollable,
|
||||
let bounds = api::LayoutRect::new(api::LayoutPoint::zero(), *layout_size);
|
||||
builder.push_stacking_context(api::ScrollPolicy::Scrollable,
|
||||
bounds,
|
||||
None,
|
||||
wt::TransformStyle::Flat,
|
||||
api::TransformStyle::Flat,
|
||||
None,
|
||||
wt::MixBlendMode::Normal,
|
||||
api::MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
|
||||
let clip = builder.push_clip_region(&bounds, vec![], None);
|
||||
builder.push_image(
|
||||
(30, 30).by(500, 500),
|
||||
clip,
|
||||
wt::LayoutSize::new(500.0, 500.0),
|
||||
wt::LayoutSize::new(0.0, 0.0),
|
||||
wt::ImageRendering::Auto,
|
||||
Some(api::LocalClip::from(bounds)),
|
||||
api::LayoutSize::new(500.0, 500.0),
|
||||
api::LayoutSize::new(0.0, 0.0),
|
||||
api::ImageRendering::Auto,
|
||||
blob_img1,
|
||||
);
|
||||
|
||||
let clip = builder.push_clip_region(&bounds, vec![], None);
|
||||
builder.push_image(
|
||||
(600, 600).by(200, 200),
|
||||
clip,
|
||||
wt::LayoutSize::new(200.0, 200.0),
|
||||
wt::LayoutSize::new(0.0, 0.0),
|
||||
wt::ImageRendering::Auto,
|
||||
Some(api::LocalClip::from(bounds)),
|
||||
api::LayoutSize::new(200.0, 200.0),
|
||||
api::LayoutSize::new(0.0, 0.0),
|
||||
api::ImageRendering::Auto,
|
||||
blob_img2,
|
||||
);
|
||||
|
||||
@ -267,7 +263,7 @@ fn body(api: &wt::RenderApi,
|
||||
}
|
||||
|
||||
fn event_handler(_event: &glutin::Event,
|
||||
_api: &wt::RenderApi)
|
||||
_api: &api::RenderApi)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ use glutin;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use webrender;
|
||||
use webrender_traits::*;
|
||||
use webrender::api::*;
|
||||
|
||||
struct Notifier {
|
||||
window_proxy: glutin::WindowProxy,
|
||||
@ -16,7 +16,7 @@ struct Notifier {
|
||||
impl Notifier {
|
||||
fn new(window_proxy: glutin::WindowProxy) -> Notifier {
|
||||
Notifier {
|
||||
window_proxy: window_proxy,
|
||||
window_proxy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,6 @@
|
||||
extern crate gleam;
|
||||
extern crate glutin;
|
||||
extern crate webrender;
|
||||
extern crate webrender_traits;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
@ -15,63 +14,63 @@ mod boilerplate;
|
||||
|
||||
use boilerplate::HandyDandyRectBuilder;
|
||||
use std::sync::Mutex;
|
||||
use webrender_traits::*;
|
||||
use webrender::api::*;
|
||||
|
||||
fn body(_api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
pipeline_id: &PipelineId,
|
||||
layout_size: &LayoutSize)
|
||||
{
|
||||
layout_size: &LayoutSize) {
|
||||
let bounds = LayoutRect::new(LayoutPoint::zero(), *layout_size);
|
||||
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
|
||||
builder.push_stacking_context(ScrollPolicy::Scrollable,
|
||||
bounds,
|
||||
None,
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
webrender_traits::MixBlendMode::Normal,
|
||||
MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
|
||||
let outer_scroll_frame_rect = (100, 100).to(600, 400);
|
||||
let token = builder.push_clip_region(&outer_scroll_frame_rect, vec![], None);
|
||||
builder.push_rect(outer_scroll_frame_rect,
|
||||
token, ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
let token = builder.push_clip_region(&outer_scroll_frame_rect, vec![], None);
|
||||
let nested_clip_id = builder.define_clip((100, 100).to(1000, 1000), token, None);
|
||||
builder.push_rect(outer_scroll_frame_rect, None, ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
|
||||
let nested_clip_id = builder.define_scroll_frame(None,
|
||||
(100, 100).to(1000, 1000),
|
||||
outer_scroll_frame_rect,
|
||||
vec![],
|
||||
None);
|
||||
builder.push_clip_id(nested_clip_id);
|
||||
|
||||
let mut builder2 = webrender_traits::DisplayListBuilder::new(*pipeline_id, *layout_size);
|
||||
let mut builder3 = webrender_traits::DisplayListBuilder::new(*pipeline_id, *layout_size);
|
||||
let mut builder2 = DisplayListBuilder::new(*pipeline_id, *layout_size);
|
||||
let mut builder3 = DisplayListBuilder::new(*pipeline_id, *layout_size);
|
||||
|
||||
let rect = (110, 110).to(210, 210);
|
||||
let token = builder3.push_clip_region(&rect, vec![], None);
|
||||
builder3.push_rect(rect, token, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
builder3.push_rect(rect, None, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
|
||||
// A fixed position rectangle should be fixed to the reference frame that starts
|
||||
// in the outer display list.
|
||||
builder3.push_stacking_context(webrender_traits::ScrollPolicy::Fixed,
|
||||
builder3.push_stacking_context(ScrollPolicy::Fixed,
|
||||
(220, 110).to(320, 210),
|
||||
None,
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
webrender_traits::MixBlendMode::Normal,
|
||||
MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
let rect = (0, 0).to(100, 100);
|
||||
let token = builder3.push_clip_region(&rect, vec![], None);
|
||||
builder3.push_rect(rect, token, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
builder3.push_rect(rect, None, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
builder3.pop_stacking_context();
|
||||
|
||||
// Now we push an inner scroll frame that should have the same id as the outer one,
|
||||
// but the WebRender nested display list replacement code should convert it into
|
||||
// a unique ClipId.
|
||||
let inner_scroll_frame_rect = (330, 110).to(530, 360);
|
||||
let token = builder3.push_clip_region(&inner_scroll_frame_rect, vec![], None);
|
||||
builder3.push_rect(inner_scroll_frame_rect, token, ColorF::new(1.0, 0.0, 1.0, 0.5));
|
||||
let token = builder3.push_clip_region(&inner_scroll_frame_rect, vec![], None);
|
||||
let inner_nested_clip_id = builder3.define_clip((330, 110).to(2000, 2000), token, None);
|
||||
builder3.push_rect(inner_scroll_frame_rect, None, ColorF::new(1.0, 0.0, 1.0, 0.5));
|
||||
let inner_nested_clip_id = builder3.define_scroll_frame(None,
|
||||
(330, 110).to(2000, 2000),
|
||||
inner_scroll_frame_rect,
|
||||
vec![],
|
||||
None);
|
||||
builder3.push_clip_id(inner_nested_clip_id);
|
||||
let rect = (340, 120).to(440, 220);
|
||||
let token = builder3.push_clip_region(&rect, vec![], None);
|
||||
builder3.push_rect(rect, token, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
builder3.push_rect(rect, None, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
builder3.pop_clip_id();
|
||||
|
||||
let (_, _, built_list) = builder3.finalize();
|
||||
|
@ -5,7 +5,6 @@
|
||||
extern crate gleam;
|
||||
extern crate glutin;
|
||||
extern crate webrender;
|
||||
extern crate webrender_traits;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
@ -15,84 +14,76 @@ mod boilerplate;
|
||||
|
||||
use boilerplate::HandyDandyRectBuilder;
|
||||
use std::sync::Mutex;
|
||||
use webrender_traits::*;
|
||||
use webrender::api::*;
|
||||
|
||||
fn body(_api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
pipeline_id: &PipelineId,
|
||||
layout_size: &LayoutSize)
|
||||
{
|
||||
_pipeline_id: &PipelineId,
|
||||
layout_size: &LayoutSize) {
|
||||
let bounds = LayoutRect::new(LayoutPoint::zero(), *layout_size);
|
||||
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
|
||||
builder.push_stacking_context(ScrollPolicy::Scrollable,
|
||||
bounds,
|
||||
None,
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
webrender_traits::MixBlendMode::Normal,
|
||||
MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
|
||||
if true { // scrolling and clips stuff
|
||||
// let's make a scrollbox
|
||||
let scrollbox = (0, 0).to(300, 400);
|
||||
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
|
||||
builder.push_stacking_context(ScrollPolicy::Scrollable,
|
||||
LayoutRect::new(LayoutPoint::new(10.0, 10.0),
|
||||
LayoutSize::zero()),
|
||||
None,
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
webrender_traits::MixBlendMode::Normal,
|
||||
MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
// set the scrolling clip
|
||||
let clip = builder.push_clip_region(&scrollbox, vec![], None);
|
||||
let clip_id = builder.define_clip((0, 0).to(1000, 1000),
|
||||
clip,
|
||||
Some(ClipId::new(42, *pipeline_id)));
|
||||
let clip_id = builder.define_scroll_frame(None,
|
||||
(0, 0).by(1000, 1000),
|
||||
scrollbox,
|
||||
vec![],
|
||||
None);
|
||||
builder.push_clip_id(clip_id);
|
||||
|
||||
// now put some content into it.
|
||||
// start with a white background
|
||||
let clip = builder.push_clip_region(&(0, 0).to(1000, 1000), vec![], None);
|
||||
builder.push_rect((0, 0).to(500, 500),
|
||||
clip,
|
||||
ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
builder.push_rect((0, 0).to(1000, 1000), None, ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
|
||||
// let's make a 50x50 blue square as a visual reference
|
||||
let clip = builder.push_clip_region(&(0, 0).to(50, 50), vec![], None);
|
||||
builder.push_rect((0, 0).to(50, 50),
|
||||
clip,
|
||||
ColorF::new(0.0, 0.0, 1.0, 1.0));
|
||||
builder.push_rect((0, 0).to(50, 50), None, ColorF::new(0.0, 0.0, 1.0, 1.0));
|
||||
|
||||
// and a 50x50 green square next to it with an offset clip
|
||||
// to see what that looks like
|
||||
let clip = builder.push_clip_region(&(60, 10).to(110, 60), vec![], None);
|
||||
builder.push_rect((50, 0).to(100, 50),
|
||||
clip,
|
||||
Some(LocalClip::from((60, 10).to(110, 60))),
|
||||
ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
|
||||
// Below the above rectangles, set up a nested scrollbox. It's still in
|
||||
// the same stacking context, so note that the rects passed in need to
|
||||
// be relative to the stacking context.
|
||||
let clip = builder.push_clip_region(&(0, 100).to(200, 300), vec![], None);
|
||||
let nested_clip_id = builder.define_clip((0, 100).to(300, 400),
|
||||
clip,
|
||||
Some(ClipId::new(43, *pipeline_id)));
|
||||
let nested_clip_id = builder.define_scroll_frame(None,
|
||||
(0, 100).to(300, 400),
|
||||
(0, 100).to(200, 300),
|
||||
vec![],
|
||||
None);
|
||||
builder.push_clip_id(nested_clip_id);
|
||||
|
||||
// give it a giant gray background just to distinguish it and to easily
|
||||
// visually identify the nested scrollbox
|
||||
let clip = builder.push_clip_region(&(-1000, -1000).to(5000, 5000), vec![], None);
|
||||
builder.push_rect((-1000, -1000).to(5000, 5000),
|
||||
clip,
|
||||
ColorF::new(0.5, 0.5, 0.5, 1.0));
|
||||
builder.push_rect((-1000, -1000).to(5000, 5000), None, ColorF::new(0.5, 0.5, 0.5, 1.0));
|
||||
|
||||
// add a teal square to visualize the scrolling/clipping behaviour
|
||||
// as you scroll the nested scrollbox with WASD keys
|
||||
let clip = builder.push_clip_region(&(0, 100).to(50, 150), vec![], None);
|
||||
builder.push_rect((0, 100).to(50, 150),
|
||||
clip,
|
||||
ColorF::new(0.0, 1.0, 1.0, 1.0));
|
||||
builder.push_rect((0, 100).to(50, 150), None, ColorF::new(0.0, 1.0, 1.0, 1.0));
|
||||
|
||||
// just for good measure add another teal square in the bottom-right
|
||||
// corner of the nested scrollframe content, which can be scrolled into
|
||||
// view by the user
|
||||
let clip = builder.push_clip_region(&(250, 350).to(300, 400), vec![], None);
|
||||
builder.push_rect((250, 350).to(300, 400),
|
||||
clip,
|
||||
ColorF::new(0.0, 1.0, 1.0, 1.0));
|
||||
builder.push_rect((250, 350).to(300, 400), None, ColorF::new(0.0, 1.0, 1.0, 1.0));
|
||||
|
||||
builder.pop_clip_id(); // nested_clip_id
|
||||
|
||||
builder.pop_clip_id(); // clip_id
|
||||
@ -106,9 +97,7 @@ lazy_static! {
|
||||
static ref CURSOR_POSITION: Mutex<WorldPoint> = Mutex::new(WorldPoint::zero());
|
||||
}
|
||||
|
||||
fn event_handler(event: &glutin::Event,
|
||||
api: &RenderApi)
|
||||
{
|
||||
fn event_handler(event: &glutin::Event, api: &RenderApi) {
|
||||
match *event {
|
||||
glutin::Event::KeyboardInput(glutin::ElementState::Pressed, _, Some(key)) => {
|
||||
let offset = match key {
|
||||
|
@ -7,18 +7,17 @@ extern crate euclid;
|
||||
extern crate gleam;
|
||||
extern crate glutin;
|
||||
extern crate webrender;
|
||||
extern crate webrender_traits;
|
||||
|
||||
use gleam::gl;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
#[path="common/boilerplate.rs"]
|
||||
mod boilerplate;
|
||||
|
||||
use glutin::TouchPhase;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use webrender_traits::{ColorF, Epoch};
|
||||
use webrender_traits::{DeviceIntPoint, DeviceUintSize, LayoutPoint, LayoutRect, LayoutSize};
|
||||
use webrender_traits::{ImageData, ImageDescriptor, ImageFormat, ImageRendering};
|
||||
use webrender_traits::{PipelineId, TransformStyle};
|
||||
use webrender_traits::{YuvColorSpace, YuvData};
|
||||
use std::sync::Mutex;
|
||||
use webrender::api::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Gesture {
|
||||
@ -158,92 +157,21 @@ impl TouchState {
|
||||
}
|
||||
}
|
||||
|
||||
struct Notifier {
|
||||
window_proxy: glutin::WindowProxy,
|
||||
}
|
||||
|
||||
impl Notifier {
|
||||
fn new(window_proxy: glutin::WindowProxy) -> Notifier {
|
||||
Notifier {
|
||||
window_proxy: window_proxy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl webrender_traits::RenderNotifier for Notifier {
|
||||
fn new_frame_ready(&mut self) {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
self.window_proxy.wakeup_event_loop();
|
||||
}
|
||||
|
||||
fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
|
||||
#[cfg(not(target_os = "android"))]
|
||||
self.window_proxy.wakeup_event_loop();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let res_path = if args.len() > 1 {
|
||||
Some(PathBuf::from(&args[1]))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
boilerplate::main_wrapper(body, event_handler, None);
|
||||
}
|
||||
|
||||
let window = glutin::WindowBuilder::new()
|
||||
.with_title("WebRender Sample")
|
||||
.with_multitouch()
|
||||
.with_gl(glutin::GlRequest::GlThenGles {
|
||||
opengl_version: (3, 2),
|
||||
opengles_version: (3, 0)
|
||||
})
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
unsafe {
|
||||
window.make_current().ok();
|
||||
}
|
||||
|
||||
let gl = match gl::GlType::default() {
|
||||
gl::GlType::Gl => unsafe { gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
|
||||
gl::GlType::Gles => unsafe { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) },
|
||||
};
|
||||
|
||||
println!("OpenGL version {}", gl.get_string(gl::VERSION));
|
||||
println!("Shader resource path: {:?}", res_path);
|
||||
|
||||
let (width, height) = window.get_inner_size_pixels().unwrap();
|
||||
|
||||
let opts = webrender::RendererOptions {
|
||||
resource_override_path: res_path,
|
||||
debug: true,
|
||||
precache_shaders: true,
|
||||
blob_image_renderer: None,
|
||||
device_pixel_ratio: window.hidpi_factor(),
|
||||
.. Default::default()
|
||||
};
|
||||
|
||||
let size = DeviceUintSize::new(width, height);
|
||||
let (mut renderer, sender) = webrender::renderer::Renderer::new(gl, opts, size).unwrap();
|
||||
let api = sender.create_api();
|
||||
|
||||
let notifier = Box::new(Notifier::new(window.create_window_proxy()));
|
||||
renderer.set_render_notifier(notifier);
|
||||
|
||||
let epoch = Epoch(0);
|
||||
let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);
|
||||
|
||||
let pipeline_id = PipelineId(0, 0);
|
||||
let layout_size = LayoutSize::new(width as f32, height as f32);
|
||||
let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id, layout_size);
|
||||
|
||||
let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size);
|
||||
builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
|
||||
fn body(api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_pipeline_id: &PipelineId,
|
||||
layout_size: &LayoutSize) {
|
||||
let bounds = LayoutRect::new(LayoutPoint::zero(), *layout_size);
|
||||
builder.push_stacking_context(ScrollPolicy::Scrollable,
|
||||
bounds,
|
||||
None,
|
||||
TransformStyle::Flat,
|
||||
None,
|
||||
webrender_traits::MixBlendMode::Normal,
|
||||
MixBlendMode::Normal,
|
||||
Vec::new());
|
||||
|
||||
|
||||
@ -276,76 +204,45 @@ fn main() {
|
||||
None,
|
||||
);
|
||||
|
||||
let clip = builder.push_clip_region(&bounds, vec![], None);
|
||||
builder.push_yuv_image(
|
||||
LayoutRect::new(LayoutPoint::new(100.0, 0.0), LayoutSize::new(100.0, 100.0)),
|
||||
clip,
|
||||
Some(LocalClip::from(bounds)),
|
||||
YuvData::NV12(yuv_chanel1, yuv_chanel2),
|
||||
YuvColorSpace::Rec601,
|
||||
ImageRendering::Auto,
|
||||
);
|
||||
|
||||
let clip = builder.push_clip_region(&bounds, vec![], None);
|
||||
builder.push_yuv_image(
|
||||
LayoutRect::new(LayoutPoint::new(300.0, 0.0), LayoutSize::new(100.0, 100.0)),
|
||||
clip,
|
||||
Some(LocalClip::from(bounds)),
|
||||
YuvData::PlanarYCbCr(yuv_chanel1, yuv_chanel2_1, yuv_chanel3),
|
||||
YuvColorSpace::Rec601,
|
||||
ImageRendering::Auto,
|
||||
);
|
||||
|
||||
builder.pop_stacking_context();
|
||||
|
||||
api.set_display_list(
|
||||
Some(root_background_color),
|
||||
epoch,
|
||||
LayoutSize::new(width as f32, height as f32),
|
||||
builder.finalize(),
|
||||
true);
|
||||
api.set_root_pipeline(pipeline_id);
|
||||
api.generate_frame(None);
|
||||
|
||||
let mut touch_state = TouchState::new();
|
||||
|
||||
'outer: for event in window.wait_events() {
|
||||
let mut events = Vec::new();
|
||||
events.push(event);
|
||||
|
||||
for event in window.poll_events() {
|
||||
events.push(event);
|
||||
}
|
||||
|
||||
for event in events {
|
||||
match event {
|
||||
glutin::Event::Closed |
|
||||
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
|
||||
glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break 'outer,
|
||||
glutin::Event::KeyboardInput(glutin::ElementState::Pressed,
|
||||
_, Some(glutin::VirtualKeyCode::P)) => {
|
||||
let enable_profiler = !renderer.get_profiler_enabled();
|
||||
renderer.set_profiler_enabled(enable_profiler);
|
||||
api.generate_frame(None);
|
||||
}
|
||||
glutin::Event::Touch(touch) => {
|
||||
match touch_state.handle_event(touch) {
|
||||
TouchResult::Pan(pan) => {
|
||||
api.set_pan(pan);
|
||||
api.generate_frame(None);
|
||||
}
|
||||
TouchResult::Zoom(zoom) => {
|
||||
api.set_pinch_zoom(webrender_traits::ZoomFactor::new(zoom));
|
||||
api.generate_frame(None);
|
||||
}
|
||||
TouchResult::None => {}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
renderer.update();
|
||||
renderer.render(DeviceUintSize::new(width, height));
|
||||
window.swap_buffers().ok();
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref TOUCH_STATE: Mutex<TouchState> = Mutex::new(TouchState::new());
|
||||
}
|
||||
|
||||
|
||||
fn event_handler(event: &glutin::Event, api: &RenderApi) {
|
||||
match *event {
|
||||
glutin::Event::Touch(touch) => {
|
||||
match TOUCH_STATE.lock().unwrap().handle_event(touch) {
|
||||
TouchResult::Pan(pan) => {
|
||||
api.set_pan(pan);
|
||||
api.generate_frame(None);
|
||||
}
|
||||
TouchResult::Zoom(zoom) => {
|
||||
api.set_pinch_zoom(ZoomFactor::new(zoom));
|
||||
api.generate_frame(None);
|
||||
}
|
||||
TouchResult::None => {}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ struct BorderCorner {
|
||||
};
|
||||
|
||||
BorderCorner fetch_border_corner(int index) {
|
||||
vec4 data[2] = fetch_data_2(index);
|
||||
vec4 data[2] = fetch_from_resource_cache_2(index);
|
||||
return BorderCorner(RectWithSize(data[0].xy, data[0].zw),
|
||||
data[1].xy,
|
||||
int(data[1].z),
|
||||
@ -36,7 +36,7 @@ struct BorderClipDash {
|
||||
};
|
||||
|
||||
BorderClipDash fetch_border_clip_dash(int index) {
|
||||
vec4 data[2] = fetch_data_2(index);
|
||||
vec4 data[2] = fetch_from_resource_cache_2(index);
|
||||
return BorderClipDash(data[0], data[1]);
|
||||
}
|
||||
|
||||
@ -46,8 +46,8 @@ struct BorderClipDot {
|
||||
};
|
||||
|
||||
BorderClipDot fetch_border_clip_dot(int index) {
|
||||
vec4 data[2] = fetch_data_2(index);
|
||||
return BorderClipDot(data[0].xyz);
|
||||
vec4 data = fetch_from_resource_cache_1(index);
|
||||
return BorderClipDot(data.xyz);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
@ -85,7 +85,7 @@ void main(void) {
|
||||
switch (corner.clip_mode) {
|
||||
case CLIP_MODE_DASH: {
|
||||
// Fetch the information about this particular dash.
|
||||
BorderClipDash dash = fetch_border_clip_dash(cci.data_index + cci.segment_index);
|
||||
BorderClipDash dash = fetch_border_clip_dash(cci.data_index + 2 + 2 * (cci.segment_index - 1));
|
||||
vPoint_Tangent0 = dash.point_tangent_0 * sign_modifier.xyxy;
|
||||
vPoint_Tangent1 = dash.point_tangent_1 * sign_modifier.xyxy;
|
||||
vDotParams = vec3(0.0);
|
||||
@ -93,7 +93,7 @@ void main(void) {
|
||||
break;
|
||||
}
|
||||
case CLIP_MODE_DOT: {
|
||||
BorderClipDot cdot = fetch_border_clip_dot(cci.data_index + cci.segment_index);
|
||||
BorderClipDot cdot = fetch_border_clip_dot(cci.data_index + 2 + (cci.segment_index - 1));
|
||||
vPoint_Tangent0 = vec4(1.0);
|
||||
vPoint_Tangent1 = vec4(1.0);
|
||||
vDotParams = vec3(cdot.center_radius.xy * sign_modifier, cdot.center_radius.z);
|
||||
|
@ -8,8 +8,8 @@ struct ImageMaskData {
|
||||
};
|
||||
|
||||
ImageMaskData fetch_mask_data(int index) {
|
||||
vec4 data[2] = fetch_data_2(index);
|
||||
return ImageMaskData(RectWithSize(data[0].xy, data[0].zw));
|
||||
vec4 data = fetch_from_resource_cache_1(index);
|
||||
return ImageMaskData(RectWithSize(data.xy, data.zw));
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
|
@ -9,7 +9,7 @@ struct ClipRect {
|
||||
};
|
||||
|
||||
ClipRect fetch_clip_rect(int index) {
|
||||
vec4 data[2] = fetch_data_2(index);
|
||||
vec4 data[2] = fetch_from_resource_cache_2(index);
|
||||
return ClipRect(RectWithSize(data[0].xy, data[0].zw), data[1]);
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ struct ClipCorner {
|
||||
};
|
||||
|
||||
ClipCorner fetch_clip_corner(int index) {
|
||||
vec4 data[2] = fetch_data_2(index);
|
||||
vec4 data[2] = fetch_from_resource_cache_2(index);
|
||||
return ClipCorner(RectWithSize(data[0].xy, data[0].zw), data[1]);
|
||||
}
|
||||
|
||||
@ -35,10 +35,10 @@ ClipData fetch_clip(int index) {
|
||||
ClipData clip;
|
||||
|
||||
clip.rect = fetch_clip_rect(index + 0);
|
||||
clip.top_left = fetch_clip_corner(index + 1);
|
||||
clip.top_right = fetch_clip_corner(index + 2);
|
||||
clip.bottom_left = fetch_clip_corner(index + 3);
|
||||
clip.bottom_right = fetch_clip_corner(index + 4);
|
||||
clip.top_left = fetch_clip_corner(index + 2);
|
||||
clip.top_right = fetch_clip_corner(index + 4);
|
||||
clip.bottom_left = fetch_clip_corner(index + 6);
|
||||
clip.bottom_right = fetch_clip_corner(index + 8);
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
@ -31,8 +31,9 @@ void main(void) {
|
||||
vec2 pos = mix(local_rect.xy,
|
||||
local_rect.xy + local_rect.zw,
|
||||
aPosition.xy);
|
||||
vUv = mix(st0, st1, aPosition.xy);
|
||||
vColor = text.color;
|
||||
|
||||
vUv = mix(st0, st1, aPosition.xy);
|
||||
vColor = text.color;
|
||||
|
||||
gl_Position = uTransform * vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@
|
||||
#define BORDER_RIGHT 2
|
||||
#define BORDER_BOTTOM 3
|
||||
|
||||
// Border styles as defined in webrender_traits/types.rs
|
||||
// Border styles as defined in webrender_api/types.rs
|
||||
#define BORDER_STYLE_NONE 0
|
||||
#define BORDER_STYLE_SOLID 1
|
||||
#define BORDER_STYLE_DOUBLE 2
|
||||
@ -140,8 +140,6 @@ vec4[2] fetch_from_resource_cache_2(int address) {
|
||||
uniform HIGHP_SAMPLER_FLOAT sampler2D sLayers;
|
||||
uniform HIGHP_SAMPLER_FLOAT sampler2D sRenderTasks;
|
||||
|
||||
uniform HIGHP_SAMPLER_FLOAT sampler2D sData32;
|
||||
|
||||
// Instanced attributes
|
||||
in ivec4 aData0;
|
||||
in ivec4 aData1;
|
||||
@ -152,13 +150,6 @@ in ivec4 aData1;
|
||||
// https://github.com/servo/servo/issues/13953
|
||||
#define get_fetch_uv(i, vpi) ivec2(vpi * (i % (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi)), i / (WR_MAX_VERTEX_TEXTURE_WIDTH/vpi))
|
||||
|
||||
vec4[2] fetch_data_2(int index) {
|
||||
ivec2 uv = get_fetch_uv(index, 2);
|
||||
return vec4[2](
|
||||
texelFetchOffset(sData32, uv, 0, ivec2(0, 0)),
|
||||
texelFetchOffset(sData32, uv, 0, ivec2(1, 0))
|
||||
);
|
||||
}
|
||||
|
||||
vec4[8] fetch_from_resource_cache_8(int address) {
|
||||
ivec2 uv = get_resource_cache_uv(address);
|
||||
|
@ -2,14 +2,15 @@
|
||||
* 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::{BorderSide, BorderStyle, BorderWidths, ClipAndScrollInfo, ColorF, LayerPoint, LayerRect};
|
||||
use api::{LayerSize, LocalClip, NormalBorder};
|
||||
use ellipse::Ellipse;
|
||||
use gpu_cache::GpuDataRequest;
|
||||
use frame_builder::FrameBuilder;
|
||||
use mask_cache::{ClipSource};
|
||||
use prim_store::{BorderPrimitiveCpu, GpuBlock32, PrimitiveContainer};
|
||||
use mask_cache::ClipSource;
|
||||
use prim_store::{BorderPrimitiveCpu, PrimitiveContainer};
|
||||
use tiling::PrimitiveFlags;
|
||||
use util::{lerp, pack_as_float};
|
||||
use webrender_traits::{BorderSide, BorderStyle, BorderWidths, ClipAndScrollInfo, ClipRegion};
|
||||
use webrender_traits::{ColorF, LayerPoint, LayerRect, LayerSize, NormalBorder};
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@ -79,7 +80,7 @@ impl BorderCornerKind {
|
||||
};
|
||||
let clip_data = BorderCornerClipData {
|
||||
corner_rect: LayerRect::new(origin, size),
|
||||
clip_center: clip_center,
|
||||
clip_center,
|
||||
corner: pack_as_float(corner as u32),
|
||||
kind: pack_as_float(kind as u32),
|
||||
};
|
||||
@ -225,7 +226,7 @@ impl FrameBuilder {
|
||||
border: &NormalBorder,
|
||||
widths: &BorderWidths,
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
clip_region: &ClipRegion,
|
||||
local_clip: &LocalClip,
|
||||
corner_instances: [BorderCornerInstance; 4],
|
||||
extra_clips: &[ClipSource]) {
|
||||
let radius = &border.radius;
|
||||
@ -241,7 +242,7 @@ impl FrameBuilder {
|
||||
let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3);
|
||||
|
||||
let prim_cpu = BorderPrimitiveCpu {
|
||||
corner_instances: corner_instances,
|
||||
corner_instances,
|
||||
|
||||
// TODO(gw): In the future, we will build these on demand
|
||||
// from the deserialized display list, rather
|
||||
@ -272,7 +273,7 @@ impl FrameBuilder {
|
||||
|
||||
self.add_primitive(clip_and_scroll,
|
||||
&rect,
|
||||
clip_region,
|
||||
local_clip,
|
||||
extra_clips,
|
||||
PrimitiveContainer::Border(prim_cpu));
|
||||
}
|
||||
@ -286,7 +287,7 @@ impl FrameBuilder {
|
||||
border: &NormalBorder,
|
||||
widths: &BorderWidths,
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
clip_region: &ClipRegion) {
|
||||
local_clip: &LocalClip) {
|
||||
// The border shader is quite expensive. For simple borders, we can just draw
|
||||
// the border with a few rectangles. This generally gives better batching, and
|
||||
// a GPU win in fragment shader time.
|
||||
@ -366,7 +367,7 @@ impl FrameBuilder {
|
||||
if top_edge == BorderEdgeKind::Solid {
|
||||
self.add_solid_rectangle(clip_and_scroll,
|
||||
&LayerRect::new(p0, LayerSize::new(rect_width, top_len)),
|
||||
clip_region,
|
||||
local_clip,
|
||||
&border.top.color,
|
||||
PrimitiveFlags::None);
|
||||
}
|
||||
@ -375,7 +376,7 @@ impl FrameBuilder {
|
||||
&LayerRect::new(LayerPoint::new(p0.x, p0.y + top_len),
|
||||
LayerSize::new(left_len,
|
||||
rect_height - top_len - bottom_len)),
|
||||
clip_region,
|
||||
local_clip,
|
||||
&border.left.color,
|
||||
PrimitiveFlags::None);
|
||||
}
|
||||
@ -385,7 +386,7 @@ impl FrameBuilder {
|
||||
p0.y + top_len),
|
||||
LayerSize::new(right_len,
|
||||
rect_height - top_len - bottom_len)),
|
||||
clip_region,
|
||||
local_clip,
|
||||
&border.right.color,
|
||||
PrimitiveFlags::None);
|
||||
}
|
||||
@ -393,7 +394,7 @@ impl FrameBuilder {
|
||||
self.add_solid_rectangle(clip_and_scroll,
|
||||
&LayerRect::new(LayerPoint::new(p0.x, p1.y - bottom_len),
|
||||
LayerSize::new(rect_width, bottom_len)),
|
||||
clip_region,
|
||||
local_clip,
|
||||
&border.bottom.color,
|
||||
PrimitiveFlags::None);
|
||||
}
|
||||
@ -422,7 +423,7 @@ impl FrameBuilder {
|
||||
border,
|
||||
widths,
|
||||
clip_and_scroll,
|
||||
clip_region,
|
||||
local_clip,
|
||||
corner_instances,
|
||||
&extra_clips);
|
||||
}
|
||||
@ -535,18 +536,17 @@ impl BorderCornerClipSource {
|
||||
};
|
||||
|
||||
BorderCornerClipSource {
|
||||
kind: kind,
|
||||
corner_data: corner_data,
|
||||
max_clip_count: max_clip_count,
|
||||
kind,
|
||||
corner_data,
|
||||
max_clip_count,
|
||||
actual_clip_count: 0,
|
||||
ellipse: ellipse,
|
||||
widths: widths,
|
||||
ellipse,
|
||||
widths,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn populate_gpu_data(&mut self, slice: &mut [GpuBlock32]) {
|
||||
let (header, clips) = slice.split_first_mut().unwrap();
|
||||
*header = self.corner_data.into();
|
||||
pub fn write(&mut self, mut request: GpuDataRequest) {
|
||||
self.corner_data.write(&mut request);
|
||||
|
||||
match self.kind {
|
||||
BorderCornerClipKind::Dash => {
|
||||
@ -554,7 +554,7 @@ impl BorderCornerClipSource {
|
||||
self.actual_clip_count = self.max_clip_count;
|
||||
let dash_arc_length = 0.5 * self.ellipse.total_arc_length / (self.actual_clip_count - 1) as f32;
|
||||
let mut current_arc_length = -0.5 * dash_arc_length;
|
||||
for dash_index in 0..self.actual_clip_count {
|
||||
for _ in 0..self.actual_clip_count {
|
||||
let arc_length0 = current_arc_length;
|
||||
current_arc_length += dash_arc_length;
|
||||
|
||||
@ -564,9 +564,10 @@ impl BorderCornerClipSource {
|
||||
let dash_data = BorderCornerDashClipData::new(arc_length0,
|
||||
arc_length1,
|
||||
&self.ellipse);
|
||||
|
||||
clips[dash_index] = dash_data.into();
|
||||
dash_data.write(&mut request);
|
||||
}
|
||||
|
||||
assert_eq!(request.close(), 2 + 2 * self.actual_clip_count);
|
||||
}
|
||||
BorderCornerClipKind::Dot => {
|
||||
let mut forward_dots = Vec::new();
|
||||
@ -623,17 +624,15 @@ impl BorderCornerClipSource {
|
||||
// leftover space on the arc between them evenly. Once
|
||||
// the final arc position is determined, generate the correct
|
||||
// arc positions and angles that get passed to the clip shader.
|
||||
self.actual_clip_count = 0;
|
||||
let dot_count = forward_dots.len() + back_dots.len();
|
||||
let extra_space_per_dot = leftover_arc_length / (dot_count - 1) as f32;
|
||||
self.actual_clip_count = forward_dots.len() + back_dots.len();
|
||||
let extra_space_per_dot = leftover_arc_length / (self.actual_clip_count - 1) as f32;
|
||||
|
||||
for (i, dot) in forward_dots.iter().enumerate() {
|
||||
let extra_dist = i as f32 * extra_space_per_dot;
|
||||
let dot = BorderCornerDotClipData::new(dot.arc_pos + extra_dist,
|
||||
0.5 * dot.diameter,
|
||||
&self.ellipse);
|
||||
clips[self.actual_clip_count] = dot.into();
|
||||
self.actual_clip_count += 1;
|
||||
dot.write(&mut request);
|
||||
}
|
||||
|
||||
for (i, dot) in back_dots.iter().enumerate() {
|
||||
@ -641,9 +640,10 @@ impl BorderCornerClipSource {
|
||||
let dot = BorderCornerDotClipData::new(dot.arc_pos - extra_dist,
|
||||
0.5 * dot.diameter,
|
||||
&self.ellipse);
|
||||
clips[self.actual_clip_count] = dot.into();
|
||||
self.actual_clip_count += 1;
|
||||
dot.write(&mut request);
|
||||
}
|
||||
|
||||
assert_eq!(request.close(), 2 + self.actual_clip_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -666,6 +666,13 @@ pub struct BorderCornerClipData {
|
||||
kind: f32, // Of type BorderCornerClipKind enum
|
||||
}
|
||||
|
||||
impl BorderCornerClipData {
|
||||
fn write(&self, request: &mut GpuDataRequest) {
|
||||
request.push(self.corner_rect);
|
||||
request.push([self.clip_center.x, self.clip_center.y, self.corner, self.kind]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the GPU data for drawing a single dash
|
||||
/// to a clip mask. A dash clip is defined by two lines.
|
||||
/// We store a point on the ellipse curve, and a tangent
|
||||
@ -697,6 +704,13 @@ impl BorderCornerDashClipData {
|
||||
tangent1: t1,
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, request: &mut GpuDataRequest) {
|
||||
request.push([self.point0.x, self.point0.y,
|
||||
self.tangent0.x, self.tangent0.y]);
|
||||
request.push([self.point1.x, self.point1.y,
|
||||
self.tangent1.x, self.tangent1.y]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents the GPU data for drawing a single dot
|
||||
@ -706,7 +720,6 @@ impl BorderCornerDashClipData {
|
||||
pub struct BorderCornerDotClipData {
|
||||
pub center: LayerPoint,
|
||||
pub radius: f32,
|
||||
pub padding: [f32; 5],
|
||||
}
|
||||
|
||||
impl BorderCornerDotClipData {
|
||||
@ -717,11 +730,14 @@ impl BorderCornerDotClipData {
|
||||
let (center, _) = ellipse.get_point_and_tangent(theta);
|
||||
|
||||
BorderCornerDotClipData {
|
||||
center: center,
|
||||
radius: radius,
|
||||
padding: [0.0; 5],
|
||||
center,
|
||||
radius,
|
||||
}
|
||||
}
|
||||
|
||||
fn write(&self, request: &mut GpuDataRequest) {
|
||||
request.push([self.center.x, self.center.y, self.radius, 0.0]);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -733,8 +749,8 @@ struct DotInfo {
|
||||
impl DotInfo {
|
||||
fn new(arc_pos: f32, diameter: f32) -> DotInfo {
|
||||
DotInfo {
|
||||
arc_pos: arc_pos,
|
||||
diameter: diameter,
|
||||
arc_pos,
|
||||
diameter,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,14 @@
|
||||
* 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::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize};
|
||||
use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, PipelineId};
|
||||
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, WorldPoint};
|
||||
use geometry::ray_intersects_rect;
|
||||
use mask_cache::{ClipSource, MaskCacheInfo, RegionMode};
|
||||
use prim_store::GpuBlock32;
|
||||
use renderer::VertexDataStore;
|
||||
use mask_cache::{ClipRegion, ClipSource, MaskCacheInfo};
|
||||
use spring::{DAMPING, STIFFNESS, Spring};
|
||||
use tiling::PackedLayerIndex;
|
||||
use util::TransformedRectKind;
|
||||
use webrender_traits::{ClipId, ClipRegion, DeviceIntRect, LayerPixel, LayerPoint, LayerRect};
|
||||
use webrender_traits::{LayerSize, LayerToScrollTransform, LayerToWorldTransform, PipelineId};
|
||||
use webrender_traits::{ScrollClamping, ScrollEventPhase, ScrollLayerRect, ScrollLocation};
|
||||
use webrender_traits::{WorldPoint, LayerVector2D};
|
||||
use webrender_traits::{as_scroll_parent_vector};
|
||||
use util::{MatrixHelpers, TransformedRectKind};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
const CAN_OVERSCROLL: bool = true;
|
||||
@ -28,7 +24,7 @@ pub struct ClipInfo {
|
||||
|
||||
/// The MaskCacheInfo for this node, which is produced by processing the
|
||||
/// provided ClipSource.
|
||||
pub mask_cache_info: Option<MaskCacheInfo>,
|
||||
pub mask_cache_info: MaskCacheInfo,
|
||||
|
||||
/// The packed layer index for this node, which is used to render a clip mask
|
||||
/// for it, if necessary.
|
||||
@ -38,32 +34,31 @@ pub struct ClipInfo {
|
||||
/// which depends on the screen rectangle and the transformation of all of
|
||||
/// the parents.
|
||||
pub screen_bounding_rect: Option<(TransformedRectKind, DeviceIntRect)>,
|
||||
|
||||
/// The biggest final transformed rectangle that is completely inside the
|
||||
/// clipping region for this node.
|
||||
pub screen_inner_rect: DeviceIntRect,
|
||||
|
||||
/// A rectangle which defines the rough boundaries of this clip in reference
|
||||
/// frame relative coordinates (with no scroll offsets).
|
||||
pub clip_rect: LayerRect,
|
||||
}
|
||||
|
||||
impl ClipInfo {
|
||||
pub fn new(clip_region: &ClipRegion,
|
||||
clip_store: &mut VertexDataStore<GpuBlock32>,
|
||||
packed_layer_index: PackedLayerIndex,)
|
||||
-> ClipInfo {
|
||||
// We pass true here for the MaskCacheInfo because this type of
|
||||
// mask needs an extra clip for the clip rectangle.
|
||||
let clip_sources = vec![ClipSource::Region(clip_region.clone(), RegionMode::IncludeRect)];
|
||||
pub fn new(clip_region: ClipRegion, packed_layer_index: PackedLayerIndex) -> ClipInfo {
|
||||
let clip_rect = LayerRect::new(clip_region.origin, clip_region.main.size);
|
||||
let clip_sources = vec![ClipSource::Region(clip_region)];
|
||||
ClipInfo {
|
||||
mask_cache_info: MaskCacheInfo::new(&clip_sources, clip_store),
|
||||
clip_sources: clip_sources,
|
||||
packed_layer_index: packed_layer_index,
|
||||
mask_cache_info: MaskCacheInfo::new(&clip_sources),
|
||||
clip_sources,
|
||||
packed_layer_index,
|
||||
screen_bounding_rect: None,
|
||||
screen_inner_rect: DeviceIntRect::zero(),
|
||||
clip_rect: clip_rect,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_masking(&self) -> bool {
|
||||
match self.mask_cache_info {
|
||||
Some(ref info) => info.is_masking(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum NodeType {
|
||||
/// Transform for this layer, relative to parent reference frame. A reference
|
||||
@ -91,7 +86,10 @@ pub struct ClipScrollNode {
|
||||
pub local_clip_rect: LayerRect,
|
||||
|
||||
/// Viewport rectangle clipped against parent layer(s) viewport rectangles.
|
||||
/// This is in the coordinate system which starts at our origin.
|
||||
/// This is in the coordinate system of the node origin.
|
||||
/// Precisely, it combines the local clipping rectangles of all the parent
|
||||
/// nodes on the way to the root, including those of `ClipRegion` rectangles.
|
||||
/// The combined clip is lossy/concervative on `ReferenceFrame` nodes.
|
||||
pub combined_local_viewport_rect: LayerRect,
|
||||
|
||||
/// World transform for the viewport rect itself. This is the parent
|
||||
@ -123,11 +121,11 @@ pub struct ClipScrollNode {
|
||||
impl ClipScrollNode {
|
||||
pub fn new_scroll_frame(pipeline_id: PipelineId,
|
||||
parent_id: ClipId,
|
||||
content_rect: &LayerRect,
|
||||
frame_rect: &LayerRect)
|
||||
frame_rect: &LayerRect,
|
||||
content_size: &LayerSize)
|
||||
-> ClipScrollNode {
|
||||
ClipScrollNode {
|
||||
content_size: content_rect.size,
|
||||
content_size: *content_size,
|
||||
local_viewport_rect: *frame_rect,
|
||||
local_clip_rect: *frame_rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
@ -136,31 +134,23 @@ impl ClipScrollNode {
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: Some(parent_id),
|
||||
children: Vec::new(),
|
||||
pipeline_id: pipeline_id,
|
||||
pipeline_id,
|
||||
node_type: NodeType::ScrollFrame(ScrollingState::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(pipeline_id: PipelineId,
|
||||
parent_id: ClipId,
|
||||
content_rect: &LayerRect,
|
||||
clip_rect: &LayerRect,
|
||||
clip_info: ClipInfo)
|
||||
-> ClipScrollNode {
|
||||
// FIXME(mrobinson): We don't yet handle clipping rectangles that don't start at the origin
|
||||
// of the node.
|
||||
let local_viewport_rect = LayerRect::new(content_rect.origin, clip_rect.size);
|
||||
pub fn new(pipeline_id: PipelineId, parent_id: ClipId, clip_info: ClipInfo) -> ClipScrollNode {
|
||||
ClipScrollNode {
|
||||
content_size: content_rect.size,
|
||||
local_viewport_rect: local_viewport_rect,
|
||||
local_clip_rect: local_viewport_rect,
|
||||
content_size: clip_info.clip_rect.size,
|
||||
local_viewport_rect: clip_info.clip_rect,
|
||||
local_clip_rect: clip_info.clip_rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
world_viewport_transform: LayerToWorldTransform::identity(),
|
||||
world_content_transform: LayerToWorldTransform::identity(),
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: Some(parent_id),
|
||||
children: Vec::new(),
|
||||
pipeline_id: pipeline_id,
|
||||
pipeline_id,
|
||||
node_type: NodeType::Clip(clip_info),
|
||||
}
|
||||
}
|
||||
@ -172,7 +162,7 @@ impl ClipScrollNode {
|
||||
pipeline_id: PipelineId)
|
||||
-> ClipScrollNode {
|
||||
ClipScrollNode {
|
||||
content_size: content_size,
|
||||
content_size,
|
||||
local_viewport_rect: *local_viewport_rect,
|
||||
local_clip_rect: *local_viewport_rect,
|
||||
combined_local_viewport_rect: LayerRect::zero(),
|
||||
@ -181,7 +171,7 @@ impl ClipScrollNode {
|
||||
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
|
||||
parent: parent_id,
|
||||
children: Vec::new(),
|
||||
pipeline_id: pipeline_id,
|
||||
pipeline_id,
|
||||
node_type: NodeType::ReferenceFrame(*local_transform),
|
||||
}
|
||||
}
|
||||
@ -192,7 +182,11 @@ impl ClipScrollNode {
|
||||
|
||||
pub fn finalize(&mut self, new_scrolling: &ScrollingState) {
|
||||
match self.node_type {
|
||||
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => (),
|
||||
NodeType::ReferenceFrame(_) | NodeType::Clip(_) => {
|
||||
if new_scrolling.offset != LayerVector2D::zero() {
|
||||
warn!("Tried to scroll a non-scroll node.");
|
||||
}
|
||||
}
|
||||
NodeType::ScrollFrame(ref mut scrolling) => *scrolling = *new_scrolling,
|
||||
}
|
||||
}
|
||||
@ -234,53 +228,30 @@ impl ClipScrollNode {
|
||||
|
||||
pub fn update_transform(&mut self,
|
||||
parent_reference_frame_transform: &LayerToWorldTransform,
|
||||
parent_combined_viewport_rect: &ScrollLayerRect,
|
||||
parent_combined_viewport_rect: &LayerRect,
|
||||
parent_scroll_offset: LayerVector2D,
|
||||
parent_accumulated_scroll_offset: LayerVector2D) {
|
||||
self.reference_frame_relative_scroll_offset = match self.node_type {
|
||||
NodeType::ReferenceFrame(_) => LayerVector2D::zero(),
|
||||
NodeType::Clip(_) | NodeType::ScrollFrame(..) => parent_accumulated_scroll_offset,
|
||||
};
|
||||
|
||||
let local_transform = match self.node_type {
|
||||
NodeType::ReferenceFrame(transform) => transform,
|
||||
NodeType::Clip(_) | NodeType::ScrollFrame(..) => LayerToScrollTransform::identity(),
|
||||
};
|
||||
let scrolled_parent_combined_clip = parent_combined_viewport_rect
|
||||
.translate(&-parent_scroll_offset);
|
||||
|
||||
let inv_transform = match local_transform.inverse() {
|
||||
Some(transform) => transform,
|
||||
None => {
|
||||
// If a transform function causes the current transformation matrix of an object
|
||||
// to be non-invertible, the object and its content do not get displayed.
|
||||
self.combined_local_viewport_rect = LayerRect::zero();
|
||||
return;
|
||||
let (local_transform, combined_clip, reference_frame_scroll_offset) = match self.node_type {
|
||||
NodeType::ReferenceFrame(transform) => {
|
||||
let combined_clip = transform.with_destination::<LayerPixel>()
|
||||
.inverse_rect_footprint(&scrolled_parent_combined_clip);
|
||||
(transform, combined_clip, LayerVector2D::zero())
|
||||
}
|
||||
NodeType::Clip(_) | NodeType::ScrollFrame(_) => {
|
||||
// Move the parent's viewport into the local space (of the node origin)
|
||||
// and intersect with the local clip rectangle to get the local viewport.
|
||||
let combined_clip = scrolled_parent_combined_clip.intersection(&self.local_clip_rect)
|
||||
.unwrap_or(LayerRect::zero());
|
||||
(LayerToScrollTransform::identity(), combined_clip, parent_accumulated_scroll_offset)
|
||||
}
|
||||
};
|
||||
|
||||
// We are trying to move the combined viewport rectangle of our parent nodes into the
|
||||
// coordinate system of this node, so we must invert our transformation (only for
|
||||
// reference frames) and then apply the scroll offset the parent layer. The combined
|
||||
// local viewport rect doesn't include scrolling offsets so the only one that matters
|
||||
// is the relative offset between us and the parent.
|
||||
let parent_combined_viewport_in_local_space =
|
||||
inv_transform.pre_translate(-as_scroll_parent_vector(&parent_scroll_offset).to_3d())
|
||||
.transform_rect(parent_combined_viewport_rect);
|
||||
|
||||
// Now that we have the combined viewport rectangle of the parent nodes in local space,
|
||||
// we do the intersection and get our combined viewport rect in the coordinate system
|
||||
// starting from our origin.
|
||||
self.combined_local_viewport_rect = match self.node_type {
|
||||
NodeType::Clip(_) | NodeType::ScrollFrame(..) => {
|
||||
parent_combined_viewport_in_local_space.intersection(&self.local_clip_rect)
|
||||
.unwrap_or(LayerRect::zero())
|
||||
}
|
||||
NodeType::ReferenceFrame(_) => parent_combined_viewport_in_local_space,
|
||||
};
|
||||
|
||||
// HACK: prevent the code above for non-AA transforms, it's incorrect.
|
||||
if (local_transform.m13, local_transform.m23) != (0.0, 0.0) {
|
||||
self.combined_local_viewport_rect = self.local_clip_rect;
|
||||
}
|
||||
self.combined_local_viewport_rect = combined_clip;
|
||||
self.reference_frame_relative_scroll_offset = reference_frame_scroll_offset;
|
||||
|
||||
// The transformation for this viewport in world coordinates is the transformation for
|
||||
// our parent reference frame, plus any accumulated scrolling offsets from nodes
|
||||
|
@ -7,10 +7,9 @@ use fnv::FnvHasher;
|
||||
use print_tree::PrintTree;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::hash::BuildHasherDefault;
|
||||
use webrender_traits::{ClipId, LayerPoint, LayerRect, LayerToScrollTransform};
|
||||
use webrender_traits::{LayerToWorldTransform, PipelineId, ScrollClamping, ScrollEventPhase};
|
||||
use webrender_traits::{ScrollLayerRect, ScrollLayerState, ScrollLocation, WorldPoint};
|
||||
use webrender_traits::{as_scroll_parent_rect, LayerVector2D};
|
||||
use api::{ClipId, LayerPoint, LayerRect, LayerToScrollTransform};
|
||||
use api::{LayerToWorldTransform, PipelineId, ScrollClamping, ScrollEventPhase};
|
||||
use api::{LayerVector2D, ScrollLayerState, ScrollLocation, WorldPoint};
|
||||
|
||||
pub type ScrollStates = HashMap<ClipId, ScrollingState, BuildHasherDefault<FnvHasher>>;
|
||||
|
||||
@ -231,7 +230,7 @@ impl ClipScrollTree {
|
||||
let root_viewport = self.nodes[&root_reference_frame_id].local_clip_rect;
|
||||
self.update_node_transform(root_reference_frame_id,
|
||||
&LayerToWorldTransform::create_translation(pan.x, pan.y, 0.0),
|
||||
&as_scroll_parent_rect(&root_viewport),
|
||||
&root_viewport,
|
||||
LayerVector2D::zero(),
|
||||
LayerVector2D::zero());
|
||||
}
|
||||
@ -239,54 +238,56 @@ impl ClipScrollTree {
|
||||
fn update_node_transform(&mut self,
|
||||
layer_id: ClipId,
|
||||
parent_reference_frame_transform: &LayerToWorldTransform,
|
||||
parent_viewport_rect: &ScrollLayerRect,
|
||||
parent_viewport_rect: &LayerRect,
|
||||
parent_scroll_offset: LayerVector2D,
|
||||
parent_accumulated_scroll_offset: LayerVector2D) {
|
||||
// TODO(gw): This is an ugly borrow check workaround to clone these.
|
||||
// Restructure this to avoid the clones!
|
||||
let (reference_frame_transform,
|
||||
viewport_rect,
|
||||
combined_local_viewport_rect,
|
||||
scroll_offset,
|
||||
accumulated_scroll_offset,
|
||||
node_children) = {
|
||||
match self.nodes.get_mut(&layer_id) {
|
||||
Some(node) => {
|
||||
node.update_transform(parent_reference_frame_transform,
|
||||
parent_viewport_rect,
|
||||
parent_scroll_offset,
|
||||
parent_accumulated_scroll_offset);
|
||||
|
||||
// The transformation we are passing is the transformation of the parent
|
||||
// reference frame and the offset is the accumulated offset of all the nodes
|
||||
// between us and the parent reference frame. If we are a reference frame,
|
||||
// we need to reset both these values.
|
||||
let (transform, offset, accumulated_scroll_offset) = match node.node_type {
|
||||
NodeType::ReferenceFrame(..) =>
|
||||
(node.world_viewport_transform,
|
||||
LayerVector2D::zero(),
|
||||
LayerVector2D::zero()),
|
||||
_ => {
|
||||
let scroll_offset = node.scroll_offset();
|
||||
(*parent_reference_frame_transform,
|
||||
scroll_offset,
|
||||
scroll_offset + parent_accumulated_scroll_offset)
|
||||
}
|
||||
};
|
||||
|
||||
(transform,
|
||||
as_scroll_parent_rect(&node.combined_local_viewport_rect),
|
||||
offset,
|
||||
accumulated_scroll_offset,
|
||||
node.children.clone())
|
||||
}
|
||||
let mut node = match self.nodes.get_mut(&layer_id) {
|
||||
Some(node) => node,
|
||||
None => return,
|
||||
}
|
||||
};
|
||||
node.update_transform(parent_reference_frame_transform,
|
||||
parent_viewport_rect,
|
||||
parent_scroll_offset,
|
||||
parent_accumulated_scroll_offset);
|
||||
|
||||
// The transformation we are passing is the transformation of the parent
|
||||
// reference frame and the offset is the accumulated offset of all the nodes
|
||||
// between us and the parent reference frame. If we are a reference frame,
|
||||
// we need to reset both these values.
|
||||
let (reference_frame_transform, scroll_offset, accumulated_scroll_offset) = match node.node_type {
|
||||
NodeType::ReferenceFrame(..) =>
|
||||
(node.world_viewport_transform,
|
||||
LayerVector2D::zero(),
|
||||
LayerVector2D::zero()),
|
||||
NodeType::Clip(..) =>
|
||||
(*parent_reference_frame_transform,
|
||||
LayerVector2D::zero(),
|
||||
parent_accumulated_scroll_offset),
|
||||
NodeType::ScrollFrame(ref scrolling) =>
|
||||
(*parent_reference_frame_transform,
|
||||
scrolling.offset,
|
||||
scrolling.offset + parent_accumulated_scroll_offset),
|
||||
};
|
||||
|
||||
(reference_frame_transform,
|
||||
node.combined_local_viewport_rect,
|
||||
scroll_offset,
|
||||
accumulated_scroll_offset,
|
||||
node.children.clone())
|
||||
};
|
||||
|
||||
for child_layer_id in node_children {
|
||||
self.update_node_transform(child_layer_id,
|
||||
&reference_frame_transform,
|
||||
&viewport_rect,
|
||||
&combined_local_viewport_rect,
|
||||
scroll_offset,
|
||||
accumulated_scroll_offset);
|
||||
}
|
||||
@ -313,7 +314,6 @@ impl ClipScrollTree {
|
||||
node.set_scroll_origin(&pending_offset, clamping);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn generate_new_clip_id(&mut self, pipeline_id: PipelineId) -> ClipId {
|
||||
@ -365,6 +365,7 @@ impl ClipScrollTree {
|
||||
NodeType::Clip(ref info) => {
|
||||
pt.new_level("Clip".to_owned());
|
||||
pt.add_item(format!("screen_bounding_rect: {:?}", info.screen_bounding_rect));
|
||||
pt.add_item(format!("screen_inner_rect: {:?}", info.screen_inner_rect));
|
||||
|
||||
pt.new_level(format!("Clip Sources [{}]", info.clip_sources.len()));
|
||||
for source in &info.clip_sources {
|
||||
@ -382,9 +383,9 @@ impl ClipScrollTree {
|
||||
}
|
||||
|
||||
pt.add_item(format!("content_size: {:?}", node.content_size));
|
||||
pt.add_item(format!("combined_local_viewport_rect: {:?}", node.combined_local_viewport_rect));
|
||||
pt.add_item(format!("local_viewport_rect: {:?}", node.local_viewport_rect));
|
||||
pt.add_item(format!("local_clip_rect: {:?}", node.local_clip_rect));
|
||||
pt.add_item(format!("combined_local_viewport_rect: {:?}", node.combined_local_viewport_rect));
|
||||
pt.add_item(format!("world_viewport_transform: {:?}", node.world_viewport_transform));
|
||||
pt.add_item(format!("world_content_transform: {:?}", node.world_content_transform));
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use webrender_traits::ColorF;
|
||||
use api::ColorF;
|
||||
|
||||
// A subset of the standard CSS colors, useful for defining GPU tag colors etc.
|
||||
|
||||
|
@ -9,7 +9,7 @@ use euclid::{Transform3D, Point2D, Size2D, Rect};
|
||||
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, TextureSampler};
|
||||
use internal_types::{DebugFontVertex, DebugColorVertex, RenderTargetMode, PackedColor};
|
||||
use std::f32;
|
||||
use webrender_traits::{ColorF, ImageFormat, DeviceUintSize};
|
||||
use api::{ColorF, ImageFormat, DeviceUintSize};
|
||||
|
||||
pub struct DebugRenderer {
|
||||
font_vertices: Vec<DebugFontVertex>,
|
||||
@ -48,14 +48,14 @@ impl DebugRenderer {
|
||||
font_vertices: Vec::new(),
|
||||
font_indices: Vec::new(),
|
||||
line_vertices: Vec::new(),
|
||||
tri_vao: tri_vao,
|
||||
tri_vao,
|
||||
tri_vertices: Vec::new(),
|
||||
tri_indices: Vec::new(),
|
||||
font_program_id: font_program_id,
|
||||
color_program_id: color_program_id,
|
||||
font_vao: font_vao,
|
||||
line_vao: line_vao,
|
||||
font_texture_id: font_texture_id,
|
||||
font_program_id,
|
||||
color_program_id,
|
||||
font_vao,
|
||||
line_vao,
|
||||
font_texture_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,11 +18,12 @@ use std::iter::repeat;
|
||||
use std::mem;
|
||||
use std::ops::Add;
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
//use std::sync::mpsc::{channel, Sender};
|
||||
//use std::thread;
|
||||
use webrender_traits::{ColorF, ImageFormat};
|
||||
use webrender_traits::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize};
|
||||
use api::{ColorF, ImageFormat};
|
||||
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Ord, Eq, PartialOrd)]
|
||||
pub struct FrameId(usize);
|
||||
@ -51,11 +52,11 @@ const GL_FORMAT_BGRA_GL: gl::GLuint = gl::BGRA;
|
||||
|
||||
const GL_FORMAT_BGRA_GLES: gl::GLuint = gl::BGRA_EXT;
|
||||
|
||||
const SHADER_VERSION_GL: &'static str = "#version 150\n";
|
||||
const SHADER_VERSION_GL: &str = "#version 150\n";
|
||||
|
||||
const SHADER_VERSION_GLES: &'static str = "#version 300 es\n";
|
||||
const SHADER_VERSION_GLES: &str = "#version 300 es\n";
|
||||
|
||||
static SHADER_PREAMBLE: &'static str = "shared";
|
||||
static SHADER_PREAMBLE: &str = "shared";
|
||||
|
||||
#[repr(u32)]
|
||||
pub enum DepthFunction {
|
||||
@ -298,7 +299,7 @@ impl TextureId {
|
||||
|
||||
pub fn new(name: gl::GLuint, texture_target: TextureTarget) -> TextureId {
|
||||
TextureId {
|
||||
name: name,
|
||||
name,
|
||||
target: texture_target.to_gl_target(),
|
||||
}
|
||||
}
|
||||
@ -488,6 +489,9 @@ struct IBOId(gl::GLuint);
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
|
||||
pub struct UBOId(gl::GLuint);
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
|
||||
pub struct PBOId(gl::GLuint);
|
||||
|
||||
const MAX_EVENTS_PER_FRAME: usize = 256;
|
||||
const MAX_PROFILE_FRAMES: usize = 4;
|
||||
|
||||
@ -517,8 +521,8 @@ impl<T> GpuFrameProfile<T> {
|
||||
gl::GlType::Gl => {
|
||||
let queries = gl.gen_queries(MAX_EVENTS_PER_FRAME as gl::GLint);
|
||||
GpuFrameProfile {
|
||||
gl: gl,
|
||||
queries: queries,
|
||||
gl,
|
||||
queries,
|
||||
samples: Vec::new(),
|
||||
next_query: 0,
|
||||
pending_query: 0,
|
||||
@ -528,7 +532,7 @@ impl<T> GpuFrameProfile<T> {
|
||||
}
|
||||
gl::GlType::Gles => {
|
||||
GpuFrameProfile {
|
||||
gl: gl,
|
||||
gl,
|
||||
queries: Vec::new(),
|
||||
samples: Vec::new(),
|
||||
next_query: 0,
|
||||
@ -585,7 +589,7 @@ impl<T> GpuFrameProfile<T> {
|
||||
self.pending_query = self.queries[self.next_query];
|
||||
self.gl.begin_query(gl::TIME_ELAPSED, self.pending_query);
|
||||
self.samples.push(GpuSample {
|
||||
tag: tag,
|
||||
tag,
|
||||
time_ns: 0,
|
||||
});
|
||||
} else {
|
||||
@ -600,7 +604,7 @@ impl<T> GpuFrameProfile<T> {
|
||||
where T: NamedTag {
|
||||
let marker = GpuMarker::new(&self.gl, tag.get_label());
|
||||
self.samples.push(GpuSample {
|
||||
tag: tag,
|
||||
tag,
|
||||
time_ns: 0,
|
||||
});
|
||||
marker
|
||||
@ -815,7 +819,7 @@ impl FileWatcherThread {
|
||||
});
|
||||
|
||||
FileWatcherThread {
|
||||
api_tx: api_tx,
|
||||
api_tx,
|
||||
}
|
||||
}
|
||||
|
||||
@ -846,6 +850,7 @@ pub struct Device {
|
||||
bound_textures: [TextureId; 16],
|
||||
bound_program: ProgramId,
|
||||
bound_vao: VAOId,
|
||||
bound_pbo: PBOId,
|
||||
bound_read_fbo: FBOId,
|
||||
bound_draw_fbo: FBOId,
|
||||
default_read_fbo: gl::GLuint,
|
||||
@ -892,21 +897,22 @@ impl Device {
|
||||
let max_texture_size = gl.get_integer_v(gl::MAX_TEXTURE_SIZE) as u32;
|
||||
|
||||
Device {
|
||||
gl: gl,
|
||||
resource_override_path: resource_override_path,
|
||||
gl,
|
||||
resource_override_path,
|
||||
// This is initialized to 1 by default, but it is set
|
||||
// every frame by the call to begin_frame().
|
||||
device_pixel_ratio: 1.0,
|
||||
inside_frame: false,
|
||||
|
||||
capabilities: Capabilities {
|
||||
max_ubo_size: max_ubo_size,
|
||||
max_ubo_size,
|
||||
supports_multisampling: false, //TODO
|
||||
},
|
||||
|
||||
bound_textures: [ TextureId::invalid(); 16 ],
|
||||
bound_program: ProgramId(0),
|
||||
bound_vao: VAOId(0),
|
||||
bound_pbo: PBOId(0),
|
||||
bound_read_fbo: FBOId(0),
|
||||
bound_draw_fbo: FBOId(0),
|
||||
default_read_fbo: 0,
|
||||
@ -916,12 +922,12 @@ impl Device {
|
||||
programs: HashMap::default(),
|
||||
vaos: HashMap::default(),
|
||||
|
||||
shader_preamble: shader_preamble,
|
||||
shader_preamble,
|
||||
|
||||
next_vao_id: 1,
|
||||
//file_watcher: file_watcher,
|
||||
|
||||
max_texture_size: max_texture_size,
|
||||
max_texture_size,
|
||||
frame_id: FrameId(0),
|
||||
}
|
||||
}
|
||||
@ -1006,6 +1012,8 @@ impl Device {
|
||||
|
||||
// Pixel op state
|
||||
self.gl.pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
|
||||
self.bound_pbo = PBOId(0);
|
||||
self.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, 0);
|
||||
|
||||
// Default is sampler 0, always
|
||||
self.gl.active_texture(gl::TEXTURE0);
|
||||
@ -1089,7 +1097,7 @@ impl Device {
|
||||
|
||||
let texture = Texture {
|
||||
gl: Rc::clone(&self.gl),
|
||||
id: id,
|
||||
id,
|
||||
width: 0,
|
||||
height: 0,
|
||||
format: ImageFormat::Invalid,
|
||||
@ -1438,7 +1446,7 @@ impl Device {
|
||||
u_device_pixel_ratio: -1,
|
||||
vs_source: get_shader_source(&vs_name, &self.resource_override_path),
|
||||
fs_source: get_shader_source(&fs_name, &self.resource_override_path),
|
||||
prefix: prefix,
|
||||
prefix,
|
||||
vs_id: None,
|
||||
fs_id: None,
|
||||
};
|
||||
@ -1556,11 +1564,6 @@ impl Device {
|
||||
self.gl.uniform_1i(u_tasks, TextureSampler::RenderTasks as i32);
|
||||
}
|
||||
|
||||
let u_data32 = self.gl.get_uniform_location(program.id, "sData32");
|
||||
if u_data32 != -1 {
|
||||
self.gl.uniform_1i(u_data32, TextureSampler::Data32 as i32);
|
||||
}
|
||||
|
||||
let u_resource_cache = self.gl.get_uniform_location(program.id, "sResourceCache");
|
||||
if u_resource_cache != -1 {
|
||||
self.gl.uniform_1i(u_resource_cache, TextureSampler::ResourceCache as i32);
|
||||
@ -1628,6 +1631,69 @@ impl Device {
|
||||
self.gl.uniform_1f(program.u_device_pixel_ratio, device_pixel_ratio);
|
||||
}
|
||||
|
||||
pub fn create_pbo(&mut self) -> PBOId {
|
||||
let id = self.gl.gen_buffers(1)[0];
|
||||
PBOId(id)
|
||||
}
|
||||
|
||||
pub fn destroy_pbo(&mut self, id: PBOId) {
|
||||
self.gl.delete_buffers(&[id.0]);
|
||||
}
|
||||
|
||||
pub fn bind_pbo(&mut self, pbo_id: Option<PBOId>) {
|
||||
debug_assert!(self.inside_frame);
|
||||
let pbo_id = pbo_id.unwrap_or(PBOId(0));
|
||||
|
||||
if self.bound_pbo != pbo_id {
|
||||
self.bound_pbo = pbo_id;
|
||||
|
||||
self.gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, pbo_id.0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_pbo_data<T>(&mut self, data: &[T]) {
|
||||
debug_assert!(self.inside_frame);
|
||||
debug_assert!(self.bound_pbo.0 != 0);
|
||||
|
||||
gl::buffer_data(&*self.gl,
|
||||
gl::PIXEL_UNPACK_BUFFER,
|
||||
data,
|
||||
gl::STREAM_DRAW);
|
||||
}
|
||||
|
||||
pub fn orphan_pbo(&mut self, new_size: usize) {
|
||||
debug_assert!(self.inside_frame);
|
||||
debug_assert!(self.bound_pbo.0 != 0);
|
||||
|
||||
self.gl.buffer_data_untyped(gl::PIXEL_UNPACK_BUFFER,
|
||||
new_size as isize,
|
||||
ptr::null(),
|
||||
gl::STREAM_DRAW);
|
||||
}
|
||||
|
||||
pub fn update_texture_from_pbo(&mut self,
|
||||
texture_id: TextureId,
|
||||
x0: u32,
|
||||
y0: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
offset: usize) {
|
||||
debug_assert!(self.inside_frame);
|
||||
debug_assert_eq!(self.textures.get(&texture_id).unwrap().format, ImageFormat::RGBAF32);
|
||||
|
||||
self.bind_texture(DEFAULT_TEXTURE, texture_id);
|
||||
|
||||
self.gl.tex_sub_image_2d_pbo(texture_id.target,
|
||||
0,
|
||||
x0 as gl::GLint,
|
||||
y0 as gl::GLint,
|
||||
width as gl::GLint,
|
||||
height as gl::GLint,
|
||||
gl::RGBA,
|
||||
gl::FLOAT,
|
||||
offset);
|
||||
}
|
||||
|
||||
pub fn update_texture(&mut self,
|
||||
texture_id: TextureId,
|
||||
x0: u32,
|
||||
@ -1728,13 +1794,13 @@ impl Device {
|
||||
let vao = VAO {
|
||||
gl: Rc::clone(&self.gl),
|
||||
id: vao_id,
|
||||
ibo_id: ibo_id,
|
||||
main_vbo_id: main_vbo_id,
|
||||
instance_vbo_id: instance_vbo_id,
|
||||
instance_stride: instance_stride,
|
||||
owns_indices: owns_indices,
|
||||
owns_vertices: owns_vertices,
|
||||
owns_instances: owns_instances,
|
||||
ibo_id,
|
||||
main_vbo_id,
|
||||
instance_vbo_id,
|
||||
instance_stride,
|
||||
owns_indices,
|
||||
owns_vertices,
|
||||
owns_instances,
|
||||
};
|
||||
|
||||
self.gl.bind_vertex_array(0);
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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 webrender_traits::{LayerPoint, LayerSize};
|
||||
use api::{LayerPoint, LayerSize};
|
||||
use std::f32::consts::FRAC_PI_2;
|
||||
|
||||
/// Number of steps to integrate arc length over.
|
||||
@ -23,8 +23,8 @@ impl Ellipse {
|
||||
radius.height);
|
||||
|
||||
Ellipse {
|
||||
radius: radius,
|
||||
total_arc_length: total_arc_length,
|
||||
radius,
|
||||
total_arc_length,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,14 @@
|
||||
* 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::{BuiltDisplayList, BuiltDisplayListIter, ClipAndScrollInfo, ClipId, ColorF};
|
||||
use api::{ComplexClipRegion, DeviceUintRect, DeviceUintSize, DisplayItemRef, Epoch, FilterOp};
|
||||
use api::{ImageDisplayItem, ItemRange, LayerPoint, LayerRect, LayerSize, LayerToScrollTransform};
|
||||
use api::{LayerVector2D, LayoutSize, LayoutTransform, LocalClip, MixBlendMode, PipelineId};
|
||||
use api::{ScrollClamping, ScrollEventPhase, ScrollLayerState, ScrollLocation, ScrollPolicy};
|
||||
use api::{SpecificDisplayItem, StackingContext, TileOffset, TransformStyle, WorldPoint};
|
||||
use app_units::Au;
|
||||
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
|
||||
use euclid::rect;
|
||||
use fnv::FnvHasher;
|
||||
use gpu_cache::GpuCache;
|
||||
@ -10,7 +17,7 @@ use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection};
|
||||
use internal_types::{LowLevelFilterOp};
|
||||
use internal_types::{RendererFrame};
|
||||
use frame_builder::{FrameBuilder, FrameBuilderConfig};
|
||||
use clip_scroll_tree::{ClipScrollTree, ScrollStates};
|
||||
use mask_cache::ClipRegion;
|
||||
use profiler::{GpuCacheProfileCounters, TextureCacheProfileCounters};
|
||||
use resource_cache::ResourceCache;
|
||||
use scene::{Scene, SceneProperties};
|
||||
@ -19,13 +26,6 @@ use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use tiling::{CompositeOps, DisplayListMap, PrimitiveFlags};
|
||||
use util::{ComplexClipRegionHelpers, subtract_rect};
|
||||
use webrender_traits::{BuiltDisplayList, BuiltDisplayListIter, ClipAndScrollInfo, ClipDisplayItem};
|
||||
use webrender_traits::{ClipId, ClipRegion, ColorF, DeviceUintRect, DeviceUintSize, DisplayItemRef};
|
||||
use webrender_traits::{Epoch, FilterOp, ImageDisplayItem, ItemRange, LayerPoint, LayerRect};
|
||||
use webrender_traits::{LayerSize, LayerToScrollTransform, LayoutSize, LayoutTransform, LayerVector2D};
|
||||
use webrender_traits::{MixBlendMode, PipelineId, ScrollClamping, ScrollEventPhase};
|
||||
use webrender_traits::{ScrollLayerState, ScrollLocation, ScrollPolicy, SpecificDisplayItem};
|
||||
use webrender_traits::{StackingContext, TileOffset, TransformStyle, WorldPoint};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
|
||||
pub struct FrameId(pub u32);
|
||||
@ -97,9 +97,9 @@ impl<'a> FlattenContext<'a> {
|
||||
resource_cache: &'a mut ResourceCache)
|
||||
-> FlattenContext<'a> {
|
||||
FlattenContext {
|
||||
scene: scene,
|
||||
builder: builder,
|
||||
resource_cache: resource_cache,
|
||||
scene,
|
||||
builder,
|
||||
resource_cache,
|
||||
replacements: Vec::new(),
|
||||
nested_display_list_info: Vec::new(),
|
||||
current_nested_display_list_index: 0,
|
||||
@ -152,6 +152,20 @@ impl<'a> FlattenContext<'a> {
|
||||
_ => id,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_complex_clips(&self,
|
||||
pipeline_id: PipelineId,
|
||||
complex_clips: ItemRange<ComplexClipRegion>)
|
||||
-> Vec<ComplexClipRegion> {
|
||||
if complex_clips.is_empty() {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
self.scene.display_lists.get(&pipeline_id)
|
||||
.expect("No display list?")
|
||||
.get(complex_clips)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: doc
|
||||
@ -227,22 +241,6 @@ impl StackingContextHelpers for StackingContext {
|
||||
}
|
||||
}
|
||||
|
||||
fn clip_intersection(original_rect: &LayerRect,
|
||||
region: &ClipRegion,
|
||||
display_list: &BuiltDisplayList)
|
||||
-> Option<LayerRect> {
|
||||
if region.image_mask.is_some() {
|
||||
return None;
|
||||
}
|
||||
let clips = display_list.get(region.complex_clips);
|
||||
let base_rect = region.main.intersection(original_rect);
|
||||
clips.fold(base_rect, |inner_combined, ccr| {
|
||||
inner_combined.and_then(|combined| {
|
||||
ccr.get_inner_rect_full().and_then(|ir| ir.intersection(&combined))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new(config: FrameBuilderConfig) -> Frame {
|
||||
Frame {
|
||||
@ -357,26 +355,39 @@ impl Frame {
|
||||
fn flatten_clip<'a>(&mut self,
|
||||
context: &mut FlattenContext,
|
||||
pipeline_id: PipelineId,
|
||||
parent_id: ClipId,
|
||||
item: &ClipDisplayItem,
|
||||
content_rect: &LayerRect,
|
||||
clip: &ClipRegion) {
|
||||
let clip_viewport = LayerRect::new(content_rect.origin, clip.main.size);
|
||||
let new_clip_id = self.clip_scroll_tree.generate_new_clip_id(pipeline_id);
|
||||
context.builder.add_clip_scroll_node(new_clip_id,
|
||||
parent_id,
|
||||
pipeline_id,
|
||||
&clip_viewport,
|
||||
clip,
|
||||
&mut self.clip_scroll_tree);
|
||||
let new_id = context.convert_new_id_to_neested(&item.id);
|
||||
context.builder.add_scroll_frame(new_id,
|
||||
new_clip_id,
|
||||
pipeline_id,
|
||||
&content_rect,
|
||||
&clip_viewport,
|
||||
&mut self.clip_scroll_tree);
|
||||
parent_id: &ClipId,
|
||||
new_clip_id: &ClipId,
|
||||
clip_region: ClipRegion) {
|
||||
let new_clip_id = context.convert_new_id_to_neested(new_clip_id);
|
||||
context.builder.add_clip_node(new_clip_id,
|
||||
*parent_id,
|
||||
pipeline_id,
|
||||
clip_region,
|
||||
&mut self.clip_scroll_tree);
|
||||
}
|
||||
|
||||
fn flatten_scroll_frame<'a>(&mut self,
|
||||
context: &mut FlattenContext,
|
||||
pipeline_id: PipelineId,
|
||||
parent_id: &ClipId,
|
||||
new_scroll_frame_id: &ClipId,
|
||||
frame_rect: &LayerRect,
|
||||
content_rect: &LayerRect,
|
||||
clip_region: ClipRegion) {
|
||||
let clip_id = self.clip_scroll_tree.generate_new_clip_id(pipeline_id);
|
||||
context.builder.add_clip_node(clip_id,
|
||||
*parent_id,
|
||||
pipeline_id,
|
||||
clip_region,
|
||||
&mut self.clip_scroll_tree);
|
||||
|
||||
let new_scroll_frame_id = context.convert_new_id_to_neested(new_scroll_frame_id);
|
||||
context.builder.add_scroll_frame(new_scroll_frame_id,
|
||||
clip_id,
|
||||
pipeline_id,
|
||||
&frame_rect,
|
||||
&content_rect.size,
|
||||
&mut self.clip_scroll_tree);
|
||||
}
|
||||
|
||||
fn flatten_stacking_context<'a>(&mut self,
|
||||
@ -449,7 +460,6 @@ impl Frame {
|
||||
context.builder.push_stacking_context(&reference_frame_relative_offset,
|
||||
pipeline_id,
|
||||
composition_operations,
|
||||
*bounds,
|
||||
stacking_context.transform_style);
|
||||
|
||||
self.flatten_items(traversal,
|
||||
@ -473,7 +483,6 @@ impl Frame {
|
||||
pipeline_id: PipelineId,
|
||||
parent_id: ClipId,
|
||||
bounds: &LayerRect,
|
||||
clip_region: &ClipRegion,
|
||||
context: &mut FlattenContext,
|
||||
reference_frame_relative_offset: LayerVector2D) {
|
||||
let pipeline = match context.scene.pipeline_map.get(&pipeline_id) {
|
||||
@ -494,16 +503,8 @@ impl Frame {
|
||||
reference_frame_relative_offset.y + bounds.origin.y,
|
||||
0.0);
|
||||
|
||||
let new_clip_id = self.clip_scroll_tree.generate_new_clip_id(pipeline_id);
|
||||
context.builder.add_clip_scroll_node(new_clip_id,
|
||||
parent_id,
|
||||
parent_id.pipeline_id(),
|
||||
bounds,
|
||||
clip_region,
|
||||
&mut self.clip_scroll_tree);
|
||||
|
||||
let iframe_reference_frame_id =
|
||||
context.builder.push_reference_frame(Some(new_clip_id),
|
||||
context.builder.push_reference_frame(Some(parent_id),
|
||||
pipeline_id,
|
||||
&iframe_rect,
|
||||
&transform,
|
||||
@ -513,8 +514,8 @@ impl Frame {
|
||||
ClipId::root_scroll_node(pipeline_id),
|
||||
iframe_reference_frame_id,
|
||||
pipeline_id,
|
||||
&LayerRect::new(LayerPoint::zero(), pipeline.content_size),
|
||||
&iframe_rect,
|
||||
&pipeline.content_size,
|
||||
&mut self.clip_scroll_tree);
|
||||
|
||||
self.flatten_root(&mut display_list.iter(), pipeline_id, context, &pipeline.content_size);
|
||||
@ -539,7 +540,7 @@ impl Frame {
|
||||
SpecificDisplayItem::WebGL(ref info) => {
|
||||
context.builder.add_webgl_rectangle(clip_and_scroll,
|
||||
item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
info.context_id);
|
||||
}
|
||||
SpecificDisplayItem::Image(ref info) => {
|
||||
@ -552,14 +553,14 @@ impl Frame {
|
||||
self.decompose_image(clip_and_scroll,
|
||||
context,
|
||||
&item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
info,
|
||||
image_size,
|
||||
tile_size as u32);
|
||||
} else {
|
||||
context.builder.add_image(clip_and_scroll,
|
||||
item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
&info.stretch_size,
|
||||
&info.tile_spacing,
|
||||
None,
|
||||
@ -571,7 +572,7 @@ impl Frame {
|
||||
SpecificDisplayItem::YuvImage(ref info) => {
|
||||
context.builder.add_yuv_image(clip_and_scroll,
|
||||
item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
info.yuv_data,
|
||||
info.color_space,
|
||||
info.image_rendering);
|
||||
@ -579,7 +580,7 @@ impl Frame {
|
||||
SpecificDisplayItem::Text(ref text_info) => {
|
||||
context.builder.add_text(clip_and_scroll,
|
||||
item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
text_info.font_key,
|
||||
text_info.size,
|
||||
text_info.blur_radius,
|
||||
@ -589,38 +590,23 @@ impl Frame {
|
||||
text_info.glyph_options);
|
||||
}
|
||||
SpecificDisplayItem::Rectangle(ref info) => {
|
||||
// Try to extract the opaque inner rectangle out of the clipped primitive.
|
||||
if let Some(opaque_rect) = clip_intersection(&item.rect(),
|
||||
item.clip_region(),
|
||||
item.display_list()) {
|
||||
let mut results = Vec::new();
|
||||
subtract_rect(&item.rect(), &opaque_rect, &mut results);
|
||||
// The inner rectangle is considered opaque within this layer.
|
||||
// It may still inherit some masking from the clip stack.
|
||||
context.builder.add_solid_rectangle(clip_and_scroll,
|
||||
&opaque_rect,
|
||||
&ClipRegion::simple(&item.clip_region().main),
|
||||
&info.color,
|
||||
PrimitiveFlags::None);
|
||||
for transparent_rect in &results {
|
||||
context.builder.add_solid_rectangle(clip_and_scroll,
|
||||
transparent_rect,
|
||||
item.clip_region(),
|
||||
&info.color,
|
||||
PrimitiveFlags::None);
|
||||
}
|
||||
} else {
|
||||
if !self.try_to_add_rectangle_splitting_on_clip(context,
|
||||
&item.rect(),
|
||||
item.local_clip(),
|
||||
&info.color,
|
||||
&clip_and_scroll) {
|
||||
context.builder.add_solid_rectangle(clip_and_scroll,
|
||||
&item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
&info.color,
|
||||
PrimitiveFlags::None);
|
||||
|
||||
}
|
||||
}
|
||||
SpecificDisplayItem::Gradient(ref info) => {
|
||||
context.builder.add_gradient(clip_and_scroll,
|
||||
item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
info.gradient.start_point,
|
||||
info.gradient.end_point,
|
||||
item.gradient_stops(),
|
||||
@ -633,7 +619,7 @@ impl Frame {
|
||||
SpecificDisplayItem::RadialGradient(ref info) => {
|
||||
context.builder.add_radial_gradient(clip_and_scroll,
|
||||
item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
info.gradient.start_center,
|
||||
info.gradient.start_radius,
|
||||
info.gradient.end_center,
|
||||
@ -647,7 +633,7 @@ impl Frame {
|
||||
SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
|
||||
context.builder.add_box_shadow(clip_and_scroll,
|
||||
&box_shadow_info.box_bounds,
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
&box_shadow_info.offset,
|
||||
&box_shadow_info.color,
|
||||
box_shadow_info.blur_radius,
|
||||
@ -658,7 +644,7 @@ impl Frame {
|
||||
SpecificDisplayItem::Border(ref info) => {
|
||||
context.builder.add_border(clip_and_scroll,
|
||||
item.rect(),
|
||||
item.clip_region(),
|
||||
item.local_clip(),
|
||||
info,
|
||||
item.gradient_stops(),
|
||||
item.display_list()
|
||||
@ -680,18 +666,43 @@ impl Frame {
|
||||
self.flatten_iframe(info.pipeline_id,
|
||||
clip_and_scroll.scroll_node_id,
|
||||
&item.rect(),
|
||||
&item.clip_region(),
|
||||
context,
|
||||
reference_frame_relative_offset);
|
||||
}
|
||||
SpecificDisplayItem::Clip(ref info) => {
|
||||
let content_rect = &item.rect().translate(&reference_frame_relative_offset);
|
||||
let complex_clips = context.get_complex_clips(pipeline_id, item.complex_clip().0);
|
||||
let mut clip_region = ClipRegion::for_clip_node(*item.local_clip().clip_rect(),
|
||||
complex_clips,
|
||||
info.image_mask);
|
||||
clip_region.origin += reference_frame_relative_offset;
|
||||
|
||||
self.flatten_clip(context,
|
||||
pipeline_id,
|
||||
clip_and_scroll.scroll_node_id,
|
||||
&info,
|
||||
&content_rect,
|
||||
item.clip_region());
|
||||
&clip_and_scroll.scroll_node_id,
|
||||
&info.id,
|
||||
clip_region);
|
||||
}
|
||||
SpecificDisplayItem::ScrollFrame(ref info) => {
|
||||
let complex_clips = context.get_complex_clips(pipeline_id, item.complex_clip().0);
|
||||
let mut clip_region = ClipRegion::for_clip_node(*item.local_clip().clip_rect(),
|
||||
complex_clips,
|
||||
info.image_mask);
|
||||
clip_region.origin += reference_frame_relative_offset;
|
||||
|
||||
// Just use clip rectangle as the frame rect for this scroll frame.
|
||||
// This is only interesting when calculating scroll extents for the
|
||||
// ClipScrollNode::scroll(..) API
|
||||
let frame_rect = item.local_clip()
|
||||
.clip_rect()
|
||||
.translate(&reference_frame_relative_offset);
|
||||
let content_rect = item.rect().translate(&reference_frame_relative_offset);
|
||||
self.flatten_scroll_frame(context,
|
||||
pipeline_id,
|
||||
&clip_and_scroll.scroll_node_id,
|
||||
&info.id,
|
||||
&frame_rect,
|
||||
&content_rect,
|
||||
clip_region);
|
||||
}
|
||||
SpecificDisplayItem::PushNestedDisplayList => {
|
||||
// Using the clip and scroll already processed for nesting here
|
||||
@ -703,7 +714,7 @@ impl Frame {
|
||||
SpecificDisplayItem::PopNestedDisplayList => context.pop_nested_display_list_ids(),
|
||||
|
||||
// Do nothing; these are dummy items for the display list parser
|
||||
SpecificDisplayItem::SetGradientStops | SpecificDisplayItem::SetClipRegion(_) => { }
|
||||
SpecificDisplayItem::SetGradientStops => { }
|
||||
|
||||
SpecificDisplayItem::PopStackingContext =>
|
||||
unreachable!("Should have returned in parent method."),
|
||||
@ -711,16 +722,63 @@ impl Frame {
|
||||
None
|
||||
}
|
||||
|
||||
/// Try to optimize the rendering of a solid rectangle that is clipped by a single
|
||||
/// rounded rectangle, by only masking the parts of the rectangle that intersect
|
||||
/// the rounded parts of the clip. This is pretty simple now, so has a lot of
|
||||
/// potential for further optimizations.
|
||||
fn try_to_add_rectangle_splitting_on_clip(&mut self,
|
||||
context: &mut FlattenContext,
|
||||
rect: &LayerRect,
|
||||
local_clip: &LocalClip,
|
||||
color: &ColorF,
|
||||
clip_and_scroll: &ClipAndScrollInfo)
|
||||
-> bool {
|
||||
// If this rectangle is not opaque, splitting the rectangle up
|
||||
// into an inner opaque region just ends up hurting batching and
|
||||
// doing more work than necessary.
|
||||
if color.a != 1.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let inner_unclipped_rect = match local_clip {
|
||||
&LocalClip::Rect(_) => return false,
|
||||
&LocalClip::RoundedRect(_, ref region) => region.get_inner_rect_full(),
|
||||
};
|
||||
let inner_unclipped_rect = match inner_unclipped_rect {
|
||||
Some(rect) => rect,
|
||||
None => return false,
|
||||
};
|
||||
|
||||
// The inner rectangle is not clipped by its assigned clipping node, so we can
|
||||
// let it be clipped by the parent of the clipping node, which may result in
|
||||
// less masking some cases.
|
||||
let mut clipped_rects = Vec::new();
|
||||
subtract_rect(rect, &inner_unclipped_rect, &mut clipped_rects);
|
||||
|
||||
context.builder.add_solid_rectangle(*clip_and_scroll,
|
||||
&inner_unclipped_rect,
|
||||
&LocalClip::from(*local_clip.clip_rect()),
|
||||
color,
|
||||
PrimitiveFlags::None);
|
||||
|
||||
for clipped_rect in &clipped_rects {
|
||||
context.builder.add_solid_rectangle(*clip_and_scroll,
|
||||
clipped_rect,
|
||||
local_clip,
|
||||
color,
|
||||
PrimitiveFlags::None);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn flatten_root<'a>(&mut self,
|
||||
traversal: &mut BuiltDisplayListIter<'a>,
|
||||
pipeline_id: PipelineId,
|
||||
context: &mut FlattenContext,
|
||||
content_size: &LayoutSize) {
|
||||
let root_bounds = LayerRect::new(LayerPoint::zero(), *content_size);
|
||||
context.builder.push_stacking_context(&LayerVector2D::zero(),
|
||||
pipeline_id,
|
||||
CompositeOps::default(),
|
||||
root_bounds,
|
||||
TransformStyle::Flat);
|
||||
|
||||
// We do this here, rather than above because we want any of the top-level
|
||||
@ -735,9 +793,10 @@ impl Frame {
|
||||
if context.scene.root_pipeline_id != Some(pipeline_id) {
|
||||
if let Some(pipeline) = context.scene.pipeline_map.get(&pipeline_id) {
|
||||
if let Some(bg_color) = pipeline.background_color {
|
||||
let root_bounds = LayerRect::new(LayerPoint::zero(), *content_size);
|
||||
context.builder.add_solid_rectangle(ClipAndScrollInfo::simple(clip_id),
|
||||
&root_bounds,
|
||||
&ClipRegion::simple(&root_bounds),
|
||||
&LocalClip::from(root_bounds),
|
||||
&bg_color,
|
||||
PrimitiveFlags::None);
|
||||
}
|
||||
@ -752,7 +811,7 @@ impl Frame {
|
||||
context.builder.add_solid_rectangle(
|
||||
ClipAndScrollInfo::simple(clip_id),
|
||||
&scrollbar_rect,
|
||||
&ClipRegion::simple(&scrollbar_rect),
|
||||
&LocalClip::from(scrollbar_rect),
|
||||
&DEFAULT_SCROLLBAR_COLOR,
|
||||
PrimitiveFlags::Scrollbar(self.clip_scroll_tree.topmost_scrolling_node_id(), 4.0));
|
||||
}
|
||||
@ -802,7 +861,7 @@ impl Frame {
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
context: &mut FlattenContext,
|
||||
item_rect: &LayerRect,
|
||||
item_clip: &ClipRegion,
|
||||
item_local_clip: &LocalClip,
|
||||
info: &ImageDisplayItem,
|
||||
image_size: DeviceUintSize,
|
||||
tile_size: u32) {
|
||||
@ -812,7 +871,7 @@ impl Frame {
|
||||
self.decompose_image_row(clip_and_scroll,
|
||||
context,
|
||||
item_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
image_size,
|
||||
tile_size);
|
||||
@ -832,7 +891,7 @@ impl Frame {
|
||||
self.decompose_image_row(clip_and_scroll,
|
||||
context,
|
||||
&row_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
image_size,
|
||||
tile_size);
|
||||
@ -844,7 +903,7 @@ impl Frame {
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
context: &mut FlattenContext,
|
||||
item_rect: &LayerRect,
|
||||
item_clip: &ClipRegion,
|
||||
item_local_clip: &LocalClip,
|
||||
info: &ImageDisplayItem,
|
||||
image_size: DeviceUintSize,
|
||||
tile_size: u32) {
|
||||
@ -854,7 +913,7 @@ impl Frame {
|
||||
self.decompose_tiled_image(clip_and_scroll,
|
||||
context,
|
||||
item_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
image_size,
|
||||
tile_size);
|
||||
@ -874,7 +933,7 @@ impl Frame {
|
||||
self.decompose_tiled_image(clip_and_scroll,
|
||||
context,
|
||||
&decomposed_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
image_size,
|
||||
tile_size);
|
||||
@ -886,7 +945,7 @@ impl Frame {
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
context: &mut FlattenContext,
|
||||
item_rect: &LayerRect,
|
||||
item_clip: &ClipRegion,
|
||||
item_local_clip: &LocalClip,
|
||||
info: &ImageDisplayItem,
|
||||
image_size: DeviceUintSize,
|
||||
tile_size: u32) {
|
||||
@ -965,7 +1024,7 @@ impl Frame {
|
||||
self.add_tile_primitive(clip_and_scroll,
|
||||
context,
|
||||
item_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
TileOffset::new(tx, ty),
|
||||
stretched_tile_size,
|
||||
@ -977,7 +1036,7 @@ impl Frame {
|
||||
self.add_tile_primitive(clip_and_scroll,
|
||||
context,
|
||||
item_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
TileOffset::new(num_tiles_x, ty),
|
||||
stretched_tile_size,
|
||||
@ -993,7 +1052,7 @@ impl Frame {
|
||||
self.add_tile_primitive(clip_and_scroll,
|
||||
context,
|
||||
item_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
TileOffset::new(tx, num_tiles_y),
|
||||
stretched_tile_size,
|
||||
@ -1008,7 +1067,7 @@ impl Frame {
|
||||
self.add_tile_primitive(clip_and_scroll,
|
||||
context,
|
||||
item_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
info,
|
||||
TileOffset::new(num_tiles_x, num_tiles_y),
|
||||
stretched_tile_size,
|
||||
@ -1024,7 +1083,7 @@ impl Frame {
|
||||
clip_and_scroll: ClipAndScrollInfo,
|
||||
context: &mut FlattenContext,
|
||||
item_rect: &LayerRect,
|
||||
item_clip: &ClipRegion,
|
||||
item_local_clip: &LocalClip,
|
||||
info: &ImageDisplayItem,
|
||||
tile_offset: TileOffset,
|
||||
stretched_tile_size: LayerSize,
|
||||
@ -1068,7 +1127,7 @@ impl Frame {
|
||||
if let Some(prim_rect) = prim_rect.intersection(item_rect) {
|
||||
context.builder.add_image(clip_and_scroll,
|
||||
prim_rect,
|
||||
item_clip,
|
||||
item_local_clip,
|
||||
&stretched_size,
|
||||
&info.tile_spacing,
|
||||
None,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,10 +18,10 @@ use std::collections::hash_map::Entry;
|
||||
use std::collections::HashSet;
|
||||
use std::mem;
|
||||
use texture_cache::{TextureCacheItemId, TextureCache};
|
||||
use webrender_traits::FontTemplate;
|
||||
use webrender_traits::{FontKey, FontRenderMode, ImageData, ImageFormat};
|
||||
use webrender_traits::{ImageDescriptor, ColorF, LayoutPoint};
|
||||
use webrender_traits::{GlyphKey, GlyphOptions, GlyphInstance, GlyphDimensions};
|
||||
use api::FontTemplate;
|
||||
use api::{FontKey, FontRenderMode, ImageData, ImageFormat};
|
||||
use api::{ImageDescriptor, ColorF, LayoutPoint};
|
||||
use api::{GlyphKey, GlyphOptions, GlyphInstance, GlyphDimensions};
|
||||
|
||||
pub type GlyphCache = ResourceClassCache<GlyphRequest, Option<TextureCacheItemId>>;
|
||||
|
||||
@ -114,10 +114,10 @@ impl GlyphRasterizer {
|
||||
workers: Arc::clone(&workers),
|
||||
}
|
||||
),
|
||||
glyph_rx: glyph_rx,
|
||||
glyph_tx: glyph_tx,
|
||||
glyph_rx,
|
||||
glyph_tx,
|
||||
pending_glyphs: HashSet::new(),
|
||||
workers: workers,
|
||||
workers,
|
||||
fonts_to_remove: Vec::new(),
|
||||
}
|
||||
}
|
||||
@ -337,8 +337,8 @@ impl GlyphRequest {
|
||||
) -> GlyphRequest {
|
||||
GlyphRequest {
|
||||
key: GlyphKey::new(font_key, size, color, index, point, render_mode),
|
||||
render_mode: render_mode,
|
||||
glyph_options: glyph_options,
|
||||
render_mode,
|
||||
glyph_options,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ use internal_types::UvRect;
|
||||
use profiler::GpuCacheProfileCounters;
|
||||
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
|
||||
use std::{mem, u32};
|
||||
use webrender_traits::{ColorF, LayerRect};
|
||||
use api::{ColorF, LayerRect};
|
||||
|
||||
pub const GPU_CACHE_INITIAL_HEIGHT: u32 = 512;
|
||||
const FRAMES_BEFORE_EVICTION: usize = 10;
|
||||
@ -56,6 +56,14 @@ pub struct GpuBlockData {
|
||||
pub data: [f32; 4],
|
||||
}
|
||||
|
||||
impl GpuBlockData {
|
||||
pub fn empty() -> GpuBlockData {
|
||||
GpuBlockData {
|
||||
data: [0.0; 4],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Conversion helpers for GpuBlockData
|
||||
impl Into<GpuBlockData> for ColorF {
|
||||
fn into(self) -> GpuBlockData {
|
||||
@ -154,8 +162,8 @@ impl Block {
|
||||
next: Option<BlockIndex>,
|
||||
frame_id: FrameId) -> Block {
|
||||
Block {
|
||||
address: address,
|
||||
next: next,
|
||||
address,
|
||||
next,
|
||||
last_access_time: frame_id,
|
||||
epoch: Epoch(0),
|
||||
}
|
||||
@ -177,7 +185,7 @@ struct Row {
|
||||
impl Row {
|
||||
fn new(block_count_per_item: usize) -> Row {
|
||||
Row {
|
||||
block_count_per_item: block_count_per_item,
|
||||
block_count_per_item,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -348,7 +356,7 @@ impl Texture {
|
||||
// to be updated on the GPU.
|
||||
self.updates.push(GpuCacheUpdate::Copy {
|
||||
block_index: pending_block_index,
|
||||
block_count: block_count,
|
||||
block_count,
|
||||
address: block.address,
|
||||
});
|
||||
}
|
||||
@ -431,13 +439,20 @@ pub struct GpuDataRequest<'a> {
|
||||
}
|
||||
|
||||
impl<'a> GpuDataRequest<'a> {
|
||||
pub fn push(&mut self, block: GpuBlockData) {
|
||||
self.texture.pending_blocks.push(block);
|
||||
pub fn push<B>(&mut self, block: B)
|
||||
where B: Into<GpuBlockData>
|
||||
{
|
||||
self.texture.pending_blocks.push(block.into());
|
||||
}
|
||||
|
||||
pub fn extend_from_slice(&mut self, blocks: &[GpuBlockData]) {
|
||||
self.texture.pending_blocks.extend_from_slice(blocks);
|
||||
}
|
||||
|
||||
/// Consume the request and return the number of blocks written
|
||||
pub fn close(self) -> usize {
|
||||
self.texture.pending_blocks.len() - self.start_index
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for GpuDataRequest<'a> {
|
||||
@ -499,7 +514,7 @@ impl GpuCache {
|
||||
}
|
||||
|
||||
Some(GpuDataRequest {
|
||||
handle: handle,
|
||||
handle,
|
||||
frame_id: self.frame_id,
|
||||
start_index: self.texture.pending_blocks.len(),
|
||||
texture: &mut self.texture,
|
||||
|
@ -1,158 +0,0 @@
|
||||
/* 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 device::TextureFilter;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::ops::Add;
|
||||
use util::recycle_vec;
|
||||
use webrender_traits::ImageFormat;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
|
||||
pub struct GpuStoreAddress(pub i32);
|
||||
|
||||
|
||||
impl Add<i32> for GpuStoreAddress {
|
||||
type Output = GpuStoreAddress;
|
||||
|
||||
fn add(self, other: i32) -> GpuStoreAddress {
|
||||
GpuStoreAddress(self.0 + other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for GpuStoreAddress {
|
||||
type Output = GpuStoreAddress;
|
||||
|
||||
fn add(self, other: usize) -> GpuStoreAddress {
|
||||
GpuStoreAddress(self.0 + other as i32)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GpuStoreLayout {
|
||||
fn image_format() -> ImageFormat;
|
||||
|
||||
fn texture_width<T>() -> usize;
|
||||
|
||||
fn texture_filter() -> TextureFilter;
|
||||
|
||||
fn texel_size() -> usize {
|
||||
match Self::image_format() {
|
||||
ImageFormat::BGRA8 => 4,
|
||||
ImageFormat::RGBAF32 => 16,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn texels_per_item<T>() -> usize {
|
||||
let item_size = mem::size_of::<T>();
|
||||
let texel_size = Self::texel_size();
|
||||
debug_assert!(item_size % texel_size == 0);
|
||||
item_size / texel_size
|
||||
}
|
||||
|
||||
fn items_per_row<T>() -> usize {
|
||||
Self::texture_width::<T>() / Self::texels_per_item::<T>()
|
||||
}
|
||||
|
||||
fn rows_per_item<T>() -> usize {
|
||||
Self::texels_per_item::<T>() / Self::texture_width::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
/// A CPU-side buffer storing content to be uploaded to the GPU.
|
||||
pub struct GpuStore<T, L> {
|
||||
data: Vec<T>,
|
||||
layout: PhantomData<L>,
|
||||
// TODO(gw): Could store this intrusively inside
|
||||
// the data array free slots.
|
||||
//free_list: Vec<GpuStoreAddress>,
|
||||
}
|
||||
|
||||
impl<T: Clone + Default, L: GpuStoreLayout> GpuStore<T, L> {
|
||||
pub fn new() -> GpuStore<T, L> {
|
||||
GpuStore {
|
||||
data: Vec::new(),
|
||||
layout: PhantomData,
|
||||
//free_list: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recycle(self) -> Self {
|
||||
GpuStore {
|
||||
data: recycle_vec(self.data),
|
||||
layout: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push<E>(&mut self, data: E) -> GpuStoreAddress where T: From<E> {
|
||||
let address = GpuStoreAddress(self.data.len() as i32);
|
||||
self.data.push(T::from(data));
|
||||
address
|
||||
}
|
||||
|
||||
// TODO(gw): Change this to do incremental updates, which means
|
||||
// there is no need to copy all this data during every scroll!
|
||||
pub fn build(&self) -> Vec<T> {
|
||||
let items_per_row = L::items_per_row::<T>();
|
||||
|
||||
let mut items = self.data.clone();
|
||||
|
||||
// Extend the data array to be a multiple of the row size.
|
||||
// This ensures memory safety when the array is passed to
|
||||
// OpenGL to upload to the GPU.
|
||||
if items_per_row != 0 {
|
||||
while items_per_row != 0 && items.len() % items_per_row != 0 {
|
||||
items.push(T::default());
|
||||
}
|
||||
}
|
||||
|
||||
items
|
||||
}
|
||||
|
||||
pub fn alloc(&mut self, count: usize) -> GpuStoreAddress {
|
||||
let address = self.get_next_address();
|
||||
|
||||
for _ in 0..count {
|
||||
self.data.push(T::default());
|
||||
}
|
||||
|
||||
address
|
||||
}
|
||||
|
||||
pub fn get_next_address(&self) -> GpuStoreAddress {
|
||||
GpuStoreAddress(self.data.len() as i32)
|
||||
}
|
||||
|
||||
pub fn get(&mut self, address: GpuStoreAddress) -> &T {
|
||||
&self.data[address.0 as usize]
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, address: GpuStoreAddress) -> &mut T {
|
||||
&mut self.data[address.0 as usize]
|
||||
}
|
||||
|
||||
pub fn get_slice_mut(&mut self,
|
||||
address: GpuStoreAddress,
|
||||
count: usize) -> &mut [T] {
|
||||
let offset = address.0 as usize;
|
||||
&mut self.data[offset..offset + count]
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.data.clear()
|
||||
}
|
||||
|
||||
// TODO(gw): Implement incremental updates of
|
||||
// GPU backed data, and support freelist for removing
|
||||
// dynamic items.
|
||||
|
||||
/*
|
||||
pub fn free(&mut self, address: GpuStoreAddress) {
|
||||
|
||||
}
|
||||
|
||||
pub fn update(&mut self, address: GpuStoreAddress, data: T) {
|
||||
|
||||
}*/
|
||||
}
|
@ -14,8 +14,8 @@ use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use tiling;
|
||||
use renderer::BlendMode;
|
||||
use webrender_traits::{ClipId, ColorF, DeviceUintRect, Epoch, ExternalImageData, ExternalImageId};
|
||||
use webrender_traits::{DevicePoint, ImageData, ImageFormat, PipelineId};
|
||||
use api::{ClipId, ColorF, DeviceUintRect, Epoch, ExternalImageData, ExternalImageId};
|
||||
use api::{DevicePoint, ImageData, ImageFormat, PipelineId};
|
||||
|
||||
// An ID for a texture that is owned by the
|
||||
// texture cache module. This can include atlases
|
||||
@ -59,7 +59,6 @@ pub enum TextureSampler {
|
||||
Color2,
|
||||
CacheA8,
|
||||
CacheRGBA8,
|
||||
Data32,
|
||||
ResourceCache,
|
||||
Layers,
|
||||
RenderTasks,
|
||||
@ -171,11 +170,11 @@ pub struct DebugFontVertex {
|
||||
impl DebugFontVertex {
|
||||
pub fn new(x: f32, y: f32, u: f32, v: f32, color: PackedColor) -> DebugFontVertex {
|
||||
DebugFontVertex {
|
||||
x: x,
|
||||
y: y,
|
||||
color: color,
|
||||
u: u,
|
||||
v: v,
|
||||
x,
|
||||
y,
|
||||
color,
|
||||
u,
|
||||
v,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -190,9 +189,9 @@ pub struct DebugColorVertex {
|
||||
impl DebugColorVertex {
|
||||
pub fn new(x: f32, y: f32, color: PackedColor) -> DebugColorVertex {
|
||||
DebugColorVertex {
|
||||
x: x,
|
||||
y: y,
|
||||
color: color,
|
||||
x,
|
||||
y,
|
||||
color,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -279,9 +278,9 @@ impl RendererFrame {
|
||||
frame: Option<tiling::Frame>)
|
||||
-> RendererFrame {
|
||||
RendererFrame {
|
||||
pipeline_epoch_map: pipeline_epoch_map,
|
||||
layers_bouncing_back: layers_bouncing_back,
|
||||
frame: frame,
|
||||
pipeline_epoch_map,
|
||||
layers_bouncing_back,
|
||||
frame,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
//! they're nestable.
|
||||
//!
|
||||
//! [stacking_contexts]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
|
||||
//! [newframe]: ../webrender_traits/struct.RenderApi.html#method.set_display_list
|
||||
//! [newframe]: ../webrender_api/struct.RenderApi.html#method.set_display_list
|
||||
//! [notifier]: renderer/struct.Renderer.html#method.set_render_notifier
|
||||
|
||||
#[macro_use]
|
||||
@ -59,7 +59,6 @@ mod freelist;
|
||||
mod geometry;
|
||||
mod glyph_rasterizer;
|
||||
mod gpu_cache;
|
||||
mod gpu_store;
|
||||
mod internal_types;
|
||||
mod mask_cache;
|
||||
mod prim_store;
|
||||
@ -134,7 +133,7 @@ extern crate gleam;
|
||||
extern crate num_traits;
|
||||
//extern crate notify;
|
||||
extern crate time;
|
||||
extern crate webrender_traits;
|
||||
pub extern crate webrender_api;
|
||||
#[cfg(feature = "webgl")]
|
||||
extern crate offscreen_gl_context;
|
||||
extern crate byteorder;
|
||||
@ -146,3 +145,5 @@ extern crate gamma_lut;
|
||||
|
||||
pub use renderer::{ExternalImage, ExternalImageSource, ExternalImageHandler};
|
||||
pub use renderer::{GraphicsApi, GraphicsApiInfo, ReadPixelsFormat, Renderer, RendererOptions};
|
||||
|
||||
pub use webrender_api as api;
|
||||
|
@ -2,19 +2,63 @@
|
||||
* 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::{BorderRadius, ComplexClipRegion, DeviceIntRect, ImageMask, LayerPoint, LayerRect};
|
||||
use api::{LayerSize, LayerToWorldTransform, LocalClip};
|
||||
use border::BorderCornerClipSource;
|
||||
use gpu_store::GpuStoreAddress;
|
||||
use prim_store::{ClipData, GpuBlock32, ImageMaskData, PrimitiveStore};
|
||||
use prim_store::{CLIP_DATA_GPU_SIZE, MASK_DATA_GPU_SIZE};
|
||||
use renderer::VertexDataStore;
|
||||
use util::{ComplexClipRegionHelpers, MatrixHelpers, TransformedRect};
|
||||
use webrender_traits::{BorderRadius, BuiltDisplayList, ClipRegion, ComplexClipRegion, ImageMask};
|
||||
use webrender_traits::{DeviceIntRect, LayerToWorldTransform};
|
||||
use webrender_traits::{DeviceRect, LayerRect, LayerPoint, LayerSize};
|
||||
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
|
||||
use prim_store::{CLIP_DATA_GPU_BLOCKS, ClipData, ImageMaskData};
|
||||
use util::{ComplexClipRegionHelpers, TransformedRect};
|
||||
use std::ops::Not;
|
||||
|
||||
const MAX_CLIP: f32 = 1000000.0;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClipRegion {
|
||||
pub origin: LayerPoint,
|
||||
pub main: LayerRect,
|
||||
pub image_mask: Option<ImageMask>,
|
||||
pub complex_clips: Vec<ComplexClipRegion>,
|
||||
}
|
||||
|
||||
impl ClipRegion {
|
||||
pub fn for_clip_node(rect: LayerRect,
|
||||
mut complex_clips: Vec<ComplexClipRegion>,
|
||||
mut image_mask: Option<ImageMask>)
|
||||
-> ClipRegion {
|
||||
// All the coordinates we receive are relative to the stacking context, but we want
|
||||
// to convert them to something relative to the origin of the clip.
|
||||
let negative_origin = -rect.origin.to_vector();
|
||||
if let Some(ref mut image_mask) = image_mask {
|
||||
image_mask.rect = image_mask.rect.translate(&negative_origin);
|
||||
}
|
||||
|
||||
for complex_clip in complex_clips.iter_mut() {
|
||||
complex_clip.rect = complex_clip.rect.translate(&negative_origin);
|
||||
}
|
||||
|
||||
ClipRegion {
|
||||
origin: rect.origin,
|
||||
main: LayerRect::new(LayerPoint::zero(), rect.size),
|
||||
image_mask,
|
||||
complex_clips,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_local_clip(local_clip: &LocalClip) -> ClipRegion {
|
||||
let complex_clips = match local_clip {
|
||||
&LocalClip::Rect(_) => Vec::new(),
|
||||
&LocalClip::RoundedRect(_, ref region) => vec![region.clone()],
|
||||
};
|
||||
|
||||
ClipRegion {
|
||||
origin: LayerPoint::zero(),
|
||||
main: *local_clip.clip_rect(),
|
||||
image_mask: None,
|
||||
complex_clips,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ClipMode {
|
||||
@ -33,26 +77,14 @@ impl Not for ClipMode {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum RegionMode {
|
||||
IncludeRect,
|
||||
ExcludeRect,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ClipSource {
|
||||
Complex(LayerRect, f32, ClipMode),
|
||||
// The RegionMode here specifies whether to consider the rect
|
||||
// from the clip region as part of the mask. This is true
|
||||
// for clip/scroll nodes, but false for primitives, where
|
||||
// the clip rect is handled in local space.
|
||||
Region(ClipRegion, RegionMode),
|
||||
|
||||
// TODO(gw): This currently only handles dashed style
|
||||
// clips, where the border style is dashed for both
|
||||
// adjacent border edges. Expand to handle dotted style
|
||||
// and different styles per edge.
|
||||
Region(ClipRegion),
|
||||
/// TODO(gw): This currently only handles dashed style
|
||||
/// clips, where the border style is dashed for both
|
||||
/// adjacent border edges. Expand to handle dotted style
|
||||
/// and different styles per edge.
|
||||
BorderCorner(BorderCornerClipSource),
|
||||
}
|
||||
|
||||
@ -60,42 +92,53 @@ impl ClipSource {
|
||||
pub fn image_mask(&self) -> Option<ImageMask> {
|
||||
match *self {
|
||||
ClipSource::Complex(..) |
|
||||
ClipSource::BorderCorner{..} => None,
|
||||
ClipSource::Region(ref region, _) => region.image_mask,
|
||||
ClipSource::BorderCorner(..) => None,
|
||||
ClipSource::Region(ref region) => region.image_mask,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ClipAddressRange {
|
||||
pub start: GpuStoreAddress,
|
||||
pub location: GpuCacheHandle,
|
||||
item_count: usize,
|
||||
}
|
||||
|
||||
/// Represents a local rect and a device space
|
||||
/// bounding rect that can be updated when the
|
||||
/// transform changes.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Geometry {
|
||||
pub local_rect: LayerRect,
|
||||
pub bounding_rect: DeviceIntRect,
|
||||
}
|
||||
|
||||
impl Geometry {
|
||||
fn new(local_rect: LayerRect) -> Geometry {
|
||||
Geometry {
|
||||
local_rect: local_rect,
|
||||
bounding_rect: DeviceIntRect::zero(),
|
||||
impl ClipAddressRange {
|
||||
fn new(count: usize) -> Self {
|
||||
ClipAddressRange {
|
||||
location: GpuCacheHandle::new(),
|
||||
item_count: count,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self,
|
||||
transform: &LayerToWorldTransform,
|
||||
device_pixel_ratio: f32) {
|
||||
let transformed = TransformedRect::new(&self.local_rect,
|
||||
transform,
|
||||
device_pixel_ratio);
|
||||
self.bounding_rect = transformed.bounding_rect;
|
||||
pub fn get_count(&self) -> usize {
|
||||
self.item_count
|
||||
}
|
||||
|
||||
fn get_block_count(&self) -> Option<usize> {
|
||||
if self.item_count != 0 {
|
||||
Some(self.item_count * CLIP_DATA_GPU_BLOCKS)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a local rect and a device space
|
||||
/// rectangles that are either outside or inside bounds.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Geometry {
|
||||
pub local_rect: LayerRect,
|
||||
pub device_rect: DeviceIntRect,
|
||||
}
|
||||
|
||||
impl From<LayerRect> for Geometry {
|
||||
fn from(local_rect: LayerRect) -> Self {
|
||||
Geometry {
|
||||
local_rect,
|
||||
device_rect: DeviceIntRect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,41 +149,48 @@ impl Geometry {
|
||||
/// correctness. In the future we can make this a lot
|
||||
/// more clever with some proper region handling.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum MaskBounds {
|
||||
/// We know both the outer and inner rect. This is the
|
||||
/// fast path for, e.g. a simple rounded rect.
|
||||
OuterInner(Geometry, Geometry),
|
||||
/// We know the outer rect only.
|
||||
Outer(Geometry),
|
||||
/// We can't determine the bounds - draw mask over entire rect.
|
||||
/// This is currently used for clip-out operations on
|
||||
/// box shadows.
|
||||
None,
|
||||
pub struct MaskBounds {
|
||||
pub outer: Option<Geometry>,
|
||||
pub inner: Option<Geometry>,
|
||||
}
|
||||
|
||||
impl MaskBounds {
|
||||
pub fn update(&mut self, transform: &LayerToWorldTransform, device_pixel_ratio: f32) {
|
||||
if let Some(ref mut outer) = self.outer {
|
||||
let transformed = TransformedRect::new(&outer.local_rect,
|
||||
transform,
|
||||
device_pixel_ratio);
|
||||
outer.device_rect = transformed.bounding_rect;
|
||||
}
|
||||
if let Some(ref mut inner) = self.inner {
|
||||
let transformed = TransformedRect::new(&inner.local_rect,
|
||||
transform,
|
||||
device_pixel_ratio);
|
||||
inner.device_rect = transformed.inner_rect;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MaskCacheInfo {
|
||||
/// Clip items that are always applied
|
||||
pub complex_clip_range: ClipAddressRange,
|
||||
pub effective_complex_clip_count: usize,
|
||||
pub image: Option<(ImageMask, GpuStoreAddress)>,
|
||||
pub border_corners: Vec<(BorderCornerClipSource, GpuStoreAddress)>,
|
||||
pub bounds: Option<MaskBounds>,
|
||||
pub is_aligned: bool,
|
||||
/// Clip items that are only applied if the clip space is transformed from
|
||||
/// the local space of target primitive/layer.
|
||||
pub layer_clip_range: ClipAddressRange,
|
||||
pub image: Option<(ImageMask, GpuCacheHandle)>,
|
||||
pub border_corners: Vec<(BorderCornerClipSource, GpuCacheHandle)>,
|
||||
pub bounds: MaskBounds,
|
||||
}
|
||||
|
||||
impl MaskCacheInfo {
|
||||
/// Create a new mask cache info. It allocates the GPU store data but leaves
|
||||
/// it unitialized for the following `update()` call to deal with.
|
||||
pub fn new(clips: &[ClipSource],
|
||||
clip_store: &mut VertexDataStore<GpuBlock32>)
|
||||
-> Option<MaskCacheInfo> {
|
||||
if clips.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
/// it uninitialized for the following `update()` call to deal with.
|
||||
pub fn new(clips: &[ClipSource]) -> MaskCacheInfo {
|
||||
let mut image = None;
|
||||
let mut border_corners = Vec::new();
|
||||
let mut complex_clip_count = 0;
|
||||
let mut layer_clip_count = 0;
|
||||
|
||||
// Work out how much clip data space we need to allocate
|
||||
// and if we have an image mask.
|
||||
@ -149,63 +199,47 @@ impl MaskCacheInfo {
|
||||
ClipSource::Complex(..) => {
|
||||
complex_clip_count += 1;
|
||||
}
|
||||
ClipSource::Region(ref region, region_mode) => {
|
||||
ClipSource::Region(ref region) => {
|
||||
if let Some(info) = region.image_mask {
|
||||
debug_assert!(image.is_none()); // TODO(gw): Support >1 image mask!
|
||||
image = Some((info, clip_store.alloc(MASK_DATA_GPU_SIZE)));
|
||||
}
|
||||
complex_clip_count += region.complex_clip_count;
|
||||
if region_mode == RegionMode::IncludeRect {
|
||||
complex_clip_count += 1;
|
||||
image = Some((info, GpuCacheHandle::new()));
|
||||
}
|
||||
complex_clip_count += region.complex_clips.len();
|
||||
layer_clip_count += 1;
|
||||
}
|
||||
ClipSource::BorderCorner(ref source) => {
|
||||
// One block for the corner header, plus one
|
||||
// block per dash to clip out.
|
||||
let gpu_address = clip_store.alloc(1 + source.max_clip_count);
|
||||
border_corners.push((source.clone(), gpu_address));
|
||||
border_corners.push((source.clone(), GpuCacheHandle::new()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let complex_clip_range = ClipAddressRange {
|
||||
start: if complex_clip_count > 0 {
|
||||
clip_store.alloc(CLIP_DATA_GPU_SIZE * complex_clip_count)
|
||||
} else {
|
||||
GpuStoreAddress(0)
|
||||
MaskCacheInfo {
|
||||
complex_clip_range: ClipAddressRange::new(complex_clip_count),
|
||||
layer_clip_range: ClipAddressRange::new(layer_clip_count),
|
||||
image,
|
||||
border_corners,
|
||||
bounds: MaskBounds {
|
||||
inner: None,
|
||||
outer: None,
|
||||
},
|
||||
item_count: complex_clip_count,
|
||||
};
|
||||
|
||||
Some(MaskCacheInfo {
|
||||
complex_clip_range: complex_clip_range,
|
||||
effective_complex_clip_count: complex_clip_range.item_count,
|
||||
image: image,
|
||||
border_corners: border_corners,
|
||||
bounds: None,
|
||||
is_aligned: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self,
|
||||
sources: &[ClipSource],
|
||||
transform: &LayerToWorldTransform,
|
||||
clip_store: &mut VertexDataStore<GpuBlock32>,
|
||||
device_pixel_ratio: f32,
|
||||
display_list: &BuiltDisplayList) {
|
||||
let is_aligned = transform.preserves_2d_axis_alignment();
|
||||
gpu_cache: &mut GpuCache,
|
||||
device_pixel_ratio: f32)
|
||||
-> &MaskBounds {
|
||||
|
||||
// If we haven't cached this info, or if the transform type has changed
|
||||
// we need to re-calculate the number of clips.
|
||||
if self.bounds.is_none() || self.is_aligned != is_aligned {
|
||||
// Step[1] - compute the local bounds
|
||||
//TODO: move to initialization stage?
|
||||
if self.bounds.inner.is_none() {
|
||||
let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP),
|
||||
LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP)));
|
||||
let mut local_inner: Option<LayerRect> = None;
|
||||
let mut has_clip_out = false;
|
||||
let mut has_border_clip = false;
|
||||
|
||||
self.effective_complex_clip_count = 0;
|
||||
self.is_aligned = is_aligned;
|
||||
let has_border_clip = !self.border_corners.is_empty();
|
||||
|
||||
for source in sources {
|
||||
match *source {
|
||||
@ -214,48 +248,25 @@ impl MaskCacheInfo {
|
||||
// case clip mask size, for now.
|
||||
if mode == ClipMode::ClipOut {
|
||||
has_clip_out = true;
|
||||
break;
|
||||
}
|
||||
debug_assert!(self.effective_complex_clip_count < self.complex_clip_range.item_count);
|
||||
let address = self.complex_clip_range.start + self.effective_complex_clip_count * CLIP_DATA_GPU_SIZE;
|
||||
self.effective_complex_clip_count += 1;
|
||||
|
||||
let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
|
||||
let data = ClipData::uniform(rect, radius, mode);
|
||||
PrimitiveStore::populate_clip_data(slice, data);
|
||||
local_rect = local_rect.and_then(|r| r.intersection(&rect));
|
||||
local_inner = ComplexClipRegion::new(rect, BorderRadius::uniform(radius))
|
||||
.get_inner_rect_safe();
|
||||
}
|
||||
ClipSource::Region(ref region, region_mode) => {
|
||||
ClipSource::Region(ref region) => {
|
||||
local_rect = local_rect.and_then(|r| r.intersection(®ion.main));
|
||||
local_inner = match region.image_mask {
|
||||
Some(ref mask) if !mask.repeat => {
|
||||
local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
|
||||
Some(ref mask) => {
|
||||
if !mask.repeat {
|
||||
local_rect = local_rect.and_then(|r| r.intersection(&mask.rect));
|
||||
}
|
||||
None
|
||||
},
|
||||
Some(_) => None,
|
||||
None => local_rect,
|
||||
};
|
||||
|
||||
let clips = display_list.get(region.complex_clips);
|
||||
if !self.is_aligned && region_mode == RegionMode::IncludeRect {
|
||||
// we have an extra clip rect coming from the transformed layer
|
||||
debug_assert!(self.effective_complex_clip_count < self.complex_clip_range.item_count);
|
||||
let address = self.complex_clip_range.start + self.effective_complex_clip_count * CLIP_DATA_GPU_SIZE;
|
||||
self.effective_complex_clip_count += 1;
|
||||
|
||||
let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE);
|
||||
PrimitiveStore::populate_clip_data(slice, ClipData::uniform(region.main, 0.0, ClipMode::Clip));
|
||||
}
|
||||
|
||||
debug_assert!(self.effective_complex_clip_count + clips.len() <= self.complex_clip_range.item_count);
|
||||
let address = self.complex_clip_range.start + self.effective_complex_clip_count * CLIP_DATA_GPU_SIZE;
|
||||
self.effective_complex_clip_count += clips.len();
|
||||
|
||||
let slice = clip_store.get_slice_mut(address, CLIP_DATA_GPU_SIZE * clips.len());
|
||||
for (clip, chunk) in clips.zip(slice.chunks_mut(CLIP_DATA_GPU_SIZE)) {
|
||||
let data = ClipData::from_clip_region(&clip);
|
||||
PrimitiveStore::populate_clip_data(chunk, data);
|
||||
for clip in ®ion.complex_clips {
|
||||
local_rect = local_rect.and_then(|r| r.intersection(&clip.rect));
|
||||
local_inner = local_inner.and_then(|r| clip.get_inner_rect_safe()
|
||||
.and_then(|ref inner| r.intersection(inner)));
|
||||
@ -265,26 +276,14 @@ impl MaskCacheInfo {
|
||||
}
|
||||
}
|
||||
|
||||
for &mut (ref mut source, gpu_address) in &mut self.border_corners {
|
||||
has_border_clip = true;
|
||||
let slice = clip_store.get_slice_mut(gpu_address,
|
||||
1 + source.max_clip_count);
|
||||
source.populate_gpu_data(slice);
|
||||
}
|
||||
|
||||
if let Some((ref mask, gpu_address)) = self.image {
|
||||
let mask_data = clip_store.get_slice_mut(gpu_address, MASK_DATA_GPU_SIZE);
|
||||
mask_data[0] = GpuBlock32::from(ImageMaskData {
|
||||
padding: DeviceRect::zero(),
|
||||
local_rect: mask.rect,
|
||||
});
|
||||
}
|
||||
|
||||
// Work out the type of mask geometry we have, based on the
|
||||
// list of clip sources above.
|
||||
if has_clip_out || has_border_clip {
|
||||
self.bounds = if has_clip_out || has_border_clip {
|
||||
// For clip-out, the mask rect is not known.
|
||||
self.bounds = Some(MaskBounds::None);
|
||||
MaskBounds {
|
||||
outer: None,
|
||||
inner: Some(LayerRect::zero().into()),
|
||||
}
|
||||
} else {
|
||||
// TODO(gw): local inner is only valid if there's a single clip (for now).
|
||||
// This can be improved in the future, with some proper
|
||||
@ -293,40 +292,81 @@ impl MaskCacheInfo {
|
||||
local_inner = None;
|
||||
}
|
||||
|
||||
let local_rect = local_rect.unwrap_or(LayerRect::zero());
|
||||
MaskBounds {
|
||||
outer: Some(local_rect.unwrap_or(LayerRect::zero()).into()),
|
||||
inner: Some(local_inner.unwrap_or(LayerRect::zero()).into()),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
self.bounds = match local_inner {
|
||||
Some(local_inner) => {
|
||||
Some(MaskBounds::OuterInner(Geometry::new(local_rect),
|
||||
Geometry::new(local_inner)))
|
||||
// Step[2] - update GPU cache data
|
||||
|
||||
if let Some(block_count) = self.complex_clip_range.get_block_count() {
|
||||
if let Some(mut request) = gpu_cache.request(&mut self.complex_clip_range.location) {
|
||||
for source in sources {
|
||||
match *source {
|
||||
ClipSource::Complex(rect, radius, mode) => {
|
||||
let data = ClipData::uniform(rect, radius, mode);
|
||||
data.write(&mut request);
|
||||
}
|
||||
ClipSource::Region(ref region) => {
|
||||
for clip in ®ion.complex_clips {
|
||||
let data = ClipData::from_clip_region(&clip);
|
||||
data.write(&mut request);
|
||||
}
|
||||
}
|
||||
ClipSource::BorderCorner{..} => {}
|
||||
}
|
||||
None => {
|
||||
Some(MaskBounds::Outer(Geometry::new(local_rect)))
|
||||
}
|
||||
assert_eq!(request.close(), block_count);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(block_count) = self.layer_clip_range.get_block_count() {
|
||||
if let Some(mut request) = gpu_cache.request(&mut self.layer_clip_range.location) {
|
||||
for source in sources {
|
||||
if let ClipSource::Region(ref region) = *source {
|
||||
let data = ClipData::uniform(region.main, 0.0, ClipMode::Clip);
|
||||
data.write(&mut request);
|
||||
}
|
||||
}
|
||||
assert_eq!(request.close(), block_count);
|
||||
}
|
||||
}
|
||||
|
||||
for &mut (ref mut border_source, ref mut gpu_location) in &mut self.border_corners {
|
||||
if let Some(request) = gpu_cache.request(gpu_location) {
|
||||
border_source.write(request);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((ref mask, ref mut gpu_location)) = self.image {
|
||||
if let Some(request) = gpu_cache.request(gpu_location) {
|
||||
let data = ImageMaskData {
|
||||
local_rect: mask.rect,
|
||||
};
|
||||
data.write_gpu_blocks(request);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the device space bounding rects of the mask
|
||||
// geometry.
|
||||
match self.bounds.as_mut().unwrap() {
|
||||
&mut MaskBounds::None => {}
|
||||
&mut MaskBounds::Outer(ref mut outer) => {
|
||||
outer.update(transform, device_pixel_ratio);
|
||||
}
|
||||
&mut MaskBounds::OuterInner(ref mut outer, ref mut inner) => {
|
||||
outer.update(transform, device_pixel_ratio);
|
||||
inner.update(transform, device_pixel_ratio);
|
||||
}
|
||||
}
|
||||
// Step[3] - update the screen bounds
|
||||
self.bounds.update(transform, device_pixel_ratio);
|
||||
&self.bounds
|
||||
}
|
||||
|
||||
/// Check if this `MaskCacheInfo` actually carries any masks. `effective_complex_clip_count`
|
||||
/// can change during the `update` call depending on the transformation, so the mask may
|
||||
/// appear to be empty.
|
||||
/// Check if this `MaskCacheInfo` actually carries any masks.
|
||||
pub fn is_masking(&self) -> bool {
|
||||
self.image.is_some() ||
|
||||
self.effective_complex_clip_count != 0 ||
|
||||
self.complex_clip_range.item_count != 0 ||
|
||||
self.layer_clip_range.item_count != 0 ||
|
||||
!self.border_corners.is_empty()
|
||||
}
|
||||
|
||||
/// Return a clone of this object without any layer-aligned clip items
|
||||
pub fn strip_aligned(&self) -> Self {
|
||||
MaskCacheInfo {
|
||||
layer_clip_range: ClipAddressRange::new(0),
|
||||
.. self.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,9 @@ use core_text::font_descriptor::kCTFontDefaultOrientation;
|
||||
use core_text;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use webrender_traits::{ColorU, FontKey, FontRenderMode, GlyphDimensions};
|
||||
use webrender_traits::{GlyphKey, GlyphOptions, SubpixelPoint};
|
||||
use webrender_traits::NativeFontHandle;
|
||||
use api::{ColorU, FontKey, FontRenderMode, GlyphDimensions};
|
||||
use api::{GlyphKey, GlyphOptions, SubpixelPoint};
|
||||
use api::NativeFontHandle;
|
||||
use gamma_lut::{GammaLut, Color as ColorLut};
|
||||
|
||||
pub struct FontContext {
|
||||
|
@ -3,9 +3,9 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use app_units::Au;
|
||||
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};
|
||||
use webrender_traits::{NativeFontHandle, GlyphOptions};
|
||||
use webrender_traits::{GlyphKey};
|
||||
use api::{FontKey, FontRenderMode, GlyphDimensions};
|
||||
use api::{NativeFontHandle, GlyphOptions};
|
||||
use api::{GlyphKey};
|
||||
|
||||
use freetype::freetype::{FT_Render_Mode, FT_Pixel_Mode};
|
||||
use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter};
|
||||
@ -65,7 +65,7 @@ impl FontContext {
|
||||
}
|
||||
|
||||
FontContext {
|
||||
lib: lib,
|
||||
lib,
|
||||
faces: HashMap::new(),
|
||||
}
|
||||
}
|
||||
@ -86,7 +86,7 @@ impl FontContext {
|
||||
};
|
||||
if result.succeeded() && !face.is_null() {
|
||||
self.faces.insert(*font_key, Face {
|
||||
face: face,
|
||||
face,
|
||||
//_bytes: bytes
|
||||
});
|
||||
} else {
|
||||
|
@ -3,8 +3,8 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::collections::HashMap;
|
||||
use webrender_traits::{FontKey, FontRenderMode, GlyphDimensions};
|
||||
use webrender_traits::{GlyphKey, GlyphOptions};
|
||||
use api::{FontKey, FontRenderMode, GlyphDimensions};
|
||||
use api::{GlyphKey, GlyphOptions};
|
||||
use gamma_lut::{GammaLut, Color as ColorLut};
|
||||
|
||||
use dwrote;
|
||||
@ -103,8 +103,8 @@ fn get_glyph_dimensions_with_analysis(analysis: dwrote::GlyphRunAnalysis,
|
||||
Some(GlyphDimensions {
|
||||
left: bounds.left,
|
||||
top: -bounds.top,
|
||||
width: width,
|
||||
height: height,
|
||||
width,
|
||||
height,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -2,30 +2,53 @@
|
||||
* 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::{BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect, DeviceIntSize, DevicePoint};
|
||||
use api::{ExtendMode, FontKey, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop};
|
||||
use api::{ImageKey, ImageRendering, ItemRange, LayerPoint, LayerRect, LayerSize};
|
||||
use api::{LayerToWorldTransform, TileOffset, WebGLContextId, YuvColorSpace, YuvFormat};
|
||||
use api::device_length;
|
||||
use app_units::Au;
|
||||
use border::{BorderCornerClipData, BorderCornerDashClipData, BorderCornerDotClipData};
|
||||
use border::BorderCornerInstance;
|
||||
use euclid::{Size2D};
|
||||
use gpu_cache::{GpuCacheAddress, GpuBlockData, GpuCache, GpuCacheHandle, GpuDataRequest, ToGpuBlocks};
|
||||
use gpu_store::GpuStoreAddress;
|
||||
use mask_cache::{ClipMode, ClipSource, MaskCacheInfo};
|
||||
use renderer::{VertexDataStore, MAX_VERTEX_TEXTURE_WIDTH};
|
||||
use mask_cache::{ClipMode, ClipRegion, ClipSource, MaskCacheInfo};
|
||||
use renderer::MAX_VERTEX_TEXTURE_WIDTH;
|
||||
use render_task::{RenderTask, RenderTaskLocation};
|
||||
use resource_cache::{ImageProperties, ResourceCache};
|
||||
use std::mem;
|
||||
use std::usize;
|
||||
use std::{mem, usize};
|
||||
use util::{TransformedRect, recycle_vec};
|
||||
use webrender_traits::{BuiltDisplayList, ColorF, ImageKey, ImageRendering, YuvColorSpace};
|
||||
use webrender_traits::{YuvFormat, ClipRegion, ComplexClipRegion, ItemRange};
|
||||
use webrender_traits::{FontKey, FontRenderMode, WebGLContextId};
|
||||
use webrender_traits::{device_length, DeviceIntRect, DeviceIntSize};
|
||||
use webrender_traits::{DeviceRect, DevicePoint};
|
||||
use webrender_traits::{LayerRect, LayerSize, LayerPoint};
|
||||
use webrender_traits::{LayerToWorldTransform, GlyphInstance, GlyphOptions};
|
||||
use webrender_traits::{ExtendMode, GradientStop, TileOffset};
|
||||
|
||||
pub const CLIP_DATA_GPU_SIZE: usize = 5;
|
||||
pub const MASK_DATA_GPU_SIZE: usize = 1;
|
||||
|
||||
pub const CLIP_DATA_GPU_BLOCKS: usize = 10;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct PrimitiveOpacity {
|
||||
pub is_opaque: bool,
|
||||
}
|
||||
|
||||
impl PrimitiveOpacity {
|
||||
pub fn opaque() -> PrimitiveOpacity {
|
||||
PrimitiveOpacity {
|
||||
is_opaque: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translucent() -> PrimitiveOpacity {
|
||||
PrimitiveOpacity {
|
||||
is_opaque: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_alpha(alpha: f32) -> PrimitiveOpacity {
|
||||
PrimitiveOpacity {
|
||||
is_opaque: alpha == 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accumulate(&mut self, alpha: f32) {
|
||||
self.is_opaque = self.is_opaque && alpha == 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores two coordinates in texel space. The coordinates
|
||||
/// are stored in texel coordinates because the texture atlas
|
||||
@ -114,7 +137,7 @@ impl GpuCacheHandle {
|
||||
// TODO(gw): Pack the fields here better!
|
||||
#[derive(Debug)]
|
||||
pub struct PrimitiveMetadata {
|
||||
pub is_opaque: bool,
|
||||
pub opacity: PrimitiveOpacity,
|
||||
pub clips: Vec<ClipSource>,
|
||||
pub clip_cache_info: Option<MaskCacheInfo>,
|
||||
pub prim_kind: PrimitiveKind,
|
||||
@ -152,7 +175,7 @@ pub struct RectanglePrimitive {
|
||||
|
||||
impl ToGpuBlocks for RectanglePrimitive {
|
||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||
request.push(self.color.into());
|
||||
request.push(self.color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,15 +252,15 @@ pub struct BoxShadowPrimitiveCpu {
|
||||
|
||||
impl ToGpuBlocks for BoxShadowPrimitiveCpu {
|
||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||
request.push(self.src_rect.into());
|
||||
request.push(self.bs_rect.into());
|
||||
request.push(self.color.into());
|
||||
request.push(self.src_rect);
|
||||
request.push(self.bs_rect);
|
||||
request.push(self.color);
|
||||
request.push([self.border_radius,
|
||||
self.edge_size,
|
||||
self.blur_radius,
|
||||
self.inverted].into());
|
||||
self.inverted]);
|
||||
for &rect in &self.rects {
|
||||
request.push(rect.into());
|
||||
request.push(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -254,14 +277,18 @@ pub struct GradientPrimitiveCpu {
|
||||
impl GradientPrimitiveCpu {
|
||||
fn build_gpu_blocks_for_aligned(&self,
|
||||
display_list: &BuiltDisplayList,
|
||||
mut request: GpuDataRequest) {
|
||||
mut request: GpuDataRequest) -> PrimitiveOpacity {
|
||||
let mut opacity = PrimitiveOpacity::opaque();
|
||||
request.extend_from_slice(&self.gpu_blocks);
|
||||
let src_stops = display_list.get(self.stops_range);
|
||||
|
||||
for src in src_stops {
|
||||
request.push(src.color.premultiplied().into());
|
||||
request.push([src.offset, 0.0, 0.0, 0.0].into());
|
||||
request.push(src.color.premultiplied());
|
||||
request.push([src.offset, 0.0, 0.0, 0.0]);
|
||||
opacity.accumulate(src.color.a);
|
||||
}
|
||||
|
||||
opacity
|
||||
}
|
||||
|
||||
fn build_gpu_blocks_for_angle_radial(&self,
|
||||
@ -307,8 +334,8 @@ impl<'a> GradientGpuBlockBuilder<'a> {
|
||||
fn new(stops_range: ItemRange<GradientStop>,
|
||||
display_list: &'a BuiltDisplayList) -> GradientGpuBlockBuilder<'a> {
|
||||
GradientGpuBlockBuilder {
|
||||
stops_range: stops_range,
|
||||
display_list: display_list,
|
||||
stops_range,
|
||||
display_list,
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,8 +453,8 @@ impl<'a> GradientGpuBlockBuilder<'a> {
|
||||
}
|
||||
|
||||
for entry in entries.iter() {
|
||||
request.push(entry.start_color.into());
|
||||
request.push(entry.end_color.into());
|
||||
request.push(entry.start_color);
|
||||
request.push(entry.end_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -436,7 +463,6 @@ impl<'a> GradientGpuBlockBuilder<'a> {
|
||||
pub struct RadialGradientPrimitiveCpu {
|
||||
pub stops_range: ItemRange<GradientStop>,
|
||||
pub extend_mode: ExtendMode,
|
||||
pub gpu_data_address: GpuStoreAddress,
|
||||
pub gpu_data_count: i32,
|
||||
pub gpu_blocks: [GpuBlockData; 3],
|
||||
}
|
||||
@ -469,7 +495,7 @@ pub struct TextRunPrimitiveCpu {
|
||||
|
||||
impl ToGpuBlocks for TextRunPrimitiveCpu {
|
||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||
request.push(self.color.into());
|
||||
request.push(self.color);
|
||||
|
||||
// Two glyphs are packed per GPU block.
|
||||
for glyph_chunk in self.glyph_instances.chunks(2) {
|
||||
@ -481,7 +507,7 @@ impl ToGpuBlocks for TextRunPrimitiveCpu {
|
||||
request.push([first_glyph.point.x,
|
||||
first_glyph.point.y,
|
||||
second_glyph.point.x,
|
||||
second_glyph.point.y].into());
|
||||
second_glyph.point.y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -498,7 +524,6 @@ struct GlyphPrimitive {
|
||||
struct ClipRect {
|
||||
rect: LayerRect,
|
||||
mode: f32,
|
||||
padding: [f32; 3],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -511,10 +536,23 @@ struct ClipCorner {
|
||||
inner_radius_y: f32,
|
||||
}
|
||||
|
||||
impl ToGpuBlocks for ClipCorner {
|
||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||
self.write(&mut request)
|
||||
}
|
||||
}
|
||||
|
||||
impl ClipCorner {
|
||||
fn write(&self, request: &mut GpuDataRequest) {
|
||||
request.push(self.rect);
|
||||
request.push([self.outer_radius_x, self.outer_radius_y,
|
||||
self.inner_radius_x, self.inner_radius_y,
|
||||
]);
|
||||
}
|
||||
|
||||
fn uniform(rect: LayerRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
|
||||
ClipCorner {
|
||||
rect: rect,
|
||||
rect,
|
||||
outer_radius_x: outer_radius,
|
||||
outer_radius_y: outer_radius,
|
||||
inner_radius_x: inner_radius,
|
||||
@ -527,7 +565,12 @@ impl ClipCorner {
|
||||
#[repr(C)]
|
||||
pub struct ImageMaskData {
|
||||
pub local_rect: LayerRect,
|
||||
pub padding: DeviceRect,
|
||||
}
|
||||
|
||||
impl ToGpuBlocks for ImageMaskData {
|
||||
fn write_gpu_blocks(&self, mut request: GpuDataRequest) {
|
||||
request.push(self.local_rect);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -544,7 +587,6 @@ impl ClipData {
|
||||
ClipData {
|
||||
rect: ClipRect {
|
||||
rect: clip.rect,
|
||||
padding: [0.0; 3],
|
||||
// TODO(gw): Support other clip modes for regions?
|
||||
mode: ClipMode::Clip as u32 as f32,
|
||||
},
|
||||
@ -591,8 +633,7 @@ impl ClipData {
|
||||
pub fn uniform(rect: LayerRect, radius: f32, mode: ClipMode) -> ClipData {
|
||||
ClipData {
|
||||
rect: ClipRect {
|
||||
rect: rect,
|
||||
padding: [0.0; 3],
|
||||
rect,
|
||||
mode: mode as u32 as f32,
|
||||
},
|
||||
top_left: ClipCorner::uniform(
|
||||
@ -617,6 +658,14 @@ impl ClipData {
|
||||
radius, 0.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, request: &mut GpuDataRequest) {
|
||||
request.push(self.rect.rect);
|
||||
request.push([self.rect.mode, 0.0, 0.0, 0.0]);
|
||||
for corner in &[&self.top_left, &self.top_right, &self.bottom_left, &self.bottom_right] {
|
||||
corner.write(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -644,9 +693,6 @@ pub struct PrimitiveStore {
|
||||
pub cpu_metadata: Vec<PrimitiveMetadata>,
|
||||
pub cpu_borders: Vec<BorderPrimitiveCpu>,
|
||||
pub cpu_box_shadows: Vec<BoxShadowPrimitiveCpu>,
|
||||
|
||||
/// Gets uploaded directly to GPU via vertex texture.
|
||||
pub gpu_data32: VertexDataStore<GpuBlock32>,
|
||||
}
|
||||
|
||||
impl PrimitiveStore {
|
||||
@ -662,7 +708,6 @@ impl PrimitiveStore {
|
||||
cpu_radial_gradients: Vec::new(),
|
||||
cpu_borders: Vec::new(),
|
||||
cpu_box_shadows: Vec::new(),
|
||||
gpu_data32: VertexDataStore::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,18 +723,9 @@ impl PrimitiveStore {
|
||||
cpu_radial_gradients: recycle_vec(self.cpu_radial_gradients),
|
||||
cpu_borders: recycle_vec(self.cpu_borders),
|
||||
cpu_box_shadows: recycle_vec(self.cpu_box_shadows),
|
||||
gpu_data32: self.gpu_data32.recycle(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn populate_clip_data(data: &mut [GpuBlock32], clip: ClipData) {
|
||||
data[0] = GpuBlock32::from(clip.rect);
|
||||
data[1] = GpuBlock32::from(clip.top_left);
|
||||
data[2] = GpuBlock32::from(clip.top_right);
|
||||
data[3] = GpuBlock32::from(clip.bottom_left);
|
||||
data[4] = GpuBlock32::from(clip.bottom_right);
|
||||
}
|
||||
|
||||
pub fn add_primitive(&mut self,
|
||||
local_rect: &LayerRect,
|
||||
local_clip_rect: &LayerRect,
|
||||
@ -701,11 +737,9 @@ impl PrimitiveStore {
|
||||
|
||||
let metadata = match container {
|
||||
PrimitiveContainer::Rectangle(rect) => {
|
||||
let is_opaque = rect.color.a == 1.0;
|
||||
|
||||
let metadata = PrimitiveMetadata {
|
||||
is_opaque: is_opaque,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::from_alpha(rect.color.a),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::Rectangle,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_rectangles.len()),
|
||||
@ -722,8 +756,8 @@ impl PrimitiveStore {
|
||||
}
|
||||
PrimitiveContainer::TextRun(text_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
is_opaque: false,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::TextRun,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_runs.len()),
|
||||
@ -739,8 +773,8 @@ impl PrimitiveStore {
|
||||
}
|
||||
PrimitiveContainer::Image(image_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
is_opaque: false,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::Image,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_images.len()),
|
||||
@ -756,8 +790,8 @@ impl PrimitiveStore {
|
||||
}
|
||||
PrimitiveContainer::YuvImage(image_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
is_opaque: true,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::opaque(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::YuvImage,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_yuv_images.len()),
|
||||
@ -773,8 +807,8 @@ impl PrimitiveStore {
|
||||
}
|
||||
PrimitiveContainer::Border(border_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
is_opaque: false,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::Border,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_borders.len()),
|
||||
@ -790,9 +824,8 @@ impl PrimitiveStore {
|
||||
}
|
||||
PrimitiveContainer::AlignedGradient(gradient_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
// TODO: calculate if the gradient is actually opaque
|
||||
is_opaque: false,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::AlignedGradient,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()),
|
||||
@ -809,8 +842,8 @@ impl PrimitiveStore {
|
||||
PrimitiveContainer::AngleGradient(gradient_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
// TODO: calculate if the gradient is actually opaque
|
||||
is_opaque: false,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::AngleGradient,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()),
|
||||
@ -827,8 +860,8 @@ impl PrimitiveStore {
|
||||
PrimitiveContainer::RadialGradient(radial_gradient_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
// TODO: calculate if the gradient is actually opaque
|
||||
is_opaque: false,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::RadialGradient,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_radial_gradients.len()),
|
||||
@ -869,8 +902,8 @@ impl PrimitiveStore {
|
||||
PrimitiveIndex(prim_index));
|
||||
|
||||
let metadata = PrimitiveMetadata {
|
||||
is_opaque: false,
|
||||
clips: clips,
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
clips,
|
||||
clip_cache_info: clip_info,
|
||||
prim_kind: PrimitiveKind::BoxShadow,
|
||||
cpu_prim_index: SpecificPrimitiveIndex(self.cpu_box_shadows.len()),
|
||||
@ -904,21 +937,21 @@ impl PrimitiveStore {
|
||||
screen_rect: &DeviceIntRect,
|
||||
layer_transform: &LayerToWorldTransform,
|
||||
layer_combined_local_clip_rect: &LayerRect,
|
||||
device_pixel_ratio: f32) -> bool {
|
||||
device_pixel_ratio: f32) -> Option<(LayerRect, DeviceIntRect)> {
|
||||
let metadata = &self.cpu_metadata[prim_index.0];
|
||||
let local_rect = metadata.local_rect
|
||||
.intersection(&metadata.local_clip_rect)
|
||||
.and_then(|rect| rect.intersection(layer_combined_local_clip_rect));
|
||||
|
||||
let bounding_rect = metadata.local_rect
|
||||
.intersection(&metadata.local_clip_rect)
|
||||
.and_then(|rect| rect.intersection(layer_combined_local_clip_rect))
|
||||
.and_then(|ref local_rect| {
|
||||
let xf_rect = TransformedRect::new(local_rect,
|
||||
let bounding_rect = local_rect.and_then(|local_rect| {
|
||||
let xf_rect = TransformedRect::new(&local_rect,
|
||||
layer_transform,
|
||||
device_pixel_ratio);
|
||||
xf_rect.bounding_rect.intersection(screen_rect)
|
||||
});
|
||||
|
||||
self.cpu_bounding_rects[prim_index.0] = bounding_rect;
|
||||
bounding_rect.is_some()
|
||||
bounding_rect.map(|screen_bound| (local_rect.unwrap(), screen_bound))
|
||||
}
|
||||
|
||||
/// Returns true if the bounding box needs to be updated.
|
||||
@ -928,16 +961,17 @@ impl PrimitiveStore {
|
||||
gpu_cache: &mut GpuCache,
|
||||
layer_transform: &LayerToWorldTransform,
|
||||
device_pixel_ratio: f32,
|
||||
display_list: &BuiltDisplayList) {
|
||||
display_list: &BuiltDisplayList)
|
||||
-> &mut PrimitiveMetadata {
|
||||
|
||||
let metadata = &mut self.cpu_metadata[prim_index.0];
|
||||
|
||||
if let Some(ref mut clip_info) = metadata.clip_cache_info {
|
||||
clip_info.update(&metadata.clips,
|
||||
layer_transform,
|
||||
&mut self.gpu_data32,
|
||||
device_pixel_ratio,
|
||||
display_list);
|
||||
clip_info.update(&metadata.clips, layer_transform, gpu_cache, device_pixel_ratio);
|
||||
|
||||
//TODO-LCCR: we could tighten up the `local_clip_rect` here
|
||||
// but that would require invalidating the whole GPU block
|
||||
|
||||
for clip in &metadata.clips {
|
||||
if let ClipSource::Region(ClipRegion{ image_mask: Some(ref mask), .. }, ..) = *clip {
|
||||
resource_cache.request_image(mask.image, ImageRendering::Auto, None);
|
||||
@ -1020,9 +1054,9 @@ impl PrimitiveStore {
|
||||
// right now, but if we introduce a cache for images for some other
|
||||
// reason then we might as well cache this with it.
|
||||
let image_properties = resource_cache.get_image_properties(image_key);
|
||||
metadata.is_opaque = image_properties.descriptor.is_opaque &&
|
||||
tile_spacing.width == 0.0 &&
|
||||
tile_spacing.height == 0.0;
|
||||
metadata.opacity.is_opaque = image_properties.descriptor.is_opaque &&
|
||||
tile_spacing.width == 0.0 &&
|
||||
tile_spacing.height == 0.0;
|
||||
}
|
||||
ImagePrimitiveKind::WebGL(..) => {}
|
||||
}
|
||||
@ -1035,9 +1069,6 @@ impl PrimitiveStore {
|
||||
for channel in 0..channel_num {
|
||||
resource_cache.request_image(image_cpu.yuv_key[channel], image_cpu.image_rendering, None);
|
||||
}
|
||||
|
||||
// TODO(nical): Currently assuming no tile_spacing for yuv images.
|
||||
metadata.is_opaque = true;
|
||||
}
|
||||
PrimitiveKind::AlignedGradient |
|
||||
PrimitiveKind::AngleGradient |
|
||||
@ -1046,8 +1077,8 @@ impl PrimitiveStore {
|
||||
|
||||
// Mark this GPU resource as required for this frame.
|
||||
if let Some(mut request) = gpu_cache.request(&mut metadata.gpu_location) {
|
||||
request.push(metadata.local_rect.into());
|
||||
request.push(metadata.local_clip_rect.into());
|
||||
request.push(metadata.local_rect);
|
||||
request.push(metadata.local_clip_rect);
|
||||
|
||||
match metadata.prim_kind {
|
||||
PrimitiveKind::Rectangle => {
|
||||
@ -1072,8 +1103,8 @@ impl PrimitiveStore {
|
||||
}
|
||||
PrimitiveKind::AlignedGradient => {
|
||||
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
|
||||
gradient.build_gpu_blocks_for_aligned(display_list,
|
||||
request);
|
||||
metadata.opacity = gradient.build_gpu_blocks_for_aligned(display_list,
|
||||
request);
|
||||
}
|
||||
PrimitiveKind::AngleGradient => {
|
||||
let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0];
|
||||
@ -1091,41 +1122,12 @@ impl PrimitiveStore {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
metadata
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! define_gpu_block {
|
||||
($name:ident: $ty:ty = $($derive:ident),* ) => (
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct $name {
|
||||
data: $ty,
|
||||
}
|
||||
|
||||
impl Default for $name {
|
||||
fn default() -> $name {
|
||||
$name {
|
||||
data: unsafe { mem::uninitialized() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$(
|
||||
impl From<$derive> for $name {
|
||||
fn from(data: $derive) -> $name {
|
||||
unsafe { mem::transmute(data) }
|
||||
}
|
||||
}
|
||||
)*
|
||||
)
|
||||
}
|
||||
|
||||
define_gpu_block!(GpuBlock32: [f32; 8] =
|
||||
ClipCorner, ClipRect, ImageMaskData,
|
||||
BorderCornerClipData, BorderCornerDashClipData, BorderCornerDotClipData
|
||||
);
|
||||
|
||||
//Test for one clip region contains another
|
||||
trait InsideTest<T> {
|
||||
fn might_contain(&self, clip: &T) -> bool;
|
||||
|
@ -8,7 +8,7 @@ use euclid::{Point2D, Size2D, Rect, vec2};
|
||||
use std::collections::vec_deque::VecDeque;
|
||||
use std::f32;
|
||||
use std::mem;
|
||||
use webrender_traits::ColorF;
|
||||
use api::ColorF;
|
||||
use time::precise_time_ns;
|
||||
|
||||
const GRAPH_WIDTH: f32 = 1024.0;
|
||||
@ -45,7 +45,7 @@ pub struct IntProfileCounter {
|
||||
impl IntProfileCounter {
|
||||
fn new(description: &'static str) -> IntProfileCounter {
|
||||
IntProfileCounter {
|
||||
description: description,
|
||||
description,
|
||||
value: 0,
|
||||
}
|
||||
}
|
||||
@ -94,7 +94,7 @@ pub struct ResourceProfileCounter {
|
||||
impl ResourceProfileCounter {
|
||||
fn new(description: &'static str) -> ResourceProfileCounter {
|
||||
ResourceProfileCounter {
|
||||
description: description,
|
||||
description,
|
||||
value: 0,
|
||||
size: 0,
|
||||
}
|
||||
@ -134,9 +134,9 @@ pub struct TimeProfileCounter {
|
||||
impl TimeProfileCounter {
|
||||
pub fn new(description: &'static str, invert: bool) -> TimeProfileCounter {
|
||||
TimeProfileCounter {
|
||||
description: description,
|
||||
description,
|
||||
nanoseconds: 0,
|
||||
invert: invert,
|
||||
invert,
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,13 +195,13 @@ pub struct AverageTimeProfileCounter {
|
||||
impl AverageTimeProfileCounter {
|
||||
pub fn new(description: &'static str, invert: bool, average_over_ns: u64) -> AverageTimeProfileCounter {
|
||||
AverageTimeProfileCounter {
|
||||
description: description,
|
||||
average_over_ns: average_over_ns,
|
||||
description,
|
||||
average_over_ns,
|
||||
start_ns: precise_time_ns(),
|
||||
sum_ns: 0,
|
||||
num_samples: 0,
|
||||
nanoseconds: 0,
|
||||
invert: invert,
|
||||
invert,
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,7 +425,7 @@ struct ProfileGraph {
|
||||
impl ProfileGraph {
|
||||
fn new(max_samples: usize) -> ProfileGraph {
|
||||
ProfileGraph {
|
||||
max_samples: max_samples,
|
||||
max_samples,
|
||||
values: VecDeque::new(),
|
||||
}
|
||||
}
|
||||
@ -556,8 +556,8 @@ impl GpuFrameCollection {
|
||||
self.frames.pop_back();
|
||||
}
|
||||
self.frames.push_front(GpuFrame {
|
||||
total_time: total_time,
|
||||
samples: samples,
|
||||
total_time,
|
||||
samples,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use std::any::TypeId;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use webrender_traits::ApiMsg;
|
||||
use api::ApiMsg;
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
pub static WEBRENDER_RECORDING_HEADER: u64 = 0xbeefbeefbeefbe01u64;
|
||||
@ -37,7 +37,7 @@ impl BinaryRecorder {
|
||||
file.write_u64::<LittleEndian>(apimsg_type_id).ok();
|
||||
|
||||
BinaryRecorder {
|
||||
file: file,
|
||||
file,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ use profiler::{BackendProfileCounters, GpuCacheProfileCounters, TextureCacheProf
|
||||
use record::ApiRecordingReceiver;
|
||||
use resource_cache::ResourceCache;
|
||||
use scene::Scene;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::Sender;
|
||||
use texture_cache::TextureCache;
|
||||
@ -18,13 +18,13 @@ use time::precise_time_ns;
|
||||
use thread_profiler::register_thread_with_profiler;
|
||||
use rayon::ThreadPool;
|
||||
use webgl_types::{GLContextHandleWrapper, GLContextWrapper};
|
||||
use webrender_traits::channel::{MsgReceiver, PayloadReceiver, PayloadReceiverHelperMethods};
|
||||
use webrender_traits::channel::{PayloadSender, PayloadSenderHelperMethods};
|
||||
use webrender_traits::{ApiMsg, BlobImageRenderer, BuiltDisplayList, DeviceIntPoint};
|
||||
use webrender_traits::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, IdNamespace, ImageData};
|
||||
use webrender_traits::{LayerPoint, PipelineId, RenderDispatcher, RenderNotifier};
|
||||
use webrender_traits::{VRCompositorCommand, VRCompositorHandler, WebGLCommand, WebGLContextId};
|
||||
use webrender_traits::{FontTemplate};
|
||||
use api::channel::{MsgReceiver, PayloadReceiver, PayloadReceiverHelperMethods};
|
||||
use api::channel::{PayloadSender, PayloadSenderHelperMethods};
|
||||
use api::{ApiMsg, BlobImageRenderer, BuiltDisplayList, DeviceIntPoint};
|
||||
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, IdNamespace, ImageData};
|
||||
use api::{LayerPoint, PipelineId, RenderDispatcher, RenderNotifier};
|
||||
use api::{VRCompositorCommand, VRCompositorHandler, WebGLCommand, WebGLContextId};
|
||||
use api::{FontTemplate};
|
||||
|
||||
#[cfg(feature = "webgl")]
|
||||
use offscreen_gl_context::GLContextDispatcher;
|
||||
@ -60,13 +60,21 @@ pub struct RenderBackend {
|
||||
notifier: Arc<Mutex<Option<Box<RenderNotifier>>>>,
|
||||
webrender_context_handle: Option<GLContextHandleWrapper>,
|
||||
webgl_contexts: HashMap<WebGLContextId, GLContextWrapper>,
|
||||
dirty_webgl_contexts: HashSet<WebGLContextId>,
|
||||
current_bound_webgl_context_id: Option<WebGLContextId>,
|
||||
recorder: Option<Box<ApiRecordingReceiver>>,
|
||||
main_thread_dispatcher: Arc<Mutex<Option<Box<RenderDispatcher>>>>,
|
||||
|
||||
next_webgl_id: usize,
|
||||
|
||||
vr_compositor_handler: Arc<Mutex<Option<Box<VRCompositorHandler>>>>
|
||||
vr_compositor_handler: Arc<Mutex<Option<Box<VRCompositorHandler>>>>,
|
||||
|
||||
// A helper switch to prevent any frames rendering triggered by scrolling
|
||||
// messages between `SetDisplayList` and `GenerateFrame`.
|
||||
// If we allow them, then a reftest that scrolls a few layers before generating
|
||||
// the first frame would produce inconsistent rendering results, because
|
||||
// scroll events are not necessarily received in deterministic order.
|
||||
render_on_scroll: bool,
|
||||
}
|
||||
|
||||
impl RenderBackend {
|
||||
@ -91,29 +99,42 @@ impl RenderBackend {
|
||||
register_thread_with_profiler("Backend".to_string());
|
||||
|
||||
RenderBackend {
|
||||
api_rx: api_rx,
|
||||
payload_rx: payload_rx,
|
||||
payload_tx: payload_tx,
|
||||
result_tx: result_tx,
|
||||
hidpi_factor: hidpi_factor,
|
||||
api_rx,
|
||||
payload_rx,
|
||||
payload_tx,
|
||||
result_tx,
|
||||
hidpi_factor,
|
||||
page_zoom_factor: 1.0,
|
||||
pinch_zoom_factor: 1.0,
|
||||
pan: DeviceIntPoint::zero(),
|
||||
resource_cache: resource_cache,
|
||||
resource_cache,
|
||||
gpu_cache: GpuCache::new(),
|
||||
scene: Scene::new(),
|
||||
frame: Frame::new(config),
|
||||
next_namespace_id: IdNamespace(1),
|
||||
notifier: notifier,
|
||||
webrender_context_handle: webrender_context_handle,
|
||||
notifier,
|
||||
webrender_context_handle,
|
||||
webgl_contexts: HashMap::new(),
|
||||
dirty_webgl_contexts: HashSet::new(),
|
||||
current_bound_webgl_context_id: None,
|
||||
recorder: recorder,
|
||||
main_thread_dispatcher: main_thread_dispatcher,
|
||||
recorder,
|
||||
main_thread_dispatcher,
|
||||
next_webgl_id: 0,
|
||||
vr_compositor_handler: vr_compositor_handler,
|
||||
vr_compositor_handler,
|
||||
window_size: initial_window_size,
|
||||
inner_rect: DeviceUintRect::new(DeviceUintPoint::zero(), initial_window_size),
|
||||
render_on_scroll: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_frame(&mut self, frame_maybe: Option<RendererFrame>,
|
||||
profile_counters: &mut BackendProfileCounters) {
|
||||
match frame_maybe {
|
||||
Some(frame) => {
|
||||
self.publish_frame(frame, profile_counters);
|
||||
self.notify_compositor_of_new_scroll_frame(true)
|
||||
}
|
||||
None => self.notify_compositor_of_new_scroll_frame(false),
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,6 +253,8 @@ impl RenderBackend {
|
||||
self.build_scene();
|
||||
});
|
||||
|
||||
self.render_on_scroll = false; //wait for `GenerateFrame`
|
||||
|
||||
// Note: this isn't quite right as auxiliary values will be
|
||||
// pulled out somewhere in the prim_store, but aux values are
|
||||
// really simple and cheap to access, so it's not a big deal.
|
||||
@ -259,7 +282,7 @@ impl RenderBackend {
|
||||
let counters = &mut profile_counters.resources.texture_cache;
|
||||
let gpu_cache_counters = &mut profile_counters.resources.gpu_cache;
|
||||
profile_counters.total_time.profile(|| {
|
||||
if self.frame.scroll(delta, cursor, move_phase) {
|
||||
if self.frame.scroll(delta, cursor, move_phase) && self.render_on_scroll {
|
||||
Some(self.render(counters, gpu_cache_counters))
|
||||
} else {
|
||||
None
|
||||
@ -267,13 +290,7 @@ impl RenderBackend {
|
||||
})
|
||||
};
|
||||
|
||||
match frame {
|
||||
Some(frame) => {
|
||||
self.publish_frame(frame, &mut profile_counters);
|
||||
self.notify_compositor_of_new_scroll_frame(true)
|
||||
}
|
||||
None => self.notify_compositor_of_new_scroll_frame(false),
|
||||
}
|
||||
self.scroll_frame(frame, &mut profile_counters);
|
||||
}
|
||||
ApiMsg::ScrollNodeWithId(origin, id, clamp) => {
|
||||
profile_scope!("ScrollNodeWithScrollId");
|
||||
@ -281,7 +298,7 @@ impl RenderBackend {
|
||||
let counters = &mut profile_counters.resources.texture_cache;
|
||||
let gpu_cache_counters = &mut profile_counters.resources.gpu_cache;
|
||||
profile_counters.total_time.profile(|| {
|
||||
if self.frame.scroll_node(origin, id, clamp) {
|
||||
if self.frame.scroll_node(origin, id, clamp) && self.render_on_scroll {
|
||||
Some(self.render(counters, gpu_cache_counters))
|
||||
} else {
|
||||
None
|
||||
@ -289,14 +306,7 @@ impl RenderBackend {
|
||||
})
|
||||
};
|
||||
|
||||
match frame {
|
||||
Some(frame) => {
|
||||
self.publish_frame(frame, &mut profile_counters);
|
||||
self.notify_compositor_of_new_scroll_frame(true)
|
||||
}
|
||||
None => self.notify_compositor_of_new_scroll_frame(false),
|
||||
}
|
||||
|
||||
self.scroll_frame(frame, &mut profile_counters);
|
||||
}
|
||||
ApiMsg::TickScrollingBounce => {
|
||||
profile_scope!("TickScrollingBounce");
|
||||
@ -305,14 +315,18 @@ impl RenderBackend {
|
||||
let gpu_cache_counters = &mut profile_counters.resources.gpu_cache;
|
||||
profile_counters.total_time.profile(|| {
|
||||
self.frame.tick_scrolling_bounce_animations();
|
||||
self.render(counters, gpu_cache_counters)
|
||||
if self.render_on_scroll {
|
||||
Some(self.render(counters, gpu_cache_counters))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
self.publish_frame_and_notify_compositor(frame, &mut profile_counters);
|
||||
self.scroll_frame(frame, &mut profile_counters);
|
||||
}
|
||||
ApiMsg::TranslatePointToLayerSpace(..) => {
|
||||
panic!("unused api - remove from webrender_traits");
|
||||
panic!("unused api - remove from webrender_api");
|
||||
}
|
||||
ApiMsg::GetScrollNodeState(tx) => {
|
||||
profile_scope!("GetScrollNodeState");
|
||||
@ -345,6 +359,7 @@ impl RenderBackend {
|
||||
self.resource_cache
|
||||
.add_webgl_texture(id, SourceTexture::WebGL(texture_id),
|
||||
real_size);
|
||||
self.dirty_webgl_contexts.insert(id);
|
||||
|
||||
tx.send(Ok((id, limits))).unwrap();
|
||||
},
|
||||
@ -369,6 +384,7 @@ impl RenderBackend {
|
||||
self.resource_cache
|
||||
.update_webgl_texture(context_id, SourceTexture::WebGL(texture_id),
|
||||
real_size);
|
||||
self.dirty_webgl_contexts.insert(context_id);
|
||||
},
|
||||
Err(msg) => {
|
||||
error!("Error resizing WebGLContext: {}", msg);
|
||||
@ -384,6 +400,7 @@ impl RenderBackend {
|
||||
self.current_bound_webgl_context_id = Some(context_id);
|
||||
}
|
||||
ctx.apply_command(command);
|
||||
self.dirty_webgl_contexts.insert(context_id);
|
||||
},
|
||||
|
||||
ApiMsg::VRCompositorCommand(context_id, command) => {
|
||||
@ -392,6 +409,7 @@ impl RenderBackend {
|
||||
self.current_bound_webgl_context_id = Some(context_id);
|
||||
}
|
||||
self.handle_vr_compositor_command(context_id, command);
|
||||
self.dirty_webgl_contexts.insert(context_id);
|
||||
}
|
||||
ApiMsg::GenerateFrame(property_bindings) => {
|
||||
profile_scope!("GenerateFrame");
|
||||
@ -413,6 +431,8 @@ impl RenderBackend {
|
||||
});
|
||||
}
|
||||
|
||||
self.render_on_scroll = true;
|
||||
|
||||
let frame = {
|
||||
let counters = &mut profile_counters.resources.texture_cache;
|
||||
let gpu_cache_counters = &mut profile_counters.resources.gpu_cache;
|
||||
@ -476,10 +496,18 @@ impl RenderBackend {
|
||||
// implementations - a single flush for each webgl
|
||||
// context at the start of a render frame should
|
||||
// incur minimal cost.
|
||||
for (_, webgl_context) in &self.webgl_contexts {
|
||||
webgl_context.make_current();
|
||||
webgl_context.apply_command(WebGLCommand::Flush);
|
||||
webgl_context.unbind();
|
||||
// glFlush is not enough in some GPUs.
|
||||
// glFlush doesn't guarantee the completion of the GL commands when the shared texture is sampled.
|
||||
// This leads to some graphic glitches on some demos or even nothing being rendered at all (GPU Mali-T880).
|
||||
// glFinish guarantees the completion of the commands but it may hurt performance a lot.
|
||||
// Sync Objects are the recommended way to ensure that textures are ready in OpenGL 3.0+.
|
||||
// They are more performant than glFinish and guarantee the completion of the GL commands.
|
||||
for (id, webgl_context) in &self.webgl_contexts {
|
||||
if self.dirty_webgl_contexts.remove(&id) {
|
||||
webgl_context.make_current();
|
||||
webgl_context.apply_command(WebGLCommand::FenceAndWaitSync);
|
||||
webgl_context.unbind();
|
||||
}
|
||||
}
|
||||
|
||||
let accumulated_scale_factor = self.accumulated_scale_factor();
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
use gpu_cache::GpuCacheHandle;
|
||||
use internal_types::{HardwareCompositeOp, LowLevelFilterOp};
|
||||
use mask_cache::{MaskBounds, MaskCacheInfo};
|
||||
use mask_cache::MaskCacheInfo;
|
||||
use prim_store::{PrimitiveCacheKey, PrimitiveIndex};
|
||||
use std::{cmp, f32, i32, mem, usize};
|
||||
use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
|
||||
use tiling::{RenderTargetKind, StackingContextIndex};
|
||||
use webrender_traits::{ClipId, DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||
use webrender_traits::{MixBlendMode};
|
||||
use api::{ClipId, DeviceIntLength, DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
||||
use api::{MixBlendMode};
|
||||
|
||||
const FLOATS_PER_RENDER_TASK_INFO: usize = 12;
|
||||
|
||||
@ -84,22 +84,16 @@ pub enum MaskGeometryKind {
|
||||
// TODO(gw): Add more types here (e.g. 4 rectangles outside the inner rect)
|
||||
}
|
||||
|
||||
pub type ClipWorkItem = (PackedLayerIndex, MaskCacheInfo);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CacheMaskTask {
|
||||
actual_rect: DeviceIntRect,
|
||||
inner_rect: DeviceIntRect,
|
||||
pub clips: Vec<(PackedLayerIndex, MaskCacheInfo)>,
|
||||
pub clips: Vec<ClipWorkItem>,
|
||||
pub geometry_kind: MaskGeometryKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MaskResult {
|
||||
/// The mask is completely outside the region
|
||||
Outside,
|
||||
/// The mask is inside and needs to be processed
|
||||
Inside(RenderTask),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RenderTaskData {
|
||||
pub data: [f32; FLOATS_PER_RENDER_TASK_INFO],
|
||||
@ -149,9 +143,9 @@ impl RenderTask {
|
||||
RenderTask {
|
||||
id: RenderTaskId::Static(task_index),
|
||||
children: Vec::new(),
|
||||
location: location,
|
||||
location,
|
||||
kind: RenderTaskKind::Alpha(AlphaRenderTask {
|
||||
screen_origin: screen_origin,
|
||||
screen_origin,
|
||||
items: Vec::new(),
|
||||
}),
|
||||
}
|
||||
@ -184,57 +178,33 @@ impl RenderTask {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_mask(actual_rect: DeviceIntRect,
|
||||
pub fn new_mask(task_rect: DeviceIntRect,
|
||||
mask_key: MaskCacheKey,
|
||||
clips: &[(PackedLayerIndex, MaskCacheInfo)])
|
||||
-> MaskResult {
|
||||
if clips.is_empty() {
|
||||
return MaskResult::Outside;
|
||||
}
|
||||
|
||||
// We scan through the clip stack and detect if our actual rectangle
|
||||
// is in the intersection of all of all the outer bounds,
|
||||
// and if it's completely inside the intersection of all of the inner bounds.
|
||||
|
||||
// TODO(gw): If we encounter a clip with unknown bounds, we'll just use
|
||||
// the original rect. This is overly conservative, but can
|
||||
// be optimized later.
|
||||
let mut result = Some(actual_rect);
|
||||
for &(_, ref clip) in clips {
|
||||
match *clip.bounds.as_ref().unwrap() {
|
||||
MaskBounds::OuterInner(ref outer, _) |
|
||||
MaskBounds::Outer(ref outer) => {
|
||||
result = result.and_then(|rect| {
|
||||
rect.intersection(&outer.bounding_rect)
|
||||
});
|
||||
raw_clips: &[ClipWorkItem],
|
||||
extra_clip: Option<ClipWorkItem>)
|
||||
-> Option<RenderTask> {
|
||||
/// Filter out all the clip instances that don't contribute to the result
|
||||
let mut inner_rect = Some(task_rect);
|
||||
let clips: Vec<_> = raw_clips.iter()
|
||||
.chain(extra_clip.iter())
|
||||
.filter(|&&(_, ref clip_info)| {
|
||||
match clip_info.bounds.inner {
|
||||
Some(ref inner) if !inner.device_rect.is_empty() => {
|
||||
inner_rect = inner_rect.and_then(|r| r.intersection(&inner.device_rect));
|
||||
!inner.device_rect.contains_rect(&task_rect)
|
||||
}
|
||||
MaskBounds::None => {
|
||||
result = Some(actual_rect);
|
||||
break;
|
||||
_ => {
|
||||
inner_rect = None;
|
||||
true
|
||||
}
|
||||
}
|
||||
}).cloned().collect();
|
||||
|
||||
// Nothing to do, all clips are irrelevant for this case
|
||||
if clips.is_empty() {
|
||||
return None
|
||||
}
|
||||
|
||||
let task_rect = match result {
|
||||
None => return MaskResult::Outside,
|
||||
Some(rect) => rect,
|
||||
};
|
||||
|
||||
// Accumulate inner rects. As soon as we encounter
|
||||
// a clip mask where we don't have or don't know
|
||||
// the inner rect, this will become None.
|
||||
let inner_rect = clips.iter()
|
||||
.fold(Some(task_rect), |current, clip| {
|
||||
current.and_then(|rect| {
|
||||
let inner_rect = match *clip.1.bounds.as_ref().unwrap() {
|
||||
MaskBounds::Outer(..) |
|
||||
MaskBounds::None => DeviceIntRect::zero(),
|
||||
MaskBounds::OuterInner(_, ref inner) => inner.bounding_rect
|
||||
};
|
||||
rect.intersection(&inner_rect)
|
||||
})
|
||||
});
|
||||
|
||||
// TODO(gw): This optimization is very conservative for now.
|
||||
// For now, only draw optimized geometry if it is
|
||||
// a single aligned rect mask with rounded corners.
|
||||
@ -242,25 +212,24 @@ impl RenderTask {
|
||||
// more complex types of clip mask geometry.
|
||||
let mut geometry_kind = MaskGeometryKind::Default;
|
||||
if inner_rect.is_some() && clips.len() == 1 {
|
||||
let (_, ref clip_info) = clips[0];
|
||||
if clip_info.image.is_none() &&
|
||||
clip_info.effective_complex_clip_count == 1 &&
|
||||
clip_info.is_aligned {
|
||||
let (_, ref info) = clips[0];
|
||||
if info.border_corners.is_empty() &&
|
||||
info.image.is_none() &&
|
||||
info.complex_clip_range.get_count() == 1 &&
|
||||
info.layer_clip_range.get_count() == 0 {
|
||||
geometry_kind = MaskGeometryKind::CornersOnly;
|
||||
}
|
||||
}
|
||||
|
||||
let inner_rect = inner_rect.unwrap_or(DeviceIntRect::zero());
|
||||
|
||||
MaskResult::Inside(RenderTask {
|
||||
Some(RenderTask {
|
||||
id: RenderTaskId::Dynamic(RenderTaskKey::CacheMask(mask_key)),
|
||||
children: Vec::new(),
|
||||
location: RenderTaskLocation::Dynamic(None, task_rect.size),
|
||||
kind: RenderTaskKind::CacheMask(CacheMaskTask {
|
||||
actual_rect: task_rect,
|
||||
inner_rect: inner_rect,
|
||||
clips: clips.to_vec(),
|
||||
geometry_kind: geometry_kind,
|
||||
inner_rect: inner_rect.unwrap_or(DeviceIntRect::zero()),
|
||||
clips,
|
||||
geometry_kind,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
use debug_colors;
|
||||
use debug_render::DebugRenderer;
|
||||
use device::{DepthFunction, Device, FrameId, ProgramId, TextureId, VertexFormat, GpuMarker, GpuProfiler};
|
||||
use device::{DepthFunction, Device, FrameId, ProgramId, TextureId, VertexFormat, GpuMarker, GpuProfiler, PBOId};
|
||||
use device::{GpuSample, TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler, TextureTarget, ShaderError};
|
||||
use device::get_gl_format_bgra;
|
||||
use euclid::Transform3D;
|
||||
@ -19,7 +19,6 @@ use fnv::FnvHasher;
|
||||
use frame_builder::FrameBuilderConfig;
|
||||
use gleam::gl;
|
||||
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
|
||||
use gpu_store::{GpuStore, GpuStoreLayout};
|
||||
use internal_types::{CacheTextureId, RendererFrame, ResultMsg, TextureUpdateOp};
|
||||
use internal_types::{TextureUpdateList, PackedVertex, RenderTargetMode};
|
||||
use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, SourceTexture};
|
||||
@ -38,7 +37,6 @@ use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::slice;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::sync::mpsc::{channel, Receiver, Sender};
|
||||
use std::thread;
|
||||
@ -51,13 +49,13 @@ use time::precise_time_ns;
|
||||
use thread_profiler::{register_thread_with_profiler, write_profile};
|
||||
use util::TransformedRectKind;
|
||||
use webgl_types::GLContextHandleWrapper;
|
||||
use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher};
|
||||
use webrender_traits::{ExternalImageId, ExternalImageType, ImageData, ImageFormat, RenderApiSender};
|
||||
use webrender_traits::{DeviceIntRect, DeviceUintRect, DeviceIntPoint, DeviceIntSize, DeviceUintSize};
|
||||
use webrender_traits::{BlobImageRenderer, channel, FontRenderMode};
|
||||
use webrender_traits::VRCompositorHandler;
|
||||
use webrender_traits::{YuvColorSpace, YuvFormat};
|
||||
use webrender_traits::{YUV_COLOR_SPACES, YUV_FORMATS};
|
||||
use api::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher};
|
||||
use api::{ExternalImageId, ExternalImageType, ImageData, ImageFormat, RenderApiSender};
|
||||
use api::{DeviceIntRect, DeviceUintRect, DeviceIntPoint, DeviceIntSize, DeviceUintSize};
|
||||
use api::{BlobImageRenderer, channel, FontRenderMode};
|
||||
use api::VRCompositorHandler;
|
||||
use api::{YuvColorSpace, YuvFormat};
|
||||
use api::{YUV_COLOR_SPACES, YUV_FORMATS};
|
||||
|
||||
pub const GPU_DATA_TEXTURE_POOL: usize = 5;
|
||||
pub const MAX_VERTEX_TEXTURE_WIDTH: usize = 1024;
|
||||
@ -156,8 +154,8 @@ impl GpuProfile {
|
||||
paint_time_ns += sample.time_ns;
|
||||
}
|
||||
GpuProfile {
|
||||
frame_id: frame_id,
|
||||
paint_time_ns: paint_time_ns,
|
||||
frame_id,
|
||||
paint_time_ns,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -174,9 +172,9 @@ impl CpuProfile {
|
||||
composite_time_ns: u64,
|
||||
draw_calls: usize) -> CpuProfile {
|
||||
CpuProfile {
|
||||
frame_id: frame_id,
|
||||
composite_time_ns: composite_time_ns,
|
||||
draw_calls: draw_calls,
|
||||
frame_id,
|
||||
composite_time_ns,
|
||||
draw_calls,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -191,90 +189,165 @@ pub enum BlendMode {
|
||||
Subpixel(ColorF),
|
||||
}
|
||||
|
||||
// Tracks the state of each row in the GPU cache texture.
|
||||
struct CacheRow {
|
||||
is_dirty: bool,
|
||||
}
|
||||
|
||||
impl CacheRow {
|
||||
fn new() -> CacheRow {
|
||||
CacheRow {
|
||||
is_dirty: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The device-specific representation of the cache texture in gpu_cache.rs
|
||||
struct CacheTexture {
|
||||
current_id: TextureId,
|
||||
next_id: TextureId,
|
||||
texture_id: TextureId,
|
||||
pbo_id: PBOId,
|
||||
rows: Vec<CacheRow>,
|
||||
cpu_blocks: Vec<GpuBlockData>,
|
||||
}
|
||||
|
||||
impl CacheTexture {
|
||||
fn new(device: &mut Device) -> CacheTexture {
|
||||
let ids = device.create_texture_ids(2, TextureTarget::Default);
|
||||
let texture_id = device.create_texture_ids(1, TextureTarget::Default)[0];
|
||||
let pbo_id = device.create_pbo();
|
||||
|
||||
CacheTexture {
|
||||
current_id: ids[0],
|
||||
next_id: ids[1],
|
||||
texture_id,
|
||||
pbo_id,
|
||||
rows: Vec::new(),
|
||||
cpu_blocks: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_patch(&mut self,
|
||||
device: &mut Device,
|
||||
update: &GpuCacheUpdate,
|
||||
blocks: &[GpuBlockData]) {
|
||||
match update {
|
||||
&GpuCacheUpdate::Copy { block_index, block_count, address } => {
|
||||
// Apply an incremental update to the cache texture.
|
||||
// TODO(gw): For the initial implementation, we will just
|
||||
// use update_texture() since it's simple. If / when
|
||||
// we profile this and find it to be slow on some / all
|
||||
// devices - we can look into other options, such as
|
||||
// using glMapBuffer() with the unsynchronized bit,
|
||||
// and managing the synchronization ourselves with fences.
|
||||
let data: &[u8] = unsafe {
|
||||
let ptr = blocks.as_ptr()
|
||||
.offset(block_index as isize);
|
||||
slice::from_raw_parts(ptr as *const _, block_count * 16)
|
||||
};
|
||||
device.update_texture(self.current_id,
|
||||
address.u as u32,
|
||||
address.v as u32,
|
||||
block_count as u32,
|
||||
1,
|
||||
None,
|
||||
data);
|
||||
let row = address.v as usize;
|
||||
|
||||
// Ensure that the CPU-side shadow copy of the GPU cache data has enough
|
||||
// rows to apply this patch.
|
||||
while self.rows.len() <= row {
|
||||
// Add a new row.
|
||||
self.rows.push(CacheRow::new());
|
||||
// Add enough GPU blocks for this row.
|
||||
self.cpu_blocks.extend_from_slice(&[GpuBlockData::empty(); MAX_VERTEX_TEXTURE_WIDTH]);
|
||||
}
|
||||
|
||||
// This row is dirty (needs to be updated in GPU texture).
|
||||
self.rows[row].is_dirty = true;
|
||||
|
||||
// Copy the blocks from the patch array in the shadow CPU copy.
|
||||
let block_offset = row * MAX_VERTEX_TEXTURE_WIDTH + address.u as usize;
|
||||
let data = &mut self.cpu_blocks[block_offset..(block_offset + block_count)];
|
||||
for i in 0..block_count {
|
||||
data[i] = blocks[block_index + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, device: &mut Device, updates: &GpuCacheUpdateList) {
|
||||
// See if we need to create or resize the texture.
|
||||
let current_dimensions = device.get_texture_dimensions(self.current_id);
|
||||
let current_dimensions = device.get_texture_dimensions(self.texture_id);
|
||||
if updates.height > current_dimensions.height {
|
||||
// Create a f32 texture that can be used for the vertex shader
|
||||
// to fetch data from.
|
||||
device.init_texture(self.next_id,
|
||||
device.init_texture(self.texture_id,
|
||||
MAX_VERTEX_TEXTURE_WIDTH as u32,
|
||||
updates.height as u32,
|
||||
ImageFormat::RGBAF32,
|
||||
TextureFilter::Nearest,
|
||||
RenderTargetMode::SimpleRenderTarget,
|
||||
RenderTargetMode::None,
|
||||
None);
|
||||
|
||||
// Copy the current texture into the newly resized texture.
|
||||
if current_dimensions.height > 0 {
|
||||
device.bind_draw_target(Some((self.next_id, 0)), None);
|
||||
|
||||
let blit_rect = DeviceIntRect::new(DeviceIntPoint::zero(),
|
||||
DeviceIntSize::new(MAX_VERTEX_TEXTURE_WIDTH as i32,
|
||||
current_dimensions.height as i32));
|
||||
|
||||
// TODO(gw): Should probably switch this to glCopyTexSubImage2D, since we
|
||||
// don't do any stretching here.
|
||||
device.blit_render_target(Some((self.current_id, 0)),
|
||||
Some(blit_rect),
|
||||
blit_rect);
|
||||
|
||||
// Free the GPU memory for that texture until we need to resize again.
|
||||
device.deinit_texture(self.current_id);
|
||||
// If we had to resize the texture, just mark all rows
|
||||
// as dirty so they will be uploaded to the texture
|
||||
// during the next flush.
|
||||
for row in &mut self.rows {
|
||||
row.is_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
mem::swap(&mut self.current_id, &mut self.next_id);
|
||||
}
|
||||
|
||||
for update in &updates.updates {
|
||||
self.apply_patch(device, update, &updates.blocks);
|
||||
self.apply_patch(update, &updates.blocks);
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&mut self, device: &mut Device) {
|
||||
// Bind a PBO to do the texture upload.
|
||||
// Updating the texture via PBO avoids CPU-side driver stalls.
|
||||
device.bind_pbo(Some(self.pbo_id));
|
||||
|
||||
for (row_index, row) in self.rows.iter_mut().enumerate() {
|
||||
if row.is_dirty {
|
||||
// Get the data for this row and push to the PBO.
|
||||
let block_index = row_index * MAX_VERTEX_TEXTURE_WIDTH;
|
||||
let cpu_blocks = &self.cpu_blocks[block_index..(block_index + MAX_VERTEX_TEXTURE_WIDTH)];
|
||||
device.update_pbo_data(cpu_blocks);
|
||||
|
||||
// Insert a command to copy the PBO data to the right place in
|
||||
// the GPU-side cache texture.
|
||||
device.update_texture_from_pbo(self.texture_id,
|
||||
0,
|
||||
row_index as u32,
|
||||
MAX_VERTEX_TEXTURE_WIDTH as u32,
|
||||
1,
|
||||
0);
|
||||
|
||||
// Orphan the PBO. This is the recommended way to hint to the
|
||||
// driver to detach the underlying storage from this PBO id.
|
||||
// Keeping the size the same gives the driver a hint for future
|
||||
// use of this PBO.
|
||||
device.orphan_pbo(mem::size_of::<GpuBlockData>() * MAX_VERTEX_TEXTURE_WIDTH);
|
||||
|
||||
row.is_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that other texture updates won't read from this PBO.
|
||||
device.bind_pbo(None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
trait GpuStoreLayout {
|
||||
fn image_format() -> ImageFormat;
|
||||
|
||||
fn texture_width<T>() -> usize;
|
||||
|
||||
fn texture_filter() -> TextureFilter;
|
||||
|
||||
fn texel_size() -> usize {
|
||||
match Self::image_format() {
|
||||
ImageFormat::BGRA8 => 4,
|
||||
ImageFormat::RGBAF32 => 16,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn texels_per_item<T>() -> usize {
|
||||
let item_size = mem::size_of::<T>();
|
||||
let texel_size = Self::texel_size();
|
||||
debug_assert!(item_size % texel_size == 0);
|
||||
item_size / texel_size
|
||||
}
|
||||
|
||||
fn items_per_row<T>() -> usize {
|
||||
Self::texture_width::<T>() / Self::texels_per_item::<T>()
|
||||
}
|
||||
|
||||
fn rows_per_item<T>() -> usize {
|
||||
Self::texels_per_item::<T>() / Self::texture_width::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
struct GpuDataTexture<L> {
|
||||
@ -287,7 +360,7 @@ impl<L: GpuStoreLayout> GpuDataTexture<L> {
|
||||
let id = device.create_texture_ids(1, TextureTarget::Default)[0];
|
||||
|
||||
GpuDataTexture {
|
||||
id: id,
|
||||
id,
|
||||
layout: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -344,11 +417,10 @@ impl GpuStoreLayout for VertexDataTextureLayout {
|
||||
}
|
||||
|
||||
type VertexDataTexture = GpuDataTexture<VertexDataTextureLayout>;
|
||||
pub type VertexDataStore<T> = GpuStore<T, VertexDataTextureLayout>;
|
||||
|
||||
const TRANSFORM_FEATURE: &'static str = "TRANSFORM";
|
||||
const SUBPIXEL_AA_FEATURE: &'static str = "SUBPIXEL_AA";
|
||||
const CLIP_FEATURE: &'static str = "CLIP";
|
||||
const TRANSFORM_FEATURE: &str = "TRANSFORM";
|
||||
const SUBPIXEL_AA_FEATURE: &str = "SUBPIXEL_AA";
|
||||
const CLIP_FEATURE: &str = "CLIP";
|
||||
|
||||
enum ShaderKind {
|
||||
Primitive,
|
||||
@ -371,8 +443,8 @@ impl LazilyCompiledShader {
|
||||
precache: bool) -> Result<LazilyCompiledShader, ShaderError> {
|
||||
let mut shader = LazilyCompiledShader {
|
||||
id: None,
|
||||
name: name,
|
||||
kind: kind,
|
||||
name,
|
||||
kind,
|
||||
features: features.to_vec(),
|
||||
};
|
||||
|
||||
@ -465,8 +537,8 @@ impl PrimitiveShader {
|
||||
};
|
||||
|
||||
Ok(PrimitiveShader {
|
||||
simple: simple,
|
||||
transform: transform,
|
||||
simple,
|
||||
transform,
|
||||
})
|
||||
}
|
||||
|
||||
@ -511,7 +583,6 @@ fn create_clip_shader(name: &'static str, device: &mut Device) -> Result<Program
|
||||
struct GpuDataTextures {
|
||||
layer_texture: VertexDataTexture,
|
||||
render_task_texture: VertexDataTexture,
|
||||
data32_texture: VertexDataTexture,
|
||||
}
|
||||
|
||||
impl GpuDataTextures {
|
||||
@ -519,18 +590,15 @@ impl GpuDataTextures {
|
||||
GpuDataTextures {
|
||||
layer_texture: VertexDataTexture::new(device),
|
||||
render_task_texture: VertexDataTexture::new(device),
|
||||
data32_texture: VertexDataTexture::new(device),
|
||||
}
|
||||
}
|
||||
|
||||
fn init_frame(&mut self, device: &mut Device, frame: &mut Frame) {
|
||||
self.data32_texture.init(device, &mut frame.gpu_data32);
|
||||
self.layer_texture.init(device, &mut frame.layer_texture_data);
|
||||
self.render_task_texture.init(device, &mut frame.render_task_data);
|
||||
|
||||
device.bind_texture(TextureSampler::Layers, self.layer_texture.id);
|
||||
device.bind_texture(TextureSampler::RenderTasks, self.render_task_texture.id);
|
||||
device.bind_texture(TextureSampler::Data32, self.data32_texture.id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1054,7 +1122,7 @@ impl Renderer {
|
||||
|
||||
let config = FrameBuilderConfig {
|
||||
enable_scrollbars: options.enable_scrollbars,
|
||||
default_font_render_mode: default_font_render_mode,
|
||||
default_font_render_mode,
|
||||
debug: options.debug,
|
||||
cache_expiry_frames: options.cache_expiry_frames,
|
||||
};
|
||||
@ -1095,38 +1163,38 @@ impl Renderer {
|
||||
let gpu_profile = GpuProfiler::new(device.rc_gl());
|
||||
|
||||
let renderer = Renderer {
|
||||
result_rx: result_rx,
|
||||
device: device,
|
||||
result_rx,
|
||||
device,
|
||||
current_frame: None,
|
||||
pending_texture_updates: Vec::new(),
|
||||
pending_gpu_cache_updates: Vec::new(),
|
||||
pending_shader_updates: Vec::new(),
|
||||
cs_box_shadow: cs_box_shadow,
|
||||
cs_text_run: cs_text_run,
|
||||
cs_blur: cs_blur,
|
||||
cs_clip_rectangle: cs_clip_rectangle,
|
||||
cs_clip_border: cs_clip_border,
|
||||
cs_clip_image: cs_clip_image,
|
||||
ps_rectangle: ps_rectangle,
|
||||
ps_rectangle_clip: ps_rectangle_clip,
|
||||
ps_text_run: ps_text_run,
|
||||
ps_text_run_subpixel: ps_text_run_subpixel,
|
||||
ps_image: ps_image,
|
||||
ps_yuv_image: ps_yuv_image,
|
||||
ps_border_corner: ps_border_corner,
|
||||
ps_border_edge: ps_border_edge,
|
||||
ps_box_shadow: ps_box_shadow,
|
||||
ps_gradient: ps_gradient,
|
||||
ps_angle_gradient: ps_angle_gradient,
|
||||
ps_radial_gradient: ps_radial_gradient,
|
||||
ps_cache_image: ps_cache_image,
|
||||
ps_blend: ps_blend,
|
||||
ps_hw_composite: ps_hw_composite,
|
||||
ps_split_composite: ps_split_composite,
|
||||
ps_composite: ps_composite,
|
||||
notifier: notifier,
|
||||
cs_box_shadow,
|
||||
cs_text_run,
|
||||
cs_blur,
|
||||
cs_clip_rectangle,
|
||||
cs_clip_border,
|
||||
cs_clip_image,
|
||||
ps_rectangle,
|
||||
ps_rectangle_clip,
|
||||
ps_text_run,
|
||||
ps_text_run_subpixel,
|
||||
ps_image,
|
||||
ps_yuv_image,
|
||||
ps_border_corner,
|
||||
ps_border_edge,
|
||||
ps_box_shadow,
|
||||
ps_gradient,
|
||||
ps_angle_gradient,
|
||||
ps_radial_gradient,
|
||||
ps_cache_image,
|
||||
ps_blend,
|
||||
ps_hw_composite,
|
||||
ps_split_composite,
|
||||
ps_composite,
|
||||
notifier,
|
||||
debug: debug_renderer,
|
||||
render_target_debug: render_target_debug,
|
||||
render_target_debug,
|
||||
enable_batcher: options.enable_batcher,
|
||||
backend_profile_counters: BackendProfileCounters::new(),
|
||||
profile_counters: RendererProfileCounters::new(),
|
||||
@ -1139,23 +1207,23 @@ impl Renderer {
|
||||
last_time: 0,
|
||||
color_render_targets: Vec::new(),
|
||||
alpha_render_targets: Vec::new(),
|
||||
gpu_profile: gpu_profile,
|
||||
prim_vao_id: prim_vao_id,
|
||||
blur_vao_id: blur_vao_id,
|
||||
clip_vao_id: clip_vao_id,
|
||||
gpu_profile,
|
||||
prim_vao_id,
|
||||
blur_vao_id,
|
||||
clip_vao_id,
|
||||
gdt_index: 0,
|
||||
gpu_data_textures: gpu_data_textures,
|
||||
gpu_data_textures,
|
||||
pipeline_epoch_map: HashMap::default(),
|
||||
main_thread_dispatcher: main_thread_dispatcher,
|
||||
main_thread_dispatcher,
|
||||
cache_texture_id_map: Vec::new(),
|
||||
dummy_cache_texture_id: dummy_cache_texture_id,
|
||||
dither_matrix_texture_id: dither_matrix_texture_id,
|
||||
dummy_cache_texture_id,
|
||||
dither_matrix_texture_id,
|
||||
external_image_handler: None,
|
||||
external_images: HashMap::default(),
|
||||
vr_compositor_handler: vr_compositor,
|
||||
cpu_profiles: VecDeque::new(),
|
||||
gpu_profiles: VecDeque::new(),
|
||||
gpu_cache_texture: gpu_cache_texture,
|
||||
gpu_cache_texture,
|
||||
};
|
||||
|
||||
let sender = RenderApiSender::new(api_tx, payload_tx);
|
||||
@ -1282,7 +1350,7 @@ impl Renderer {
|
||||
/// Renders the current frame.
|
||||
///
|
||||
/// A Frame is supplied by calling [`set_display_list()`][newframe].
|
||||
/// [newframe]: ../../webrender_traits/struct.RenderApi.html#method.set_display_list
|
||||
/// [newframe]: ../../webrender_api/struct.RenderApi.html#method.set_display_list
|
||||
pub fn render(&mut self, framebuffer_size: DeviceUintSize) {
|
||||
profile_scope!("render");
|
||||
|
||||
@ -1319,10 +1387,9 @@ impl Renderer {
|
||||
|
||||
self.update_texture_cache();
|
||||
|
||||
self.update_gpu_cache();
|
||||
self.update_deferred_resolves(frame);
|
||||
self.update_gpu_cache(frame);
|
||||
|
||||
self.device.bind_texture(TextureSampler::ResourceCache, self.gpu_cache_texture.current_id);
|
||||
self.device.bind_texture(TextureSampler::ResourceCache, self.gpu_cache_texture.texture_id);
|
||||
|
||||
frame_id
|
||||
};
|
||||
@ -1396,11 +1463,13 @@ impl Renderer {
|
||||
}
|
||||
*/
|
||||
|
||||
fn update_gpu_cache(&mut self) {
|
||||
fn update_gpu_cache(&mut self, frame: &mut Frame) {
|
||||
let _gm = GpuMarker::new(self.device.rc_gl(), "gpu cache update");
|
||||
for update_list in self.pending_gpu_cache_updates.drain(..) {
|
||||
self.gpu_cache_texture.update(&mut self.device, &update_list);
|
||||
}
|
||||
self.update_deferred_resolves(frame);
|
||||
self.gpu_cache_texture.flush(&mut self.device);
|
||||
}
|
||||
|
||||
fn update_texture_cache(&mut self) {
|
||||
@ -1759,16 +1828,21 @@ impl Renderer {
|
||||
self.device.set_blend(false);
|
||||
let shader = self.cs_blur.get(&mut self.device).unwrap();
|
||||
|
||||
self.draw_instanced_batch(&target.vertical_blurs,
|
||||
vao,
|
||||
shader,
|
||||
&BatchTextures::no_texture(),
|
||||
&projection);
|
||||
self.draw_instanced_batch(&target.horizontal_blurs,
|
||||
vao,
|
||||
shader,
|
||||
&BatchTextures::no_texture(),
|
||||
&projection);
|
||||
if !target.vertical_blurs.is_empty() {
|
||||
self.draw_instanced_batch(&target.vertical_blurs,
|
||||
vao,
|
||||
shader,
|
||||
&BatchTextures::no_texture(),
|
||||
&projection);
|
||||
}
|
||||
|
||||
if !target.horizontal_blurs.is_empty() {
|
||||
self.draw_instanced_batch(&target.horizontal_blurs,
|
||||
vao,
|
||||
shader,
|
||||
&BatchTextures::no_texture(),
|
||||
&projection);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw any box-shadow caches for this target.
|
||||
@ -1805,58 +1879,66 @@ impl Renderer {
|
||||
&projection);
|
||||
}
|
||||
|
||||
let _gm2 = GpuMarker::new(self.device.rc_gl(), "alpha batches");
|
||||
self.device.set_blend(false);
|
||||
let mut prev_blend_mode = BlendMode::None;
|
||||
if !target.alpha_batcher.is_empty() {
|
||||
let _gm2 = GpuMarker::new(self.device.rc_gl(), "alpha batches");
|
||||
self.device.set_blend(false);
|
||||
let mut prev_blend_mode = BlendMode::None;
|
||||
|
||||
//Note: depth equality is needed for split planes
|
||||
self.device.set_depth_func(DepthFunction::LessEqual);
|
||||
self.device.enable_depth();
|
||||
self.device.enable_depth_write();
|
||||
//Note: depth equality is needed for split planes
|
||||
self.device.set_depth_func(DepthFunction::LessEqual);
|
||||
self.device.enable_depth();
|
||||
self.device.enable_depth_write();
|
||||
|
||||
for batch in &target.alpha_batcher.batch_list.opaque_batches {
|
||||
self.submit_batch(batch,
|
||||
&projection,
|
||||
render_task_data,
|
||||
color_cache_texture,
|
||||
render_target,
|
||||
target_size);
|
||||
}
|
||||
|
||||
self.device.disable_depth_write();
|
||||
|
||||
for batch in &target.alpha_batcher.batch_list.alpha_batches {
|
||||
if batch.key.blend_mode != prev_blend_mode {
|
||||
match batch.key.blend_mode {
|
||||
BlendMode::None => {
|
||||
self.device.set_blend(false);
|
||||
}
|
||||
BlendMode::Alpha => {
|
||||
self.device.set_blend(true);
|
||||
self.device.set_blend_mode_alpha();
|
||||
}
|
||||
BlendMode::PremultipliedAlpha => {
|
||||
self.device.set_blend(true);
|
||||
self.device.set_blend_mode_premultiplied_alpha();
|
||||
}
|
||||
BlendMode::Subpixel(color) => {
|
||||
self.device.set_blend(true);
|
||||
self.device.set_blend_mode_subpixel(color);
|
||||
}
|
||||
}
|
||||
prev_blend_mode = batch.key.blend_mode;
|
||||
// Draw opaque batches front-to-back for maximum
|
||||
// z-buffer efficiency!
|
||||
for batch in target.alpha_batcher
|
||||
.batch_list
|
||||
.opaque_batches
|
||||
.iter()
|
||||
.rev() {
|
||||
self.submit_batch(batch,
|
||||
&projection,
|
||||
render_task_data,
|
||||
color_cache_texture,
|
||||
render_target,
|
||||
target_size);
|
||||
}
|
||||
|
||||
self.submit_batch(batch,
|
||||
&projection,
|
||||
render_task_data,
|
||||
color_cache_texture,
|
||||
render_target,
|
||||
target_size);
|
||||
}
|
||||
self.device.disable_depth_write();
|
||||
|
||||
self.device.disable_depth();
|
||||
self.device.set_blend(false);
|
||||
for batch in &target.alpha_batcher.batch_list.alpha_batches {
|
||||
if batch.key.blend_mode != prev_blend_mode {
|
||||
match batch.key.blend_mode {
|
||||
BlendMode::None => {
|
||||
self.device.set_blend(false);
|
||||
}
|
||||
BlendMode::Alpha => {
|
||||
self.device.set_blend(true);
|
||||
self.device.set_blend_mode_alpha();
|
||||
}
|
||||
BlendMode::PremultipliedAlpha => {
|
||||
self.device.set_blend(true);
|
||||
self.device.set_blend_mode_premultiplied_alpha();
|
||||
}
|
||||
BlendMode::Subpixel(color) => {
|
||||
self.device.set_blend(true);
|
||||
self.device.set_blend_mode_subpixel(color);
|
||||
}
|
||||
}
|
||||
prev_blend_mode = batch.key.blend_mode;
|
||||
}
|
||||
|
||||
self.submit_batch(batch,
|
||||
&projection,
|
||||
render_task_data,
|
||||
color_cache_texture,
|
||||
render_target,
|
||||
target_size);
|
||||
}
|
||||
|
||||
self.device.disable_depth();
|
||||
self.device.set_blend(false);
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_alpha_target(&mut self,
|
||||
@ -1990,7 +2072,7 @@ impl Renderer {
|
||||
address: deferred_resolve.address,
|
||||
};
|
||||
let blocks = [ [image.u0, image.v0, image.u1, image.v1].into() ];
|
||||
self.gpu_cache_texture.apply_patch(&mut self.device, &update, &blocks);
|
||||
self.gpu_cache_texture.apply_patch(&update, &blocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,13 +17,13 @@ use std::hash::Hash;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use texture_cache::{TextureCache, TextureCacheItemId};
|
||||
use webrender_traits::{Epoch, FontKey, FontTemplate, GlyphKey, ImageKey, ImageRendering};
|
||||
use webrender_traits::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId};
|
||||
use webrender_traits::{DevicePoint, DeviceIntSize, DeviceUintRect, ImageDescriptor, ColorF};
|
||||
use webrender_traits::{GlyphOptions, GlyphInstance, TileOffset, TileSize};
|
||||
use webrender_traits::{BlobImageRenderer, BlobImageDescriptor, BlobImageError, BlobImageRequest, BlobImageData};
|
||||
use webrender_traits::BlobImageResources;
|
||||
use webrender_traits::{ExternalImageData, ExternalImageType, LayoutPoint};
|
||||
use api::{Epoch, FontKey, FontTemplate, GlyphKey, ImageKey, ImageRendering};
|
||||
use api::{FontRenderMode, ImageData, GlyphDimensions, WebGLContextId};
|
||||
use api::{DevicePoint, DeviceIntSize, DeviceUintRect, ImageDescriptor, ColorF};
|
||||
use api::{GlyphOptions, GlyphInstance, TileOffset, TileSize};
|
||||
use api::{BlobImageRenderer, BlobImageDescriptor, BlobImageError, BlobImageRequest, BlobImageData};
|
||||
use api::BlobImageResources;
|
||||
use api::{ExternalImageData, ExternalImageType, LayoutPoint};
|
||||
use rayon::ThreadPool;
|
||||
use glyph_rasterizer::{GlyphRasterizer, GlyphCache, GlyphRequest};
|
||||
|
||||
@ -228,13 +228,13 @@ impl ResourceCache {
|
||||
image_templates: ImageTemplates::new(),
|
||||
},
|
||||
cached_glyph_dimensions: HashMap::default(),
|
||||
texture_cache: texture_cache,
|
||||
texture_cache,
|
||||
state: State::Idle,
|
||||
current_frame_id: FrameId(0),
|
||||
pending_image_requests: Vec::new(),
|
||||
glyph_rasterizer: GlyphRasterizer::new(workers),
|
||||
|
||||
blob_image_renderer: blob_image_renderer,
|
||||
blob_image_renderer,
|
||||
blob_image_requests: HashSet::new(),
|
||||
|
||||
requested_glyphs: HashSet::default(),
|
||||
@ -294,10 +294,10 @@ impl ResourceCache {
|
||||
}
|
||||
|
||||
let resource = ImageResource {
|
||||
descriptor: descriptor,
|
||||
data: data,
|
||||
descriptor,
|
||||
data,
|
||||
epoch: Epoch(0),
|
||||
tiling: tiling,
|
||||
tiling,
|
||||
dirty_rect: None,
|
||||
};
|
||||
|
||||
@ -329,10 +329,10 @@ impl ResourceCache {
|
||||
}
|
||||
|
||||
ImageResource {
|
||||
descriptor: descriptor,
|
||||
data: data,
|
||||
descriptor,
|
||||
data,
|
||||
epoch: next_epoch,
|
||||
tiling: tiling,
|
||||
tiling,
|
||||
dirty_rect: match (dirty_rect, image.dirty_rect) {
|
||||
(Some(rect), Some(prev_rect)) => Some(rect.union(&prev_rect)),
|
||||
(Some(rect), None) => Some(rect),
|
||||
@ -364,7 +364,7 @@ impl ResourceCache {
|
||||
pub fn add_webgl_texture(&mut self, id: WebGLContextId, texture_id: SourceTexture, size: DeviceIntSize) {
|
||||
self.webgl_textures.insert(id, WebGLTexture {
|
||||
id: texture_id,
|
||||
size: size,
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
||||
@ -383,9 +383,9 @@ impl ResourceCache {
|
||||
|
||||
debug_assert_eq!(self.state, State::AddResources);
|
||||
let request = ImageRequest {
|
||||
key: key,
|
||||
rendering: rendering,
|
||||
tile: tile,
|
||||
key,
|
||||
rendering,
|
||||
tile,
|
||||
};
|
||||
|
||||
let template = self.resources.image_templates.get(key).unwrap();
|
||||
@ -433,7 +433,7 @@ impl ResourceCache {
|
||||
&BlobImageDescriptor {
|
||||
width: w,
|
||||
height: h,
|
||||
offset: offset,
|
||||
offset,
|
||||
format: template.descriptor.format,
|
||||
},
|
||||
template.dirty_rect,
|
||||
@ -525,7 +525,7 @@ impl ResourceCache {
|
||||
let key = ImageRequest {
|
||||
key: image_key,
|
||||
rendering: image_rendering,
|
||||
tile: tile,
|
||||
tile,
|
||||
};
|
||||
let image_info = &self.cached_images.get(&key, self.current_frame_id);
|
||||
let item = self.texture_cache.get(image_info.texture_cache_id);
|
||||
@ -556,7 +556,7 @@ impl ResourceCache {
|
||||
|
||||
ImageProperties {
|
||||
descriptor: image_template.descriptor,
|
||||
external_image: external_image,
|
||||
external_image,
|
||||
tiling: image_template.tiling,
|
||||
}
|
||||
}
|
||||
@ -635,15 +635,15 @@ impl ResourceCache {
|
||||
for texture_cache_item_id in self.requested_images.drain() {
|
||||
let item = self.texture_cache.get_mut(texture_cache_item_id);
|
||||
if let Some(mut request) = gpu_cache.request(&mut item.uv_rect_handle) {
|
||||
request.push(item.uv_rect.into());
|
||||
request.push(item.uv_rect);
|
||||
}
|
||||
}
|
||||
|
||||
for texture_cache_item_id in self.requested_glyphs.drain() {
|
||||
let item = self.texture_cache.get_mut(texture_cache_item_id);
|
||||
if let Some(mut request) = gpu_cache.request(&mut item.uv_rect_handle) {
|
||||
request.push(item.uv_rect.into());
|
||||
request.push([item.user_data[0], item.user_data[1], 0.0, 0.0].into());
|
||||
request.push(item.uv_rect);
|
||||
request.push([item.user_data[0], item.user_data[1], 0.0, 0.0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -681,8 +681,8 @@ impl ResourceCache {
|
||||
ImageDescriptor {
|
||||
width: actual_width,
|
||||
height: actual_height,
|
||||
stride: stride,
|
||||
offset: offset,
|
||||
stride,
|
||||
offset,
|
||||
format: image_descriptor.format,
|
||||
is_opaque: image_descriptor.is_opaque,
|
||||
}
|
||||
|
@ -5,8 +5,8 @@
|
||||
use fnv::FnvHasher;
|
||||
use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use webrender_traits::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayerSize, LayoutSize};
|
||||
use webrender_traits::{LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
|
||||
use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, LayerSize, LayoutSize};
|
||||
use api::{LayoutTransform, PipelineId, PropertyBinding, PropertyBindingId};
|
||||
|
||||
/// Stores a map of the animated property bindings for the current display list. These
|
||||
/// can be used to animate the transform and/or opacity of a display list without
|
||||
@ -120,11 +120,11 @@ impl Scene {
|
||||
self.display_lists.insert(pipeline_id, built_display_list);
|
||||
|
||||
let new_pipeline = ScenePipeline {
|
||||
pipeline_id: pipeline_id,
|
||||
epoch: epoch,
|
||||
viewport_size: viewport_size,
|
||||
content_size: content_size,
|
||||
background_color: background_color,
|
||||
pipeline_id,
|
||||
epoch,
|
||||
viewport_size,
|
||||
content_size,
|
||||
background_color,
|
||||
};
|
||||
|
||||
self.pipeline_map.insert(pipeline_id, new_pipeline);
|
||||
|
@ -2,7 +2,7 @@
|
||||
* 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 webrender_traits::LayerPoint;
|
||||
use api::LayerPoint;
|
||||
|
||||
/// Some arbitrarily small positive number used as threshold value.
|
||||
pub const EPSILON: f32 = 0.1;
|
||||
@ -34,8 +34,8 @@ impl Spring {
|
||||
cur: pos,
|
||||
prev: pos,
|
||||
dest: pos,
|
||||
stiffness: stiffness,
|
||||
damping: damping,
|
||||
stiffness,
|
||||
damping,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,9 +17,9 @@ use std::mem;
|
||||
use std::slice::Iter;
|
||||
use time;
|
||||
use util;
|
||||
use webrender_traits::{ExternalImageType, ImageData, ImageFormat};
|
||||
use webrender_traits::{DeviceUintRect, DeviceUintSize, DeviceUintPoint};
|
||||
use webrender_traits::{DevicePoint, ImageDescriptor};
|
||||
use api::{ExternalImageType, ImageData, ImageFormat};
|
||||
use api::{DeviceUintRect, DeviceUintSize, DeviceUintPoint};
|
||||
use api::{DevicePoint, ImageDescriptor};
|
||||
|
||||
/// The number of bytes we're allowed to use for a texture.
|
||||
const MAX_BYTES_PER_TEXTURE: u32 = 1024 * 1024 * 256; // 256MB
|
||||
@ -77,8 +77,8 @@ pub struct TexturePage {
|
||||
impl TexturePage {
|
||||
pub fn new(texture_id: CacheTextureId, texture_size: DeviceUintSize) -> TexturePage {
|
||||
let mut page = TexturePage {
|
||||
texture_id: texture_id,
|
||||
texture_size: texture_size,
|
||||
texture_id,
|
||||
texture_size,
|
||||
free_list: FreeRectList::new(),
|
||||
coalesce_vec: Vec::new(),
|
||||
allocations: 0,
|
||||
@ -496,7 +496,7 @@ impl TextureCacheItem {
|
||||
user_data: [f32; 2])
|
||||
-> TextureCacheItem {
|
||||
TextureCacheItem {
|
||||
texture_id: texture_id,
|
||||
texture_id,
|
||||
uv_rect: UvRect {
|
||||
uv0: DevicePoint::new(rect.origin.x as f32,
|
||||
rect.origin.y as f32),
|
||||
@ -505,7 +505,7 @@ impl TextureCacheItem {
|
||||
},
|
||||
allocated_rect: rect,
|
||||
uv_rect_handle: GpuCacheHandle::new(),
|
||||
user_data: user_data,
|
||||
user_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -603,7 +603,7 @@ impl TextureCache {
|
||||
items: FreeList::new(),
|
||||
pending_updates: TextureUpdateList::new(),
|
||||
arena: TextureCacheArena::new(),
|
||||
max_texture_size: max_texture_size,
|
||||
max_texture_size,
|
||||
}
|
||||
}
|
||||
|
||||
@ -642,7 +642,7 @@ impl TextureCache {
|
||||
return AllocationResult {
|
||||
item: self.items.get(image_id).clone(),
|
||||
kind: AllocationKind::Standalone,
|
||||
image_id: image_id,
|
||||
image_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,7 +717,7 @@ impl TextureCache {
|
||||
self.pending_updates.push(update_op);
|
||||
|
||||
free_texture_levels.push(FreeTextureLevel {
|
||||
texture_id: texture_id,
|
||||
texture_id,
|
||||
});
|
||||
}
|
||||
let free_texture_level = free_texture_levels.pop().unwrap();
|
||||
@ -739,7 +739,7 @@ impl TextureCache {
|
||||
AllocationResult {
|
||||
item: cache_item,
|
||||
kind: AllocationKind::TexturePage,
|
||||
image_id: image_id,
|
||||
image_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -773,7 +773,7 @@ impl TextureCache {
|
||||
height: dirty.size.height,
|
||||
data: bytes,
|
||||
stride: Some(stride),
|
||||
offset: offset,
|
||||
offset,
|
||||
}
|
||||
}
|
||||
None => {
|
||||
@ -793,7 +793,7 @@ impl TextureCache {
|
||||
|
||||
let update_op = TextureUpdate {
|
||||
id: existing_item.texture_id,
|
||||
op: op,
|
||||
op,
|
||||
};
|
||||
|
||||
self.pending_updates.push(update_op);
|
||||
@ -845,7 +845,7 @@ impl TextureCache {
|
||||
rect: result.item.allocated_rect,
|
||||
id: ext_image.id,
|
||||
channel_index: ext_image.channel_index,
|
||||
stride: stride,
|
||||
stride,
|
||||
offset: descriptor.offset,
|
||||
},
|
||||
};
|
||||
@ -866,7 +866,7 @@ impl TextureCache {
|
||||
width: result.item.allocated_rect.size.width,
|
||||
height: result.item.allocated_rect.size.height,
|
||||
data: bytes,
|
||||
stride: stride,
|
||||
stride,
|
||||
offset: descriptor.offset,
|
||||
},
|
||||
};
|
||||
@ -888,10 +888,10 @@ impl TextureCache {
|
||||
let update_op = TextureUpdate {
|
||||
id: result.item.texture_id,
|
||||
op: TextureUpdateOp::Create {
|
||||
width: width,
|
||||
height: height,
|
||||
format: format,
|
||||
filter: filter,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
filter,
|
||||
mode: RenderTargetMode::None,
|
||||
data: Some(data),
|
||||
},
|
||||
@ -905,10 +905,10 @@ impl TextureCache {
|
||||
let update_op = TextureUpdate {
|
||||
id: result.item.texture_id,
|
||||
op: TextureUpdateOp::Create {
|
||||
width: width,
|
||||
height: height,
|
||||
format: format,
|
||||
filter: filter,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
filter,
|
||||
mode: RenderTargetMode::None,
|
||||
data: Some(data),
|
||||
},
|
||||
@ -953,9 +953,9 @@ fn texture_create_op(texture_size: DeviceUintSize, format: ImageFormat, mode: Re
|
||||
TextureUpdateOp::Create {
|
||||
width: texture_size.width,
|
||||
height: texture_size.height,
|
||||
format: format,
|
||||
format,
|
||||
filter: TextureFilter::Linear,
|
||||
mode: mode,
|
||||
mode,
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
@ -967,9 +967,9 @@ fn texture_grow_op(texture_size: DeviceUintSize,
|
||||
TextureUpdateOp::Grow {
|
||||
width: texture_size.width,
|
||||
height: texture_size.height,
|
||||
format: format,
|
||||
format,
|
||||
filter: TextureFilter::Linear,
|
||||
mode: mode,
|
||||
mode,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,12 +7,10 @@ use border::{BorderCornerInstance, BorderCornerSide};
|
||||
use device::TextureId;
|
||||
use fnv::FnvHasher;
|
||||
use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheUpdateList};
|
||||
use gpu_store::GpuStoreAddress;
|
||||
use internal_types::{ANGLE_FLOAT_TO_FIXED, BatchTextures, CacheTextureId, LowLevelFilterOp};
|
||||
use internal_types::SourceTexture;
|
||||
use mask_cache::MaskCacheInfo;
|
||||
use prim_store::{CLIP_DATA_GPU_SIZE, DeferredResolve, GpuBlock32};
|
||||
use prim_store::{ImagePrimitiveKind, PrimitiveCacheKey};
|
||||
use prim_store::{CLIP_DATA_GPU_BLOCKS, DeferredResolve, ImagePrimitiveKind, PrimitiveCacheKey};
|
||||
use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore};
|
||||
use profiler::FrameProfileCounters;
|
||||
use render_task::{AlphaRenderItem, MaskGeometryKind, MaskSegment, RenderTask, RenderTaskData};
|
||||
@ -26,11 +24,11 @@ use std::collections::HashMap;
|
||||
use std::hash::BuildHasherDefault;
|
||||
use texture_cache::TexturePage;
|
||||
use util::{TransformedRect, TransformedRectKind};
|
||||
use webrender_traits::{BuiltDisplayList, ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint, ImageKey};
|
||||
use webrender_traits::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize};
|
||||
use webrender_traits::{ExternalImageType, FontRenderMode, ImageRendering, LayerRect};
|
||||
use webrender_traits::{LayerToWorldTransform, MixBlendMode, PipelineId, TransformStyle};
|
||||
use webrender_traits::{TileOffset, WorldToLayerTransform, YuvColorSpace, YuvFormat, LayerVector2D};
|
||||
use api::{BuiltDisplayList, ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint, ImageKey};
|
||||
use api::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize};
|
||||
use api::{ExternalImageType, FontRenderMode, ImageRendering, LayerRect};
|
||||
use api::{LayerToWorldTransform, MixBlendMode, PipelineId, TransformStyle};
|
||||
use api::{TileOffset, WorldToLayerTransform, YuvColorSpace, YuvFormat, LayerVector2D};
|
||||
|
||||
// Special sentinel value recognized by the shader. It is considered to be
|
||||
// a dummy task that doesn't mask out anything.
|
||||
@ -109,11 +107,13 @@ pub struct RenderTargetIndex(pub usize);
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct RenderPassIndex(isize);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DynamicTaskInfo {
|
||||
index: RenderTaskIndex,
|
||||
rect: DeviceIntRect,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RenderTaskCollection {
|
||||
pub render_task_data: Vec<RenderTaskData>,
|
||||
dynamic_tasks: HashMap<(RenderTaskKey, RenderPassIndex), DynamicTaskInfo, BuildHasherDefault<FnvHasher>>,
|
||||
@ -136,9 +136,9 @@ impl RenderTaskCollection {
|
||||
RenderTaskId::Dynamic(key) => {
|
||||
let index = RenderTaskIndex(self.render_task_data.len());
|
||||
let key = (key, pass);
|
||||
debug_assert!(self.dynamic_tasks.contains_key(&key) == false);
|
||||
debug_assert!(!self.dynamic_tasks.contains_key(&key));
|
||||
self.dynamic_tasks.insert(key, DynamicTaskInfo {
|
||||
index: index,
|
||||
index,
|
||||
rect: match task.location {
|
||||
RenderTaskLocation::Fixed => panic!("Dynamic tasks should not have fixed locations!"),
|
||||
RenderTaskLocation::Dynamic(Some((origin, _)), size) => DeviceIntRect::new(origin, size),
|
||||
@ -250,6 +250,18 @@ impl BatchList {
|
||||
|
||||
batch
|
||||
}
|
||||
|
||||
fn finalize(&mut self) {
|
||||
// Reverse the instance arrays in the opaque batches
|
||||
// to get maximum z-buffer efficiency by drawing
|
||||
// front-to-back.
|
||||
// TODO(gw): Maybe we can change the batch code to
|
||||
// build these in reverse and avoid having
|
||||
// to reverse the instance array here.
|
||||
for batch in &mut self.opaque_batches {
|
||||
batch.instances.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Encapsulates the logic of building batches for items that are blended.
|
||||
@ -368,7 +380,7 @@ impl AlphaRenderItem {
|
||||
OPAQUE_TASK_INDEX
|
||||
}
|
||||
};
|
||||
let needs_blending = !prim_metadata.is_opaque ||
|
||||
let needs_blending = !prim_metadata.opacity.is_opaque ||
|
||||
needs_clipping ||
|
||||
transform_kind == TransformedRectKind::Complex;
|
||||
let blend_mode = ctx.prim_store.get_blend_mode(needs_blending, prim_metadata);
|
||||
@ -660,6 +672,13 @@ impl AlphaBatcher {
|
||||
deferred_resolves);
|
||||
}
|
||||
}
|
||||
|
||||
self.batch_list.finalize();
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.batch_list.opaque_batches.is_empty() &&
|
||||
self.batch_list.alpha_batches.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
@ -695,40 +714,41 @@ impl ClipBatcher {
|
||||
let instance = CacheClipInstance {
|
||||
task_id: task_index.0 as i32,
|
||||
layer_index: packed_layer_index.0 as i32,
|
||||
address: GpuStoreAddress(0),
|
||||
address: 0,
|
||||
segment: 0,
|
||||
resource_address: 0,
|
||||
};
|
||||
|
||||
for clip_index in 0..info.effective_complex_clip_count as usize {
|
||||
let offset = info.complex_clip_range.start.0 + ((CLIP_DATA_GPU_SIZE * clip_index) as i32);
|
||||
for clip_index in 0 .. info.complex_clip_range.get_count() {
|
||||
let gpu_address = info.complex_clip_range.location.as_int(gpu_cache) +
|
||||
(CLIP_DATA_GPU_BLOCKS * clip_index) as i32;
|
||||
match geometry_kind {
|
||||
MaskGeometryKind::Default => {
|
||||
self.rectangles.push(CacheClipInstance {
|
||||
address: GpuStoreAddress(offset),
|
||||
address: gpu_address,
|
||||
segment: MaskSegment::All as i32,
|
||||
..instance
|
||||
});
|
||||
}
|
||||
MaskGeometryKind::CornersOnly => {
|
||||
self.rectangles.extend(&[
|
||||
self.rectangles.extend_from_slice(&[
|
||||
CacheClipInstance {
|
||||
address: GpuStoreAddress(offset),
|
||||
address: gpu_address,
|
||||
segment: MaskSegment::TopLeftCorner as i32,
|
||||
..instance
|
||||
},
|
||||
CacheClipInstance {
|
||||
address: GpuStoreAddress(offset),
|
||||
address: gpu_address,
|
||||
segment: MaskSegment::TopRightCorner as i32,
|
||||
..instance
|
||||
},
|
||||
CacheClipInstance {
|
||||
address: GpuStoreAddress(offset),
|
||||
address: gpu_address,
|
||||
segment: MaskSegment::BottomLeftCorner as i32,
|
||||
..instance
|
||||
},
|
||||
CacheClipInstance {
|
||||
address: GpuStoreAddress(offset),
|
||||
address: gpu_address,
|
||||
segment: MaskSegment::BottomRightCorner as i32,
|
||||
..instance
|
||||
},
|
||||
@ -737,24 +757,34 @@ impl ClipBatcher {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((ref mask, address)) = info.image {
|
||||
for clip_index in 0 .. info.layer_clip_range.get_count() {
|
||||
let gpu_address = info.layer_clip_range.location.as_int(gpu_cache) +
|
||||
(CLIP_DATA_GPU_BLOCKS * clip_index) as i32;
|
||||
self.rectangles.push(CacheClipInstance {
|
||||
address: gpu_address,
|
||||
segment: MaskSegment::All as i32,
|
||||
..instance
|
||||
});
|
||||
}
|
||||
|
||||
if let Some((ref mask, gpu_location)) = info.image {
|
||||
let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None);
|
||||
self.images.entry(cache_item.texture_id)
|
||||
.or_insert(Vec::new())
|
||||
.push(CacheClipInstance {
|
||||
address: address,
|
||||
address: gpu_location.as_int(gpu_cache),
|
||||
resource_address: cache_item.uv_rect_handle.as_int(gpu_cache),
|
||||
..instance
|
||||
})
|
||||
}
|
||||
|
||||
for &(ref source, gpu_address) in &info.border_corners {
|
||||
for &(ref source, gpu_location) in &info.border_corners {
|
||||
let gpu_address = gpu_location.as_int(gpu_cache);
|
||||
self.border_clears.push(CacheClipInstance {
|
||||
address: gpu_address,
|
||||
segment: 0,
|
||||
..instance
|
||||
});
|
||||
|
||||
for clip_index in 0..source.actual_clip_count {
|
||||
self.borders.push(CacheClipInstance {
|
||||
address: gpu_address,
|
||||
@ -852,8 +882,8 @@ impl<T: RenderTarget> RenderTargetList<T> {
|
||||
}
|
||||
|
||||
RenderTargetList {
|
||||
targets: targets,
|
||||
target_size: target_size,
|
||||
targets,
|
||||
target_size,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1134,7 +1164,7 @@ impl RenderPass {
|
||||
pub fn new(pass_index: isize, is_framebuffer: bool, size: DeviceUintSize) -> RenderPass {
|
||||
RenderPass {
|
||||
pass_index: RenderPassIndex(pass_index),
|
||||
is_framebuffer: is_framebuffer,
|
||||
is_framebuffer,
|
||||
color_targets: RenderTargetList::new(size, is_framebuffer),
|
||||
alpha_targets: RenderTargetList::new(size, false),
|
||||
tasks: vec![],
|
||||
@ -1254,9 +1284,9 @@ pub enum AlphaBatchKind {
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub flags AlphaBatchKeyFlags: u8 {
|
||||
const NEEDS_CLIPPING = 0b00000001,
|
||||
const AXIS_ALIGNED = 0b00000010,
|
||||
pub struct AlphaBatchKeyFlags: u8 {
|
||||
const NEEDS_CLIPPING = 0b00000001;
|
||||
const AXIS_ALIGNED = 0b00000010;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1288,10 +1318,10 @@ impl AlphaBatchKey {
|
||||
blend_mode: BlendMode,
|
||||
textures: BatchTextures) -> AlphaBatchKey {
|
||||
AlphaBatchKey {
|
||||
kind: kind,
|
||||
flags: flags,
|
||||
blend_mode: blend_mode,
|
||||
textures: textures,
|
||||
kind,
|
||||
flags,
|
||||
blend_mode,
|
||||
textures,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1333,7 +1363,7 @@ pub struct BlurCommand {
|
||||
pub struct CacheClipInstance {
|
||||
task_id: i32,
|
||||
layer_index: i32,
|
||||
address: GpuStoreAddress,
|
||||
address: i32,
|
||||
segment: i32,
|
||||
resource_address: i32,
|
||||
}
|
||||
@ -1365,11 +1395,11 @@ impl SimplePrimitiveInstance {
|
||||
layer_index: PackedLayerIndex,
|
||||
z_sort_index: i32) -> SimplePrimitiveInstance {
|
||||
SimplePrimitiveInstance {
|
||||
specific_prim_address: specific_prim_address,
|
||||
specific_prim_address,
|
||||
task_index: task_index.0 as i32,
|
||||
clip_task_index: clip_task_index.0 as i32,
|
||||
layer_index: layer_index.0 as i32,
|
||||
z_sort_index: z_sort_index,
|
||||
z_sort_index,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1406,12 +1436,12 @@ impl CompositePrimitiveInstance {
|
||||
data1: i32,
|
||||
z: i32) -> CompositePrimitiveInstance {
|
||||
CompositePrimitiveInstance {
|
||||
task_index: task_index,
|
||||
src_task_index: src_task_index,
|
||||
backdrop_task_index: backdrop_task_index,
|
||||
data0: data0,
|
||||
data1: data1,
|
||||
z: z,
|
||||
task_index,
|
||||
src_task_index,
|
||||
backdrop_task_index,
|
||||
data0,
|
||||
data1,
|
||||
z,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1456,7 +1486,7 @@ pub struct PrimitiveBatch {
|
||||
impl PrimitiveBatch {
|
||||
fn new(key: AlphaBatchKey) -> PrimitiveBatch {
|
||||
PrimitiveBatch {
|
||||
key: key,
|
||||
key,
|
||||
instances: Vec::new(),
|
||||
item_rects: Vec::new(),
|
||||
}
|
||||
@ -1499,13 +1529,15 @@ pub struct StackingContext {
|
||||
/// The `ClipId` of the owning reference frame.
|
||||
pub reference_frame_id: ClipId,
|
||||
|
||||
/// Local bounding rectangle for this stacking context.
|
||||
pub local_bounds: LayerRect,
|
||||
|
||||
/// Screen space bounding rectangle for this stacking context,
|
||||
/// calculated based on the size and position of all its children.
|
||||
pub screen_bounds: DeviceIntRect,
|
||||
|
||||
/// Local bounding rectangle of this stacking context,
|
||||
/// computed as the union of all contained items that are not
|
||||
/// `ContextIsolation::Items` on their own
|
||||
pub isolated_items_bounds: LayerRect,
|
||||
|
||||
pub composite_ops: CompositeOps,
|
||||
pub clip_scroll_groups: Vec<ClipScrollGroupIndex>,
|
||||
|
||||
@ -1526,7 +1558,6 @@ impl StackingContext {
|
||||
reference_frame_offset: LayerVector2D,
|
||||
is_page_root: bool,
|
||||
reference_frame_id: ClipId,
|
||||
local_bounds: LayerRect,
|
||||
transform_style: TransformStyle,
|
||||
composite_ops: CompositeOps)
|
||||
-> StackingContext {
|
||||
@ -1535,15 +1566,15 @@ impl StackingContext {
|
||||
TransformStyle::Preserve3D => ContextIsolation::Items,
|
||||
};
|
||||
StackingContext {
|
||||
pipeline_id: pipeline_id,
|
||||
reference_frame_offset: reference_frame_offset,
|
||||
reference_frame_id: reference_frame_id,
|
||||
local_bounds: local_bounds,
|
||||
pipeline_id,
|
||||
reference_frame_offset,
|
||||
reference_frame_id,
|
||||
screen_bounds: DeviceIntRect::zero(),
|
||||
composite_ops: composite_ops,
|
||||
isolated_items_bounds: LayerRect::zero(),
|
||||
composite_ops,
|
||||
clip_scroll_groups: Vec::new(),
|
||||
isolation: isolation,
|
||||
is_page_root: is_page_root,
|
||||
isolation,
|
||||
is_page_root,
|
||||
is_visible: false,
|
||||
}
|
||||
}
|
||||
@ -1610,9 +1641,15 @@ impl PackedLayer {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn set_transform(&mut self, transform: LayerToWorldTransform) {
|
||||
pub fn set_transform(&mut self, transform: LayerToWorldTransform) -> bool {
|
||||
self.transform = transform;
|
||||
self.inv_transform = self.transform.inverse().unwrap();
|
||||
match self.transform.inverse() {
|
||||
Some(inv) => {
|
||||
self.inv_transform = inv;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_rect(&mut self,
|
||||
@ -1620,11 +1657,10 @@ impl PackedLayer {
|
||||
screen_rect: &DeviceIntRect,
|
||||
device_pixel_ratio: f32)
|
||||
-> Option<(TransformedRectKind, DeviceIntRect)> {
|
||||
let xf_rect = TransformedRect::new(&local_rect, &self.transform, device_pixel_ratio);
|
||||
xf_rect.bounding_rect.intersection(screen_rect).map(|rect| {
|
||||
self.local_clip_rect = *local_rect;
|
||||
(xf_rect.kind, rect)
|
||||
})
|
||||
self.local_clip_rect = *local_rect;
|
||||
let xf_rect = TransformedRect::new(local_rect, &self.transform, device_pixel_ratio);
|
||||
xf_rect.bounding_rect.intersection(screen_rect)
|
||||
.map(|rect| (xf_rect.kind, rect))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1640,7 +1676,7 @@ pub struct CompositeOps {
|
||||
impl CompositeOps {
|
||||
pub fn new(filters: Vec<LowLevelFilterOp>, mix_blend_mode: Option<MixBlendMode>) -> CompositeOps {
|
||||
CompositeOps {
|
||||
filters: filters,
|
||||
filters,
|
||||
mix_blend_mode: mix_blend_mode
|
||||
}
|
||||
}
|
||||
@ -1680,7 +1716,6 @@ pub struct Frame {
|
||||
|
||||
pub layer_texture_data: Vec<PackedLayer>,
|
||||
pub render_task_data: Vec<RenderTaskData>,
|
||||
pub gpu_data32: Vec<GpuBlock32>,
|
||||
|
||||
// List of updates that need to be pushed to the
|
||||
// gpu resource cache.
|
||||
@ -1710,7 +1745,7 @@ fn resolve_image(image_key: ImageKey,
|
||||
// the render thread...
|
||||
let cache_handle = gpu_cache.push_deferred_per_frame_blocks(1);
|
||||
deferred_resolves.push(DeferredResolve {
|
||||
image_properties: image_properties,
|
||||
image_properties,
|
||||
address: gpu_cache.get_address(&cache_handle),
|
||||
});
|
||||
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
use std::f32::consts::{FRAC_1_SQRT_2};
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedTransform3D};
|
||||
use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize};
|
||||
use webrender_traits::{LayerRect, WorldPoint3D, LayerToWorldTransform};
|
||||
use webrender_traits::{BorderRadius, ComplexClipRegion, LayoutRect};
|
||||
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedTransform2D, TypedTransform3D};
|
||||
use api::{DeviceIntRect, DevicePoint, DeviceRect, DeviceSize};
|
||||
use api::{LayerRect, WorldPoint3D, LayerToWorldTransform};
|
||||
use api::{BorderRadius, ComplexClipRegion, LayoutRect};
|
||||
use num_traits::Zero;
|
||||
|
||||
// Matches the definition of SK_ScalarNearlyZero in Skia.
|
||||
@ -18,6 +18,8 @@ pub trait MatrixHelpers<Src, Dst> {
|
||||
fn transform_rect(&self, rect: &TypedRect<f32, Src>) -> TypedRect<f32, Dst>;
|
||||
fn is_identity(&self) -> bool;
|
||||
fn preserves_2d_axis_alignment(&self) -> bool;
|
||||
fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>>;
|
||||
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src>;
|
||||
}
|
||||
|
||||
impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
|
||||
@ -64,6 +66,31 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
|
||||
|
||||
col0 < 2 && col1 < 2 && row0 < 2 && row1 < 2
|
||||
}
|
||||
|
||||
fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>> {
|
||||
let m: TypedTransform2D<f32, Src, Dst>;
|
||||
m = TypedTransform2D::column_major(self.m11 - target.x * self.m14,
|
||||
self.m21 - target.x * self.m24,
|
||||
self.m41 - target.x * self.m44,
|
||||
self.m12 - target.y * self.m14,
|
||||
self.m22 - target.y * self.m24,
|
||||
self.m42 - target.y * self.m44);
|
||||
m.inverse()
|
||||
.map(|inv| TypedPoint2D::new(inv.m31, inv.m32))
|
||||
}
|
||||
|
||||
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src> {
|
||||
TypedRect::from_points(&[
|
||||
self.inverse_project(&rect.origin)
|
||||
.unwrap_or(TypedPoint2D::zero()),
|
||||
self.inverse_project(&rect.top_right())
|
||||
.unwrap_or(TypedPoint2D::zero()),
|
||||
self.inverse_project(&rect.bottom_left())
|
||||
.unwrap_or(TypedPoint2D::zero()),
|
||||
self.inverse_project(&rect.bottom_right())
|
||||
.unwrap_or(TypedPoint2D::zero()),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
pub trait RectHelpers<U> where Self: Sized {
|
||||
@ -175,6 +202,13 @@ pub struct TransformedRect {
|
||||
pub kind: TransformedRectKind,
|
||||
}
|
||||
|
||||
// Having an unlimited bounding box is fine up until we try
|
||||
// to cast it to `i32`, where we get `-2147483648` for any
|
||||
// values larger than or equal to 2^31.
|
||||
//Note: clamping to i32::MIN and i32::MAX is not a solution,
|
||||
// with explanation left as an exercise for the reader.
|
||||
const MAX_COORD: f32 = 1.0e9;
|
||||
|
||||
impl TransformedRect {
|
||||
pub fn new(rect: &LayerRect,
|
||||
transform: &LayerToWorldTransform,
|
||||
@ -186,80 +220,43 @@ impl TransformedRect {
|
||||
TransformedRectKind::Complex
|
||||
};
|
||||
|
||||
// FIXME(gw): This code is meant to be a fast path for simple transforms.
|
||||
// However, it fails on transforms that translate Z but result in an
|
||||
// axis aligned rect.
|
||||
|
||||
/*
|
||||
match kind {
|
||||
TransformedRectKind::AxisAligned => {
|
||||
let v0 = transform.transform_point(&rect.origin);
|
||||
let v1 = transform.transform_point(&rect.top_right());
|
||||
let v2 = transform.transform_point(&rect.bottom_left());
|
||||
let v3 = transform.transform_point(&rect.bottom_right());
|
||||
let vertices = [
|
||||
transform.transform_point3d(&rect.origin.to_3d()),
|
||||
transform.transform_point3d(&rect.bottom_left().to_3d()),
|
||||
transform.transform_point3d(&rect.bottom_right().to_3d()),
|
||||
transform.transform_point3d(&rect.top_right().to_3d()),
|
||||
];
|
||||
|
||||
let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32),
|
||||
DevicePixel((v0.y * device_pixel_ratio).floor() as i32));
|
||||
let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32),
|
||||
DevicePixel((v3.y * device_pixel_ratio).ceil() as i32));
|
||||
let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);
|
||||
|
||||
let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x,
|
||||
screen_max_dp.y - screen_min_dp.y));
|
||||
for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
|
||||
*x = get_normal(vertex.x).unwrap_or(0.0);
|
||||
*y = get_normal(vertex.y).unwrap_or(0.0);
|
||||
}
|
||||
|
||||
TransformedRect {
|
||||
local_rect: *rect,
|
||||
vertices: [
|
||||
Point4D::new(v0.x, v0.y, 0.0, 1.0),
|
||||
Point4D::new(v1.x, v1.y, 0.0, 1.0),
|
||||
Point4D::new(v2.x, v2.y, 0.0, 1.0),
|
||||
Point4D::new(v3.x, v3.y, 0.0, 1.0),
|
||||
],
|
||||
bounding_rect: screen_rect_dp,
|
||||
kind: kind,
|
||||
}
|
||||
}
|
||||
TransformedRectKind::Complex => {
|
||||
*/
|
||||
let vertices = [
|
||||
transform.transform_point3d(&rect.origin.to_3d()),
|
||||
transform.transform_point3d(&rect.bottom_left().to_3d()),
|
||||
transform.transform_point3d(&rect.bottom_right().to_3d()),
|
||||
transform.transform_point3d(&rect.top_right().to_3d()),
|
||||
];
|
||||
xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
ys.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
|
||||
let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);
|
||||
let outer_min_dp = (DevicePoint::new(xs[0], ys[0]) * device_pixel_ratio).floor();
|
||||
let outer_max_dp = (DevicePoint::new(xs[3], ys[3]) * device_pixel_ratio).ceil();
|
||||
let inner_min_dp = (DevicePoint::new(xs[1], ys[1]) * device_pixel_ratio).ceil();
|
||||
let inner_max_dp = (DevicePoint::new(xs[2], ys[2]) * device_pixel_ratio).floor();
|
||||
|
||||
for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
|
||||
*x = get_normal(vertex.x).unwrap_or(0.0);
|
||||
*y = get_normal(vertex.y).unwrap_or(0.0);
|
||||
}
|
||||
let max_rect = DeviceRect::new(DevicePoint::new(-MAX_COORD, -MAX_COORD),
|
||||
DeviceSize::new(2.0*MAX_COORD, 2.0*MAX_COORD));
|
||||
let bounding_rect = DeviceRect::new(outer_min_dp, (outer_max_dp - outer_min_dp).to_size())
|
||||
.intersection(&max_rect).unwrap_or(max_rect).to_i32();
|
||||
let inner_rect = DeviceRect::new(inner_min_dp, (inner_max_dp - inner_min_dp).to_size())
|
||||
.intersection(&max_rect).unwrap_or(max_rect).to_i32();
|
||||
|
||||
xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
ys.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
||||
|
||||
let outer_min_dp = DeviceIntPoint::new((xs[0] * device_pixel_ratio).floor() as i32,
|
||||
(ys[0] * device_pixel_ratio).floor() as i32);
|
||||
let outer_max_dp = DeviceIntPoint::new((xs[3] * device_pixel_ratio).ceil() as i32,
|
||||
(ys[3] * device_pixel_ratio).ceil() as i32);
|
||||
let inner_min_dp = DeviceIntPoint::new((xs[1] * device_pixel_ratio).ceil() as i32,
|
||||
(ys[1] * device_pixel_ratio).ceil() as i32);
|
||||
let inner_max_dp = DeviceIntPoint::new((xs[2] * device_pixel_ratio).floor() as i32,
|
||||
(ys[2] * device_pixel_ratio).floor() as i32);
|
||||
|
||||
TransformedRect {
|
||||
local_rect: *rect,
|
||||
vertices: vertices,
|
||||
bounding_rect: DeviceIntRect::new(outer_min_dp,
|
||||
DeviceIntSize::new(outer_max_dp.x.saturating_sub(outer_min_dp.x),
|
||||
outer_max_dp.y.saturating_sub(outer_min_dp.y))),
|
||||
inner_rect: DeviceIntRect::new(inner_min_dp,
|
||||
DeviceIntSize::new(inner_max_dp.x.saturating_sub(inner_min_dp.x),
|
||||
inner_max_dp.y.saturating_sub(inner_min_dp.y))),
|
||||
kind: kind,
|
||||
}
|
||||
/*
|
||||
}
|
||||
}*/
|
||||
TransformedRect {
|
||||
local_rect: *rect,
|
||||
vertices,
|
||||
bounding_rect,
|
||||
inner_rect,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,3 +324,22 @@ pub fn recycle_vec<T>(mut old_vec: Vec<T>) -> Vec<T> {
|
||||
|
||||
return old_vec;
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
use euclid::{Point2D, Radians, Transform3D};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
#[test]
|
||||
fn inverse_project() {
|
||||
let m0 = Transform3D::identity();
|
||||
let p0 = Point2D::new(1.0, 2.0);
|
||||
// an identical transform doesn't need any inverse projection
|
||||
assert_eq!(m0.inverse_project(&p0), Some(p0));
|
||||
let m1 = Transform3D::create_rotation(0.0, 1.0, 0.0, Radians::new(PI / 3.0));
|
||||
// rotation by 60 degrees would imply scaling of X component by a factor of 2
|
||||
assert_eq!(m1.inverse_project(&p0), Some(Point2D::new(2.0, 2.0)));
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,9 @@
|
||||
//! The API surface provided here should be roughly the same to the one provided
|
||||
//! in webgl_types, modulo completely compiled-out stuff.
|
||||
|
||||
use webrender_traits::DeviceIntSize;
|
||||
use webrender_traits::{GLContextAttributes, GLLimits};
|
||||
use webrender_traits::WebGLCommand;
|
||||
use api::DeviceIntSize;
|
||||
use api::{GLContextAttributes, GLLimits};
|
||||
use api::WebGLCommand;
|
||||
|
||||
pub struct GLContextHandleWrapper;
|
||||
|
||||
|
@ -10,7 +10,7 @@ use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle};
|
||||
use offscreen_gl_context::{GLContext, NativeGLContextMethods, GLContextDispatcher};
|
||||
use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle};
|
||||
use offscreen_gl_context::{ColorAttachmentType, GLContextAttributes, GLLimits};
|
||||
use webrender_traits::{WebGLCommand, DeviceIntSize};
|
||||
use api::{WebGLCommand, DeviceIntSize};
|
||||
|
||||
pub enum GLContextHandleWrapper {
|
||||
Native(NativeGLContextHandle),
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "webrender_traits"
|
||||
version = "0.43.0"
|
||||
name = "webrender_api"
|
||||
version = "0.47.0"
|
||||
authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/servo/webrender"
|
@ -117,7 +117,7 @@ pub struct GLLimits([u8; 0]);
|
||||
#[cfg(not(feature = "webgl"))]
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub enum WebGLCommand {
|
||||
Flush,
|
||||
FenceAndWaitSync,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -164,8 +164,8 @@ impl RenderApiSender {
|
||||
payload_sender: PayloadSender)
|
||||
-> RenderApiSender {
|
||||
RenderApiSender {
|
||||
api_sender: api_sender,
|
||||
payload_sender: payload_sender,
|
||||
api_sender,
|
||||
payload_sender,
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,7 +271,7 @@ impl RenderApi {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use webrender_traits::{PipelineId, RenderApiSender};
|
||||
/// # use webrender_api::{PipelineId, RenderApiSender};
|
||||
/// # fn example(sender: RenderApiSender) {
|
||||
/// let api = sender.create_api();
|
||||
/// // ...
|
||||
@ -322,9 +322,9 @@ impl RenderApi {
|
||||
self.api_sender.send(msg).unwrap();
|
||||
|
||||
self.payload_sender.send_payload(Payload {
|
||||
epoch: epoch,
|
||||
pipeline_id: pipeline_id,
|
||||
display_list_data: display_list_data,
|
||||
epoch,
|
||||
pipeline_id,
|
||||
display_list_data,
|
||||
}).unwrap();
|
||||
}
|
||||
|
||||
@ -507,7 +507,6 @@ impl PropertyBindingId {
|
||||
|
||||
/// A unique key that is used for connecting animated property
|
||||
/// values to bindings in the display list.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct PropertyBindingKey<T> {
|
||||
pub id: PropertyBindingId,
|
||||
@ -519,7 +518,7 @@ impl<T: Copy> PropertyBindingKey<T> {
|
||||
pub fn with(&self, value: T) -> PropertyValue<T> {
|
||||
PropertyValue {
|
||||
key: *self,
|
||||
value: value,
|
||||
value,
|
||||
}
|
||||
}
|
||||
}
|
@ -53,8 +53,8 @@ impl Payload {
|
||||
assert_eq!(payload_reader.position(), data.len() as u64);
|
||||
|
||||
Payload {
|
||||
epoch: epoch,
|
||||
pipeline_id: pipeline_id,
|
||||
epoch,
|
||||
pipeline_id,
|
||||
display_list_data: built_display_list_data,
|
||||
}
|
||||
}
|
@ -65,11 +65,10 @@ impl ColorU {
|
||||
|
||||
pub fn new(r: u8, g: u8, b: u8, a: u8) -> ColorU {
|
||||
ColorU {
|
||||
r: r,
|
||||
g: g,
|
||||
b: b,
|
||||
a: a,
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,8 @@
|
||||
|
||||
use app_units::Au;
|
||||
use euclid::SideOffsets2D;
|
||||
use {ColorF, FontKey, ImageKey, ItemRange, PipelineId, WebGLContextId};
|
||||
use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D};
|
||||
use {PropertyBinding};
|
||||
use {ColorF, FontKey, ImageKey, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
|
||||
use {LayoutVector2D, PipelineId, PropertyBinding, WebGLContextId};
|
||||
|
||||
// NOTE: some of these structs have an "IMPLICIT" comment.
|
||||
// This indicates that the BuiltDisplayList will have serialized
|
||||
@ -29,7 +28,7 @@ impl ClipAndScrollInfo {
|
||||
|
||||
pub fn new(scroll_node_id: ClipId, clip_node_id: ClipId) -> ClipAndScrollInfo {
|
||||
ClipAndScrollInfo {
|
||||
scroll_node_id: scroll_node_id,
|
||||
scroll_node_id,
|
||||
clip_node_id: Some(clip_node_id),
|
||||
}
|
||||
}
|
||||
@ -43,12 +42,14 @@ impl ClipAndScrollInfo {
|
||||
pub struct DisplayItem {
|
||||
pub item: SpecificDisplayItem,
|
||||
pub rect: LayoutRect,
|
||||
pub local_clip: LocalClip,
|
||||
pub clip_and_scroll: ClipAndScrollInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub enum SpecificDisplayItem {
|
||||
Clip(ClipDisplayItem),
|
||||
ScrollFrame(ClipDisplayItem),
|
||||
Rectangle(RectangleDisplayItem),
|
||||
Text(TextDisplayItem),
|
||||
Image(ImageDisplayItem),
|
||||
@ -62,7 +63,6 @@ pub enum SpecificDisplayItem {
|
||||
PushStackingContext(PushStackingContextDisplayItem),
|
||||
PopStackingContext,
|
||||
SetGradientStops,
|
||||
SetClipRegion(ClipRegion),
|
||||
PushNestedDisplayList,
|
||||
PopNestedDisplayList,
|
||||
}
|
||||
@ -71,6 +71,7 @@ pub enum SpecificDisplayItem {
|
||||
pub struct ClipDisplayItem {
|
||||
pub id: ClipId,
|
||||
pub parent_id: ClipId,
|
||||
pub image_mask: Option<ImageMask>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
@ -118,6 +119,7 @@ pub enum RepeatMode {
|
||||
Space,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct NinePatchDescriptor {
|
||||
pub width: u32,
|
||||
@ -129,6 +131,9 @@ pub struct NinePatchDescriptor {
|
||||
pub struct ImageBorder {
|
||||
pub image_key: ImageKey,
|
||||
pub patch: NinePatchDescriptor,
|
||||
/// Controls whether the center of the 9 patch image is
|
||||
/// rendered or ignored.
|
||||
pub fill: bool,
|
||||
pub outset: SideOffsets2D<f32>,
|
||||
pub repeat_horizontal: RepeatMode,
|
||||
pub repeat_vertical: RepeatMode,
|
||||
@ -160,6 +165,7 @@ pub struct BorderDisplayItem {
|
||||
pub details: BorderDetails,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct BorderRadius {
|
||||
pub top_left: LayoutSize,
|
||||
@ -168,6 +174,7 @@ pub struct BorderRadius {
|
||||
pub bottom_right: LayoutSize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct BorderWidths {
|
||||
pub left: f32,
|
||||
@ -432,6 +439,7 @@ impl YuvFormat {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct ImageMask {
|
||||
pub image: ImageKey,
|
||||
@ -440,13 +448,24 @@ pub struct ImageMask {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
pub struct ClipRegion {
|
||||
pub main: LayoutRect,
|
||||
pub image_mask: Option<ImageMask>,
|
||||
#[serde(default, skip_serializing, skip_deserializing)]
|
||||
pub complex_clips: ItemRange<ComplexClipRegion>,
|
||||
#[serde(default, skip_serializing, skip_deserializing)]
|
||||
pub complex_clip_count: usize,
|
||||
pub enum LocalClip {
|
||||
Rect(LayoutRect),
|
||||
RoundedRect(LayoutRect, ComplexClipRegion),
|
||||
}
|
||||
|
||||
impl From<LayoutRect> for LocalClip {
|
||||
fn from(rect: LayoutRect) -> Self {
|
||||
LocalClip::Rect(rect)
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalClip {
|
||||
pub fn clip_rect(&self) -> &LayoutRect {
|
||||
match *self {
|
||||
LocalClip::Rect(ref rect) => rect,
|
||||
LocalClip::RoundedRect(ref rect, _) => &rect,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
@ -512,48 +531,13 @@ impl BorderRadius {
|
||||
}
|
||||
}
|
||||
|
||||
impl ClipRegion {
|
||||
pub fn new(rect: &LayoutRect,
|
||||
image_mask: Option<ImageMask>)
|
||||
-> ClipRegion {
|
||||
ClipRegion {
|
||||
main: *rect,
|
||||
image_mask: image_mask,
|
||||
complex_clips: ItemRange::default(),
|
||||
complex_clip_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn simple(rect: &LayoutRect) -> ClipRegion {
|
||||
ClipRegion {
|
||||
main: *rect,
|
||||
image_mask: None,
|
||||
complex_clips: ItemRange::default(),
|
||||
complex_clip_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> ClipRegion {
|
||||
ClipRegion {
|
||||
main: LayoutRect::zero(),
|
||||
image_mask: None,
|
||||
complex_clips: ItemRange::default(),
|
||||
complex_clip_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_complex(&self) -> bool {
|
||||
self.complex_clip_count != 0 || self.image_mask.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl ColorF {
|
||||
pub fn new(r: f32, g: f32, b: f32, a: f32) -> ColorF {
|
||||
ColorF {
|
||||
r: r,
|
||||
g: g,
|
||||
b: b,
|
||||
a: a,
|
||||
r,
|
||||
g,
|
||||
b,
|
||||
a,
|
||||
}
|
||||
}
|
||||
|
||||
@ -575,8 +559,8 @@ impl ComplexClipRegion {
|
||||
/// Create a new complex clip region.
|
||||
pub fn new(rect: LayoutRect, radii: BorderRadius) -> ComplexClipRegion {
|
||||
ComplexClipRegion {
|
||||
rect: rect,
|
||||
radii: radii,
|
||||
rect,
|
||||
radii,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -652,3 +636,4 @@ define_empty_heap_size_of!(RepeatMode);
|
||||
define_empty_heap_size_of!(ImageKey);
|
||||
define_empty_heap_size_of!(MixBlendMode);
|
||||
define_empty_heap_size_of!(TransformStyle);
|
||||
define_empty_heap_size_of!(LocalClip);
|
@ -8,14 +8,14 @@ use serde::{Deserialize, Serialize, Serializer};
|
||||
use serde::ser::{SerializeSeq, SerializeMap};
|
||||
use time::precise_time_ns;
|
||||
use {BorderDetails, BorderDisplayItem, BorderWidths, BoxShadowClipMode, BoxShadowDisplayItem};
|
||||
use {ClipAndScrollInfo, ClipDisplayItem, ClipId, ClipRegion, ColorF, ComplexClipRegion};
|
||||
use {DisplayItem, ExtendMode, FilterOp, FontKey, GlyphInstance, GlyphOptions, Gradient};
|
||||
use {GradientDisplayItem, GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask};
|
||||
use {ImageRendering, LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, MixBlendMode};
|
||||
use {PipelineId, PropertyBinding, PushStackingContextDisplayItem, RadialGradient};
|
||||
use {ClipAndScrollInfo, ClipDisplayItem, ClipId, ColorF, ComplexClipRegion, DisplayItem};
|
||||
use {ExtendMode, FilterOp, FontKey, GlyphInstance, GlyphOptions, Gradient, GradientDisplayItem};
|
||||
use {GradientStop, IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering};
|
||||
use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D, LocalClip};
|
||||
use {MixBlendMode, PipelineId, PropertyBinding, PushStackingContextDisplayItem, RadialGradient};
|
||||
use {RadialGradientDisplayItem, RectangleDisplayItem, ScrollPolicy, SpecificDisplayItem};
|
||||
use {StackingContext, TextDisplayItem, TransformStyle, WebGLContextId, WebGLDisplayItem};
|
||||
use {YuvColorSpace, YuvData, YuvImageDisplayItem, LayoutVector2D};
|
||||
use {YuvColorSpace, YuvData, YuvImageDisplayItem};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[repr(C)]
|
||||
@ -67,7 +67,7 @@ pub struct BuiltDisplayListIter<'a> {
|
||||
cur_stops: ItemRange<GradientStop>,
|
||||
cur_glyphs: ItemRange<GlyphInstance>,
|
||||
cur_filters: ItemRange<FilterOp>,
|
||||
cur_clip: ClipRegion,
|
||||
cur_complex_clip: (ItemRange<ComplexClipRegion>, usize),
|
||||
peeking: Peek,
|
||||
}
|
||||
|
||||
@ -95,8 +95,8 @@ impl BuiltDisplayListDescriptor {
|
||||
impl BuiltDisplayList {
|
||||
pub fn from_data(data: Vec<u8>, descriptor: BuiltDisplayListDescriptor) -> BuiltDisplayList {
|
||||
BuiltDisplayList {
|
||||
data: data,
|
||||
descriptor: descriptor,
|
||||
data,
|
||||
descriptor,
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,19 +127,23 @@ impl BuiltDisplayList {
|
||||
|
||||
impl<'a> BuiltDisplayListIter<'a> {
|
||||
pub fn new(list: &'a BuiltDisplayList) -> Self {
|
||||
Self::new_with_list_and_data(list, &list.data)
|
||||
}
|
||||
|
||||
pub fn new_with_list_and_data(list: &'a BuiltDisplayList, data: &'a [u8]) -> Self {
|
||||
BuiltDisplayListIter {
|
||||
list: list,
|
||||
data: &list.data,
|
||||
// Dummy data, will be overwritten by `next`
|
||||
cur_item: DisplayItem {
|
||||
list,
|
||||
data: &data,
|
||||
cur_item: DisplayItem { // Dummy data, will be overwritten by `next`
|
||||
item: SpecificDisplayItem::PopStackingContext,
|
||||
rect: LayoutRect::zero(),
|
||||
local_clip: LocalClip::from(LayoutRect::zero()),
|
||||
clip_and_scroll: ClipAndScrollInfo::simple(ClipId::new(0, PipelineId(0, 0))),
|
||||
},
|
||||
cur_stops: ItemRange::default(),
|
||||
cur_glyphs: ItemRange::default(),
|
||||
cur_filters: ItemRange::default(),
|
||||
cur_clip: ClipRegion::empty(),
|
||||
cur_complex_clip: (ItemRange::default(), 0),
|
||||
peeking: Peek::NotPeeking,
|
||||
}
|
||||
}
|
||||
@ -164,7 +168,7 @@ impl<'a> BuiltDisplayListIter<'a> {
|
||||
|
||||
// Don't let these bleed into another item
|
||||
self.cur_stops = ItemRange::default();
|
||||
self.cur_clip = ClipRegion::empty();
|
||||
self.cur_complex_clip = (ItemRange::default(), 0);
|
||||
|
||||
loop {
|
||||
if self.data.len() == 0 {
|
||||
@ -175,27 +179,16 @@ impl<'a> BuiltDisplayListIter<'a> {
|
||||
.expect("MEH: malicious process?");
|
||||
|
||||
match self.cur_item.item {
|
||||
SetClipRegion(clip) => {
|
||||
self.cur_clip = clip;
|
||||
let (clip_range, clip_count) = self.skip_slice::<ComplexClipRegion>();
|
||||
self.cur_clip.complex_clip_count = clip_count;
|
||||
self.cur_clip.complex_clips = clip_range;
|
||||
|
||||
// This is a dummy item, skip over it
|
||||
continue;
|
||||
}
|
||||
SetGradientStops => {
|
||||
self.cur_stops = self.skip_slice::<GradientStop>().0;
|
||||
|
||||
// This is a dummy item, skip over it
|
||||
continue;
|
||||
}
|
||||
Text(_) => {
|
||||
self.cur_glyphs = self.skip_slice::<GlyphInstance>().0;
|
||||
}
|
||||
PushStackingContext(_) => {
|
||||
self.cur_filters = self.skip_slice::<FilterOp>().0;
|
||||
}
|
||||
Clip(_) | ScrollFrame(_) =>
|
||||
self.cur_complex_clip = self.skip_slice::<ComplexClipRegion>(),
|
||||
Text(_) => self.cur_glyphs = self.skip_slice::<GlyphInstance>().0,
|
||||
PushStackingContext(_) => self.cur_filters = self.skip_slice::<FilterOp>().0,
|
||||
_ => { /* do nothing */ }
|
||||
}
|
||||
|
||||
@ -279,6 +272,10 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
|
||||
self.iter.cur_item.rect
|
||||
}
|
||||
|
||||
pub fn local_clip(&self) -> &LocalClip {
|
||||
&self.iter.cur_item.local_clip
|
||||
}
|
||||
|
||||
pub fn clip_and_scroll(&self) -> ClipAndScrollInfo {
|
||||
self.iter.cur_item.clip_and_scroll
|
||||
}
|
||||
@ -287,8 +284,8 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
|
||||
&self.iter.cur_item.item
|
||||
}
|
||||
|
||||
pub fn clip_region(&self) -> &ClipRegion {
|
||||
&self.iter.cur_clip
|
||||
pub fn complex_clip(&self) -> &(ItemRange<ComplexClipRegion>, usize) {
|
||||
&self.iter.cur_complex_clip
|
||||
}
|
||||
|
||||
pub fn gradient_stops(&self) -> ItemRange<GradientStop> {
|
||||
@ -307,24 +304,9 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> {
|
||||
self.iter.display_list()
|
||||
}
|
||||
|
||||
// Creates a new iterator where this element's iterator
|
||||
// is, to hack around borrowck.
|
||||
// Creates a new iterator where this element's iterator is, to hack around borrowck.
|
||||
pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
|
||||
BuiltDisplayListIter {
|
||||
list: self.iter.list,
|
||||
data: self.iter.data,
|
||||
// Dummy data, will be overwritten by `next`
|
||||
cur_item: DisplayItem {
|
||||
item: SpecificDisplayItem::PopStackingContext,
|
||||
rect: LayoutRect::zero(),
|
||||
clip_and_scroll: ClipAndScrollInfo::simple(ClipId::new(0, PipelineId(0, 0))),
|
||||
},
|
||||
cur_stops: ItemRange::default(),
|
||||
cur_glyphs: ItemRange::default(),
|
||||
cur_filters: ItemRange::default(),
|
||||
cur_clip: ClipRegion::empty(),
|
||||
peeking: Peek::NotPeeking,
|
||||
}
|
||||
BuiltDisplayListIter::new_with_list_and_data(self.iter.list, self.iter.data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,8 +321,8 @@ impl<'de, 'a, T: Deserialize<'de>> AuxIter<'a, T> {
|
||||
};
|
||||
|
||||
AuxIter {
|
||||
data: data,
|
||||
size: size,
|
||||
data,
|
||||
size,
|
||||
_boo: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -397,13 +379,12 @@ impl<'a, 'b> Serialize for DisplayItemRef<'a, 'b> {
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let clip_region = self.clip_region();
|
||||
let &(complex_clips, number_of_complex_clips) = self.complex_clip();
|
||||
let gradient_stops = self.gradient_stops();
|
||||
|
||||
map.serialize_entry("clip_region", &clip_region)?;
|
||||
if !clip_region.complex_clips.is_empty() {
|
||||
if number_of_complex_clips > 0 {
|
||||
map.serialize_entry("complex_clips",
|
||||
&self.iter.list.get(clip_region.complex_clips).collect::<Vec<_>>())?;
|
||||
&self.iter.list.get(complex_clips).collect::<Vec<_>>())?;
|
||||
}
|
||||
|
||||
if !gradient_stops.is_empty() {
|
||||
@ -443,11 +424,11 @@ impl DisplayListBuilder {
|
||||
|
||||
DisplayListBuilder {
|
||||
data: Vec::with_capacity(capacity),
|
||||
pipeline_id: pipeline_id,
|
||||
pipeline_id,
|
||||
clip_stack: vec![ClipAndScrollInfo::simple(ClipId::root_scroll_node(pipeline_id))],
|
||||
next_clip_id: FIRST_CLIP_ID,
|
||||
builder_start_time: start_time,
|
||||
content_size: content_size,
|
||||
content_size,
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,18 +446,24 @@ impl DisplayListBuilder {
|
||||
self.data = temp.data;
|
||||
}
|
||||
|
||||
fn push_item(&mut self, item: SpecificDisplayItem, rect: LayoutRect) {
|
||||
fn push_item(&mut self,
|
||||
item: SpecificDisplayItem,
|
||||
rect: LayoutRect,
|
||||
local_clip: Option<LocalClip>) {
|
||||
let local_clip = local_clip.unwrap_or_else(|| LocalClip::from(rect));
|
||||
bincode::serialize_into(&mut self.data, &DisplayItem {
|
||||
item: item,
|
||||
rect: rect,
|
||||
item,
|
||||
rect,
|
||||
local_clip: local_clip,
|
||||
clip_and_scroll: *self.clip_stack.last().unwrap(),
|
||||
}, bincode::Infinite).unwrap();
|
||||
}
|
||||
|
||||
fn push_new_empty_item(&mut self, item: SpecificDisplayItem) {
|
||||
bincode::serialize_into(&mut self.data, &DisplayItem {
|
||||
item: item,
|
||||
item,
|
||||
rect: LayoutRect::zero(),
|
||||
local_clip: LocalClip::from(LayoutRect::zero()),
|
||||
clip_and_scroll: *self.clip_stack.last().unwrap(),
|
||||
}, bincode::Infinite).unwrap();
|
||||
}
|
||||
@ -499,62 +486,59 @@ impl DisplayListBuilder {
|
||||
debug_assert_eq!(len, count);
|
||||
}
|
||||
|
||||
pub fn push_rect(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
color: ColorF) {
|
||||
pub fn push_rect(&mut self, rect: LayoutRect, local_clip: Option<LocalClip>, color: ColorF) {
|
||||
let item = SpecificDisplayItem::Rectangle(RectangleDisplayItem {
|
||||
color: color,
|
||||
color,
|
||||
});
|
||||
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
pub fn push_image(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
stretch_size: LayoutSize,
|
||||
tile_spacing: LayoutSize,
|
||||
image_rendering: ImageRendering,
|
||||
key: ImageKey) {
|
||||
let item = SpecificDisplayItem::Image(ImageDisplayItem {
|
||||
image_key: key,
|
||||
stretch_size: stretch_size,
|
||||
tile_spacing: tile_spacing,
|
||||
image_rendering: image_rendering,
|
||||
stretch_size,
|
||||
tile_spacing,
|
||||
image_rendering,
|
||||
});
|
||||
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
/// Push a yuv image. All planar data in yuv image should use the same buffer type.
|
||||
pub fn push_yuv_image(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
yuv_data: YuvData,
|
||||
color_space: YuvColorSpace,
|
||||
image_rendering: ImageRendering) {
|
||||
let item = SpecificDisplayItem::YuvImage(YuvImageDisplayItem {
|
||||
yuv_data: yuv_data,
|
||||
color_space: color_space,
|
||||
image_rendering: image_rendering,
|
||||
yuv_data,
|
||||
color_space,
|
||||
image_rendering,
|
||||
});
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
pub fn push_webgl_canvas(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
context_id: WebGLContextId) {
|
||||
let item = SpecificDisplayItem::WebGL(WebGLDisplayItem {
|
||||
context_id: context_id,
|
||||
context_id,
|
||||
});
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
pub fn push_text(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
glyphs: &[GlyphInstance],
|
||||
font_key: FontKey,
|
||||
color: ColorF,
|
||||
@ -569,14 +553,14 @@ impl DisplayListBuilder {
|
||||
// by the azure renderer.
|
||||
if size < Au::from_px(4096) {
|
||||
let item = SpecificDisplayItem::Text(TextDisplayItem {
|
||||
color: color,
|
||||
font_key: font_key,
|
||||
size: size,
|
||||
blur_radius: blur_radius,
|
||||
glyph_options: glyph_options,
|
||||
color,
|
||||
font_key,
|
||||
size,
|
||||
blur_radius,
|
||||
glyph_options,
|
||||
});
|
||||
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
self.push_iter(glyphs);
|
||||
}
|
||||
}
|
||||
@ -588,8 +572,7 @@ impl DisplayListBuilder {
|
||||
// of the gradient line to where stop[0] and the end of the gradient line
|
||||
// to stop[n-1]. this function adjusts the stops in place, and returns
|
||||
// the amount to adjust the gradient line start and stop
|
||||
fn normalize_stops(stops: &mut Vec<GradientStop>,
|
||||
extend_mode: ExtendMode) -> (f32, f32) {
|
||||
fn normalize_stops(stops: &mut Vec<GradientStop>, extend_mode: ExtendMode) -> (f32, f32) {
|
||||
assert!(stops.len() >= 2);
|
||||
|
||||
let first = *stops.first().unwrap();
|
||||
@ -675,7 +658,7 @@ impl DisplayListBuilder {
|
||||
Gradient {
|
||||
start_point: start_point + start_to_end * start_offset,
|
||||
end_point: start_point + start_to_end * end_offset,
|
||||
extend_mode: extend_mode,
|
||||
extend_mode,
|
||||
}
|
||||
}
|
||||
|
||||
@ -711,7 +694,7 @@ impl DisplayListBuilder {
|
||||
end_center: center,
|
||||
end_radius: 1.0,
|
||||
ratio_xy: 1.0,
|
||||
extend_mode: extend_mode,
|
||||
extend_mode,
|
||||
};
|
||||
}
|
||||
|
||||
@ -726,7 +709,7 @@ impl DisplayListBuilder {
|
||||
end_center: center,
|
||||
end_radius: radius.width * end_offset,
|
||||
ratio_xy: radius.width / radius.height,
|
||||
extend_mode: extend_mode,
|
||||
extend_mode,
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,31 +727,31 @@ impl DisplayListBuilder {
|
||||
self.push_stops(&stops);
|
||||
|
||||
RadialGradient {
|
||||
start_center: start_center,
|
||||
start_radius: start_radius,
|
||||
end_center: end_center,
|
||||
end_radius: end_radius,
|
||||
ratio_xy: ratio_xy,
|
||||
extend_mode: extend_mode,
|
||||
start_center,
|
||||
start_radius,
|
||||
end_center,
|
||||
end_radius,
|
||||
ratio_xy,
|
||||
extend_mode,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_border(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
widths: BorderWidths,
|
||||
details: BorderDetails) {
|
||||
let item = SpecificDisplayItem::Border(BorderDisplayItem {
|
||||
details: details,
|
||||
widths: widths,
|
||||
details,
|
||||
widths,
|
||||
});
|
||||
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
pub fn push_box_shadow(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
box_bounds: LayoutRect,
|
||||
offset: LayoutVector2D,
|
||||
color: ColorF,
|
||||
@ -777,46 +760,46 @@ impl DisplayListBuilder {
|
||||
border_radius: f32,
|
||||
clip_mode: BoxShadowClipMode) {
|
||||
let item = SpecificDisplayItem::BoxShadow(BoxShadowDisplayItem {
|
||||
box_bounds: box_bounds,
|
||||
offset: offset,
|
||||
color: color,
|
||||
blur_radius: blur_radius,
|
||||
spread_radius: spread_radius,
|
||||
border_radius: border_radius,
|
||||
clip_mode: clip_mode,
|
||||
box_bounds,
|
||||
offset,
|
||||
color,
|
||||
blur_radius,
|
||||
spread_radius,
|
||||
border_radius,
|
||||
clip_mode,
|
||||
});
|
||||
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
pub fn push_gradient(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
gradient: Gradient,
|
||||
tile_size: LayoutSize,
|
||||
tile_spacing: LayoutSize) {
|
||||
let item = SpecificDisplayItem::Gradient(GradientDisplayItem {
|
||||
gradient: gradient,
|
||||
tile_size: tile_size,
|
||||
tile_spacing: tile_spacing,
|
||||
gradient,
|
||||
tile_size,
|
||||
tile_spacing,
|
||||
});
|
||||
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
pub fn push_radial_gradient(&mut self,
|
||||
rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
local_clip: Option<LocalClip>,
|
||||
gradient: RadialGradient,
|
||||
tile_size: LayoutSize,
|
||||
tile_spacing: LayoutSize) {
|
||||
let item = SpecificDisplayItem::RadialGradient(RadialGradientDisplayItem {
|
||||
gradient: gradient,
|
||||
tile_size: tile_size,
|
||||
tile_spacing: tile_spacing,
|
||||
gradient,
|
||||
tile_size,
|
||||
tile_spacing,
|
||||
});
|
||||
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, local_clip);
|
||||
}
|
||||
|
||||
pub fn push_stacking_context(&mut self,
|
||||
@ -829,15 +812,15 @@ impl DisplayListBuilder {
|
||||
filters: Vec<FilterOp>) {
|
||||
let item = SpecificDisplayItem::PushStackingContext(PushStackingContextDisplayItem {
|
||||
stacking_context: StackingContext {
|
||||
scroll_policy: scroll_policy,
|
||||
transform: transform,
|
||||
transform_style: transform_style,
|
||||
perspective: perspective,
|
||||
mix_blend_mode: mix_blend_mode,
|
||||
scroll_policy,
|
||||
transform,
|
||||
transform_style,
|
||||
perspective,
|
||||
mix_blend_mode,
|
||||
}
|
||||
});
|
||||
|
||||
self.push_item(item, bounds);
|
||||
self.push_item(item, bounds, None);
|
||||
self.push_iter(&filters);
|
||||
}
|
||||
|
||||
@ -853,34 +836,52 @@ impl DisplayListBuilder {
|
||||
self.push_iter(stops);
|
||||
}
|
||||
|
||||
pub fn define_clip(&mut self,
|
||||
content_rect: LayoutRect,
|
||||
_token: ClipRegionToken,
|
||||
id: Option<ClipId>)
|
||||
-> ClipId {
|
||||
let id = match id {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
self.next_clip_id += 1;
|
||||
ClipId::Clip(self.next_clip_id - 1, 0, self.pipeline_id)
|
||||
}
|
||||
};
|
||||
fn generate_clip_id(&mut self, id: Option<ClipId>) -> ClipId {
|
||||
id.unwrap_or_else(|| {
|
||||
self.next_clip_id += 1;
|
||||
ClipId::Clip(self.next_clip_id - 1, 0, self.pipeline_id)
|
||||
})
|
||||
}
|
||||
|
||||
let item = SpecificDisplayItem::Clip(ClipDisplayItem {
|
||||
pub fn define_scroll_frame<I>(&mut self,
|
||||
id: Option<ClipId>,
|
||||
content_rect: LayoutRect,
|
||||
clip_rect: LayoutRect,
|
||||
complex_clips: I,
|
||||
image_mask: Option<ImageMask>)
|
||||
-> ClipId
|
||||
where I: IntoIterator<Item = ComplexClipRegion>,
|
||||
I::IntoIter: ExactSizeIterator {
|
||||
let id = self.generate_clip_id(id);
|
||||
let item = SpecificDisplayItem::ScrollFrame(ClipDisplayItem {
|
||||
id: id,
|
||||
parent_id: self.clip_stack.last().unwrap().scroll_node_id,
|
||||
image_mask: image_mask,
|
||||
});
|
||||
|
||||
self.push_item(item, content_rect);
|
||||
self.push_item(item, content_rect, Some(LocalClip::from(clip_rect)));
|
||||
self.push_iter(complex_clips);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn push_clip_node(&mut self,
|
||||
content_rect: LayoutRect,
|
||||
token: ClipRegionToken,
|
||||
id: Option<ClipId>){
|
||||
let id = self.define_clip(content_rect, token, id);
|
||||
self.clip_stack.push(ClipAndScrollInfo::simple(id));
|
||||
pub fn define_clip<I>(&mut self,
|
||||
id: Option<ClipId>,
|
||||
clip_rect: LayoutRect,
|
||||
complex_clips: I,
|
||||
image_mask: Option<ImageMask>)
|
||||
-> ClipId
|
||||
where I: IntoIterator<Item = ComplexClipRegion>,
|
||||
I::IntoIter: ExactSizeIterator {
|
||||
let id = self.generate_clip_id(id);
|
||||
let item = SpecificDisplayItem::Clip(ClipDisplayItem {
|
||||
id,
|
||||
parent_id: self.clip_stack.last().unwrap().scroll_node_id,
|
||||
image_mask: image_mask,
|
||||
});
|
||||
|
||||
self.push_item(item, clip_rect, Some(LocalClip::from(clip_rect)));
|
||||
self.push_iter(complex_clips);
|
||||
id
|
||||
}
|
||||
|
||||
pub fn push_clip_id(&mut self, id: ClipId) {
|
||||
@ -896,13 +897,9 @@ impl DisplayListBuilder {
|
||||
assert!(self.clip_stack.len() > 0);
|
||||
}
|
||||
|
||||
pub fn pop_clip_node(&mut self) {
|
||||
self.pop_clip_id();
|
||||
}
|
||||
|
||||
pub fn push_iframe(&mut self, rect: LayoutRect, _token: ClipRegionToken, pipeline_id: PipelineId) {
|
||||
pub fn push_iframe(&mut self, rect: LayoutRect, pipeline_id: PipelineId) {
|
||||
let item = SpecificDisplayItem::Iframe(IframeDisplayItem { pipeline_id: pipeline_id });
|
||||
self.push_item(item, rect);
|
||||
self.push_item(item, rect, None);
|
||||
}
|
||||
|
||||
// Don't use this function. It will go away.
|
||||
@ -912,31 +909,11 @@ impl DisplayListBuilder {
|
||||
// will replace references to the root scroll frame id with the current scroll frame
|
||||
// id.
|
||||
pub fn push_nested_display_list(&mut self, built_display_list: &BuiltDisplayList) {
|
||||
self.push_clip_region(&LayoutRect::zero(), vec![], None);
|
||||
self.push_new_empty_item(SpecificDisplayItem::PushNestedDisplayList);
|
||||
|
||||
self.data.extend_from_slice(&built_display_list.data);
|
||||
|
||||
self.push_clip_region(&LayoutRect::zero(), vec![], None);
|
||||
self.push_new_empty_item(SpecificDisplayItem::PopNestedDisplayList);
|
||||
}
|
||||
|
||||
pub fn push_clip_region<I>(&mut self,
|
||||
rect: &LayoutRect,
|
||||
complex: I,
|
||||
image_mask: Option<ImageMask>)
|
||||
-> ClipRegionToken
|
||||
where I: IntoIterator<Item = ComplexClipRegion>,
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
{
|
||||
self.push_new_empty_item(SpecificDisplayItem::SetClipRegion(
|
||||
ClipRegion::new(rect, image_mask),
|
||||
));
|
||||
self.push_iter(complex);
|
||||
|
||||
ClipRegionToken { _unforgeable: () }
|
||||
}
|
||||
|
||||
pub fn finalize(self) -> (PipelineId, LayoutSize, BuiltDisplayList) {
|
||||
let end_time = precise_time_ns();
|
||||
|
||||
@ -951,7 +928,3 @@ impl DisplayListBuilder {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Verification that push_clip_region was called before
|
||||
/// pushing an item that requires it.
|
||||
pub struct ClipRegionToken { _unforgeable: () }
|
@ -178,10 +178,10 @@ impl GlyphKey {
|
||||
point: LayoutPoint,
|
||||
render_mode: FontRenderMode) -> GlyphKey {
|
||||
GlyphKey {
|
||||
font_key: font_key,
|
||||
size: size,
|
||||
font_key,
|
||||
size,
|
||||
color: ColorU::from(color),
|
||||
index: index,
|
||||
index,
|
||||
subpixel_point: SubpixelPoint::new(point, render_mode),
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ pub enum ExternalImageType {
|
||||
ExternalBuffer,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ExternalImageData {
|
||||
pub id: ExternalImageId,
|
||||
@ -77,12 +78,12 @@ pub struct ImageDescriptor {
|
||||
impl ImageDescriptor {
|
||||
pub fn new(width: u32, height: u32, format: ImageFormat, is_opaque: bool) -> Self {
|
||||
ImageDescriptor {
|
||||
width: width,
|
||||
height: height,
|
||||
format: format,
|
||||
width,
|
||||
height,
|
||||
format,
|
||||
stride: None,
|
||||
offset: 0,
|
||||
is_opaque: is_opaque,
|
||||
is_opaque,
|
||||
}
|
||||
}
|
||||
|
@ -107,4 +107,3 @@ pub fn as_scroll_parent_rect(rect: &LayerRect) -> ScrollLayerRect {
|
||||
pub fn as_scroll_parent_vector(vector: &LayerVector2D) -> ScrollLayerVector2D {
|
||||
ScrollLayerVector2D::from_untyped(&vector.to_untyped())
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ pub enum WebGLCommand {
|
||||
CreateVertexArray(MsgSender<Option<WebGLVertexArrayId>>),
|
||||
DeleteVertexArray(WebGLVertexArrayId),
|
||||
BindVertexArray(Option<WebGLVertexArrayId>),
|
||||
FenceAndWaitSync,
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
@ -388,7 +389,8 @@ impl fmt::Debug for WebGLCommand {
|
||||
GenerateMipmap(..) => "GenerateMipmap",
|
||||
CreateVertexArray(..) => "CreateVertexArray",
|
||||
DeleteVertexArray(..) => "DeleteVertexArray",
|
||||
BindVertexArray(..) => "BindVertexArray"
|
||||
BindVertexArray(..) => "BindVertexArray",
|
||||
FenceAndWaitSync => "FenceAndWaitSync",
|
||||
};
|
||||
|
||||
write!(f, "CanvasWebGLMsg::{}(..)", name)
|
||||
@ -631,6 +633,8 @@ impl WebGLCommand {
|
||||
ctx.gl().delete_vertex_arrays(&[id.get()]),
|
||||
WebGLCommand::BindVertexArray(id) =>
|
||||
ctx.gl().bind_vertex_array(id.map_or(0, WebGLVertexArrayId::get)),
|
||||
WebGLCommand::FenceAndWaitSync =>
|
||||
Self::fence_and_wait_sync(ctx.gl()),
|
||||
}
|
||||
|
||||
// FIXME: Use debug_assertions once tests are run with them
|
||||
@ -901,7 +905,7 @@ impl WebGLCommand {
|
||||
shader_type: u32,
|
||||
precision_type: u32,
|
||||
chan: MsgSender<WebGLResult<(i32, i32, i32)>>) {
|
||||
|
||||
|
||||
let result = match precision_type {
|
||||
gl::LOW_FLOAT |
|
||||
gl::MEDIUM_FLOAT |
|
||||
@ -1040,4 +1044,13 @@ impl WebGLCommand {
|
||||
gl.shader_source(shader_id.get(), &[source.as_bytes()]);
|
||||
gl.compile_shader(shader_id.get());
|
||||
}
|
||||
|
||||
fn fence_and_wait_sync(gl: &gl::Gl) {
|
||||
// Call FenceSync and ClientWaitSync to ensure that textures are ready.
|
||||
let sync = gl.fence_sync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
// SYNC_FLUSH_COMMANDS_BIT is used to automatically generate a glFlush before blocking on the sync object.
|
||||
gl.wait_sync(sync, gl::SYNC_FLUSH_COMMANDS_BIT, gl::TIMEOUT_IGNORED);
|
||||
// Release GLsync object
|
||||
gl.delete_sync(sync);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user