diff options
author | ecoal95 <ecoal95@gmail.com> | 2015-04-21 09:16:48 +0200 |
---|---|---|
committer | ecoal95 <ecoal95@gmail.com> | 2015-04-27 04:16:47 +0200 |
commit | 79a5dae1702916c724e7c9e08ead44a1b90cdedb (patch) | |
tree | 34216d0c75ff570ffbdf2d2699391e286a9e9225 /components/canvas/webgl_paint_task.rs | |
parent | ea00e949a45ca2e8842882b1b8a6ad7970890c00 (diff) | |
download | servo-79a5dae1702916c724e7c9e08ead44a1b90cdedb.tar.gz servo-79a5dae1702916c724e7c9e08ead44a1b90cdedb.zip |
WebGL context hardware acceleration + error detection
Diffstat (limited to 'components/canvas/webgl_paint_task.rs')
-rw-r--r-- | components/canvas/webgl_paint_task.rs | 105 |
1 files changed, 63 insertions, 42 deletions
diff --git a/components/canvas/webgl_paint_task.rs b/components/canvas/webgl_paint_task.rs index eaa224c22b3..97e711b6718 100644 --- a/components/canvas/webgl_paint_task.rs +++ b/components/canvas/webgl_paint_task.rs @@ -2,36 +2,73 @@ * 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 canvas_msg::{CanvasWebGLMsg, CanvasCommonMsg, CanvasMsg}; +use canvas_msg::{CanvasMsg, CanvasWebGLMsg, CanvasCommonMsg}; use geom::size::Size2D; use gleam::gl; -use gleam::gl::types::{GLint, GLsizei}; +use gleam::gl::types::{GLsizei}; use util::task::spawn_named; use std::borrow::ToOwned; use std::sync::mpsc::{channel, Sender}; use util::vec::byte_swap; +use offscreen_gl_context::{GLContext, GLContextAttributes}; -use glutin::{HeadlessRendererBuilder}; +use glutin::{HeadlessRendererBuilder, HeadlessContext}; + +// FIXME(ecoal95): We use glutin as a fallback until GLContext support improves. +enum PlatformIndependentContext { + GLContext(GLContext), + GlutinContext(HeadlessContext), +} + +impl PlatformIndependentContext { + fn make_current(&self) { + match *self { + PlatformIndependentContext::GLContext(ref ctx) => ctx.make_current().unwrap(), + PlatformIndependentContext::GlutinContext(ref ctx) => unsafe { ctx.make_current() } + } + } +} + +fn create_offscreen_context(size: Size2D<i32>, attrs: GLContextAttributes) -> Result<PlatformIndependentContext, &'static str> { + match GLContext::create_offscreen(size, attrs) { + Ok(ctx) => Ok(PlatformIndependentContext::GLContext(ctx)), + Err(msg) => { + debug!("GLContext creation error: {}", msg); + match HeadlessRendererBuilder::new(size.width as u32, size.height as u32).build() { + Ok(ctx) => Ok(PlatformIndependentContext::GlutinContext(ctx)), + Err(_) => Err("Glutin headless context creation failed") + } + } + } +} pub struct WebGLPaintTask { size: Size2D<i32>, + original_context_size: Size2D<i32>, + gl_context: PlatformIndependentContext, } +// This allows trying to create the PaintTask +// before creating the thread +unsafe impl Send for WebGLPaintTask {} + impl WebGLPaintTask { - fn new(size: Size2D<i32>) -> WebGLPaintTask { - WebGLPaintTask::create(size); - WebGLPaintTask { + fn new(size: Size2D<i32>) -> Result<WebGLPaintTask, &'static str> { + let context = try!(create_offscreen_context(size, GLContextAttributes::default())); + Ok(WebGLPaintTask { size: size, - } + original_context_size: size, + gl_context: context + }) } - pub fn start(size: Size2D<i32>) -> Sender<CanvasMsg> { + pub fn start(size: Size2D<i32>) -> Result<Sender<CanvasMsg>, &'static str> { let (chan, port) = channel::<CanvasMsg>(); + let mut painter = try!(WebGLPaintTask::new(size)); spawn_named("WebGLTask".to_owned(), move || { - let mut painter = WebGLPaintTask::new(size); painter.init(); loop { match port.recv().unwrap() { @@ -52,35 +89,8 @@ impl WebGLPaintTask { } } }); - chan - } - fn create(size: Size2D<i32>) { - // It creates OpenGL context - let context = HeadlessRendererBuilder::new(size.width as u32, size.height as u32).build().unwrap(); - unsafe { - context.make_current(); - } - } - - fn init(&self) { - let framebuffer_ids = gl::gen_framebuffers(1); - gl::bind_framebuffer(gl::FRAMEBUFFER, framebuffer_ids[0]); - - let texture_ids = gl::gen_textures(1); - gl::bind_texture(gl::TEXTURE_2D, texture_ids[0]); - - gl::tex_image_2d(gl::TEXTURE_2D, 0, gl::RGB as GLint, self.size.width as GLsizei, - self.size.height as GLsizei, 0, gl::RGB, gl::UNSIGNED_BYTE, None); - gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); - gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); - - gl::framebuffer_texture_2d(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, - texture_ids[0], 0); - gl::bind_texture(gl::TEXTURE_2D, 0); - - gl::viewport(0 as GLint, 0 as GLint, - self.size.width as GLsizei, self.size.height as GLsizei); + Ok(chan) } fn clear(&self, mask: u32) { @@ -95,9 +105,9 @@ impl WebGLPaintTask { // FIXME(#5652, dmarcos) Instead of a readback strategy we have // to layerize the canvas let mut pixels = gl::read_pixels(0, 0, - self.size.width as gl::GLsizei, - self.size.height as gl::GLsizei, - gl::RGBA, gl::UNSIGNED_BYTE); + self.size.width as gl::GLsizei, + self.size.height as gl::GLsizei, + gl::RGBA, gl::UNSIGNED_BYTE); // rgba -> bgra byte_swap(&mut pixels); @@ -105,8 +115,19 @@ impl WebGLPaintTask { } fn recreate(&mut self, size: Size2D<i32>) { - self.size = size; - self.init(); + // TODO(ecoal95): GLContext should support a resize() method + if size.width > self.original_context_size.width || + size.height > self.original_context_size.height { + panic!("Can't grow a GLContext (yet)"); + } else { + // Right now we just crop the viewport, it will do the job + self.size = size; + gl::viewport(0, 0, size.width, size.height); + unsafe { gl::Scissor(0, 0, size.width, size.height); } + } } + fn init(&mut self) { + self.gl_context.make_current(); + } } |