Merge "Add test in VTS MapperV4 for YCbCr_P010"
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index f55a6b7..e18b1fa 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -59,6 +59,12 @@
using DecodeFunction = std::function<void(const IMapper::BufferDescriptorInfo& descriptorInfo,
const hidl_vec<uint8_t>& vec)>;
+struct YCbCr {
+ android_ycbcr yCbCr;
+ int64_t horizontalSubSampling;
+ int64_t verticalSubSampling;
+};
+
class GraphicsMapperHidlTest
: public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
protected:
@@ -215,8 +221,8 @@
}
ASSERT_EQ(0, planeLayoutComponent.offsetInBits % 8);
- uint8_t* tmpData =
- data + planeLayout.offsetInBytes + (planeLayoutComponent.offsetInBits / 8);
+ uint8_t* tmpData = data + planeLayout.offsetInBytes +
+ bitsToBytes(planeLayoutComponent.offsetInBits);
uint64_t sampleIncrementInBytes;
auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
@@ -271,6 +277,96 @@
ASSERT_NE(nullptr, outYCbCr->cr);
}
+ YCbCr getAndroidYCbCr_P010(const native_handle_t* bufferHandle, uint8_t* data) {
+ YCbCr yCbCr_P010;
+ hidl_vec<uint8_t> vec;
+ EXPECT_EQ(Error::NONE,
+ mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+ std::vector<PlaneLayout> planeLayouts;
+ EXPECT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+ EXPECT_EQ(2, planeLayouts.size());
+ EXPECT_EQ(1, planeLayouts[0].components.size());
+ EXPECT_EQ(2, planeLayouts[1].components.size());
+
+ yCbCr_P010.yCbCr.y = nullptr;
+ yCbCr_P010.yCbCr.cb = nullptr;
+ yCbCr_P010.yCbCr.cr = nullptr;
+ yCbCr_P010.yCbCr.ystride = 0;
+ yCbCr_P010.yCbCr.cstride = 0;
+ yCbCr_P010.yCbCr.chroma_step = 0;
+ int64_t cb_offset = 0;
+ int64_t cr_offset = 0;
+
+ for (const auto& planeLayout : planeLayouts) {
+ for (const auto& planeLayoutComponent : planeLayout.components) {
+ if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
+ continue;
+ }
+
+ uint8_t* tmpData = data + planeLayout.offsetInBytes +
+ bitsToBytes(planeLayoutComponent.offsetInBits);
+ uint64_t sampleIncrementInBytes = 0;
+ auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
+ switch (type) {
+ case PlaneLayoutComponentType::Y:
+ // For specs refer:
+ // https://docs.microsoft.com/en-us/windows/win32/medfound/10-bit-and-16-bit-yuv-video-formats
+ EXPECT_EQ(6, planeLayoutComponent.offsetInBits);
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.y);
+ EXPECT_EQ(10, planeLayoutComponent.sizeInBits);
+ EXPECT_EQ(16, planeLayout.sampleIncrementInBits);
+
+ yCbCr_P010.yCbCr.y = tmpData;
+ yCbCr_P010.yCbCr.ystride = planeLayout.strideInBytes;
+ break;
+
+ case PlaneLayoutComponentType::CB:
+ case PlaneLayoutComponentType::CR:
+ sampleIncrementInBytes = bitsToBytes(planeLayout.sampleIncrementInBits);
+ EXPECT_EQ(4, sampleIncrementInBytes);
+
+ if (yCbCr_P010.yCbCr.cstride == 0 && yCbCr_P010.yCbCr.chroma_step == 0) {
+ yCbCr_P010.yCbCr.cstride = planeLayout.strideInBytes;
+ yCbCr_P010.yCbCr.chroma_step = sampleIncrementInBytes;
+ } else {
+ EXPECT_EQ(yCbCr_P010.yCbCr.cstride, planeLayout.strideInBytes);
+ EXPECT_EQ(yCbCr_P010.yCbCr.chroma_step, sampleIncrementInBytes);
+ }
+
+ if (yCbCr_P010.horizontalSubSampling == 0 &&
+ yCbCr_P010.verticalSubSampling == 0) {
+ yCbCr_P010.horizontalSubSampling = planeLayout.horizontalSubsampling;
+ yCbCr_P010.verticalSubSampling = planeLayout.verticalSubsampling;
+ } else {
+ EXPECT_EQ(yCbCr_P010.horizontalSubSampling,
+ planeLayout.horizontalSubsampling);
+ EXPECT_EQ(yCbCr_P010.verticalSubSampling,
+ planeLayout.verticalSubsampling);
+ }
+
+ if (type == PlaneLayoutComponentType::CB) {
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cb);
+ yCbCr_P010.yCbCr.cb = tmpData;
+ cb_offset = planeLayoutComponent.offsetInBits;
+ } else {
+ EXPECT_EQ(nullptr, yCbCr_P010.yCbCr.cr);
+ yCbCr_P010.yCbCr.cr = tmpData;
+ cr_offset = planeLayoutComponent.offsetInBits;
+ }
+ break;
+ default:
+ break;
+ };
+ }
+ }
+
+ EXPECT_EQ(cb_offset + bytesToBits(2), cr_offset);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.y);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cb);
+ EXPECT_NE(nullptr, yCbCr_P010.yCbCr.cr);
+ return yCbCr_P010;
+ }
+
void fillRGBA8888(uint8_t* data, uint32_t height, size_t strideInBytes, size_t widthInBytes,
uint32_t seed = 0) {
for (uint32_t y = 0; y < height; y++) {
@@ -297,9 +393,9 @@
}
}
- void traverseYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
- int64_t hSubsampling, int64_t vSubsampling,
- std::function<void(uint8_t*, uint8_t)> traverseFuncion) {
+ void traverseYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling,
+ std::function<void(uint8_t*, uint8_t)> traverseFuncion) {
auto yData = static_cast<uint8_t*>(yCbCr.y);
auto cbData = static_cast<uint8_t*>(yCbCr.cb);
auto crData = static_cast<uint8_t*>(yCbCr.cr);
@@ -327,21 +423,25 @@
}
}
- void fillYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
- int64_t hSubsampling, int64_t vSubsampling) {
- traverseYCbCr888Data(yCbCr, width, height, hSubsampling, vSubsampling,
- [](auto address, auto fillingData) { *address = fillingData; });
+ void fillYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling) {
+ traverseYCbCrData(yCbCr, width, height, hSubsampling, vSubsampling,
+ [](auto address, auto fillingData) { *address = fillingData; });
}
- void verifyYCbCr888Data(const android_ycbcr& yCbCr, int32_t width, int32_t height,
- int64_t hSubsampling, int64_t vSubsampling) {
- traverseYCbCr888Data(
+ void verifyYCbCrData(const android_ycbcr& yCbCr, int32_t width, int32_t height,
+ int64_t hSubsampling, int64_t vSubsampling) {
+ traverseYCbCrData(
yCbCr, width, height, hSubsampling, vSubsampling,
[](auto address, auto expectedData) { EXPECT_EQ(*address, expectedData); });
}
bool isEqual(float a, float b) { return abs(a - b) < 0.0001; }
+ uint64_t bitsToBytes(int64_t bits) { return bits / 8; }
+
+ uint64_t bytesToBits(int64_t bytes) { return bytes * 8; }
+
std::unique_ptr<Gralloc> mGralloc;
IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
static const std::set<StandardMetadataType> sRequiredMetadataTypes;
@@ -645,7 +745,7 @@
ASSERT_EQ(crData + 1, cbData);
ASSERT_EQ(2, yCbCr.chroma_step);
- fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
@@ -656,7 +756,7 @@
ASSERT_NO_FATAL_FAILURE(
getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
- verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}
@@ -744,7 +844,7 @@
ASSERT_EQ(crData + yCbCr.cstride * info.height / vSubsampling, cbData);
ASSERT_EQ(1, yCbCr.chroma_step);
- fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
@@ -755,7 +855,7 @@
ASSERT_NO_FATAL_FAILURE(
getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
- verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}
@@ -788,7 +888,7 @@
ASSERT_EQ(kCbCrSubSampleFactor, hSubsampling);
ASSERT_EQ(kCbCrSubSampleFactor, vSubsampling);
- fillYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+ fillYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
@@ -799,7 +899,7 @@
ASSERT_NO_FATAL_FAILURE(
getAndroidYCbCr(bufferHandle, data, &yCbCr, &hSubsampling, &vSubsampling));
- verifyYCbCr888Data(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
+ verifyYCbCrData(yCbCr, info.width, info.height, hSubsampling, vSubsampling);
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}
@@ -888,6 +988,42 @@
ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
}
+TEST_P(GraphicsMapperHidlTest, Lock_YCBCR_P010) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::YCBCR_P010;
+
+ const native_handle_t* bufferHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandle = mGralloc->allocate(info, true, Tolerance::kToleranceStrict, &stride));
+
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ unique_fd fence;
+ uint8_t* data;
+
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage,
+ region, fence.release())));
+
+ YCbCr yCbCr;
+ ASSERT_NO_FATAL_FAILURE(yCbCr = getAndroidYCbCr_P010(bufferHandle, data));
+
+ constexpr uint32_t kCbCrSubSampleFactor = 2;
+ ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.horizontalSubSampling);
+ ASSERT_EQ(kCbCrSubSampleFactor, yCbCr.verticalSubSampling);
+
+ ASSERT_EQ(0, info.height % 2);
+
+ // fill the data
+ fillYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+ yCbCr.verticalSubSampling);
+ // verify the YCbCr data
+ verifyYCbCrData(yCbCr.yCbCr, info.width, info.height, yCbCr.horizontalSubSampling,
+ yCbCr.verticalSubSampling);
+
+ ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
/**
* Test IMapper::unlock with bad access region
*/