mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 15:58:43 +00:00
Revise IAllocator and IMapper to reduce IPC and to support gralloc0
devices.
Specifically, IAllocator is trimmed down to have essentially only
allocate(BufferDescriptor descriptor, uint32_t count)
generates (Error error,
uint32_t stride,
vec<handle> buffers);
The ability to allocate buffers with shared backing store is
removed. ProducerUsage and ConsumerUsage are moved to the
graphics.common package and are merged and renamed to BufferUsage.
BufferUsage's bits follow gralloc0.
IMapper gains
typedef vec<uint32_t> BufferDescriptor;
createDescriptor(BufferDescriptorInfo descriptorInfo)
generates (Error error,
BufferDescriptor descriptor);
where BufferDescriptor is an implementation-defined blob. lockFlex
is replaced by lockYCbCr. All getters are removed.
Reference counting with retain/release is replaced by
importBuffer/freeBuffer.
Most if not all gralloc1 features are not used by the runtime yet.
There is also not too much test written for them. As such, they
tend to behave differently between implementations and cannot be
used reliably.
Bug: 36481301
Test: builds and boots on Pixel
Change-Id: I1d31105120517ea2c128c7a19297acf3bfd312bb
425 lines
14 KiB
C++
425 lines
14 KiB
C++
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "VtsHalGraphicsMapperV2_0TargetTest"
|
|
|
|
#include <VtsHalHidlTargetTestBase.h>
|
|
#include <android-base/logging.h>
|
|
#include <sync/sync.h>
|
|
#include "VtsHalGraphicsMapperTestUtils.h"
|
|
|
|
namespace android {
|
|
namespace hardware {
|
|
namespace graphics {
|
|
namespace mapper {
|
|
namespace V2_0 {
|
|
namespace tests {
|
|
namespace {
|
|
|
|
using android::hardware::graphics::common::V1_0::BufferUsage;
|
|
using android::hardware::graphics::common::V1_0::PixelFormat;
|
|
|
|
class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
|
|
protected:
|
|
void SetUp() override {
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
|
|
|
|
mDummyDescriptorInfo.width = 64;
|
|
mDummyDescriptorInfo.height = 64;
|
|
mDummyDescriptorInfo.layerCount = 1;
|
|
mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
|
|
mDummyDescriptorInfo.usage = static_cast<uint64_t>(
|
|
BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
|
|
}
|
|
|
|
void TearDown() override {}
|
|
|
|
std::unique_ptr<Gralloc> mGralloc;
|
|
IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
|
|
};
|
|
|
|
/**
|
|
* Test IAllocator::dumpDebugInfo by calling it.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
|
|
mGralloc->dumpDebugInfo();
|
|
}
|
|
|
|
/**
|
|
* Test IAllocator::allocate with valid buffer descriptors.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
|
|
BufferDescriptor descriptor;
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
|
|
|
|
for (uint32_t count = 0; count < 5; count++) {
|
|
std::vector<const native_handle_t*> bufferHandles;
|
|
uint32_t stride;
|
|
ASSERT_NO_FATAL_FAILURE(bufferHandles = mGralloc->allocate(
|
|
descriptor, count, false, &stride));
|
|
|
|
if (count >= 1) {
|
|
EXPECT_LE(mDummyDescriptorInfo.width, stride)
|
|
<< "invalid buffer stride";
|
|
}
|
|
|
|
for (auto bufferHandle : bufferHandles) {
|
|
mGralloc->freeBuffer(bufferHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test IAllocator::allocate with invalid buffer descriptors.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
|
|
// this assumes any valid descriptor is non-empty
|
|
BufferDescriptor descriptor;
|
|
mGralloc->getAllocator()->allocate(
|
|
descriptor, 1, [&](const auto& tmpError, const auto&, const auto&) {
|
|
EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test IAllocator::allocate does not leak.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
|
|
auto info = mDummyDescriptorInfo;
|
|
info.width = 1024;
|
|
info.height = 1024;
|
|
|
|
for (int i = 0; i < 2048; i++) {
|
|
auto bufferHandle = mGralloc->allocate(info, false);
|
|
mGralloc->freeBuffer(bufferHandle);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::createDescriptor with valid descriptor info.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::createDescriptor with invalid descriptor info.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
|
|
auto info = mDummyDescriptorInfo;
|
|
info.width = 0;
|
|
mGralloc->getMapper()->createDescriptor(
|
|
info, [&](const auto& tmpError, const auto&) {
|
|
EXPECT_EQ(Error::BAD_VALUE, tmpError)
|
|
<< "createDescriptor did not fail with BAD_VALUE";
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
|
|
const native_handle_t* bufferHandle;
|
|
ASSERT_NO_FATAL_FAILURE(bufferHandle =
|
|
mGralloc->allocate(mDummyDescriptorInfo, true));
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
|
|
const native_handle_t* clonedBufferHandle;
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
|
|
|
|
// A cloned handle is a raw handle. Check that we can import it multiple
|
|
// times.
|
|
const native_handle_t* importedBufferHandles[2];
|
|
ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] =
|
|
mGralloc->importBuffer(clonedBufferHandle));
|
|
ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] =
|
|
mGralloc->importBuffer(clonedBufferHandle));
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));
|
|
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
|
|
const native_handle_t* rawHandle;
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
|
|
|
|
native_handle_t* importedHandle = nullptr;
|
|
mGralloc->getMapper()->importBuffer(
|
|
rawHandle, [&](const auto& tmpError, const auto& buffer) {
|
|
ASSERT_EQ(Error::NONE, tmpError);
|
|
importedHandle = static_cast<native_handle_t*>(buffer);
|
|
});
|
|
|
|
// free the imported handle with another mapper
|
|
std::unique_ptr<Gralloc> anotherGralloc;
|
|
ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>());
|
|
Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
|
|
ASSERT_EQ(Error::NONE, error);
|
|
|
|
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
|
|
auto info = mDummyDescriptorInfo;
|
|
info.width = 1024;
|
|
info.height = 1024;
|
|
|
|
for (int i = 0; i < 2048; i++) {
|
|
auto bufferHandle = mGralloc->allocate(info, true);
|
|
mGralloc->freeBuffer(bufferHandle);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::importBuffer with invalid buffers.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
|
|
native_handle_t* invalidHandle = nullptr;
|
|
mGralloc->getMapper()->importBuffer(
|
|
invalidHandle, [&](const auto& tmpError, const auto&) {
|
|
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
|
|
<< "importBuffer with nullptr did not fail with BAD_BUFFER";
|
|
});
|
|
|
|
invalidHandle = native_handle_create(0, 0);
|
|
mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError,
|
|
const auto&) {
|
|
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
|
|
<< "importBuffer with invalid handle did not fail with BAD_BUFFER";
|
|
});
|
|
native_handle_delete(invalidHandle);
|
|
|
|
const native_handle_t* importedHandle;
|
|
ASSERT_NO_FATAL_FAILURE(importedHandle =
|
|
mGralloc->allocate(mDummyDescriptorInfo, true));
|
|
mGralloc->getMapper()->importBuffer(
|
|
importedHandle, [&](const auto& tmpError, const auto&) {
|
|
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
|
|
<< "importBuffer with an "
|
|
"already imported handle did "
|
|
"not fail with BAD_BUFFER";
|
|
});
|
|
mGralloc->freeBuffer(importedHandle);
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::freeBuffer with invalid buffers.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
|
|
native_handle_t* invalidHandle = nullptr;
|
|
Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
|
|
EXPECT_EQ(Error::BAD_BUFFER, error)
|
|
<< "freeBuffer with nullptr did not fail with BAD_BUFFER";
|
|
|
|
invalidHandle = native_handle_create(0, 0);
|
|
error = mGralloc->getMapper()->freeBuffer(invalidHandle);
|
|
EXPECT_EQ(Error::BAD_BUFFER, error)
|
|
<< "freeBuffer with invalid handle did not fail with BAD_BUFFER";
|
|
native_handle_delete(invalidHandle);
|
|
|
|
const native_handle_t* clonedBufferHandle;
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
|
|
error = mGralloc->getMapper()->freeBuffer(invalidHandle);
|
|
EXPECT_EQ(Error::BAD_BUFFER, error)
|
|
<< "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
|
|
|
|
mGralloc->freeBuffer(clonedBufferHandle);
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::lock and IMapper::unlock.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
|
|
const auto& info = mDummyDescriptorInfo;
|
|
|
|
const native_handle_t* bufferHandle;
|
|
uint32_t stride;
|
|
ASSERT_NO_FATAL_FAILURE(bufferHandle =
|
|
mGralloc->allocate(info, true, &stride));
|
|
|
|
// lock buffer for writing
|
|
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
|
|
static_cast<int32_t>(info.height)};
|
|
int fence = -1;
|
|
uint8_t* data;
|
|
ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
|
|
bufferHandle, info.usage, region, fence)));
|
|
|
|
// RGBA_8888
|
|
size_t strideInBytes = stride * 4;
|
|
size_t writeInBytes = info.width * 4;
|
|
|
|
for (uint32_t y = 0; y < info.height; y++) {
|
|
memset(data, y, writeInBytes);
|
|
data += strideInBytes;
|
|
}
|
|
|
|
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
|
|
|
|
// lock again for reading
|
|
ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
|
|
bufferHandle, info.usage, region, fence)));
|
|
for (uint32_t y = 0; y < info.height; y++) {
|
|
for (size_t i = 0; i < writeInBytes; i++) {
|
|
EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
|
|
}
|
|
data += strideInBytes;
|
|
}
|
|
|
|
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
|
|
if (fence >= 0) {
|
|
close(fence);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can
|
|
* write to and read from it.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
|
|
auto info = mDummyDescriptorInfo;
|
|
info.format = PixelFormat::YV12;
|
|
|
|
const native_handle_t* bufferHandle;
|
|
uint32_t stride;
|
|
ASSERT_NO_FATAL_FAILURE(bufferHandle =
|
|
mGralloc->allocate(info, true, &stride));
|
|
|
|
// lock buffer for writing
|
|
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
|
|
static_cast<int32_t>(info.height)};
|
|
int fence = -1;
|
|
YCbCrLayout layout;
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
|
|
|
|
auto yData = static_cast<uint8_t*>(layout.y);
|
|
auto cbData = static_cast<uint8_t*>(layout.cb);
|
|
auto crData = static_cast<uint8_t*>(layout.cr);
|
|
for (uint32_t y = 0; y < info.height; y++) {
|
|
for (uint32_t x = 0; x < info.width; x++) {
|
|
auto val = static_cast<uint8_t>(info.height * y + x);
|
|
|
|
yData[layout.yStride * y + x] = val;
|
|
if (y % 2 == 0 && x % 2 == 0) {
|
|
cbData[layout.cStride * y / 2 + x / 2] = val;
|
|
crData[layout.cStride * y / 2 + x / 2] = val;
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
|
|
|
|
// lock again for reading
|
|
ASSERT_NO_FATAL_FAILURE(
|
|
layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
|
|
|
|
yData = static_cast<uint8_t*>(layout.y);
|
|
cbData = static_cast<uint8_t*>(layout.cb);
|
|
crData = static_cast<uint8_t*>(layout.cr);
|
|
for (uint32_t y = 0; y < info.height; y++) {
|
|
for (uint32_t x = 0; x < info.width; x++) {
|
|
auto val = static_cast<uint8_t>(info.height * y + x);
|
|
|
|
EXPECT_EQ(val, yData[layout.yStride * y + x]);
|
|
if (y % 2 == 0 && x % 2 == 0) {
|
|
EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]);
|
|
EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
|
|
if (fence >= 0) {
|
|
close(fence);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test IMapper::unlock with invalid buffers.
|
|
*/
|
|
TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
|
|
native_handle_t* invalidHandle = nullptr;
|
|
mGralloc->getMapper()->unlock(
|
|
invalidHandle, [&](const auto& tmpError, const auto&) {
|
|
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
|
|
<< "unlock with nullptr did not fail with BAD_BUFFER";
|
|
});
|
|
|
|
invalidHandle = native_handle_create(0, 0);
|
|
mGralloc->getMapper()->unlock(
|
|
invalidHandle, [&](const auto& tmpError, const auto&) {
|
|
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
|
|
<< "unlock with invalid handle did not fail with BAD_BUFFER";
|
|
});
|
|
native_handle_delete(invalidHandle);
|
|
|
|
ASSERT_NO_FATAL_FAILURE(invalidHandle =
|
|
const_cast<native_handle_t*>(mGralloc->allocate(
|
|
mDummyDescriptorInfo, false)));
|
|
mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError,
|
|
const auto&) {
|
|
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
|
|
<< "unlock with un-imported handle did not fail with BAD_BUFFER";
|
|
});
|
|
mGralloc->freeBuffer(invalidHandle);
|
|
|
|
// disabled as it fails on many existing drivers
|
|
#if 0
|
|
ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
|
|
mGralloc->allocate(mDummyDescriptorInfo, true)));
|
|
mGralloc->getMapper()->unlock(
|
|
invalidHandle, [&](const auto& tmpError, const auto&) {
|
|
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
|
|
<< "unlock with unlocked handle did not fail with BAD_BUFFER";
|
|
});
|
|
mGralloc->freeBuffer(invalidHandle);
|
|
#endif
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace tests
|
|
} // namespace V2_0
|
|
} // namespace mapper
|
|
} // namespace graphics
|
|
} // namespace hardware
|
|
} // namespace android
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
|
|
int status = RUN_ALL_TESTS();
|
|
LOG(INFO) << "Test result = " << status;
|
|
|
|
return status;
|
|
}
|