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