From 9dcecfe1105b06ee2077213b49e5159713e1d742 Mon Sep 17 00:00:00 2001 From: "aydin.kim" Date: Wed, 20 Nov 2013 15:58:35 +0900 Subject: [PATCH] works for android rendering by using EGLImage --- lib.rs | 7 ++ platform/android/surface.rs | 165 ++++++++++++++++++++++++++++++++++++ platform/surface.rs | 8 ++ rendergl.rs | 113 ++++++++++++++++-------- 4 files changed, 256 insertions(+), 37 deletions(-) create mode 100644 platform/android/surface.rs diff --git a/lib.rs b/lib.rs index 01b45f3..ab67bb3 100755 --- a/lib.rs +++ b/lib.rs @@ -24,6 +24,9 @@ extern mod io_surface; #[cfg(target_os="linux")] extern mod xlib; +#[cfg(target_os="android")] +extern mod egl; + pub mod layers; pub mod color; pub mod rendergl; @@ -40,6 +43,10 @@ pub mod platform { pub mod macos { pub mod surface; } + #[cfg(target_os="android")] + pub mod android { + pub mod surface; + } pub mod surface; } diff --git a/platform/android/surface.rs b/platform/android/surface.rs new file mode 100644 index 0000000..a7f8916 --- /dev/null +++ b/platform/android/surface.rs @@ -0,0 +1,165 @@ +// Copyright 2013 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 for Android. This uses EGL surface. + +use platform::surface::NativeSurfaceMethods; +use texturegl::Texture; + +use geom::size::Size2D; +use opengles::gl2::{egl_image_target_texture2d_oes, TEXTURE_2D, GLsizei, GLint, glTexImage2D, BGRA, UNSIGNED_BYTE}; +use egl::egl::EGLDisplay; +use egl::eglext::{EGLImageKHR, CreateImageKHR, DestroyImageKHR}; +use std::cast; +use std::ptr; +use std::util; +use std::vec; +use std::libc::c_void; +use std::vec::bytes; + +/// FIXME(Aydin Kim) :Currently, native surface is consist of 2 types of hybrid image buffer. EGLImageKHR is used to GPU rendering and vector is used to CPU rendering. EGL extension seems not provide simple way to accessing its bitmap directly. In the future, we need to find out the way to integrate them. + +pub struct NativeGraphicsMetadata { + display : EGLDisplay, +} + +pub struct NativePaintingGraphicsContext{ + display : EGLDisplay, +} + +impl NativePaintingGraphicsContext { + #[fixed_stack_segment] + pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext { + unsafe { + NativePaintingGraphicsContext { + display : metadata.display, + } + } + } +} + +impl Drop for NativePaintingGraphicsContext { + #[fixed_stack_segment] + fn drop(&mut self) {} +} + +pub struct NativeCompositingGraphicsContext { + contents: (), +} + +impl NativeCompositingGraphicsContext { + pub fn new() -> NativeCompositingGraphicsContext { + NativeCompositingGraphicsContext { + contents: (), + } + } +} + +pub struct NativeSurface { + image: Option, + bitmap: *c_void, + will_leak: bool, +} + +impl NativeSurface { + #[fixed_stack_segment] + pub fn from_image_khr(image_khr: EGLImageKHR) -> NativeSurface { + let mut _image: Option = None; + if image_khr != ptr::null() { + _image = Some(image_khr); + } + NativeSurface { + image : _image, + bitmap : ptr::null(), + will_leak: true, + } + } +} + +impl NativeSurfaceMethods for NativeSurface { + /// This may only be called on the case of CPU rendering. + #[fixed_stack_segment] + fn new(native_context: &NativePaintingGraphicsContext, size: Size2D, stride: i32) -> NativeSurface { + unsafe { + let len = size.width * size.height * 4; + let bitmap = vec::from_elem::(len as uint, 0); + + NativeSurface { + image: None, + bitmap: cast::transmute(bitmap), + will_leak : true, + } + } + } + + /// This may only be called on the compositor side. + #[fixed_stack_segment] + fn bind_to_texture(&self, + native_context: &NativeCompositingGraphicsContext, + texture: &Texture, + _size: Size2D) { + let _bound = texture.bind(); + + unsafe { + match self.image { + None => { + if self.bitmap != ptr::null() { + glTexImage2D(TEXTURE_2D, 0, BGRA as i32, _size.width as i32, _size.height as i32, 0, BGRA as u32, UNSIGNED_BYTE, self.bitmap); + } + else { + debug!("Cannot bind the buffer(CPU rendering), there is no bitmap"); + } + }, + Some(image_khr) => { + egl_image_target_texture2d_oes(TEXTURE_2D, image_khr); + } + } + } + } + + /// This may only be called on the painting side. + #[fixed_stack_segment] + fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) { + unsafe { + if self.bitmap != ptr::null() { + let dest:&mut [u8] = cast::transmute((self.bitmap, data.len())); + bytes::copy_memory(dest, data, data.len()); + } + else { + debug!("Cannot upload the buffer(CPU rendering), there is no bitmap"); + } + } + } + + fn get_id(&self) -> int { + match self.image { + None => 0, + Some(image_khr) => image_khr as int, + } + } + +#[fixed_stack_segment] + fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) { + match self.image { + None => {}, + Some(image_khr) => { + DestroyImageKHR(graphics_context.display, image_khr); + util::replace(&mut self.image, None); + } + } + self.mark_wont_leak() + } + + fn mark_will_leak(&mut self) { + self.will_leak = true + } + fn mark_wont_leak(&mut self) { + self.will_leak = false + } +} diff --git a/platform/surface.rs b/platform/surface.rs index a7e6820..0397a77 100644 --- a/platform/surface.rs +++ b/platform/surface.rs @@ -34,6 +34,14 @@ pub use platform::linux::surface::NativeGraphicsMetadata; pub use platform::linux::surface::NativeGraphicsMetadataDescriptor; #[cfg(target_os="linux")] pub use platform::linux::surface::NativeSurface; +#[cfg(target_os="android")] +pub use platform::android::surface::NativePaintingGraphicsContext; +#[cfg(target_os="android")] +pub use platform::android::surface::NativeCompositingGraphicsContext; +#[cfg(target_os="android")] +pub use platform::android::surface::NativeGraphicsMetadata; +#[cfg(target_os="android")] +pub use platform::android::surface::NativeSurface; pub trait NativeSurfaceMethods { /// Creates a new native surface with uninitialized data. diff --git a/rendergl.rs b/rendergl.rs index af8dfea..c6ecd16 100755 --- a/rendergl.rs +++ b/rendergl.rs @@ -138,39 +138,59 @@ struct ProgramRectangle { } pub struct RenderContext { - program_2d: Program2D, - program_rectangle: ProgramRectangle, + program_2d: Option, + program_rectangle: Option, buffers: Buffers, } impl RenderContext { - fn new(program_2d: GLuint, program_rectangle: GLuint) -> RenderContext { + fn new(program_2d: Option, program_rectangle: Option) -> RenderContext { let render_context = RenderContext { - program_2d: Program2D { - id: program_2d, - vertex_position_attr: get_attrib_location(program_2d, "aVertexPosition"), - texture_coord_attr: get_attrib_location(program_2d, "aTextureCoord"), - modelview_uniform: get_uniform_location(program_2d, "uMVMatrix"), - projection_uniform: get_uniform_location(program_2d, "uPMatrix"), - sampler_uniform: get_uniform_location(program_2d, "uSampler"), + program_2d: match program_2d { + Some(program) => { + Some(Program2D { + id: program, + vertex_position_attr: get_attrib_location(program, "aVertexPosition"), + texture_coord_attr: get_attrib_location(program, "aTextureCoord"), + modelview_uniform: get_uniform_location(program, "uMVMatrix"), + projection_uniform: get_uniform_location(program, "uPMatrix"), + sampler_uniform: get_uniform_location(program, "uSampler"), + }) + }, + None => None, }, - program_rectangle: ProgramRectangle { - id: program_rectangle, - vertex_position_attr: get_attrib_location(program_rectangle, "aVertexPosition"), - texture_coord_attr: get_attrib_location(program_rectangle, "aTextureCoord"), - modelview_uniform: get_uniform_location(program_rectangle, "uMVMatrix"), - projection_uniform: get_uniform_location(program_rectangle, "uPMatrix"), - sampler_uniform: get_uniform_location(program_rectangle, "uSampler"), - size_uniform: get_uniform_location(program_rectangle, "uSize"), + program_rectangle: match program_rectangle { + Some(program) => { + Some(ProgramRectangle { + id: program, + vertex_position_attr: get_attrib_location(program, "aVertexPosition"), + texture_coord_attr: get_attrib_location(program, "aTextureCoord"), + modelview_uniform: get_uniform_location(program, "uMVMatrix"), + projection_uniform: get_uniform_location(program, "uPMatrix"), + sampler_uniform: get_uniform_location(program, "uSampler"), + size_uniform: get_uniform_location(program, "uSize"), + }) + }, + None => None, }, buffers: RenderContext::init_buffers(), }; - enable_vertex_attrib_array(render_context.program_2d.vertex_position_attr as GLuint); - enable_vertex_attrib_array(render_context.program_2d.texture_coord_attr as GLuint); - enable_vertex_attrib_array(render_context.program_rectangle.vertex_position_attr as - GLuint); - enable_vertex_attrib_array(render_context.program_rectangle.texture_coord_attr as GLuint); + match render_context.program_2d { + Some(program) => { + enable_vertex_attrib_array(program.vertex_position_attr as GLuint); + enable_vertex_attrib_array(program.texture_coord_attr as GLuint); + }, + None => {} + } + + match render_context.program_rectangle { + Some(program) => { + enable_vertex_attrib_array(program.vertex_position_attr as GLuint); + enable_vertex_attrib_array(program.texture_coord_attr as GLuint); + }, + None=> {} + } render_context } @@ -208,6 +228,8 @@ pub fn init_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint { program } +#[cfg(target_os="linux")] +#[cfg(target_os="macos")] pub fn init_render_context() -> RenderContext { let vertex_2d_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); let fragment_2d_shader = load_shader(FRAGMENT_2D_SHADER_SOURCE, FRAGMENT_SHADER); @@ -220,7 +242,18 @@ pub fn init_render_context() -> RenderContext { enable(TEXTURE_2D); enable(TEXTURE_RECTANGLE_ARB); - RenderContext::new(program_2d, program_rectangle) + RenderContext::new(Some(program_2d), Some(program_rectangle)) +} + +#[cfg(target_os="android")] +pub fn init_render_context() -> RenderContext { + let vertex_2d_shader = load_shader(VERTEX_SHADER_SOURCE, VERTEX_SHADER); + let fragment_2d_shader = load_shader(FRAGMENT_2D_SHADER_SOURCE, FRAGMENT_SHADER); + let program_2d = init_program(vertex_2d_shader, fragment_2d_shader); + + enable(TEXTURE_2D); + + RenderContext::new(Some(program_2d), None) } fn bind_texture_coordinate_buffer(render_context: RenderContext, flip: Flip) { @@ -238,8 +271,14 @@ pub fn bind_and_render_quad(render_context: RenderContext, transform: &Matrix4, scene_size: Size2D) { let program_id = match texture.target { - TextureTarget2D => render_context.program_2d.id, - TextureTargetRectangle(*) => render_context.program_rectangle.id, + TextureTarget2D => match render_context.program_2d { + Some(program) => {program.id}, + None => {fail!("There is no shader program for texture 2D");} + }, + TextureTargetRectangle(*) => match render_context.program_rectangle { + Some(program) => {program.id}, + None => {fail!("There is no shader program for texture rectangle");} + }, }; use_program(program_id); @@ -252,42 +291,42 @@ pub fn bind_and_render_quad(render_context: RenderContext, // Set uniforms and vertex attribute pointers. match texture.target { TextureTarget2D => { - uniform_1i(render_context.program_2d.sampler_uniform, 0); - uniform_matrix_4fv(render_context.program_2d.modelview_uniform, + uniform_1i(render_context.program_2d.unwrap().sampler_uniform, 0); + uniform_matrix_4fv(render_context.program_2d.unwrap().modelview_uniform, false, transform.to_array()); - uniform_matrix_4fv(render_context.program_2d.projection_uniform, + uniform_matrix_4fv(render_context.program_2d.unwrap().projection_uniform, false, projection_matrix.to_array()); bind_buffer(ARRAY_BUFFER, render_context.buffers.vertex_buffer); - vertex_attrib_pointer_f32(render_context.program_2d.vertex_position_attr as GLuint, + vertex_attrib_pointer_f32(render_context.program_2d.unwrap().vertex_position_attr as GLuint, 3, false, 0, 0); bind_texture_coordinate_buffer(render_context, flip); - vertex_attrib_pointer_f32(render_context.program_2d.texture_coord_attr as GLuint, + vertex_attrib_pointer_f32(render_context.program_2d.unwrap().texture_coord_attr as GLuint, 2, false, 0, 0); } TextureTargetRectangle(size) => { - uniform_1i(render_context.program_rectangle.sampler_uniform, 0); - uniform_2f(render_context.program_rectangle.size_uniform, + uniform_1i(render_context.program_rectangle.unwrap().sampler_uniform, 0); + uniform_2f(render_context.program_rectangle.unwrap().size_uniform, size.width as GLfloat, size.height as GLfloat); - uniform_matrix_4fv(render_context.program_rectangle.modelview_uniform, + uniform_matrix_4fv(render_context.program_rectangle.unwrap().modelview_uniform, false, transform.to_array()); - uniform_matrix_4fv(render_context.program_rectangle.projection_uniform, + uniform_matrix_4fv(render_context.program_rectangle.unwrap().projection_uniform, false, projection_matrix.to_array()); bind_buffer(ARRAY_BUFFER, render_context.buffers.vertex_buffer); - vertex_attrib_pointer_f32(render_context.program_rectangle.vertex_position_attr as + vertex_attrib_pointer_f32(render_context.program_rectangle.unwrap().vertex_position_attr as GLuint, 3, false, @@ -295,7 +334,7 @@ pub fn bind_and_render_quad(render_context: RenderContext, 0); bind_texture_coordinate_buffer(render_context, flip); - vertex_attrib_pointer_f32(render_context.program_rectangle.texture_coord_attr as + vertex_attrib_pointer_f32(render_context.program_rectangle.unwrap().texture_coord_attr as GLuint, 2, false,