mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
auto merge of #553 : pcwalton/servo/cpu-rendering, r=pcwalton
r? @metajack
This commit is contained in:
commit
4eb1e88e8f
25 changed files with 675 additions and 277 deletions
|
@ -2,10 +2,12 @@
|
|||
* 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 geom::size::Size2D;
|
||||
use layers::platform::surface::NativePaintingGraphicsContext;
|
||||
use servo_msg::compositor_msg::Tile;
|
||||
use std::hashmap::HashMap;
|
||||
use std::to_bytes::Cb;
|
||||
use geom::size::Size2D;
|
||||
use servo_msg::compositor_msg::Tile;
|
||||
use std::util;
|
||||
|
||||
/// This is a struct used to store buffers when they are not in use.
|
||||
/// The render task can quickly query for a particular size of buffer when it
|
||||
|
@ -15,7 +17,7 @@ pub struct BufferMap<T> {
|
|||
map: HashMap<BufferKey, BufferValue<T>>,
|
||||
/// The current amount of memory stored by the BufferMap's buffers.
|
||||
mem: uint,
|
||||
/// The maximum allowed memory. Unused buffers willl be deleted
|
||||
/// The maximum allowed memory. Unused buffers will be deleted
|
||||
/// when this threshold is exceeded.
|
||||
max_mem: uint,
|
||||
/// A monotonically increasing counter to track how recently tile sizes were used.
|
||||
|
@ -64,8 +66,8 @@ impl<T: Tile> BufferMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Insert a new buffer into the map.
|
||||
pub fn insert(&mut self, new_buffer: T) {
|
||||
/// Insert a new buffer into the map.
|
||||
pub fn insert(&mut self, graphics_context: &NativePaintingGraphicsContext, new_buffer: T) {
|
||||
let new_key = BufferKey::get(new_buffer.get_size_2d());
|
||||
|
||||
// If all our buffers are the same size and we're already at our
|
||||
|
@ -95,7 +97,9 @@ impl<T: Tile> BufferMap<T> {
|
|||
};
|
||||
if {
|
||||
let list = &mut self.map.get_mut(&old_key).buffers;
|
||||
self.mem -= list.pop().get_mem();
|
||||
let condemned_buffer = list.pop();
|
||||
self.mem -= condemned_buffer.get_mem();
|
||||
condemned_buffer.destroy(graphics_context);
|
||||
list.is_empty()
|
||||
}
|
||||
{ // then
|
||||
|
@ -132,4 +136,15 @@ impl<T: Tile> BufferMap<T> {
|
|||
|
||||
ret
|
||||
}
|
||||
|
||||
/// Destroys all buffers.
|
||||
pub fn clear(&mut self, graphics_context: &NativePaintingGraphicsContext) {
|
||||
let map = util::replace(&mut self.map, HashMap::new());
|
||||
for (_, value) in map.move_iter() {
|
||||
for tile in value.buffers.move_iter() {
|
||||
tile.destroy(graphics_context)
|
||||
}
|
||||
}
|
||||
self.mem = 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
#[feature(globs)];
|
||||
|
||||
extern mod azure;
|
||||
extern mod geom;
|
||||
extern mod stb_image;
|
||||
extern mod extra;
|
||||
extern mod geom;
|
||||
extern mod layers;
|
||||
extern mod stb_image;
|
||||
extern mod servo_net (name = "net");
|
||||
extern mod servo_util (name = "util");
|
||||
extern mod style;
|
||||
|
|
|
@ -7,27 +7,45 @@
|
|||
|
||||
use azure::azure_hl::{BackendType, CairoBackend, CoreGraphicsBackend};
|
||||
use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBackend};
|
||||
use extra::getopts;
|
||||
|
||||
use std::result;
|
||||
|
||||
/// Global flags for Servo, currently set on the command line.
|
||||
#[deriving(Clone)]
|
||||
pub struct Opts {
|
||||
/// The initial URLs to load.
|
||||
urls: ~[~str],
|
||||
|
||||
/// The rendering backend to use (`-r`).
|
||||
render_backend: BackendType,
|
||||
|
||||
/// How many threads to use for CPU rendering (`-t`).
|
||||
///
|
||||
/// FIXME(pcwalton): This is not currently used. All rendering is sequential.
|
||||
n_render_threads: uint,
|
||||
|
||||
/// True to use CPU painting, false to use GPU painting via Skia-GL (`-c`). Note that
|
||||
/// compositing is always done on the GPU.
|
||||
cpu_painting: bool,
|
||||
|
||||
/// The maximum size of each tile in pixels (`-s`).
|
||||
tile_size: uint,
|
||||
|
||||
/// `None` to disable the profiler or `Some` with an interval in seconds to enable it and cause
|
||||
/// it to produce output on that interval (`-p`).
|
||||
profiler_period: Option<f64>,
|
||||
|
||||
/// True to exit after the page load (`-x`).
|
||||
exit_after_load: bool,
|
||||
|
||||
output_file: Option<~str>,
|
||||
headless: bool,
|
||||
}
|
||||
|
||||
pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
||||
use extra::getopts;
|
||||
|
||||
let args = args.tail();
|
||||
|
||||
let opts = ~[
|
||||
getopts::optflag("c"), // CPU rendering
|
||||
getopts::optopt("o"), // output file
|
||||
getopts::optopt("r"), // rendering backend
|
||||
getopts::optopt("s"), // size of tiles
|
||||
|
@ -38,8 +56,8 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
|||
];
|
||||
|
||||
let opt_match = match getopts::getopts(args, opts) {
|
||||
result::Ok(m) => m,
|
||||
result::Err(f) => fail!(f.to_err_msg()),
|
||||
Ok(m) => m,
|
||||
Err(f) => fail!(f.to_err_msg()),
|
||||
};
|
||||
|
||||
let urls = if opt_match.free.is_empty() {
|
||||
|
@ -82,10 +100,13 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
|
|||
from_str(period).unwrap()
|
||||
};
|
||||
|
||||
let cpu_painting = opt_match.opt_present("c");
|
||||
|
||||
Opts {
|
||||
urls: urls,
|
||||
render_backend: render_backend,
|
||||
n_render_threads: n_render_threads,
|
||||
cpu_painting: cpu_painting,
|
||||
tile_size: tile_size,
|
||||
profiler_period: profiler_period,
|
||||
exit_after_load: opt_match.opt_present("x"),
|
||||
|
|
|
@ -101,10 +101,8 @@ impl FontHandleMethods for FontHandle {
|
|||
};
|
||||
|
||||
#[fixed_stack_segment]
|
||||
fn create_face_from_buffer(lib: FT_Library,
|
||||
cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||
fn create_face_from_buffer(lib: FT_Library, cbuf: *u8, cbuflen: uint, pt_size: f64)
|
||||
-> Result<FT_Face, ()> {
|
||||
|
||||
unsafe {
|
||||
let mut face: FT_Face = ptr::null();
|
||||
let face_index = 0 as FT_Long;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
* 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 servo_msg::compositor_msg::LayerBuffer;
|
||||
use servo_util::geometry::Au;
|
||||
use font_context::FontContext;
|
||||
use style::computed_values::border_style;
|
||||
use opts::Opts;
|
||||
|
@ -13,30 +11,35 @@ use azure::azure_hl::{DrawSurfaceOptions, DrawTarget, Linear, StrokeOptions};
|
|||
use azure::{AZ_CAP_BUTT, AZ_CAP_ROUND};
|
||||
use azure::AZ_JOIN_BEVEL;
|
||||
use azure::AzFloat;
|
||||
use std::vec;
|
||||
use std::libc::types::common::c99::uint16_t;
|
||||
use std::libc::size_t;
|
||||
use extra::arc::Arc;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use geom::side_offsets::SideOffsets2D;
|
||||
use servo_net::image::base::Image;
|
||||
use extra::arc::Arc;
|
||||
use servo_util::geometry::Au;
|
||||
use std::vec;
|
||||
use std::libc::types::common::c99::uint16_t;
|
||||
use std::libc::size_t;
|
||||
|
||||
pub struct RenderContext<'self> {
|
||||
canvas: &'self ~LayerBuffer,
|
||||
draw_target: &'self DrawTarget,
|
||||
font_ctx: @mut FontContext,
|
||||
opts: &'self Opts
|
||||
opts: &'self Opts,
|
||||
/// The rectangle that this context encompasses in page coordinates.
|
||||
page_rect: Rect<f32>,
|
||||
/// The rectangle that this context encompasses in screen coordinates (pixels).
|
||||
screen_rect: Rect<uint>,
|
||||
}
|
||||
|
||||
impl<'self> RenderContext<'self> {
|
||||
pub fn get_draw_target(&self) -> &'self DrawTarget {
|
||||
&self.canvas.draw_target
|
||||
self.draw_target
|
||||
}
|
||||
|
||||
pub fn draw_solid_color(&self, bounds: &Rect<Au>, color: Color) {
|
||||
self.canvas.draw_target.make_current();
|
||||
self.canvas.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
|
||||
self.draw_target.make_current();
|
||||
self.draw_target.fill_rect(&bounds.to_azure_rect(), &ColorPattern(color));
|
||||
}
|
||||
|
||||
pub fn draw_border(&self,
|
||||
|
@ -48,7 +51,7 @@ impl<'self> RenderContext<'self> {
|
|||
let rect = bounds.to_azure_rect();
|
||||
let border = border.to_float_px();
|
||||
|
||||
self.canvas.draw_target.make_current();
|
||||
self.draw_target.make_current();
|
||||
let mut dash: [AzFloat, ..2] = [0 as AzFloat, 0 as AzFloat];
|
||||
let mut stroke_opts = StrokeOptions(0 as AzFloat, 10 as AzFloat);
|
||||
|
||||
|
@ -57,28 +60,44 @@ impl<'self> RenderContext<'self> {
|
|||
let y = rect.origin.y + border.top * 0.5;
|
||||
let start = Point2D(rect.origin.x, y);
|
||||
let end = Point2D(rect.origin.x + rect.size.width, y);
|
||||
self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.top), &stroke_opts, &draw_opts);
|
||||
self.draw_target.stroke_line(start,
|
||||
end,
|
||||
&ColorPattern(color.top),
|
||||
&stroke_opts,
|
||||
&draw_opts);
|
||||
|
||||
// draw right border
|
||||
RenderContext::apply_border_style(style.right, border.right, dash, &mut stroke_opts);
|
||||
let x = rect.origin.x + rect.size.width - border.right * 0.5;
|
||||
let start = Point2D(x, rect.origin.y);
|
||||
let end = Point2D(x, rect.origin.y + rect.size.height);
|
||||
self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.right), &stroke_opts, &draw_opts);
|
||||
self.draw_target.stroke_line(start,
|
||||
end,
|
||||
&ColorPattern(color.right),
|
||||
&stroke_opts,
|
||||
&draw_opts);
|
||||
|
||||
// draw bottom border
|
||||
RenderContext::apply_border_style(style.bottom, border.bottom, dash, &mut stroke_opts);
|
||||
let y = rect.origin.y + rect.size.height - border.bottom * 0.5;
|
||||
let start = Point2D(rect.origin.x, y);
|
||||
let end = Point2D(rect.origin.x + rect.size.width, y);
|
||||
self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.bottom), &stroke_opts, &draw_opts);
|
||||
self.draw_target.stroke_line(start,
|
||||
end,
|
||||
&ColorPattern(color.bottom),
|
||||
&stroke_opts,
|
||||
&draw_opts);
|
||||
|
||||
// draw left border
|
||||
RenderContext::apply_border_style(style.left, border.left, dash, &mut stroke_opts);
|
||||
let x = rect.origin.x + border.left * 0.5;
|
||||
let start = Point2D(x, rect.origin.y);
|
||||
let end = Point2D(x, rect.origin.y + rect.size.height);
|
||||
self.canvas.draw_target.stroke_line(start, end, &ColorPattern(color.left), &stroke_opts, &draw_opts);
|
||||
self.draw_target.stroke_line(start,
|
||||
end,
|
||||
&ColorPattern(color.left),
|
||||
&stroke_opts,
|
||||
&draw_opts);
|
||||
}
|
||||
|
||||
pub fn draw_image(&self, bounds: Rect<Au>, image: Arc<~Image>) {
|
||||
|
@ -86,8 +105,8 @@ impl<'self> RenderContext<'self> {
|
|||
let size = Size2D(image.width as i32, image.height as i32);
|
||||
let stride = image.width * 4;
|
||||
|
||||
self.canvas.draw_target.make_current();
|
||||
let draw_target_ref = &self.canvas.draw_target;
|
||||
self.draw_target.make_current();
|
||||
let draw_target_ref = &self.draw_target;
|
||||
let azure_surface = draw_target_ref.create_source_surface_from_data(image.data, size,
|
||||
stride as i32, B8G8R8A8);
|
||||
let source_rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat),
|
||||
|
@ -104,12 +123,12 @@ impl<'self> RenderContext<'self> {
|
|||
|
||||
pub fn clear(&self) {
|
||||
let pattern = ColorPattern(Color(1.0, 1.0, 1.0, 1.0));
|
||||
let rect = Rect(Point2D(self.canvas.rect.origin.x as AzFloat,
|
||||
self.canvas.rect.origin.y as AzFloat),
|
||||
Size2D(self.canvas.screen_pos.size.width as AzFloat,
|
||||
self.canvas.screen_pos.size.height as AzFloat));
|
||||
self.canvas.draw_target.make_current();
|
||||
self.canvas.draw_target.fill_rect(&rect, &pattern);
|
||||
let rect = Rect(Point2D(self.page_rect.origin.x as AzFloat,
|
||||
self.page_rect.origin.y as AzFloat),
|
||||
Size2D(self.screen_rect.size.width as AzFloat,
|
||||
self.screen_rect.size.height as AzFloat));
|
||||
self.draw_target.make_current();
|
||||
self.draw_target.fill_rect(&rect, &pattern);
|
||||
}
|
||||
|
||||
fn apply_border_style(style: border_style::T, border_width: AzFloat, dash: &mut [AzFloat], stroke_opts: &mut StrokeOptions){
|
||||
|
|
|
@ -4,28 +4,31 @@
|
|||
|
||||
// The task that handles all rendering/painting.
|
||||
|
||||
use azure::{AzFloat, AzGLContext};
|
||||
use azure::azure_hl::{B8G8R8A8, DrawTarget};
|
||||
use display_list::DisplayList;
|
||||
use servo_msg::compositor_msg::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer};
|
||||
use servo_msg::compositor_msg::{LayerBufferSet, Epoch};
|
||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg};
|
||||
use font_context::FontContext;
|
||||
use azure::azure_hl::{B8G8R8A8, DrawTarget, StolenGLResources};
|
||||
use azure::AzFloat;
|
||||
use geom::matrix2d::Matrix2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::rect::Rect;
|
||||
use opts::Opts;
|
||||
use render_context::RenderContext;
|
||||
|
||||
use std::comm::{Chan, Port, SharedChan};
|
||||
use std::task::spawn_with;
|
||||
use extra::arc::Arc;
|
||||
|
||||
use geom::size::Size2D;
|
||||
use layers::platform::surface::{NativePaintingGraphicsContext, NativeSurface};
|
||||
use layers::platform::surface::{NativeSurfaceMethods};
|
||||
use layers;
|
||||
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBuffer, LayerBufferSet};
|
||||
use servo_msg::compositor_msg::{RenderListener, RenderingRenderState};
|
||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg};
|
||||
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
|
||||
use servo_util::time::{ProfilerChan, profile};
|
||||
use servo_util::time;
|
||||
|
||||
use buffer_map::BufferMap;
|
||||
use std::comm::{Chan, Port, SharedChan};
|
||||
use std::task::spawn_with;
|
||||
use std::util;
|
||||
use extra::arc::Arc;
|
||||
|
||||
use buffer_map::BufferMap;
|
||||
use display_list::DisplayList;
|
||||
use font_context::FontContext;
|
||||
use opts::Opts;
|
||||
use render_context::RenderContext;
|
||||
|
||||
pub struct RenderLayer<T> {
|
||||
display_list: Arc<DisplayList<T>>,
|
||||
|
@ -82,6 +85,13 @@ impl<T: Send> GenericSmartChan<Msg<T>> for RenderChan<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// If we're using GPU rendering, this provides the metadata needed to create a GL context that
|
||||
/// is compatible with that of the main thread.
|
||||
enum GraphicsContext {
|
||||
CpuGraphicsContext,
|
||||
GpuGraphicsContext,
|
||||
}
|
||||
|
||||
pub struct RenderTask<C,T> {
|
||||
id: PipelineId,
|
||||
port: Port<Msg<T>>,
|
||||
|
@ -93,16 +103,21 @@ pub struct RenderTask<C,T> {
|
|||
/// A channel to the profiler.
|
||||
profiler_chan: ProfilerChan,
|
||||
|
||||
share_gl_context: AzGLContext,
|
||||
/// The graphics context to use.
|
||||
graphics_context: GraphicsContext,
|
||||
|
||||
/// The native graphics context.
|
||||
native_graphics_context: NativePaintingGraphicsContext,
|
||||
|
||||
/// The layer to be rendered
|
||||
render_layer: Option<RenderLayer<T>>,
|
||||
|
||||
/// Permission to send paint messages to the compositor
|
||||
paint_permission: bool,
|
||||
/// Cached copy of last layers rendered
|
||||
last_paint_msg: Option<~LayerBufferSet>,
|
||||
|
||||
/// A counter for epoch messages
|
||||
epoch: Epoch,
|
||||
|
||||
/// A data structure to store unused LayerBuffers
|
||||
buffer_map: BufferMap<~LayerBuffer>,
|
||||
}
|
||||
|
@ -114,11 +129,13 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
constellation_chan: ConstellationChan,
|
||||
opts: Opts,
|
||||
profiler_chan: ProfilerChan) {
|
||||
|
||||
do spawn_with((port, compositor, constellation_chan, opts, profiler_chan))
|
||||
|(port, compositor, constellation_chan, opts, profiler_chan)| {
|
||||
|
||||
let share_gl_context = compositor.get_gl_context();
|
||||
let graphics_metadata = compositor.get_graphics_metadata();
|
||||
let cpu_painting = opts.cpu_painting;
|
||||
let native_graphics_context =
|
||||
NativePaintingGraphicsContext::from_metadata(&graphics_metadata);
|
||||
|
||||
// FIXME: rust/#5967
|
||||
let mut render_task = RenderTask {
|
||||
|
@ -131,16 +148,26 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
profiler_chan.clone()),
|
||||
opts: opts,
|
||||
profiler_chan: profiler_chan,
|
||||
share_gl_context: share_gl_context,
|
||||
|
||||
graphics_context: if cpu_painting {
|
||||
CpuGraphicsContext
|
||||
} else {
|
||||
GpuGraphicsContext
|
||||
},
|
||||
|
||||
native_graphics_context: native_graphics_context,
|
||||
|
||||
render_layer: None,
|
||||
|
||||
paint_permission: false,
|
||||
last_paint_msg: None,
|
||||
epoch: Epoch(0),
|
||||
buffer_map: BufferMap::new(10000000),
|
||||
};
|
||||
|
||||
render_task.start();
|
||||
|
||||
// Destroy all the buffers.
|
||||
render_task.buffer_map.clear(&render_task.native_graphics_context)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +184,6 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
self.constellation_chan.send(RendererReadyMsg(self.id));
|
||||
}
|
||||
self.render_layer = Some(render_layer);
|
||||
self.last_paint_msg = None;
|
||||
}
|
||||
ReRenderMsg(tiles, scale, epoch) => {
|
||||
if self.epoch == epoch {
|
||||
|
@ -169,7 +195,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
UnusedBufferMsg(unused_buffers) => {
|
||||
// move_rev_iter is more efficient
|
||||
for buffer in unused_buffers.move_rev_iter() {
|
||||
self.buffer_map.insert(buffer);
|
||||
self.buffer_map.insert(&self.native_graphics_context, buffer);
|
||||
}
|
||||
}
|
||||
PaintPermissionGranted => {
|
||||
|
@ -181,16 +207,6 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
}
|
||||
None => {}
|
||||
}
|
||||
// FIXME: This sends the last paint request, anticipating what
|
||||
// the compositor will ask for. However, even if it sends the right
|
||||
// tiles, the compositor still asks for them, and they will be
|
||||
// re-rendered redundantly.
|
||||
match self.last_paint_msg {
|
||||
Some(ref layer_buffer_set) => {
|
||||
self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch);
|
||||
}
|
||||
None => {} // Nothing to do
|
||||
}
|
||||
}
|
||||
PaintPermissionRevoked => {
|
||||
self.paint_permission = false;
|
||||
|
@ -221,7 +237,6 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
|
||||
self.compositor.set_render_state(RenderingRenderState);
|
||||
do time::profile(time::RenderingCategory, self.profiler_chan.clone()) {
|
||||
|
||||
// FIXME: Try not to create a new array here.
|
||||
let mut new_buffers = ~[];
|
||||
|
||||
|
@ -231,42 +246,41 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
let width = tile.screen_rect.size.width;
|
||||
let height = tile.screen_rect.size.height;
|
||||
|
||||
let buffer = match self.buffer_map.find(tile.screen_rect.size) {
|
||||
Some(buffer) => {
|
||||
let mut buffer = buffer;
|
||||
buffer.rect = tile.page_rect;
|
||||
buffer.screen_pos = tile.screen_rect;
|
||||
buffer.resolution = scale;
|
||||
buffer
|
||||
let size = Size2D(width as i32, height as i32);
|
||||
let draw_target = match self.graphics_context {
|
||||
CpuGraphicsContext => {
|
||||
DrawTarget::new(self.opts.render_backend, size, B8G8R8A8)
|
||||
}
|
||||
None => ~LayerBuffer {
|
||||
draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
|
||||
self.share_gl_context,
|
||||
Size2D(width as i32, height as i32),
|
||||
B8G8R8A8),
|
||||
rect: tile.page_rect,
|
||||
screen_pos: tile.screen_rect,
|
||||
resolution: scale,
|
||||
stride: (width * 4) as uint
|
||||
GpuGraphicsContext => {
|
||||
// FIXME(pcwalton): Cache the components of draw targets
|
||||
// (texture color buffer, renderbuffers) instead of recreating them.
|
||||
let draw_target =
|
||||
DrawTarget::new_with_fbo(self.opts.render_backend,
|
||||
&self.native_graphics_context,
|
||||
size,
|
||||
B8G8R8A8);
|
||||
draw_target.make_current();
|
||||
draw_target
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
{
|
||||
// Build the render context.
|
||||
let ctx = RenderContext {
|
||||
canvas: &buffer,
|
||||
draw_target: &draw_target,
|
||||
font_ctx: self.font_ctx,
|
||||
opts: &self.opts
|
||||
opts: &self.opts,
|
||||
page_rect: tile.page_rect,
|
||||
screen_rect: tile.screen_rect,
|
||||
};
|
||||
|
||||
// Apply the translation to render the tile we want.
|
||||
let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
|
||||
let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
|
||||
let matrix = matrix.translate(-(buffer.rect.origin.x) as AzFloat,
|
||||
-(buffer.rect.origin.y) as AzFloat);
|
||||
let matrix = matrix.translate(-(tile.page_rect.origin.x) as AzFloat,
|
||||
-(tile.page_rect.origin.y) as AzFloat);
|
||||
|
||||
ctx.canvas.draw_target.set_transform(&matrix);
|
||||
ctx.draw_target.set_transform(&matrix);
|
||||
|
||||
// Clear the buffer.
|
||||
ctx.clear();
|
||||
|
@ -274,14 +288,78 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
// Draw the display list.
|
||||
do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) {
|
||||
render_layer.display_list.get().draw_into_context(&ctx);
|
||||
ctx.canvas.draw_target.flush();
|
||||
ctx.draw_target.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the texture from the draw target and place it into its slot in the
|
||||
// buffer. If using CPU rendering, upload it first.
|
||||
//
|
||||
// FIXME(pcwalton): We should supply the texture and native surface *to* the
|
||||
// draw target in GPU rendering mode, so that it doesn't have to recreate it.
|
||||
let buffer = match self.graphics_context {
|
||||
CpuGraphicsContext => {
|
||||
let buffer = match self.buffer_map.find(tile.screen_rect.size) {
|
||||
Some(buffer) => {
|
||||
let mut buffer = buffer;
|
||||
buffer.rect = tile.page_rect;
|
||||
buffer.screen_pos = tile.screen_rect;
|
||||
buffer.resolution = scale;
|
||||
buffer.native_surface.mark_wont_leak();
|
||||
buffer
|
||||
}
|
||||
None => {
|
||||
// Create an empty native surface. We mark it as not leaking
|
||||
// in case it dies in transit to the compositor task.
|
||||
let mut native_surface: NativeSurface =
|
||||
layers::platform::surface::NativeSurfaceMethods::new(
|
||||
&self.native_graphics_context,
|
||||
Size2D(width as i32, height as i32),
|
||||
width as i32 * 4);
|
||||
native_surface.mark_wont_leak();
|
||||
|
||||
~LayerBuffer {
|
||||
native_surface: native_surface,
|
||||
rect: tile.page_rect,
|
||||
screen_pos: tile.screen_rect,
|
||||
resolution: scale,
|
||||
stride: (width * 4) as uint
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
do draw_target.snapshot().get_data_surface().with_data |data| {
|
||||
buffer.native_surface.upload(&self.native_graphics_context, data);
|
||||
debug!("RENDERER uploading to native surface %d",
|
||||
buffer.native_surface.get_id() as int);
|
||||
}
|
||||
|
||||
buffer
|
||||
}
|
||||
GpuGraphicsContext => {
|
||||
draw_target.make_current();
|
||||
let StolenGLResources {
|
||||
surface: native_surface
|
||||
} = draw_target.steal_gl_resources().unwrap();
|
||||
|
||||
// We mark the native surface as not leaking in case the surfaces
|
||||
// die on their way to the compositor task.
|
||||
let mut native_surface: NativeSurface =
|
||||
NativeSurfaceAzureMethods::from_azure_surface(native_surface);
|
||||
native_surface.mark_wont_leak();
|
||||
|
||||
~LayerBuffer {
|
||||
native_surface: native_surface,
|
||||
rect: tile.page_rect,
|
||||
screen_pos: tile.screen_rect,
|
||||
resolution: scale,
|
||||
stride: (width * 4) as uint
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
new_buffers.push(buffer);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let layer_buffer_set = ~LayerBufferSet {
|
||||
|
@ -290,12 +368,10 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
|
|||
|
||||
debug!("render_task: returning surface");
|
||||
if self.paint_permission {
|
||||
self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch);
|
||||
self.compositor.paint(self.id, layer_buffer_set, self.epoch);
|
||||
} else {
|
||||
self.constellation_chan.send(RendererReadyMsg(self.id));
|
||||
}
|
||||
debug!("caching paint msg");
|
||||
self.last_paint_msg = Some(layer_buffer_set);
|
||||
self.compositor.set_render_state(IdleRenderState);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,21 +2,27 @@
|
|||
* 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 std::cell::Cell;
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::rect::Rect;
|
||||
use compositing::quadtree::{Quadtree, Normal, Invalid, Hidden};
|
||||
use constellation::{SendableChildFrameTree, SendableFrameTree};
|
||||
use geom::matrix::identity;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use gfx::render_task::{ReRenderMsg, UnusedBufferMsg};
|
||||
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch};
|
||||
use servo_msg::constellation_msg::PipelineId;
|
||||
use layers::layers::{ContainerLayerKind, ContainerLayer, Flip, NoFlip, TextureLayer};
|
||||
use layers::layers::{TextureLayerKind, VerticalFlip};
|
||||
use layers::platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceMethods};
|
||||
use layers::texturegl::{Texture, TextureTarget, TextureTargetRectangle};
|
||||
use pipeline::Pipeline;
|
||||
use script::dom::event::{ClickEvent, MouseDownEvent, MouseUpEvent};
|
||||
use script::script_task::SendEventMsg;
|
||||
use servo_msg::compositor_msg::{LayerBuffer, LayerBufferSet, Epoch, Tile};
|
||||
use servo_msg::constellation_msg::PipelineId;
|
||||
use std::cell::Cell;
|
||||
use windowing::{MouseWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
|
||||
use compositing::quadtree::{Quadtree, Normal, Invalid, Hidden};
|
||||
use layers::layers::{ContainerLayerKind, ContainerLayer, TextureLayerKind, TextureLayer, TextureManager};
|
||||
use pipeline::Pipeline;
|
||||
use constellation::{SendableChildFrameTree, SendableFrameTree};
|
||||
|
||||
#[cfg(not(target_os="macos"))]
|
||||
use layers::texturegl::TextureTarget2D;
|
||||
|
||||
/// The CompositorLayer represents an element on a page that has a unique scroll
|
||||
/// or animation behavior. This can include absolute positioned elements, iframes, etc.
|
||||
|
@ -24,31 +30,42 @@ use constellation::{SendableChildFrameTree, SendableFrameTree};
|
|||
pub struct CompositorLayer {
|
||||
/// This layer's pipeline. BufferRequests and mouse events will be sent through this.
|
||||
pipeline: Pipeline,
|
||||
|
||||
/// The size of the underlying page in page coordinates. This is an option
|
||||
/// because we may not know the size of the page until layout is finished completely.
|
||||
/// if we have no size yet, the layer is hidden until a size message is recieved.
|
||||
page_size: Option<Size2D<f32>>,
|
||||
|
||||
/// The offset of the page due to scrolling. (0,0) is when the window sees the
|
||||
/// top left corner of the page.
|
||||
scroll_offset: Point2D<f32>,
|
||||
|
||||
/// This layer's children. These could be iframes or any element which
|
||||
/// differs in scroll behavior from its parent. Each is associated with a
|
||||
/// ContainerLayer which determines its position relative to its parent and
|
||||
/// clipping rect. Children are stored in the order in which they are drawn.
|
||||
children: ~[CompositorLayerChild],
|
||||
|
||||
/// This layer's quadtree. This is where all buffers are stored for this layer.
|
||||
quadtree: MaybeQuadtree,
|
||||
|
||||
/// The root layer of this CompositorLayer's layer tree. Buffers are collected
|
||||
/// from the quadtree and inserted here when the layer is painted to the screen.
|
||||
root_layer: @mut ContainerLayer,
|
||||
|
||||
/// When set to true, this layer is ignored by its parents. This is useful for
|
||||
/// soft deletion or when waiting on a page size.
|
||||
hidden: bool,
|
||||
|
||||
/// A monotonically increasing counter that keeps track of the current epoch.
|
||||
/// add_buffer() calls that don't match the current epoch will be ignored.
|
||||
epoch: Epoch,
|
||||
|
||||
/// The behavior of this layer when a scroll message is received.
|
||||
scroll_behavior: ScrollBehavior,
|
||||
|
||||
/// True if CPU rendering is enabled, false if we're using GPU rendering.
|
||||
cpu_painting: bool,
|
||||
}
|
||||
|
||||
/// Helper struct for keeping CompositorLayer children organized.
|
||||
|
@ -76,11 +93,14 @@ enum ScrollBehavior {
|
|||
FixedPosition,
|
||||
}
|
||||
|
||||
|
||||
impl CompositorLayer {
|
||||
/// Creates a new CompositorLayer with an optional page size. If no page size is given,
|
||||
/// the layer is initially hidden and initialized without a quadtree.
|
||||
pub fn new(pipeline: Pipeline, page_size: Option<Size2D<f32>>, tile_size: uint, max_mem: Option<uint>)
|
||||
pub fn new(pipeline: Pipeline,
|
||||
page_size: Option<Size2D<f32>>,
|
||||
tile_size: uint,
|
||||
max_mem: Option<uint>,
|
||||
cpu_painting: bool)
|
||||
-> CompositorLayer {
|
||||
CompositorLayer {
|
||||
pipeline: pipeline,
|
||||
|
@ -89,8 +109,8 @@ impl CompositorLayer {
|
|||
children: ~[],
|
||||
quadtree: match page_size {
|
||||
None => NoTree(tile_size, max_mem),
|
||||
Some(page_size) => Tree(Quadtree::new(page_size.width as uint,
|
||||
page_size.height as uint,
|
||||
Some(page_size) => Tree(Quadtree::new(Size2D(page_size.width as uint,
|
||||
page_size.height as uint),
|
||||
tile_size,
|
||||
max_mem)),
|
||||
},
|
||||
|
@ -98,15 +118,18 @@ impl CompositorLayer {
|
|||
hidden: true,
|
||||
epoch: Epoch(0),
|
||||
scroll_behavior: Scroll,
|
||||
cpu_painting: cpu_painting,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a CompositorLayer tree from a frame tree.
|
||||
pub fn from_frame_tree(frame_tree: SendableFrameTree,
|
||||
tile_size: uint,
|
||||
max_mem: Option<uint>) -> CompositorLayer {
|
||||
max_mem: Option<uint>,
|
||||
cpu_painting: bool)
|
||||
-> CompositorLayer {
|
||||
let SendableFrameTree { pipeline, children } = frame_tree;
|
||||
let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem);
|
||||
let mut layer = CompositorLayer::new(pipeline, None, tile_size, max_mem, cpu_painting);
|
||||
layer.children = (do children.move_iter().map |child| {
|
||||
let SendableChildFrameTree { frame_tree, rect } = child;
|
||||
let container = @mut ContainerLayer();
|
||||
|
@ -121,7 +144,10 @@ impl CompositorLayer {
|
|||
None => {}
|
||||
}
|
||||
|
||||
let child_layer = ~CompositorLayer::from_frame_tree(frame_tree, tile_size, max_mem);
|
||||
let child_layer = ~CompositorLayer::from_frame_tree(frame_tree,
|
||||
tile_size,
|
||||
max_mem,
|
||||
cpu_painting);
|
||||
container.add_child_start(ContainerLayerKind(child_layer.root_layer));
|
||||
|
||||
CompositorLayerChild {
|
||||
|
@ -137,7 +163,8 @@ impl CompositorLayer {
|
|||
// the position of the layer relative to its parent. This also takes in a cursor position
|
||||
// to see if the mouse is over child layers first. If a layer successfully scrolled, returns
|
||||
// true; otherwise returns false, so a parent layer can scroll instead.
|
||||
pub fn scroll(&mut self, delta: Point2D<f32>, cursor: Point2D<f32>, window_size: Size2D<f32>) -> bool {
|
||||
pub fn scroll(&mut self, delta: Point2D<f32>, cursor: Point2D<f32>, window_size: Size2D<f32>)
|
||||
-> bool {
|
||||
let cursor = cursor - self.scroll_offset;
|
||||
for child in self.children.mut_iter().filter(|x| !x.child.hidden) {
|
||||
match child.container.scissor {
|
||||
|
@ -218,7 +245,11 @@ impl CompositorLayer {
|
|||
// Given the current window size, determine which tiles need to be (re)rendered
|
||||
// and sends them off the the appropriate renderer.
|
||||
// Returns a bool that is true if the scene should be repainted.
|
||||
pub fn get_buffer_request(&mut self, window_rect: Rect<f32>, scale: f32) -> bool {
|
||||
pub fn get_buffer_request(&mut self,
|
||||
graphics_context: &NativeCompositingGraphicsContext,
|
||||
window_rect: Rect<f32>,
|
||||
scale: f32)
|
||||
-> bool {
|
||||
let rect = Rect(Point2D(-self.scroll_offset.x + window_rect.origin.x,
|
||||
-self.scroll_offset.y + window_rect.origin.y),
|
||||
window_rect.size);
|
||||
|
@ -239,7 +270,7 @@ impl CompositorLayer {
|
|||
}
|
||||
}
|
||||
if redisplay {
|
||||
self.build_layer_tree();
|
||||
self.build_layer_tree(graphics_context);
|
||||
}
|
||||
let transform = |x: &mut CompositorLayerChild| -> bool {
|
||||
match x.container.scissor {
|
||||
|
@ -252,7 +283,7 @@ impl CompositorLayer {
|
|||
// to make the child_rect appear in coordinates local to it.
|
||||
let child_rect = Rect(new_rect.origin.sub(&scissor.origin),
|
||||
new_rect.size);
|
||||
x.child.get_buffer_request(child_rect, scale)
|
||||
x.child.get_buffer_request(graphics_context, child_rect, scale)
|
||||
}
|
||||
None => {
|
||||
false //Layer is offscreen
|
||||
|
@ -324,10 +355,10 @@ impl CompositorLayer {
|
|||
new_size.height as uint)));
|
||||
}
|
||||
NoTree(tile_size, max_mem) => {
|
||||
self.quadtree = Tree(Quadtree::new(new_size.width as uint,
|
||||
new_size.height as uint,
|
||||
self.quadtree = Tree(Quadtree::new(Size2D(new_size.width as uint,
|
||||
new_size.height as uint),
|
||||
tile_size,
|
||||
max_mem));
|
||||
max_mem))
|
||||
}
|
||||
}
|
||||
// Call scroll for bounds checking if the page shrunk. Use (-1, -1) as the cursor position
|
||||
|
@ -341,6 +372,23 @@ impl CompositorLayer {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns whether the layer should be vertically flipped. and
|
||||
#[cfg(target_os="macos")]
|
||||
fn texture_flip_and_target(cpu_painting: bool, size: Size2D<uint>) -> (Flip, TextureTarget) {
|
||||
let flip = if cpu_painting {
|
||||
NoFlip
|
||||
} else {
|
||||
VerticalFlip
|
||||
};
|
||||
|
||||
(flip, TextureTargetRectangle(size))
|
||||
}
|
||||
|
||||
#[cfg(not(target_os="macos"))]
|
||||
fn texture_flip_and_target(_: bool, _: Size2D<uint>) -> (Flip, TextureTarget) {
|
||||
(NoFlip, TextureTarget2D)
|
||||
}
|
||||
|
||||
// A helper method to resize sublayers.
|
||||
fn resize_helper(&mut self, pipeline_id: PipelineId, new_size: Size2D<f32>, epoch: Epoch) -> bool {
|
||||
let found = match self.children.iter().position(|x| pipeline_id == x.child.pipeline.id) {
|
||||
|
@ -355,10 +403,10 @@ impl CompositorLayer {
|
|||
new_size.height as uint)));
|
||||
}
|
||||
NoTree(tile_size, max_mem) => {
|
||||
child.quadtree = Tree(Quadtree::new(new_size.width as uint,
|
||||
new_size.height as uint,
|
||||
child.quadtree = Tree(Quadtree::new(Size2D(new_size.width as uint,
|
||||
new_size.height as uint),
|
||||
tile_size,
|
||||
max_mem));
|
||||
max_mem))
|
||||
}
|
||||
}
|
||||
match child_node.container.scissor {
|
||||
|
@ -386,7 +434,7 @@ impl CompositorLayer {
|
|||
|
||||
// Collect buffers from the quadtree. This method IS NOT recursive, so child CompositorLayers
|
||||
// are not rebuilt directly from this method.
|
||||
pub fn build_layer_tree(&mut self) {
|
||||
pub fn build_layer_tree(&mut self, graphics_context: &NativeCompositingGraphicsContext) {
|
||||
// Iterate over the children of the container layer.
|
||||
let mut current_layer_child = self.root_layer.first_child;
|
||||
|
||||
|
@ -410,19 +458,37 @@ impl CompositorLayer {
|
|||
for buffer in all_tiles.iter() {
|
||||
debug!("osmain: compositing buffer rect %?", &buffer.rect);
|
||||
|
||||
let size = Size2D(buffer.screen_pos.size.width as int,
|
||||
buffer.screen_pos.size.height as int);
|
||||
|
||||
// Find or create a texture layer.
|
||||
let texture_layer;
|
||||
current_layer_child = match current_layer_child {
|
||||
None => {
|
||||
debug!("osmain: adding new texture layer");
|
||||
texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
|
||||
|
||||
// Determine, in a platform-specific way, whether we should flip the texture
|
||||
// and which target to use.
|
||||
let (flip, target) =
|
||||
CompositorLayer::texture_flip_and_target(self.cpu_painting,
|
||||
buffer.screen_pos.size);
|
||||
|
||||
// Make a new texture and bind the layer buffer's surface to it.
|
||||
let texture = Texture::new(target);
|
||||
debug!("COMPOSITOR binding to native surface %d",
|
||||
buffer.native_surface.get_id() as int);
|
||||
buffer.native_surface.bind_to_texture(graphics_context, &texture, size);
|
||||
|
||||
// Make a texture layer and add it.
|
||||
texture_layer = @mut TextureLayer::new(texture, buffer.screen_pos.size, flip);
|
||||
self.root_layer.add_child_end(TextureLayerKind(texture_layer));
|
||||
None
|
||||
}
|
||||
Some(TextureLayerKind(existing_texture_layer)) => {
|
||||
texture_layer = existing_texture_layer;
|
||||
texture_layer.manager = @buffer.draw_target.clone() as @TextureManager;
|
||||
|
||||
let texture = &texture_layer.texture;
|
||||
buffer.native_surface.bind_to_texture(graphics_context, texture, size);
|
||||
|
||||
// Move on to the next sibling.
|
||||
do current_layer_child.unwrap().with_common |common| {
|
||||
|
@ -432,9 +498,8 @@ impl CompositorLayer {
|
|||
Some(_) => fail!(~"found unexpected layer kind"),
|
||||
};
|
||||
|
||||
|
||||
let rect = buffer.rect;
|
||||
// Set the layer's transform.
|
||||
let rect = buffer.rect;
|
||||
let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0);
|
||||
let transform = transform.scale(rect.size.width, rect.size.height, 1.0);
|
||||
texture_layer.common.set_transform(transform);
|
||||
|
@ -455,21 +520,32 @@ impl CompositorLayer {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Add LayerBuffers to the specified layer. Returns false if the layer is not found.
|
||||
// If the epoch of the message does not match the layer's epoch, the message is ignored.
|
||||
pub fn add_buffers(&mut self, pipeline_id: PipelineId, new_buffers: ~LayerBufferSet, epoch: Epoch) -> bool {
|
||||
// Add LayerBuffers to the specified layer. Returns the layer buffer set back if the layer that
|
||||
// matches the given pipeline ID was not found; otherwise returns None and consumes the layer
|
||||
// buffer set.
|
||||
//
|
||||
// If the epoch of the message does not match the layer's epoch, the message is ignored, the
|
||||
// layer buffer set is consumed, and None is returned.
|
||||
pub fn add_buffers(&mut self,
|
||||
graphics_context: &NativeCompositingGraphicsContext,
|
||||
pipeline_id: PipelineId,
|
||||
new_buffers: ~LayerBufferSet,
|
||||
epoch: Epoch)
|
||||
-> Option<~LayerBufferSet> {
|
||||
let cell = Cell::new(new_buffers);
|
||||
if self.pipeline.id == pipeline_id {
|
||||
if self.epoch != epoch {
|
||||
debug!("compositor epoch mismatch: %? != %?, id: %?", self.epoch, epoch, self.pipeline.id);
|
||||
debug!("compositor epoch mismatch: %? != %?, id: %?",
|
||||
self.epoch,
|
||||
epoch,
|
||||
self.pipeline.id);
|
||||
self.pipeline.render_chan.send(UnusedBufferMsg(cell.take().buffers));
|
||||
return true;
|
||||
return None;
|
||||
}
|
||||
{ // block here to prevent double mutable borrow of self
|
||||
{
|
||||
// Block here to prevent double mutable borrow of self.
|
||||
let quadtree = match self.quadtree {
|
||||
NoTree(*) => fail!("CompositorLayer: cannot add buffers, no quadtree initialized"),
|
||||
Tree(ref mut quadtree) => quadtree,
|
||||
|
@ -486,22 +562,30 @@ impl CompositorLayer {
|
|||
self.pipeline.render_chan.send(UnusedBufferMsg(unused_tiles));
|
||||
}
|
||||
}
|
||||
self.build_layer_tree();
|
||||
true
|
||||
} else {
|
||||
self.build_layer_tree(graphics_context);
|
||||
return None;
|
||||
}
|
||||
|
||||
// ID does not match ours, so recurse on descendents (including hidden children).
|
||||
self.children.mut_iter().map(|x| &mut x.child)
|
||||
.any(|x| {
|
||||
let buffers = cell.take();
|
||||
let result = x.add_buffers(pipeline_id, buffers.clone(), epoch);
|
||||
cell.put_back(buffers);
|
||||
result
|
||||
})
|
||||
for child_layer in self.children.mut_iter() {
|
||||
match child_layer.child.add_buffers(graphics_context,
|
||||
pipeline_id,
|
||||
cell.take(),
|
||||
epoch) {
|
||||
None => return None,
|
||||
Some(buffers) => cell.put_back(buffers),
|
||||
}
|
||||
}
|
||||
|
||||
// Not found. Give the caller the buffers back.
|
||||
Some(cell.take())
|
||||
}
|
||||
|
||||
// Deletes a specified sublayer, including hidden children. Returns false if the layer is not found.
|
||||
pub fn delete(&mut self, pipeline_id: PipelineId) -> bool {
|
||||
pub fn delete(&mut self,
|
||||
graphics_context: &NativeCompositingGraphicsContext,
|
||||
pipeline_id: PipelineId)
|
||||
-> bool {
|
||||
match self.children.iter().position(|x| x.child.pipeline.id == pipeline_id) {
|
||||
Some(i) => {
|
||||
let mut child = self.children.remove(i);
|
||||
|
@ -516,18 +600,16 @@ impl CompositorLayer {
|
|||
}
|
||||
}
|
||||
}
|
||||
match child.child.quadtree {
|
||||
NoTree(*) => {} // Nothing to do
|
||||
Tree(ref mut quadtree) => {
|
||||
|
||||
// Send back all tiles to renderer.
|
||||
child.child.pipeline.render_chan.send(UnusedBufferMsg(quadtree.collect_tiles()));
|
||||
}
|
||||
}
|
||||
self.build_layer_tree();
|
||||
child.child.clear();
|
||||
|
||||
self.build_layer_tree(graphics_context);
|
||||
true
|
||||
}
|
||||
None => {
|
||||
self.children.mut_iter().map(|x| &mut x.child).any(|x| x.delete(pipeline_id))
|
||||
self.children.mut_iter().map(|x| &mut x.child)
|
||||
.any(|x| x.delete(graphics_context, pipeline_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -554,7 +636,11 @@ impl CompositorLayer {
|
|||
container.common.set_transform(identity().translate(clipping_rect.origin.x,
|
||||
clipping_rect.origin.y,
|
||||
0.0));
|
||||
let child = ~CompositorLayer::new(pipeline, page_size, tile_size, max_mem);
|
||||
let child = ~CompositorLayer::new(pipeline,
|
||||
page_size,
|
||||
tile_size,
|
||||
max_mem,
|
||||
self.cpu_painting);
|
||||
container.add_child_start(ContainerLayerKind(child.root_layer));
|
||||
self.children.push(CompositorLayerChild {
|
||||
child: child,
|
||||
|
@ -582,4 +668,57 @@ impl CompositorLayer {
|
|||
child.child.set_occlusions();
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys all quadtree tiles, sending the buffers back to the renderer to be destroyed or
|
||||
/// reused.
|
||||
fn clear(&mut self) {
|
||||
match self.quadtree {
|
||||
NoTree(*) => {}
|
||||
Tree(ref mut quadtree) => {
|
||||
let mut tiles = quadtree.collect_tiles();
|
||||
|
||||
// We have no way of knowing without a race whether the render task is even up and
|
||||
// running, but mark the tiles as not leaking. If the render task died, then the
|
||||
// tiles are going to be cleaned up.
|
||||
for tile in tiles.mut_iter() {
|
||||
tile.mark_wont_leak()
|
||||
}
|
||||
|
||||
self.pipeline.render_chan.send(UnusedBufferMsg(tiles))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys all quadtree tiles of all layers, including child layers, sending the buffers
|
||||
/// back to the renderer to be destroyed or reused.
|
||||
pub fn clear_all(&mut self) {
|
||||
self.clear();
|
||||
|
||||
for kid in self.children.mut_iter() {
|
||||
kid.child.clear_all()
|
||||
}
|
||||
}
|
||||
|
||||
/// Destroys all tiles of all layers, including children, *without* sending them back to the
|
||||
/// renderer. You must call this only when the render task is destined to be going down;
|
||||
/// otherwise, you will leak tiles.
|
||||
///
|
||||
/// This is used during shutdown, when we know the render task is going away.
|
||||
pub fn forget_all_tiles(&mut self) {
|
||||
match self.quadtree {
|
||||
NoTree(*) => {}
|
||||
Tree(ref mut quadtree) => {
|
||||
let tiles = quadtree.collect_tiles();
|
||||
for tile in tiles.move_iter() {
|
||||
let mut tile = tile;
|
||||
tile.mark_wont_leak()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for kid in self.children.mut_iter() {
|
||||
kid.child.forget_all_tiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,21 +4,25 @@
|
|||
|
||||
pub use windowing;
|
||||
|
||||
use servo_msg::compositor_msg::{RenderListener, LayerBufferSet, RenderState};
|
||||
use servo_msg::compositor_msg::{ReadyState, ScriptListener, Epoch};
|
||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
|
||||
use gfx::opts::Opts;
|
||||
|
||||
use azure::azure::AzGLContext;
|
||||
use std::comm;
|
||||
use std::comm::{Chan, SharedChan, Port};
|
||||
use std::num::Orderable;
|
||||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::rect::Rect;
|
||||
use servo_util::time::ProfilerChan;
|
||||
|
||||
use constellation::SendableFrameTree;
|
||||
use windowing::WindowMethods;
|
||||
|
||||
use azure::azure_hl::SourceSurfaceMethods;
|
||||
use geom::point::Point2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use gfx::opts::Opts;
|
||||
use layers::platform::surface::{NativeCompositingGraphicsContext, NativeGraphicsMetadata};
|
||||
use servo_msg::compositor_msg::{Epoch, RenderListener, LayerBufferSet, RenderState, ReadyState};
|
||||
use servo_msg::compositor_msg::{ScriptListener, Tile};
|
||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
|
||||
use servo_util::time::ProfilerChan;
|
||||
use std::comm::{Chan, SharedChan, Port};
|
||||
use std::comm;
|
||||
use std::num::Orderable;
|
||||
|
||||
#[cfg(target_os="linux")]
|
||||
use azure::azure_hl;
|
||||
|
||||
mod quadtree;
|
||||
mod compositor_layer;
|
||||
|
@ -36,7 +40,6 @@ pub struct CompositorChan {
|
|||
|
||||
/// Implementation of the abstract `ScriptListener` interface.
|
||||
impl ScriptListener for CompositorChan {
|
||||
|
||||
fn set_ready_state(&self, ready_state: ReadyState) {
|
||||
let msg = ChangeReadyState(ready_state);
|
||||
self.chan.send(msg);
|
||||
|
@ -54,10 +57,9 @@ impl ScriptListener for CompositorChan {
|
|||
|
||||
/// Implementation of the abstract `RenderListener` interface.
|
||||
impl RenderListener for CompositorChan {
|
||||
|
||||
fn get_gl_context(&self) -> AzGLContext {
|
||||
fn get_graphics_metadata(&self) -> NativeGraphicsMetadata {
|
||||
let (port, chan) = comm::stream();
|
||||
self.chan.send(GetGLContext(chan));
|
||||
self.chan.send(GetGraphicsMetadata(chan));
|
||||
port.recv()
|
||||
}
|
||||
|
||||
|
@ -115,8 +117,10 @@ pub enum Msg {
|
|||
Exit,
|
||||
/// Requests the window size
|
||||
GetSize(Chan<Size2D<int>>),
|
||||
/// Requests the compositors GL context.
|
||||
GetGLContext(Chan<AzGLContext>),
|
||||
/// Requests the compositor's graphics metadata. Graphics metadata is what the renderer needs
|
||||
/// to create surfaces that the compositor can see. On Linux this is the X display; on Mac this
|
||||
/// is the pixel format.
|
||||
GetGraphicsMetadata(Chan<NativeGraphicsMetadata>),
|
||||
|
||||
/// Alerts the compositor that there is a new layer to be rendered.
|
||||
NewLayer(PipelineId, Size2D<f32>),
|
||||
|
@ -160,6 +164,18 @@ impl CompositorTask {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a graphics context. Platform-specific.
|
||||
///
|
||||
/// FIXME(pcwalton): Probably could be less platform-specific, using the metadata abstraction.
|
||||
#[cfg(target_os="linux")]
|
||||
fn create_graphics_context() -> NativeCompositingGraphicsContext {
|
||||
NativeCompositingGraphicsContext::from_display(azure_hl::current_display())
|
||||
}
|
||||
#[cfg(not(target_os="linux"))]
|
||||
fn create_graphics_context() -> NativeCompositingGraphicsContext {
|
||||
NativeCompositingGraphicsContext::new()
|
||||
}
|
||||
|
||||
pub fn run(&self) {
|
||||
if self.opts.headless {
|
||||
run_headless::run_compositor(self);
|
||||
|
|
|
@ -8,12 +8,16 @@
|
|||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::rect::Rect;
|
||||
use gfx::render_task::BufferRequest;
|
||||
use std::uint::{div_ceil, next_power_of_two};
|
||||
use std::vec;
|
||||
use std::util::replace;
|
||||
use gfx::render_task::BufferRequest;
|
||||
use std::vec::build;
|
||||
use servo_msg::compositor_msg::Tile;
|
||||
|
||||
#[cfg(test)]
|
||||
use layers::platform::surface::NativePaintingGraphicsContext;
|
||||
|
||||
static HEADER: &'static str = "<!DOCTYPE html><html>";
|
||||
|
||||
/// Parent to all quadtree nodes. Stores variables needed at all levels. All method calls
|
||||
|
@ -75,9 +79,9 @@ impl<T: Tile> Quadtree<T> {
|
|||
/// Takes in the initial width and height of the space, a maximum tile size, and
|
||||
/// a maximum amount of memory. Tiles will be deleted if this memory is exceeded.
|
||||
/// Set max_mem to None to turn off automatic tile removal.
|
||||
pub fn new(width: uint, height: uint, tile_size: uint, max_mem: Option<uint>) -> Quadtree<T> {
|
||||
pub fn new(clip_size: Size2D<uint>, tile_size: uint, max_mem: Option<uint>) -> Quadtree<T> {
|
||||
// Spaces must be squares and powers of 2, so expand the space until it is
|
||||
let longer = width.max(&height);
|
||||
let longer = clip_size.width.max(&clip_size.height);
|
||||
let num_tiles = div_ceil(longer, tile_size);
|
||||
let power_of_two = next_power_of_two(num_tiles);
|
||||
let size = power_of_two * tile_size;
|
||||
|
@ -91,7 +95,7 @@ impl<T: Tile> Quadtree<T> {
|
|||
tile_mem: 0,
|
||||
status: Normal,
|
||||
},
|
||||
clip_size: Size2D(width, height),
|
||||
clip_size: clip_size,
|
||||
max_tile_size: tile_size,
|
||||
max_mem: max_mem,
|
||||
}
|
||||
|
@ -111,7 +115,7 @@ impl<T: Tile> Quadtree<T> {
|
|||
self.root.get_tile(x, y)
|
||||
}
|
||||
|
||||
/// Add a tile associtated with a given pixel position and scale.
|
||||
/// Add a tile associated with a given pixel position and scale.
|
||||
/// If the tile pushes the total memory over its maximum, tiles will be removed
|
||||
/// until total memory is below the maximum again. These tiles are returned.
|
||||
pub fn add_tile_pixel(&mut self, x: uint, y: uint, scale: f32, tile: T) -> ~[T] {
|
||||
|
@ -133,7 +137,7 @@ impl<T: Tile> Quadtree<T> {
|
|||
tiles
|
||||
}
|
||||
|
||||
/// Add a tile associtated with a given page position.
|
||||
/// Add a tile associated with a given page position.
|
||||
/// If the tile pushes the total memory over its maximum, tiles will be removed
|
||||
/// until total memory is below the maximum again. These tiles are returned.
|
||||
pub fn add_tile_page(&mut self, x: f32, y: f32, scale: f32, tile: T) -> ~[T] {
|
||||
|
@ -302,7 +306,6 @@ impl<T: Tile> Quadtree<T> {
|
|||
pub fn get_html(&self) -> ~str {
|
||||
fmt!("%s<body>%s</body></html>", HEADER, self.root.get_html())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<T: Tile> QuadtreeNode<T> {
|
||||
|
@ -769,7 +772,6 @@ impl<T: Tile> QuadtreeNode<T> {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -789,9 +791,11 @@ pub fn test_resize() {
|
|||
fn get_size_2d(&self) -> Size2D<uint> {
|
||||
Size2D(0u, 0u)
|
||||
}
|
||||
fn mark_wont_leak(&mut self) {}
|
||||
fn destroy(self, _: &NativePaintingGraphicsContext) {}
|
||||
}
|
||||
|
||||
let mut q = Quadtree::new(6, 6, 1, None);
|
||||
let mut q = Quadtree::new(Size2D(6u, 6), 1, None);
|
||||
q.add_tile_pixel(0, 0, 1f32, T{a: 0});
|
||||
q.add_tile_pixel(5, 5, 1f32, T{a: 1});
|
||||
q.bad_resize(8, 1);
|
||||
|
@ -822,9 +826,11 @@ pub fn test() {
|
|||
fn get_size_2d(&self) -> Size2D<uint> {
|
||||
Size2D(0u, 0u)
|
||||
}
|
||||
fn mark_wont_leak(&mut self) {}
|
||||
fn destroy(self, _: &NativePaintingGraphicsContext) {}
|
||||
}
|
||||
|
||||
let mut q = Quadtree::new(8, 8, 2, Some(4));
|
||||
let mut q = Quadtree::new(Size2D(8u, 8), 2, Some(4));
|
||||
q.add_tile_pixel(0, 0, 1f32, T{a: 0});
|
||||
q.add_tile_pixel(0, 0, 2f32, T{a: 1});
|
||||
q.add_tile_pixel(0, 0, 2f32, T{a: 2});
|
||||
|
|
|
@ -12,7 +12,8 @@ use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEven
|
|||
use servo_msg::constellation_msg::{ConstellationChan, NavigateMsg, ResizedWindowMsg, LoadUrlMsg};
|
||||
use servo_msg::constellation_msg;
|
||||
|
||||
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
|
||||
use azure::azure_hl::SourceSurfaceMethods;
|
||||
use azure::azure_hl;
|
||||
use std::comm::Port;
|
||||
use std::num::Orderable;
|
||||
use std::vec;
|
||||
|
@ -22,8 +23,7 @@ use geom::matrix::identity;
|
|||
use geom::point::Point2D;
|
||||
use geom::size::Size2D;
|
||||
use geom::rect::Rect;
|
||||
use layers::layers::{ARGB32Format, ContainerLayer, ContainerLayerKind, Format};
|
||||
use layers::layers::{ImageData, WithDataFn};
|
||||
use layers::layers::{ContainerLayer, ContainerLayerKind};
|
||||
use layers::rendergl;
|
||||
use layers::scene::Scene;
|
||||
use opengles::gl2;
|
||||
|
@ -38,31 +38,6 @@ use compositing::compositor_layer::CompositorLayer;
|
|||
|
||||
use compositing::*;
|
||||
|
||||
/// Azure surface wrapping to work with the layers infrastructure.
|
||||
struct AzureDrawTargetImageData {
|
||||
draw_target: DrawTarget,
|
||||
data_source_surface: DataSourceSurface,
|
||||
size: Size2D<uint>,
|
||||
}
|
||||
|
||||
impl ImageData for AzureDrawTargetImageData {
|
||||
fn size(&self) -> Size2D<uint> {
|
||||
self.size
|
||||
}
|
||||
fn stride(&self) -> uint {
|
||||
self.data_source_surface.stride() as uint
|
||||
}
|
||||
fn format(&self) -> Format {
|
||||
// FIXME: This is not always correct. We should query the Azure draw target for the format.
|
||||
ARGB32Format
|
||||
}
|
||||
fn with_data(&self, f: WithDataFn) {
|
||||
do self.data_source_surface.with_data |data| {
|
||||
f(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the compositor, which listens for messages on the specified port.
|
||||
pub fn run_compositor(compositor: &CompositorTask) {
|
||||
let app: Application = ApplicationMethods::new();
|
||||
|
@ -79,6 +54,7 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
let mut window_size = Size2D(window_size.width as uint, window_size.height as uint);
|
||||
let mut done = false;
|
||||
let mut recomposite = false;
|
||||
let graphics_context = CompositorTask::create_graphics_context();
|
||||
|
||||
// Keeps track of the current zoom factor
|
||||
let mut world_zoom = 1f32;
|
||||
|
@ -95,8 +71,9 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
window_size.height as f32 / world_zoom);
|
||||
for layer in compositor_layer.mut_iter() {
|
||||
if !layer.hidden {
|
||||
recomposite = layer.get_buffer_request(Rect(Point2D(0f32, 0f32), window_size_page),
|
||||
world_zoom) || recomposite;
|
||||
let rect = Rect(Point2D(0f32, 0f32), window_size_page);
|
||||
recomposite = layer.get_buffer_request(&graphics_context, rect, world_zoom) ||
|
||||
recomposite;
|
||||
} else {
|
||||
debug!("Compositor: root layer is hidden!");
|
||||
}
|
||||
|
@ -123,10 +100,17 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
|
||||
let layer = CompositorLayer::from_frame_tree(frame_tree,
|
||||
compositor.opts.tile_size,
|
||||
Some(10000000u));
|
||||
Some(10000000u),
|
||||
compositor.opts.cpu_painting);
|
||||
root_layer.add_child_start(ContainerLayerKind(layer.root_layer));
|
||||
compositor_layer = Some(layer);
|
||||
|
||||
// If there's already a root layer, destroy it cleanly.
|
||||
match compositor_layer {
|
||||
None => {}
|
||||
Some(ref mut compositor_layer) => compositor_layer.clear_all(),
|
||||
}
|
||||
|
||||
compositor_layer = Some(layer);
|
||||
constellation_chan = Some(new_constellation_chan);
|
||||
}
|
||||
|
||||
|
@ -135,7 +119,7 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
chan.send(Size2D(size.width as int, size.height as int));
|
||||
}
|
||||
|
||||
GetGLContext(chan) => chan.send(current_gl_context()),
|
||||
GetGraphicsMetadata(chan) => chan.send(azure_hl::current_graphics_metadata()),
|
||||
|
||||
NewLayer(_id, new_size) => {
|
||||
// FIXME: This should create an additional layer instead of replacing the current one.
|
||||
|
@ -146,8 +130,11 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
None => fail!("Compositor: Received new layer without initialized pipeline"),
|
||||
};
|
||||
let page_size = Size2D(new_size.width as f32, new_size.height as f32);
|
||||
let new_layer = CompositorLayer::new(p, Some(page_size),
|
||||
compositor.opts.tile_size, Some(10000000u));
|
||||
let new_layer = CompositorLayer::new(p,
|
||||
Some(page_size),
|
||||
compositor.opts.tile_size,
|
||||
Some(10000000u),
|
||||
compositor.opts.cpu_painting);
|
||||
|
||||
let current_child = root_layer.first_child;
|
||||
// This assumes there is at most one child, which should be the case.
|
||||
|
@ -186,7 +173,7 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
DeleteLayer(id) => {
|
||||
match compositor_layer {
|
||||
Some(ref mut layer) => {
|
||||
assert!(layer.delete(id));
|
||||
assert!(layer.delete(&graphics_context, id));
|
||||
ask_for_tiles();
|
||||
}
|
||||
None => {}
|
||||
|
@ -196,9 +183,16 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
Paint(id, new_layer_buffer_set, epoch) => {
|
||||
debug!("osmain: received new frame");
|
||||
|
||||
// From now on, if we destroy the buffers, they will leak.
|
||||
let mut new_layer_buffer_set = new_layer_buffer_set;
|
||||
new_layer_buffer_set.mark_will_leak();
|
||||
|
||||
match compositor_layer {
|
||||
Some(ref mut layer) => {
|
||||
assert!(layer.add_buffers(id, new_layer_buffer_set, epoch));
|
||||
assert!(layer.add_buffers(&graphics_context,
|
||||
id,
|
||||
new_layer_buffer_set,
|
||||
epoch).is_none());
|
||||
recomposite = true;
|
||||
}
|
||||
None => {
|
||||
|
@ -401,5 +395,11 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
|
||||
}
|
||||
|
||||
compositor.shutdown_chan.send(())
|
||||
compositor.shutdown_chan.send(());
|
||||
|
||||
// Clear out the compositor layers so that painting tasks can destroy the buffers.
|
||||
match compositor_layer {
|
||||
None => {}
|
||||
Some(ref mut layer) => layer.forget_all_tiles(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
* 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 geom::size::Size2D;
|
||||
use std::ptr;
|
||||
|
||||
use compositing::*;
|
||||
|
||||
use geom::size::Size2D;
|
||||
use std::unstable::intrinsics;
|
||||
|
||||
/// Starts the compositor, which listens for messages on the specified port.
|
||||
///
|
||||
/// This is the null compositor which doesn't draw anything to the screen.
|
||||
|
@ -20,8 +20,10 @@ pub fn run_compositor(compositor: &CompositorTask) {
|
|||
chan.send(Size2D(500, 500));
|
||||
}
|
||||
|
||||
GetGLContext(chan) => {
|
||||
chan.send(ptr::null());
|
||||
GetGraphicsMetadata(chan) => {
|
||||
unsafe {
|
||||
chan.send(intrinsics::uninit());
|
||||
}
|
||||
}
|
||||
|
||||
SetIds(_, response_chan, _) => {
|
||||
|
|
|
@ -39,6 +39,8 @@ extern mod extra;
|
|||
extern mod core_graphics;
|
||||
#[cfg(target_os="macos")]
|
||||
extern mod core_text;
|
||||
#[cfg(target_os="macos")]
|
||||
extern mod io_surface;
|
||||
|
||||
use compositing::{CompositorChan, CompositorTask};
|
||||
use constellation::Constellation;
|
||||
|
|
|
@ -2,38 +2,46 @@
|
|||
* 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 azure::azure_hl::DrawTarget;
|
||||
use azure::azure::AzGLContext;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use layers::platform::surface::{NativeGraphicsMetadata, NativePaintingGraphicsContext};
|
||||
use layers::platform::surface::{NativeSurface, NativeSurfaceMethods};
|
||||
|
||||
use constellation_msg::PipelineId;
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct LayerBuffer {
|
||||
draw_target: DrawTarget,
|
||||
/// The native surface which can be shared between threads or processes. On Mac this is an
|
||||
/// `IOSurface`; on Linux this is an X Pixmap; on Android this is an `EGLImageKHR`.
|
||||
native_surface: NativeSurface,
|
||||
|
||||
// The rect in the containing RenderLayer that this represents.
|
||||
/// The rect in the containing RenderLayer that this represents.
|
||||
rect: Rect<f32>,
|
||||
|
||||
// The rect in pixels that will be drawn to the screen.
|
||||
/// The rect in pixels that will be drawn to the screen.
|
||||
screen_pos: Rect<uint>,
|
||||
|
||||
// The scale at which this tile is rendered
|
||||
/// The scale at which this tile is rendered
|
||||
resolution: f32,
|
||||
|
||||
// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
|
||||
/// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
|
||||
stride: uint,
|
||||
|
||||
}
|
||||
|
||||
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
|
||||
/// buffers.
|
||||
#[deriving(Clone)]
|
||||
pub struct LayerBufferSet {
|
||||
buffers: ~[~LayerBuffer]
|
||||
}
|
||||
|
||||
impl LayerBufferSet {
|
||||
/// Notes all buffer surfaces will leak if not destroyed via a call to `destroy`.
|
||||
pub fn mark_will_leak(&mut self) {
|
||||
for buffer in self.buffers.mut_iter() {
|
||||
buffer.native_surface.mark_will_leak()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of the renderer.
|
||||
#[deriving(Eq)]
|
||||
pub enum RenderState {
|
||||
|
@ -66,7 +74,7 @@ impl Epoch {
|
|||
/// The interface used by the renderer to acquire draw targets for each render frame and
|
||||
/// submit them to be drawn to the display.
|
||||
pub trait RenderListener {
|
||||
fn get_gl_context(&self) -> AzGLContext;
|
||||
fn get_graphics_metadata(&self) -> NativeGraphicsMetadata;
|
||||
fn new_layer(&self, PipelineId, Size2D<uint>);
|
||||
fn set_layer_page_size(&self, PipelineId, Size2D<uint>, Epoch);
|
||||
fn set_layer_clip_rect(&self, PipelineId, Rect<uint>);
|
||||
|
@ -83,7 +91,7 @@ pub trait ScriptListener : Clone {
|
|||
fn close(&self);
|
||||
}
|
||||
|
||||
/// The interface used by the quadtree to get info about LayerBuffers
|
||||
/// The interface used by the quadtree and buffer map to get info about layer buffers.
|
||||
pub trait Tile {
|
||||
/// Returns the amount of memory used by the tile
|
||||
fn get_mem(&self) -> uint;
|
||||
|
@ -91,6 +99,13 @@ pub trait Tile {
|
|||
fn is_valid(&self, f32) -> bool;
|
||||
/// Returns the Size2D of the tile
|
||||
fn get_size_2d(&self) -> Size2D<uint>;
|
||||
|
||||
/// Marks the layer buffer as not leaking. See comments on
|
||||
/// `NativeSurfaceMethods::mark_wont_leak` for how this is used.
|
||||
fn mark_wont_leak(&mut self);
|
||||
|
||||
/// Destroys the layer buffer. Painting task only.
|
||||
fn destroy(self, graphics_context: &NativePaintingGraphicsContext);
|
||||
}
|
||||
|
||||
impl Tile for ~LayerBuffer {
|
||||
|
@ -104,4 +119,12 @@ impl Tile for ~LayerBuffer {
|
|||
fn get_size_2d(&self) -> Size2D<uint> {
|
||||
self.screen_pos.size
|
||||
}
|
||||
fn mark_wont_leak(&mut self) {
|
||||
self.native_surface.mark_wont_leak()
|
||||
}
|
||||
fn destroy(self, graphics_context: &NativePaintingGraphicsContext) {
|
||||
let mut this = self;
|
||||
this.native_surface.destroy(graphics_context)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,33 @@
|
|||
url = "http://servo.org/")];
|
||||
#[crate_type = "lib"];
|
||||
|
||||
|
||||
extern mod azure;
|
||||
extern mod std;
|
||||
extern mod geom;
|
||||
extern mod extra;
|
||||
extern mod geom;
|
||||
extern mod layers;
|
||||
extern mod std;
|
||||
|
||||
#[cfg(target_os="macos")]
|
||||
extern mod core_foundation;
|
||||
#[cfg(target_os="macos")]
|
||||
extern mod io_surface;
|
||||
|
||||
pub mod compositor_msg;
|
||||
pub mod constellation_msg;
|
||||
|
||||
pub mod platform {
|
||||
#[cfg(target_os="macos")]
|
||||
pub mod macos {
|
||||
#[cfg(target_os="macos")]
|
||||
pub mod surface;
|
||||
}
|
||||
|
||||
#[cfg(target_os="linux")]
|
||||
pub mod linux {
|
||||
#[cfg(target_os="linux")]
|
||||
pub mod surface;
|
||||
}
|
||||
|
||||
pub mod surface;
|
||||
}
|
||||
|
||||
|
|
20
src/components/msg/platform/linux/surface.rs
Normal file
20
src/components/msg/platform/linux/surface.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* 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/. */
|
||||
|
||||
//! X11-specific implementation of cross-process surfaces. This uses X pixmaps.
|
||||
|
||||
use platform::surface::NativeSurfaceAzureMethods;
|
||||
|
||||
use azure::AzSkiaGrGLSharedSurfaceRef;
|
||||
use layers::platform::surface::NativeSurface;
|
||||
use std::cast;
|
||||
|
||||
impl NativeSurfaceAzureMethods for NativeSurface {
|
||||
fn from_azure_surface(surface: AzSkiaGrGLSharedSurfaceRef) -> NativeSurface {
|
||||
unsafe {
|
||||
NativeSurface::from_pixmap(cast::transmute(surface))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
src/components/msg/platform/macos/surface.rs
Normal file
26
src/components/msg/platform/macos/surface.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* 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/. */
|
||||
|
||||
//! Mac OS-specific implementation of cross-process surfaces. This uses `IOSurface`, introduced
|
||||
//! in Mac OS X 10.6 Snow Leopard.
|
||||
|
||||
use platform::surface::NativeSurfaceAzureMethods;
|
||||
|
||||
use azure::AzSkiaGrGLSharedSurfaceRef;
|
||||
use core_foundation::base::CFWrapper;
|
||||
use io_surface::IOSurface;
|
||||
use layers::platform::surface::NativeSurface;
|
||||
use std::cast;
|
||||
|
||||
impl NativeSurfaceAzureMethods for NativeSurface {
|
||||
fn from_azure_surface(surface: AzSkiaGrGLSharedSurfaceRef) -> NativeSurface {
|
||||
unsafe {
|
||||
let io_surface = IOSurface {
|
||||
contents: CFWrapper::wrap_owned(cast::transmute(surface)),
|
||||
};
|
||||
NativeSurface::from_io_surface(io_surface)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
src/components/msg/platform/surface.rs
Normal file
12
src/components/msg/platform/surface.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* 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/. */
|
||||
|
||||
//! Declarations of types for cross-process surfaces.
|
||||
|
||||
use azure::AzSkiaGrGLSharedSurfaceRef;
|
||||
|
||||
pub trait NativeSurfaceAzureMethods {
|
||||
fn from_azure_surface(surface: AzSkiaGrGLSharedSurfaceRef) -> Self;
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit deefb42dd238f54f95bf09f47d19e1c2acfd1c74
|
||||
Subproject commit 71ca7ff52c7f342c95608c00bb0823aa8f39cd34
|
|
@ -1 +1 @@
|
|||
Subproject commit 45e3f33cf6a3109b4dbb7bf9e0cb814d6e1e4b55
|
||||
Subproject commit a4bd491ddfd5d17bdcb228cf515cce776e2b8239
|
|
@ -1 +1 @@
|
|||
Subproject commit 614d65361a29c0100bd662102e1b8d33698ea330
|
||||
Subproject commit b932f0d91dad470baefafe291d4958de4ff01d47
|
|
@ -1 +1 @@
|
|||
Subproject commit b5212699f9ad364898b685f5f945b821ee528771
|
||||
Subproject commit 82d56dfc632fe458d126d049fd5abe856170f48d
|
|
@ -1 +1 @@
|
|||
Subproject commit 716c3326d3d6073c48ecfb301c2ab6e7eeeccfcf
|
||||
Subproject commit 191fab2cf685671ef73ec13e85bdd889b0e93662
|
|
@ -1 +1 @@
|
|||
Subproject commit 71dcba600f546d6c4daec56659e02c8db9fdf003
|
||||
Subproject commit a5da47f086c06a5ff9e179203fc8dbd5b7bb3c04
|
|
@ -1 +1 @@
|
|||
Subproject commit 96665d2033e5cda1ae419ce70a4071b61bc58b09
|
||||
Subproject commit 70ba8e70d7828e572dd1a4dd8807e9730db56137
|
|
@ -1 +1 @@
|
|||
Subproject commit aeae6a5cd5a6ecb7fd2d3b2f806e9661ce3b2e3b
|
||||
Subproject commit 73b73c23696a373b84289711b537eaa00065e4f9
|
Loading…
Add table
Add a link
Reference in a new issue