carnelian/render/generic/forma/
image.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::io::Read;
6use std::sync::Arc;
7use std::{mem, slice};
8
9use anyhow::Error;
10use fidl_fuchsia_sysmem2::{BufferCollectionSynchronousProxy, CoherencyDomain};
11use fuchsia_trace::duration;
12use mapped_vmo::Mapping;
13use zx::prelude::*;
14use zx::{self as zx, sys};
15
16#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
17pub struct FormaImage(pub(crate) usize);
18
19#[derive(Debug)]
20pub(crate) struct VmoImage {
21    // TODO(https://fxbug.dev/42165549)
22    #[allow(unused)]
23    vmo: zx::Vmo,
24    // TODO(https://fxbug.dev/42165549)
25    #[allow(unused)]
26    width: u32,
27    // TODO(https://fxbug.dev/42165549)
28    #[allow(unused)]
29    height: u32,
30    // TODO(https://fxbug.dev/42165549)
31    #[allow(unused)]
32    len_bytes: u64,
33    mapping: Arc<Mapping>,
34    stride: usize,
35    pub(crate) buffer_layer_cache: Option<(usize, forma::buffer::BufferLayerCache)>,
36    coherency_domain: CoherencyDomain,
37    layout: forma::buffer::layout::LinearLayout,
38}
39
40impl VmoImage {
41    pub fn new(width: u32, height: u32) -> Self {
42        let len_bytes = (width * height * 4) as usize * mem::size_of::<u8>();
43        let (mapping, vmo) = mapped_vmo::Mapping::allocate(len_bytes as usize)
44            .expect("failed to allocated mapped VMO");
45
46        Self {
47            vmo,
48            width,
49            height,
50            len_bytes: len_bytes as u64,
51            mapping: Arc::new(mapping),
52            stride: (width * 4) as usize,
53            buffer_layer_cache: None,
54            coherency_domain: CoherencyDomain::Cpu,
55            layout: forma::buffer::layout::LinearLayout::new(
56                width as usize,
57                (width * 4) as usize,
58                height as usize,
59            ),
60        }
61    }
62
63    pub fn from_png<R: Read>(reader: &mut png::Reader<R>) -> Result<Self, Error> {
64        let info = reader.info();
65        let color_type = info.color_type;
66        let (width, height) = info.size();
67        let stride = (width * 4) as usize * mem::size_of::<u8>();
68        let len_bytes = stride * height as usize;
69        let (mut mapping, vmo) = mapped_vmo::Mapping::allocate(len_bytes as usize)
70            .expect("failed to allocated mapped VMO");
71        let (data, len) = mapping.as_ptr_len();
72        let slice = unsafe { slice::from_raw_parts_mut(data, len) };
73        for dst_row in slice.chunks_mut(stride) {
74            let src_row = reader.next_row()?.unwrap();
75            // Transfer row and convert to BGRA.
76            match color_type {
77                png::ColorType::RGB | png::ColorType::Indexed => {
78                    for (src, dst) in src_row.chunks(3).zip(dst_row.chunks_mut(4)) {
79                        dst.copy_from_slice(&[src[2], src[1], src[0], 0xff]);
80                    }
81                }
82                png::ColorType::RGBA => {
83                    for (src, dst) in src_row.chunks(4).zip(dst_row.chunks_mut(4)) {
84                        dst.copy_from_slice(&[src[2], src[1], src[0], src[3]]);
85                    }
86                }
87                _ => panic!("unsupported color type {:#?}", color_type),
88            }
89        }
90
91        Ok(Self {
92            vmo,
93            width,
94            height,
95            len_bytes: len_bytes as u64,
96            mapping: Arc::new(mapping),
97            stride: (width * 4) as usize,
98            buffer_layer_cache: None,
99            coherency_domain: CoherencyDomain::Cpu,
100            layout: forma::buffer::layout::LinearLayout::new(
101                width as usize,
102                (width * 4) as usize,
103                height as usize,
104            ),
105        })
106    }
107
108    pub fn from_buffer_collection(
109        buffer_collection: &mut BufferCollectionSynchronousProxy,
110        width: u32,
111        height: u32,
112        index: u32,
113    ) -> Self {
114        let wait_result = buffer_collection
115            .wait_for_all_buffers_allocated(zx::MonotonicInstant::INFINITE)
116            .expect("failed to allocate buffer collection");
117        assert!(
118            wait_result.is_ok(),
119            "wait_for_all_buffers_allocated failed: {:?}",
120            wait_result.unwrap_err()
121        );
122
123        let buffers = wait_result.unwrap().buffer_collection_info.unwrap();
124        let vmo_buffer = &buffers.buffers.as_ref().unwrap()[index as usize];
125        let vmo = vmo_buffer
126            .vmo
127            .as_ref()
128            .expect("failed to get VMO buffer")
129            .duplicate_handle(zx::Rights::SAME_RIGHTS)
130            .expect("failed to duplicate VMO handle");
131
132        let settings = buffers.settings.as_ref().unwrap();
133        let buffer_settings = settings.buffer_settings.as_ref().unwrap();
134        let len_bytes = buffer_settings.size_bytes.as_ref().unwrap();
135        let mapping = Arc::new(
136            mapped_vmo::Mapping::create_from_vmo(
137                &vmo,
138                *len_bytes as usize,
139                zx::VmarFlags::PERM_READ
140                    | zx::VmarFlags::PERM_WRITE
141                    | zx::VmarFlags::MAP_RANGE
142                    | zx::VmarFlags::REQUIRE_NON_RESIZABLE,
143            )
144            .expect("failed to crate mapping from VMO"),
145        );
146
147        assert!(settings.image_format_constraints.is_some());
148        let image_format_constraints = settings.image_format_constraints.as_ref().unwrap();
149        let bytes_per_row = image_format_constraints.min_bytes_per_row.as_ref().unwrap();
150        let divisor = image_format_constraints.bytes_per_row_divisor.as_ref().unwrap();
151        let bytes_per_row = ((bytes_per_row + divisor - 1) / divisor) * divisor;
152        let stride = bytes_per_row as usize / mem::size_of::<u8>();
153
154        Self {
155            vmo,
156            width,
157            height,
158            len_bytes: *len_bytes as u64,
159            mapping,
160            stride,
161            buffer_layer_cache: None,
162            coherency_domain: *buffer_settings.coherency_domain.as_ref().unwrap(),
163            layout: forma::buffer::layout::LinearLayout::new(
164                width as usize,
165                stride,
166                height as usize,
167            ),
168        }
169    }
170
171    pub fn bytes_per_row(&self) -> usize {
172        self.stride * mem::size_of::<u8>()
173    }
174
175    pub fn coherency_domain(&self) -> CoherencyDomain {
176        self.coherency_domain
177    }
178
179    pub fn as_mut_slice(&mut self) -> &mut [u8] {
180        let (data, len) = Arc::get_mut(&mut self.mapping).unwrap().as_ptr_len();
181        unsafe { slice::from_raw_parts_mut(data, len) }
182    }
183
184    pub fn as_buffer(
185        &mut self,
186    ) -> forma::buffer::Buffer<'_, '_, forma::buffer::layout::LinearLayout> {
187        #[derive(Debug)]
188        struct SliceFlusher;
189
190        impl forma::buffer::layout::Flusher for SliceFlusher {
191            fn flush(&self, slice: &mut [u8]) {
192                unsafe {
193                    sys::zx_cache_flush(
194                        slice.as_ptr() as *const u8,
195                        slice.len(),
196                        sys::ZX_CACHE_FLUSH_DATA,
197                    );
198                }
199            }
200        }
201
202        let (data, len) = Arc::get_mut(&mut self.mapping).unwrap().as_ptr_len();
203        let raw_buffer = unsafe { slice::from_raw_parts_mut(data as *mut u8, len) };
204
205        let mut buffer = forma::buffer::BufferBuilder::new(raw_buffer, &mut self.layout);
206
207        if let Some(buffer_layer_cache) =
208            self.buffer_layer_cache.as_ref().map(|(_, cache)| cache).cloned()
209        {
210            buffer = buffer.layer_cache(buffer_layer_cache);
211        }
212
213        if self.coherency_domain == CoherencyDomain::Ram {
214            buffer = buffer.flusher(Box::new(SliceFlusher));
215        }
216
217        buffer.build()
218    }
219
220    pub fn clear(&mut self, clear_color: [u8; 4]) {
221        duration!(c"gfx", c"VmoImage::clear");
222
223        if let Some((_, buffer_layer_cache)) = self.buffer_layer_cache.as_ref() {
224            buffer_layer_cache.clear();
225        }
226
227        let coherency_domain = self.coherency_domain;
228
229        let (data, len) = Arc::get_mut(&mut self.mapping).unwrap().as_ptr_len();
230        let buffer = unsafe { slice::from_raw_parts_mut(data as *mut u8, len) };
231
232        forma::clear_buffer(buffer, clear_color);
233
234        if coherency_domain == CoherencyDomain::Ram {
235            unsafe {
236                sys::zx_cache_flush(
237                    buffer.as_ptr() as *const u8,
238                    buffer.len(),
239                    sys::ZX_CACHE_FLUSH_DATA,
240                );
241            }
242        }
243    }
244}