io_surface/
lib.rs

1// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10#![crate_name = "io_surface"]
11#![crate_type = "rlib"]
12
13// Rust bindings to the IOSurface framework on macOS.
14
15use cgl::{kCGLNoError, CGLErrorString, CGLGetCurrentContext, CGLTexImageIOSurface2D, GLenum};
16use core_foundation::base::{CFRelease, CFRetain, CFType, CFTypeID, CFTypeRef, TCFType};
17use core_foundation::dictionary::{CFDictionary, CFDictionaryRef};
18use core_foundation::string::{CFString, CFStringRef};
19use core_foundation_sys::base::mach_port_t;
20use leaky_cow::LeakyCow;
21use libc::{c_int, size_t};
22use std::ffi::CStr;
23use std::os::raw::c_void;
24use std::slice;
25
26const BGRA: GLenum = 0x80E1;
27const RGBA: GLenum = 0x1908;
28const RGB: GLenum = 0x1907;
29const TEXTURE_RECTANGLE_ARB: GLenum = 0x84F5;
30const UNSIGNED_INT_8_8_8_8_REV: GLenum = 0x8367;
31
32#[allow(non_snake_case, non_upper_case_globals)]
33pub mod IOSurfaceLockOptions {
34    pub const kIOSurfaceLockReadOnly: u32 = 0x00000001;
35    pub const kIOSurfaceLockAvoidSync: u32 = 0x00000002;
36}
37
38type IOReturn = c_int;
39
40#[repr(C)]
41pub struct __IOSurface(c_void);
42
43pub type IOSurfaceRef = *const __IOSurface;
44
45pub struct IOSurface {
46    pub obj: IOSurfaceRef,
47}
48
49impl Drop for IOSurface {
50    fn drop(&mut self) {
51        unsafe { CFRelease(self.as_CFTypeRef()) }
52    }
53}
54
55pub type IOSurfaceID = u32;
56
57impl Clone for IOSurface {
58    #[inline]
59    fn clone(&self) -> IOSurface {
60        unsafe { TCFType::wrap_under_get_rule(self.obj) }
61    }
62}
63
64impl TCFType for IOSurface {
65    type Ref = IOSurfaceRef;
66
67    #[inline]
68    fn as_concrete_TypeRef(&self) -> IOSurfaceRef {
69        self.obj
70    }
71
72    #[inline]
73    unsafe fn wrap_under_create_rule(obj: IOSurfaceRef) -> IOSurface {
74        assert!(!obj.is_null(), "Attempted to create a NULL object.");
75        IOSurface { obj }
76    }
77
78    #[inline]
79    fn type_id() -> CFTypeID {
80        unsafe { IOSurfaceGetTypeID() }
81    }
82
83    #[inline]
84    fn as_CFTypeRef(&self) -> CFTypeRef {
85        self.as_concrete_TypeRef() as CFTypeRef
86    }
87
88    #[inline]
89    unsafe fn wrap_under_get_rule(reference: IOSurfaceRef) -> IOSurface {
90        assert!(!reference.is_null(), "Attempted to create a NULL object.");
91        let reference = CFRetain(reference as *const c_void) as IOSurfaceRef;
92        TCFType::wrap_under_create_rule(reference)
93    }
94}
95
96pub fn new(properties: &CFDictionary<CFString, CFType>) -> IOSurface {
97    unsafe { TCFType::wrap_under_create_rule(IOSurfaceCreate(properties.as_concrete_TypeRef())) }
98}
99
100/// Looks up an `IOSurface` by its global ID.
101///
102/// FIXME(pcwalton): This should return an `Option`.
103pub fn lookup(csid: IOSurfaceID) -> IOSurface {
104    unsafe { TCFType::wrap_under_create_rule(IOSurfaceLookup(csid)) }
105}
106
107impl IOSurface {
108    pub fn get_id(&self) -> IOSurfaceID {
109        unsafe { IOSurfaceGetID(self.as_concrete_TypeRef()) }
110    }
111
112    /// Binds to the current GL texture.
113    pub fn bind_to_gl_texture(&self, width: i32, height: i32, has_alpha: bool) {
114        unsafe {
115            let context = CGLGetCurrentContext();
116            let gl_error = CGLTexImageIOSurface2D(
117                context,
118                TEXTURE_RECTANGLE_ARB,
119                if has_alpha {
120                    RGBA as GLenum
121                } else {
122                    RGB as GLenum
123                },
124                width,
125                height,
126                BGRA as GLenum,
127                UNSIGNED_INT_8_8_8_8_REV,
128                self.as_concrete_TypeRef() as *mut libc::c_void,
129                0,
130            );
131
132            if gl_error != kCGLNoError {
133                let error_msg = CStr::from_ptr(CGLErrorString(gl_error));
134                let error_msg = error_msg.to_string_lossy();
135                // This will only actually leak memory if error_msg is a `Cow::Owned`, which
136                // will only happen if the platform gives us invalid unicode.
137                panic!("{}", error_msg.leak());
138            }
139        }
140    }
141
142    pub fn upload(&self, data: &[u8]) {
143        unsafe {
144            let surface = self.as_concrete_TypeRef();
145            let mut seed = 0;
146
147            IOSurfaceLock(surface, 0, &mut seed);
148
149            let height = IOSurfaceGetHeight(surface);
150            let stride = IOSurfaceGetBytesPerRow(surface);
151            let size = height * stride;
152            let address = IOSurfaceGetBaseAddress(surface) as *mut u8;
153            let dest: &mut [u8] = slice::from_raw_parts_mut(address, size);
154            dest.clone_from_slice(data);
155
156            // FIXME(pcwalton): RAII
157            IOSurfaceUnlock(surface, 0, &mut seed);
158        }
159    }
160}
161
162#[cfg_attr(feature = "link", link(name = "IOSurface", kind = "framework"))]
163extern "C" {
164    pub static kIOSurfaceAllocSize: CFStringRef;
165    pub static kIOSurfaceWidth: CFStringRef;
166    pub static kIOSurfaceHeight: CFStringRef;
167    pub static kIOSurfaceBytesPerRow: CFStringRef;
168    pub static kIOSurfaceBytesPerElement: CFStringRef;
169    pub static kIOSurfaceElementWidth: CFStringRef;
170    pub static kIOSurfaceElementHeight: CFStringRef;
171    pub static kIOSurfaceOffset: CFStringRef;
172
173    pub static kIOSurfacePlaneInfo: CFStringRef;
174    pub static kIOSurfacePlaneWidth: CFStringRef;
175    pub static kIOSurfacePlaneHeight: CFStringRef;
176    pub static kIOSurfacePlaneBytesPerRow: CFStringRef;
177    pub static kIOSurfacePlaneOffset: CFStringRef;
178    pub static kIOSurfacePlaneSize: CFStringRef;
179
180    pub static kIOSurfacePlaneBase: CFStringRef;
181    pub static kIOSurfacePlaneBytesPerElement: CFStringRef;
182    pub static kIOSurfacePlaneElementWidth: CFStringRef;
183    pub static kIOSurfacePlaneElementHeight: CFStringRef;
184
185    pub static kIOSurfaceCacheMode: CFStringRef;
186    pub static kIOSurfaceIsGlobal: CFStringRef;
187    pub static kIOSurfacePixelFormat: CFStringRef;
188
189    pub fn IOSurfaceCreate(properties: CFDictionaryRef) -> IOSurfaceRef;
190    pub fn IOSurfaceLookup(csid: IOSurfaceID) -> IOSurfaceRef;
191    pub fn IOSurfaceGetID(buffer: IOSurfaceRef) -> IOSurfaceID;
192
193    pub fn IOSurfaceGetTypeID() -> CFTypeID;
194
195    pub fn IOSurfaceLock(buffer: IOSurfaceRef, options: u32, seed: *mut u32) -> IOReturn;
196    pub fn IOSurfaceUnlock(buffer: IOSurfaceRef, options: u32, seed: *mut u32) -> IOReturn;
197    pub fn IOSurfaceGetSeed(buffer: IOSurfaceRef) -> u32;
198
199    pub fn IOSurfaceGetHeight(buffer: IOSurfaceRef) -> size_t;
200    pub fn IOSurfaceGetWidth(buffer: IOSurfaceRef) -> usize;
201    pub fn IOSurfaceGetBytesPerRow(buffer: IOSurfaceRef) -> size_t;
202    pub fn IOSurfaceGetBaseAddress(buffer: IOSurfaceRef) -> *mut c_void;
203    pub fn IOSurfaceGetElementHeight(buffer: IOSurfaceRef) -> usize;
204    pub fn IOSurfaceGetElementWidth(buffer: IOSurfaceRef) -> usize;
205    pub fn IOSurfaceGetBytesPerElement(buffer: IOSurfaceRef) -> usize;
206    pub fn IOSurfaceGetAllocSize(buffer: IOSurfaceRef) -> usize;
207
208    pub fn IOSurfaceGetPixelFormat(buffer: IOSurfaceRef) -> i32;
209
210    pub fn IOSurfaceGetUseCount(buffer: IOSurfaceRef) -> i32;
211    pub fn IOSurfaceIncrementUseCount(buffer: IOSurfaceRef);
212    pub fn IOSurfaceDecrementUseCount(buffer: IOSurfaceRef);
213    pub fn IOSurfaceIsInUse(buffer: IOSurfaceRef) -> bool;
214
215    pub fn IOSurfaceCreateMachPort(buffer: IOSurfaceRef) -> mach_port_t;
216    pub fn IOSurfaceLookupFromMachPort(port: mach_port_t) -> IOSurfaceRef;
217
218    pub fn IOSurfaceGetPropertyAlignment(property: CFStringRef) -> usize;
219    pub fn IOSurfaceGetPropertyMaximum(property: CFStringRef) -> usize;
220
221    pub fn IOSurfaceCopyValue(buffer: IOSurfaceRef, key: CFStringRef) -> CFTypeRef;
222    pub fn IOSurfaceRemoveValue(buffer: IOSurfaceRef, key: CFStringRef);
223    pub fn IOSurfaceSetValue(buffer: IOSurfaceRef, key: CFStringRef, value: CFTypeRef);
224
225    pub fn IOSurfaceGetBaseAddressOfPlane(buffer: IOSurfaceRef, plane_index: usize) -> *mut c_void;
226    pub fn IOSurfaceGetBytesPerElementOfPlane(buffer: IOSurfaceRef, plane_index: usize) -> usize;
227    pub fn IOSurfaceGetBytesPerRowOfPlane(buffer: IOSurfaceRef, plane_index: usize) -> usize;
228    pub fn IOSurfaceGetElementHeightOfPlane(buffer: IOSurfaceRef, plane_index: usize) -> usize;
229    pub fn IOSurfaceGetElementWidthOfPlane(buffer: IOSurfaceRef, plane_index: usize) -> usize;
230    pub fn IOSurfaceGetHeightOfPlane(buffer: IOSurfaceRef, plane_index: usize) -> usize;
231    pub fn IOSurfaceGetWidthOfPlane(buffer: IOSurfaceRef, plane_index: usize) -> usize;
232}