From d38c0a3eec632af15ccce182f63f13eddcfd200f Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 1 Nov 2013 23:22:04 -0700 Subject: [PATCH 1/4] Update for Core Foundation bindings revamp --- platform/macos/surface.rs | 58 ++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/platform/macos/surface.rs b/platform/macos/surface.rs index 0e5caa5..18ceea9 100644 --- a/platform/macos/surface.rs +++ b/platform/macos/surface.rs @@ -10,6 +10,7 @@ //! Mac OS-specific implementation of cross-process surfaces. This uses `IOSurface`, introduced //! in Mac OS X 10.6 Snow Leopard. +use core_foundation::base::TCFType; use core_foundation::boolean::CFBoolean; use core_foundation::dictionary::CFDictionary; use core_foundation::number::CFNumber; @@ -72,34 +73,35 @@ impl NativeSurface { impl NativeSurfaceMethods for NativeSurface { fn new(_: &NativePaintingGraphicsContext, size: Size2D, stride: i32) -> NativeSurface { - let width_key = CFString::wrap_shared(kIOSurfaceWidth); - let width_value = CFNumber::new(size.width); - - let height_key = CFString::wrap_shared(kIOSurfaceHeight); - let height_value = CFNumber::new(size.height); - - let bytes_per_row_key = CFString::wrap_shared(kIOSurfaceBytesPerRow); - let bytes_per_row_value = CFNumber::new(stride); - - let bytes_per_elem_key = CFString::wrap_shared(kIOSurfaceBytesPerElement); - let bytes_per_elem_value = CFNumber::new(4i32); - - let is_global_key = CFString::wrap_shared(kIOSurfaceIsGlobal); - let is_global_value = CFBoolean::true_value(); - - let surface = io_surface::new(&CFDictionary::new([ - (*width_key.contents.borrow_ref(), *width_value.contents.borrow_type_ref()), - (*height_key.contents.borrow_ref(), *height_value.contents.borrow_type_ref()), - (*bytes_per_row_key.contents.borrow_ref(), - *bytes_per_row_value.contents.borrow_type_ref()), - (*bytes_per_elem_key.contents.borrow_ref(), - *bytes_per_elem_value.contents.borrow_type_ref()), - (*is_global_key.contents.borrow_ref(), *is_global_value.contents.borrow_type_ref()), - ])); - - NativeSurface { - io_surface: Some(surface), - will_leak: true, + unsafe { + let width_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceWidth); + let width_value: CFNumber = FromPrimitive::from_i32(size.width).unwrap(); + + let height_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceHeight); + let height_value: CFNumber = FromPrimitive::from_i32(size.height).unwrap(); + + let bytes_per_row_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceBytesPerRow); + let bytes_per_row_value: CFNumber = FromPrimitive::from_i32(stride).unwrap(); + + let bytes_per_elem_key: CFString = + TCFType::wrap_under_get_rule(kIOSurfaceBytesPerElement); + let bytes_per_elem_value: CFNumber = FromPrimitive::from_i32(4).unwrap(); + + let is_global_key: CFString = TCFType::wrap_under_get_rule(kIOSurfaceIsGlobal); + let is_global_value = CFBoolean::true_value(); + + let surface = io_surface::new(&CFDictionary::from_CFType_pairs([ + (width_key.as_CFType(), width_value.as_CFType()), + (height_key.as_CFType(), height_value.as_CFType()), + (bytes_per_row_key.as_CFType(), bytes_per_row_value.as_CFType()), + (bytes_per_elem_key.as_CFType(), bytes_per_elem_value.as_CFType()), + (is_global_key.as_CFType(), is_global_value.as_CFType()), + ])); + + NativeSurface { + io_surface: Some(surface), + will_leak: true, + } } } From bc7a39af10697271bae33abc4064ab0c282e8d40 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 6 Nov 2013 20:42:47 -0800 Subject: [PATCH 2/4] Make Mac surfaces serializable. This is needed for sandboxing. --- lib.rs | 4 +-- platform/macos/surface.rs | 53 ++++++++++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/lib.rs b/lib.rs index ee16d22..0afda44 100644 --- a/lib.rs +++ b/lib.rs @@ -9,10 +9,10 @@ #[feature(managed_boxes)]; -extern mod std; - +extern mod extra; extern mod geom = "rust-geom"; extern mod opengles = "rust-opengles"; +extern mod std; #[cfg(target_os="macos")] extern mod core_foundation = "rust-core-foundation"; diff --git a/platform/macos/surface.rs b/platform/macos/surface.rs index 18ceea9..8549c40 100644 --- a/platform/macos/surface.rs +++ b/platform/macos/surface.rs @@ -17,13 +17,19 @@ use core_foundation::number::CFNumber; use core_foundation::string::CFString; use geom::size::Size2D; use io_surface::{kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight}; -use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth, IOSurface}; +use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth, IOSurface, IOSurfaceID}; use io_surface; use opengles::cgl::CGLPixelFormatObj; use platform::surface::NativeSurfaceMethods; +use std::cast; +use std::cell::Cell; +use std::hashmap::HashMap; +use std::local_data; use std::util; use texturegl::Texture; +local_data_key!(io_surface_repository: HashMap) + pub struct NativeGraphicsMetadata { pixel_format: CGLPixelFormatObj, } @@ -56,17 +62,34 @@ impl NativeCompositingGraphicsContext { } } +#[deriving(Decodable, Encodable)] pub struct NativeSurface { - io_surface: Option, + io_surface_id: Option, will_leak: bool, } impl NativeSurface { #[fixed_stack_segment] pub fn from_io_surface(io_surface: IOSurface) -> NativeSurface { - NativeSurface { - io_surface: Some(io_surface), - will_leak: true, + unsafe { + // 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); + 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()); + Some(repository) + }); + + NativeSurface { + io_surface_id: Some(id), + will_leak: true, + } } } } @@ -98,10 +121,7 @@ impl NativeSurfaceMethods for NativeSurface { (is_global_key.as_CFType(), is_global_value.as_CFType()), ])); - NativeSurface { - io_surface: Some(surface), - will_leak: true, - } + NativeSurface::from_io_surface(surface) } } @@ -110,22 +130,27 @@ impl NativeSurfaceMethods for NativeSurface { texture: &Texture, size: Size2D) { let _bound_texture = texture.bind(); - self.io_surface.get_ref().bind_to_gl_texture(size) + let io_surface = io_surface::lookup(self.io_surface_id.unwrap()); + io_surface.bind_to_gl_texture(size) } fn upload(&self, _: &NativePaintingGraphicsContext, data: &[u8]) { - self.io_surface.get_ref().upload(data) + let io_surface = io_surface::lookup(self.io_surface_id.unwrap()); + io_surface.upload(data) } fn get_id(&self) -> int { - match self.io_surface { + match self.io_surface_id { None => 0, - Some(ref io_surface) => io_surface.get_id() as int, + Some(id) => id as int, } } fn destroy(&mut self, _: &NativePaintingGraphicsContext) { - let _ = util::replace(&mut self.io_surface, None); + local_data::get_mut(io_surface_repository, |opt_repository| { + opt_repository.unwrap().remove(&self.io_surface_id.unwrap()) + }); + self.io_surface_id = None; self.mark_wont_leak() } From bf28b19c1832ff13581a0e327785edb2b7c51c7c Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 8 Nov 2013 14:39:23 -0800 Subject: [PATCH 3/4] Separate out metadata from its descriptor, the latter of which is sendable --- platform/macos/surface.rs | 124 ++++++++++++++++++++++++++++++-------- platform/surface.rs | 4 ++ 2 files changed, 104 insertions(+), 24 deletions(-) diff --git a/platform/macos/surface.rs b/platform/macos/surface.rs index 8549c40..d7f7991 100644 --- a/platform/macos/surface.rs +++ b/platform/macos/surface.rs @@ -15,25 +15,104 @@ use core_foundation::boolean::CFBoolean; use core_foundation::dictionary::CFDictionary; use core_foundation::number::CFNumber; use core_foundation::string::CFString; +use extra::serialize::{Decoder, Encodable, Encoder}; use geom::size::Size2D; use io_surface::{kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow, kIOSurfaceHeight}; use io_surface::{kIOSurfaceIsGlobal, kIOSurfaceWidth, IOSurface, IOSurfaceID}; use io_surface; -use opengles::cgl::CGLPixelFormatObj; -use platform::surface::NativeSurfaceMethods; -use std::cast; +use opengles::cgl::{CGLChoosePixelFormat, CGLDescribePixelFormat, CGLPixelFormatAttribute}; +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::util; +use std::ptr; + +use platform::surface::NativeSurfaceMethods; use texturegl::Texture; local_data_key!(io_surface_repository: HashMap) +/// The Mac native graphics metadata. +#[deriving(Clone)] pub struct NativeGraphicsMetadata { pixel_format: CGLPixelFormatObj, } +impl NativeGraphicsMetadata { + /// Creates a native graphics metadatum from a CGL pixel format. + pub fn from_cgl_pixel_format(pixel_format: CGLPixelFormatObj) -> NativeGraphicsMetadata { + NativeGraphicsMetadata { + pixel_format: pixel_format, + } + } + + #[fixed_stack_segment] + pub fn from_descriptor(descriptor: &NativeGraphicsMetadataDescriptor) + -> NativeGraphicsMetadata { + unsafe { + let mut attributes = ~[]; + for (i, &set) in descriptor.boolean_attributes.iter().enumerate() { + if set { + attributes.push(CORE_BOOLEAN_ATTRIBUTES[i]); + } + } + for (i, &value) in descriptor.integer_attributes.iter().enumerate() { + attributes.push(CORE_INTEGER_ATTRIBUTES[i]); + attributes.push(value as CGLPixelFormatAttribute); + } + attributes.push(0); + let mut pixel_format = ptr::null(); + let mut count = 0; + assert!(CGLChoosePixelFormat(&attributes[0], &mut pixel_format, &mut count) == + kCGLNoError); + assert!(pixel_format != ptr::null()); + assert!(count > 0); + + NativeGraphicsMetadata { + pixel_format: pixel_format, + } + } + } +} + +/// The Mac native graphics metadata descriptor, which encompasses the values needed to create a +/// pixel format object. +#[deriving(Clone, Decodable, Encodable)] +pub struct NativeGraphicsMetadataDescriptor { + boolean_attributes: ~[bool], + integer_attributes: ~[GLint], +} + +impl NativeGraphicsMetadataDescriptor { + #[fixed_stack_segment] + pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor { + unsafe { + let mut descriptor = NativeGraphicsMetadataDescriptor { + boolean_attributes: ~[], + integer_attributes: ~[], + }; + for &attribute in CORE_BOOLEAN_ATTRIBUTES.iter() { + let mut value = 0; + assert!(CGLDescribePixelFormat(metadata.pixel_format, 0, attribute, &mut value) == + kCGLNoError); + descriptor.boolean_attributes.push(value != 0); + println!("{}: bool = {}", attribute, value); + } + for &attribute in CORE_INTEGER_ATTRIBUTES.iter() { + let mut value = 0; + assert!(CGLDescribePixelFormat(metadata.pixel_format, 0, attribute, &mut value) == + kCGLNoError); + descriptor.integer_attributes.push(value); + println!("{}: int = {}", attribute, value); + } + descriptor + } + } + +} + pub struct NativePaintingGraphicsContext { metadata: NativeGraphicsMetadata, } @@ -41,7 +120,7 @@ pub struct NativePaintingGraphicsContext { impl NativePaintingGraphicsContext { pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext { NativePaintingGraphicsContext { - metadata: *metadata, + metadata: (*metadata).clone(), } } } @@ -71,25 +150,22 @@ pub struct NativeSurface { impl NativeSurface { #[fixed_stack_segment] pub fn from_io_surface(io_surface: IOSurface) -> NativeSurface { - unsafe { - // 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); - 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()); - Some(repository) - }); - - NativeSurface { - io_surface_id: Some(id), - will_leak: true, - } + // 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); + 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()); + Some(repository) + }); + + NativeSurface { + io_surface_id: Some(id), + will_leak: true, } } } diff --git a/platform/surface.rs b/platform/surface.rs index f430901..a7e6820 100644 --- a/platform/surface.rs +++ b/platform/surface.rs @@ -21,6 +21,8 @@ pub use platform::macos::surface::NativeCompositingGraphicsContext; #[cfg(target_os="macos")] pub use platform::macos::surface::NativeGraphicsMetadata; #[cfg(target_os="macos")] +pub use platform::macos::surface::NativeGraphicsMetadataDescriptor; +#[cfg(target_os="macos")] pub use platform::macos::surface::NativeSurface; #[cfg(target_os="linux")] pub use platform::linux::surface::NativePaintingGraphicsContext; @@ -29,6 +31,8 @@ pub use platform::linux::surface::NativeCompositingGraphicsContext; #[cfg(target_os="linux")] pub use platform::linux::surface::NativeGraphicsMetadata; #[cfg(target_os="linux")] +pub use platform::linux::surface::NativeGraphicsMetadataDescriptor; +#[cfg(target_os="linux")] pub use platform::linux::surface::NativeSurface; pub trait NativeSurfaceMethods { From 237ebbe998b0d6fd5acfe31eb2e7e15cd177b4b6 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 8 Nov 2013 16:39:36 -0800 Subject: [PATCH 4/4] Make Linux surfaces serializable. This is necessary for multiprocess. --- platform/linux/surface.rs | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/platform/linux/surface.rs b/platform/linux/surface.rs index e39d587..5ce3b7f 100644 --- a/platform/linux/surface.rs +++ b/platform/linux/surface.rs @@ -23,7 +23,7 @@ use opengles::glx; use opengles::gl2::NO_ERROR; use opengles::gl2; use std::cast; -use std::libc::{c_char, c_int, c_uint, c_void}; +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}; @@ -42,7 +42,7 @@ impl NativePaintingGraphicsContext { #[fixed_stack_segment] pub fn from_metadata(metadata: &NativeGraphicsMetadata) -> NativePaintingGraphicsContext { unsafe { - let display = XOpenDisplay(*metadata); + let display = XOpenDisplay(metadata.display.to_c_str().with_ref(|c_str| c_str)); // FIXME(pcwalton): It would be more robust to actually have the compositor pass the // visual. @@ -154,7 +154,37 @@ impl NativeCompositingGraphicsContext { } /// The X display string. -pub type NativeGraphicsMetadata = *c_char; +#[deriving(Clone)] +pub struct NativeGraphicsMetadata { + display: ~str, +} + +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(), + } + } +} + +/// A sendable form of the X display string. +#[deriving(Clone, Decodable, Encodable)] +pub struct NativeGraphicsMetadataDescriptor { + display: ~str, +} + +impl NativeGraphicsMetadataDescriptor { + /// Creates a metadata descriptor from metadata. + #[fixed_stack_segment] + pub fn from_metadata(metadata: NativeGraphicsMetadata) -> NativeGraphicsMetadataDescriptor { + NativeGraphicsMetadataDescriptor { + display: metadata.display.to_str() + } + } +} #[deriving(Eq)] pub enum NativeSurfaceTransientData { @@ -162,6 +192,7 @@ pub enum NativeSurfaceTransientData { RenderTaskTransientData(*Display, *XVisualInfo), } +#[deriving(Decodable, Encodable)] pub struct NativeSurface { /// The pixmap. pixmap: Pixmap,