diff --git a/Cargo.toml b/Cargo.toml index 735fa42..3767b3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "layers" -version = "0.1.0" +version = "0.1.1" authors = ["The Servo Project Developers"] [features] @@ -58,3 +58,15 @@ features = ["xlib"] [target.arm-linux-androideabi.dependencies.egl] git = "https://github.com/servo/rust-egl" + +[target.i686-unknown-linux-gnu.dependencies.egl] +git = "https://github.com/servo/rust-egl" + +[target.x86_64-unknown-linux-gnu.dependencies.egl] +git = "https://github.com/servo/rust-egl" + +[target.arm-unknown-linux-gnueabihf.dependencies.egl] +git = "https://github.com/servo/rust-egl" + +[target.aarch64-unknown-linux-gnu.dependencies.egl] +git = "https://github.com/servo/rust-egl" diff --git a/src/lib.rs b/src/lib.rs index 83b37af..e9dc618 100755 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,7 +37,7 @@ extern crate x11; #[cfg(target_os="linux")] extern crate glx; -#[cfg(target_os="android")] +#[cfg(any(target_os = "linux", target_os = "android"))] extern crate egl; pub mod color; @@ -62,10 +62,13 @@ pub mod platform { pub mod android { pub mod surface; } + #[cfg(any(target_os="android",target_os="linux"))] + pub mod egl { + pub mod surface; + } #[cfg(target_os="windows")] pub mod windows { pub mod surface; } pub mod surface; } - diff --git a/src/platform/egl/surface.rs b/src/platform/egl/surface.rs new file mode 100644 index 0000000..cb691c6 --- /dev/null +++ b/src/platform/egl/surface.rs @@ -0,0 +1,142 @@ +// Copyright 2015 The Servo Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementation of cross-process surfaces implementing EGL surface. + +use texturegl::Texture; + +use egl::egl::{EGLDisplay, GetCurrentDisplay}; +use egl::eglext::{EGLImageKHR, DestroyImageKHR}; +use euclid::size::Size2D; +use gleam::gl::{TEXTURE_2D, TexImage2D, BGRA, UNSIGNED_BYTE}; +use libc::c_void; +use skia::gl_context::{GLContext, PlatformDisplayData}; +use skia::gl_rasterization_context::GLRasterizationContext; +use std::iter::repeat; +use std::mem; +use std::sync::Arc; +use std::vec::Vec; + +use gleam::gl; + +#[cfg(target_os = "linux")] +const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA; + +#[cfg(any(target_os = "android", target_os = "gonk"))] +const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA_EXT; + +#[cfg(target_os="linux")] +pub use platform::linux::surface::NativeDisplay; + +#[cfg(target_os="android")] +pub use platform::android::surface::NativeDisplay; + +pub struct EGLImageNativeSurface { + /// An EGLImage for the case of GPU rendering. + image: Option, + + /// A heap-allocated bitmap for the case of CPU rendering. + bitmap: Option>, + + /// Whether this pixmap will leak if the destructor runs. This is for debugging purposes. + will_leak: bool, + + /// The size of this surface. + pub size: Size2D, +} + +unsafe impl Send for EGLImageNativeSurface {} + +impl EGLImageNativeSurface { + pub fn new(_: &NativeDisplay, size: Size2D) -> EGLImageNativeSurface { + let len = size.width * size.height * 4; + let bitmap: Vec = repeat(0).take(len as usize).collect(); + + EGLImageNativeSurface { + image: None, + bitmap: Some(bitmap), + will_leak: true, + size: size, + } + } + + /// This may only be called on the compositor side. + pub fn bind_to_texture(&self, _: &NativeDisplay, texture: &Texture) { + let _bound = texture.bind(); + match self.image { + None => match self.bitmap { + Some(ref bitmap) => { + let data = bitmap.as_ptr() as *const c_void; + unsafe { + TexImage2D(TEXTURE_2D, + 0, + GL_FORMAT_BGRA as i32, + self.size.width as i32, + self.size.height as i32, + 0, + GL_FORMAT_BGRA as u32, + UNSIGNED_BYTE, + data); + } + } + None => { + debug!("Cannot bind the buffer(CPU rendering), there is no bitmap"); + } + }, + Some(image_khr) => { + panic!("TODO: Support GPU rasterizer path on EGL"); + } + } + } + + /// This may only be called on the painting side. + pub fn upload(&mut self, _: &NativeDisplay, data: &[u8]) { + match self.bitmap { + Some(ref mut bitmap) => { + bitmap.clear(); + bitmap.push_all(data); + } + None => { + debug!("Cannot upload the buffer(CPU rendering), there is no bitmap"); + } + } + } + + pub fn get_id(&self) -> isize { + match self.image { + None => 0, + Some(image_khr) => image_khr as isize, + } + } + + pub fn destroy(&mut self, graphics_context: &NativeDisplay) { + match self.image { + None => {}, + Some(image_khr) => { + panic!("TODO: Support GPU rendering path on Android"); + mem::replace(&mut self.image, None); + } + } + self.mark_wont_leak() + } + + pub fn mark_will_leak(&mut self) { + self.will_leak = true + } + + pub fn mark_wont_leak(&mut self) { + self.will_leak = false + } + + pub fn gl_rasterization_context(&mut self, + gl_context: Arc) + -> Option { + panic!("TODO: Support GL context on EGL"); + } +} diff --git a/src/platform/linux/surface.rs b/src/platform/linux/surface.rs index bb4a215..e1e2b05 100644 --- a/src/platform/linux/surface.rs +++ b/src/platform/linux/surface.rs @@ -11,6 +11,10 @@ #![allow(non_snake_case)] +//TODO: Linking EGL here is probably wrong - should it be done in gleam / glutin etc? +#[link(name = "EGL")] +extern {} + use texturegl::Texture; use euclid::size::Size2D; @@ -26,6 +30,8 @@ use std::str; use std::sync::Arc; use x11::xlib; +use egl::egl::{EGLDisplay, GetCurrentDisplay}; + /// The display, visual info, and framebuffer configuration. This is needed in order to bind to a /// texture on the compositor side. This holds only a *weak* reference to the display and does not /// close it. @@ -34,12 +40,25 @@ use x11::xlib; /// to fix because the Display is given to us by the native windowing system, but we should fix it /// someday. /// FIXME(pcwalton): Mark nonsendable. + #[derive(Copy, Clone)] -pub struct NativeDisplay { +pub struct GLXDisplayInfo { pub display: *mut xlib::Display, visual_info: *mut xlib::XVisualInfo, framebuffer_configuration: Option, } +#[derive(Copy, Clone)] +pub struct EGLDisplayInfo { + pub display: EGLDisplay, +} + +#[derive(Copy, Clone)] +pub enum NativeDisplay { + Egl(EGLDisplayInfo), + Glx(GLXDisplayInfo), +} + + unsafe impl Send for NativeDisplay {} @@ -50,11 +69,11 @@ impl NativeDisplay { let (compositor_visual_info, frambuffer_configuration) = NativeDisplay::compositor_visual_info(display); - NativeDisplay { + NativeDisplay::Glx(GLXDisplayInfo { display: display, visual_info: compositor_visual_info, framebuffer_configuration: frambuffer_configuration, - } + }) } /// Chooses the compositor visual info using the same algorithm that the compositor uses. @@ -141,11 +160,22 @@ impl NativeDisplay { } pub fn platform_display_data(&self) -> PlatformDisplayData { - PlatformDisplayData { - display: self.display, - visual_info: self.visual_info, + match *self { + NativeDisplay::Glx(info) => { + PlatformDisplayData { + display: info.display, + visual_info: info.visual_info, + } + } + NativeDisplay::Egl(_) => unreachable!(), } } + + pub fn from_es2() -> NativeDisplay { + NativeDisplay::Egl(EGLDisplayInfo { + display: GetCurrentDisplay() + }) + } } #[derive(RustcDecodable, RustcEncodable)] @@ -170,7 +200,7 @@ impl Drop for PixmapNativeSurface { } impl PixmapNativeSurface { - pub fn new(display: &NativeDisplay, size: Size2D) -> PixmapNativeSurface { + pub fn new(display: &GLXDisplayInfo, size: Size2D) -> PixmapNativeSurface { unsafe { // Create the pixmap. let screen = xlib::XDefaultScreen(display.display); @@ -197,6 +227,11 @@ impl PixmapNativeSurface { // // FIXME(pcwalton): RAII for exception safety? unsafe { + let display = match display { + &NativeDisplay::Glx(info) => info, + &NativeDisplay::Egl(_) => unreachable!(), + }; + let pixmap_attributes = [ glx::TEXTURE_TARGET_EXT as i32, glx::TEXTURE_2D_EXT as i32, glx::TEXTURE_FORMAT_EXT as i32, glx::TEXTURE_FORMAT_RGBA_EXT as i32, @@ -228,6 +263,11 @@ impl PixmapNativeSurface { /// This may only be called on the painting side. pub fn upload(&mut self, display: &NativeDisplay, data: &[u8]) { unsafe { + let display = match display { + &NativeDisplay::Glx(info) => info, + &NativeDisplay::Egl(_) => unreachable!(), + }; + let image = xlib::XCreateImage(display.display, (*display.visual_info).visual, 32, @@ -259,6 +299,11 @@ impl PixmapNativeSurface { pub fn destroy(&mut self, display: &NativeDisplay) { unsafe { + let display = match display { + &NativeDisplay::Glx(info) => info, + &NativeDisplay::Egl(_) => unreachable!(), + }; + assert!(self.pixmap != 0); xlib::XFreePixmap(display.display, self.pixmap); self.mark_wont_leak() diff --git a/src/platform/surface.rs b/src/platform/surface.rs index 7a70691..3abe8ce 100644 --- a/src/platform/surface.rs +++ b/src/platform/surface.rs @@ -31,9 +31,11 @@ pub use platform::linux::surface::{NativeDisplay, #[cfg(target_os="linux")] use std::ptr; +#[cfg(any(target_os="android",target_os="linux"))] +pub use platform::egl::surface::{EGLImageNativeSurface}; + #[cfg(target_os="android")] -pub use platform::android::surface::{NativeDisplay, - EGLImageNativeSurface}; +pub use platform::android::surface::NativeDisplay; #[cfg(target_os="windows")] pub use platform::windows::surface::NativeDisplay; @@ -44,7 +46,7 @@ pub enum NativeSurface { Pixmap(PixmapNativeSurface), #[cfg(target_os="macos")] IOSurface(IOSurfaceNativeSurface), -#[cfg(target_os="android")] +#[cfg(any(target_os="android",target_os="linux"))] EGLImage(EGLImageNativeSurface), } @@ -52,12 +54,19 @@ pub enum NativeSurface { impl NativeSurface { /// Creates a new native surface with uninitialized data. pub fn new(display: &NativeDisplay, size: Size2D) -> NativeSurface { - if display.display == ptr::null_mut() { - NativeSurface::MemoryBuffer(MemoryBufferNativeSurface::new(display, size)) - } else { - NativeSurface::Pixmap(PixmapNativeSurface::new(display, size)) + match display { + &NativeDisplay::Egl(info) => { + NativeSurface::EGLImage(EGLImageNativeSurface::new(display, size)) + } + &NativeDisplay::Glx(info) => { + if info.display == ptr::null_mut() { + NativeSurface::MemoryBuffer(MemoryBufferNativeSurface::new(display, size)) + } else { + NativeSurface::Pixmap(PixmapNativeSurface::new(&info, size)) + } + } } - } + } } #[cfg(target_os="macos")] @@ -95,7 +104,7 @@ macro_rules! native_surface_method_with_mutability { #[cfg(target_os="macos")] NativeSurface::IOSurface($pattern) => $surface.$function_name($($argument), *), - #[cfg(target_os="android")] + #[cfg(any(target_os="android",target_os="linux"))] NativeSurface::EGLImage($pattern) => $surface.$function_name($($argument), *), } @@ -132,7 +141,7 @@ macro_rules! native_surface_property { NativeSurface::Pixmap(ref surface) => surface.$property_name, #[cfg(target_os="macos")] NativeSurface::IOSurface(ref surface) => surface.$property_name, - #[cfg(target_os="android")] + #[cfg(any(target_os="android",target_os="linux"))] NativeSurface::EGLImage(ref surface) => surface.$property_name, } }; @@ -268,4 +277,3 @@ impl MemoryBufferNativeSurface { None } } -