aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas/webgl_paint_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/canvas/webgl_paint_task.rs')
-rw-r--r--components/canvas/webgl_paint_task.rs112
1 files changed, 112 insertions, 0 deletions
diff --git a/components/canvas/webgl_paint_task.rs b/components/canvas/webgl_paint_task.rs
new file mode 100644
index 00000000000..1afcf20089c
--- /dev/null
+++ b/components/canvas/webgl_paint_task.rs
@@ -0,0 +1,112 @@
+/* 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 canvas_msg::{CanvasWebGLMsg, CanvasCommonMsg, CanvasMsg};
+use geom::size::Size2D;
+
+use gleam::gl;
+use gleam::gl::types::{GLint, GLsizei};
+
+use util::task::spawn_named;
+
+use std::borrow::ToOwned;
+use std::sync::mpsc::{channel, Sender};
+use util::vec::byte_swap;
+
+use glutin::{HeadlessRendererBuilder};
+
+pub struct WebGLPaintTask {
+ size: Size2D<i32>,
+}
+
+impl WebGLPaintTask {
+ fn new(size: Size2D<i32>) -> WebGLPaintTask {
+ WebGLPaintTask::create(size);
+ WebGLPaintTask {
+ size: size,
+ }
+ }
+
+ pub fn start(size: Size2D<i32>) -> Sender<CanvasMsg> {
+ let (chan, port) = channel::<CanvasMsg>();
+ spawn_named("WebGLTask".to_owned(), move || {
+ let mut painter = WebGLPaintTask::new(size);
+ painter.init();
+ loop {
+ match port.recv().unwrap() {
+ CanvasMsg::WebGL(message) => {
+ match message {
+ CanvasWebGLMsg::Clear(mask) => painter.clear(mask),
+ CanvasWebGLMsg::ClearColor(r, g, b, a) => painter.clear_color(r, g, b, a),
+ }
+ },
+ CanvasMsg::Common(message) => {
+ match message {
+ CanvasCommonMsg::Close => break,
+ CanvasCommonMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan),
+ CanvasCommonMsg::Recreate(size) => painter.recreate(size),
+ }
+ },
+ CanvasMsg::Canvas2d(_) => panic!("Wrong message sent to WebGLTask"),
+ }
+ }
+ });
+ 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);
+ }
+
+ fn clear(&self, mask: u32) {
+ gl::clear(mask);
+ }
+
+ fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
+ gl::clear_color(r, g, b, a);
+ }
+
+ fn send_pixel_contents(&mut self, chan: Sender<Vec<u8>>) {
+ // 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);
+
+ // rgba -> bgra
+ byte_swap(pixels.as_mut_slice());
+ chan.send(pixels).unwrap();
+ }
+
+ fn recreate(&mut self, size: Size2D<i32>) {
+ self.size = size;
+ self.init();
+ }
+
+}