blob: 98ccd4ed43faedff456624af09e7d2f59cb2dc81 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/image-format-llcpp/image-format-llcpp.h>
#include <lib/image-format/image_format.h>
#include <lib/sysmem-version/sysmem-version.h>
#include <fbl/array.h>
#include <zxtest/zxtest.h>
#include "fuchsia/sysmem/c/fidl.h"
#include "fuchsia/sysmem/llcpp/fidl.h"
#include "fuchsia/sysmem2/llcpp/fidl.h"
namespace sysmem_v1 = fuchsia_sysmem;
namespace sysmem_v2 = fuchsia_sysmem2;
TEST(ImageFormat, LinearComparison_V2_LLCPP) {
fidl::FidlAllocator allocator;
sysmem_v2::wire::PixelFormat plain(allocator);
plain.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
sysmem_v2::wire::PixelFormat linear(allocator);
linear.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
linear.set_format_modifier_value(allocator, sysmem_v2::wire::kFormatModifierLinear);
sysmem_v2::wire::PixelFormat x_tiled(allocator);
x_tiled.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
x_tiled.set_format_modifier_value(allocator, sysmem_v2::wire::kFormatModifierIntelI915XTiled);
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(plain, plain));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(linear, linear));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(plain, linear));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(linear, plain));
EXPECT_FALSE(ImageFormatIsPixelFormatEqual(linear, x_tiled));
EXPECT_FALSE(ImageFormatIsPixelFormatEqual(plain, x_tiled));
}
TEST(ImageFormat, LinearComparison_V1_LLCPP) {
sysmem_v1::wire::PixelFormat plain = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = false,
};
sysmem_v1::wire::PixelFormat linear = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierLinear,
};
sysmem_v1::wire::PixelFormat x_tiled = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierIntelI915XTiled,
};
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(plain, plain));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(linear, linear));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(plain, linear));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(linear, plain));
EXPECT_FALSE(ImageFormatIsPixelFormatEqual(linear, x_tiled));
EXPECT_FALSE(ImageFormatIsPixelFormatEqual(plain, x_tiled));
}
TEST(ImageFormat, LinearComparison_V1_C) {
fuchsia_sysmem_PixelFormat plain = {
.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.has_format_modifier = false,
};
fuchsia_sysmem_PixelFormat linear = {
.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.has_format_modifier = true,
.format_modifier.value = fuchsia_sysmem_FORMAT_MODIFIER_LINEAR,
};
fuchsia_sysmem_PixelFormat x_tiled = {
.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.has_format_modifier = true,
.format_modifier.value = fuchsia_sysmem_FORMAT_MODIFIER_INTEL_I915_X_TILED,
};
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(plain, plain));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(linear, linear));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(plain, linear));
EXPECT_TRUE(ImageFormatIsPixelFormatEqual(linear, plain));
EXPECT_FALSE(ImageFormatIsPixelFormatEqual(linear, x_tiled));
EXPECT_FALSE(ImageFormatIsPixelFormatEqual(plain, x_tiled));
}
TEST(ImageFormat, LinearRowBytes_V2_LLCPP) {
fidl::FidlAllocator allocator;
sysmem_v2::wire::PixelFormat linear(allocator);
linear.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
linear.set_format_modifier_value(allocator, sysmem_v2::wire::kFormatModifierLinear);
sysmem_v2::wire::ImageFormatConstraints constraints(allocator);
constraints.set_pixel_format(allocator, std::move(linear));
constraints.set_min_coded_width(allocator, 12u);
constraints.set_max_coded_width(allocator, 100u);
constraints.set_bytes_per_row_divisor(allocator, 4u * 8u);
constraints.set_max_bytes_per_row(allocator, 100000u);
uint32_t row_bytes;
EXPECT_TRUE(ImageFormatMinimumRowBytes(constraints, 17, &row_bytes));
EXPECT_EQ(row_bytes, 4 * 24);
EXPECT_FALSE(ImageFormatMinimumRowBytes(constraints, 11, &row_bytes));
EXPECT_FALSE(ImageFormatMinimumRowBytes(constraints, 101, &row_bytes));
}
TEST(ImageFormat, LinearRowBytes_V1_LLCPP) {
sysmem_v1::wire::PixelFormat linear = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierLinear,
};
sysmem_v1::wire::ImageFormatConstraints constraints = {
.pixel_format = linear,
.min_coded_width = 12,
.max_coded_width = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 4 * 8,
};
uint32_t row_bytes;
EXPECT_TRUE(ImageFormatMinimumRowBytes(constraints, 17, &row_bytes));
EXPECT_EQ(row_bytes, 4 * 24);
EXPECT_FALSE(ImageFormatMinimumRowBytes(constraints, 11, &row_bytes));
EXPECT_FALSE(ImageFormatMinimumRowBytes(constraints, 101, &row_bytes));
}
TEST(ImageFormat, LinearRowBytes_V1_C) {
fuchsia_sysmem_PixelFormat linear = {
.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.has_format_modifier = true,
.format_modifier.value = fuchsia_sysmem_FORMAT_MODIFIER_LINEAR,
};
fuchsia_sysmem_ImageFormatConstraints constraints = {
.pixel_format = linear,
.min_coded_width = 12,
.max_coded_width = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 4 * 8,
};
uint32_t row_bytes;
EXPECT_TRUE(ImageFormatMinimumRowBytes(&constraints, 17, &row_bytes));
EXPECT_EQ(row_bytes, 4 * 24);
EXPECT_FALSE(ImageFormatMinimumRowBytes(&constraints, 11, &row_bytes));
EXPECT_FALSE(ImageFormatMinimumRowBytes(&constraints, 101, &row_bytes));
}
TEST(ImageFormat, InvalidColorSpace_V1_LLCPP) {
fidl::FidlAllocator allocator;
auto sysmem_format_result = ImageFormatConvertZxToSysmem_v1(allocator, ZX_PIXEL_FORMAT_RGB_565);
EXPECT_TRUE(sysmem_format_result.is_ok());
auto sysmem_format = sysmem_format_result.take_value();
sysmem_v1::wire::ColorSpace color_space{sysmem_v1::wire::ColorSpaceType::kInvalid};
// Shouldn't crash.
EXPECT_FALSE(ImageFormatIsSupportedColorSpaceForPixelFormat(color_space, sysmem_format));
}
TEST(ImageFormat, ZxPixelFormat_V2_LLCPP) {
fidl::FidlAllocator allocator;
zx_pixel_format_t pixel_formats[] = {
ZX_PIXEL_FORMAT_RGB_565, ZX_PIXEL_FORMAT_RGB_332, ZX_PIXEL_FORMAT_RGB_2220,
ZX_PIXEL_FORMAT_ARGB_8888, ZX_PIXEL_FORMAT_RGB_x888, ZX_PIXEL_FORMAT_MONO_8,
ZX_PIXEL_FORMAT_GRAY_8, ZX_PIXEL_FORMAT_NV12, ZX_PIXEL_FORMAT_RGB_888,
};
for (zx_pixel_format_t format : pixel_formats) {
fprintf(stderr, "Format %x\n", format);
auto sysmem_format_result = ImageFormatConvertZxToSysmem_v2(allocator, format);
EXPECT_TRUE(sysmem_format_result.is_ok());
sysmem_v2::wire::PixelFormat sysmem_format = sysmem_format_result.take_value();
zx_pixel_format_t back_format;
EXPECT_TRUE(ImageFormatConvertSysmemToZx(sysmem_format, &back_format));
if (format == ZX_PIXEL_FORMAT_RGB_x888) {
EXPECT_EQ(ZX_PIXEL_FORMAT_ARGB_8888, back_format);
} else {
EXPECT_EQ(back_format, format);
}
EXPECT_TRUE(sysmem_format.has_format_modifier_value());
EXPECT_EQ(sysmem_v2::wire::kFormatModifierLinear,
static_cast<uint64_t>(sysmem_format.format_modifier_value()));
sysmem_v2::wire::ColorSpace color_space(allocator);
if (format == ZX_PIXEL_FORMAT_NV12) {
color_space.set_type(allocator, sysmem_v2::wire::ColorSpaceType::kRec601Ntsc);
} else {
color_space.set_type(allocator, sysmem_v2::wire::ColorSpaceType::kSrgb);
}
EXPECT_TRUE(ImageFormatIsSupportedColorSpaceForPixelFormat(color_space, sysmem_format));
EXPECT_EQ(ZX_PIXEL_FORMAT_BYTES(format), ImageFormatStrideBytesPerWidthPixel(sysmem_format));
EXPECT_TRUE(ImageFormatIsSupported(sysmem_format));
EXPECT_LT(0u, ImageFormatBitsPerPixel(sysmem_format));
}
sysmem_v2::wire::PixelFormat other_format(allocator);
other_format.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
other_format.set_format_modifier_value(allocator,
sysmem_v2::wire::kFormatModifierIntelI915XTiled);
zx_pixel_format_t back_format;
EXPECT_FALSE(ImageFormatConvertSysmemToZx(other_format, &back_format));
// Treat as linear.
auto other_format2 = sysmem::V2ClonePixelFormat(allocator, other_format);
other_format2.set_format_modifier_value(nullptr);
EXPECT_TRUE(ImageFormatConvertSysmemToZx(other_format2, &back_format));
}
TEST(ImageFormat, ZxPixelFormat_V1_LLCPP) {
fidl::FidlAllocator allocator;
zx_pixel_format_t pixel_formats[] = {
ZX_PIXEL_FORMAT_RGB_565, ZX_PIXEL_FORMAT_RGB_332, ZX_PIXEL_FORMAT_RGB_2220,
ZX_PIXEL_FORMAT_ARGB_8888, ZX_PIXEL_FORMAT_RGB_x888, ZX_PIXEL_FORMAT_MONO_8,
ZX_PIXEL_FORMAT_GRAY_8, ZX_PIXEL_FORMAT_NV12, ZX_PIXEL_FORMAT_RGB_888,
};
for (zx_pixel_format_t format : pixel_formats) {
fprintf(stderr, "Format %x\n", format);
auto sysmem_format_result = ImageFormatConvertZxToSysmem_v1(allocator, format);
EXPECT_TRUE(sysmem_format_result.is_ok());
auto sysmem_format = sysmem_format_result.take_value();
zx_pixel_format_t back_format;
EXPECT_TRUE(ImageFormatConvertSysmemToZx(sysmem_format, &back_format));
if (format == ZX_PIXEL_FORMAT_RGB_x888) {
EXPECT_EQ(ZX_PIXEL_FORMAT_ARGB_8888, back_format);
} else {
EXPECT_EQ(back_format, format);
}
EXPECT_TRUE(sysmem_format.has_format_modifier);
EXPECT_EQ(fuchsia_sysmem_FORMAT_MODIFIER_LINEAR,
static_cast<uint64_t>(sysmem_format.format_modifier.value));
sysmem_v1::wire::ColorSpace color_space;
if (format == ZX_PIXEL_FORMAT_NV12) {
color_space.type = sysmem_v1::wire::ColorSpaceType::kRec601Ntsc;
} else {
color_space.type = sysmem_v1::wire::ColorSpaceType::kSrgb;
}
EXPECT_TRUE(ImageFormatIsSupportedColorSpaceForPixelFormat(color_space, sysmem_format));
EXPECT_EQ(ZX_PIXEL_FORMAT_BYTES(format), ImageFormatStrideBytesPerWidthPixel(sysmem_format));
EXPECT_TRUE(ImageFormatIsSupported(sysmem_format));
EXPECT_LT(0u, ImageFormatBitsPerPixel(sysmem_format));
}
sysmem_v1::wire::PixelFormat other_format = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierIntelI915XTiled,
};
zx_pixel_format_t back_format;
EXPECT_FALSE(ImageFormatConvertSysmemToZx(other_format, &back_format));
// Treat as linear.
other_format.has_format_modifier = false;
EXPECT_TRUE(ImageFormatConvertSysmemToZx(other_format, &back_format));
}
TEST(ImageFormat, ZxPixelFormat_V1_C) {
zx_pixel_format_t pixel_formats[] = {
ZX_PIXEL_FORMAT_RGB_565, ZX_PIXEL_FORMAT_RGB_332, ZX_PIXEL_FORMAT_RGB_2220,
ZX_PIXEL_FORMAT_ARGB_8888, ZX_PIXEL_FORMAT_RGB_x888, ZX_PIXEL_FORMAT_MONO_8,
ZX_PIXEL_FORMAT_GRAY_8, ZX_PIXEL_FORMAT_NV12, ZX_PIXEL_FORMAT_RGB_888,
};
for (zx_pixel_format_t format : pixel_formats) {
fprintf(stderr, "Format %x\n", format);
fuchsia_sysmem_PixelFormat sysmem_format;
EXPECT_TRUE(ImageFormatConvertZxToSysmem(format, &sysmem_format));
zx_pixel_format_t back_format;
EXPECT_TRUE(ImageFormatConvertSysmemToZx(&sysmem_format, &back_format));
if (format == ZX_PIXEL_FORMAT_RGB_x888) {
EXPECT_EQ(ZX_PIXEL_FORMAT_ARGB_8888, back_format);
} else {
EXPECT_EQ(back_format, format);
}
EXPECT_TRUE(sysmem_format.has_format_modifier);
EXPECT_EQ(fuchsia_sysmem_FORMAT_MODIFIER_LINEAR,
static_cast<uint64_t>(sysmem_format.format_modifier.value));
fuchsia_sysmem_ColorSpace color_space;
if (format == ZX_PIXEL_FORMAT_NV12) {
color_space.type = fuchsia_sysmem_ColorSpaceType_REC601_NTSC;
} else {
color_space.type = fuchsia_sysmem_ColorSpaceType_SRGB;
}
EXPECT_TRUE(ImageFormatIsSupportedColorSpaceForPixelFormat(color_space, sysmem_format));
EXPECT_EQ(ZX_PIXEL_FORMAT_BYTES(format), ImageFormatStrideBytesPerWidthPixel(&sysmem_format));
EXPECT_TRUE(ImageFormatIsSupported(&sysmem_format));
EXPECT_LT(0u, ImageFormatBitsPerPixel(&sysmem_format));
}
fuchsia_sysmem_PixelFormat other_format = {
.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.has_format_modifier = true,
.format_modifier.value = fuchsia_sysmem_FORMAT_MODIFIER_INTEL_I915_X_TILED,
};
zx_pixel_format_t back_format;
EXPECT_FALSE(ImageFormatConvertSysmemToZx(&other_format, &back_format));
// Treat as linear.
other_format.has_format_modifier = false;
EXPECT_TRUE(ImageFormatConvertSysmemToZx(&other_format, &back_format));
}
TEST(ImageFormat, PlaneByteOffset_V2_LLCPP) {
fidl::FidlAllocator allocator;
sysmem_v2::wire::PixelFormat linear(allocator);
linear.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
linear.set_format_modifier_value(allocator, sysmem_v2::wire::kFormatModifierLinear);
sysmem_v2::wire::ImageFormatConstraints constraints(allocator);
constraints.set_pixel_format(allocator, std::move(linear));
constraints.set_min_coded_width(allocator, 12u);
constraints.set_max_coded_width(allocator, 100u);
constraints.set_min_coded_height(allocator, 12u);
constraints.set_max_coded_height(allocator, 100u);
constraints.set_bytes_per_row_divisor(allocator, 4u * 8u);
constraints.set_max_bytes_per_row(allocator, 100000u);
auto image_format_result = ImageConstraintsToFormat(allocator, constraints, 18, 17);
EXPECT_TRUE(image_format_result.is_ok());
auto image_format = image_format_result.take_value();
// The raw size would be 72 without bytes_per_row_divisor of 32.
EXPECT_EQ(96u, image_format.bytes_per_row());
uint64_t byte_offset;
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 0, &byte_offset));
EXPECT_EQ(0u, byte_offset);
EXPECT_FALSE(ImageFormatPlaneByteOffset(image_format, 1, &byte_offset));
auto constraints2 = sysmem::V2CloneImageFormatConstraints(allocator, constraints);
constraints2.pixel_format().set_type(allocator, sysmem_v2::wire::PixelFormatType::kI420);
constexpr uint32_t kBytesPerRow = 32;
image_format_result = ImageConstraintsToFormat(allocator, constraints2, 18, 20);
EXPECT_TRUE(image_format_result.is_ok());
image_format = image_format_result.take_value();
EXPECT_EQ(kBytesPerRow, image_format.bytes_per_row());
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 0, &byte_offset));
EXPECT_EQ(0u, byte_offset);
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 1, &byte_offset));
EXPECT_EQ(kBytesPerRow * 20, byte_offset);
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 2, &byte_offset));
EXPECT_EQ(kBytesPerRow * 20 + kBytesPerRow / 2 * 20 / 2, byte_offset);
EXPECT_FALSE(ImageFormatPlaneByteOffset(image_format, 3, &byte_offset));
uint32_t row_bytes;
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, 0, &row_bytes));
EXPECT_EQ(kBytesPerRow, row_bytes);
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, 1, &row_bytes));
EXPECT_EQ(kBytesPerRow / 2, row_bytes);
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, 2, &row_bytes));
EXPECT_EQ(kBytesPerRow / 2, row_bytes);
EXPECT_FALSE(ImageFormatPlaneRowBytes(image_format, 3, &row_bytes));
}
TEST(ImageFormat, PlaneByteOffset_V1_LLCPP) {
sysmem_v1::wire::PixelFormat linear = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierLinear,
};
sysmem_v1::wire::ImageFormatConstraints constraints = {
.pixel_format = linear,
.min_coded_width = 12,
.max_coded_width = 100,
.min_coded_height = 12,
.max_coded_height = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 4 * 8,
};
auto image_format_result = ImageConstraintsToFormat(constraints, 18, 17);
EXPECT_TRUE(image_format_result.is_ok());
auto image_format = image_format_result.take_value();
// The raw size would be 72 without bytes_per_row_divisor of 32.
EXPECT_EQ(96u, image_format.bytes_per_row);
uint64_t byte_offset;
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 0, &byte_offset));
EXPECT_EQ(0u, byte_offset);
EXPECT_FALSE(ImageFormatPlaneByteOffset(image_format, 1, &byte_offset));
constraints.pixel_format.type = sysmem_v1::wire::PixelFormatType::kI420;
constexpr uint32_t kBytesPerRow = 32;
image_format_result = ImageConstraintsToFormat(constraints, 18, 20);
EXPECT_TRUE(image_format_result.is_ok());
image_format = image_format_result.take_value();
EXPECT_EQ(kBytesPerRow, image_format.bytes_per_row);
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 0, &byte_offset));
EXPECT_EQ(0u, byte_offset);
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 1, &byte_offset));
EXPECT_EQ(kBytesPerRow * 20, byte_offset);
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 2, &byte_offset));
EXPECT_EQ(kBytesPerRow * 20 + kBytesPerRow / 2 * 20 / 2, byte_offset);
EXPECT_FALSE(ImageFormatPlaneByteOffset(image_format, 3, &byte_offset));
uint32_t row_bytes;
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, 0, &row_bytes));
EXPECT_EQ(kBytesPerRow, row_bytes);
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, 1, &row_bytes));
EXPECT_EQ(kBytesPerRow / 2, row_bytes);
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, 2, &row_bytes));
EXPECT_EQ(kBytesPerRow / 2, row_bytes);
EXPECT_FALSE(ImageFormatPlaneRowBytes(image_format, 3, &row_bytes));
}
TEST(ImageFormat, PlaneByteOffset_V1_C) {
fuchsia_sysmem_PixelFormat linear = {
.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.has_format_modifier = true,
.format_modifier.value = fuchsia_sysmem_FORMAT_MODIFIER_LINEAR,
};
fuchsia_sysmem_ImageFormatConstraints constraints = {
.pixel_format = linear,
.min_coded_width = 12,
.max_coded_width = 100,
.min_coded_height = 12,
.max_coded_height = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 4 * 8,
};
fuchsia_sysmem_ImageFormat_2 image_format;
EXPECT_TRUE(ImageConstraintsToFormat(&constraints, 18, 17, &image_format));
// The raw size would be 72 without bytes_per_row_divisor of 32.
EXPECT_EQ(96u, image_format.bytes_per_row);
uint64_t byte_offset;
EXPECT_TRUE(ImageFormatPlaneByteOffset(&image_format, 0, &byte_offset));
EXPECT_EQ(0u, byte_offset);
EXPECT_FALSE(ImageFormatPlaneByteOffset(&image_format, 1, &byte_offset));
constraints.pixel_format.type = fuchsia_sysmem_PixelFormatType_I420;
constexpr uint32_t kBytesPerRow = 32;
EXPECT_TRUE(ImageConstraintsToFormat(&constraints, 18, 20, &image_format));
EXPECT_EQ(kBytesPerRow, image_format.bytes_per_row);
EXPECT_TRUE(ImageFormatPlaneByteOffset(&image_format, 0, &byte_offset));
EXPECT_EQ(0u, byte_offset);
EXPECT_TRUE(ImageFormatPlaneByteOffset(&image_format, 1, &byte_offset));
EXPECT_EQ(kBytesPerRow * 20, byte_offset);
EXPECT_TRUE(ImageFormatPlaneByteOffset(&image_format, 2, &byte_offset));
EXPECT_EQ(kBytesPerRow * 20 + kBytesPerRow / 2 * 20 / 2, byte_offset);
EXPECT_FALSE(ImageFormatPlaneByteOffset(&image_format, 3, &byte_offset));
uint32_t row_bytes;
EXPECT_TRUE(ImageFormatPlaneRowBytes(&image_format, 0, &row_bytes));
EXPECT_EQ(kBytesPerRow, row_bytes);
EXPECT_TRUE(ImageFormatPlaneRowBytes(&image_format, 1, &row_bytes));
EXPECT_EQ(kBytesPerRow / 2, row_bytes);
EXPECT_TRUE(ImageFormatPlaneRowBytes(&image_format, 2, &row_bytes));
EXPECT_EQ(kBytesPerRow / 2, row_bytes);
EXPECT_FALSE(ImageFormatPlaneRowBytes(&image_format, 3, &row_bytes));
}
TEST(ImageFormat, TransactionEliminationFormats_V2_LLCPP) {
fidl::FidlAllocator allocator;
sysmem_v2::wire::PixelFormat format(allocator);
format.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
format.set_format_modifier_value(allocator, sysmem_v2::wire::kFormatModifierLinear);
EXPECT_TRUE(ImageFormatCompatibleWithProtectedMemory(format));
auto format2 = sysmem::V2ClonePixelFormat(allocator, format);
format2.set_format_modifier_value(allocator, sysmem_v2::wire::kFormatModifierArmLinearTe);
EXPECT_FALSE(ImageFormatCompatibleWithProtectedMemory(format2));
sysmem_v2::wire::ImageFormatConstraints constraints(allocator);
constraints.set_pixel_format(allocator, std::move(format2));
constraints.set_min_coded_width(allocator, 12u);
constraints.set_max_coded_width(allocator, 100u);
constraints.set_min_coded_height(allocator, 12u);
constraints.set_max_coded_height(allocator, 100u);
constraints.set_bytes_per_row_divisor(allocator, 4u * 8u);
constraints.set_max_bytes_per_row(allocator, 100000u);
auto image_format_result = ImageConstraintsToFormat(allocator, constraints, 18, 17);
EXPECT_TRUE(image_format_result.is_ok());
auto image_format = image_format_result.take_value();
// The raw size would be 72 without bytes_per_row_divisor of 32.
EXPECT_EQ(96u, image_format.bytes_per_row());
// Check the color plane data.
uint32_t row_bytes;
uint64_t plane_offset;
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, 0, &plane_offset));
EXPECT_EQ(0u, plane_offset);
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, 0, &row_bytes));
EXPECT_EQ(image_format.bytes_per_row(), row_bytes);
constexpr uint32_t kTePlane = 3;
// Check the TE plane data.
EXPECT_TRUE(ImageFormatPlaneByteOffset(image_format, kTePlane, &plane_offset));
EXPECT_LE(image_format.bytes_per_row() * 17, plane_offset);
EXPECT_TRUE(ImageFormatPlaneRowBytes(image_format, kTePlane, &row_bytes));
// Row size should be rounded up to 64 bytes.
EXPECT_EQ(64, row_bytes);
}
TEST(ImageFormat, TransactionEliminationFormats_V1_LLCPP) {
sysmem_v1::wire::PixelFormat format = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierLinear,
};
EXPECT_TRUE(image_format::FormatCompatibleWithProtectedMemory(format));
EXPECT_TRUE(ImageFormatCompatibleWithProtectedMemory(format));
format.format_modifier.value = sysmem_v1::wire::kFormatModifierArmLinearTe;
EXPECT_FALSE(image_format::FormatCompatibleWithProtectedMemory(format));
EXPECT_FALSE(ImageFormatCompatibleWithProtectedMemory(format));
sysmem_v1::wire::ImageFormatConstraints constraints = {
.pixel_format = format,
.min_coded_width = 12,
.max_coded_width = 100,
.min_coded_height = 12,
.max_coded_height = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 4 * 8,
};
auto optional_format = image_format::ConstraintsToFormat(constraints, 18, 17);
EXPECT_TRUE(optional_format);
auto& image_format = *optional_format;
// The raw size would be 72 without bytes_per_row_divisor of 32.
EXPECT_EQ(96u, image_format.bytes_per_row);
// Check the color plane data.
uint32_t row_bytes;
uint64_t plane_offset;
EXPECT_TRUE(image_format::GetPlaneByteOffset(image_format, 0, &plane_offset));
EXPECT_EQ(0u, plane_offset);
EXPECT_TRUE(image_format::GetPlaneRowBytes(image_format, 0, &row_bytes));
EXPECT_EQ(image_format.bytes_per_row, row_bytes);
constexpr uint32_t kTePlane = 3;
// Check the TE plane data.
EXPECT_TRUE(image_format::GetPlaneByteOffset(image_format, kTePlane, &plane_offset));
EXPECT_LE(image_format.bytes_per_row * 17, plane_offset);
EXPECT_TRUE(image_format::GetPlaneRowBytes(image_format, kTePlane, &row_bytes));
// Row size should be rounded up to 64 bytes.
EXPECT_EQ(64, row_bytes);
}
TEST(ImageFormat, BasicSizes_V2_LLCPP) {
fidl::FidlAllocator allocator;
constexpr uint32_t kWidth = 64;
constexpr uint32_t kHeight = 128;
constexpr uint32_t kStride = kWidth * 6;
sysmem_v2::wire::ImageFormat image_format_bgra32(allocator);
{
sysmem_v2::wire::PixelFormat pixel_format(allocator);
pixel_format.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
image_format_bgra32.set_pixel_format(allocator, std::move(pixel_format));
}
image_format_bgra32.set_coded_width(allocator, kWidth);
image_format_bgra32.set_coded_height(allocator, kHeight);
image_format_bgra32.set_bytes_per_row(allocator, kStride);
EXPECT_EQ(kHeight * kStride, ImageFormatImageSize(image_format_bgra32));
EXPECT_EQ(1, ImageFormatCodedWidthMinDivisor(image_format_bgra32.pixel_format()));
EXPECT_EQ(1, ImageFormatCodedHeightMinDivisor(image_format_bgra32.pixel_format()));
EXPECT_EQ(4, ImageFormatSampleAlignment(image_format_bgra32.pixel_format()));
sysmem_v2::wire::ImageFormat image_format_nv12(allocator);
{
sysmem_v2::wire::PixelFormat pixel_format(allocator);
pixel_format.set_type(allocator, sysmem_v2::wire::PixelFormatType::kNv12);
image_format_nv12.set_pixel_format(allocator, std::move(pixel_format));
}
image_format_nv12.set_coded_width(allocator, kWidth);
image_format_nv12.set_coded_height(allocator, kHeight);
image_format_nv12.set_bytes_per_row(allocator, kStride);
EXPECT_EQ(kHeight * kStride * 3 / 2, ImageFormatImageSize(image_format_nv12));
EXPECT_EQ(2, ImageFormatCodedWidthMinDivisor(image_format_nv12.pixel_format()));
EXPECT_EQ(2, ImageFormatCodedHeightMinDivisor(image_format_nv12.pixel_format()));
EXPECT_EQ(2, ImageFormatSampleAlignment(image_format_nv12.pixel_format()));
}
TEST(ImageFormat, BasicSizes_V1_LLCPP) {
constexpr uint32_t kWidth = 64;
constexpr uint32_t kHeight = 128;
constexpr uint32_t kStride = 256;
sysmem_v1::wire::ImageFormat2 image_format_bgra32 = {
.pixel_format.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.coded_width = kWidth,
.coded_height = kHeight,
.bytes_per_row = kStride,
};
EXPECT_EQ(kHeight * kStride, ImageFormatImageSize(image_format_bgra32));
EXPECT_EQ(1, ImageFormatCodedWidthMinDivisor(image_format_bgra32.pixel_format));
EXPECT_EQ(1, ImageFormatCodedHeightMinDivisor(image_format_bgra32.pixel_format));
EXPECT_EQ(4, ImageFormatSampleAlignment(image_format_bgra32.pixel_format));
sysmem_v1::wire::ImageFormat2 image_format_nv12 = {
.pixel_format.type = sysmem_v1::wire::PixelFormatType::kNv12,
.coded_width = kWidth,
.coded_height = kHeight,
.bytes_per_row = kStride,
};
EXPECT_EQ(kHeight * kStride * 3 / 2, ImageFormatImageSize(image_format_nv12));
EXPECT_EQ(2, ImageFormatCodedWidthMinDivisor(image_format_nv12.pixel_format));
EXPECT_EQ(2, ImageFormatCodedHeightMinDivisor(image_format_nv12.pixel_format));
EXPECT_EQ(2, ImageFormatSampleAlignment(image_format_nv12.pixel_format));
}
TEST(ImageFormat, BasicSizes_V1_C) {
constexpr uint32_t kWidth = 64;
constexpr uint32_t kHeight = 128;
constexpr uint32_t kStride = 256;
fuchsia_sysmem_ImageFormat_2 image_format_bgra32 = {
.pixel_format.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.coded_width = kWidth,
.coded_height = kHeight,
.bytes_per_row = kStride,
};
EXPECT_EQ(kHeight * kStride, ImageFormatImageSize(&image_format_bgra32));
EXPECT_EQ(1, ImageFormatCodedWidthMinDivisor(&image_format_bgra32.pixel_format));
EXPECT_EQ(1, ImageFormatCodedHeightMinDivisor(&image_format_bgra32.pixel_format));
EXPECT_EQ(4, ImageFormatSampleAlignment(&image_format_bgra32.pixel_format));
fuchsia_sysmem_ImageFormat_2 image_format_nv12{
.pixel_format.type = fuchsia_sysmem_PixelFormatType_NV12,
.coded_width = kWidth,
.coded_height = kHeight,
.bytes_per_row = kStride,
};
EXPECT_EQ(kHeight * kStride * 3 / 2, ImageFormatImageSize(&image_format_nv12));
EXPECT_EQ(2, ImageFormatCodedWidthMinDivisor(&image_format_nv12.pixel_format));
EXPECT_EQ(2, ImageFormatCodedHeightMinDivisor(&image_format_nv12.pixel_format));
EXPECT_EQ(2, ImageFormatSampleAlignment(&image_format_nv12.pixel_format));
}
TEST(ImageFormat, AfbcFlagFormats_V1_LLCPP) {
sysmem_v1::wire::PixelFormat format = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierArmAfbc16X16SplitBlockSparseYuvTe,
};
EXPECT_FALSE(image_format::FormatCompatibleWithProtectedMemory(format));
sysmem_v1::wire::ImageFormatConstraints constraints = {
.pixel_format = format,
.min_coded_width = 12,
.max_coded_width = 100,
.min_coded_height = 12,
.max_coded_height = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 4 * 8,
};
auto optional_format = image_format::ConstraintsToFormat(constraints, 18, 17);
EXPECT_TRUE(optional_format);
sysmem_v1::wire::PixelFormat tiled_format = {
.type = sysmem_v1::wire::PixelFormatType::kBgra32,
.has_format_modifier = true,
.format_modifier.value =
sysmem_v1::wire::kFormatModifierArmAfbc16X16SplitBlockSparseYuvTiledHeader,
};
constraints.pixel_format = tiled_format;
optional_format = image_format::ConstraintsToFormat(constraints, 18, 17);
EXPECT_TRUE(optional_format);
auto& image_format = *optional_format;
constexpr uint32_t kMinHeaderOffset = 4096u;
constexpr uint32_t kMinWidth = 128;
constexpr uint32_t kMinHeight = 128;
EXPECT_EQ(kMinHeaderOffset + kMinWidth * kMinHeight * 4, ImageFormatImageSize(image_format));
}
TEST(ImageFormat, R8G8Formats_V1_LLCPP) {
sysmem_v1::wire::PixelFormat format = {
.type = sysmem_v1::wire::PixelFormatType::kR8G8,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::kFormatModifierLinear,
};
sysmem_v1::wire::ImageFormatConstraints constraints = {
.pixel_format = format,
.min_coded_width = 12,
.max_coded_width = 100,
.min_coded_height = 12,
.max_coded_height = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 1,
};
auto optional_format = image_format::ConstraintsToFormat(constraints, 18, 17);
EXPECT_TRUE(optional_format);
EXPECT_EQ(18u * 2, optional_format->bytes_per_row);
EXPECT_EQ(18u * 17u * 2, ImageFormatImageSize(*optional_format));
constraints.pixel_format.type = sysmem_v1::wire::PixelFormatType::kR8;
optional_format = image_format::ConstraintsToFormat(constraints, 18, 17);
EXPECT_TRUE(optional_format);
EXPECT_EQ(18u * 1, optional_format->bytes_per_row);
EXPECT_EQ(18u * 17u * 1, ImageFormatImageSize(*optional_format));
}
TEST(ImageFormat, A2R10G10B10_Formats_V1_LLCPP) {
for (const auto& pixel_format_type : {sysmem_v1::wire::PixelFormatType::A2R10G10B10,
sysmem_v1::wire::PixelFormatType::A2B10G10R10}) {
sysmem_v1::wire::PixelFormat format = {
.type = pixel_format_type,
.has_format_modifier = true,
.format_modifier.value = sysmem_v1::wire::FORMAT_MODIFIER_LINEAR,
};
sysmem_v1::wire::ImageFormatConstraints constraints = {
.pixel_format = format,
.min_coded_width = 12,
.max_coded_width = 100,
.min_coded_height = 12,
.max_coded_height = 100,
.max_bytes_per_row = 100000,
.bytes_per_row_divisor = 1,
};
auto optional_format = image_format::ConstraintsToFormat(constraints, 18, 17);
EXPECT_TRUE(optional_format);
EXPECT_EQ(18u * 4, optional_format->bytes_per_row);
EXPECT_EQ(18u * 17u * 4, ImageFormatImageSize(*optional_format));
EXPECT_EQ(1, ImageFormatCodedWidthMinDivisor(optional_format->pixel_format));
EXPECT_EQ(1, ImageFormatCodedHeightMinDivisor(optional_format->pixel_format));
EXPECT_EQ(4, ImageFormatSampleAlignment(optional_format->pixel_format));
}
}
TEST(ImageFormat, GoldfishOptimal_V2_LLCPP) {
fidl::FidlAllocator allocator;
constexpr uint32_t kWidth = 64;
constexpr uint32_t kHeight = 128;
constexpr uint32_t kStride = kWidth * 6;
sysmem_v2::wire::ImageFormat linear_image_format_bgra32(allocator);
{
sysmem_v2::wire::PixelFormat pixel_format(allocator);
pixel_format.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
linear_image_format_bgra32.set_pixel_format(allocator, std::move(pixel_format));
}
linear_image_format_bgra32.set_coded_width(allocator, kWidth);
linear_image_format_bgra32.set_coded_height(allocator, kHeight);
linear_image_format_bgra32.set_bytes_per_row(allocator, kStride);
sysmem_v2::wire::ImageFormat goldfish_optimal_image_format_bgra32(allocator);
{
sysmem_v2::wire::PixelFormat pixel_format(allocator);
pixel_format.set_type(allocator, sysmem_v2::wire::PixelFormatType::kBgra32);
pixel_format.set_format_modifier_value(allocator,
sysmem_v2::wire::kFormatModifierGoogleGoldfishOptimal);
goldfish_optimal_image_format_bgra32.set_pixel_format(allocator, std::move(pixel_format));
}
goldfish_optimal_image_format_bgra32.set_coded_width(allocator, kWidth);
goldfish_optimal_image_format_bgra32.set_coded_height(allocator, kHeight);
goldfish_optimal_image_format_bgra32.set_bytes_per_row(allocator, kStride);
EXPECT_EQ(ImageFormatImageSize(linear_image_format_bgra32),
ImageFormatImageSize(goldfish_optimal_image_format_bgra32));
EXPECT_EQ(ImageFormatCodedWidthMinDivisor(linear_image_format_bgra32.pixel_format()),
ImageFormatCodedWidthMinDivisor(goldfish_optimal_image_format_bgra32.pixel_format()));
EXPECT_EQ(ImageFormatCodedHeightMinDivisor(linear_image_format_bgra32.pixel_format()),
ImageFormatCodedHeightMinDivisor(goldfish_optimal_image_format_bgra32.pixel_format()));
EXPECT_EQ(ImageFormatSampleAlignment(linear_image_format_bgra32.pixel_format()),
ImageFormatSampleAlignment(goldfish_optimal_image_format_bgra32.pixel_format()));
}
TEST(ImageFormat, CorrectModifiers) {
EXPECT_EQ(sysmem_v1::wire::kFormatModifierArmAfbc16X16YuvTiledHeader,
sysmem_v1::wire::kFormatModifierArmAfbc16X16YuvTiledHeader);
EXPECT_EQ(sysmem_v1::wire::kFormatModifierArmAfbc16X16YuvTiledHeader,
sysmem_v1::wire::kFormatModifierArmAfbc16X16 |
sysmem_v1::wire::kFormatModifierArmYuvBit |
sysmem_v1::wire::kFormatModifierArmTiledHeaderBit);
EXPECT_EQ(sysmem_v1::wire::kFormatModifierGoogleGoldfishOptimal,
sysmem_v2::wire::kFormatModifierGoogleGoldfishOptimal);
}