Skip to content

Commit

Permalink
Improve WebGL architecture.
Browse files Browse the repository at this point in the history
  • Loading branch information
MortimerGoro committed Aug 15, 2017
1 parent e9cbbc5 commit 703962f
Show file tree
Hide file tree
Showing 54 changed files with 3,154 additions and 1,426 deletions.
11 changes: 7 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion components/canvas/Cargo.toml
Expand Up @@ -12,12 +12,13 @@ path = "lib.rs"
[dependencies]
azure = {git = "https://github.com/servo/rust-azure"}
canvas_traits = {path = "../canvas_traits"}
compositing = {path = "../compositing"}
cssparser = "0.19"
euclid = "0.15"
gleam = "0.4"
ipc-channel = "0.8"
log = "0.3.5"
num-traits = "0.1.32"
offscreen_gl_context = { version = "0.11", features = ["serde"] }
servo_config = {path = "../config"}
webrender = {git = "https://github.com/servo/webrender"}
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
16 changes: 5 additions & 11 deletions components/canvas/canvas_paint_thread.rs
Expand Up @@ -8,7 +8,7 @@ use azure::azure_hl::{BackendType, DrawOptions, DrawTarget, Pattern, StrokeOptio
use azure::azure_hl::{Color, ColorPattern, DrawSurfaceOptions, Filter, PathBuilder};
use azure::azure_hl::{ExtendMode, GradientStop, LinearGradientPattern, RadialGradientPattern};
use azure::azure_hl::SurfacePattern;
use canvas_traits::*;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::{Transform2D, Point2D, Vector2D, Rect, Size2D};
use ipc_channel::ipc::{self, IpcSender};
Expand Down Expand Up @@ -193,12 +193,8 @@ impl<'a> CanvasPaintThread<'a> {
Canvas2dMsg::SetShadowColor(ref color) => painter.set_shadow_color(color.to_azure_style()),
}
},
CanvasMsg::Common(message) => {
match message {
CanvasCommonMsg::Close => break,
CanvasCommonMsg::Recreate(size) => painter.recreate(size),
}
},
CanvasMsg::Close => break,
CanvasMsg::Recreate(size) => painter.recreate(size),
CanvasMsg::FromScript(message) => {
match message {
FromScriptMsg::SendPixels(chan) => {
Expand All @@ -213,8 +209,6 @@ impl<'a> CanvasPaintThread<'a> {
}
}
}
CanvasMsg::WebGL(_) => panic!("Wrong WebGL message sent to Canvas2D thread"),
CanvasMsg::WebVR(_) => panic!("Wrong WebVR message sent to Canvas2D thread"),
}
}
}).expect("Thread spawning failed");
Expand Down Expand Up @@ -571,7 +565,7 @@ impl<'a> CanvasPaintThread<'a> {
})
}

fn send_data(&mut self, chan: IpcSender<CanvasData>) {
fn send_data(&mut self, chan: IpcSender<CanvasImageData>) {
self.drawtarget.snapshot().get_data_surface().with_data(|element| {
let size = self.drawtarget.get_size();

Expand Down Expand Up @@ -614,7 +608,7 @@ impl<'a> CanvasPaintThread<'a> {
let data = CanvasImageData {
image_key: self.image_key.unwrap(),
};
chan.send(CanvasData::Image(data)).unwrap();
chan.send(data).unwrap();
})
}

Expand Down
203 changes: 203 additions & 0 deletions components/canvas/gl_context.rs
@@ -0,0 +1,203 @@
/* 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_traits::webgl::WebGLCommand;
use compositing::compositor_thread::{CompositorProxy, self};
use euclid::Size2D;
use gleam::gl;
use offscreen_gl_context::{ColorAttachmentType, GLContext, GLContextAttributes, GLContextDispatcher, GLLimits};
use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle, NativeGLContextMethods};
use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle};
use std::sync::{Arc, Mutex};
use super::webgl_thread::WebGLImpl;

/// The GLContextFactory is used to create shared GL contexts with the main thread GL context.
/// Currently, shared textures are used to render WebGL textures into the WR compositor.
/// In order to create a shared context, the GLContextFactory stores the handle of the main GL context.
pub enum GLContextFactory {
Native(NativeGLContextHandle, Option<MainThreadDispatcher>),
OSMesa(OSMesaContextHandle),
}

impl GLContextFactory {
/// Creates a new GLContextFactory that uses the currently bound GL context to create shared contexts.
pub fn current_native_handle(proxy: &CompositorProxy) -> Option<GLContextFactory> {
NativeGLContext::current_handle().map(|handle| {
if cfg!(target_os = "windows") {
// Used to dispatch functions from the GLContext thread to the main thread's event loop.
// Required to allow WGL GLContext sharing in Windows.
GLContextFactory::Native(handle, Some(MainThreadDispatcher::new(proxy.clone_compositor_proxy())))
} else {
GLContextFactory::Native(handle, None)
}
})
}

/// Creates a new GLContextFactory that uses the currently bound OSMesa context to create shared contexts.
pub fn current_osmesa_handle() -> Option<GLContextFactory> {
OSMesaContext::current_handle().map(GLContextFactory::OSMesa)
}

/// Creates a new shared GLContext with the main GLContext
pub fn new_shared_context(&self,
size: Size2D<i32>,
attributes: GLContextAttributes) -> Result<GLContextWrapper, &'static str> {
match *self {
GLContextFactory::Native(ref handle, ref dispatcher) => {
let dispatcher = dispatcher.as_ref().map(|d| Box::new(d.clone()) as Box<_>);
let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(handle),
dispatcher);
ctx.map(GLContextWrapper::Native)
}
GLContextFactory::OSMesa(ref handle) => {
let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(handle),
None);
ctx.map(GLContextWrapper::OSMesa)
}
}
}

/// Creates a new non-shared GLContext
pub fn new_context(&self,
size: Size2D<i32>,
attributes: GLContextAttributes) -> Result<GLContextWrapper, &'static str> {
match *self {
GLContextFactory::Native(..) => {
let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None,
None);
ctx.map(GLContextWrapper::Native)
}
GLContextFactory::OSMesa(_) => {
let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None,
None);
ctx.map(GLContextWrapper::OSMesa)
}
}
}
}


/// GLContextWrapper used to abstract NativeGLContext and OSMesaContext types
pub enum GLContextWrapper {
Native(GLContext<NativeGLContext>),
OSMesa(GLContext<OSMesaContext>),
}

impl GLContextWrapper {
pub fn make_current(&self) {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.make_current().unwrap();
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.make_current().unwrap();
}
}
}

pub fn unbind(&self) {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.unbind().unwrap();
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.unbind().unwrap();
}
}
}

pub fn apply_command(&self, cmd: WebGLCommand) {
match *self {
GLContextWrapper::Native(ref ctx) => {
WebGLImpl::apply(ctx, cmd);
}
GLContextWrapper::OSMesa(ref ctx) => {
WebGLImpl::apply(ctx, cmd);
}
}
}

pub fn gl(&self) -> &gl::Gl {
match *self {
GLContextWrapper::Native(ref ctx) => {
ctx.gl()
}
GLContextWrapper::OSMesa(ref ctx) => {
ctx.gl()
}
}
}

pub fn get_info(&self) -> (Size2D<i32>, u32, GLLimits) {
match *self {
GLContextWrapper::Native(ref ctx) => {
let (real_size, texture_id) = {
let draw_buffer = ctx.borrow_draw_buffer().unwrap();
(draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
};

let limits = ctx.borrow_limits().clone();

(real_size, texture_id, limits)
}
GLContextWrapper::OSMesa(ref ctx) => {
let (real_size, texture_id) = {
let draw_buffer = ctx.borrow_draw_buffer().unwrap();
(draw_buffer.size(), draw_buffer.get_bound_texture_id().unwrap())
};

let limits = ctx.borrow_limits().clone();

(real_size, texture_id, limits)
}
}
}

pub fn resize(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
match *self {
GLContextWrapper::Native(ref mut ctx) => {
ctx.resize(size)
}
GLContextWrapper::OSMesa(ref mut ctx) => {
ctx.resize(size)
}
}
}
}

/// Implements GLContextDispatcher to dispatch functions from GLContext threads to the main thread's event loop.
/// It's used in Windows to allow WGL GLContext sharing.
#[derive(Clone)]
pub struct MainThreadDispatcher {
compositor_proxy: Arc<Mutex<CompositorProxy>>
}

impl MainThreadDispatcher {
fn new(proxy: CompositorProxy) -> Self {
Self {
compositor_proxy: Arc::new(Mutex::new(proxy)),
}
}
}
impl GLContextDispatcher for MainThreadDispatcher {
fn dispatch(&self, f: Box<Fn() + Send>) {
self.compositor_proxy.lock().unwrap().send(compositor_thread::Msg::Dispatch(f));
}
}
10 changes: 6 additions & 4 deletions components/canvas/lib.rs
Expand Up @@ -6,16 +6,18 @@

extern crate azure;
extern crate canvas_traits;
extern crate compositing;
extern crate cssparser;
extern crate euclid;
extern crate gleam;
extern crate ipc_channel;
#[macro_use]
extern crate log;
#[macro_use] extern crate log;
extern crate num_traits;
extern crate offscreen_gl_context;
extern crate servo_config;
extern crate webrender;
extern crate webrender_api;

pub mod canvas_paint_thread;
pub mod webgl_paint_thread;
pub mod gl_context;
mod webgl_mode;
pub mod webgl_thread;

0 comments on commit 703962f

Please sign in to comment.