diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..ad2f528 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,24 @@ +VPATH=%VPATH% + +RUSTC ?= rustc +RUSTFLAGS ?= + +RUST_SRC=$(shell find $(VPATH)/. -type f -name '*.rs') + +.PHONY: all +all: librust-layers.dummy + +librust-layers.dummy: lib.rs $(RUST_SRC) + $(RUSTC) $(RUSTFLAGS) $< --lib --out-dir . + touch $@ + +rust-layers-test: lib.rs $(RUST_SRC) + $(RUSTC) $(RUSTFLAGS) $< -o $@ --test + +.PHONY: check +check: rust-layers-test + ./rust-layers-test $(TEST) + +.PHONY: clean +clean: + rm -f *.o *.a *.so *.dylib *.dll *.dummy *-test diff --git a/configure b/configure new file mode 100755 index 0000000..62a0f4c --- /dev/null +++ b/configure @@ -0,0 +1,4 @@ +#!/bin/bash + +SRCDIR="$(cd $(dirname $0) && pwd)" +sed "s#%VPATH%#${SRCDIR}#" ${SRCDIR}/Makefile.in > Makefile diff --git a/layers.rs b/layers.rs index 1a67168..2d5ec23 100644 --- a/layers.rs +++ b/layers.rs @@ -25,7 +25,7 @@ pub enum Layer { } impl Layer { - pub fn with_common(&self, f: &fn(&mut CommonLayer) -> T) -> T { + pub fn with_common(&self, f: |&mut CommonLayer| -> T) -> T { match *self { ContainerLayerKind(container_layer) => f(&mut container_layer.common), TextureLayerKind(texture_layer) => f(&mut texture_layer.common), @@ -99,7 +99,7 @@ impl ContainerLayer { /// Adds a child to the beginning of the list. /// Only works when the child is disconnected from the layer tree. pub fn add_child_start(@mut self, new_child: Layer) { - do new_child.with_common |new_child_common| { + new_child.with_common(|new_child_common| { assert!(new_child_common.parent.is_none()); assert!(new_child_common.prev_sibling.is_none()); assert!(new_child_common.next_sibling.is_none()); @@ -109,11 +109,11 @@ impl ContainerLayer { match self.first_child { None => {} Some(first_child) => { - do first_child.with_common |first_child_common| { + first_child.with_common(|first_child_common| { assert!(first_child_common.prev_sibling.is_none()); first_child_common.prev_sibling = Some(new_child); new_child_common.next_sibling = Some(first_child); - } + }); } } @@ -123,13 +123,13 @@ impl ContainerLayer { None => self.last_child = Some(new_child), Some(_) => {} } - } + }); } /// Adds a child to the end of the list. /// Only works when the child is disconnected from the layer tree. pub fn add_child_end(@mut self, new_child: Layer) { - do new_child.with_common |new_child_common| { + new_child.with_common(|new_child_common| { assert!(new_child_common.parent.is_none()); assert!(new_child_common.prev_sibling.is_none()); assert!(new_child_common.next_sibling.is_none()); @@ -139,11 +139,11 @@ impl ContainerLayer { match self.last_child { None => {} Some(last_child) => { - do last_child.with_common |last_child_common| { + last_child.with_common(|last_child_common| { assert!(last_child_common.next_sibling.is_none()); last_child_common.next_sibling = Some(new_child); new_child_common.prev_sibling = Some(last_child); - } + }); } } @@ -153,11 +153,11 @@ impl ContainerLayer { None => self.first_child = Some(new_child), Some(_) => {} } - } + }); } pub fn remove_child(@mut self, child: Layer) { - do child.with_common |child_common| { + child.with_common(|child_common| { assert!(child_common.parent.is_some()); match child_common.parent.unwrap() { ContainerLayerKind(ref container) => { @@ -171,9 +171,9 @@ impl ContainerLayer { self.last_child = child_common.prev_sibling; }, Some(ref sibling) => { - do sibling.with_common |sibling_common| { + sibling.with_common(|sibling_common| { sibling_common.prev_sibling = child_common.prev_sibling; - } + }); } } match child_common.prev_sibling { @@ -181,12 +181,12 @@ impl ContainerLayer { self.first_child = child_common.next_sibling; }, Some(ref sibling) => { - do sibling.with_common |sibling_common| { + sibling.with_common(|sibling_common| { sibling_common.next_sibling = child_common.next_sibling; - } + }); } } - } + }); } } diff --git a/lib.rs b/lib.rs index e450d4d..f7cffb7 100755 --- a/lib.rs +++ b/lib.rs @@ -7,20 +7,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[crate_id = "github.com/mozilla-servo/rust-layers#layers:0.1"]; + #[feature(managed_boxes)]; extern mod extra; -extern mod geom = "rust-geom"; -extern mod opengles = "rust-opengles"; +extern mod geom; +extern mod opengles; extern mod std; #[cfg(target_os="macos")] -extern mod core_foundation = "rust-core-foundation"; +extern mod core_foundation; #[cfg(target_os="macos")] -extern mod io_surface = "rust-io-surface"; +extern mod io_surface; #[cfg(target_os="linux")] -extern mod xlib = "rust-xlib"; +extern mod xlib; + +#[cfg(target_os="android")] +extern mod egl; pub mod layers; pub mod color; @@ -38,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..17c3d39 --- /dev/null +++ b/platform/android/surface.rs @@ -0,0 +1,155 @@ +// 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, glTexImage2D, BGRA, UNSIGNED_BYTE}; +use egl::egl::EGLDisplay; +use egl::eglext::{EGLImageKHR, DestroyImageKHR}; +use std::cast; +use std::ptr; +use std::util; +use std::vec; +use std::libc::c_void; + +/// 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 { + pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext { + NativePaintingGraphicsContext { + display : metadata.display, + } + } +} + +impl Drop for NativePaintingGraphicsContext { + 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 { + 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. + 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. + 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. + fn upload(&self, _graphics_context: &NativePaintingGraphicsContext, data: &[u8]) { + unsafe { + if self.bitmap != ptr::null() { + let dest:&mut [u8] = cast::transmute((self.bitmap, data.len())); + dest.copy_memory(data); + } + 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, + } + } + + 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/linux/surface.rs b/platform/linux/surface.rs index 8881f88..8295ff2 100644 --- a/platform/linux/surface.rs +++ b/platform/linux/surface.rs @@ -13,24 +13,26 @@ use platform::surface::NativeSurfaceMethods; use texturegl::Texture; use geom::size::Size2D; -use opengles::glx::{GLXFBConfig, GLXDrawable, GLX_BIND_TO_TEXTURE_RGBA_EXT}; -use opengles::glx::{GLX_DEPTH_SIZE, GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT, GLX_RGBA}; +use opengles::glx::{GLXFBConfig, GLXDrawable}; +use opengles::glx::{GLX_BIND_TO_TEXTURE_RGBA_EXT}; +use opengles::glx::{GLX_DRAWABLE_TYPE, GLX_FRONT_EXT, GLX_PIXMAP_BIT}; use opengles::glx::{GLX_TEXTURE_2D_EXT, GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT}; -use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXChooseVisual, glXCreatePixmap, glXDestroyPixmap}; -use opengles::glx::{glXGetProcAddress, glXGetFBConfigAttrib, glXGetFBConfigs}; +use opengles::glx::{GLX_TEXTURE_TARGET_EXT, glXCreatePixmap, glXDestroyPixmap}; +use opengles::glx::{glXGetProcAddress, glXChooseFBConfig}; use opengles::glx::{glXGetVisualFromFBConfig}; -use opengles::glx; +use opengles::glx::{GLX_RGBA_BIT, GLX_WINDOW_BIT, GLX_RENDER_TYPE, GLX_DOUBLEBUFFER}; use opengles::gl2::NO_ERROR; use opengles::gl2; use std::cast; +use std::c_str::CString; use std::libc::{c_int, c_uint, c_void}; use std::ptr; -use xlib::xlib::{Display, Pixmap, XCloseDisplay, XCreateGC, XCreateImage, XCreatePixmap}; -use xlib::xlib::{XDefaultScreen, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow}; +use xlib::xlib::{Display, Pixmap, XCreateGC, XCreateImage, XCreatePixmap, XDefaultScreen}; +use xlib::xlib::{XDisplayString, XFreePixmap, XGetGeometry, XOpenDisplay, XPutImage, XRootWindow}; use xlib::xlib::{XVisualInfo, ZPixmap}; -/// The display and visual info. This is needed in order to upload on the painting side. This holds -/// a *strong* reference to the display and will close it when done. +/// The display and visual info. This is needed in order to upload on the painting side. This +/// holds a weak reference to the display and will not close it when done. /// /// FIXME(pcwalton): Mark nonsendable and noncopyable. pub struct NativePaintingGraphicsContext { @@ -39,35 +41,15 @@ pub struct NativePaintingGraphicsContext { } impl NativePaintingGraphicsContext { - #[fixed_stack_segment] pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext { - unsafe { - let display = do metadata.display.with_c_str |c_str| { - XOpenDisplay(c_str) - }; - - if display.is_null() { - fail!("XOpenDisplay() failed!"); - } - - // FIXME(pcwalton): It would be more robust to actually have the compositor pass the - // visual. - let compositor_visual_info = - NativeCompositingGraphicsContext::compositor_visual_info(display); - - NativePaintingGraphicsContext { - display: display, - visual_info: compositor_visual_info, - } - } - } -} - -impl Drop for NativePaintingGraphicsContext { - #[fixed_stack_segment] - fn drop(&mut self) { - unsafe { - let _ = XCloseDisplay(self.display); + // FIXME(pcwalton): It would be more robust to actually have the compositor pass the + // visual. + let (compositor_visual_info, _) = + NativeCompositingGraphicsContext::compositor_visual_info(metadata.display); + + NativePaintingGraphicsContext { + display: metadata.display, + visual_info: compositor_visual_info, } } } @@ -84,94 +66,82 @@ impl Drop for NativePaintingGraphicsContext { pub struct NativeCompositingGraphicsContext { display: *Display, visual_info: *XVisualInfo, - framebuffer_configuration: GLXFBConfig, + framebuffer_configuration: Option, } impl NativeCompositingGraphicsContext { /// Chooses the compositor visual info using the same algorithm that the compositor uses. /// /// FIXME(pcwalton): It would be more robust to actually have the compositor pass the visual. - #[fixed_stack_segment] - fn compositor_visual_info(display: *Display) -> *XVisualInfo { + fn compositor_visual_info(display: *Display) -> (*XVisualInfo, Option) { unsafe { - let glx_display: *glx::Display = cast::transmute(display); + let glx_display = cast::transmute(display); + + // CONSIDER: + // In skia, they compute the GLX_ALPHA_SIZE minimum and request + // that as well. + + let fbconfig_attributes = [ + GLX_DOUBLEBUFFER, 0, + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT, + GLX_BIND_TO_TEXTURE_RGBA_EXT, 1, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + 0 + ]; + let screen = XDefaultScreen(display); - let attributes = [ GLX_RGBA, GLX_DEPTH_SIZE, 24, 0 ]; - let compositor_visual_info = glXChooseVisual(glx_display, screen, &attributes[0]); - cast::transmute(compositor_visual_info) + let mut configs = 0; + let fbconfigs = glXChooseFBConfig(glx_display, screen, + &fbconfig_attributes[0], &mut configs); + if (configs == 0) { + fail!("Unable to locate a GLX FB configuration that supports RGBA."); + } + + let fbconfig = *ptr::offset(fbconfigs, 0); + let vi = glXGetVisualFromFBConfig(glx_display, fbconfig); + (cast::transmute(vi), Some(fbconfig)) } } /// Creates a native graphics context from the given X display connection. This uses GLX. Only /// the compositor is allowed to call this. - #[fixed_stack_segment] pub fn from_display(display: *Display) -> NativeCompositingGraphicsContext { - unsafe { - // FIXME(pcwalton): It would be more robust to actually have the compositor pass the - // visual. - let compositor_visual_info = - NativeCompositingGraphicsContext::compositor_visual_info(display); - let compositor_visual_id = (*compositor_visual_info).visualid; - - // Choose an FB config. - let glx_display = cast::transmute(display); - let screen = XDefaultScreen(display); - let mut fbconfig_count = 0; - let fbconfigs = glXGetFBConfigs(glx_display, screen, &mut fbconfig_count); - let mut fbconfig_index = None; - for i in range(0, fbconfig_count) { - let fbconfig = *ptr::offset(fbconfigs, i as int); - let visual_info = glXGetVisualFromFBConfig(glx_display, fbconfig); - let visual_info: *XVisualInfo = cast::transmute(visual_info); - if visual_info == ptr::null() || (*visual_info).visualid != compositor_visual_id { - continue - } - - let mut value = 0; - glXGetFBConfigAttrib(glx_display, fbconfig, GLX_DRAWABLE_TYPE, &mut value); - if (value & GLX_PIXMAP_BIT) == 0 { - continue - } - - glXGetFBConfigAttrib(glx_display, - fbconfig, - GLX_BIND_TO_TEXTURE_RGBA_EXT, - &mut value); - if value == 0 { - continue - } - - fbconfig_index = Some(i); - break - } - - let framebuffer_configuration = match fbconfig_index { - None => fail!("No appropriate framebuffer config found!"), - Some(index) => *ptr::offset(fbconfigs, index as int), - }; + let (visual_info, fbconfig) = NativeCompositingGraphicsContext::compositor_visual_info(display); - NativeCompositingGraphicsContext { - display: display, - visual_info: compositor_visual_info, - framebuffer_configuration: framebuffer_configuration, - } + NativeCompositingGraphicsContext { + display: display, + visual_info: visual_info, + framebuffer_configuration: fbconfig, } } } -/// The X display string. +/// The X display. #[deriving(Clone)] pub struct NativeGraphicsMetadata { - display: ~str, + display: *Display, } impl NativeGraphicsMetadata { /// Creates graphics metadata from a metadata descriptor. - #[fixed_stack_segment] pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor) -> NativeGraphicsMetadata { - NativeGraphicsMetadata { - display: descriptor.display.to_str(), + // WARNING: We currently rely on the X display connection being the + // same in both the Painting and Compositing contexts, as otherwise + // the X Pixmap will not be sharable across them. Using this + // method breaks that assumption. + unsafe { + let display = do descriptor.display.with_c_str |c_str| { + XOpenDisplay(c_str) + }; + + if display.is_null() { + fail!("XOpenDisplay() failed!"); + } + + NativeGraphicsMetadata { + display: display, + } } } } @@ -184,10 +154,12 @@ pub struct NativeGraphicsMetadataDescriptor { impl NativeGraphicsMetadataDescriptor { /// Creates a metadata descriptor from metadata. - #[fixed_stack_segment] pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor { - NativeGraphicsMetadataDescriptor { - display: metadata.display.to_str() + unsafe { + let c_str = CString::new(XDisplayString(metadata.display), false); + NativeGraphicsMetadataDescriptor { + display: c_str.as_str().unwrap().to_str(), + } } } } @@ -217,7 +189,6 @@ impl Drop for NativeSurface { } impl NativeSurface { - #[fixed_stack_segment] pub fn from_pixmap(pixmap: Pixmap) -> NativeSurface { NativeSurface { pixmap: pixmap, @@ -227,26 +198,22 @@ impl NativeSurface { } impl NativeSurfaceMethods for NativeSurface { - #[fixed_stack_segment] fn new(native_context: &NativePaintingGraphicsContext, size: Size2D, stride: i32) -> NativeSurface { unsafe { // Create the pixmap. let screen = XDefaultScreen(native_context.display); let window = XRootWindow(native_context.display, screen); - let pixmap = XCreatePixmap(native_context.display, window, size.width as c_uint, size.height as c_uint, ((stride / size.width) * 8) as c_uint); - NativeSurface::from_pixmap(pixmap) } } /// This may only be called on the compositor side. - #[fixed_stack_segment] fn bind_to_texture(&self, native_context: &NativeCompositingGraphicsContext, texture: &Texture, @@ -260,9 +227,12 @@ impl NativeSurfaceMethods for NativeSurface { GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, 0 ]; + let glx_display = cast::transmute(native_context.display); + let glx_pixmap = glXCreatePixmap(glx_display, - native_context.framebuffer_configuration, + native_context.framebuffer_configuration.expect( + "GLX 1.3 should have a framebuffer_configuration"), self.pixmap, &pixmap_attributes[0]); @@ -282,7 +252,6 @@ impl NativeSurfaceMethods for NativeSurface { } /// This may only be called on the painting side. - #[fixed_stack_segment] fn upload(&self, graphics_context: &NativePaintingGraphicsContext, data: &[u8]) { unsafe { // Ensure that we're running on the render task. Take the display. @@ -339,7 +308,6 @@ impl NativeSurfaceMethods for NativeSurface { self.pixmap as int } - #[fixed_stack_segment] fn destroy(&mut self, graphics_context: &NativePaintingGraphicsContext) { unsafe { assert!(self.pixmap != 0); diff --git a/platform/macos/surface.rs b/platform/macos/surface.rs index d7f7991..671bf9f 100644 --- a/platform/macos/surface.rs +++ b/platform/macos/surface.rs @@ -24,7 +24,6 @@ use opengles::cgl::{CGLChoosePixelFormat, CGLDescribePixelFormat, CGLPixelFormat use opengles::cgl::{CGLPixelFormatObj, CORE_BOOLEAN_ATTRIBUTES, CORE_INTEGER_ATTRIBUTES}; use opengles::cgl::{kCGLNoError}; use opengles::gl2::GLint; -use std::cell::Cell; use std::hashmap::HashMap; use std::local_data; use std::ptr; @@ -48,7 +47,6 @@ impl NativeGraphicsMetadata { } } - #[fixed_stack_segment] pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor) -> NativeGraphicsMetadata { unsafe { @@ -86,7 +84,6 @@ pub struct NativeGraphicsMetadataDescriptor { } impl NativeGraphicsMetadataDescriptor { - #[fixed_stack_segment] pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor { unsafe { let mut descriptor = NativeGraphicsMetadataDescriptor { @@ -148,18 +145,17 @@ pub struct NativeSurface { } impl NativeSurface { - #[fixed_stack_segment] pub fn from_io_surface(io_surface: IOSurface) -> NativeSurface { // Take the surface by ID (so that we can send it cross-process) and consume its reference. let id = io_surface.get_id(); - let io_surface_cell = Cell::new(io_surface); + let mut io_surface = Some(io_surface); local_data::modify(io_surface_repository, |opt_repository| { let mut repository = match opt_repository { None => HashMap::new(), Some(repository) => repository, }; - repository.insert(id, io_surface_cell.take()); + repository.insert(id, io_surface.take().unwrap()); Some(repository) }); 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..9db6269 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, diff --git a/scene.rs b/scene.rs index a900070..772d464 100755 --- a/scene.rs +++ b/scene.rs @@ -35,7 +35,7 @@ pub fn Scene(root: Layer, size: Size2D, transform: Matrix4) -> Scene { impl Scene { // FIXME: Workaround for cross-crate bug regarding mutability of class fields - fn set_transform(&mut self, new_transform: Matrix4) { + pub fn set_transform(&mut self, new_transform: Matrix4) { self.transform = new_transform; } } diff --git a/texturegl.rs b/texturegl.rs index 4eeb7cb..8326711 100644 --- a/texturegl.rs +++ b/texturegl.rs @@ -19,11 +19,11 @@ use opengles::gl2; use std::num::Zero; /// Image data used when uploading to a texture. -pub struct TextureImageData<'self> { +pub struct TextureImageData<'a> { size: Size2D, stride: uint, format: Format, - data: &'self [u8], + data: &'a [u8], } /// The texture target. @@ -38,7 +38,7 @@ impl TextureTarget { fn as_gl_target(self) -> GLenum { match self { TextureTarget2D => TEXTURE_2D, - TextureTargetRectangle(*) => TEXTURE_RECTANGLE_ARB, + TextureTargetRectangle(_) => TEXTURE_RECTANGLE_ARB, } } } diff --git a/util.rs b/util.rs index 47acd63..62e2b89 100644 --- a/util.rs +++ b/util.rs @@ -9,11 +9,11 @@ // Miscellaneous utilities. -use std::vec::from_fn; +use std::vec; pub fn convert_rgb32_to_rgb24(buffer: ~[u8]) -> ~[u8] { let mut i = 0; - do from_fn(buffer.len() * 3 / 4) |j| { + vec::from_fn(buffer.len() * 3 / 4, |j| { match j % 3 { 0 => { buffer[i + 2] @@ -30,6 +30,6 @@ pub fn convert_rgb32_to_rgb24(buffer: ~[u8]) -> ~[u8] { fail!() } } - } + }) }