1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Contains definitions for wlc render functions (wlc-render.h)

use libc::{c_void, uint32_t, uintptr_t};
use std::mem;
use super::types::{Geometry};

/// Number of bits per pixel (RGBA8888)
pub const BITS_PER_PIXEL: u32 = 32;

#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Allowed pixel formats
pub enum wlc_pixel_format {
    /// RGBA8888 format
    WLC_RGBA8888
}

#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
/// Enabled renderers
pub enum wlc_renderer {
    /// Render using GLE
    WLC_RENDERER_GLES2,
    /// Don't render (headless)
    WLC_NO_RENDERER
}

#[allow(missing_docs)]
#[repr(C)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum wlc_surface_format {
    SURFACE_RGB,
    SURFACE_RGBA,
    SURFACE_EGL,
    SURFACE_Y_UV,
    SURFACE_Y_U_V,
    SURFACE_Y_XUXV,
}

#[cfg_attr(feature = "static-wlc", link(name = "wlc", kind = "static"))]
#[cfg_attr(not(feature = "static-wlc"), link(name = "wlc"))]
extern "C" {
    /// Write pixel data with the specific format to output's framebuffer.
    /// If the geometry is out of bounds, it will be automatically clamped.
    pub fn wlc_pixels_write(format: wlc_pixel_format, geometry: *const Geometry, data: *const c_void);

    pub fn wlc_pixels_read(format: wlc_pixel_format,
                           geometry: *const Geometry,
                           out_geo: *mut Geometry,
                           data: *mut c_void);

    /** Renders surface. */
    pub fn wlc_surface_render(surface: uintptr_t, geometry: *const Geometry);

    /// Read pixel data from output's framebuffer.
    /// If theif output is currently rendering, it will render immediately after.
    pub fn wlc_output_schedule_render(output: uintptr_t) -> wlc_renderer;

    /// Adds frame callbacks of the given surface for the next output frame.
    /// It applies recursively to all subsurfaces.
    /// Useful when the compositor creates custom animations which require disabling internal rendering,
    /// but still need to update the surface textures (for ex. video players).
    pub fn wlc_surface_flush_frame_callbacks(surface: uintptr_t);

    /// Returns currently active renderer on the given output
    pub fn wlc_output_get_renderer(output: uintptr_t) -> wlc_renderer;

    /// Fills out_textures[] with the textures of a surface. Returns false if surface is invalid.
    /// Array must have at least 3 elements and should be refreshed at each frame.
    /// Note that these are not only OpenGL textures but rather render-specific.
    /// For more info what they are check the renderer's source code */
    pub fn wlc_surface_get_textures(surface: uintptr_t,
                                out_textures: *mut uint32_t,
                                out_format: *mut wlc_surface_format) -> bool;

    pub fn wlc_output_set_gamma(output: uintptr_t,
                                size: u16,
                                red: *mut u16,
                                green: *mut u16,
                                blue: *mut u16);

    pub fn wlc_output_get_gamma_size(output: uintptr_t) -> u16 ;
}


/// Write pixel data with the specific format to output's framebuffer.
/// If the geometry is out of bounds, it will be automatically clamped.
///
/// # Unsafety
/// The data is converted to a *mut c_void and then passed to C to read.
/// The size of it should be the stride of the geometry * height of the geometry.
pub fn write_pixels(format: wlc_pixel_format, geometry: Geometry, data: &[u8]) {
    unsafe {
        let data = data as *const _ as *const c_void;
        wlc_pixels_write(format, &geometry as *const Geometry, data);
    }
}

/// Reads the pixels at the specified geometry
pub fn read_pixels(format: wlc_pixel_format, mut geometry: Geometry) -> ([u8; 9], Vec<u8>) {
    let data_size = (geometry.size.w * geometry.size.h * 4) as usize;
    // magic response header size
    let header_size = 9;
    let mut in_buf: Vec<u8> = Vec::with_capacity(header_size + data_size);
    let in_buf_ptr = in_buf.as_mut_ptr();
    mem::forget(in_buf);
    let mut out_buf = unsafe {
        let mut out_geo = Geometry::zero();
        wlc_pixels_read(format,
                        &mut geometry as *mut _,
                        &mut out_geo as *mut _,
                        in_buf_ptr as *mut c_void);
        // TODO read the header for this information!
        let size = header_size +
            out_geo.size.w as usize * out_geo.size.h as usize * 4;
        Vec::from_raw_parts(in_buf_ptr, size, size)
    };
    let mut header_response = [0u8; 9];
    let response: Vec<u8> = out_buf.drain(0..9).collect();
    header_response.copy_from_slice(response.as_slice());
    (header_response, out_buf)
}

/// Calculates the stride for ARGB32 encoded buffers
pub fn calculate_stride(width: u32) -> u32 {
    // function stolen from CAIRO_STRIDE_FOR_WIDTH macro in carioint.h
    // can be found in the most recent version of the cairo source
    let stride_alignment = ::std::mem::size_of::<u32>() as u32;
    ((BITS_PER_PIXEL * width + 7 ) / 8 + (stride_alignment - 1))  & (stride_alignment.overflowing_neg().0)
}