aboutsummaryrefslogtreecommitdiffstats
path: root/components/canvas/webgl_paint_thread.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/canvas/webgl_paint_thread.rs')
-rw-r--r--components/canvas/webgl_paint_thread.rs379
1 files changed, 0 insertions, 379 deletions
diff --git a/components/canvas/webgl_paint_thread.rs b/components/canvas/webgl_paint_thread.rs
deleted file mode 100644
index 2b6819effba..00000000000
--- a/components/canvas/webgl_paint_thread.rs
+++ /dev/null
@@ -1,379 +0,0 @@
-/* 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::{CanvasCommonMsg, CanvasData, CanvasMsg, CanvasImageData};
-use canvas_traits::{FromLayoutMsg, FromScriptMsg, byte_swap};
-use euclid::Size2D;
-use gleam::gl;
-use ipc_channel::ipc::{self, IpcSender};
-use offscreen_gl_context::{ColorAttachmentType, GLContext, GLLimits};
-use offscreen_gl_context::{GLContextAttributes, NativeGLContext, OSMesaContext};
-use servo_config::opts;
-use std::borrow::ToOwned;
-use std::mem;
-use std::sync::Arc;
-use std::sync::mpsc::channel;
-use std::thread;
-use webrender_api;
-
-enum GLContextWrapper {
- Native(GLContext<NativeGLContext>),
- OSMesa(GLContext<OSMesaContext>),
-}
-
-impl GLContextWrapper {
- fn new(size: Size2D<i32>,
- attributes: GLContextAttributes,
- gl_type: gl::GlType) -> Result<GLContextWrapper, &'static str> {
- if opts::get().should_use_osmesa() {
- let ctx = GLContext::<OSMesaContext>::new(size,
- attributes,
- ColorAttachmentType::Texture,
- gl_type,
- None);
- ctx.map(GLContextWrapper::OSMesa)
- } else {
- let ctx = GLContext::<NativeGLContext>::new(size,
- attributes,
- ColorAttachmentType::Texture,
- gl_type,
- None);
- ctx.map(GLContextWrapper::Native)
- }
- }
-
- pub fn get_limits(&self) -> GLLimits {
- match *self {
- GLContextWrapper::Native(ref ctx) => {
- ctx.borrow_limits().clone()
- }
- GLContextWrapper::OSMesa(ref ctx) => {
- ctx.borrow_limits().clone()
- }
- }
- }
-
- fn resize(&mut self, size: Size2D<i32>) -> Result<Size2D<i32>, &'static str> {
- match *self {
- GLContextWrapper::Native(ref mut ctx) => {
- ctx.resize(size)?;
- Ok(ctx.borrow_draw_buffer().unwrap().size())
- }
- GLContextWrapper::OSMesa(ref mut ctx) => {
- ctx.resize(size)?;
- Ok(ctx.borrow_draw_buffer().unwrap().size())
- }
- }
- }
-
- fn gl(&self) -> &gl::Gl {
- match *self {
- GLContextWrapper::Native(ref ctx) => {
- ctx.gl()
- }
- GLContextWrapper::OSMesa(ref ctx) => {
- ctx.gl()
- }
- }
- }
-
- 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 apply_command(&self, cmd: webrender_api::WebGLCommand) {
- match *self {
- GLContextWrapper::Native(ref ctx) => {
- cmd.apply(ctx);
- }
- GLContextWrapper::OSMesa(ref ctx) => {
- cmd.apply(ctx);
- }
- }
- }
-}
-
-enum WebGLPaintTaskData {
- WebRender(webrender_api::RenderApi, webrender_api::WebGLContextId),
- Readback {
- context: GLContextWrapper,
- webrender_api: webrender_api::RenderApi,
- image_key: Option<webrender_api::ImageKey>,
- /// An old webrender image key that can be deleted when the next epoch ends.
- old_image_key: Option<webrender_api::ImageKey>,
- /// An old webrender image key that can be deleted when the current epoch ends.
- very_old_image_key: Option<webrender_api::ImageKey>,
- },
-}
-
-pub struct WebGLPaintThread {
- size: Size2D<i32>,
- data: WebGLPaintTaskData,
-}
-
-fn create_readback_painter(size: Size2D<i32>,
- attrs: GLContextAttributes,
- webrender_api: webrender_api::RenderApi,
- gl_type: gl::GlType)
- -> Result<(WebGLPaintThread, GLLimits), String> {
- let context = GLContextWrapper::new(size, attrs, gl_type)?;
- let limits = context.get_limits();
- let painter = WebGLPaintThread {
- size: size,
- data: WebGLPaintTaskData::Readback {
- context: context,
- webrender_api: webrender_api,
- image_key: None,
- old_image_key: None,
- very_old_image_key: None,
- },
- };
-
- Ok((painter, limits))
-}
-
-impl WebGLPaintThread {
- fn new(size: Size2D<i32>,
- attrs: GLContextAttributes,
- webrender_api_sender: webrender_api::RenderApiSender,
- gl_type: gl::GlType)
- -> Result<(WebGLPaintThread, GLLimits), String> {
- let wr_api = webrender_api_sender.create_api();
- let device_size = webrender_api::DeviceIntSize::from_untyped(&size);
- match wr_api.request_webgl_context(&device_size, attrs) {
- Ok((id, limits)) => {
- let painter = WebGLPaintThread {
- data: WebGLPaintTaskData::WebRender(wr_api, id),
- size: size
- };
- Ok((painter, limits))
- },
- Err(msg) => {
- warn!("Initial context creation failed, falling back to readback: {}", msg);
- create_readback_painter(size, attrs, wr_api, gl_type)
- }
- }
- }
-
- fn handle_webgl_message(&self, message: webrender_api::WebGLCommand) {
- debug!("WebGL message: {:?}", message);
- match self.data {
- WebGLPaintTaskData::WebRender(ref api, id) => {
- api.send_webgl_command(id, message);
- }
- WebGLPaintTaskData::Readback { ref context, .. } => {
- context.apply_command(message);
- }
- }
- }
-
- fn handle_webvr_message(&self, message: webrender_api::VRCompositorCommand) {
- match self.data {
- WebGLPaintTaskData::WebRender(ref api, id) => {
- api.send_vr_compositor_command(id, message);
- }
- WebGLPaintTaskData::Readback { .. } => {
- error!("Webrender is required for WebVR implementation");
- }
- }
- }
-
-
- /// Creates a new `WebGLPaintThread` and returns an `IpcSender` to
- /// communicate with it.
- pub fn start(size: Size2D<i32>,
- attrs: GLContextAttributes,
- webrender_api_sender: webrender_api::RenderApiSender)
- -> Result<(IpcSender<CanvasMsg>, GLLimits), String> {
- let (sender, receiver) = ipc::channel::<CanvasMsg>().unwrap();
- let (result_chan, result_port) = channel();
- thread::Builder::new().name("WebGLThread".to_owned()).spawn(move || {
- let gl_type = gl::GlType::default();
- let mut painter = match WebGLPaintThread::new(size, attrs, webrender_api_sender, gl_type) {
- Ok((thread, limits)) => {
- result_chan.send(Ok(limits)).unwrap();
- thread
- },
- Err(e) => {
- result_chan.send(Err(e)).unwrap();
- return
- }
- };
- painter.init();
- loop {
- match receiver.recv().unwrap() {
- CanvasMsg::WebGL(message) => painter.handle_webgl_message(message),
- CanvasMsg::Common(message) => {
- match message {
- CanvasCommonMsg::Close => break,
- // TODO(emilio): handle error nicely
- CanvasCommonMsg::Recreate(size) => painter.recreate(size).unwrap(),
- }
- },
- CanvasMsg::FromScript(message) => {
- match message {
- FromScriptMsg::SendPixels(chan) =>{
- // Read the comment on
- // HTMLCanvasElement::fetch_all_data.
- chan.send(None).unwrap();
- }
- }
- }
- CanvasMsg::FromLayout(message) => {
- match message {
- FromLayoutMsg::SendData(chan) =>
- painter.send_data(chan),
- }
- }
- CanvasMsg::Canvas2d(_) => panic!("Wrong message sent to WebGLThread"),
- CanvasMsg::WebVR(message) => painter.handle_webvr_message(message)
- }
- }
- }).expect("Thread spawning failed");
-
- result_port.recv().unwrap().map(|limits| (sender, limits))
- }
-
- fn send_data(&mut self, chan: IpcSender<CanvasData>) {
- match self.data {
- WebGLPaintTaskData::Readback {
- ref context,
- ref webrender_api,
- ref mut image_key,
- ref mut old_image_key,
- ref mut very_old_image_key,
- } => {
- let width = self.size.width as usize;
- let height = self.size.height as usize;
-
- let mut pixels = context.gl().read_pixels(0, 0,
- self.size.width as gl::GLsizei,
- self.size.height as gl::GLsizei,
- gl::RGBA, gl::UNSIGNED_BYTE);
- // flip image vertically (texture is upside down)
- let orig_pixels = pixels.clone();
- let stride = width * 4;
- for y in 0..height {
- let dst_start = y * stride;
- let src_start = (height - y - 1) * stride;
- let src_slice = &orig_pixels[src_start .. src_start + stride];
- (&mut pixels[dst_start .. dst_start + stride]).clone_from_slice(&src_slice[..stride]);
- }
-
- // rgba -> bgra
- byte_swap(&mut pixels);
-
- let descriptor = webrender_api::ImageDescriptor {
- width: width as u32,
- height: height as u32,
- stride: None,
- format: webrender_api::ImageFormat::BGRA8,
- offset: 0,
- is_opaque: false,
- };
- let data = webrender_api::ImageData::Raw(Arc::new(pixels));
-
- let mut updates = webrender_api::ResourceUpdates::new();
-
- match *image_key {
- Some(image_key) => {
- updates.update_image(image_key,
- descriptor,
- data,
- None);
- }
- None => {
- *image_key = Some(webrender_api.generate_image_key());
- updates.add_image(image_key.unwrap(),
- descriptor,
- data,
- None);
- }
- }
-
- if let Some(image_key) = mem::replace(very_old_image_key, old_image_key.take()) {
- updates.delete_image(image_key);
- }
-
- webrender_api.update_resources(updates);
-
- let image_data = CanvasImageData {
- image_key: image_key.unwrap(),
- };
-
- chan.send(CanvasData::Image(image_data)).unwrap();
- }
- WebGLPaintTaskData::WebRender(_, id) => {
- chan.send(CanvasData::WebGL(id)).unwrap();
- }
- }
- }
-
- #[allow(unsafe_code)]
- fn recreate(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
- match self.data {
- WebGLPaintTaskData::Readback { ref mut context, ref mut image_key, ref mut old_image_key, .. } => {
- if size.width > self.size.width ||
- size.height > self.size.height {
- self.size = context.resize(size)?;
- } else {
- self.size = size;
- context.gl().scissor(0, 0, size.width, size.height);
- }
- // Webrender doesn't let images change size, so we clear the webrender image key.
- if let Some(image_key) = image_key.take() {
- // If this executes, then we are in a new epoch since we last recreated the canvas,
- // so `old_image_key` must be `None`.
- debug_assert!(old_image_key.is_none());
- *old_image_key = Some(image_key);
- }
- }
- WebGLPaintTaskData::WebRender(ref api, id) => {
- let device_size = webrender_api::DeviceIntSize::from_untyped(&size);
- api.resize_webgl_context(id, &device_size);
- }
- }
-
- Ok(())
- }
-
- fn init(&mut self) {
- if let WebGLPaintTaskData::Readback { ref context, .. } = self.data {
- context.make_current();
- }
- }
-}
-
-impl Drop for WebGLPaintThread {
- fn drop(&mut self) {
- if let WebGLPaintTaskData::Readback {
- ref mut webrender_api,
- image_key,
- old_image_key,
- very_old_image_key,
- ..
- } = self.data {
- let mut updates = webrender_api::ResourceUpdates::new();
-
- if let Some(image_key) = image_key {
- updates.delete_image(image_key);
- }
- if let Some(image_key) = old_image_key {
- updates.delete_image(image_key);
- }
- if let Some(image_key) = very_old_image_key {
- updates.delete_image(image_key);
- }
-
- webrender_api.update_resources(updates);
- }
- }
-}