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
79const PVRIC_TILES_PLANE: u32 = 0;
80const PVRIC_HEADER_PLANE: u32 = 3;
81const PVRIC_HEADER_ALIGNMENT: u32 = 256;
82
83fn is_pvric_pixel_format_supported(pixel_format: fimages2::PixelFormat) -> bool {
84 matches!(
85 pixel_format,
86 fimages2::PixelFormat::R8G8B8A8
87 | fimages2::PixelFormat::R8G8B8X8
88 | fimages2::PixelFormat::B8G8R8A8
89 | fimages2::PixelFormat::B8G8R8X8
90 | fimages2::PixelFormat::A2R10G10B10
91 | fimages2::PixelFormat::A2B10G10R10
92 | fimages2::PixelFormat::R5G6B5
93 )
94}
95
96#[derive(Clone, Copy, Debug, Eq, PartialEq)]
97pub struct PvricTilingData {
98 pub tile_rows: u32,
99 pub bytes_per_row_per_tile: u32,
100}
101
102pub fn pvric_tiling_data(modifier: fimages2::PixelFormatModifier) -> Option<PvricTilingData> {
103 match modifier {
104 fimages2::PixelFormatModifier::PvrFbcdc8X8V14 => {
105 Some(PvricTilingData { tile_rows: 8, bytes_per_row_per_tile: 32 })
106 }
107 fimages2::PixelFormatModifier::PvrFbcdc16X4V14 => {
108 Some(PvricTilingData { tile_rows: 4, bytes_per_row_per_tile: 64 })
109 }
110 _ => None,
111 }
112}
113
114pub fn get_plane_row_bytes_2(
119 image_format: &fimages2::ImageFormat,
120 plane: u32,
121) -> Result<u32, Error> {
122 let bytes_per_row = *image_format
123 .bytes_per_row
124 .as_ref()
125 .ok_or_else(|| anyhow!("ImageFormat.bytes_per_row missing - tiled format?"))?;
126
127 if let Some(modifier) = image_format.pixel_format_modifier {
130 if let Some(tiling) = pvric_tiling_data(modifier) {
131 let pixel_format = *image_format
132 .pixel_format
133 .as_ref()
134 .ok_or_else(|| anyhow!("ImageFormat.pixel_format missing"))?;
135 if !is_pvric_pixel_format_supported(pixel_format) {
136 return Err(anyhow!("Invalid pixel format for PVRIC modifier."));
137 }
138 let width_in_tiles = bytes_per_row.div_ceil(tiling.bytes_per_row_per_tile);
139 return match plane {
140 PVRIC_TILES_PLANE => width_in_tiles
141 .checked_mul(tiling.bytes_per_row_per_tile)
142 .ok_or_else(|| anyhow!("Overflow calculating plane 0 row bytes.")),
143 PVRIC_HEADER_PLANE => Ok(width_in_tiles),
144 _ => Err(anyhow!("Invalid plane.")),
145 };
146 }
147 }
148 match plane {
149 0 => Ok(bytes_per_row),
150 1 => {
151 let pixel_format = image_format.pixel_format.as_ref().expect("pixel_format");
152 match pixel_format {
153 fimages2::PixelFormat::Nv12 => Ok(bytes_per_row),
154 fimages2::PixelFormat::I420 | fimages2::PixelFormat::Yv12 => Ok(bytes_per_row / 2),
155 _ => Err(anyhow!("Invalid pixel format for plane 1.")),
156 }
157 }
158 2 => {
159 let pixel_format = image_format.pixel_format.as_ref().expect("pixel_format");
160 match pixel_format {
161 fimages2::PixelFormat::I420 | fimages2::PixelFormat::Yv12 => Ok(bytes_per_row / 2),
162 _ => Err(anyhow!("Invalid pixel format for plane 2.")),
163 }
164 }
165 _ => Err(anyhow!("Invalid plane.")),
166 }
167}
168
169pub fn get_plane_row_bytes(image_format: &fsysmem::ImageFormat2, plane: u32) -> Result<u32, Error> {
174 match plane {
175 0 => Ok(image_format.bytes_per_row),
176 1 => match image_format.pixel_format.type_ {
177 fsysmem::PixelFormatType::Nv12 => Ok(image_format.bytes_per_row),
178 fsysmem::PixelFormatType::I420 | fsysmem::PixelFormatType::Yv12 => {
179 Ok(image_format.bytes_per_row / 2)
180 }
181 _ => Err(anyhow!("Invalid pixel format for plane 1.")),
182 },
183 2 => match image_format.pixel_format.type_ {
184 fsysmem::PixelFormatType::I420 | fsysmem::PixelFormatType::Yv12 => {
185 Ok(image_format.bytes_per_row / 2)
186 }
187 _ => Err(anyhow!("Invalid pixel format for plane 2.")),
188 },
189 _ => Err(anyhow!("Invalid plane.")),
190 }
191}
192
193pub fn image_format_plane_byte_offset_2(
198 image_format: &fimages2::ImageFormat,
199 plane: u32,
200) -> Result<u32, Error> {
201 if let Some(modifier) = image_format.pixel_format_modifier {
204 if let Some(tiling) = pvric_tiling_data(modifier) {
205 let pixel_format = *image_format
206 .pixel_format
207 .as_ref()
208 .ok_or_else(|| anyhow!("ImageFormat.pixel_format missing"))?;
209 if !is_pvric_pixel_format_supported(pixel_format) {
210 return Err(anyhow!("Invalid pixel format for PVRIC modifier."));
211 }
212 let bytes_per_row = *image_format
213 .bytes_per_row
214 .as_ref()
215 .ok_or_else(|| anyhow!("ImageFormat.bytes_per_row missing"))?;
216 let size =
217 image_format.size.as_ref().ok_or_else(|| anyhow!("ImageFormat.size missing"))?;
218 let width_in_tiles = bytes_per_row.div_ceil(tiling.bytes_per_row_per_tile);
219 let height_in_tiles = size.height.div_ceil(tiling.tile_rows);
220 let num_tiles = width_in_tiles
221 .checked_mul(height_in_tiles)
222 .ok_or_else(|| anyhow!("Overflow calculating num_tiles."))?;
223 let header_size = num_tiles
224 .checked_next_multiple_of(PVRIC_HEADER_ALIGNMENT)
225 .ok_or_else(|| anyhow!("Overflow calculating header_size."))?;
226 return match plane {
227 PVRIC_TILES_PLANE => Ok(header_size),
228 PVRIC_HEADER_PLANE => Ok(0),
229 _ => Err(anyhow!("Invalid plane.")),
230 };
231 }
232 }
233 match plane {
234 0 => Ok(0),
235 1 => match image_format.pixel_format.as_ref().expect("pixel_format") {
236 fimages2::PixelFormat::Nv12
237 | fimages2::PixelFormat::I420
238 | fimages2::PixelFormat::Yv12 => Ok(image_format.size.as_ref().expect("size").height
239 * image_format.bytes_per_row.as_ref().expect("bytes_per_row")),
240 _ => Err(anyhow!("Invalid pixelformat for plane 1.")),
241 },
242 2 => match image_format.pixel_format.as_ref().expect("pixel_format") {
243 fimages2::PixelFormat::I420 | fimages2::PixelFormat::Yv12 => {
244 let size = image_format.size.as_ref().expect("size");
245 let bytes_per_row = image_format.bytes_per_row.as_ref().expect("bytes_per_row");
246 Ok(size.height * bytes_per_row + size.height / 2 * bytes_per_row / 2)
247 }
248 _ => Err(anyhow!("Invalid pixelformat for plane 2.")),
249 },
250 _ => Err(anyhow!("Invalid plane.")),
251 }
252}
253
254pub fn image_format_plane_byte_offset(
259 image_format: &fsysmem::ImageFormat2,
260 plane: u32,
261) -> Result<u32, Error> {
262 match plane {
263 0 => Ok(0),
264 1 => match image_format.pixel_format.type_ {
265 fsysmem::PixelFormatType::Nv12
266 | fsysmem::PixelFormatType::I420
267 | fsysmem::PixelFormatType::Yv12 => {
268 Ok(image_format.coded_height * image_format.bytes_per_row)
269 }
270 _ => Err(anyhow!("Invalid pixelformat for plane 1.")),
271 },
272 2 => match image_format.pixel_format.type_ {
273 fsysmem::PixelFormatType::I420 | fsysmem::PixelFormatType::Yv12 => {
274 Ok(image_format.coded_height * image_format.bytes_per_row
275 + image_format.coded_height / 2 * image_format.bytes_per_row / 2)
276 }
277 _ => Err(anyhow!("Invalid pixelformat for plane 2.")),
278 },
279 _ => Err(anyhow!("Invalid plane.")),
280 }
281}
282
283pub fn linear_size(
287 coded_height: u32,
288 bytes_per_row: u32,
289 type_: &fsysmem::PixelFormatType,
290) -> Result<u32, Error> {
291 match type_ {
292 fsysmem::PixelFormatType::R8G8B8A8
293 | fsysmem::PixelFormatType::Bgra32
294 | fsysmem::PixelFormatType::Bgr24
295 | fsysmem::PixelFormatType::Rgb565
296 | fsysmem::PixelFormatType::Rgb332
297 | fsysmem::PixelFormatType::Rgb2220
298 | fsysmem::PixelFormatType::L8
299 | fsysmem::PixelFormatType::R8
300 | fsysmem::PixelFormatType::R8G8
301 | fsysmem::PixelFormatType::A2B10G10R10
302 | fsysmem::PixelFormatType::A2R10G10B10 => Ok(coded_height * bytes_per_row),
303 fsysmem::PixelFormatType::I420 => Ok(coded_height * bytes_per_row * 3 / 2),
304 fsysmem::PixelFormatType::M420 => Ok(coded_height * bytes_per_row * 3 / 2),
305 fsysmem::PixelFormatType::Nv12 => Ok(coded_height * bytes_per_row * 3 / 2),
306 fsysmem::PixelFormatType::Yuy2 => Ok(coded_height * bytes_per_row),
307 fsysmem::PixelFormatType::Yv12 => Ok(coded_height * bytes_per_row * 3 / 2),
308 _ => Err(anyhow!("Invalid pixel format.")),
309 }
310}
311
312pub fn constraints_to_image_format(
314 constraints: &fsysmem2::ImageFormatConstraints,
315 coded_width: u32,
316 coded_height: u32,
317) -> Result<fimages2::ImageFormat, Error> {
318 if let Some(min_size) = &constraints.min_size {
319 if coded_width < min_size.width {
320 return Err(anyhow!("Coded width < min_size.width"));
321 }
322 if coded_height < min_size.height {
323 return Err(anyhow!("Coded height < min_size.height"));
324 }
325 }
326 if let Some(max_size) = &constraints.max_size {
327 if coded_width > max_size.width {
328 return Err(anyhow!("Coded width > max_size.width"));
329 }
330 if coded_height > max_size.height {
331 return Err(anyhow!("Coded height > max_size.height"));
332 }
333 }
334
335 let pixel_format_and_modifier = first_pixel_format_and_modifier_from_constraints(constraints)?;
336
337 let color_space = if constraints.color_spaces.is_some()
338 && constraints.color_spaces.as_ref().unwrap().len() > 0
339 {
340 Some(constraints.color_spaces.as_ref().unwrap()[0])
341 } else {
342 None
343 };
344
345 let format = fimages2::ImageFormat {
346 pixel_format: Some(pixel_format_and_modifier.pixel_format),
347 pixel_format_modifier: Some(pixel_format_and_modifier.pixel_format_modifier),
348 size: Some(SizeU { width: coded_width, height: coded_height }),
349 bytes_per_row: image_format_minimum_row_bytes_2(constraints, coded_width).ok(),
350 color_space,
351 ..Default::default()
352 };
353
354 Ok(format)
355}
356
357pub fn constraints_to_format(
359 constraints: &fsysmem::ImageFormatConstraints,
360 coded_width: u32,
361 coded_height: u32,
362) -> Result<fsysmem::ImageFormat2, Error> {
363 if coded_width < constraints.min_coded_width
364 || (constraints.max_coded_width > 0 && coded_width > constraints.max_coded_width)
365 {
366 return Err(anyhow!("Coded width not within constraint bounds."));
367 }
368 if coded_height < constraints.min_coded_height
369 || (constraints.max_coded_height > 0 && coded_height > constraints.max_coded_height)
370 {
371 return Err(anyhow!("Coded height not within constraint bounds."));
372 }
373
374 let format = fsysmem::ImageFormat2 {
375 pixel_format: constraints.pixel_format,
376 coded_width,
377 coded_height,
378 bytes_per_row: image_format_minimum_row_bytes(constraints, coded_width).unwrap_or(0),
379 display_width: coded_width,
380 display_height: coded_height,
381 layers: 0,
382 color_space: if constraints.color_spaces_count > 0 {
383 constraints.color_space[0]
384 } else {
385 fsysmem::ColorSpace { type_: fsysmem::ColorSpaceType::Invalid }
386 },
387 has_pixel_aspect_ratio: false,
388 pixel_aspect_ratio_width: 0,
389 pixel_aspect_ratio_height: 0,
390 };
391
392 Ok(format)
393}
394
395fn first_pixel_format_and_modifier_from_constraints(
396 constraints: &fsysmem2::ImageFormatConstraints,
397) -> Result<fsysmem2::PixelFormatAndModifier, Error> {
398 Ok(if let Some(pixel_format) = constraints.pixel_format {
399 fsysmem2::PixelFormatAndModifier {
400 pixel_format,
401 pixel_format_modifier: *constraints
402 .pixel_format_modifier
403 .as_ref()
404 .unwrap_or(&fimages2::PixelFormatModifier::Linear),
405 }
406 } else {
407 constraints
408 .pixel_format_and_modifiers
409 .as_ref()
410 .ok_or_else(|| format_err!("missing pixel_format"))?
411 .get(0)
412 .ok_or_else(|| format_err!("missing pixel_format"))?
413 .clone()
414 })
415}
416
417pub fn image_format_minimum_row_bytes_2(
422 constraints: &fsysmem2::ImageFormatConstraints,
423 width: u32,
424) -> Result<u32, Error> {
425 let pvric_tiling = match constraints.pixel_format_modifier {
428 None | Some(fimages2::PixelFormatModifier::Linear) => None,
429 Some(modifier) => match pvric_tiling_data(modifier) {
430 Some(tiling) => Some(tiling),
431 None => return Err(anyhow!("Non-linear format modifier.")),
432 },
433 };
434 if pvric_tiling.is_some() {
435 let pixel_format =
436 *constraints.pixel_format.as_ref().ok_or_else(|| anyhow!("missing pixel_format"))?;
437 if !is_pvric_pixel_format_supported(pixel_format) {
438 return Err(anyhow!("Invalid pixel format for PVRIC modifier."));
439 }
440 }
441 if let Some(min_size) = constraints.min_size {
442 if width < min_size.width {
443 return Err(anyhow!("width < min_size.width"));
444 }
445 }
446 if let Some(max_size) = constraints.max_size {
447 if width > max_size.width {
448 return Err(anyhow!("width > max_size.width"));
449 }
450 }
451
452 let constraints_min_bytes_per_row = constraints.min_bytes_per_row.unwrap_or(0);
453
454 let maybe_stride_bytes_per_width_pixel = image_format_stride_bytes_per_width_pixel_2(
455 *constraints.pixel_format.as_ref().expect("pixel_format"),
456 )
457 .ok();
458
459 let mut bytes_per_row_divisor = constraints.bytes_per_row_divisor.unwrap_or(1);
460 if *constraints.require_bytes_per_row_at_pixel_boundary.as_ref().unwrap_or(&false) {
461 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"))?;
462 bytes_per_row_divisor =
463 num_integer::lcm(bytes_per_row_divisor, stride_bytes_per_width_pixel);
464 }
465 if let Some(tiling) = pvric_tiling {
466 bytes_per_row_divisor =
467 num_integer::lcm(bytes_per_row_divisor, tiling.bytes_per_row_per_tile);
468 }
469 let bytes_per_row_divisor = bytes_per_row_divisor;
470
471 round_up_to_increment(
472 std::cmp::max(
473 maybe_stride_bytes_per_width_pixel.unwrap_or(0) * width,
474 constraints_min_bytes_per_row,
475 ) as usize,
476 bytes_per_row_divisor as usize,
477 )
478 .map(|bytes| bytes as u32)
479}
480
481pub fn image_format_minimum_row_bytes(
486 constraints: &fsysmem::ImageFormatConstraints,
487 width: u32,
488) -> Result<u32, Error> {
489 if constraints.pixel_format.format_modifier.value != DRM_FORMAT_MOD_LINEAR {
490 return Err(anyhow!("Non-linear format modifier."));
491 }
492 if width < constraints.min_coded_width
493 || (constraints.max_coded_width > 0 && width > constraints.max_coded_width)
494 {
495 return Err(anyhow!("Width outside of constraints."));
496 }
497
498 let constraints_min_bytes_per_row = constraints.min_bytes_per_row;
499 let constraints_bytes_per_row_divisor = constraints.bytes_per_row_divisor;
500
501 round_up_to_increment(
502 std::cmp::max(
503 image_format_stride_bytes_per_width_pixel(&constraints.pixel_format) * width,
504 constraints_min_bytes_per_row,
505 ) as usize,
506 constraints_bytes_per_row_divisor as usize,
507 )
508 .map(|bytes| bytes as u32)
509}
510
511pub fn image_format_stride_bytes_per_width_pixel_2(
512 pixel_format: fimages2::PixelFormat,
513) -> Result<u32, Error> {
514 match pixel_format {
515 fimages2::PixelFormat::R8G8B8A8 => Ok(4),
516 fimages2::PixelFormat::R8G8B8X8 => Ok(4),
517 fimages2::PixelFormat::B8G8R8A8 => Ok(4),
518 fimages2::PixelFormat::B8G8R8X8 => Ok(4),
519 fimages2::PixelFormat::B8G8R8 => Ok(3),
520 fimages2::PixelFormat::R8G8B8 => Ok(3),
521 fimages2::PixelFormat::I420 => Ok(1),
522 fimages2::PixelFormat::M420 => Ok(1),
523 fimages2::PixelFormat::Nv12 => Ok(1),
524 fimages2::PixelFormat::Yuy2 => Ok(2),
525 fimages2::PixelFormat::Yv12 => Ok(1),
526 fimages2::PixelFormat::R5G6B5 => Ok(2),
527 fimages2::PixelFormat::R3G3B2 => Ok(1),
528 fimages2::PixelFormat::R2G2B2X2 => Ok(1),
529 fimages2::PixelFormat::L8 => Ok(1),
530 fimages2::PixelFormat::R8 => Ok(1),
531 fimages2::PixelFormat::R8G8 => Ok(2),
532 fimages2::PixelFormat::A2B10G10R10 => Ok(4),
533 fimages2::PixelFormat::A2R10G10B10 => Ok(4),
534 fimages2::PixelFormat::P010 => Ok(2),
535 _ => Err(format_err!(
536 "stride_bytes_per_width_pixel not available for pixel_format: {:?}",
537 pixel_format
538 )),
539 }
540}
541
542pub fn image_format_stride_bytes_per_width_pixel(pixel_format: &fsysmem::PixelFormat) -> u32 {
543 match pixel_format.type_ {
544 fsysmem::PixelFormatType::Invalid
545 | fsysmem::PixelFormatType::Mjpeg
546 | fsysmem::PixelFormatType::DoNotCare => 0,
547 fsysmem::PixelFormatType::R8G8B8A8 => 4,
548 fsysmem::PixelFormatType::Bgra32 => 4,
549 fsysmem::PixelFormatType::Bgr24 => 3,
550 fsysmem::PixelFormatType::I420 => 1,
551 fsysmem::PixelFormatType::M420 => 1,
552 fsysmem::PixelFormatType::Nv12 => 1,
553 fsysmem::PixelFormatType::Yuy2 => 2,
554 fsysmem::PixelFormatType::Yv12 => 1,
555 fsysmem::PixelFormatType::Rgb565 => 2,
556 fsysmem::PixelFormatType::Rgb332 => 1,
557 fsysmem::PixelFormatType::Rgb2220 => 1,
558 fsysmem::PixelFormatType::L8 => 1,
559 fsysmem::PixelFormatType::R8 => 1,
560 fsysmem::PixelFormatType::R8G8 => 2,
561 fsysmem::PixelFormatType::A2B10G10R10 => 4,
562 fsysmem::PixelFormatType::A2R10G10B10 => 4,
563 }
564}
565
566pub fn sysmem1_pixel_format_type_from_images2_pixel_format(
567 pixel_format: fimages2::PixelFormat,
568) -> Result<fsysmem::PixelFormatType, Error> {
569 fsysmem::PixelFormatType::from_primitive(pixel_format.into_primitive())
570 .ok_or_else(|| format_err!("pixel_format not convertible to sysmem1: {:?}", pixel_format))
571}
572
573pub fn images2_pixel_format_from_sysmem_pixel_format_type(
574 pixel_format: fsysmem::PixelFormatType,
575) -> Result<fimages2::PixelFormat, Error> {
576 fimages2::PixelFormat::from_primitive(pixel_format.into_primitive())
577 .ok_or_else(|| format_err!("pixel_format not convertible to images2: {:?}", pixel_format))
578}
579
580pub fn sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
581 pixel_format_modifier: fimages2::PixelFormatModifier,
582) -> u64 {
583 if pixel_format_modifier == fimages2::PixelFormatModifier::GoogleGoldfishOptimal {
584 return fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL;
585 }
586 pixel_format_modifier.into_primitive()
587}
588
589pub fn images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
590 pixel_format_modifier: u64,
591) -> Result<fimages2::PixelFormatModifier, Error> {
592 if pixel_format_modifier == fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL {
593 return Ok(fimages2::PixelFormatModifier::GoogleGoldfishOptimal);
594 }
595 fimages2::PixelFormatModifier::from_primitive(pixel_format_modifier).ok_or_else(|| {
596 format_err!("pixel_format_modifier not convertible to images2: {:?}", pixel_format_modifier)
597 })
598}
599
600pub fn sysmem1_color_space_type_from_images2_color_space(
601 color_space: fimages2::ColorSpace,
602) -> Result<fsysmem::ColorSpaceType, Error> {
603 fsysmem::ColorSpaceType::from_primitive(color_space.into_primitive())
604 .ok_or_else(|| format_err!("color_space not convertible to sysmem1: {:?}", color_space))
605}
606
607pub fn images2_color_space_from_sysmem_color_space_type(
608 color_space: fsysmem::ColorSpaceType,
609) -> fimages2::ColorSpace {
610 fimages2::ColorSpace::from_primitive(color_space.into_primitive()).unwrap()
613}
614
615pub fn sysmem1_image_format_from_images2_image_format(
616 image_format: &fimages2::ImageFormat,
617) -> Result<fsysmem::ImageFormat2, Error> {
618 let coded_size = image_format.size.as_ref().ok_or_else(|| format_err!("missing size"))?;
619 let format_modifier = sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
620 *image_format
621 .pixel_format_modifier
622 .as_ref()
623 .unwrap_or(&fimages2::PixelFormatModifier::Linear),
624 );
625 let bytes_per_row = match format_modifier {
628 fsysmem::FORMAT_MODIFIER_LINEAR => {
629 *image_format
631 .bytes_per_row
632 .as_ref()
633 .ok_or_else(|| format_err!("missing bytes_per_row (required when Linear)"))?
634 }
635 _ => {
636 *image_format.bytes_per_row.as_ref().unwrap_or(&0)
638 }
639 };
640 let display_rect = image_format.display_rect.as_ref();
641 let color_space_type = sysmem1_color_space_type_from_images2_color_space(
642 *image_format.color_space.as_ref().ok_or_else(|| format_err!("missing color_space"))?,
643 )?;
644 let pixel_aspect_ratio = image_format.pixel_aspect_ratio.as_ref();
645 Ok(fsysmem::ImageFormat2 {
646 pixel_format: fsysmem::PixelFormat {
647 type_: sysmem1_pixel_format_type_from_images2_pixel_format(
648 *image_format
649 .pixel_format
650 .as_ref()
651 .ok_or_else(|| format_err!("missing pixel_format"))?,
652 )?,
653 has_format_modifier: image_format.pixel_format_modifier.is_some(),
657 format_modifier: fsysmem::FormatModifier { value: format_modifier },
658 },
659 coded_width: coded_size.width,
660 coded_height: coded_size.height,
661 bytes_per_row,
662 display_width: display_rect.map(|rect| rect.width).unwrap_or(0),
663 display_height: display_rect.map(|rect| rect.height).unwrap_or(0),
664 layers: 1,
665 color_space: fsysmem::ColorSpace { type_: color_space_type },
666 has_pixel_aspect_ratio: pixel_aspect_ratio.is_some(),
667 pixel_aspect_ratio_width: pixel_aspect_ratio.map(|size| size.width).unwrap_or(0),
668 pixel_aspect_ratio_height: pixel_aspect_ratio.map(|size| size.height).unwrap_or(0),
669 })
670}
671
672pub fn images2_image_format_from_sysmem_image_format(
673 image_format: &fsysmem::ImageFormat2,
674) -> Result<fimages2::ImageFormat, Error> {
675 let pixel_format_modifier = if image_format.pixel_format.has_format_modifier {
676 Some(images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
677 image_format.pixel_format.format_modifier.value,
678 )?)
679 } else {
680 None
681 };
682 let display_rect = if image_format.display_width != 0 || image_format.display_height != 0 {
683 let display_width = if image_format.display_width != 0 {
684 image_format.display_width
685 } else {
686 image_format.coded_width
687 };
688 let display_height = if image_format.display_height != 0 {
689 image_format.display_height
690 } else {
691 image_format.coded_height
692 };
693 Some(RectU { x: 0, y: 0, width: display_width, height: display_height })
694 } else {
695 None
696 };
697 let pixel_aspect_ratio = if image_format.has_pixel_aspect_ratio {
698 Some(SizeU {
699 width: image_format.pixel_aspect_ratio_width,
700 height: image_format.pixel_aspect_ratio_height,
701 })
702 } else {
703 None
704 };
705 Ok(fimages2::ImageFormat {
706 pixel_format: Some(images2_pixel_format_from_sysmem_pixel_format_type(
707 image_format.pixel_format.type_,
708 )?),
709 pixel_format_modifier,
710 color_space: Some(images2_color_space_from_sysmem_color_space_type(
711 image_format.color_space.type_,
712 )),
713 size: Some(SizeU { width: image_format.coded_width, height: image_format.coded_height }),
714 bytes_per_row: Some(image_format.bytes_per_row),
715 display_rect,
716 pixel_aspect_ratio,
717 ..Default::default()
718 })
719}
720
721#[cfg(test)]
722mod tests {
723 use super::*;
724 use fidl_fuchsia_math as fmath;
725
726 #[test]
727 fn test_linear_row_bytes_2() {
728 let constraints = fsysmem2::ImageFormatConstraints {
729 pixel_format: Some(fimages2::PixelFormat::B8G8R8A8),
730 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
731 min_size: Some(SizeU { width: 12, height: 12 }),
732 max_size: Some(SizeU { width: 100, height: 100 }),
733 bytes_per_row_divisor: Some(4 * 8),
734 max_bytes_per_row: Some(100000),
735 ..Default::default()
736 };
737
738 assert_eq!(image_format_minimum_row_bytes_2(&constraints, 17).unwrap(), 4 * 24);
739
740 assert!(image_format_minimum_row_bytes_2(&constraints, 11).is_err());
741 assert!(image_format_minimum_row_bytes_2(&constraints, 101).is_err());
742 }
743
744 #[test]
745 fn test_linear_row_bytes() {
746 let linear = fsysmem::PixelFormat {
747 type_: fsysmem::PixelFormatType::Bgra32,
748 has_format_modifier: true,
749 format_modifier: fsysmem::FormatModifier { value: fsysmem::FORMAT_MODIFIER_LINEAR },
750 };
751
752 let constraints = fsysmem::ImageFormatConstraints {
753 pixel_format: linear,
754 min_coded_width: 12,
755 max_coded_width: 100,
756 bytes_per_row_divisor: 4 * 8,
757 max_bytes_per_row: 100000,
758 ..IMAGE_FORMAT_CONSTRAINTS_DEFAULT
759 };
760
761 assert_eq!(image_format_minimum_row_bytes(&constraints, 17).unwrap(), 4 * 24);
762
763 assert!(image_format_minimum_row_bytes(&constraints, 11).is_err());
764 assert!(image_format_minimum_row_bytes(&constraints, 101).is_err());
765 }
766
767 #[test]
768 fn plane_byte_offset_2() {
769 let constraints = fsysmem2::ImageFormatConstraints {
770 pixel_format: Some(fimages2::PixelFormat::B8G8R8A8),
771 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
772 min_size: Some(SizeU { width: 12, height: 12 }),
773 max_size: Some(SizeU { width: 100, height: 100 }),
774 bytes_per_row_divisor: Some(4 * 8),
775 max_bytes_per_row: Some(100000),
776 ..Default::default()
777 };
778
779 let image_format = constraints_to_image_format(&constraints, 18, 17).unwrap();
780 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), 96);
782
783 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
784 assert!(image_format_plane_byte_offset_2(&image_format, 1).is_err());
785
786 let constraints = fsysmem2::ImageFormatConstraints {
787 pixel_format: Some(fimages2::PixelFormat::I420),
788 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
789 min_size: Some(SizeU { width: 12, height: 12 }),
790 max_size: Some(SizeU { width: 100, height: 100 }),
791 bytes_per_row_divisor: Some(4 * 8),
792 max_bytes_per_row: Some(100000),
793 ..Default::default()
794 };
795
796 const BYTES_PER_ROW: u32 = 32;
797 let image_format = constraints_to_image_format(&constraints, 18, 20).unwrap();
798 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), BYTES_PER_ROW);
799
800 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
801 assert_eq!(image_format_plane_byte_offset_2(&image_format, 1).unwrap(), BYTES_PER_ROW * 20);
802 assert_eq!(
803 image_format_plane_byte_offset_2(&image_format, 2).unwrap(),
804 BYTES_PER_ROW * 20 + BYTES_PER_ROW / 2 * 20 / 2
805 );
806 assert!(image_format_plane_byte_offset_2(&image_format, 3).is_err());
807
808 assert_eq!(get_plane_row_bytes_2(&image_format, 0).unwrap(), BYTES_PER_ROW);
809 assert_eq!(get_plane_row_bytes_2(&image_format, 1).unwrap(), BYTES_PER_ROW / 2);
810 assert_eq!(get_plane_row_bytes_2(&image_format, 2).unwrap(), BYTES_PER_ROW / 2);
811 assert!(get_plane_row_bytes_2(&image_format, 3).is_err())
812 }
813
814 #[test]
815 fn plane_byte_offset() {
816 let constraints = fsysmem2::ImageFormatConstraints {
817 pixel_format: Some(fimages2::PixelFormat::B8G8R8A8),
818 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
819 min_size: Some(SizeU { width: 12, height: 12 }),
820 max_size: Some(SizeU { width: 100, height: 100 }),
821 bytes_per_row_divisor: Some(4 * 8),
822 max_bytes_per_row: Some(100000),
823 ..Default::default()
824 };
825
826 let image_format = constraints_to_image_format(&constraints, 18, 17).unwrap();
827 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), 96);
829
830 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
831 assert!(image_format_plane_byte_offset_2(&image_format, 1).is_err());
832
833 let constraints = fsysmem2::ImageFormatConstraints {
834 pixel_format: Some(fimages2::PixelFormat::I420),
835 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
836 min_size: Some(SizeU { width: 12, height: 12 }),
837 max_size: Some(SizeU { width: 100, height: 100 }),
838 bytes_per_row_divisor: Some(4 * 8),
839 max_bytes_per_row: Some(100000),
840 ..Default::default()
841 };
842
843 const BYTES_PER_ROW: u32 = 32;
844 let image_format = constraints_to_image_format(&constraints, 18, 20).unwrap();
845 assert_eq!(*image_format.bytes_per_row.as_ref().unwrap(), BYTES_PER_ROW);
846
847 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 0);
848 assert_eq!(image_format_plane_byte_offset_2(&image_format, 1).unwrap(), BYTES_PER_ROW * 20);
849 assert_eq!(
850 image_format_plane_byte_offset_2(&image_format, 2).unwrap(),
851 BYTES_PER_ROW * 20 + BYTES_PER_ROW / 2 * 20 / 2
852 );
853 assert!(image_format_plane_byte_offset_2(&image_format, 3).is_err());
854
855 assert_eq!(get_plane_row_bytes_2(&image_format, 0).unwrap(), BYTES_PER_ROW);
856 assert_eq!(get_plane_row_bytes_2(&image_format, 1).unwrap(), BYTES_PER_ROW / 2);
857 assert_eq!(get_plane_row_bytes_2(&image_format, 2).unwrap(), BYTES_PER_ROW / 2);
858 assert!(get_plane_row_bytes_2(&image_format, 3).is_err())
859 }
860
861 #[test]
862 fn test_constraints_to_image_format() {
863 let constraints = fsysmem2::ImageFormatConstraints {
866 pixel_format: Some(fimages2::PixelFormat::R8G8B8),
867 pixel_format_modifier: Some(fimages2::PixelFormatModifier::Linear),
868 min_size: Some(SizeU { width: 12, height: 12 }),
869 max_size: Some(SizeU { width: 100, height: 100 }),
870 bytes_per_row_divisor: Some(4 * 8),
871 max_bytes_per_row: Some(100000),
872 color_spaces: Some(vec![fimages2::ColorSpace::Rec709]),
873 min_bytes_per_row: Some(24),
874 max_width_times_height: Some(12 * 12),
875 size_alignment: Some(fmath::SizeU { width: 37, height: 1 }),
876 display_rect_alignment: Some(fmath::SizeU { width: 37, height: 37 }),
877 required_min_size: Some(fmath::SizeU { width: 37, height: 37 }),
878 required_max_size: Some(fmath::SizeU { width: 37, height: 37 }),
879 start_offset_divisor: Some(37),
880 pixel_format_and_modifiers: Some(vec![fsysmem2::PixelFormatAndModifier {
881 pixel_format: fimages2::PixelFormat::Yv12,
882 pixel_format_modifier: fimages2::PixelFormatModifier::GoogleGoldfishOptimal,
883 }]),
884 require_bytes_per_row_at_pixel_boundary: Some(true),
885 ..Default::default()
886 };
887
888 let image_format = constraints_to_image_format(&constraints, 18, 17).unwrap();
889
890 assert_eq!(image_format.pixel_format, Some(fimages2::PixelFormat::R8G8B8));
891 assert_eq!(image_format.pixel_format_modifier, Some(fimages2::PixelFormatModifier::Linear));
892 assert_eq!(image_format.color_space, Some(fimages2::ColorSpace::Rec709));
893 assert_eq!(image_format.size, Some(fmath::SizeU { width: 18, height: 17 }));
894 assert_eq!(image_format.bytes_per_row, Some(96));
895
896 assert_eq!(image_format.display_rect, None);
898 assert_eq!(image_format.valid_size, None);
899 assert_eq!(image_format.pixel_aspect_ratio, None);
900 }
901
902 #[test]
903 fn test_image_format_stride_bytes_per_width_pixel_2() {
904 assert_eq!(
905 4,
906 image_format_stride_bytes_per_width_pixel_2(fimages2::PixelFormat::R8G8B8A8).unwrap()
907 );
908 assert!(
909 image_format_stride_bytes_per_width_pixel_2(fimages2::PixelFormat::DoNotCare).is_err()
910 );
911 }
912
913 #[test]
914 fn test_sysmem1_pixel_format_type_from_images2_pixel_format() {
915 assert_eq!(
916 fsysmem::PixelFormatType::Bgra32,
917 sysmem1_pixel_format_type_from_images2_pixel_format(fimages2::PixelFormat::B8G8R8A8)
918 .unwrap()
919 );
920 assert!(
921 sysmem1_pixel_format_type_from_images2_pixel_format(
922 fimages2::PixelFormat::from_primitive_allow_unknown(1189673091)
923 )
924 .is_err()
925 );
926 }
927
928 #[test]
929 fn test_sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier() {
930 assert_eq!(
931 fsysmem::FORMAT_MODIFIER_ARM_AFBC_16_X16_SPLIT_BLOCK_SPARSE_YUV_TE_TILED_HEADER,
932 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
933 fimages2::PixelFormatModifier::ArmAfbc16X16SplitBlockSparseYuvTeTiledHeader
934 )
935 );
936 assert_eq!(
937 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL,
938 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
939 fimages2::PixelFormatModifier::GoogleGoldfishOptimal
940 )
941 );
942 assert_eq!(
943 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL,
944 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
945 fimages2::PixelFormatModifier::from_primitive_allow_unknown(
946 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL
947 )
948 )
949 );
950 assert_eq!(
952 1189673091,
953 sysmem1_pixel_format_modifier_from_images2_pixel_format_modifier(
954 fimages2::PixelFormatModifier::from_primitive_allow_unknown(1189673091)
955 )
956 );
957 }
958
959 #[test]
960 fn test_images2_pixel_format_from_sysmem_pixel_format_type() {
961 assert_eq!(
962 fimages2::PixelFormat::B8G8R8A8,
963 images2_pixel_format_from_sysmem_pixel_format_type(fsysmem::PixelFormatType::Bgra32)
964 .unwrap()
965 );
966 assert_eq!(
967 fimages2::PixelFormat::Yv12,
968 images2_pixel_format_from_sysmem_pixel_format_type(fsysmem::PixelFormatType::Yv12)
969 .unwrap()
970 );
971 }
972
973 #[test]
974 fn test_images2_pixel_format_modifier_from_sysmem_pixel_format_modifier() {
975 assert_eq!(
976 fimages2::PixelFormatModifier::ArmAfbc16X16SplitBlockSparseYuvTeTiledHeader,
977 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
978 fsysmem::FORMAT_MODIFIER_ARM_AFBC_16_X16_SPLIT_BLOCK_SPARSE_YUV_TE_TILED_HEADER
979 )
980 .unwrap()
981 );
982 assert_eq!(
983 fimages2::PixelFormatModifier::GoogleGoldfishOptimal,
984 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
985 fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL
986 )
987 .unwrap()
988 );
989 assert_eq!(
990 fimages2::PixelFormatModifier::GoogleGoldfishOptimal,
991 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(
992 fimages2::PixelFormatModifier::GoogleGoldfishOptimal.into_primitive()
993 )
994 .unwrap()
995 );
996 assert!(
997 images2_pixel_format_modifier_from_sysmem_pixel_format_modifier(1189673091).is_err()
998 );
999 }
1000
1001 #[test]
1002 fn test_sysmem1_color_space_type_from_images2_color_space() {
1003 assert_eq!(
1004 fsysmem::ColorSpaceType::Rec709,
1005 sysmem1_color_space_type_from_images2_color_space(fimages2::ColorSpace::Rec709)
1006 .unwrap()
1007 );
1008 assert!(
1009 sysmem1_color_space_type_from_images2_color_space(
1010 fimages2::ColorSpace::from_primitive_allow_unknown(1189673091)
1011 )
1012 .is_err()
1013 );
1014 }
1015
1016 #[test]
1017 fn test_images2_color_space_from_sysmem_color_space_type() {
1018 assert_eq!(
1019 fimages2::ColorSpace::Rec709,
1020 images2_color_space_from_sysmem_color_space_type(fsysmem::ColorSpaceType::Rec709)
1021 );
1022 assert_eq!(
1023 fimages2::ColorSpace::Srgb,
1024 images2_color_space_from_sysmem_color_space_type(fsysmem::ColorSpaceType::Srgb)
1025 );
1026 }
1027
1028 #[test]
1029 fn test_sysmem1_image_format_from_images2_image_format() {
1030 {
1031 let images2_format = fimages2::ImageFormat {
1032 pixel_format: Some(fimages2::PixelFormat::Yv12),
1033 pixel_format_modifier: None,
1034 color_space: Some(fimages2::ColorSpace::Rec709),
1035 size: Some(fmath::SizeU { width: 17, height: 13 }),
1036 bytes_per_row: Some(32),
1037 display_rect: Some(fmath::RectU { x: 0, y: 0, width: 15, height: 11 }),
1038 valid_size: Some(fmath::SizeU { width: 12, height: 10 }),
1039 pixel_aspect_ratio: Some(fmath::SizeU { width: 2, height: 3 }),
1040 ..Default::default()
1041 };
1042
1043 let sysmem_format =
1044 sysmem1_image_format_from_images2_image_format(&images2_format).unwrap();
1045
1046 assert_eq!(fsysmem::PixelFormatType::Yv12, sysmem_format.pixel_format.type_);
1047 assert_eq!(false, sysmem_format.pixel_format.has_format_modifier);
1048 assert_eq!(17, sysmem_format.coded_width);
1049 assert_eq!(13, sysmem_format.coded_height);
1050 assert_eq!(32, sysmem_format.bytes_per_row);
1051 assert_eq!(15, sysmem_format.display_width);
1052 assert_eq!(11, sysmem_format.display_height);
1053 assert_eq!(1, sysmem_format.layers);
1054 assert_eq!(fsysmem::ColorSpaceType::Rec709, sysmem_format.color_space.type_);
1055 assert_eq!(true, sysmem_format.has_pixel_aspect_ratio);
1056 assert_eq!(2, sysmem_format.pixel_aspect_ratio_width);
1057 assert_eq!(3, sysmem_format.pixel_aspect_ratio_height);
1058 }
1059
1060 {
1061 let images2_format = fimages2::ImageFormat {
1062 pixel_format: Some(fimages2::PixelFormat::Yv12),
1063 pixel_format_modifier: Some(
1064 fimages2::PixelFormatModifier::ArmAfbc16X16SplitBlockSparseYuvTeTiledHeader,
1065 ),
1066 color_space: Some(fimages2::ColorSpace::Rec709),
1067 size: Some(fmath::SizeU { width: 17, height: 13 }),
1068 bytes_per_row: Some(32),
1069 display_rect: Some(fmath::RectU { x: 0, y: 0, width: 15, height: 11 }),
1070 valid_size: Some(fmath::SizeU { width: 12, height: 10 }),
1071 pixel_aspect_ratio: Some(fmath::SizeU { width: 2, height: 3 }),
1072 ..Default::default()
1073 };
1074
1075 let sysmem_format =
1076 sysmem1_image_format_from_images2_image_format(&images2_format).unwrap();
1077
1078 assert_eq!(fsysmem::PixelFormatType::Yv12, sysmem_format.pixel_format.type_);
1079 assert_eq!(true, sysmem_format.pixel_format.has_format_modifier);
1080 assert_eq!(
1081 fsysmem::FORMAT_MODIFIER_ARM_AFBC_16_X16_SPLIT_BLOCK_SPARSE_YUV_TE_TILED_HEADER,
1082 sysmem_format.pixel_format.format_modifier.value
1083 );
1084 assert_eq!(17, sysmem_format.coded_width);
1085 assert_eq!(13, sysmem_format.coded_height);
1086 assert_eq!(32, sysmem_format.bytes_per_row);
1087 assert_eq!(15, sysmem_format.display_width);
1088 assert_eq!(11, sysmem_format.display_height);
1089 assert_eq!(1, sysmem_format.layers);
1090 assert_eq!(fsysmem::ColorSpaceType::Rec709, sysmem_format.color_space.type_);
1091 assert_eq!(true, sysmem_format.has_pixel_aspect_ratio);
1092 assert_eq!(2, sysmem_format.pixel_aspect_ratio_width);
1093 assert_eq!(3, sysmem_format.pixel_aspect_ratio_height);
1094 }
1095 }
1096
1097 #[test]
1098 fn test_images2_image_format_from_sysmem_image_format() {
1099 let sysmem_format = fsysmem::ImageFormat2 {
1100 pixel_format: fsysmem::PixelFormat {
1101 type_: fsysmem::PixelFormatType::Yv12,
1102 has_format_modifier: true,
1103 format_modifier: fsysmem::FormatModifier {
1104 value: fsysmem::FORMAT_MODIFIER_GOOGLE_GOLDFISH_OPTIMAL,
1105 },
1106 },
1107 coded_width: 17,
1108 coded_height: 13,
1109 bytes_per_row: 32,
1110 display_width: 15,
1111 display_height: 11,
1112 layers: 1,
1113 color_space: fsysmem::ColorSpace { type_: fsysmem::ColorSpaceType::Rec709 },
1114 has_pixel_aspect_ratio: true,
1115 pixel_aspect_ratio_width: 2,
1116 pixel_aspect_ratio_height: 3,
1117 };
1118
1119 let images2_format = images2_image_format_from_sysmem_image_format(&sysmem_format).unwrap();
1120
1121 assert_eq!(Some(fimages2::PixelFormat::Yv12), images2_format.pixel_format);
1122 assert_eq!(
1123 Some(fimages2::PixelFormatModifier::GoogleGoldfishOptimal),
1124 images2_format.pixel_format_modifier
1125 );
1126 assert_eq!(Some(fimages2::ColorSpace::Rec709), images2_format.color_space);
1127 assert_eq!(Some(fmath::SizeU { width: 17, height: 13 }), images2_format.size);
1128 assert_eq!(Some(32), images2_format.bytes_per_row);
1129 assert_eq!(
1130 Some(fmath::RectU { x: 0, y: 0, width: 15, height: 11 }),
1131 images2_format.display_rect
1132 );
1133 assert_eq!(None, images2_format.valid_size);
1134 assert_eq!(Some(fmath::SizeU { width: 2, height: 3 }), images2_format.pixel_aspect_ratio);
1135 }
1136
1137 #[test]
1138 fn test_pvric_tiling_data() {
1139 assert_eq!(
1140 pvric_tiling_data(fimages2::PixelFormatModifier::PvrFbcdc8X8V14),
1141 Some(PvricTilingData { tile_rows: 8, bytes_per_row_per_tile: 32 })
1142 );
1143 assert_eq!(
1144 pvric_tiling_data(fimages2::PixelFormatModifier::PvrFbcdc16X4V14),
1145 Some(PvricTilingData { tile_rows: 4, bytes_per_row_per_tile: 64 })
1146 );
1147 assert_eq!(pvric_tiling_data(fimages2::PixelFormatModifier::Linear), None);
1148 }
1149
1150 #[test]
1151 fn test_pvric_16x4_row_bytes_and_planes() {
1152 let supported_32bpp_formats = [
1153 fimages2::PixelFormat::R8G8B8A8,
1154 fimages2::PixelFormat::R8G8B8X8,
1155 fimages2::PixelFormat::B8G8R8A8,
1156 fimages2::PixelFormat::B8G8R8X8,
1157 fimages2::PixelFormat::A2R10G10B10,
1158 fimages2::PixelFormat::A2B10G10R10,
1159 ];
1160
1161 for format in supported_32bpp_formats {
1162 let constraints = fsysmem2::ImageFormatConstraints {
1163 pixel_format: Some(format),
1164 pixel_format_modifier: Some(fimages2::PixelFormatModifier::PvrFbcdc16X4V14),
1165 min_size: Some(SizeU { width: 12, height: 12 }),
1166 max_size: Some(SizeU { width: 100, height: 100 }),
1167 bytes_per_row_divisor: Some(32),
1168 max_bytes_per_row: Some(100000),
1169 ..Default::default()
1170 };
1171
1172 assert_eq!(image_format_minimum_row_bytes_2(&constraints, 18).unwrap(), 128);
1178 assert!(image_format_minimum_row_bytes_2(&constraints, 11).is_err());
1179 assert!(image_format_minimum_row_bytes_2(&constraints, 101).is_err());
1180
1181 let image_format = constraints_to_image_format(&constraints, 18, 17).unwrap();
1182 assert_eq!(image_format.bytes_per_row, Some(128));
1183
1184 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 256);
1185 assert!(image_format_plane_byte_offset_2(&image_format, 1).is_err());
1186 assert!(image_format_plane_byte_offset_2(&image_format, 2).is_err());
1187 assert_eq!(image_format_plane_byte_offset_2(&image_format, 3).unwrap(), 0);
1188 assert!(image_format_plane_byte_offset_2(&image_format, 4).is_err());
1189
1190 assert_eq!(get_plane_row_bytes_2(&image_format, 0).unwrap(), 128);
1191 assert!(get_plane_row_bytes_2(&image_format, 1).is_err());
1192 assert!(get_plane_row_bytes_2(&image_format, 2).is_err());
1193 assert_eq!(get_plane_row_bytes_2(&image_format, 3).unwrap(), 2);
1194 assert!(get_plane_row_bytes_2(&image_format, 4).is_err());
1195 }
1196
1197 let large_constraints = fsysmem2::ImageFormatConstraints {
1203 pixel_format: Some(fimages2::PixelFormat::B8G8R8A8),
1204 pixel_format_modifier: Some(fimages2::PixelFormatModifier::PvrFbcdc16X4V14),
1205 min_size: Some(SizeU { width: 1, height: 1 }),
1206 max_size: Some(SizeU { width: 4096, height: 4096 }),
1207 bytes_per_row_divisor: Some(64),
1208 ..Default::default()
1209 };
1210 assert_eq!(image_format_minimum_row_bytes_2(&large_constraints, 1280).unwrap(), 5120);
1211 let large_format = constraints_to_image_format(&large_constraints, 1280, 2856).unwrap();
1212 assert_eq!(large_format.bytes_per_row, Some(5120));
1213 assert_eq!(image_format_plane_byte_offset_2(&large_format, 0).unwrap(), 57_344);
1214 assert_eq!(image_format_plane_byte_offset_2(&large_format, 3).unwrap(), 0);
1215 assert_eq!(get_plane_row_bytes_2(&large_format, 0).unwrap(), 5120);
1216 assert_eq!(get_plane_row_bytes_2(&large_format, 3).unwrap(), 80);
1217
1218 let rgb565_constraints = fsysmem2::ImageFormatConstraints {
1223 pixel_format: Some(fimages2::PixelFormat::R5G6B5),
1224 pixel_format_modifier: Some(fimages2::PixelFormatModifier::PvrFbcdc16X4V14),
1225 min_size: Some(SizeU { width: 1, height: 1 }),
1226 max_size: Some(SizeU { width: 4096, height: 4096 }),
1227 ..Default::default()
1228 };
1229 let rgb565_format = constraints_to_image_format(&rgb565_constraints, 18, 17).unwrap();
1230 assert_eq!(rgb565_format.bytes_per_row, Some(64));
1231 assert_eq!(image_format_plane_byte_offset_2(&rgb565_format, 0).unwrap(), 256);
1232 assert_eq!(image_format_plane_byte_offset_2(&rgb565_format, 3).unwrap(), 0);
1233 assert_eq!(get_plane_row_bytes_2(&rgb565_format, 0).unwrap(), 64);
1234 assert_eq!(get_plane_row_bytes_2(&rgb565_format, 3).unwrap(), 1);
1235
1236 for unsupported in [fimages2::PixelFormat::Nv12, fimages2::PixelFormat::B8G8R8] {
1238 let bad_constraints = fsysmem2::ImageFormatConstraints {
1239 pixel_format: Some(unsupported),
1240 pixel_format_modifier: Some(fimages2::PixelFormatModifier::PvrFbcdc16X4V14),
1241 ..Default::default()
1242 };
1243 assert!(image_format_minimum_row_bytes_2(&bad_constraints, 64).is_err());
1244 }
1245 }
1246
1247 #[test]
1248 fn test_pvric_8x8_row_bytes_and_planes() {
1249 let constraints = fsysmem2::ImageFormatConstraints {
1256 pixel_format: Some(fimages2::PixelFormat::R8G8B8A8),
1257 pixel_format_modifier: Some(fimages2::PixelFormatModifier::PvrFbcdc8X8V14),
1258 min_size: Some(SizeU { width: 1, height: 1 }),
1259 max_size: Some(SizeU { width: 4096, height: 4096 }),
1260 ..Default::default()
1261 };
1262
1263 let image_format = constraints_to_image_format(&constraints, 1920, 1080).unwrap();
1264 assert_eq!(image_format.bytes_per_row, Some(7680));
1265 assert_eq!(image_format_plane_byte_offset_2(&image_format, 0).unwrap(), 32_512);
1266 assert!(image_format_plane_byte_offset_2(&image_format, 1).is_err());
1267 assert!(image_format_plane_byte_offset_2(&image_format, 2).is_err());
1268 assert_eq!(image_format_plane_byte_offset_2(&image_format, 3).unwrap(), 0);
1269 assert!(image_format_plane_byte_offset_2(&image_format, 4).is_err());
1270
1271 assert_eq!(get_plane_row_bytes_2(&image_format, 0).unwrap(), 7680);
1272 assert!(get_plane_row_bytes_2(&image_format, 1).is_err());
1273 assert!(get_plane_row_bytes_2(&image_format, 2).is_err());
1274 assert_eq!(get_plane_row_bytes_2(&image_format, 3).unwrap(), 240);
1275 assert!(get_plane_row_bytes_2(&image_format, 4).is_err());
1276 }
1277}