mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
WebGL context hardware acceleration + error detection
This commit is contained in:
parent
ea00e949a4
commit
79a5dae170
10 changed files with 172 additions and 94 deletions
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue