Kicks off a WebGL implementation

This commit is contained in:
Diego Marcos 2015-04-02 17:44:44 -07:00
parent b2585bee4d
commit c82485874d
23 changed files with 1326 additions and 165 deletions

View file

@ -16,6 +16,17 @@ git = "https://github.com/servo/rust-cssparser"
[dependencies.geom]
git = "https://github.com/servo/rust-geom"
[dependencies.gleam]
git = "https://github.com/servo/gleam"
[dependencies.glutin]
git = "https://github.com/servo/glutin"
branch = "servo"
features = ["headless"]
[dependencies.msg]
path = "../msg"
[dependencies.util]
path = "../util"

View file

@ -0,0 +1,61 @@
/* 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_paint_task::{FillOrStrokeStyle, LineCapStyle, LineJoinStyle};
use geom::matrix2d::Matrix2D;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use std::sync::mpsc::{Sender};
#[derive(Clone)]
pub enum CanvasMsg {
Canvas2d(Canvas2dMsg),
Common(CanvasCommonMsg),
WebGL(CanvasWebGLMsg),
}
#[derive(Clone)]
pub enum Canvas2dMsg {
Arc(Point2D<f32>, f32, f32, f32, bool),
ArcTo(Point2D<f32>, Point2D<f32>, f32),
DrawImage(Vec<u8>, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool),
BeginPath,
BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
ClosePath,
ClearRect(Rect<f32>),
Fill,
FillRect(Rect<f32>),
GetImageData(Rect<f64>, Size2D<f64>, Sender<Vec<u8>>),
LineTo(Point2D<f32>),
MoveTo(Point2D<f32>),
PutImageData(Vec<u8>, Rect<f64>, Option<Rect<f64>>),
QuadraticCurveTo(Point2D<f32>, Point2D<f32>),
RestoreContext,
SaveContext,
StrokeRect(Rect<f32>),
Stroke,
SetFillStyle(FillOrStrokeStyle),
SetStrokeStyle(FillOrStrokeStyle),
SetLineWidth(f32),
SetLineCap(LineCapStyle),
SetLineJoin(LineJoinStyle),
SetMiterLimit(f32),
SetGlobalAlpha(f32),
SetTransform(Matrix2D<f32>),
}
#[derive(Clone)]
pub enum CanvasWebGLMsg {
Clear(u32),
ClearColor(f32, f32, f32, f32),
}
#[derive(Clone)]
pub enum CanvasCommonMsg {
Close,
Recreate(Size2D<i32>),
SendPixelContents(Sender<Vec<u8>>),
}

View file

@ -6,6 +6,7 @@ use azure::azure::AzFloat;
use azure::azure_hl::{DrawTarget, SurfaceFormat, BackendType, StrokeOptions, DrawOptions, Pattern};
use azure::azure_hl::{ColorPattern, PathBuilder, JoinStyle, CapStyle, DrawSurfaceOptions, Filter};
use azure::azure_hl::{GradientStop, LinearGradientPattern, RadialGradientPattern, ExtendMode};
use canvas_msg::{CanvasMsg, Canvas2dMsg, CanvasCommonMsg};
use geom::matrix2d::Matrix2D;
use geom::point::Point2D;
use geom::rect::Rect;
@ -20,40 +21,6 @@ use std::mem;
use std::num::{Float, ToPrimitive};
use std::sync::mpsc::{channel, Sender};
#[derive(Clone)]
pub enum CanvasMsg {
SaveContext,
RestoreContext,
FillRect(Rect<f32>),
ClearRect(Rect<f32>),
StrokeRect(Rect<f32>),
BeginPath,
ClosePath,
Fill,
Stroke,
DrawImage(Vec<u8>, Size2D<f64>, Rect<f64>, Rect<f64>, bool),
DrawImageSelf(Size2D<f64>, Rect<f64>, Rect<f64>, bool),
MoveTo(Point2D<f32>),
LineTo(Point2D<f32>),
QuadraticCurveTo(Point2D<f32>, Point2D<f32>),
BezierCurveTo(Point2D<f32>, Point2D<f32>, Point2D<f32>),
Arc(Point2D<f32>, f32, f32, f32, bool),
ArcTo(Point2D<f32>, Point2D<f32>, f32),
SetFillStyle(FillOrStrokeStyle),
SetStrokeStyle(FillOrStrokeStyle),
SetLineWidth(f32),
SetLineCap(LineCapStyle),
SetLineJoin(LineJoinStyle),
SetMiterLimit(f32),
SetTransform(Matrix2D<f32>),
SetGlobalAlpha(f32),
Recreate(Size2D<i32>),
SendPixelContents(Sender<Vec<u8>>),
GetImageData(Rect<f64>, Size2D<f64>, Sender<Vec<u8>>),
PutImageData(Vec<u8>, Rect<f64>, Option<Rect<f64>>),
Close,
}
impl<'a> CanvasPaintTask<'a> {
/// It reads image data from the canvas
/// canvas_size: The size of the canvas we're reading from
@ -236,49 +203,59 @@ impl<'a> CanvasPaintTask<'a> {
loop {
match port.recv().unwrap() {
CanvasMsg::SaveContext => painter.save_context_state(),
CanvasMsg::RestoreContext => painter.restore_context_state(),
CanvasMsg::FillRect(ref rect) => painter.fill_rect(rect),
CanvasMsg::StrokeRect(ref rect) => painter.stroke_rect(rect),
CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect),
CanvasMsg::BeginPath => painter.begin_path(),
CanvasMsg::ClosePath => painter.close_path(),
CanvasMsg::Fill => painter.fill(),
CanvasMsg::Stroke => painter.stroke(),
CanvasMsg::DrawImage(imagedata, image_size, dest_rect, source_rect, smoothing_enabled) => {
painter.draw_image(imagedata, image_size, dest_rect, source_rect, smoothing_enabled)
}
CanvasMsg::DrawImageSelf(image_size, dest_rect, source_rect, smoothing_enabled) => {
painter.draw_image_self(image_size, dest_rect, source_rect, smoothing_enabled)
}
CanvasMsg::MoveTo(ref point) => painter.move_to(point),
CanvasMsg::LineTo(ref point) => painter.line_to(point),
CanvasMsg::QuadraticCurveTo(ref cp, ref pt) => {
painter.quadratic_curve_to(cp, pt)
}
CanvasMsg::BezierCurveTo(ref cp1, ref cp2, ref pt) => {
painter.bezier_curve_to(cp1, cp2, pt)
}
CanvasMsg::Arc(ref center, radius, start, end, ccw) => {
painter.arc(center, radius, start, end, ccw)
}
CanvasMsg::ArcTo(ref cp1, ref cp2, radius) => {
painter.arc_to(cp1, cp2, radius)
}
CanvasMsg::SetFillStyle(style) => painter.set_fill_style(style),
CanvasMsg::SetStrokeStyle(style) => painter.set_stroke_style(style),
CanvasMsg::SetLineWidth(width) => painter.set_line_width(width),
CanvasMsg::SetLineCap(cap) => painter.set_line_cap(cap),
CanvasMsg::SetLineJoin(join) => painter.set_line_join(join),
CanvasMsg::SetMiterLimit(limit) => painter.set_miter_limit(limit),
CanvasMsg::SetTransform(ref matrix) => painter.set_transform(matrix),
CanvasMsg::SetGlobalAlpha(alpha) => painter.set_global_alpha(alpha),
CanvasMsg::Recreate(size) => painter.recreate(size),
CanvasMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan),
CanvasMsg::GetImageData(dest_rect, canvas_size, chan) => painter.get_image_data(dest_rect, canvas_size, chan),
CanvasMsg::PutImageData(imagedata, image_data_rect, dirty_rect)
=> painter.put_image_data(imagedata, image_data_rect, dirty_rect),
CanvasMsg::Close => break,
CanvasMsg::Canvas2d(message) => {
match message {
Canvas2dMsg::FillRect(ref rect) => painter.fill_rect(rect),
Canvas2dMsg::StrokeRect(ref rect) => painter.stroke_rect(rect),
Canvas2dMsg::ClearRect(ref rect) => painter.clear_rect(rect),
Canvas2dMsg::BeginPath => painter.begin_path(),
Canvas2dMsg::ClosePath => painter.close_path(),
Canvas2dMsg::Fill => painter.fill(),
Canvas2dMsg::Stroke => painter.stroke(),
Canvas2dMsg::DrawImage(imagedata, image_size, dest_rect, source_rect, smoothing_enabled) => {
painter.draw_image(imagedata, image_size, dest_rect, source_rect, smoothing_enabled)
}
Canvas2dMsg::DrawImageSelf(image_size, dest_rect, source_rect, smoothing_enabled) => {
painter.draw_image_self(image_size, dest_rect, source_rect, smoothing_enabled)
}
Canvas2dMsg::MoveTo(ref point) => painter.move_to(point),
Canvas2dMsg::LineTo(ref point) => painter.line_to(point),
Canvas2dMsg::QuadraticCurveTo(ref cp, ref pt) => {
painter.quadratic_curve_to(cp, pt)
}
Canvas2dMsg::BezierCurveTo(ref cp1, ref cp2, ref pt) => {
painter.bezier_curve_to(cp1, cp2, pt)
}
Canvas2dMsg::Arc(ref center, radius, start, end, ccw) => {
painter.arc(center, radius, start, end, ccw)
}
Canvas2dMsg::ArcTo(ref cp1, ref cp2, radius) => {
painter.arc_to(cp1, cp2, radius)
}
Canvas2dMsg::RestoreContext => painter.restore_context_state(),
Canvas2dMsg::SaveContext => painter.save_context_state(),
Canvas2dMsg::SetFillStyle(style) => painter.set_fill_style(style),
Canvas2dMsg::SetStrokeStyle(style) => painter.set_stroke_style(style),
Canvas2dMsg::SetLineWidth(width) => painter.set_line_width(width),
Canvas2dMsg::SetLineCap(cap) => painter.set_line_cap(cap),
Canvas2dMsg::SetLineJoin(join) => painter.set_line_join(join),
Canvas2dMsg::SetMiterLimit(limit) => painter.set_miter_limit(limit),
Canvas2dMsg::SetTransform(ref matrix) => painter.set_transform(matrix),
Canvas2dMsg::SetGlobalAlpha(alpha) => painter.set_global_alpha(alpha),
Canvas2dMsg::GetImageData(dest_rect, canvas_size, chan) => painter.get_image_data(dest_rect, canvas_size, chan),
Canvas2dMsg::PutImageData(imagedata, image_data_rect, dirty_rect)
=> painter.put_image_data(imagedata, image_data_rect, dirty_rect),
}
},
CanvasMsg::Common(message) => {
match message {
CanvasCommonMsg::Close => break,
CanvasCommonMsg::Recreate(size) => painter.recreate(size),
CanvasCommonMsg::SendPixelContents(chan) =>
painter.send_pixel_contents(chan),
}
},
CanvasMsg::WebGL(_) => panic!("Wrong message sent to Canvas2D task"),
}
}
});

View file

@ -11,6 +11,10 @@ extern crate cssparser;
extern crate geom;
extern crate gfx;
extern crate util;
extern crate gleam;
extern crate msg;
extern crate glutin;
pub mod canvas_paint_task;
pub mod webgl_paint_task;
pub mod canvas_msg;

View file

@ -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();
}
}