mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Kicks off a WebGL implementation
This commit is contained in:
parent
b2585bee4d
commit
c82485874d
23 changed files with 1326 additions and 165 deletions
|
@ -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"
|
||||
|
||||
|
|
61
components/canvas/canvas_msg.rs
Normal file
61
components/canvas/canvas_msg.rs
Normal 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>>),
|
||||
}
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
112
components/canvas/webgl_paint_task.rs
Normal file
112
components/canvas/webgl_paint_task.rs
Normal 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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue