Add a headless null compositor

We also have to disable rendering in headless mode because it uses OpenGL calls
for now.

Fixes #471.
This commit is contained in:
Keegan McAllister 2013-10-18 16:16:48 -07:00
parent ecc3db7b1f
commit 1b785f150c
5 changed files with 60 additions and 1 deletions

View file

@ -72,6 +72,7 @@ make
- `-p INTERVAL` turns on the profiler and dumps info to the console every - `-p INTERVAL` turns on the profiler and dumps info to the console every
`INTERVAL` seconds `INTERVAL` seconds
- `-s SIZE` sets the tile size for rendering; defaults to 512 - `-s SIZE` sets the tile size for rendering; defaults to 512
- `-z` disables all graphical output; useful for running JS / layout tests
### Keyboard Shortcuts ### Keyboard Shortcuts

View file

@ -19,6 +19,7 @@ pub struct Opts {
profiler_period: Option<f64>, profiler_period: Option<f64>,
exit_after_load: bool, exit_after_load: bool,
output_file: Option<~str>, output_file: Option<~str>,
headless: bool,
} }
pub fn from_cmdline_args(args: &[~str]) -> Opts { pub fn from_cmdline_args(args: &[~str]) -> Opts {
@ -33,6 +34,7 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
getopts::optopt("t"), // threads to render with getopts::optopt("t"), // threads to render with
getopts::optflagopt("p"), // profiler flag and output interval getopts::optflagopt("p"), // profiler flag and output interval
getopts::optflag("x"), // exit after load flag getopts::optflag("x"), // exit after load flag
getopts::optflag("z"), // headless mode
]; ];
let opt_match = match getopts::getopts(args, opts) { let opt_match = match getopts::getopts(args, opts) {
@ -81,6 +83,7 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
}; };
let exit_after_load = opt_match.opt_present("x"); let exit_after_load = opt_match.opt_present("x");
let headless = opt_match.opt_present("z");
let output_file = opt_match.opt_str("o"); let output_file = opt_match.opt_str("o");
@ -92,5 +95,6 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
profiler_period: profiler_period, profiler_period: profiler_period,
exit_after_load: exit_after_load, exit_after_load: exit_after_load,
output_file: output_file, output_file: output_file,
headless: headless,
} }
} }

View file

@ -204,6 +204,13 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
} }
fn render(&mut self, tiles: ~[BufferRequest], scale: f32) { fn render(&mut self, tiles: ~[BufferRequest], scale: f32) {
// In headless mode, disable the renderer, because it makes OpenGL
// calls. Once we have CPU rendering we should render in CPU mode and
// just disable texture upload.
if self.opts.headless {
return;
}
let render_layer; let render_layer;
match self.render_layer { match self.render_layer {
Some(ref r_layer) => { Some(ref r_layer) => {

View file

@ -22,7 +22,9 @@ use constellation::SendableFrameTree;
mod quadtree; mod quadtree;
mod compositor_layer; mod compositor_layer;
mod run; mod run;
mod run_headless;
/// The implementation of the layers-based compositor. /// The implementation of the layers-based compositor.
@ -159,6 +161,10 @@ impl CompositorTask {
} }
pub fn run(&self) { pub fn run(&self) {
if self.opts.headless {
run_headless::run_compositor(self);
} else {
run::run_compositor(self); run::run_compositor(self);
} }
}
} }

View file

@ -0,0 +1,41 @@
/* 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 geom::size::Size2D;
use std::ptr;
use compositing::*;
/// Starts the compositor, which listens for messages on the specified port.
///
/// This is the null compositor which doesn't draw anything to the screen.
/// It's intended for headless testing.
pub fn run_compositor(compositor: &CompositorTask) {
loop {
match compositor.port.recv() {
Exit => break,
GetSize(chan) => {
chan.send(Size2D(500, 500));
}
GetGLContext(chan) => {
chan.send(ptr::null());
}
SetIds(_, response_chan, _) => {
response_chan.send(());
}
// Explicitly list ignored messages so that when we add a new one,
// we'll notice and think about whether it needs a response, like
// SetIds.
NewLayer(*) | SetLayerPageSize(*) | SetLayerClipRect(*) | DeleteLayer(*) |
Paint(*) | InvalidateRect(*) | ChangeReadyState(*) | ChangeRenderState(*)
=> ()
}
}
compositor.shutdown_chan.send(())
}