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