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// -------------------------------------------------------------------------------------------------