aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas/webgl_paint_task.rs
diff options
context:
space:
mode:
authorecoal95 <ecoal95@gmail.com>2015-04-21 09:16:48 +0200
committerecoal95 <ecoal95@gmail.com>2015-04-27 04:16:47 +0200
commit79a5dae1702916c724e7c9e08ead44a1b90cdedb (patch)
tree34216d0c75ff570ffbdf2d2699391e286a9e9225 /components/canvas/webgl_paint_task.rs
parentea00e949a45ca2e8842882b1b8a6ad7970890c00 (diff)
downloadservo-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.rs105
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();
+ }
}