<commit_before>use {Backend};

use std::collections::{Bound, BTreeMap, HashMap};
use std::sync::{Arc, Mutex};
use std::ops::Range;
use std::os::raw::{c_void, c_long, c_int};
use std::ptr;

use hal::{self, image, pass, pso};

use cocoa::foundation::{NSRange, NSUInteger};
use foreign_types::ForeignType;
use metal::{self, MTLPrimitiveType};
use objc;
use spirv_cross::{msl, spirv};

/// Shader module can be compiled in advance if it's resource bindings do not
/// depend on pipeline layout, in which case the value would become `Compiled`.
#[derive(Debug)]
pub enum ShaderModule {
    Compiled {
        library: metal::Library,
        entry_point_map: HashMap<String, spirv::EntryPoint>,
    },
    Raw(Vec<u8>),
}

unsafe impl Send for ShaderModule {}
unsafe impl Sync for ShaderModule {}

#[derive(Debug)]
pub struct RenderPass {
    pub(crate) desc: metal::RenderPassDescriptor,
    pub(crate) attachments: Vec<pass::Attachment>,
    pub(crate) num_colors: usize,
}

unsafe impl Send for RenderPass {}
unsafe impl Sync for RenderPass {}

#[derive(Debug)]
pub struct FrameBuffer(pub(crate) metal::RenderPassDescriptor);

unsafe impl Send for FrameBuffer {}
unsafe impl Sync for FrameBuffer {}

#[derive(Debug)]
pub struct PipelineLayout {
    // First vertex buffer index to be used by attributes
    pub(crate) attribute_buffer_index: u32,
    pub(crate) res_overrides: HashMap<msl::ResourceBindingLocation, msl::ResourceBinding>,
}

#[derive(Debug)]
pub struct GraphicsPipeline {
    // we hold the compiled libraries here for now
    // TODO: move to some cache in `Device`
    pub(crate) vs_lib: metal::Library,
    pub(crate) fs_lib: Option<metal::Library>,
    pub(crate) raw: metal::RenderPipelineState,
    pub(crate) primitive_type: MTLPrimitiveType,
    pub(crate) attribute_buffer_index: u32,
    pub(crate) depth_stencil_state: Option<metal::DepthStencilState>,
}

unsafe impl Send for GraphicsPipeline {}
unsafe impl Sync for GraphicsPipeline {}

#[derive(Debug)]
pub struct ComputePipeline {
    pub(crate) cs_lib: metal::Library,
    pub(crate) raw: metal::ComputePipelineState,
    pub(crate) work_group_size: metal::MTLSize,
}

unsafe impl Send for ComputePipeline {}
unsafe impl Sync for ComputePipeline {}

#[derive(Debug)]
pub struct Image {
    pub(crate) raw: metal::Texture,
    pub(crate) bytes_per_block: u8,
    // Dimension of a texel block (compressed formats).
    pub(crate) block_dim: (u8, u8),
}

unsafe impl Send for Image {}
unsafe impl Sync for Image {}

#[derive(Debug)]
pub struct BufferView {}

#[derive(Debug)]
pub struct ImageView(pub(crate) metal::Texture);

unsafe impl Send for ImageView {}
unsafe impl Sync for ImageView {}

#[derive(Debug)]
pub struct Sampler(pub(crate) metal::SamplerState);

unsafe impl Send for Sampler {}
unsafe impl Sync for Sampler {}

#[derive(Debug)]
pub struct Semaphore(pub(crate) *mut c_void);

unsafe impl Send for Semaphore {}
unsafe impl Sync for Semaphore {}

#[derive(Debug)]
pub struct Buffer {
    pub(crate) raw: metal::Buffer,
    pub(crate) allocations: Option<Arc<Mutex<MemoryAllocations>>>,
    pub(crate) offset: u64,
}

unsafe impl Send for Buffer {}
unsafe impl Sync for Buffer {}

#[derive(Debug)]
pub enum DescriptorPool {
    Emulated,
    ArgumentBuffer {
        buffer: metal::Buffer,
        total_size: NSUInteger,
        offset: NSUInteger,
    }
}
//TODO: re-evaluate Send/Sync here
unsafe impl Send for DescriptorPool {}
unsafe impl Sync for DescriptorPool {}

impl hal::DescriptorPool<Backend> for DescriptorPool {
    fn allocate_set(&mut self, layout: &DescriptorSetLayout) -> DescriptorSet {
        match *self {
            DescriptorPool::Emulated => {
                let layout_bindings = match layout {
                    &DescriptorSetLayout::Emulated(ref bindings) => bindings,
                    _ => panic!("Incompatible descriptor set layout type"),
                };

                let bindings = layout_bindings.iter().map(|layout| {
                    let binding = match layout.ty {
                        pso::DescriptorType::Sampler => {
                            DescriptorSetBinding::Sampler(vec![None; layout.count])
                        }
                        pso::DescriptorType::SampledImage |
                        pso::DescriptorType::StorageImage => {
                            DescriptorSetBinding::Image(vec![None; layout.count])
                        }
                        pso::DescriptorType::UniformBuffer |
                        pso::DescriptorType::StorageBuffer => {
                            DescriptorSetBinding::Buffer(vec![None; layout.count])
                        }
                        pso::DescriptorType::UniformTexelBuffer |
                        pso::DescriptorType::StorageTexelBuffer |
                        pso::DescriptorType::InputAttachment => unimplemented!()
                    };
                    (layout.binding, binding)
                }).collect();

                let inner = DescriptorSetInner {
                    layout: layout_bindings.to_vec(),
                    bindings,
                };
                DescriptorSet::Emulated(Arc::new(Mutex::new(inner)))
            }
            DescriptorPool::ArgumentBuffer { ref buffer, total_size, ref mut offset } => {
                let (encoder, stage_flags) = match layout {
                    &DescriptorSetLayout::ArgumentBuffer(ref encoder, stages) => (encoder, stages),
                    _ => panic!("Incompatible descriptor set layout type"),
                };

                let cur_offset = *offset;
                *offset += encoder.encoded_length();
                assert!(*offset <= total_size);

                DescriptorSet::ArgumentBuffer {
                    buffer: buffer.clone(),
                    offset: cur_offset,
                    encoder: encoder.clone(),
                    stage_flags,
                }
            }
        }
    }

    fn reset(&mut self) {
        unimplemented!()
    }
}

#[derive(Debug)]
pub enum DescriptorSetLayout {
    Emulated(Vec<pso::DescriptorSetLayoutBinding>),
    ArgumentBuffer(metal::ArgumentEncoder, pso::ShaderStageFlags),
}
unsafe impl Send for DescriptorSetLayout {}
unsafe impl Sync for DescriptorSetLayout {}

#[derive(Clone, Debug)]
pub enum DescriptorSet {
    Emulated(Arc<Mutex<DescriptorSetInner>>),
    ArgumentBuffer {
        buffer: metal::Buffer,
        offset: NSUInteger,
        encoder: metal::ArgumentEncoder,
        stage_flags: pso::ShaderStageFlags,
    }
}
unsafe impl Send for DescriptorSet {}
unsafe impl Sync for DescriptorSet {}

#[derive(Debug)]
pub struct DescriptorSetInner {
    pub(crate) layout: Vec<pso::DescriptorSetLayoutBinding>, // TODO: maybe don't clone?
    pub(crate) bindings: HashMap<usize, DescriptorSetBinding>,
}
unsafe impl Send for DescriptorSetInner {}

#[derive(Debug)]
pub enum DescriptorSetBinding {
    Sampler(Vec<Option<metal::SamplerState>>),
    Image(Vec<Option<(metal::Texture, image::ImageLayout)>>),
    //UniformTexelBuffer,
    //StorageTexelBuffer,
    Buffer(Vec<Option<(metal::Buffer, u64)>>),
    //InputAttachment(Vec<(metal::Texture, image::ImageLayout)>),
}

#[derive(Debug)]
pub struct Memory {
    pub(crate) heap: MemoryHeap,
    pub(crate) size: u64,
    pub(crate) allocations: Arc<Mutex<MemoryAllocations>>,
    pub(crate) mapping: Mutex<Option<MemoryMapping>>,
}

impl Memory {
    pub(crate) fn new(heap: MemoryHeap, size: u64) -> Self {
        Memory {
            heap,
            size,
            allocations: Arc::new(Mutex::new(MemoryAllocations {
                starts: BTreeMap::new(),
                ends: BTreeMap::new(),
            })),
            mapping: Mutex::new(None),
        }
    }
}

#[derive(Debug)]
pub(crate) struct MemoryMapping {
    pub(crate) range: Range<u64>,
    pub(crate) buffer: metal::Buffer,
    pub(crate) location: NSUInteger,
    pub(crate) length: NSUInteger,
}

#[derive(Debug)]
pub(crate) struct MemoryAllocations {
    starts: BTreeMap<u64, (u64, metal::Buffer)>,
    ends: BTreeMap<u64, (u64, metal::Buffer)>,
}

impl MemoryAllocations {
    pub(crate) fn find(&self, range: Range<u64>) -> Vec<(Range<u64>, metal::Buffer)> {
        // Get all unique buffers that intersects specified range
        let mut buffers = Vec::new();
        buffers.extend(self.starts.range(range.clone()).map(|(&start, &(end, ref b))| (start .. end, b.clone())));
        let range = (Bound::Excluded(range.start), Bound::Included(range.end));
        buffers.extend(self.ends.range(range).map(|(&end, &(start, ref b))| (start .. end, b.clone())));
        buffers.sort_unstable_by_key(|&(_, ref b)| b.as_ptr());
        buffers.dedup_by_key(|&mut (_, ref b)| b.as_ptr());
        buffers
    }

    pub(crate) fn insert(&mut self, range: Range<u64>, buffer: metal::Buffer) {
        self.starts.insert(range.start, (range.end, buffer.clone()));
        self.ends.insert(range.end, (range.start, buffer));
    }

    pub(crate) fn remove(&mut self, range: Range<u64>) {
        self.starts.remove(&range.start);
        self.ends.remove(&range.end);
    }
}

#[derive(Debug)]
pub(crate) enum MemoryHeap {
    Emulated { memory_type: usize },
    Native(metal::Heap),
}

#[derive(Debug)]
pub struct UnboundBuffer {
    pub(crate) size: u64,
}

unsafe impl Send for UnboundBuffer {}
unsafe impl Sync for UnboundBuffer {}

#[derive(Debug)]
pub struct UnboundImage {
    pub desc: metal::TextureDescriptor,
    pub bytes_per_block: u8,
    // Dimension of a texel block (compressed formats).
    pub block_dim: (u8, u8),
}
unsafe impl Send for UnboundImage {}
unsafe impl Sync for UnboundImage {}

#[derive(Debug)]
pub struct Fence(pub Arc<Mutex<bool>>);

pub unsafe fn objc_err_description(object: *mut objc::runtime::Object) -> String {
    let description: *mut objc::runtime::Object = msg_send![object, localizedDescription];
    let utf16_len: NSUInteger = msg_send![description, length];
    let utf8_bytes: NSUInteger = msg_send![description, lengthOfBytesUsingEncoding: 4 as NSUInteger];
    let mut bytes = Vec::with_capacity(utf8_bytes as usize);
    bytes.set_len(utf8_bytes as usize);
    let success: objc::runtime::BOOL = msg_send![description,
        getBytes: bytes.as_mut_ptr()
        maxLength: utf8_bytes
        usedLength: ptr::null_mut::<NSUInteger>()
        encoding: 4 as NSUInteger
        options: 0 as c_int
        range: NSRange  { location: 0, length: utf16_len }
        remainingRange: ptr::null_mut::<NSRange>()
    ];
    if success == objc::runtime::YES {
        String::from_utf8_unchecked(bytes)
    } else {
        panic!("failed to get object description")
    }
}

extern "C" {
    #[allow(dead_code)]
    pub fn dispatch_semaphore_wait(
        semaphore: *mut c_void,
        timeout: u64,
    ) -> c_long;

    pub fn dispatch_semaphore_signal(
        semaphore: *mut c_void,
    ) -> c_long;

    pub fn dispatch_semaphore_create(
        value: c_long,
    ) -> *mut c_void;

    pub fn dispatch_release(
        object: *mut c_void,
    );
}
<commit_msg>mtl: try fixing build<commit_after>use {Backend};

use std::collections::{Bound, BTreeMap, HashMap};
use std::sync::{Arc, Mutex};
use std::ops::Range;
use std::os::raw::{c_void, c_long, c_int};
use std::ptr;

use hal::{self, image, pass, pso};

use cocoa::foundation::{NSRange, NSUInteger};
use foreign_types::ForeignType;
use metal::{self, MTLPrimitiveType};
use objc;
use spirv_cross::{msl, spirv};

/// Shader module can be compiled in advance if it's resource bindings do not
/// depend on pipeline layout, in which case the value would become `Compiled`.
#[derive(Debug)]
pub enum ShaderModule {
    Compiled {
        library: metal::Library,
        entry_point_map: HashMap<String, spirv::EntryPoint>,
    },
    Raw(Vec<u8>),
}

unsafe impl Send for ShaderModule {}
unsafe impl Sync for ShaderModule {}

#[derive(Debug)]
pub struct RenderPass {
    pub(crate) desc: metal::RenderPassDescriptor,
    pub(crate) attachments: Vec<pass::Attachment>,
    pub(crate) num_colors: usize,
}

unsafe impl Send for RenderPass {}
unsafe impl Sync for RenderPass {}

#[derive(Debug)]
pub struct FrameBuffer(pub(crate) metal::RenderPassDescriptor);

unsafe impl Send for FrameBuffer {}
unsafe impl Sync for FrameBuffer {}

#[derive(Debug)]
pub struct PipelineLayout {
    // First vertex buffer index to be used by attributes
    pub(crate) attribute_buffer_index: u32,
    pub(crate) res_overrides: HashMap<msl::ResourceBindingLocation, msl::ResourceBinding>,
}

#[derive(Debug)]
pub struct GraphicsPipeline {
    // we hold the compiled libraries here for now
    // TODO: move to some cache in `Device`
    pub(crate) vs_lib: metal::Library,
    pub(crate) fs_lib: Option<metal::Library>,
    pub(crate) raw: metal::RenderPipelineState,
    pub(crate) primitive_type: MTLPrimitiveType,
    pub(crate) attribute_buffer_index: u32,
    pub(crate) depth_stencil_state: Option<metal::DepthStencilState>,
}

unsafe impl Send for GraphicsPipeline {}
unsafe impl Sync for GraphicsPipeline {}

#[derive(Debug)]
pub struct ComputePipeline {
    pub(crate) cs_lib: metal::Library,
    pub(crate) raw: metal::ComputePipelineState,
    pub(crate) work_group_size: metal::MTLSize,
}

unsafe impl Send for ComputePipeline {}
unsafe impl Sync for ComputePipeline {}

#[derive(Debug)]
pub struct Image {
    pub(crate) raw: metal::Texture,
    pub(crate) bytes_per_block: u8,
    // Dimension of a texel block (compressed formats).
    pub(crate) block_dim: (u8, u8),
}

unsafe impl Send for Image {}
unsafe impl Sync for Image {}

#[derive(Debug)]
pub struct BufferView {}

#[derive(Debug)]
pub struct ImageView(pub(crate) metal::Texture);

unsafe impl Send for ImageView {}
unsafe impl Sync for ImageView {}

#[derive(Debug)]
pub struct Sampler(pub(crate) metal::SamplerState);

unsafe impl Send for Sampler {}
unsafe impl Sync for Sampler {}

#[derive(Debug)]
pub struct Semaphore(pub(crate) *mut c_void);

unsafe impl Send for Semaphore {}
unsafe impl Sync for Semaphore {}

#[derive(Debug)]
pub struct Buffer {
    pub(crate) raw: metal::Buffer,
    pub(crate) allocations: Option<Arc<Mutex<MemoryAllocations>>>,
    pub(crate) offset: u64,
}

unsafe impl Send for Buffer {}
unsafe impl Sync for Buffer {}

#[derive(Debug)]
pub enum DescriptorPool {
    Emulated,
    ArgumentBuffer {
        buffer: metal::Buffer,
        total_size: NSUInteger,
        offset: NSUInteger,
    }
}
//TODO: re-evaluate Send/Sync here
unsafe impl Send for DescriptorPool {}
unsafe impl Sync for DescriptorPool {}

impl hal::DescriptorPool<Backend> for DescriptorPool {
    fn allocate_set(&mut self, layout: &DescriptorSetLayout) -> DescriptorSet {
        match *self {
            DescriptorPool::Emulated => {
                let layout_bindings = match layout {
                    &DescriptorSetLayout::Emulated(ref bindings) => bindings,
                    _ => panic!("Incompatible descriptor set layout type"),
                };

                let bindings = layout_bindings.iter().map(|layout| {
                    let binding = match layout.ty {
                        pso::DescriptorType::Sampler => {
                            DescriptorSetBinding::Sampler(vec![None; layout.count])
                        }
                        pso::DescriptorType::SampledImage |
                        pso::DescriptorType::StorageImage => {
                            DescriptorSetBinding::Image(vec![None; layout.count])
                        }
                        pso::DescriptorType::UniformBuffer |
                        pso::DescriptorType::StorageBuffer => {
                            DescriptorSetBinding::Buffer(vec![None; layout.count])
                        }
                        pso::DescriptorType::UniformTexelBuffer |
                        pso::DescriptorType::StorageTexelBuffer |
                        pso::DescriptorType::CombinedImageSampler |
                        pso::DescriptorType::InputAttachment => unimplemented!()
                    };
                    (layout.binding, binding)
                }).collect();

                let inner = DescriptorSetInner {
                    layout: layout_bindings.to_vec(),
                    bindings,
                };
                DescriptorSet::Emulated(Arc::new(Mutex::new(inner)))
            }
            DescriptorPool::ArgumentBuffer { ref buffer, total_size, ref mut offset } => {
                let (encoder, stage_flags) = match layout {
                    &DescriptorSetLayout::ArgumentBuffer(ref encoder, stages) => (encoder, stages),
                    _ => panic!("Incompatible descriptor set layout type"),
                };

                let cur_offset = *offset;
                *offset += encoder.encoded_length();
                assert!(*offset <= total_size);

                DescriptorSet::ArgumentBuffer {
                    buffer: buffer.clone(),
                    offset: cur_offset,
                    encoder: encoder.clone(),
                    stage_flags,
                }
            }
        }
    }

    fn reset(&mut self) {
        unimplemented!()
    }
}

#[derive(Debug)]
pub enum DescriptorSetLayout {
    Emulated(Vec<pso::DescriptorSetLayoutBinding>),
    ArgumentBuffer(metal::ArgumentEncoder, pso::ShaderStageFlags),
}
unsafe impl Send for DescriptorSetLayout {}
unsafe impl Sync for DescriptorSetLayout {}

#[derive(Clone, Debug)]
pub enum DescriptorSet {
    Emulated(Arc<Mutex<DescriptorSetInner>>),
    ArgumentBuffer {
        buffer: metal::Buffer,
        offset: NSUInteger,
        encoder: metal::ArgumentEncoder,
        stage_flags: pso::ShaderStageFlags,
    }
}
unsafe impl Send for DescriptorSet {}
unsafe impl Sync for DescriptorSet {}

#[derive(Debug)]
pub struct DescriptorSetInner {
    pub(crate) layout: Vec<pso::DescriptorSetLayoutBinding>, // TODO: maybe don't clone?
    pub(crate) bindings: HashMap<usize, DescriptorSetBinding>,
}
unsafe impl Send for DescriptorSetInner {}

#[derive(Debug)]
pub enum DescriptorSetBinding {
    Sampler(Vec<Option<metal::SamplerState>>),
    Image(Vec<Option<(metal::Texture, image::ImageLayout)>>),
    //UniformTexelBuffer,
    //StorageTexelBuffer,
    Buffer(Vec<Option<(metal::Buffer, u64)>>),
    //InputAttachment(Vec<(metal::Texture, image::ImageLayout)>),
}

#[derive(Debug)]
pub struct Memory {
    pub(crate) heap: MemoryHeap,
    pub(crate) size: u64,
    pub(crate) allocations: Arc<Mutex<MemoryAllocations>>,
    pub(crate) mapping: Mutex<Option<MemoryMapping>>,
}

impl Memory {
    pub(crate) fn new(heap: MemoryHeap, size: u64) -> Self {
        Memory {
            heap,
            size,
            allocations: Arc::new(Mutex::new(MemoryAllocations {
                starts: BTreeMap::new(),
                ends: BTreeMap::new(),
            })),
            mapping: Mutex::new(None),
        }
    }
}

#[derive(Debug)]
pub(crate) struct MemoryMapping {
    pub(crate) range: Range<u64>,
    pub(crate) buffer: metal::Buffer,
    pub(crate) location: NSUInteger,
    pub(crate) length: NSUInteger,
}

#[derive(Debug)]
pub(crate) struct MemoryAllocations {
    starts: BTreeMap<u64, (u64, metal::Buffer)>,
    ends: BTreeMap<u64, (u64, metal::Buffer)>,
}

impl MemoryAllocations {
    pub(crate) fn find(&self, range: Range<u64>) -> Vec<(Range<u64>, metal::Buffer)> {
        // Get all unique buffers that intersects specified range
        let mut buffers = Vec::new();
        buffers.extend(self.starts.range(range.clone()).map(|(&start, &(end, ref b))| (start .. end, b.clone())));
        let range = (Bound::Excluded(range.start), Bound::Included(range.end));
        buffers.extend(self.ends.range(range).map(|(&end, &(start, ref b))| (start .. end, b.clone())));
        buffers.sort_unstable_by_key(|&(_, ref b)| b.as_ptr());
        buffers.dedup_by_key(|&mut (_, ref b)| b.as_ptr());
        buffers
    }

    pub(crate) fn insert(&mut self, range: Range<u64>, buffer: metal::Buffer) {
        self.starts.insert(range.start, (range.end, buffer.clone()));
        self.ends.insert(range.end, (range.start, buffer));
    }

    pub(crate) fn remove(&mut self, range: Range<u64>) {
        self.starts.remove(&range.start);
        self.ends.remove(&range.end);
    }
}

#[derive(Debug)]
pub(crate) enum MemoryHeap {
    Emulated { memory_type: usize },
    Native(metal::Heap),
}

#[derive(Debug)]
pub struct UnboundBuffer {
    pub(crate) size: u64,
}

unsafe impl Send for UnboundBuffer {}
unsafe impl Sync for UnboundBuffer {}

#[derive(Debug)]
pub struct UnboundImage {
    pub desc: metal::TextureDescriptor,
    pub bytes_per_block: u8,
    // Dimension of a texel block (compressed formats).
    pub block_dim: (u8, u8),
}
unsafe impl Send for UnboundImage {}
unsafe impl Sync for UnboundImage {}

#[derive(Debug)]
pub struct Fence(pub Arc<Mutex<bool>>);

pub unsafe fn objc_err_description(object: *mut objc::runtime::Object) -> String {
    let description: *mut objc::runtime::Object = msg_send![object, localizedDescription];
    let utf16_len: NSUInteger = msg_send![description, length];
    let utf8_bytes: NSUInteger = msg_send![description, lengthOfBytesUsingEncoding: 4 as NSUInteger];
    let mut bytes = Vec::with_capacity(utf8_bytes as usize);
    bytes.set_len(utf8_bytes as usize);
    let success: objc::runtime::BOOL = msg_send![description,
        getBytes: bytes.as_mut_ptr()
        maxLength: utf8_bytes
        usedLength: ptr::null_mut::<NSUInteger>()
        encoding: 4 as NSUInteger
        options: 0 as c_int
        range: NSRange  { location: 0, length: utf16_len }
        remainingRange: ptr::null_mut::<NSRange>()
    ];
    if success == objc::runtime::YES {
        String::from_utf8_unchecked(bytes)
    } else {
        panic!("failed to get object description")
    }
}

extern "C" {
    #[allow(dead_code)]
    pub fn dispatch_semaphore_wait(
        semaphore: *mut c_void,
        timeout: u64,
    ) -> c_long;

    pub fn dispatch_semaphore_signal(
        semaphore: *mut c_void,
    ) -> c_long;

    pub fn dispatch_semaphore_create(
        value: c_long,
    ) -> *mut c_void;

    pub fn dispatch_release(
        object: *mut c_void,
    );
}
<|endoftext|>


<commit_before>use std::time::{SystemTime, UNIX_EPOCH};

use cairo::ImageSurface;
use cairo_sys;
use glib::translate::ToGlibPtr;
use wlroots::{project_box, Area, CompositorHandle, OutputHandle, OutputHandler,
              OutputLayoutHandle, Renderer, Size, WL_SHM_FORMAT_ARGB8888};

use awesome::{Drawin, Objectable, DRAWINS_HANDLE, LUA};
use compositor::{Server, View};
use rlua::{self, AnyUserData, Lua};

pub struct Output;

impl OutputHandler for Output {
    fn on_frame(&mut self, compositor: CompositorHandle, output: OutputHandle) {
        with_handles!([(compositor: {compositor}), (output: {output})] => {
            let state: &mut Server = compositor.data.downcast_mut().unwrap();
            let Server { ref mut layout,
                         ref mut views,
                         .. } = *state;
            let renderer = compositor.renderer.as_mut().expect("gles2 disabled");
            let mut renderer = renderer.render(output, None);
            renderer.clear([0.25, 0.25, 0.25, 1.0]);
            render_views(&mut renderer, layout, views);
            LUA.with(|lua| {
                let mut lua = lua.borrow_mut();
                match render_drawins(&mut *lua, &mut renderer) {
                    Ok(_) => {},
                    Err(err) => {
                        warn!("Error rendering drawins: {:#?}", err);
                    }
                }
            });
        }).unwrap();
    }
}

/// Render all of the client views.
fn render_views(renderer: &mut Renderer, layout: &mut OutputLayoutHandle, views: &mut [View]) {
    for view in views {
        let mut surface = view.shell.surface();
        with_handles!([(surface: {surface}),
                       (layout: {&mut *layout})] => {
            let (width, height) = surface.current_state().size();
            let (render_width, render_height) =
                (width * renderer.output.scale() as i32,
                 height * renderer.output.scale() as i32);
            let render_box = Area::new(view.origin,
                                       Size::new(render_width,
                                                 render_height));
            if layout.intersects(renderer.output, render_box) {
                let transform = renderer.output.get_transform().invert();
                let matrix = project_box(render_box,
                                         transform,
                                         0.0,
                                         renderer.output
                                         .transform_matrix());
                renderer.render_texture_with_matrix(&surface.texture(),
                                                    matrix);
                let start = SystemTime::now();
                let now = start.duration_since(UNIX_EPOCH)
                    .expect("Time went backwards");
                surface.send_frame_done(now);
            }
        }).expect("Could not render views")
    }
}

/// Render all of the drawins provided by Lua.
fn render_drawins(lua: &Lua, renderer: &mut Renderer) -> rlua::Result<()> {
    let drawins = lua.named_registry_value::<Vec<AnyUserData>>(DRAWINS_HANDLE)?;
    for drawin in drawins {
        let mut drawin = Drawin::cast(drawin.into())?;
        if !drawin.get_visible()? {
            continue
        }
        let geometry = drawin.get_geometry()?;
        let drawable = drawin.drawable()?;
        let mut drawable_state = drawable.state()?;
        let surface = match drawable_state.surface.as_mut() {
            Some(surface) => surface,
            None => continue
        };
        let Area { size: Size { width, height },
                   .. } = geometry;
        let data = get_data(surface);
        let texture = renderer.create_texture_from_pixels(WL_SHM_FORMAT_ARGB8888,
                                                          (width * 4) as _,
                                                          width as _,
                                                          height as _,
                                                          data)
                              .expect("Could not allocate texture");
        let transform_matrix = renderer.output.transform_matrix();
        let inverted_transform = renderer.output.get_transform().invert();
        let matrix = project_box(geometry, inverted_transform, 0.0, transform_matrix);
        renderer.render_texture_with_matrix(&texture, matrix);
    }
    Ok(())
}

/// Get the data associated with an ImageSurface.
fn get_data(surface: &mut ImageSurface) -> &[u8] {
    use std::slice;
    // FIXME
    // This is a bad hack because we have multiple mutable pointers to the
    // image data that cairo-rs will not let us borrow it.
    //
    // Since this is single threaded it's not the _biggest_ deal, but this should
    // really be safe.
    //
    // TODO
    // In order to do so, there needs to be exactly one reference count to the
    // image surface. uncomment the following code in order to debug how many
    // there are. Once it reaches 0 _always_, this can be removed.
    //
    //unsafe { println!("count {}",
    //cairo_sys::cairo_surface_get_reference_count(surface.to_glib_none().
    //0 as _))}
    unsafe {
        let len = surface.get_stride() as usize * surface.get_height() as usize;
        let surface = surface.to_glib_none().0;
        slice::from_raw_parts(cairo_sys::cairo_image_surface_get_data(surface as _), len)
    }
}
<commit_msg>Fixed comment in get_data<commit_after>use std::time::{SystemTime, UNIX_EPOCH};

use cairo::ImageSurface;
use cairo_sys;
use glib::translate::ToGlibPtr;
use wlroots::{project_box, Area, CompositorHandle, OutputHandle, OutputHandler,
              OutputLayoutHandle, Renderer, Size, WL_SHM_FORMAT_ARGB8888};

use awesome::{Drawin, Objectable, DRAWINS_HANDLE, LUA};
use compositor::{Server, View};
use rlua::{self, AnyUserData, Lua};

pub struct Output;

impl OutputHandler for Output {
    fn on_frame(&mut self, compositor: CompositorHandle, output: OutputHandle) {
        with_handles!([(compositor: {compositor}), (output: {output})] => {
            let state: &mut Server = compositor.data.downcast_mut().unwrap();
            let Server { ref mut layout,
                         ref mut views,
                         .. } = *state;
            let renderer = compositor.renderer.as_mut().expect("gles2 disabled");
            let mut renderer = renderer.render(output, None);
            renderer.clear([0.25, 0.25, 0.25, 1.0]);
            render_views(&mut renderer, layout, views);
            LUA.with(|lua| {
                let mut lua = lua.borrow_mut();
                match render_drawins(&mut *lua, &mut renderer) {
                    Ok(_) => {},
                    Err(err) => {
                        warn!("Error rendering drawins: {:#?}", err);
                    }
                }
            });
        }).unwrap();
    }
}

/// Render all of the client views.
fn render_views(renderer: &mut Renderer, layout: &mut OutputLayoutHandle, views: &mut [View]) {
    for view in views {
        let mut surface = view.shell.surface();
        with_handles!([(surface: {surface}),
                       (layout: {&mut *layout})] => {
            let (width, height) = surface.current_state().size();
            let (render_width, render_height) =
                (width * renderer.output.scale() as i32,
                 height * renderer.output.scale() as i32);
            let render_box = Area::new(view.origin,
                                       Size::new(render_width,
                                                 render_height));
            if layout.intersects(renderer.output, render_box) {
                let transform = renderer.output.get_transform().invert();
                let matrix = project_box(render_box,
                                         transform,
                                         0.0,
                                         renderer.output
                                         .transform_matrix());
                renderer.render_texture_with_matrix(&surface.texture(),
                                                    matrix);
                let start = SystemTime::now();
                let now = start.duration_since(UNIX_EPOCH)
                    .expect("Time went backwards");
                surface.send_frame_done(now);
            }
        }).expect("Could not render views")
    }
}

/// Render all of the drawins provided by Lua.
fn render_drawins(lua: &Lua, renderer: &mut Renderer) -> rlua::Result<()> {
    let drawins = lua.named_registry_value::<Vec<AnyUserData>>(DRAWINS_HANDLE)?;
    for drawin in drawins {
        let mut drawin = Drawin::cast(drawin.into())?;
        if !drawin.get_visible()? {
            continue
        }
        let geometry = drawin.get_geometry()?;
        let drawable = drawin.drawable()?;
        let mut drawable_state = drawable.state()?;
        let surface = match drawable_state.surface.as_mut() {
            Some(surface) => surface,
            None => continue
        };
        let Area { size: Size { width, height },
                   .. } = geometry;
        let data = get_data(surface);
        let texture = renderer.create_texture_from_pixels(WL_SHM_FORMAT_ARGB8888,
                                                          (width * 4) as _,
                                                          width as _,
                                                          height as _,
                                                          data)
                              .expect("Could not allocate texture");
        let transform_matrix = renderer.output.transform_matrix();
        let inverted_transform = renderer.output.get_transform().invert();
        let matrix = project_box(geometry, inverted_transform, 0.0, transform_matrix);
        renderer.render_texture_with_matrix(&texture, matrix);
    }
    Ok(())
}

/// Get the data associated with an ImageSurface.
fn get_data(surface: &mut ImageSurface) -> &[u8] {
    use std::slice;
    // NOTE This is safe to do because there's one thread.
    //
    // We know Lua is not modifying it because it's not running.
    //
    // Otherwise we'd need to make a copy of the buffer. This ensure we
    // don't need to do that.
    unsafe {
        let len = surface.get_stride() as usize * surface.get_height() as usize;
        let surface = surface.to_glib_none().0;
        slice::from_raw_parts(cairo_sys::cairo_image_surface_get_data(surface as _), len)
    }
}
<|endoftext|>


<commit_before>//! Available languages and related data.

use std::fmt;

macro_rules! fiant_linguae {
    ( $($lang:ident, $bounds:expr, $code:expr;)* ) => {
        fiant_linguae! { $($lang, $bounds, $code);* }
    };
    ( $($lang:ident, $bounds:expr, $code:expr);* ) => {
        /// The set of languages available for hyphenation.
        #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
        pub enum Language {
            $( $lang, )*
        }

        impl Language {
            /// The default number of characters from the start and end of a word
            /// where breaks may not occur.
            pub fn minima(&self) -> (usize, usize) {
                match *self {
                    $( Language::$lang => $bounds, )*
                }
            }

            /// The TeX language code.
            pub fn code(&self) -> &'static str {
                match *self {
                    $( Language::$lang => $code, )*
                }
            }
        }

        impl fmt::Display for Language {
            fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{:?}", *self)
            }
        }
    }
}

// NOTE: These hyphenation bounds were taken directly from the relevant TeX
// packages, but it is not entirely clear how well they map to the notion of
// Unicode `char` in Rust.
//
// In the worst case, a language featuring graphemes larger than 1 `char` may
// set boundaries mid-grapheme. This should be of no practical consequence,
// since well-formed hyphenation patterns only match full graphemes; moreover,
// well-behaved hyphenators are expected to validate hyphenation opportunities,
// discarding any which arise outside `char` boundaries.
fiant_linguae! {
    Afrikaans,              (1, 2),     "af";
    Armenian,               (1, 2),     "hy";
    Assamese,               (1, 1),     "as";
    Basque,                 (2, 2),     "eu";
    Belarusian,             (2, 2),     "be";
    Bengali,                (1, 1),     "bn";
    Bulgarian,              (2, 2),     "bg";
    Catalan,                (2, 2),     "ca";
    Chinese,                (1, 1),     "zh-latn-pinyin";
    Coptic,                 (1, 1),     "cop";
    Croatian,               (2, 2),     "hr";
    Czech,                  (2, 3),     "cs";
    Danish,                 (2, 2),     "da";
    Dutch,                  (2, 2),     "nl";
    EnglishGB,              (2, 3),     "en-gb";
    EnglishUS,              (2, 3),     "en-us";
    Esperanto,              (2, 2),     "eo";
    Estonian,               (2, 3),     "et";
    Ethiopic,               (1, 1),     "mul-ethi";
    Finnish,                (2, 2),     "fi";
    French,                 (2, 3),     "fr";
    Friulan,                (2, 2),     "fur";
    Galician,               (2, 2),     "gl";
    Georgian,               (1, 2),     "ka";
    German1901,             (2, 2),     "de-1901";
    German1996,             (2, 2),     "de-1996";
    GermanSwiss,            (2, 2),     "de-ch-1901";
    GreekAncient,           (1, 1),     "grc";
    GreekMono,              (1, 1),     "el-monoton";
    GreekPoly,              (1, 1),     "el-polyton";
    Gujarati,               (1, 1),     "gu";
    Hindi,                  (1, 1),     "hi";
    Hungarian,              (2, 2),     "hu";
    Icelandic,              (2, 2),     "is";
    Indonesian,             (2, 2),     "id";
    Interlingua,            (2, 2),     "ia";
    Irish,                  (2, 3),     "ga";
    Italian,                (2, 2),     "it";
    Kannada,                (1, 1),     "kn";
    Kurmanji,               (2, 2),     "kmr";
    Latin,                  (2, 2),     "la";
    LatinClassic,           (2, 2),     "la-x-classic";
    LatinLiturgical,        (2, 2),     "la-x-liturgic";
    Latvian,                (2, 2),     "lv";
    Lithuanian,             (2, 2),     "lt";
    Malayalam,              (1, 1),     "ml";
    Marathi,                (1, 1),     "mr";
    Mongolian,              (2, 2),     "mn-cyrl";
    NorwegianBokmal,        (2, 2),     "nb";
    NorwegianNynorsk,       (2, 2),     "nn";
    Occitan,                (2, 2),     "oc";
    Oriya,                  (1, 1),     "or";
    Pali,                   (1, 2),     "pi";
    Panjabi,                (1, 1),     "pa";
    Piedmontese,            (2, 2),     "pms";
    Polish,                 (2, 2),     "pl";
    Portuguese,             (2, 3),     "pt";
    Romanian,               (2, 2),     "ro";
    Romansh,                (2, 2),     "rm";
    Russian,                (2, 2),     "ru";
    Sanskrit,               (1, 3),     "sa";
    SerbianCyrillic,        (2, 2),     "sr-cyrl";
    SerbocroatianCyrillic,  (2, 2),     "sh-cyrl";
    SerbocroatianLatin,     (2, 2),     "sh-latn";
    SlavonicChurch,         (1, 2),     "cu";
    Slovak,                 (2, 3),     "sk";
    Slovenian,              (2, 2),     "sl";
    Spanish,                (2, 2),     "es";
    Swedish,                (2, 2),     "sv";
    Tamil,                  (1, 1),     "ta";
    Telugu,                 (1, 1),     "te";
    Thai,                   (2, 3),     "th";
    Turkish,                (2, 2),     "tr";
    Turkmen,                (2, 2),     "tk";
    Ukrainian,              (2, 2),     "uk";
    Uppersorbian,           (2, 2),     "hsb";
    Welsh,                  (2, 3),     "cy";
}
<commit_msg>Specify format of Language::code()<commit_after>//! Available languages and related data.

use std::fmt;

macro_rules! fiant_linguae {
    ( $($lang:ident, $bounds:expr, $code:expr;)* ) => {
        fiant_linguae! { $($lang, $bounds, $code);* }
    };
    ( $($lang:ident, $bounds:expr, $code:expr);* ) => {
        /// The set of languages available for hyphenation.
        #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
        pub enum Language {
            $( $lang, )*
        }

        impl Language {
            /// The default number of characters from the start and end of a word
            /// where breaks may not occur.
            pub fn minima(&self) -> (usize, usize) {
                match *self {
                    $( Language::$lang => $bounds, )*
                }
            }

            /// The [BCP 47](https://tools.ietf.org/html/bcp47) tag for this language.
            pub fn code(&self) -> &'static str {
                match *self {
                    $( Language::$lang => $code, )*
                }
            }
        }

        impl fmt::Display for Language {
            fn fmt(&self, f : &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{:?}", *self)
            }
        }
    }
}

// NOTE: These hyphenation bounds were taken directly from the relevant TeX
// packages, but it is not entirely clear how well they map to the notion of
// Unicode `char` in Rust.
//
// In the worst case, a language featuring graphemes larger than 1 `char` may
// set boundaries mid-grapheme. This should be of no practical consequence,
// since well-formed hyphenation patterns only match full graphemes; moreover,
// well-behaved hyphenators are expected to validate hyphenation opportunities,
// discarding any which arise outside `char` boundaries.
fiant_linguae! {
    Afrikaans,              (1, 2),     "af";
    Armenian,               (1, 2),     "hy";
    Assamese,               (1, 1),     "as";
    Basque,                 (2, 2),     "eu";
    Belarusian,             (2, 2),     "be";
    Bengali,                (1, 1),     "bn";
    Bulgarian,              (2, 2),     "bg";
    Catalan,                (2, 2),     "ca";
    Chinese,                (1, 1),     "zh-latn-pinyin";
    Coptic,                 (1, 1),     "cop";
    Croatian,               (2, 2),     "hr";
    Czech,                  (2, 3),     "cs";
    Danish,                 (2, 2),     "da";
    Dutch,                  (2, 2),     "nl";
    EnglishGB,              (2, 3),     "en-gb";
    EnglishUS,              (2, 3),     "en-us";
    Esperanto,              (2, 2),     "eo";
    Estonian,               (2, 3),     "et";
    Ethiopic,               (1, 1),     "mul-ethi";
    Finnish,                (2, 2),     "fi";
    French,                 (2, 3),     "fr";
    Friulan,                (2, 2),     "fur";
    Galician,               (2, 2),     "gl";
    Georgian,               (1, 2),     "ka";
    German1901,             (2, 2),     "de-1901";
    German1996,             (2, 2),     "de-1996";
    GermanSwiss,            (2, 2),     "de-ch-1901";
    GreekAncient,           (1, 1),     "grc";
    GreekMono,              (1, 1),     "el-monoton";
    GreekPoly,              (1, 1),     "el-polyton";
    Gujarati,               (1, 1),     "gu";
    Hindi,                  (1, 1),     "hi";
    Hungarian,              (2, 2),     "hu";
    Icelandic,              (2, 2),     "is";
    Indonesian,             (2, 2),     "id";
    Interlingua,            (2, 2),     "ia";
    Irish,                  (2, 3),     "ga";
    Italian,                (2, 2),     "it";
    Kannada,                (1, 1),     "kn";
    Kurmanji,               (2, 2),     "kmr";
    Latin,                  (2, 2),     "la";
    LatinClassic,           (2, 2),     "la-x-classic";
    LatinLiturgical,        (2, 2),     "la-x-liturgic";
    Latvian,                (2, 2),     "lv";
    Lithuanian,             (2, 2),     "lt";
    Malayalam,              (1, 1),     "ml";
    Marathi,                (1, 1),     "mr";
    Mongolian,              (2, 2),     "mn-cyrl";
    NorwegianBokmal,        (2, 2),     "nb";
    NorwegianNynorsk,       (2, 2),     "nn";
    Occitan,                (2, 2),     "oc";
    Oriya,                  (1, 1),     "or";
    Pali,                   (1, 2),     "pi";
    Panjabi,                (1, 1),     "pa";
    Piedmontese,            (2, 2),     "pms";
    Polish,                 (2, 2),     "pl";
    Portuguese,             (2, 3),     "pt";
    Romanian,               (2, 2),     "ro";
    Romansh,                (2, 2),     "rm";
    Russian,                (2, 2),     "ru";
    Sanskrit,               (1, 3),     "sa";
    SerbianCyrillic,        (2, 2),     "sr-cyrl";
    SerbocroatianCyrillic,  (2, 2),     "sh-cyrl";
    SerbocroatianLatin,     (2, 2),     "sh-latn";
    SlavonicChurch,         (1, 2),     "cu";
    Slovak,                 (2, 3),     "sk";
    Slovenian,              (2, 2),     "sl";
    Spanish,                (2, 2),     "es";
    Swedish,                (2, 2),     "sv";
    Tamil,                  (1, 1),     "ta";
    Telugu,                 (1, 1),     "te";
    Thai,                   (2, 3),     "th";
    Turkish,                (2, 2),     "tr";
    Turkmen,                (2, 2),     "tk";
    Ukrainian,              (2, 2),     "uk";
    Uppersorbian,           (2, 2),     "hsb";
    Welsh,                  (2, 3),     "cy";
}
<|endoftext|>


<commit_before>
use std::cmp;

type Rgba = [u8; 4];

fn minf(a: f32, b: f32) -> f32 { if a < b { a } else { b } }
fn maxf(a: f32, b: f32) -> f32 { if a > b { a } else { b } }
fn saturate(a: f32) -> f32 { maxf(minf(a, 1.0), 0.0) }
fn fnorm(a: u8) -> f32 { a as f32 / 255.0 }
fn bnorm(a: f32) -> u8 { (saturate(a) * 255.0) as u8 }

/*type Hsva = [u8; 4];

fn to_hsva(rgba: &Rgba) -> Hsva {
	let (r, g, b) = (fnorm(rgba[0]), fnorm(rgba[1]), fnorm(rgba[2]));
	let max = maxf(maxf(r , g), b);
	let min = minf(minf(r , g), b);
	let c = max - min;
	let h =
		if c == 0.0 {
			0.0
		} else {
			(if max == r {
				(g - b) / c
			} else if max == g {
				(b - r) / c + 2.0
			} else {
				(r - g) / c + 4.0
			}) / 6.0
		};

	let s = if max == 0.0 { 0.0 } else { c / max };
	[bnorm(h), bnorm(s), bnorm(max), rgba[3]]
}

fn to_rgba(hsva: &Hsva) -> Rgba {
	let v = fnorm(hsva[2]);
	let c = v * fnorm(hsva[3]);
	let h = fnorm(hsva[0]) * 6.0;
	let x = c * (1.0 - (h % 2.0 - 1.0).abs());
	let rgb1 =
		if h < 1.0 {
			(c, x, 0.0)
		} else if h < 2.0 {
			(x, c, 0.0)
		} else if h < 3.0 {
			(0.0, c, x)
		} else if h < 4.0 {
			(0.0, x, c)
		} else if h < 5.0 {
			(x, 0.0, c)
		} else {
			(c, 0.0, x)
		};
	let m = v - c;
	[bnorm(rgb1.0 + m),
	bnorm(rgb1.1 + m),
	bnorm(rgb1.2 + m),
	hsva[3]]
}*/

fn bc1_dist(a: &Rgba, b: &Rgba) -> u32 {
	fn bc1_dist_one(a: u8, b: u8) -> u32 {
		let x = a as i32 - b as i32;
		(x * x) as u32
	}
	bc1_dist_one(a[0], b[0]) +
	bc1_dist_one(a[1], b[1]) +
	bc1_dist_one(a[2], b[2])
}

fn bc1_total_dist(table: &[Rgba; 4], pixels: &[Rgba; 16]) -> u32 {
	let mut sum = 0u32;
	let mut max = 0u32;
	for pix in pixels.into_iter().rev() {
		let e = (0..4).into_iter().map(|x| bc1_dist(&table[x], pix)).min().unwrap();
		sum += e;
		max = cmp::max(max, e);
	}
	sum + max * 16
}

fn bc1_build_entry(min: &Rgba, max: &Rgba, index: usize) -> Rgba {
	let coefs = match index {
		0x0 => (3, 0),
		0x1 => (0, 3),
		0x2 => (2 ,1),
		_ => (1, 2)
	};
	[((coefs.1 * min[0] as u16 + coefs.0 * max[0] as u16) / 3) as u8,
	 ((coefs.1 * min[1] as u16 + coefs.0 * max[1] as u16) / 3) as u8,
	 ((coefs.1 * min[2] as u16 + coefs.0 * max[2] as u16) / 3) as u8,
	 ((coefs.1 * min[3] as u16 + coefs.0 * max[3] as u16) / 3) as u8]
}

fn bc1_build_table(min: &Rgba, max: &Rgba) -> [Rgba; 4] {
	let mut interps = [[0u8; 4]; 4];
	for i in 0..4 {
		interps[i] = bc1_build_entry(&min, &max, i);
	}
	interps
}

fn bc1_minmax(pixels: &[Rgba; 16]) -> (Rgba, Rgba) {
	let mut min = [u8::max_value(); 4];
	let mut max = [0u8; 4];
	for p in pixels.into_iter() {
		for i in 0..4 {
			min[i] = cmp::min(min[i], p[i]);
			max[i] = cmp::max(max[i], p[i]);
		}
	}
	(min, max)
}

fn bc1_extrapolate_endpoints(e: &(Rgba, Rgba)) -> (Rgba, Rgba) {
	let mut a = e.0;
	let mut b = e.1;
	for i in 0..3 {
		let f = (fnorm(e.0[i]) - fnorm(e.1[i])) * 1.5;
		a[i] = bnorm(fnorm(e.0[i]) - f);
		b[i] = bnorm(fnorm(e.1[i]) + f);
	}
	(a, b)
}

fn bc1_sort_endpoints(e: &(Rgba, Rgba)) -> (Rgba, Rgba) {
	if bc1_encode_endpoint(&e.0) > bc1_encode_endpoint(&e.1) {
		(e.1, e.0)
	} else {
		(e.0, e.1)
	}
}

fn bc1_build_endpoints(pixels: &[Rgba; 16], quality: u8) -> Vec<(Rgba, Rgba)> {
	let (min, max) = bc1_minmax(pixels);

	let mut out = Vec::new();
	out.push((min, max));

	if quality > 0 && min != max {
		for i in 0..15 {
			for j in (i + 1)..16 {
				let px = (pixels[i], pixels[j]);
				out.push(bc1_sort_endpoints(&px));
				if quality > 1 {
					out.push(bc1_sort_endpoints(&bc1_extrapolate_endpoints(&px)));
				}
			}
		}
	}
	out
}

fn bc1_encode_endpoint(pix: &Rgba) -> u16 {
	((pix[0] as u16 >> 3) << 11) |
	((pix[1] as u16 >> 2) << 5) |
	(pix[2] as u16 >> 3)
}

fn bc1_encode_pixel(table: &[Rgba; 4], pixels: &[Rgba; 16]) -> u32 {
	let mut mask = 0u32;
	for pix in pixels.into_iter().rev() {
		let best = (0..4).into_iter().min_by_key(|x| bc1_dist(&table[*x], pix)).unwrap() as u32;
		mask = (mask << 2) | (best & 0x03);
	}
	mask
}

fn bc1_encode_block(pixels: &[Rgba; 16], quality: u8) -> (u64, u32) {
	/*let (min, max) = bc1_build_endpoints(&pixels)[0];
	let table = bc1_build_table(&min, &max);*/

	let ((min, max), table) = bc1_build_endpoints(pixels, quality).iter()
		.map(|pts| (*pts, bc1_build_table(&pts.0, &pts.1)))
		.min_by_key(|tbl| bc1_total_dist(&tbl.1, pixels)).unwrap();

	let dist = bc1_total_dist(&table, pixels);

	let min = bc1_encode_endpoint(&min) as u64;
	let max = bc1_encode_endpoint(&max) as u64;

	let encoded = bc1_encode_pixel(&table, &pixels) as u64;

	((encoded << 32) | (min << 16) | max, dist)
}

pub fn bc1(image: &Vec<u8>, size: (usize, usize), quality: u8) -> Result<Vec<u8>, ()> {
	if !(size.0 % 4 == 0 && size.1 % 4 == 0) {
		return Err(());
	}

    let mut out = Vec::with_capacity(image.len() / 8);
    let mut total_dist = 0u32;

    let block_size = 4;
    let blk_count = (size.0 / block_size, size.1 / block_size);

   	for x in 0..blk_count.0 {
   		for y in 0..blk_count.1 {

   			let mut pixels = [[0u8; 4]; 16]; // No compile time constants
   			for px in 0..block_size {
   				for py in 0..block_size {
   					let x = x * block_size + px;
   					let y = y * block_size + py;

   					let pi = (x * size.0 + y) * 4; // in bytes
   					let pix = [image[pi], image[pi + 1], image[pi + 2], image[pi + 3]];

   					pixels[px * block_size + py] = pix;
   				}
   			}

   			let (mut encoded, dist) = bc1_encode_block(&pixels, quality);
   			total_dist += dist;

   			for _ in 0..8 {
   				out.push((encoded & 0xFF) as u8);
   				encoded >>= 8;
   			}
		}
	}
	//println!("per-pixel dist = {:?}", total_dist / (size.0 * size.1) as u32);
	Ok(out)
}
<commit_msg>Fixed crashes for non square images<commit_after>
use std::cmp;

type Rgba = [u8; 4];

fn minf(a: f32, b: f32) -> f32 { if a < b { a } else { b } }
fn maxf(a: f32, b: f32) -> f32 { if a > b { a } else { b } }
fn saturate(a: f32) -> f32 { maxf(minf(a, 1.0), 0.0) }
fn fnorm(a: u8) -> f32 { a as f32 / 255.0 }
fn bnorm(a: f32) -> u8 { (saturate(a) * 255.0) as u8 }

/*type Hsva = [u8; 4];

fn to_hsva(rgba: &Rgba) -> Hsva {
	let (r, g, b) = (fnorm(rgba[0]), fnorm(rgba[1]), fnorm(rgba[2]));
	let max = maxf(maxf(r , g), b);
	let min = minf(minf(r , g), b);
	let c = max - min;
	let h =
		if c == 0.0 {
			0.0
		} else {
			(if max == r {
				(g - b) / c
			} else if max == g {
				(b - r) / c + 2.0
			} else {
				(r - g) / c + 4.0
			}) / 6.0
		};

	let s = if max == 0.0 { 0.0 } else { c / max };
	[bnorm(h), bnorm(s), bnorm(max), rgba[3]]
}

fn to_rgba(hsva: &Hsva) -> Rgba {
	let v = fnorm(hsva[2]);
	let c = v * fnorm(hsva[3]);
	let h = fnorm(hsva[0]) * 6.0;
	let x = c * (1.0 - (h % 2.0 - 1.0).abs());
	let rgb1 =
		if h < 1.0 {
			(c, x, 0.0)
		} else if h < 2.0 {
			(x, c, 0.0)
		} else if h < 3.0 {
			(0.0, c, x)
		} else if h < 4.0 {
			(0.0, x, c)
		} else if h < 5.0 {
			(x, 0.0, c)
		} else {
			(c, 0.0, x)
		};
	let m = v - c;
	[bnorm(rgb1.0 + m),
	bnorm(rgb1.1 + m),
	bnorm(rgb1.2 + m),
	hsva[3]]
}*/

fn bc1_dist(a: &Rgba, b: &Rgba) -> u32 {
	fn bc1_dist_one(a: u8, b: u8) -> u32 {
		let x = a as i32 - b as i32;
		(x * x) as u32
	}
	bc1_dist_one(a[0], b[0]) +
	bc1_dist_one(a[1], b[1]) +
	bc1_dist_one(a[2], b[2])
}

fn bc1_total_dist(table: &[Rgba; 4], pixels: &[Rgba; 16]) -> u32 {
	let mut sum = 0u32;
	let mut max = 0u32;
	for pix in pixels.into_iter().rev() {
		let e = (0..4).into_iter().map(|x| bc1_dist(&table[x], pix)).min().unwrap();
		sum += e;
		max = cmp::max(max, e);
	}
	sum + max * 16
}

fn bc1_build_entry(min: &Rgba, max: &Rgba, index: usize) -> Rgba {
	let coefs = match index {
		0x0 => (3, 0),
		0x1 => (0, 3),
		0x2 => (2 ,1),
		_ => (1, 2)
	};
	[((coefs.1 * min[0] as u16 + coefs.0 * max[0] as u16) / 3) as u8,
	 ((coefs.1 * min[1] as u16 + coefs.0 * max[1] as u16) / 3) as u8,
	 ((coefs.1 * min[2] as u16 + coefs.0 * max[2] as u16) / 3) as u8,
	 ((coefs.1 * min[3] as u16 + coefs.0 * max[3] as u16) / 3) as u8]
}

fn bc1_build_table(min: &Rgba, max: &Rgba) -> [Rgba; 4] {
	let mut interps = [[0u8; 4]; 4];
	for i in 0..4 {
		interps[i] = bc1_build_entry(&min, &max, i);
	}
	interps
}

fn bc1_minmax(pixels: &[Rgba; 16]) -> (Rgba, Rgba) {
	let mut min = [u8::max_value(); 4];
	let mut max = [0u8; 4];
	for p in pixels.into_iter() {
		for i in 0..4 {
			min[i] = cmp::min(min[i], p[i]);
			max[i] = cmp::max(max[i], p[i]);
		}
	}
	(min, max)
}

fn bc1_extrapolate_endpoints(e: &(Rgba, Rgba)) -> (Rgba, Rgba) {
	let mut a = e.0;
	let mut b = e.1;
	for i in 0..3 {
		let f = (fnorm(e.0[i]) - fnorm(e.1[i])) * 1.5;
		a[i] = bnorm(fnorm(e.0[i]) - f);
		b[i] = bnorm(fnorm(e.1[i]) + f);
	}
	(a, b)
}

fn bc1_sort_endpoints(e: &(Rgba, Rgba)) -> (Rgba, Rgba) {
	if bc1_encode_endpoint(&e.0) > bc1_encode_endpoint(&e.1) {
		(e.1, e.0)
	} else {
		(e.0, e.1)
	}
}

fn bc1_build_endpoints(pixels: &[Rgba; 16], quality: u8) -> Vec<(Rgba, Rgba)> {
	let (min, max) = bc1_minmax(pixels);

	let mut out = Vec::new();
	out.push((min, max));

	if quality > 0 && min != max {
		for i in 0..15 {
			for j in (i + 1)..16 {
				let px = (pixels[i], pixels[j]);
				out.push(bc1_sort_endpoints(&px));
				if quality > 1 {
					out.push(bc1_sort_endpoints(&bc1_extrapolate_endpoints(&px)));
				}
			}
		}
	}
	out
}

fn bc1_encode_endpoint(pix: &Rgba) -> u16 {
	((pix[0] as u16 >> 3) << 11) |
	((pix[1] as u16 >> 2) << 5) |
	(pix[2] as u16 >> 3)
}

fn bc1_encode_pixel(table: &[Rgba; 4], pixels: &[Rgba; 16]) -> u32 {
	let mut mask = 0u32;
	for pix in pixels.into_iter().rev() {
		let best = (0..4).into_iter().min_by_key(|x| bc1_dist(&table[*x], pix)).unwrap() as u32;
		mask = (mask << 2) | (best & 0x03);
	}
	mask
}

fn bc1_encode_block(pixels: &[Rgba; 16], quality: u8) -> (u64, u32) {
	/*let (min, max) = bc1_build_endpoints(&pixels)[0];
	let table = bc1_build_table(&min, &max);*/

	let ((min, max), table) = bc1_build_endpoints(pixels, quality).iter()
		.map(|pts| (*pts, bc1_build_table(&pts.0, &pts.1)))
		.min_by_key(|tbl| bc1_total_dist(&tbl.1, pixels)).unwrap();

	let dist = bc1_total_dist(&table, pixels);

	let min = bc1_encode_endpoint(&min) as u64;
	let max = bc1_encode_endpoint(&max) as u64;

	let encoded = bc1_encode_pixel(&table, &pixels) as u64;

	((encoded << 32) | (min << 16) | max, dist)
}

pub fn bc1(image: &Vec<u8>, size: (usize, usize), quality: u8) -> Result<Vec<u8>, ()> {
	if size.0 % 4 != 0 || size.1 % 4 != 0 || image.len() != size.0 * size.1 * 4 {
		return Err(());
	}

    let mut out = Vec::with_capacity(image.len() / 8);
    let mut total_dist = 0u32;

    let block_size = 4;
    let blk_count = (size.0 / block_size, size.1 / block_size);

   	for x in 0..blk_count.0 {
   		for y in 0..blk_count.1 {

   			let mut pixels = [[0u8; 4]; 16]; // No compile time constants
   			for px in 0..block_size {
   				for py in 0..block_size {
   					let x = x * block_size + px;
   					let y = y * block_size + py;

   					let pi = (x * size.1 + y) * 4; // in bytes
   					let pix = [image[pi], image[pi + 1], image[pi + 2], image[pi + 3]];

   					pixels[px * block_size + py] = pix;
   				}
   			}

   			let (mut encoded, dist) = bc1_encode_block(&pixels, quality);
   			total_dist += dist;

   			for _ in 0..8 {
   				out.push((encoded & 0xFF) as u8);
   				encoded >>= 8;
   			}
		}
	}
	//println!("per-pixel dist = {:?}", total_dist / (size.0 * size.1) as u32);
	Ok(out)
}
<|endoftext|>


<commit_before>extern crate drm;
#[macro_use]
extern crate glium;
extern crate rand;
#[macro_use(define_roles)]
extern crate smithay;
extern crate wayland_protocols;
extern crate wayland_server;

#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_term;

mod helpers;

use drm::control::{Device as ControlDevice, ResourceInfo};
use drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};

use glium::Surface;

use helpers::GliumDrawer;
use slog::*;

use smithay::backend::drm::{DrmBackend, DrmDevice, DrmHandler, Id};
use smithay::backend::graphics::egl::EGLGraphicsBackend;
use smithay::backend::graphics::glium::{GliumGraphicsBackend, IntoGlium};
use smithay::compositor::{self, CompositorHandler, CompositorToken, SubsurfaceRole, TraversalAction};
use smithay::compositor::roles::Role;
use smithay::shell::{self, PopupConfigure, PopupSurface, ShellClient, ShellHandler, ShellSurfaceRole,
                     ToplevelConfigure, ToplevelSurface};
use smithay::shm::{ShmGlobal, ShmToken};

use std::fs::OpenOptions;
use std::io::Error as IoError;
use std::os::unix::io::AsRawFd;
use std::time::Duration;

use wayland_protocols::unstable::xdg_shell::server::{zxdg_shell_v6, zxdg_toplevel_v6};

use wayland_server::{Client, EventLoopHandle};
use wayland_server::protocol::{wl_callback, wl_compositor, wl_output, wl_seat, wl_shell, wl_shm,
                               wl_subcompositor, wl_surface};
use wayland_server::sources::READ;

define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] );

struct SurfaceHandler {
    shm_token: ShmToken,
}

#[derive(Default)]
struct SurfaceData {
    buffer: Option<(Vec<u8>, (u32, u32))>,
    location: Option<(i32, i32)>,
}

impl compositor::Handler<SurfaceData, Roles> for SurfaceHandler {
    fn commit(&mut self, _evlh: &mut EventLoopHandle, _client: &Client, surface: &wl_surface::WlSurface,
              token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) {
        // we retrieve the contents of the associated buffer and copy it
        token.with_surface_data(surface, |attributes| {
            match attributes.buffer.take() {
                Some(Some((buffer, (_x, _y)))) => {
                    // we ignore hotspot coordinates in this simple example
                    self.shm_token
                        .with_buffer_contents(&buffer, |slice, data| {
                            let offset = data.offset as usize;
                            let stride = data.stride as usize;
                            let width = data.width as usize;
                            let height = data.height as usize;
                            let mut new_vec = Vec::with_capacity(width * height * 4);
                            for i in 0..height {
                                new_vec.extend(
                                    &slice[(offset + i * stride)..(offset + i * stride + width * 4)],
                                );
                            }
                            attributes.user_data.buffer =
                                Some((new_vec, (data.width as u32, data.height as u32)));
                        })
                        .unwrap();
                    buffer.release();
                }
                Some(None) => {
                    // erase the contents
                    attributes.user_data.buffer = None;
                }
                None => {}
            }
        });
    }

    fn frame(&mut self, _evlh: &mut EventLoopHandle, _client: &Client, _surface: &wl_surface::WlSurface,
             callback: wl_callback::WlCallback,
             _token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) {
        callback.done(0);
    }
}

struct ShellSurfaceHandler {
    token: CompositorToken<SurfaceData, Roles, SurfaceHandler>,
}

impl ShellSurfaceHandler {
    fn new(token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) -> ShellSurfaceHandler {
        ShellSurfaceHandler { token }
    }
}

impl shell::Handler<SurfaceData, Roles, SurfaceHandler, ()> for ShellSurfaceHandler {
    fn new_client(&mut self, _evlh: &mut EventLoopHandle, _client: ShellClient<()>) {}
    fn client_pong(&mut self, _evlh: &mut EventLoopHandle, _client: ShellClient<()>) {}
    fn new_toplevel(&mut self, _evlh: &mut EventLoopHandle,
                    surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>)
                    -> ToplevelConfigure {
        let wl_surface = surface.get_surface().unwrap();
        self.token.with_surface_data(wl_surface, |data| {
            // place the window at a random location in the [0;300]x[0;300] square
            use rand::distributions::{IndependentSample, Range};
            let range = Range::new(0, 300);
            let mut rng = rand::thread_rng();
            let x = range.ind_sample(&mut rng);
            let y = range.ind_sample(&mut rng);
            data.user_data.location = Some((x, y))
        });
        ToplevelConfigure {
            size: None,
            states: vec![],
            serial: 42,
        }
    }
    fn new_popup(&mut self, _evlh: &mut EventLoopHandle,
                 _surface: PopupSurface<SurfaceData, Roles, SurfaceHandler, ()>)
                 -> PopupConfigure {
        PopupConfigure {
            size: (10, 10),
            position: (10, 10),
            serial: 42,
        }
    }
    fn move_(&mut self, _evlh: &mut EventLoopHandle,
             _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
             _serial: u32) {
    }
    fn resize(&mut self, _evlh: &mut EventLoopHandle,
              _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
              _serial: u32, _edges: zxdg_toplevel_v6::ResizeEdge) {
    }
    fn grab(&mut self, _evlh: &mut EventLoopHandle,
            _surface: PopupSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
            _serial: u32) {
    }
    fn change_display_state(&mut self, _evlh: &mut EventLoopHandle,
                            _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>,
                            _maximized: Option<bool>, _minimized: Option<bool>, _fullscreen: Option<bool>,
                            _output: Option<&wl_output::WlOutput>)
                            -> ToplevelConfigure {
        ToplevelConfigure {
            size: None,
            states: vec![],
            serial: 42,
        }
    }
    fn show_window_menu(&mut self, _evlh: &mut EventLoopHandle,
                        _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>,
                        _seat: &wl_seat::WlSeat, _serial: u32, _x: i32, _y: i32) {
    }
}

type MyCompositorHandler = CompositorHandler<SurfaceData, Roles, SurfaceHandler>;
type MyShellHandler = ShellHandler<SurfaceData, Roles, SurfaceHandler, ShellSurfaceHandler, ()>;

fn main() {
    // A logger facility, here we use the terminal for this example
    let log = Logger::root(
        slog_async::Async::default(slog_term::term_full().fuse()).fuse(),
        o!(),
    );

    // Initialize the wayland server
    let (mut display, mut event_loop) = wayland_server::create_display();

    // "Find" a suitable drm device
    let mut options = OpenOptions::new();
    options.read(true);
    options.write(true);
    let mut device =
        DrmDevice::new_from_file(options.clone().open("/dev/dri/card0").unwrap(), log.clone()).unwrap();

    // Get a set of all modesetting resource handles (excluding planes):
    let res_handles = device.resource_handles().unwrap();

    // Use first connected connector
    let connector_info = res_handles
        .connectors()
        .iter()
        .map(|conn| {
            ConnectorInfo::load_from_device(&device, *conn).unwrap()
        })
        .find(|conn| conn.connection_state() == ConnectorState::Connected)
        .unwrap();

    // Use the first crtc (should be successful in most cases)
    let crtc = res_handles.crtcs()[0];

    // Assuming we found a good connector and loaded the info into `connector_info`
    let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)

    // Initialize the hardware backends
    let renderer = device
        .create_backend(crtc, mode, vec![connector_info.handle()])
        .unwrap();

    /*
     * Initialize wl_shm global
     */
    // Insert the ShmGlobal as a handler to your event loop
    // Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported.
    let shm_handler_id = event_loop.add_handler_with_init(ShmGlobal::new(vec![], log.clone()));
    // Register this handler to advertise a wl_shm global of version 1
    event_loop.register_global::<wl_shm::WlShm, ShmGlobal>(shm_handler_id, 1);
    // retreive the token
    let shm_token = {
        let state = event_loop.state();
        state.get_handler::<ShmGlobal>(shm_handler_id).get_token()
    };

    /*
     * Initialize the compositor global
     */
    let compositor_handler_id = event_loop.add_handler_with_init(MyCompositorHandler::new(
        SurfaceHandler {
            shm_token: shm_token.clone(),
        },
        log.clone(),
    ));
    // register it to handle wl_compositor and wl_subcompositor
    event_loop.register_global::<wl_compositor::WlCompositor, MyCompositorHandler>(compositor_handler_id, 4);
    event_loop
        .register_global::<wl_subcompositor::WlSubcompositor, MyCompositorHandler>(compositor_handler_id, 1);
    // retrieve the tokens
    let compositor_token = {
        let state = event_loop.state();
        state
            .get_handler::<MyCompositorHandler>(compositor_handler_id)
            .get_token()
    };

    /*
     * Initialize the shell global
     */
    let shell_handler_id = event_loop.add_handler_with_init(MyShellHandler::new(
        ShellSurfaceHandler::new(compositor_token),
        compositor_token,
        log.clone(),
    ));
    event_loop.register_global::<wl_shell::WlShell, MyShellHandler>(shell_handler_id, 1);
    event_loop.register_global::<zxdg_shell_v6::ZxdgShellV6, MyShellHandler>(shell_handler_id, 1);

    /*
     * Initialize glium
     */
    let drawer = GliumDrawer::new(renderer.into_glium());
    let mut frame = drawer.draw();
    frame.clear_color(0.8, 0.8, 0.9, 1.0);
    frame.finish().unwrap();

    /*
     * Add a listening socket:
     */
    let name = display.add_socket_auto().unwrap().into_string().unwrap();
    println!("Listening on socket: {}", name);

    device.set_handler(DrmHandlerImpl {
        drawer: drawer,
        shell_handler_id,
        compositor_token,
        logger: log,
    });

    let fd = device.as_raw_fd();
    let drm_device_id = event_loop.add_handler(device);
    let _drm_event_source =
        event_loop.add_fd_event_source::<DrmDevice<DrmHandlerImpl>>(fd, drm_device_id, READ);

    event_loop.run().unwrap();
}

pub struct DrmHandlerImpl {
    drawer: GliumDrawer<GliumGraphicsBackend<DrmBackend>>,
    shell_handler_id: usize,
    compositor_token: CompositorToken<SurfaceData, Roles, SurfaceHandler>,
    logger: ::slog::Logger,
}

impl DrmHandler for DrmHandlerImpl {
    fn ready(&mut self, evlh: &mut EventLoopHandle, _id: Id, _frame: u32, _duration: Duration) {
        let mut frame = self.drawer.draw();
        frame.clear_color(0.8, 0.8, 0.9, 1.0);
        // redraw the frame, in a simple but inneficient way
        {
            let screen_dimensions = self.drawer.get_framebuffer_dimensions();
            for toplevel_surface in unsafe {
                evlh.get_handler_unchecked::<MyShellHandler>(self.shell_handler_id)
                    .toplevel_surfaces()
            } {
                if let Some(wl_surface) = toplevel_surface.get_surface() {
                    // this surface is a root of a subsurface tree that needs to be drawn
                    let initial_place = self.compositor_token
                        .with_surface_data(wl_surface, |data| data.user_data.location.unwrap_or((0, 0)));
                    self.compositor_token
                        .with_surface_tree(
                            wl_surface,
                            initial_place,
                            |_surface, attributes, role, &(mut x, mut y)| {
                                if let Some((ref contents, (w, h))) = attributes.user_data.buffer {
                                    // there is actually something to draw !
                                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                                        x += subdata.x;
                                        y += subdata.y;
                                    }
                                    self.drawer.render(
                                        &mut frame,
                                        contents,
                                        (w, h),
                                        (x, y),
                                        screen_dimensions,
                                    );
                                    TraversalAction::DoChildren((x, y))
                                } else {
                                    // we are not display, so our children are neither
                                    TraversalAction::SkipChildren
                                }
                            },
                        )
                        .unwrap();
                }
            }
        }
        frame.finish().unwrap();
    }

    fn error(&mut self, _evlh: &mut EventLoopHandle, error: IoError) {
        error!(self.logger, "{:?}", error);
    }
}
<commit_msg>drm: Refine drm example commentary<commit_after>extern crate drm;
#[macro_use]
extern crate glium;
extern crate rand;
#[macro_use(define_roles)]
extern crate smithay;
extern crate wayland_protocols;
extern crate wayland_server;

#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_term;

mod helpers;

use drm::control::{Device as ControlDevice, ResourceInfo};
use drm::control::connector::{Info as ConnectorInfo, State as ConnectorState};

use glium::Surface;

use helpers::GliumDrawer;
use slog::*;

use smithay::backend::drm::{DrmBackend, DrmDevice, DrmHandler, Id};
use smithay::backend::graphics::egl::EGLGraphicsBackend;
use smithay::backend::graphics::glium::{GliumGraphicsBackend, IntoGlium};
use smithay::compositor::{self, CompositorHandler, CompositorToken, SubsurfaceRole, TraversalAction};
use smithay::compositor::roles::Role;
use smithay::shell::{self, PopupConfigure, PopupSurface, ShellClient, ShellHandler, ShellSurfaceRole,
                     ToplevelConfigure, ToplevelSurface};
use smithay::shm::{ShmGlobal, ShmToken};

use std::fs::OpenOptions;
use std::io::Error as IoError;
use std::os::unix::io::AsRawFd;
use std::time::Duration;

use wayland_protocols::unstable::xdg_shell::server::{zxdg_shell_v6, zxdg_toplevel_v6};

use wayland_server::{Client, EventLoopHandle};
use wayland_server::protocol::{wl_callback, wl_compositor, wl_output, wl_seat, wl_shell, wl_shm,
                               wl_subcompositor, wl_surface};
use wayland_server::sources::READ;

define_roles!(Roles => [ ShellSurface, ShellSurfaceRole ] );

struct SurfaceHandler {
    shm_token: ShmToken,
}

#[derive(Default)]
struct SurfaceData {
    buffer: Option<(Vec<u8>, (u32, u32))>,
    location: Option<(i32, i32)>,
}

impl compositor::Handler<SurfaceData, Roles> for SurfaceHandler {
    fn commit(&mut self, _evlh: &mut EventLoopHandle, _client: &Client, surface: &wl_surface::WlSurface,
              token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) {
        // we retrieve the contents of the associated buffer and copy it
        token.with_surface_data(surface, |attributes| {
            match attributes.buffer.take() {
                Some(Some((buffer, (_x, _y)))) => {
                    // we ignore hotspot coordinates in this simple example
                    self.shm_token
                        .with_buffer_contents(&buffer, |slice, data| {
                            let offset = data.offset as usize;
                            let stride = data.stride as usize;
                            let width = data.width as usize;
                            let height = data.height as usize;
                            let mut new_vec = Vec::with_capacity(width * height * 4);
                            for i in 0..height {
                                new_vec.extend(
                                    &slice[(offset + i * stride)..(offset + i * stride + width * 4)],
                                );
                            }
                            attributes.user_data.buffer =
                                Some((new_vec, (data.width as u32, data.height as u32)));
                        })
                        .unwrap();
                    buffer.release();
                }
                Some(None) => {
                    // erase the contents
                    attributes.user_data.buffer = None;
                }
                None => {}
            }
        });
    }

    fn frame(&mut self, _evlh: &mut EventLoopHandle, _client: &Client, _surface: &wl_surface::WlSurface,
             callback: wl_callback::WlCallback,
             _token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) {
        callback.done(0);
    }
}

struct ShellSurfaceHandler {
    token: CompositorToken<SurfaceData, Roles, SurfaceHandler>,
}

impl ShellSurfaceHandler {
    fn new(token: CompositorToken<SurfaceData, Roles, SurfaceHandler>) -> ShellSurfaceHandler {
        ShellSurfaceHandler { token }
    }
}

impl shell::Handler<SurfaceData, Roles, SurfaceHandler, ()> for ShellSurfaceHandler {
    fn new_client(&mut self, _evlh: &mut EventLoopHandle, _client: ShellClient<()>) {}
    fn client_pong(&mut self, _evlh: &mut EventLoopHandle, _client: ShellClient<()>) {}
    fn new_toplevel(&mut self, _evlh: &mut EventLoopHandle,
                    surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>)
                    -> ToplevelConfigure {
        let wl_surface = surface.get_surface().unwrap();
        self.token.with_surface_data(wl_surface, |data| {
            // place the window at a random location in the [0;300]x[0;300] square
            use rand::distributions::{IndependentSample, Range};
            let range = Range::new(0, 300);
            let mut rng = rand::thread_rng();
            let x = range.ind_sample(&mut rng);
            let y = range.ind_sample(&mut rng);
            data.user_data.location = Some((x, y))
        });
        ToplevelConfigure {
            size: None,
            states: vec![],
            serial: 42,
        }
    }
    fn new_popup(&mut self, _evlh: &mut EventLoopHandle,
                 _surface: PopupSurface<SurfaceData, Roles, SurfaceHandler, ()>)
                 -> PopupConfigure {
        PopupConfigure {
            size: (10, 10),
            position: (10, 10),
            serial: 42,
        }
    }
    fn move_(&mut self, _evlh: &mut EventLoopHandle,
             _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
             _serial: u32) {
    }
    fn resize(&mut self, _evlh: &mut EventLoopHandle,
              _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
              _serial: u32, _edges: zxdg_toplevel_v6::ResizeEdge) {
    }
    fn grab(&mut self, _evlh: &mut EventLoopHandle,
            _surface: PopupSurface<SurfaceData, Roles, SurfaceHandler, ()>, _seat: &wl_seat::WlSeat,
            _serial: u32) {
    }
    fn change_display_state(&mut self, _evlh: &mut EventLoopHandle,
                            _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>,
                            _maximized: Option<bool>, _minimized: Option<bool>, _fullscreen: Option<bool>,
                            _output: Option<&wl_output::WlOutput>)
                            -> ToplevelConfigure {
        ToplevelConfigure {
            size: None,
            states: vec![],
            serial: 42,
        }
    }
    fn show_window_menu(&mut self, _evlh: &mut EventLoopHandle,
                        _surface: ToplevelSurface<SurfaceData, Roles, SurfaceHandler, ()>,
                        _seat: &wl_seat::WlSeat, _serial: u32, _x: i32, _y: i32) {
    }
}

type MyCompositorHandler = CompositorHandler<SurfaceData, Roles, SurfaceHandler>;
type MyShellHandler = ShellHandler<SurfaceData, Roles, SurfaceHandler, ShellSurfaceHandler, ()>;

fn main() {
    // A logger facility, here we use the terminal for this example
    let log = Logger::root(
        slog_async::Async::default(slog_term::term_full().fuse()).fuse(),
        o!(),
    );

    // Initialize the wayland server
    let (mut display, mut event_loop) = wayland_server::create_display();

    /*
     * Initialize the drm backend
     */
    // "Find" a suitable drm device
    let mut options = OpenOptions::new();
    options.read(true);
    options.write(true);
    let mut device =
        DrmDevice::new_from_file(options.clone().open("/dev/dri/card0").unwrap(), log.clone()).unwrap();

    // Get a set of all modesetting resource handles (excluding planes):
    let res_handles = device.resource_handles().unwrap();

    // Use first connected connector
    let connector_info = res_handles
        .connectors()
        .iter()
        .map(|conn| {
            ConnectorInfo::load_from_device(&device, *conn).unwrap()
        })
        .find(|conn| conn.connection_state() == ConnectorState::Connected)
        .unwrap();

    // Use the first crtc (should be successful in most cases)
    let crtc = res_handles.crtcs()[0];

    // Assuming we found a good connector and loaded the info into `connector_info`
    let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.)

    // Initialize the hardware backend
    let renderer = device
        .create_backend(crtc, mode, vec![connector_info.handle()])
        .unwrap();

    /*
     * Initialize wl_shm global
     */
    // Insert the ShmGlobal as a handler to your event loop
    // Here, we specify tha the standard Argb8888 and Xrgb8888 is the only supported.
    let shm_handler_id = event_loop.add_handler_with_init(ShmGlobal::new(vec![], log.clone()));
    // Register this handler to advertise a wl_shm global of version 1
    event_loop.register_global::<wl_shm::WlShm, ShmGlobal>(shm_handler_id, 1);
    // retreive the token
    let shm_token = {
        let state = event_loop.state();
        state.get_handler::<ShmGlobal>(shm_handler_id).get_token()
    };

    /*
     * Initialize the compositor global
     */
    let compositor_handler_id = event_loop.add_handler_with_init(MyCompositorHandler::new(
        SurfaceHandler {
            shm_token: shm_token.clone(),
        },
        log.clone(),
    ));
    // register it to handle wl_compositor and wl_subcompositor
    event_loop.register_global::<wl_compositor::WlCompositor, MyCompositorHandler>(compositor_handler_id, 4);
    event_loop
        .register_global::<wl_subcompositor::WlSubcompositor, MyCompositorHandler>(compositor_handler_id, 1);
    // retrieve the tokens
    let compositor_token = {
        let state = event_loop.state();
        state
            .get_handler::<MyCompositorHandler>(compositor_handler_id)
            .get_token()
    };

    /*
     * Initialize the shell global
     */
    let shell_handler_id = event_loop.add_handler_with_init(MyShellHandler::new(
        ShellSurfaceHandler::new(compositor_token),
        compositor_token,
        log.clone(),
    ));
    event_loop.register_global::<wl_shell::WlShell, MyShellHandler>(shell_handler_id, 1);
    event_loop.register_global::<zxdg_shell_v6::ZxdgShellV6, MyShellHandler>(shell_handler_id, 1);

    /*
     * Initialize glium
     */
    let drawer = GliumDrawer::new(renderer.into_glium());
    let mut frame = drawer.draw();
    frame.clear_color(0.8, 0.8, 0.9, 1.0);
    frame.finish().unwrap();

    /*
     * Add a listening socket:
     */
    let name = display.add_socket_auto().unwrap().into_string().unwrap();
    println!("Listening on socket: {}", name);

    // Set the DrmHandler
    device.set_handler(DrmHandlerImpl {
        drawer: drawer,
        shell_handler_id,
        compositor_token,
        logger: log,
    });

    /*
     * Register the DrmDevice on the EventLoop
     */
    let fd = device.as_raw_fd();
    let drm_device_id = event_loop.add_handler(device);
    let _drm_event_source =
        event_loop.add_fd_event_source::<DrmDevice<DrmHandlerImpl>>(fd, drm_device_id, READ);

    event_loop.run().unwrap();
}

pub struct DrmHandlerImpl {
    drawer: GliumDrawer<GliumGraphicsBackend<DrmBackend>>,
    shell_handler_id: usize,
    compositor_token: CompositorToken<SurfaceData, Roles, SurfaceHandler>,
    logger: ::slog::Logger,
}

impl DrmHandler for DrmHandlerImpl {
    fn ready(&mut self, evlh: &mut EventLoopHandle, _id: Id, _frame: u32, _duration: Duration) {
        let mut frame = self.drawer.draw();
        frame.clear_color(0.8, 0.8, 0.9, 1.0);
        // redraw the frame, in a simple but inneficient way
        {
            let screen_dimensions = self.drawer.get_framebuffer_dimensions();
            for toplevel_surface in unsafe {
                evlh.get_handler_unchecked::<MyShellHandler>(self.shell_handler_id)
                    .toplevel_surfaces()
            } {
                if let Some(wl_surface) = toplevel_surface.get_surface() {
                    // this surface is a root of a subsurface tree that needs to be drawn
                    let initial_place = self.compositor_token
                        .with_surface_data(wl_surface, |data| data.user_data.location.unwrap_or((0, 0)));
                    self.compositor_token
                        .with_surface_tree(
                            wl_surface,
                            initial_place,
                            |_surface, attributes, role, &(mut x, mut y)| {
                                if let Some((ref contents, (w, h))) = attributes.user_data.buffer {
                                    // there is actually something to draw !
                                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                                        x += subdata.x;
                                        y += subdata.y;
                                    }
                                    self.drawer.render(
                                        &mut frame,
                                        contents,
                                        (w, h),
                                        (x, y),
                                        screen_dimensions,
                                    );
                                    TraversalAction::DoChildren((x, y))
                                } else {
                                    // we are not display, so our children are neither
                                    TraversalAction::SkipChildren
                                }
                            },
                        )
                        .unwrap();
                }
            }
        }
        frame.finish().unwrap();
    }

    fn error(&mut self, _evlh: &mut EventLoopHandle, error: IoError) {
        panic!("{:?}", error);
    }
}
<|endoftext|>


<commit_before>//! On Linux we can use vmsplice() to write data more efficiently.
//!
//! This does not always work. We're not allowed to splice to some targets,
//! and on some systems (notably WSL 1) it isn't supported at all.
//!
//! If we get an error code that suggests splicing isn't supported then we
//! tell that to the caller so it can fall back to a robust naïve method. If
//! we get another kind of error we bubble it up as normal.
//!
//! vmsplice() can only splice into a pipe, so if the output is not a pipe
//! we make our own and use splice() to bridge the gap from the pipe to the
//! output.
//!
//! We assume that an "unsupported" error will only ever happen before any
//! data was successfully written to the output. That way we don't have to
//! make any effort to rescue data from the pipe if splice() fails, we can
//! just fall back and start over from the beginning.

use std::{io, os::unix::io::AsRawFd};

use nix::{errno::Errno, libc::S_IFIFO, sys::stat::fstat};

use uucore::pipes::{pipe, splice_exact, vmsplice};

pub(crate) fn splice_data(bytes: &[u8], out: &impl AsRawFd) -> Result<()> {
    let is_pipe = fstat(out.as_raw_fd())?.st_mode & S_IFIFO != 0;

    if is_pipe {
        loop {
            let mut bytes = bytes;
            while !bytes.is_empty() {
                let len = vmsplice(out, bytes).map_err(maybe_unsupported)?;
                bytes = &bytes[len..];
            }
        }
    } else {
        let (read, write) = pipe()?;
        loop {
            let mut bytes = bytes;
            while !bytes.is_empty() {
                let len = vmsplice(&write, bytes).map_err(maybe_unsupported)?;
                splice_exact(&read, out, len).map_err(maybe_unsupported)?;
                bytes = &bytes[len..];
            }
        }
    }
}

pub(crate) enum Error {
    Unsupported,
    Io(io::Error),
}

type Result<T> = std::result::Result<T, Error>;

impl From<nix::Error> for Error {
    fn from(error: nix::Error) -> Self {
        match error {
            nix::Error::Sys(errno) => Error::Io(io::Error::from_raw_os_error(errno as i32)),
            _ => Error::Io(io::Error::last_os_error()),
        }
    }
}

fn maybe_unsupported(error: nix::Error) -> Error {
    match error.as_errno() {
        Some(Errno::EINVAL) | Some(Errno::ENOSYS) | Some(Errno::EBADF) => Error::Unsupported,
        _ => error.into(),
    }
}
<commit_msg>fix/yes ~ revise to match 'nix' changes<commit_after>//! On Linux we can use vmsplice() to write data more efficiently.
//!
//! This does not always work. We're not allowed to splice to some targets,
//! and on some systems (notably WSL 1) it isn't supported at all.
//!
//! If we get an error code that suggests splicing isn't supported then we
//! tell that to the caller so it can fall back to a robust naïve method. If
//! we get another kind of error we bubble it up as normal.
//!
//! vmsplice() can only splice into a pipe, so if the output is not a pipe
//! we make our own and use splice() to bridge the gap from the pipe to the
//! output.
//!
//! We assume that an "unsupported" error will only ever happen before any
//! data was successfully written to the output. That way we don't have to
//! make any effort to rescue data from the pipe if splice() fails, we can
//! just fall back and start over from the beginning.

use std::{io, os::unix::io::AsRawFd};

use nix::{errno::Errno, libc::S_IFIFO, sys::stat::fstat};

use uucore::pipes::{pipe, splice_exact, vmsplice};

pub(crate) fn splice_data(bytes: &[u8], out: &impl AsRawFd) -> Result<()> {
    let is_pipe = fstat(out.as_raw_fd())?.st_mode & S_IFIFO != 0;

    if is_pipe {
        loop {
            let mut bytes = bytes;
            while !bytes.is_empty() {
                let len = vmsplice(out, bytes).map_err(maybe_unsupported)?;
                bytes = &bytes[len..];
            }
        }
    } else {
        let (read, write) = pipe()?;
        loop {
            let mut bytes = bytes;
            while !bytes.is_empty() {
                let len = vmsplice(&write, bytes).map_err(maybe_unsupported)?;
                splice_exact(&read, out, len).map_err(maybe_unsupported)?;
                bytes = &bytes[len..];
            }
        }
    }
}

pub(crate) enum Error {
    Unsupported,
    Io(io::Error),
}

type Result<T> = std::result::Result<T, Error>;

impl From<nix::Error> for Error {
    fn from(error: nix::Error) -> Self {
        Error::Io(io::Error::from_raw_os_error(error as i32))
    }
}

fn maybe_unsupported(error: nix::Error) -> Error {
    match error {
        Errno::EINVAL | Errno::ENOSYS | Errno::EBADF => Error::Unsupported,
        _ => error.into(),
    }
}
<|endoftext|>