mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
servo: Merge #5863 - Refactor WebGL implementation (reopens #5769) (from emilio:webgl-refactor); r=jdm
GitHub doesn't allow me to reopen #5769, so I created this. Sorry about the merge fail, my bad :/ cc/ @jdm @dmarcos --- This PR uses customized GL context creation code, right now only working under Linux, so I expect the clearcolor test to fail on other platforms. It addresses some other problems: * Propagates context creation error to the top, returning null if not found. * Uses GLContextAttributes, which will allow us to write WebGLContextAttributes easily. * Doesn't allow a 2d context and a WebGL context coexist. * Panics when resizing the context to larger dimensions (to be fixed soon, but better than blindly allowing it). Removes some unused dependencies Source-Repo: https://github.com/servo/servo Source-Revision: 9f2ad9376eaf598898387ea2c26f48c3ceb0330d
This commit is contained in:
parent
32cc0bb8fb
commit
086acefea5
@ -19,16 +19,16 @@ 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"
|
||||
|
||||
[dependencies.gfx]
|
||||
path = "../gfx"
|
||||
|
||||
[dependencies.glutin]
|
||||
git = "https://github.com/servo/glutin"
|
||||
branch = "servo"
|
||||
features = ["headless"]
|
||||
|
||||
[dependencies.offscreen_gl_context]
|
||||
git = "https://github.com/ecoal95/rust-offscreen-rendering-context"
|
||||
|
@ -5,6 +5,7 @@
|
||||
#![feature(collections)]
|
||||
#![feature(core)]
|
||||
#![feature(std_misc)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate azure;
|
||||
extern crate cssparser;
|
||||
@ -12,9 +13,12 @@ extern crate geom;
|
||||
extern crate gfx;
|
||||
extern crate util;
|
||||
extern crate gleam;
|
||||
extern crate msg;
|
||||
extern crate offscreen_gl_context;
|
||||
extern crate glutin;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
pub mod canvas_paint_task;
|
||||
pub mod webgl_paint_task;
|
||||
pub mod canvas_msg;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -169,24 +169,37 @@ impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> {
|
||||
|
||||
fn GetContext(self, id: DOMString) -> Option<CanvasRenderingContext2DOrWebGLRenderingContext> {
|
||||
match &*id {
|
||||
"2d" => {
|
||||
let context_2d = self.context_2d.or_init(|| {
|
||||
let window = window_from_node(self).root();
|
||||
let size = self.get_size();
|
||||
CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size)
|
||||
});
|
||||
Some(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D(Unrooted::from_temporary(context_2d)))
|
||||
}
|
||||
"webgl" | "experimental-webgl" => {
|
||||
let context_webgl = self.context_webgl.or_init(|| {
|
||||
let window = window_from_node(self).root();
|
||||
let size = self.get_size();
|
||||
WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size)
|
||||
});
|
||||
Some(CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext(Unrooted::from_temporary(context_webgl)))
|
||||
}
|
||||
_ => return None
|
||||
}
|
||||
"2d" => {
|
||||
if self.context_webgl.get().is_some() {
|
||||
debug!("Trying to get a 2d context for a canvas with an already initialized WebGL context");
|
||||
return None;
|
||||
}
|
||||
|
||||
let context_2d = self.context_2d.or_init(|| {
|
||||
let window = window_from_node(self).root();
|
||||
let size = self.get_size();
|
||||
CanvasRenderingContext2D::new(GlobalRef::Window(window.r()), self, size)
|
||||
});
|
||||
Some(CanvasRenderingContext2DOrWebGLRenderingContext::eCanvasRenderingContext2D(Unrooted::from_temporary(context_2d)))
|
||||
}
|
||||
"webgl" | "experimental-webgl" => {
|
||||
if self.context_2d.get().is_some() {
|
||||
debug!("Trying to get a WebGL context for a canvas with an already initialized 2d context");
|
||||
return None;
|
||||
}
|
||||
|
||||
if !self.context_webgl.get().is_some() {
|
||||
let window = window_from_node(self).root();
|
||||
let size = self.get_size();
|
||||
|
||||
self.context_webgl.assign(WebGLRenderingContext::new(GlobalRef::Window(window.r()), self, size))
|
||||
}
|
||||
|
||||
self.context_webgl.get().map( |ctx|
|
||||
CanvasRenderingContext2DOrWebGLRenderingContext::eWebGLRenderingContext(Unrooted::from_temporary(ctx)))
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,11 +239,11 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLCanvasElement> {
|
||||
let value = attr.value();
|
||||
let recreate = match attr.local_name() {
|
||||
&atom!("width") => {
|
||||
self.width.set(parse_unsigned_integer(value.chars()).unwrap_or(DEFAULT_WIDTH));
|
||||
self.width.set(parse_unsigned_integer(value.as_slice().chars()).unwrap_or(DEFAULT_WIDTH));
|
||||
true
|
||||
}
|
||||
&atom!("height") => {
|
||||
self.height.set(parse_unsigned_integer(value.chars()).unwrap_or(DEFAULT_HEIGHT));
|
||||
self.height.set(parse_unsigned_integer(value.as_slice().chars()).unwrap_or(DEFAULT_HEIGHT));
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
|
@ -23,25 +23,32 @@ pub struct WebGLRenderingContext {
|
||||
|
||||
impl WebGLRenderingContext {
|
||||
fn new_inherited(global: GlobalRef, canvas: JSRef<HTMLCanvasElement>, size: Size2D<i32>)
|
||||
-> WebGLRenderingContext {
|
||||
WebGLRenderingContext {
|
||||
-> Result<WebGLRenderingContext, &'static str> {
|
||||
let chan = try!(WebGLPaintTask::start(size));
|
||||
|
||||
Ok(WebGLRenderingContext {
|
||||
reflector_: Reflector::new(),
|
||||
global: GlobalField::from_rooted(&global),
|
||||
renderer: WebGLPaintTask::start(size),
|
||||
renderer: chan,
|
||||
canvas: JS::from_rooted(canvas),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(global: GlobalRef, canvas: JSRef<HTMLCanvasElement>, size: Size2D<i32>)
|
||||
-> Temporary<WebGLRenderingContext> {
|
||||
reflect_dom_object(box WebGLRenderingContext::new_inherited(global, canvas, size),
|
||||
global, WebGLRenderingContextBinding::Wrap)
|
||||
-> Option<Temporary<WebGLRenderingContext>> {
|
||||
match WebGLRenderingContext::new_inherited(global, canvas, size) {
|
||||
Ok(ctx) => Some(reflect_dom_object(box ctx, global,
|
||||
WebGLRenderingContextBinding::Wrap)),
|
||||
Err(msg) => {
|
||||
error!("Couldn't create WebGLRenderingContext: {}", msg);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recreate(&self, size: Size2D<i32>) {
|
||||
self.renderer.send(CanvasMsg::Common(CanvasCommonMsg::Recreate(size))).unwrap();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
@ -72,4 +79,3 @@ impl LayoutCanvasWebGLRenderingContextHelpers for LayoutJS<WebGLRenderingContext
|
||||
(*self.unsafe_get()).renderer.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* 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/. */
|
||||
|
||||
// https://www.whatwg.org/html/#htmlcanvaselement
|
||||
// https://www.whatwg.org/html/#htmlcanvaselement
|
||||
typedef (CanvasRenderingContext2D or WebGLRenderingContext) RenderingContext;
|
||||
|
||||
interface HTMLCanvasElement : HTMLElement {
|
||||
|
28
servo/components/servo/Cargo.lock
generated
28
servo/components/servo/Cargo.lock
generated
@ -34,7 +34,7 @@ version = "0.0.1"
|
||||
[[package]]
|
||||
name = "android_glue"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/tomaka/android-rs-glue#5a68056599fb498b0cf3715fd359894825e3b856"
|
||||
source = "git+https://github.com/tomaka/android-rs-glue#fa1eaa1d1857e0fa93832c5c8db5dc8bbcbc1eba"
|
||||
|
||||
[[package]]
|
||||
name = "azure"
|
||||
@ -67,7 +67,7 @@ dependencies = [
|
||||
"gfx 0.0.1",
|
||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
||||
"glutin 0.0.7 (git+https://github.com/servo/glutin?branch=servo)",
|
||||
"msg 0.0.1",
|
||||
"offscreen_gl_context 0.0.1 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
|
||||
"util 0.0.1",
|
||||
]
|
||||
|
||||
@ -318,7 +318,7 @@ name = "gdi32-sys"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -517,7 +517,7 @@ name = "kernel32-sys"
|
||||
version = "0.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -709,6 +709,19 @@ dependencies = [
|
||||
"util 0.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "offscreen_gl_context"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#9547d416019b15e0e59dc5176f5b1a14e14b44ca"
|
||||
dependencies = [
|
||||
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
||||
"glx 0.0.1 (git+https://github.com/servo/rust-glx)",
|
||||
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.5.1"
|
||||
@ -1000,7 +1013,7 @@ name = "user32-sys"
|
||||
version = "0.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1082,11 +1095,6 @@ dependencies = [
|
||||
"rustc-serialize 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.1.15"
|
||||
|
15
servo/ports/cef/Cargo.lock
generated
15
servo/ports/cef/Cargo.lock
generated
@ -65,7 +65,7 @@ dependencies = [
|
||||
"gfx 0.0.1",
|
||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
||||
"glutin 0.0.7 (git+https://github.com/servo/glutin?branch=servo)",
|
||||
"msg 0.0.1",
|
||||
"offscreen_gl_context 0.0.1 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
|
||||
"util 0.0.1",
|
||||
]
|
||||
|
||||
@ -687,6 +687,19 @@ dependencies = [
|
||||
"util 0.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "offscreen_gl_context"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#9547d416019b15e0e59dc5176f5b1a14e14b44ca"
|
||||
dependencies = [
|
||||
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
||||
"glx 0.0.1 (git+https://github.com/servo/rust-glx)",
|
||||
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.5.1"
|
||||
|
15
servo/ports/gonk/Cargo.lock
generated
15
servo/ports/gonk/Cargo.lock
generated
@ -59,7 +59,7 @@ dependencies = [
|
||||
"gfx 0.0.1",
|
||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
||||
"glutin 0.0.7 (git+https://github.com/servo/glutin?branch=servo)",
|
||||
"msg 0.0.1",
|
||||
"offscreen_gl_context 0.0.1 (git+https://github.com/ecoal95/rust-offscreen-rendering-context)",
|
||||
"util 0.0.1",
|
||||
]
|
||||
|
||||
@ -679,6 +679,19 @@ dependencies = [
|
||||
"malloc_buf 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "offscreen_gl_context"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/ecoal95/rust-offscreen-rendering-context#9547d416019b15e0e59dc5176f5b1a14e14b44ca"
|
||||
dependencies = [
|
||||
"cgl 0.0.1 (git+https://github.com/servo/rust-cgl)",
|
||||
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
|
||||
"gleam 0.0.1 (git+https://github.com/servo/gleam)",
|
||||
"glx 0.0.1 (git+https://github.com/servo/rust-glx)",
|
||||
"libc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.5.1"
|
||||
|
Loading…
Reference in New Issue
Block a user