cognitive_qualia/
memory.rs

1// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
2// the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/
3
4//! This module provides buffer memory management tools.
5//!
6//! Clients usually share images with server using shared memory. Client creates big shared memory
7//! and then tells server which parts server should use for drawing on surfaces. `Memory`
8//! represents this shared memory (and is owner of data) and `MemoryView` can be used to view parts
9//! of it.
10//!
11//! Images to redraw can be also created locally or read from file. These images can be stored in
12//! `Buffer`. `Buffer` and `MemoryView` implement `Pixmap` trait, but `Buffer` is owned of its data
13//! unlike `MemoryView`.
14//!
15//! `MemoryPool` is used to provide mechanism for storing mapped and buffered memory. The only way
16//! to construct `MemoryView` is through `MemoryPool`. Both have counted reference to `Memory` and
17//! the `Memory` is destructed when its reference count goes to zero, so `MemoryView`s can be
18//! safely used even after `Memory` was removed from `MemoryPool`.
19
20use std;
21use std::os::unix::io::RawFd;
22use std::sync::Arc;
23
24use nix::sys::mman;
25
26use errors;
27use defs::Size;
28use image::{Image, Pixmap, PixelFormat};
29
30// -------------------------------------------------------------------------------------------------
31
32/// Container for all data required to draw an image.
33#[derive(Clone, Debug)]
34pub struct Buffer {
35    format: PixelFormat,
36    width: usize,
37    height: usize,
38    stride: usize,
39    data: Vec<u8>,
40}
41
42// -------------------------------------------------------------------------------------------------
43
44impl Buffer {
45    /// Constructors `Buffer`.
46    ///
47    /// Will panic if passed data size does not match declared size.
48    pub fn new(format: PixelFormat,
49               width: usize,
50               height: usize,
51               stride: usize,
52               data: Vec<u8>)
53               -> Self {
54        if (stride * height) != data.len() {
55            panic!("Data size ({}) does not match declaration ({} * {})",
56                   data.len(),
57                   stride,
58                   height);
59        }
60
61        Buffer {
62            format: format,
63            width: width,
64            height: height,
65            stride: stride,
66            data: data,
67        }
68    }
69
70    /// Constructs empty `Buffer`.
71    pub fn empty() -> Self {
72        Buffer {
73            format: PixelFormat::XRGB8888,
74            width: 0,
75            height: 0,
76            stride: 0,
77            data: Vec::new(),
78        }
79    }
80
81    /// Copies data from `other` buffer to `self`.
82    pub fn assign_from(&mut self, other: &Buffer) {
83        self.format = other.format;
84        self.width = other.width;
85        self.height = other.height;
86        self.stride = other.stride;
87        self.data = other.data.clone();
88    }
89
90    /// Checks if buffer contains drawable data.
91    pub fn is_empty(&self) -> bool {
92        (self.width == 0) || (self.height == 0) || (self.stride == 0) || (self.data.len() == 0)
93    }
94
95    /// Converts `Buffer` to memory.
96    ///
97    /// Applications share memory with server. It is their responsibility to inform server which
98    /// buffer should be used and avoid drawing to it. The same way inner parts of compositor may
99    /// want to instruct render to draw surfaces for them and for simplicity they do this in the
100    /// same (relatively unsafe) way as clients. This method converts `Buffer` to `Memory` so it
101    /// can be used just as mapped memory obtained from client. It is programmes responsibility to
102    /// ensure `Buffer` exists until `Memory` exist and not to draw on it while it may be used for
103    /// rendering.
104    pub unsafe fn as_memory(&mut self) -> Memory {
105        Memory::new_borrowed(self.data.as_mut_ptr(), self.stride * self.height)
106    }
107}
108
109// -------------------------------------------------------------------------------------------------
110
111impl Image for Buffer {
112    #[inline]
113    fn get_size(&self) -> Size {
114        Size {
115            width: self.width,
116            height: self.height,
117        }
118    }
119
120    #[inline]
121    fn get_width(&self) -> usize {
122        self.width
123    }
124
125    #[inline]
126    fn get_height(&self) -> usize {
127        self.height
128    }
129}
130
131// -------------------------------------------------------------------------------------------------
132
133impl Pixmap for Buffer {
134    #[inline]
135    fn get_format(&self) -> PixelFormat {
136        self.format
137    }
138
139    #[inline]
140    fn get_stride(&self) -> usize {
141        self.stride
142    }
143
144    #[inline]
145    fn as_slice(&self) -> &[u8] {
146        self.data.as_slice()
147    }
148
149    #[inline]
150    fn as_mut_slice(&mut self) -> &mut [u8] {
151        self.data.as_mut_slice()
152    }
153
154    #[inline]
155    unsafe fn as_ptr(&self) -> *const u8 {
156        self.data.as_ptr()
157    }
158}
159
160// -------------------------------------------------------------------------------------------------
161
162enum MemorySource {
163    Mapped,
164    Borrowed,
165}
166
167// -------------------------------------------------------------------------------------------------
168
169/// Represents memory shared with client.
170pub struct Memory {
171    data: *mut u8,
172    size: usize,
173    source: MemorySource,
174}
175
176// -------------------------------------------------------------------------------------------------
177
178unsafe impl Send for Memory {}
179
180/// `Memory` is `Sync` as long as its contents do not change. All modifying methods should be
181/// marked as `unsafe` and it is programmers responsibility to ensure they are used properly.
182unsafe impl Sync for Memory {}
183
184// -------------------------------------------------------------------------------------------------
185
186impl Memory {
187    /// Constructs new `Memory` as shared with other application.
188    pub fn new_mapped(fd: RawFd, size: usize) -> Result<Memory, errors::Illusion> {
189        match mman::mmap(std::ptr::null_mut(),
190                         size,
191                         mman::PROT_READ | mman::PROT_WRITE,
192                         mman::MAP_SHARED,
193                         fd,
194                         0) {
195            Ok(memory) => {
196                Ok(Memory {
197                       data: memory as *mut u8,
198                       size: size,
199                       source: MemorySource::Mapped,
200                   })
201            }
202            Err(err) => Err(errors::Illusion::General(format!("Failed to map memory! {:?}", err))),
203        }
204    }
205
206    /// Constructs new `Memory` from borrowed pointer.
207    ///
208    /// This is unsafe operation because `Memory` does not owns the data. It must be ensured that
209    /// the `Memory` is destructed before the memory.
210    unsafe fn new_borrowed(data: *mut u8, size: usize) -> Self {
211        Memory {
212            data: data,
213            size: size,
214            source: MemorySource::Borrowed,
215        }
216    }
217
218    /// Copies contents of given buffer to memory.
219    ///
220    /// Buffers size must be exactly the size of memory.
221    pub unsafe fn absorb(&mut self, buffer: &Buffer) -> Result<(), errors::Illusion> {
222        let buffer_size = buffer.as_slice().len();
223        if buffer_size == self.size {
224            std::ptr::copy_nonoverlapping(buffer.as_ptr(), self.data, self.size);
225            Ok(())
226        } else {
227            Err(errors::Illusion::General(format!("Sizes differ: memory map is {}, but buffer {}",
228                                                  self.size,
229                                                  buffer_size)))
230        }
231    }
232}
233
234// -------------------------------------------------------------------------------------------------
235
236impl Drop for Memory {
237    fn drop(&mut self) {
238        match self.source {
239            MemorySource::Mapped => { let _ = mman::munmap(self.data as *mut _, self.size); }
240            MemorySource::Borrowed => {}
241        }
242    }
243}
244
245// -------------------------------------------------------------------------------------------------
246
247/// Represents view into memory shared with client.
248pub struct MemoryView {
249    memory: Arc<Memory>,
250    data: *mut u8,
251    width: usize,
252    height: usize,
253    stride: usize,
254    format: PixelFormat,
255}
256
257// -------------------------------------------------------------------------------------------------
258
259unsafe impl Send for MemoryView {}
260
261/// `MemoryView` is `Sync` as long as it does not provide means to change its internals.
262unsafe impl Sync for MemoryView {}
263
264// -------------------------------------------------------------------------------------------------
265
266impl Image for MemoryView {
267    #[inline]
268    fn get_size(&self) -> Size {
269        Size {
270            width: self.width,
271            height: self.height,
272        }
273    }
274
275    #[inline]
276    fn get_width(&self) -> usize {
277        self.width
278    }
279
280    #[inline]
281    fn get_height(&self) -> usize {
282        self.height
283    }
284}
285
286// -------------------------------------------------------------------------------------------------
287
288impl Pixmap for MemoryView {
289    #[inline]
290    fn get_format(&self) -> PixelFormat {
291        self.format
292    }
293
294    #[inline]
295    fn get_stride(&self) -> usize {
296        self.stride
297    }
298
299    #[inline]
300    fn as_slice(&self) -> &[u8] {
301        unsafe { std::slice::from_raw_parts(self.data.offset(0), self.height * self.stride) }
302    }
303
304    #[inline]
305    fn as_mut_slice(&mut self) -> &mut [u8] {
306        unsafe { std::slice::from_raw_parts_mut(self.data.offset(0), self.height * self.stride) }
307    }
308
309    #[inline]
310    unsafe fn as_ptr(&self) -> *const u8 {
311        self.data.offset(0)
312    }
313}
314
315// -------------------------------------------------------------------------------------------------
316
317impl Clone for MemoryView {
318    fn clone(&self) -> Self {
319        MemoryView {
320            memory: self.memory.clone(),
321            data: unsafe { self.data.offset(0) },
322            width: self.width,
323            height: self.height,
324            stride: self.stride,
325            format: self.format,
326        }
327    }
328}
329
330// -------------------------------------------------------------------------------------------------
331
332/// This structure is used to provide storage for images of different type: shared memory and
333/// buffers and return views to them.
334pub struct MemoryPool {
335    memory: Arc<Memory>,
336}
337
338// -------------------------------------------------------------------------------------------------
339
340impl MemoryPool {
341    /// Creates new `MemoryPool` containing `Memory`.
342    pub fn new(memory: Memory) -> Self {
343        MemoryPool { memory: Arc::new(memory) }
344    }
345
346    /// Returns `MemoryView`s from `Memory`s stored in `MemoryPool`.
347    pub fn get_memory_view(&self,
348                           format: PixelFormat,
349                           offset: usize,
350                           width: usize,
351                           height: usize,
352                           stride: usize)
353                           -> MemoryView {
354        // FIXME: Check if boundaries given as arguments are correct.
355        MemoryView {
356            memory: self.memory.clone(),
357            data: unsafe { self.memory.data.offset(offset as isize) },
358            width: width,
359            height: height,
360            stride: stride,
361            format: format,
362        }
363    }
364
365    /// Consumes the pool and if there are no other references to this memory left returns the
366    /// `Memory`.
367    pub fn take_memory(self) -> Option<Memory> {
368        Arc::try_unwrap(self.memory).ok()
369    }
370}
371
372// -------------------------------------------------------------------------------------------------