Auto merge of #11744 - emilio:wr-default, r=glennw

webgl: Unlock WebRender by default by adding a readback based fallback to WebGL context creation.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors

<!-- Either: -->
- [x] These changes do not require tests because refactoring.

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

This should give us the chance to use WebRender by default in OSX.

r? @pcwalton

cc @glennw @larsbergstrom

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11744)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-07-10 17:25:29 -07:00 committed by GitHub
commit 68aca87e30
2 changed files with 55 additions and 27 deletions

View file

@ -30,7 +30,7 @@ impl<'a> CanvasPaintThread<'a> {
let canvas_rect = Rect::new(Point2D::new(0i32, 0i32), canvas_size);
let src_read_rect = canvas_rect.intersection(&read_rect).unwrap_or(Rect::zero());
let mut image_data = Vec::new();
let mut image_data = vec![];
if src_read_rect.is_empty() || canvas_size.width <= 0 && canvas_size.height <= 0 {
return image_data;
}
@ -110,7 +110,7 @@ impl<'a> CanvasPaintThread<'a> {
drawtarget: draw_target,
path_builder: path_builder,
state: CanvasPaintState::new(),
saved_states: Vec::new(),
saved_states: vec![],
webrender_api: webrender_api,
webrender_image_key: webrender_image_key,
}
@ -543,13 +543,11 @@ impl<'a> CanvasPaintThread<'a> {
self.drawtarget.snapshot().get_data_surface().with_data(|element| {
if let Some(ref webrender_api) = self.webrender_api {
let size = self.drawtarget.get_size();
let mut bytes = Vec::new();
bytes.extend_from_slice(element);
webrender_api.update_image(self.webrender_image_key.unwrap(),
size.width as u32,
size.height as u32,
webrender_traits::ImageFormat::RGBA8,
bytes);
element.into());
}
let pixel_data = CanvasPixelData {

View file

@ -15,7 +15,7 @@ use webrender_traits;
enum WebGLPaintTaskData {
WebRender(webrender_traits::RenderApi, webrender_traits::WebGLContextId),
Servo(GLContext<NativeGLContext>),
Readback(GLContext<NativeGLContext>, (Option<(webrender_traits::RenderApi, webrender_traits::ImageKey)>)),
}
pub struct WebGLPaintThread {
@ -23,36 +23,56 @@ pub struct WebGLPaintThread {
data: WebGLPaintTaskData,
}
fn create_readback_painter(size: Size2D<i32>,
attrs: GLContextAttributes,
webrender_api: Option<webrender_traits::RenderApi>)
-> Result<(WebGLPaintThread, GLLimits), String> {
let context = try!(GLContext::<NativeGLContext>::new(size, attrs, ColorAttachmentType::Texture, None));
let limits = context.borrow_limits().clone();
let webrender_api_and_image_key = webrender_api.map(|wr| {
let key = wr.alloc_image();
(wr, key)
});
let painter = WebGLPaintThread {
size: size,
data: WebGLPaintTaskData::Readback(context, webrender_api_and_image_key)
};
Ok((painter, limits))
}
impl WebGLPaintThread {
fn new(size: Size2D<i32>,
attrs: GLContextAttributes,
webrender_api_sender: Option<webrender_traits::RenderApiSender>)
-> Result<(WebGLPaintThread, GLLimits), String> {
let (data, limits) = if let Some(sender) = webrender_api_sender {
let webrender_api = sender.create_api();
let (id, limits) = try!(webrender_api.request_webgl_context(&size, attrs));
(WebGLPaintTaskData::WebRender(webrender_api, id), limits)
if let Some(sender) = webrender_api_sender {
let wr_api = sender.create_api();
match wr_api.request_webgl_context(&size, attrs) {
Ok((id, limits)) => {
let painter = WebGLPaintThread {
data: WebGLPaintTaskData::WebRender(wr_api, id),
size: size
};
Ok((painter, limits))
},
Err(msg) => {
warn!("Initial context creation failed, falling back to readback: {}", msg);
create_readback_painter(size, attrs, Some(wr_api))
}
}
} else {
let context = try!(GLContext::<NativeGLContext>::new(size, attrs, ColorAttachmentType::Texture, None));
let limits = context.borrow_limits().clone();
(WebGLPaintTaskData::Servo(context), limits)
};
let painter_object = WebGLPaintThread {
size: size,
data: data,
};
Ok((painter_object, limits))
create_readback_painter(size, attrs, None)
}
}
pub fn handle_webgl_message(&self, message: webrender_traits::WebGLCommand) {
fn handle_webgl_message(&self, message: webrender_traits::WebGLCommand) {
debug!("WebGL message: {:?}", message);
match self.data {
WebGLPaintTaskData::WebRender(ref api, id) => {
api.send_webgl_command(id, message);
}
WebGLPaintTaskData::Servo(ref ctx) => {
WebGLPaintTaskData::Readback(ref ctx, _) => {
message.apply(ctx);
}
}
@ -104,7 +124,7 @@ impl WebGLPaintThread {
fn send_data(&mut self, chan: IpcSender<CanvasData>) {
match self.data {
WebGLPaintTaskData::Servo(_) => {
WebGLPaintTaskData::Readback(_, ref webrender_api_and_image_key) => {
let width = self.size.width as usize;
let height = self.size.height as usize;
@ -125,9 +145,19 @@ impl WebGLPaintThread {
// rgba -> bgra
byte_swap(&mut pixels);
if let Some((ref wr, wr_image_key)) = *webrender_api_and_image_key {
// TODO: This shouldn't be a common path, but try to avoid
// the spurious clone().
wr.update_image(wr_image_key,
width as u32,
height as u32,
webrender_traits::ImageFormat::RGBA8,
pixels.clone());
}
let pixel_data = CanvasPixelData {
image_data: IpcSharedMemory::from_bytes(&pixels[..]),
image_key: None,
image_key: webrender_api_and_image_key.as_ref().map(|&(_, key)| key),
};
chan.send(CanvasData::Pixels(pixel_data)).unwrap();
@ -141,7 +171,7 @@ impl WebGLPaintThread {
#[allow(unsafe_code)]
fn recreate(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
match self.data {
WebGLPaintTaskData::Servo(ref mut context) => {
WebGLPaintTaskData::Readback(ref mut context, _) => {
if size.width > self.size.width ||
size.height > self.size.height {
try!(context.resize(size));
@ -160,7 +190,7 @@ impl WebGLPaintThread {
}
fn init(&mut self) {
if let WebGLPaintTaskData::Servo(ref context) = self.data {
if let WebGLPaintTaskData::Readback(ref context, _) = self.data {
context.make_current().unwrap();
}
}