1use fsysmem2::{
6 AllocatorAllocateSharedCollectionRequest, AllocatorBindSharedCollectionRequest,
7 AllocatorSetDebugClientInfoRequest, BufferCollectionSetConstraintsRequest,
8 BufferCollectionTokenDuplicateRequest, NodeSetNameRequest,
9};
10
11use fidl::endpoints::{create_endpoints, create_proxy, Proxy};
12use fidl_fuchsia_hardware_display_types as fdisplay_types;
13use fidl_fuchsia_images2::{self as fimages2};
14use fidl_fuchsia_sysmem2::{
15 self as fsysmem2, AllocatorMarker, BufferCollectionInfo, BufferCollectionMarker,
16 BufferCollectionProxy, BufferCollectionTokenMarker, BufferCollectionTokenProxy,
17};
18use fuchsia_component::client::connect_to_protocol;
19use zx::{self as zx, AsHandleRef, HandleBased};
20
21use crate::controller::Coordinator;
22use crate::error::{Error, Result};
23use crate::pixel_format::PixelFormat;
24use crate::types::{BufferCollectionId, ImageId};
25
26#[derive(Clone)]
28pub struct ImageParameters {
29 pub width: u32,
31
32 pub height: u32,
34
35 pub pixel_format: PixelFormat,
38
39 pub color_space: fimages2::ColorSpace,
42
43 pub name: Option<String>,
45}
46
47pub struct Image {
49 pub id: ImageId,
51
52 pub collection_id: BufferCollectionId,
54
55 pub vmo: zx::Vmo,
57
58 pub parameters: ImageParameters,
60
61 pub format_constraints: fsysmem2::ImageFormatConstraints,
64
65 pub buffer_settings: fsysmem2::BufferMemorySettings,
67
68 proxy: BufferCollectionProxy,
70
71 coordinator: Coordinator,
73}
74
75impl Image {
76 pub async fn create(
80 coordinator: Coordinator,
81 image_id: ImageId,
82 params: &ImageParameters,
83 ) -> Result<Image> {
84 let mut collection = allocate_image_buffer(coordinator.clone(), params).await?;
85 coordinator.import_image(collection.id, image_id, params.into()).await?;
86 let vmo = collection.info.buffers.as_ref().unwrap()[0]
87 .vmo
88 .as_ref()
89 .ok_or(Error::BuffersNotAllocated)?
90 .duplicate_handle(zx::Rights::SAME_RIGHTS)?;
91
92 collection.release();
93
94 Ok(Image {
95 id: image_id,
96 collection_id: collection.id,
97 vmo,
98 parameters: params.clone(),
99 format_constraints: collection
100 .info
101 .settings
102 .as_ref()
103 .unwrap()
104 .image_format_constraints
105 .as_ref()
106 .unwrap()
107 .clone(),
108 buffer_settings: collection
109 .info
110 .settings
111 .as_mut()
112 .unwrap()
113 .buffer_settings
114 .take()
115 .unwrap(),
116 proxy: collection.proxy.clone(),
117 coordinator,
118 })
119 }
120}
121
122impl Drop for Image {
123 fn drop(&mut self) {
124 let _ = self.proxy.release();
125 let _ = self.coordinator.release_buffer_collection(self.collection_id);
126 }
127}
128
129impl From<&ImageParameters> for fdisplay_types::ImageMetadata {
130 fn from(src: &ImageParameters) -> Self {
131 Self {
132 dimensions: fidl_fuchsia_math::SizeU { width: src.width, height: src.height },
133 tiling_type: fdisplay_types::IMAGE_TILING_TYPE_LINEAR,
134 }
135 }
136}
137
138impl From<ImageParameters> for fdisplay_types::ImageMetadata {
139 fn from(src: ImageParameters) -> Self {
140 fdisplay_types::ImageMetadata::from(&src)
141 }
142}
143
144struct BufferCollection {
148 id: BufferCollectionId,
149 info: BufferCollectionInfo,
150 proxy: BufferCollectionProxy,
151 coordinator: Coordinator,
152 released: bool,
153}
154
155impl BufferCollection {
156 fn release(&mut self) {
157 self.released = true;
158 }
159}
160
161impl Drop for BufferCollection {
162 fn drop(&mut self) {
163 if !self.released {
164 let _ = self.coordinator.release_buffer_collection(self.id);
165 let _ = self.proxy.release();
166 }
167 }
168}
169
170async fn allocate_image_buffer(
173 coordinator: Coordinator,
174 params: &ImageParameters,
175) -> Result<BufferCollection> {
176 let allocator =
177 connect_to_protocol::<AllocatorMarker>().map_err(|_| Error::SysmemConnection)?;
178 {
179 let name = fuchsia_runtime::process_self().get_name()?;
180 let koid = fuchsia_runtime::process_self().get_koid()?;
181 allocator.set_debug_client_info(&AllocatorSetDebugClientInfoRequest {
182 name: Some(name.to_string()),
183 id: Some(koid.raw_koid()),
184 ..Default::default()
185 })?;
186 }
187 let collection_token = {
188 let (proxy, remote) = create_proxy::<BufferCollectionTokenMarker>();
189 allocator.allocate_shared_collection(AllocatorAllocateSharedCollectionRequest {
190 token_request: Some(remote),
191 ..Default::default()
192 })?;
193 proxy
194 };
195 if let Some(ref name) = params.name {
199 collection_token.set_name(&NodeSetNameRequest {
200 priority: Some(100),
201 name: Some(name.clone()),
202 ..Default::default()
203 })?;
204 }
205
206 let display_duplicate = {
208 let (local, remote) = create_endpoints::<BufferCollectionTokenMarker>();
209 collection_token.duplicate(BufferCollectionTokenDuplicateRequest {
210 rights_attenuation_mask: Some(fidl::Rights::SAME_RIGHTS),
211 token_request: Some(remote),
212 ..Default::default()
213 })?;
214 collection_token.sync().await?;
215 local
216 };
217
218 let id = coordinator.import_buffer_collection(display_duplicate).await?;
220
221 match allocate_image_buffer_helper(params, allocator, collection_token).await {
223 Ok((info, proxy)) => Ok(BufferCollection { id, info, proxy, coordinator, released: false }),
224 Err(error) => {
225 let _ = coordinator.release_buffer_collection(id);
226 Err(error)
227 }
228 }
229}
230
231async fn allocate_image_buffer_helper(
232 params: &ImageParameters,
233 allocator: fsysmem2::AllocatorProxy,
234 token: BufferCollectionTokenProxy,
235) -> Result<(BufferCollectionInfo, BufferCollectionProxy)> {
236 let collection = {
238 let (local, remote) = create_endpoints::<BufferCollectionMarker>();
239 let token_client = token.into_client_end().map_err(|_| Error::SysmemConnection)?;
240 allocator.bind_shared_collection(AllocatorBindSharedCollectionRequest {
241 token: Some(token_client),
242 buffer_collection_request: Some(remote),
243 ..Default::default()
244 })?;
245 local.into_proxy()
246 };
247
248 collection.set_constraints(BufferCollectionSetConstraintsRequest {
250 constraints: Some(buffer_collection_constraints(params)),
251 ..Default::default()
252 })?;
253 let collection_info = {
254 let response = collection
255 .wait_for_all_buffers_allocated()
256 .await?
257 .map_err(|_| Error::BuffersNotAllocated)?;
258 response.buffer_collection_info.ok_or(Error::BuffersNotAllocated)?
259 };
260
261 if collection_info.buffers.as_ref().unwrap().is_empty() {
263 collection.release()?;
264 return Err(Error::BuffersNotAllocated);
265 }
266
267 Ok((collection_info, collection))
268}
269
270fn buffer_collection_constraints(
271 params: &ImageParameters,
272) -> fsysmem2::BufferCollectionConstraints {
273 let usage = fsysmem2::BufferUsage {
274 cpu: Some(fsysmem2::CPU_USAGE_READ_OFTEN | fsysmem2::CPU_USAGE_WRITE_OFTEN),
275 ..Default::default()
276 };
277
278 let buffer_memory_constraints = fsysmem2::BufferMemoryConstraints {
279 ram_domain_supported: Some(true),
280 cpu_domain_supported: Some(true),
281 ..Default::default()
282 };
283
284 let image_constraints = fsysmem2::ImageFormatConstraints {
286 pixel_format: Some(params.pixel_format.into()),
287 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
288 required_max_size: Some(fidl_fuchsia_math::SizeU {
289 width: params.width,
290 height: params.height,
291 }),
292 color_spaces: Some(vec![params.color_space]),
293 ..Default::default()
294 };
295
296 let constraints = fsysmem2::BufferCollectionConstraints {
297 min_buffer_count: Some(1),
298 usage: Some(usage),
299 buffer_memory_constraints: Some(buffer_memory_constraints),
300 image_format_constraints: Some(vec![image_constraints]),
301 ..Default::default()
302 };
303
304 constraints
305}