1use anyhow::{anyhow, format_err, Error};
6use fidl_fuchsia_math::{RectU, SizeU};
7use {
8 fidl_fuchsia_images2 as fimages2, fidl_fuchsia_sysmem as fsysmem,
9 fidl_fuchsia_sysmem2 as fsysmem2,
10};
11
12use super::linux_drm::DRM_FORMAT_MOD_LINEAR;
13use super::round_up_to_increment;
14
15pub const IMAGE_FORMAT_CONSTRAINTS_DEFAULT: fsysmem::ImageFormatConstraints =
17 fsysmem::ImageFormatConstraints {
18 pixel_format: fsysmem::PixelFormat {
19 type_: fsysmem::PixelFormatType::Nv12,
20 has_format_modifier: false,
21 format_modifier: fsysmem::FormatModifier { value: 0 },
22 },
23 color_spaces_count: 0,
24 color_space: [fsysmem::ColorSpace { type_: fsysmem::ColorSpaceType::Invalid }; 32],
25 min_coded_width: 0,
26 max_coded_width: 0,
27 min_coded_height: 0,
28 max_coded_height: 0,
29 min_bytes_per_row: 0,
30 max_bytes_per_row: 0,
31 max_coded_width_times_coded_height: 0,
32 layers: 0,
33 coded_width_divisor: 0,
34 coded_height_divisor: 0,
35 bytes_per_row_divisor: 0,
36 start_offset_divisor: 0,
37 display_width_divisor: 0,
38 display_height_divisor: 0,
39 required_min_coded_width: 0,
40 required_max_coded_width: 0,
41 required_min_coded_height: 0,
42 required_max_coded_height: 0,
43 required_min_bytes_per_row: 0,
44 required_max_bytes_per_row: 0,
45 };
46
47pub const BUFFER_USAGE_DEFAULT: fsysmem::BufferUsage =
49 fsysmem::BufferUsage { none: 0, cpu: 0, vulkan: 0, display: 0, video: 0 };
50
51pub const BUFFER_MEMORY_CONSTRAINTS_DEFAULT: fsysmem::BufferMemoryConstraints =
53 fsysmem::BufferMemoryConstraints {
54 min_size_bytes: 0,
55 max_size_bytes: u32::MAX,
56 physically_contiguous_required: false,
57 secure_required: false,
58 ram_domain_supported: false,
59 cpu_domain_supported: true,
60 inaccessible_domain_supported: false,
61 heap_permitted_count: 0,
62 heap_permitted: [fsysmem::HeapType::SystemRam; 32],
63 };
64
65pub const BUFFER_COLLECTION_CONSTRAINTS_DEFAULT: fsysmem::BufferCollectionConstraints =
67 fsysmem::BufferCollectionConstraints {
68 usage: BUFFER_USAGE_DEFAULT,
69 min_buffer_count_for_camping: 0,
70 min_buffer_count_for_dedicated_slack: 0,
71 min_buffer_count_for_shared_slack: 0,
72 min_buffer_count: 0,
73 max_buffer_count: 0,
74 has_buffer_memory_constraints: false,
75 buffer_memory_constraints: BUFFER_MEMORY_CONSTRAINTS_DEFAULT,
76 image_format_constraints_count: 0,
77 image_format_constraints: [IMAGE_FORMAT_CONSTRAINTS_DEFAULT; 32],
78 };
79
80pub fn get_plane_row_bytes_2(
85 image_format: &fimages2::ImageFormat,
86 plane: u32,
87) -> Result<u32, Error> {
88 let bytes_per_row = *image_format
89 .bytes_per_row
90 .as_ref()
91 .ok_or_else(|| anyhow!("ImageFormat.bytes_per_row missing - tiled format?"))?;
92 match plane {
93 0 => Ok(bytes_per_row),
94 1 => {
95 let pixel_format = image_format.pixel_format.as_ref().expect("pixel_format");
96 match pixel_format {
97 fimages2::PixelFormat::Nv12 => Ok(bytes_per_row),
98 fimages2::PixelFormat::I420 | fimages2::PixelFormat::Yv12 => Ok(bytes_per_row / 2),
99 _ => Err(anyhow!("Invalid pixel format for plane 1.")),
100 }
101 }
102 2 => {
103 let pixel_format = image_format.pixel_format.as_ref().expect("pixel_format");
104 match pixel_format {
105 fimages2::PixelFormat::I420 | fimages2::PixelFormat::Yv12 => Ok(bytes_per_row / 2),
106 _ => Err(anyhow!("Invalid pixel format for plane 2.")),
107 }
108 }
109 _ => Err(anyhow!("Invalid plane.")),
110 }
111}
112
113pub fn get_plane_row_bytes(image_format: &fsysmem::ImageFormat2, plane: u32) -> Result<u32, Error> {
118 match plane {
119 0 => Ok(image_format.bytes_per_row),
120 1 => match image_format.pixel_format.type_ {
121 fsysmem::PixelFormatType::Nv12 => Ok(image_format.bytes_per_row),
122 fsysmem::PixelFormatType::I420 | fsysmem::PixelFormatType::Yv12 => {
123 Ok(image_format.bytes_per_row / 2)
124 }
125 _ => Err(anyhow!("Invalid pixel format for plane 1.")),
126 },
127 2 => match image_format.pixel_format.type_ {
128 fsysmem::PixelFormatType::I420 | fsysmem::PixelFormatType::Yv12 => {
129 Ok(image_format.bytes_per_row / 2)
130 }
131 _ => Err(anyhow!("Invalid pixel format for plane 2.")),
132 },
133 _ => Err(anyhow!("Invalid plane.")),
134 }
135}
136
137pub fn image_format_plane_byte_offset_2(
142 image_format: &fimages2::ImageFormat,
143 plane: u32,
144) -> Result<u32, Error> {
145 match plane {
146 0 => Ok(0),
147 1 => match image_format.pixel_format.as_ref().expect("pixel_format") {
148 fimages2::PixelFormat::Nv12
149 | fimages2::PixelFormat::I420
150 | fimages2::PixelFormat::Yv12 => Ok(image_format.size.as_ref().expect("size").height
151 * image_format.bytes_per_row.as_ref().expect("bytes_per_row")),
152 _ => Err(anyhow!("Invalid pixelformat for plane 1.")),
153 },
154 2 => match image_format.pixel_format.as_ref().expect("pixel_format") {
155 fimages2::PixelFormat::I420 | fimages2::PixelFormat::Yv12 => {
156 let size = image_format.size.as_ref().expect("size");
157 let bytes_per_row = image_format.bytes_per_row.as_ref().expect("bytes_per_row");
158 Ok(size.height * bytes_per_row + size.height / 2 * bytes_per_row / 2)
159 }
160 _ => Err(anyhow!("Invalid pixelformat for plane 2.")),
161 },
162 _ => Err(anyhow!("Invalid plane.")),
163 }
164}
165
166pub fn image_format_plane_byte_offset(
171 image_format: &fsysmem::ImageFormat2,
172 plane: u32,
173) -> Result<u32, Error> {
174 match plane {
175 0 => Ok(0),
176 1 => match image_format.pixel_format.type_ {
177 fsysmem::PixelFormatType::Nv12
178 | fsysmem::PixelFormatType::I420
179 | fsysmem::PixelFormatType::Yv12 => {
180 Ok(image_format.coded_height * image_format.bytes_per_row)
181 }
182 _ => Err(anyhow!("Invalid pixelformat for plane 1.")),
183 },
184 2 => match image_format.pixel_format.type_ {
185 fsysmem::PixelFormatType::I420 | fsysmem::PixelFormatType::Yv12 => {
186 Ok(image_format.coded_height * image_format.bytes_per_row
187 + image_format.coded_height / 2 * image_format.bytes_per_row / 2)
188 }
189 _ => Err(anyhow!("Invalid pixelformat for plane 2.")),
190 },
191 _ => Err(anyhow!("Invalid plane.")),
192 }
193}
194
195pub fn linear_size(
199 coded_height: u32,
200 bytes_per_row: u32,
201 type_: &fsysmem::PixelFormatType,
202) -> Result<u32, Error> {
203 match type_ {
204 fsysmem::PixelFormatType::R8G8B8A8
205 | fsysmem::PixelFormatType::Bgra32
206 | fsysmem::PixelFormatType::Bgr24
207 | fsysmem::PixelFormatType::Rgb565
208 | fsysmem::PixelFormatType::Rgb332
209 | fsysmem::PixelFormatType::Rgb2220
210 | fsysmem::PixelFormatType::L8
211 | fsysmem::PixelFormatType::R8
212 | fsysmem::PixelFormatType::R8G8
213 | fsysmem::PixelFormatType::A2B10G10R10
214 | fsysmem::PixelFormatType::A2R10G10B10 => Ok(coded_height * bytes_per_row),
215 fsysmem::PixelFormatType::I420 => Ok(coded_height * bytes_per_row * 3 / 2),
216 fsysmem::PixelFormatType::M420 => Ok(coded_height * bytes_per_row * 3 / 2),
217 fsysmem::PixelFormatType::Nv12 => Ok(coded_height * bytes_per_row * 3 / 2),
218 fsysmem::PixelFormatType::Yuy2 => Ok(coded_height * bytes_per_row),
219 fsysmem::PixelFormatType::Yv12 => Ok(coded_height * bytes_per_row * 3 / 2),
220 _ => Err(anyhow!("Invalid pixel format.")),
221 }
222}
223
224pub fn constraints_to_image_format(
226 constraints: &fsysmem2::ImageFormatConstraints,
227 coded_width: u32,
228 coded_height: u32,
229) -> Result<fimages2::ImageFormat, Error> {
230 if let Some(min_size) = &constraints.min_size {
231 if coded_width < min_size.width {
232 return Err(anyhow!("Coded width < min_size.width"));
233 }
234 if coded_height < min_size.height {
235 return Err(anyhow!("Coded height < min_size.height"));
236 }
237 }
238 if let Some(max_size) = &constraints.max_size {
239 if coded_width > max_size.width {
240 return Err(anyhow!("Coded width > max_size.width"));
241 }
242 if coded_height > max_size.height {
243 return Err(anyhow!("Coded height > max_size.height"));
244 }
245 }
246
247 let pixel_format_and_modifier = first_pixel_format_and_modifier_from_constraints(constraints)?;
248
249 let color_space = if constraints.color_spaces.is_some()
250 && constraints.color_spaces.as_ref().unwrap().len() > 0
251 {
252 Some(constraints.color_spaces.as_ref().unwrap()[0])
253 } else {
254 None
255 };
256
257 let format = fimages2::ImageFormat {
258 pixel_format: Some(pixel_format_and_modifier.pixel_format),
259 pixel_format_modifier: Some(pixel_format_and_modifier.pixel_format_modifier),
260 size: Some(SizeU { width: coded_width, height: coded_height }),
261 bytes_per_row: image_format_minimum_row_bytes_2(constraints, coded_width).ok(),
262 color_space,
263 ..Default::default()
264 };
265
266 Ok(format)
267}
268
269pub fn constraints_to_format(
271 constraints: &fsysmem::ImageFormatConstraints,
272 coded_width: u32,
273 coded_height: u32,
274) -> Result<fsysmem::ImageFormat2, Error> {
275 if coded_width < constraints.min_coded_width
276 || (constraints.max_coded_width > 0 && coded_width > constraints.max_coded_width)
277 {
278 return Err(anyhow!("Coded width not within constraint bounds."));
279 }
280 if coded_height < constraints.min_coded_height
281 || (constraints.max_coded_height > 0 && coded_height > constraints.max_coded_height)
282 {
283 return Err(anyhow!("Coded height not within constraint bounds."));
284 }
285
286 let format = fsysmem::ImageFormat2 {
287 pixel_format: constraints.pixel_format,
288 coded_width,
289 coded_height,
290 bytes_per_row: image_format_minimum_row_bytes(constraints, coded_width).unwrap_or(0),
291 display_width: coded_width,
292 display_height: coded_height,
293 layers: 0,
294 color_space: if constraints.color_spaces_count > 0 {
295 constraints.color_space[0]
296 } else {
297 fsysmem::ColorSpace { type_: fsysmem::ColorSpaceType::Invalid }
298 },
299 has_pixel_aspect_ratio: false,
300 pixel_aspect_ratio_width: 0,
301 pixel_aspect_ratio_height: 0,
302 };
303
304 Ok(format)
305}
306
307fn first_pixel_format_and_modifier_from_constraints(
308 constraints: &fsysmem2::ImageFormatConstraints,
309) -> Result<fsysmem2::PixelFormatAndModifier, Error> {
310 Ok(if let Some(pixel_format) = constraints.pixel_format {
311 fsysmem2::PixelFormatAndModifier {
312 pixel_format,
313 pixel_format_modifier: *constraints
314 .pixel_format_modifier
315 .as_ref()
316 .unwrap_or(&fimages2::PixelFormatModifier::Linear),
317 }
318 } else {
319 constraints
320 .pixel_format_and_modifiers
321 .as_ref()
322 .ok_or_else(|| format_err!("missing pixel_format"))?
323 .get(0)
324 .ok_or_else(|| format_err!("missing pixel_format"))?
325 .clone()
326 })
327}
328
329pub fn image_format_minimum_row_bytes_2(
334 constraints: &fsysmem2::ImageFormatConstraints,
335 width: u32,
336) -> Result<u32, Error> {
337 if let Some(pixel_format_modifier) = constraints.pixel_format_modifier {
338 if pixel_format_modifier != fimages2::PixelFormatModifier::Linear {
339 return Err(anyhow!("Non-linear format modifier."));
340 }
341 }
342 if let Some(min_size) = constraints.min_size {
343 if width < min_size.width {
344 return Err(anyhow!("width < min_size.width"));
345 }
346 }
347 if let Some(max_size) = constraints.max_size {
348 if width > max_size.width {
349 return Err(anyhow!("width > max_size.width"));
350 }
351 }
352
353 let constraints_min_bytes_per_row = constraints.min_bytes_per_row.unwrap_or(0);
354
355 let maybe_stride_bytes_per_width_pixel = image_format_stride_bytes_per_width_pixel_2(
356 *constraints.pixel_format.as_ref().expect("pixel_format"),
357 )
358 .ok();
359
360 let mut bytes_per_row_divisor = constraints.bytes_per_row_divisor.unwrap_or(1);
361 if *constraints.require_bytes_per_row_at_pixel_boundary.as_ref().unwrap_or(&false) {
362 let stride_bytes_per_width_pixel = *maybe_stride_bytes_per_width_pixel.as_ref().ok_or_else(|| format_err!("stride_bytes_per_width_pixel required when require_bytes_per_row_at_pixel_boundary true"))?;
363 bytes_per_row_divisor =
364 num::integer::lcm(bytes_per_row_divisor, stride_bytes_per_width_pixel);
365 }
366 let bytes_per_row_divisor = bytes_per_row_divisor;
367
368 round_up_to_increment(
369 std::cmp::max(
370 maybe_stride_bytes_per_width_pixel.unwrap_or(0) * width,
371 constraints_min_bytes_per_row,
372 ) as usize,
373 bytes_per_row_divisor as usize,
374 )
375 .map(|bytes| bytes as u32)
376}
377
378pub fn image_format_minimum_row_bytes(
383 constraints: &fsysmem::ImageFormatConstraints,
384 width: u32,
385) -> Result<u32, Error> {
386 if constraints.pixel_format.format_modifier.value != DRM_FORMAT_MOD_LINEAR {
387 return Err(anyhow!("Non-linear format modifier."));
388 }
389 if width < constraints.min_coded_width
390 || (constraints.max_coded_width > 0 && width > constraints.max_coded_width)
391 {
392 return Err(anyhow!("Width outside of constraints."));
393 }
394
395 let constraints_min_bytes_per_row = constraints.min_bytes_per_row;
396 let constraints_bytes_per_row_divisor = constraints.bytes_per_row_divisor;
397
398 round_up_to_increment(
399 std::cmp::max(
400 image_format_stride_bytes_per_width_pixel(&constraints.pixel_format) * width,
401 constraints_min_bytes_per_row,
402 ) as usize,
403 constraints_bytes_per_row_divisor as usize,
404 )
405 .map(|bytes| bytes as u32)
406}
407
408pub fn image_format_stride_bytes_per_width_pixel_2(
409 pixel_format: fimages2::PixelFormat,
410) -> Result<u32, Error> {
411 match pixel_format {
412 fimages2::PixelFormat::R8G8B8A8 => Ok(4),
413 fimages2::PixelFormat::R8G8B8X8 => Ok(4),
414 fimages2::PixelFormat::B8G8R8A8 => Ok(4),
415 fimages2::PixelFormat::B8G8R8X8 => Ok(4),
416 fimages2::PixelFormat::B8G8R8 => Ok(3),
417 fimages2::PixelFormat::R8G8B8 => Ok(3),
418 fimages2::PixelFormat::I420 => Ok(1),
419 fimages2::PixelFormat::M420 => Ok(1),
420 fimages2::PixelFormat::Nv12 => Ok(1),
421 fimages2::PixelFormat::Yuy2 => Ok(2),
422 fimages2::PixelFormat::Yv12 => Ok(1),
423 fimages2::PixelFormat::R5G6B5 => Ok(2),
424 fimages2::PixelFormat::R3G3B2 => Ok(1),
425 fimages2::PixelFormat::R2G2B2X2 => Ok(1),
426 fimages2::PixelFormat::L8 => Ok(1),
427 fimages2::PixelFormat::R8 => Ok(1),
428 fimages2::PixelFormat::R8G8 => Ok(2),
429 fimages2::PixelFormat::A2B10G10R10 => Ok(4),
430 fimages2::PixelFormat::A2R10G10B10 => Ok(4),
431 fimages2::PixelFormat::P010 => Ok(2),
432 _ => Err(format_err!(
433 "stride_bytes_per_width_pixel not available for pixel_format: {:?}",
434 pixel_format
435 )),
436 }
437}
438
439pub fn image_format_stride_bytes_per_width_pixel(pixel_format: &fsysmem::PixelFormat) -> u32 {
440 match pixel_format.type_ {
441 fsysmem::PixelFormatType::Invalid
442 | fsysmem::PixelFormatType::Mjpeg
443 | fsysmem::PixelFormatType::DoNotCare => 0,
444 fsysmem::PixelFormatType::R8G8B8A8 => 4,
445 fsysmem::PixelFormatType::Bgra32 => 4,
446 fsysmem::PixelFormatType::Bgr24 => 3,
447 fsysmem::PixelFormatType::I420 => 1,
448 fsysmem::PixelFormatType::M420 => 1,
449 fsysmem::PixelFormatType::Nv12 => 1,
450 fsysmem::PixelFormatType::Yuy2 => 2,
451 fsysmem::PixelFormatType::Yv12 => 1,
452 fsysmem::PixelFormatType::Rgb565 => 2,
453 fsysmem::PixelFormatType::Rgb332 => 1,
454 fsysmem::PixelFormatType::Rgb2220 => 1,
455 fsysmem::PixelFormatType::L8 => 1,
456 fsysmem::PixelFormatType::R8 => 1,
457 fsysmem::PixelFormatType::R8G8 => 2,
458 fsysmem::PixelFormatType::A2B10G10R10 => 4,
459 fsysmem::PixelFormatType::A2R10G10B10 => 4,
460 }
461}
462
463pub fn sysmem1_pixel_format_type_from_images2_pixel_format(
464 pixel_format: fimages2::PixelFormat,
465) -> Result<fsysmem::PixelFormatType, Error> {
466 fsysmem::PixelFormatType::from_primitive(pixel_format.into_primitive())
467 .ok_or_else(|| format_err!("pixel_format not convertible to sysmem1: {:?}", pixel_format))
468}
469
470pub fn images2_pixel_format_from_sysmem_pixel_format_type(
471 pixel_format: fsysmem::PixelFormatType,
472) -> Result<fimages2::PixelFormat, Error> {
473 fimages2::PixelFormat::from_primitive(pixel_format.into_primitive())
474 .ok_or_else(|| format_err!("pixel_format not convertible to images2: {:?}", pixel_format))
475}
476
477pub fn sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
478 pixel_format_modifier: fimages2::PixelFormatModifier,
479) -> u64 {
480 if pixel_format_modifier == fimages2::PixelFormatModifier::GoogleGoldfishOptimal {
481 return fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL;
482 }
483 pixel_format_modifier.into_primitive()
484}
485
486pub fn images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
487 pixel_format_modifier: u64,
488) -> Result<fimages2::PixelFormatModifier, Error> {
489 if pixel_format_modifier == fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL {
490 return Ok(fimages2::PixelFormatModifier::GoogleGoldfishOptimal);
491 }
492 fimages2::PixelFormatModifier::from_primitive(pixel_format_modifier).ok_or_else(|| {
493 format_err!("pixel_format_modifier not convertible to images2: {:?}", pixel_format_modifier)
494 })
495}
496
497pub fn sysmem1_color_space_type_from_images2_color_space(
498 color_space: fimages2::ColorSpace,
499) -> Result<fsysmem::ColorSpaceType, Error> {
500 fsysmem::ColorSpaceType::from_primitive(color_space.into_primitive())
501 .ok_or_else(|| format_err!("color_space not convertible to sysmem1: {:?}", color_space))
502}
503
504pub fn images2_color_space_from_sysmem_color_space_type(
505 color_space: fsysmem::ColorSpaceType,
506) -> fimages2::ColorSpace {
507 fimages2::ColorSpace::from_primitive(color_space.into_primitive()).unwrap()
510}
511
512pub fn sysmem1_image_format_from_images2_image_format(
513 image_format: &fimages2::ImageFormat,
514) -> Result<fsysmem::ImageFormat2, Error> {
515 let coded_size = image_format.size.as_ref().ok_or_else(|| format_err!("missing size"))?;
516 let format_modifier = sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
517 *image_format
518 .pixel_format_modifier
519 .as_ref()
520 .unwrap_or(&fimages2::PixelFormatModifier::Linear),
521 );
522 let bytes_per_row = match format_modifier {
525 fsysmem::FORMAT_MODIFIER_LINEAR => {
526 *image_format
528 .bytes_per_row
529 .as_ref()
530 .ok_or_else(|| format_err!("missing bytes_per_row (required when Linear)"))?
531 }
532 _ => {
533 *image_format.bytes_per_row.as_ref().unwrap_or(&0)
535 }
536 };
537 let display_rect = image_format.display_rect.as_ref();
538 let color_space_type = sysmem1_color_space_type_from_images2_color_space(
539 *image_format.color_space.as_ref().ok_or_else(|| format_err!("missing color_space"))?,
540 )?;
541 let pixel_aspect_ratio = image_format.pixel_aspect_ratio.as_ref();
542 Ok(fsysmem::ImageFormat2 {
543 pixel_format: fsysmem::PixelFormat {
544 type_: sysmem1_pixel_format_type_from_images2_pixel_format(
545 *image_format
546 .pixel_format
547 .as_ref()
548 .ok_or_else(|| format_err!("missing pixel_format"))?,
549 )?,
550 has_format_modifier: image_format.pixel_format_modifier.is_some(),
554 format_modifier: fsysmem::FormatModifier { value: format_modifier },
555 },
556 coded_width: coded_size.width,
557 coded_height: coded_size.height,
558 bytes_per_row,
559 display_width: display_rect.map(|rect| rect.width).unwrap_or(0),
560 display_height: display_rect.map(|rect| rect.height).unwrap_or(0),
561 layers: 1,
562 color_space: fsysmem::ColorSpace { type_: color_space_type },
563 has_pixel_aspect_ratio: pixel_aspect_ratio.is_some(),
564 pixel_aspect_ratio_width: pixel_aspect_ratio.map(|size| size.width).unwrap_or(0),
565 pixel_aspect_ratio_height: pixel_aspect_ratio.map(|size| size.height).unwrap_or(0),
566 })
567}
568
569pub fn images2_image_format_from_sysmem_image_format(
570 image_format: &fsysmem::ImageFormat2,
571) -> Result<fimages2::ImageFormat, Error> {
572 let pixel_format_modifier = if image_format.pixel_format.has_format_modifier {
573 Some(images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
574 image_format.pixel_format.format_modifier.value,
575 )?)
576 } else {
577 None
578 };
579 let display_rect = if image_format.display_width != 0 || image_format.display_height != 0 {
580 let display_width = if image_format.display_width != 0 {
581 image_format.display_width
582 } else {
583 image_format.coded_width
584 };
585 let display_height = if image_format.display_height != 0 {
586 image_format.display_height
587 } else {
588 image_format.coded_height
589 };
590 Some(RectU { x: 0, y: 0, width: display_width, height: display_height })
591 } else {
592 None
593 };
594 let pixel_aspect_ratio = if image_format.has_pixel_aspect_ratio {
595 Some(SizeU {
596 width: image_format.pixel_aspect_ratio_width,
597 height: image_format.pixel_aspect_ratio_height,
598 })
599 } else {
600 None
601 };
602 Ok(fimages2::ImageFormat {
603 pixel_format: Some(images2_pixel_format_from_sysmem_pixel_format_type(
604 image_format.pixel_format.type_,
605 )?),
606 pixel_format_modifier,
607 color_space: Some(images2_color_space_from_sysmem_color_space_type(
608 image_format.color_space.type_,
609 )),
610 size: Some(SizeU { width: image_format.coded_width, height: image_format.coded_height }),
611 bytes_per_row: Some(image_format.bytes_per_row),
612 display_rect,
613 pixel_aspect_ratio,
614 ..Default::default()
615 })
616}
617
618#[cfg(test)]
619mod tests {
620 use super::*;
621 use fidl_fuchsia_math as fmath;
622
623 #[test]
624 fn test_linear_row_bytes_2() {
625 let constraints = fsysmem2::ImageFormatConstraints {
626 pixel_format: Some(fimages2::PixelFormat::B8G8R8A8),
627 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
628 min_size: Some(SizeU { width: 12, height: 12 }),
629 max_size: Some(SizeU { width: 100, height: 100 }),
630 bytes_per_row_divisor: Some(4 * 8),
631 max_bytes_per_row: Some(100000),
632 ..Default::default()
633 };
634
635 assert_eq!(image_format_minimum_row_bytes_2(&constraints, 17).unwrap(), 4 * 24);
636
637 assert!(image_format_minimum_row_bytes_2(&constraints, 11).is_err());
638 assert!(image_format_minimum_row_bytes_2(&constraints, 101).is_err());
639 }
640
641 #[test]
642 fn test_linear_row_bytes() {
643 let linear = fsysmem::PixelFormat {
644 type_: fsysmem::PixelFormatType::Bgra32,
645 has_format_modifier: true,
646 format_modifier: fsysmem::FormatModifier { value: fsysmem::FORMAT_MODIFIER_LINEAR },
647 };
648
649 let constraints = fsysmem::ImageFormatConstraints {
650 pixel_format: linear,
651 min_coded_width: 12,
652 max_coded_width: 100,
653 bytes_per_row_divisor: 4 * 8,
654 max_bytes_per_row: 100000,
655 ..IMAGE_FORMAT_CONSTRAINTS_DEFAULT
656 };
657
658 assert_eq!(image_format_minimum_row_bytes(&constraints, 17).unwrap(), 4 * 24);
659
660 assert!(image_format_minimum_row_bytes(&constraints, 11).is_err());
661 assert!(image_format_minimum_row_bytes(&constraints, 101).is_err());
662 }
663
664 #[test]
665 fn plane_byte_offset_2() {
666 let constraints = fsysmem2::ImageFormatConstraints {
667 pixel_format: Some(fimages2::PixelFormat::B8G8R8A8),
668 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
669 min_size: Some(SizeU { width: 12, height: 12 }),
670 max_size: Some(SizeU { width: 100, height: 100 }),
671 bytes_per_row_divisor: Some(4 * 8),
672 max_bytes_per_row: Some(100000),
673 ..Default::default()
674 };
675
676 let image_format = constraints_to_image_format(&constraints, 18, 17).unwrap();
677 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), 96);
679
680 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
681 assert!(image_format_plane_byte_offset_2(&image_format, 1).is_err());
682
683 let constraints = fsysmem2::ImageFormatConstraints {
684 pixel_format: Some(fimages2::PixelFormat::I420),
685 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
686 min_size: Some(SizeU { width: 12, height: 12 }),
687 max_size: Some(SizeU { width: 100, height: 100 }),
688 bytes_per_row_divisor: Some(4 * 8),
689 max_bytes_per_row: Some(100000),
690 ..Default::default()
691 };
692
693 const BYTES_PER_ROW: u32 = 32;
694 let image_format = constraints_to_image_format(&constraints, 18, 20).unwrap();
695 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), BYTES_PER_ROW);
696
697 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
698 assert_eq!(image_format_plane_byte_offset_2(&image_format, 1).unwrap(), BYTES_PER_ROW * 20);
699 assert_eq!(
700 image_format_plane_byte_offset_2(&image_format, 2).unwrap(),
701 BYTES_PER_ROW * 20 + BYTES_PER_ROW / 2 * 20 / 2
702 );
703 assert!(image_format_plane_byte_offset_2(&image_format, 3).is_err());
704
705 assert_eq!(get_plane_row_bytes_2(&image_format, 0).unwrap(), BYTES_PER_ROW);
706 assert_eq!(get_plane_row_bytes_2(&image_format, 1).unwrap(), BYTES_PER_ROW / 2);
707 assert_eq!(get_plane_row_bytes_2(&image_format, 2).unwrap(), BYTES_PER_ROW / 2);
708 assert!(get_plane_row_bytes_2(&image_format, 3).is_err())
709 }
710
711 #[test]
712 fn plane_byte_offset() {
713 let constraints = fsysmem2::ImageFormatConstraints {
714 pixel_format: Some(fimages2::PixelFormat::B8G8R8A8),
715 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
716 min_size: Some(SizeU { width: 12, height: 12 }),
717 max_size: Some(SizeU { width: 100, height: 100 }),
718 bytes_per_row_divisor: Some(4 * 8),
719 max_bytes_per_row: Some(100000),
720 ..Default::default()
721 };
722
723 let image_format = constraints_to_image_format(&constraints, 18, 17).unwrap();
724 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), 96);
726
727 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
728 assert!(image_format_plane_byte_offset_2(&image_format, 1).is_err());
729
730 let constraints = fsysmem2::ImageFormatConstraints {
731 pixel_format: Some(fimages2::PixelFormat::I420),
732 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
733 min_size: Some(SizeU { width: 12, height: 12 }),
734 max_size: Some(SizeU { width: 100, height: 100 }),
735 bytes_per_row_divisor: Some(4 * 8),
736 max_bytes_per_row: Some(100000),
737 ..Default::default()
738 };
739
740 const BYTES_PER_ROW: u32 = 32;
741 let image_format = constraints_to_image_format(&constraints, 18, 20).unwrap();
742 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), BYTES_PER_ROW);
743
744 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
745 assert_eq!(image_format_plane_byte_offset_2(&image_format, 1).unwrap(), BYTES_PER_ROW * 20);
746 assert_eq!(
747 image_format_plane_byte_offset_2(&image_format, 2).unwrap(),
748 BYTES_PER_ROW * 20 + BYTES_PER_ROW / 2 * 20 / 2
749 );
750 assert!(image_format_plane_byte_offset_2(&image_format, 3).is_err());
751
752 assert_eq!(get_plane_row_bytes_2(&image_format, 0).unwrap(), BYTES_PER_ROW);
753 assert_eq!(get_plane_row_bytes_2(&image_format, 1).unwrap(), BYTES_PER_ROW / 2);
754 assert_eq!(get_plane_row_bytes_2(&image_format, 2).unwrap(), BYTES_PER_ROW / 2);
755 assert!(get_plane_row_bytes_2(&image_format, 3).is_err())
756 }
757
758 #[test]
759 fn test_constraints_to_image_format() {
760 let constraints = fsysmem2::ImageFormatConstraints {
763 pixel_format: Some(fimages2::PixelFormat::R8G8B8),
764 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
765 min_size: Some(SizeU { width: 12, height: 12 }),
766 max_size: Some(SizeU { width: 100, height: 100 }),
767 bytes_per_row_divisor: Some(4 * 8),
768 max_bytes_per_row: Some(100000),
769 color_spaces: Some(vec![fimages2::ColorSpace::Rec709]),
770 min_bytes_per_row: Some(24),
771 max_width_times_height: Some(12 * 12),
772 size_alignment: Some(fmath::SizeU { width: 37, height: 1 }),
773 display_rect_alignment: Some(fmath::SizeU { width: 37, height: 37 }),
774 required_min_size: Some(fmath::SizeU { width: 37, height: 37 }),
775 required_max_size: Some(fmath::SizeU { width: 37, height: 37 }),
776 start_offset_divisor: Some(37),
777 pixel_format_and_modifiers: Some(vec![fsysmem2::PixelFormatAndModifier {
778 pixel_format: fimages2::PixelFormat::Yv12,
779 pixel_format_modifier: fimages2::PixelFormatModifier::GoogleGoldfishOptimal,
780 }]),
781 require_bytes_per_row_at_pixel_boundary: Some(true),
782 ..Default::default()
783 };
784
785 let image_format = constraints_to_image_format(&constraints, 18, 17).unwrap();
786
787 assert_eq!(image_format.pixel_format, Some(fimages2::PixelFormat::R8G8B8));
788 assert_eq!(image_format.pixel_format_modifier, Some(fimages2::PixelFormatModifier::Linear));
789 assert_eq!(image_format.color_space, Some(fimages2::ColorSpace::Rec709));
790 assert_eq!(image_format.size, Some(fmath::SizeU { width: 18, height: 17 }));
791 assert_eq!(image_format.bytes_per_row, Some(96));
792
793 assert_eq!(image_format.display_rect, None);
795 assert_eq!(image_format.valid_size, None);
796 assert_eq!(image_format.pixel_aspect_ratio, None);
797 }
798
799 #[test]
800 fn test_image_format_stride_bytes_per_width_pixel_2() {
801 assert_eq!(
802 4,
803 image_format_stride_bytes_per_width_pixel_2(fimages2::PixelFormat::R8G8B8A8).unwrap()
804 );
805 assert!(
806 image_format_stride_bytes_per_width_pixel_2(fimages2::PixelFormat::DoNotCare).is_err()
807 );
808 }
809
810 #[test]
811 fn test_sysmem1_pixel_format_type_from_images2_pixel_format() {
812 assert_eq!(
813 fsysmem::PixelFormatType::Bgra32,
814 sysmem1_pixel_format_type_from_images2_pixel_format(fimages2::PixelFormat::B8G8R8A8)
815 .unwrap()
816 );
817 assert!(sysmem1_pixel_format_type_from_images2_pixel_format(
818 fimages2::PixelFormat::from_primitive_allow_unknown(1189673091)
819 )
820 .is_err());
821 }
822
823 #[test]
824 fn test_sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier() {
825 assert_eq!(
826 fsysmem::FORMAT_MODIFIER_ARM_AFBC_16_X16_SPLIT_BLOCK_SPARSE_YUV_TE_TILED_HEADER,
827 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
828 fimages2::PixelFormatModifier::ArmAfbc16X16SplitBlockSparseYuvTeTiledHeader
829 )
830 );
831 assert_eq!(
832 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL,
833 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
834 fimages2::PixelFormatModifier::GoogleGoldfishOptimal
835 )
836 );
837 assert_eq!(
838 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL,
839 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
840 fimages2::PixelFormatModifier::from_primitive_allow_unknown(
841 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL
842 )
843 )
844 );
845 assert_eq!(
847 1189673091,
848 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
849 fimages2::PixelFormatModifier::from_primitive_allow_unknown(1189673091)
850 )
851 );
852 }
853
854 #[test]
855 fn test_images2_pixel_format_from_sysmem_pixel_format_type() {
856 assert_eq!(
857 fimages2::PixelFormat::B8G8R8A8,
858 images2_pixel_format_from_sysmem_pixel_format_type(fsysmem::PixelFormatType::Bgra32)
859 .unwrap()
860 );
861 assert_eq!(
862 fimages2::PixelFormat::Yv12,
863 images2_pixel_format_from_sysmem_pixel_format_type(fsysmem::PixelFormatType::Yv12)
864 .unwrap()
865 );
866 }
867
868 #[test]
869 fn test_images2_pixel_format_modifier_from_sysmem_pixel_format_modifier() {
870 assert_eq!(
871 fimages2::PixelFormatModifier::ArmAfbc16X16SplitBlockSparseYuvTeTiledHeader,
872 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
873 fsysmem::FORMAT_MODIFIER_ARM_AFBC_16_X16_SPLIT_BLOCK_SPARSE_YUV_TE_TILED_HEADER
874 )
875 .unwrap()
876 );
877 assert_eq!(
878 fimages2::PixelFormatModifier::GoogleGoldfishOptimal,
879 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
880 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL
881 )
882 .unwrap()
883 );
884 assert_eq!(
885 fimages2::PixelFormatModifier::GoogleGoldfishOptimal,
886 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
887 fimages2::PixelFormatModifier::GoogleGoldfishOptimal.into_primitive()
888 )
889 .unwrap()
890 );
891 assert!(
892 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(1189673091).is_err()
893 );
894 }
895
896 #[test]
897 fn test_sysmem1_color_space_type_from_images2_color_space() {
898 assert_eq!(
899 fsysmem::ColorSpaceType::Rec709,
900 sysmem1_color_space_type_from_images2_color_space(fimages2::ColorSpace::Rec709)
901 .unwrap()
902 );
903 assert!(sysmem1_color_space_type_from_images2_color_space(
904 fimages2::ColorSpace::from_primitive_allow_unknown(1189673091)
905 )
906 .is_err());
907 }
908
909 #[test]
910 fn test_images2_color_space_from_sysmem_color_space_type() {
911 assert_eq!(
912 fimages2::ColorSpace::Rec709,
913 images2_color_space_from_sysmem_color_space_type(fsysmem::ColorSpaceType::Rec709)
914 );
915 assert_eq!(
916 fimages2::ColorSpace::Srgb,
917 images2_color_space_from_sysmem_color_space_type(fsysmem::ColorSpaceType::Srgb)
918 );
919 }
920
921 #[test]
922 fn test_sysmem1_image_format_from_images2_image_format() {
923 {
924 let images2_format = fimages2::ImageFormat {
925 pixel_format: Some(fimages2::PixelFormat::Yv12),
926 pixel_format_modifier: None,
927 color_space: Some(fimages2::ColorSpace::Rec709),
928 size: Some(fmath::SizeU { width: 17, height: 13 }),
929 bytes_per_row: Some(32),
930 display_rect: Some(fmath::RectU { x: 0, y: 0, width: 15, height: 11 }),
931 valid_size: Some(fmath::SizeU { width: 12, height: 10 }),
932 pixel_aspect_ratio: Some(fmath::SizeU { width: 2, height: 3 }),
933 ..Default::default()
934 };
935
936 let sysmem_format =
937 sysmem1_image_format_from_images2_image_format(&images2_format).unwrap();
938
939 assert_eq!(fsysmem::PixelFormatType::Yv12, sysmem_format.pixel_format.type_);
940 assert_eq!(false, sysmem_format.pixel_format.has_format_modifier);
941 assert_eq!(17, sysmem_format.coded_width);
942 assert_eq!(13, sysmem_format.coded_height);
943 assert_eq!(32, sysmem_format.bytes_per_row);
944 assert_eq!(15, sysmem_format.display_width);
945 assert_eq!(11, sysmem_format.display_height);
946 assert_eq!(1, sysmem_format.layers);
947 assert_eq!(fsysmem::ColorSpaceType::Rec709, sysmem_format.color_space.type_);
948 assert_eq!(true, sysmem_format.has_pixel_aspect_ratio);
949 assert_eq!(2, sysmem_format.pixel_aspect_ratio_width);
950 assert_eq!(3, sysmem_format.pixel_aspect_ratio_height);
951 }
952
953 {
954 let images2_format = fimages2::ImageFormat {
955 pixel_format: Some(fimages2::PixelFormat::Yv12),
956 pixel_format_modifier: Some(
957 fimages2::PixelFormatModifier::ArmAfbc16X16SplitBlockSparseYuvTeTiledHeader,
958 ),
959 color_space: Some(fimages2::ColorSpace::Rec709),
960 size: Some(fmath::SizeU { width: 17, height: 13 }),
961 bytes_per_row: Some(32),
962 display_rect: Some(fmath::RectU { x: 0, y: 0, width: 15, height: 11 }),
963 valid_size: Some(fmath::SizeU { width: 12, height: 10 }),
964 pixel_aspect_ratio: Some(fmath::SizeU { width: 2, height: 3 }),
965 ..Default::default()
966 };
967
968 let sysmem_format =
969 sysmem1_image_format_from_images2_image_format(&images2_format).unwrap();
970
971 assert_eq!(fsysmem::PixelFormatType::Yv12, sysmem_format.pixel_format.type_);
972 assert_eq!(true, sysmem_format.pixel_format.has_format_modifier);
973 assert_eq!(
974 fsysmem::FORMAT_MODIFIER_ARM_AFBC_16_X16_SPLIT_BLOCK_SPARSE_YUV_TE_TILED_HEADER,
975 sysmem_format.pixel_format.format_modifier.value
976 );
977 assert_eq!(17, sysmem_format.coded_width);
978 assert_eq!(13, sysmem_format.coded_height);
979 assert_eq!(32, sysmem_format.bytes_per_row);
980 assert_eq!(15, sysmem_format.display_width);
981 assert_eq!(11, sysmem_format.display_height);
982 assert_eq!(1, sysmem_format.layers);
983 assert_eq!(fsysmem::ColorSpaceType::Rec709, sysmem_format.color_space.type_);
984 assert_eq!(true, sysmem_format.has_pixel_aspect_ratio);
985 assert_eq!(2, sysmem_format.pixel_aspect_ratio_width);
986 assert_eq!(3, sysmem_format.pixel_aspect_ratio_height);
987 }
988 }
989
990 #[test]
991 fn test_images2_image_format_from_sysmem_image_format() {
992 let sysmem_format = fsysmem::ImageFormat2 {
993 pixel_format: fsysmem::PixelFormat {
994 type_: fsysmem::PixelFormatType::Yv12,
995 has_format_modifier: true,
996 format_modifier: fsysmem::FormatModifier {
997 value: fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL,
998 },
999 },
1000 coded_width: 17,
1001 coded_height: 13,
1002 bytes_per_row: 32,
1003 display_width: 15,
1004 display_height: 11,
1005 layers: 1,
1006 color_space: fsysmem::ColorSpace { type_: fsysmem::ColorSpaceType::Rec709 },
1007 has_pixel_aspect_ratio: true,
1008 pixel_aspect_ratio_width: 2,
1009 pixel_aspect_ratio_height: 3,
1010 };
1011
1012 let images2_format = images2_image_format_from_sysmem_image_format(&sysmem_format).unwrap();
1013
1014 assert_eq!(Some(fimages2::PixelFormat::Yv12), images2_format.pixel_format);
1015 assert_eq!(
1016 Some(fimages2::PixelFormatModifier::GoogleGoldfishOptimal),
1017 images2_format.pixel_format_modifier
1018 );
1019 assert_eq!(Some(fimages2::ColorSpace::Rec709), images2_format.color_space);
1020 assert_eq!(Some(fmath::SizeU { width: 17, height: 13 }), images2_format.size);
1021 assert_eq!(Some(32), images2_format.bytes_per_row);
1022 assert_eq!(
1023 Some(fmath::RectU { x: 0, y: 0, width: 15, height: 11 }),
1024 images2_format.display_rect
1025 );
1026 assert_eq!(None, images2_format.valid_size);
1027 assert_eq!(Some(fmath::SizeU { width: 2, height: 3 }), images2_format.pixel_aspect_ratio);
1028 }
1029}