IMapper 5 - the Stable C approach
Test: make VtsHalGraphicsMapperStableC_TargetTest VtsHalGraphicsAllocatorAidl_TargetTest Change-Id: I910b27f388e3fb7261425dd4b2133885c05edd37
This commit is contained in:
parent
d2e68f1579
commit
48c546c7e9
15 changed files with 3769 additions and 100 deletions
|
@ -268,7 +268,7 @@
|
|||
</hal>
|
||||
<hal format="aidl" optional="true">
|
||||
<name>android.hardware.graphics.allocator</name>
|
||||
<version>1</version>
|
||||
<version>1-2</version>
|
||||
<interface>
|
||||
<name>IAllocator</name>
|
||||
<instance>default</instance>
|
||||
|
@ -282,7 +282,7 @@
|
|||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="false">
|
||||
<hal format="hidl" optional="true">
|
||||
<name>android.hardware.graphics.mapper</name>
|
||||
<!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
|
||||
<version>2.1</version>
|
||||
|
|
|
@ -19,14 +19,14 @@ package {
|
|||
cc_defaults {
|
||||
name: "android.hardware.graphics.allocator-ndk_static",
|
||||
static_libs: [
|
||||
"android.hardware.graphics.allocator-V1-ndk",
|
||||
"android.hardware.graphics.allocator-V2-ndk",
|
||||
],
|
||||
}
|
||||
|
||||
cc_defaults {
|
||||
name: "android.hardware.graphics.allocator-ndk_shared",
|
||||
shared_libs: [
|
||||
"android.hardware.graphics.allocator-V1-ndk",
|
||||
"android.hardware.graphics.allocator-V2-ndk",
|
||||
],
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ aidl_interface {
|
|||
enabled: true,
|
||||
support_system_process: true,
|
||||
},
|
||||
vndk_use_version: "1",
|
||||
vndk_use_version: "2",
|
||||
srcs: ["android/hardware/graphics/allocator/*.aidl"],
|
||||
imports: [
|
||||
"android.hardware.common-V2",
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
|
||||
// two cases:
|
||||
// 1). this is a frozen version file - do not edit this in any case.
|
||||
// 2). this is a 'current' file. If you make a backwards compatible change to
|
||||
// the interface (from the latest frozen version), the build system will
|
||||
// prompt you to update this file with `m <name>-update-api`.
|
||||
//
|
||||
// You must not make a backward incompatible change to any AIDL file built
|
||||
// with the aidl_interface module type with versions property set. The module
|
||||
// type is used to build AIDL files in a way that they can be used across
|
||||
// independently updatable components of the system. If a device is shipped
|
||||
// with such a backward incompatible change, it has a high risk of breaking
|
||||
// later when a module using the interface is updated, e.g., Mainline modules.
|
||||
|
||||
package android.hardware.graphics.allocator;
|
||||
@VintfStability
|
||||
parcelable BufferDescriptorInfo {
|
||||
byte[128] name;
|
||||
int width;
|
||||
int height;
|
||||
int layerCount;
|
||||
android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
|
||||
android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
|
||||
long reservedSize;
|
||||
}
|
|
@ -34,5 +34,11 @@
|
|||
package android.hardware.graphics.allocator;
|
||||
@VintfStability
|
||||
interface IAllocator {
|
||||
/**
|
||||
* @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with allocate2
|
||||
*/
|
||||
android.hardware.graphics.allocator.AllocationResult allocate(in byte[] descriptor, in int count);
|
||||
android.hardware.graphics.allocator.AllocationResult allocate2(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor, in int count);
|
||||
boolean isSupported(in android.hardware.graphics.allocator.BufferDescriptorInfo descriptor);
|
||||
String getIMapperLibrarySuffix();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
package android.hardware.graphics.allocator;
|
||||
|
||||
import android.hardware.graphics.common.BufferUsage;
|
||||
import android.hardware.graphics.common.PixelFormat;
|
||||
|
||||
@VintfStability
|
||||
parcelable BufferDescriptorInfo {
|
||||
/**
|
||||
* The name of the buffer in ASCII. Useful for debugging/tracing.
|
||||
*/
|
||||
byte[128] name;
|
||||
|
||||
/**
|
||||
* The width specifies how many columns of pixels must be in the
|
||||
* allocated buffer, but does not necessarily represent the offset in
|
||||
* columns between the same column in adjacent rows. The rows may be
|
||||
* padded.
|
||||
*/
|
||||
int width;
|
||||
|
||||
/**
|
||||
* The height specifies how many rows of pixels must be in the
|
||||
* allocated buffer.
|
||||
*/
|
||||
int height;
|
||||
|
||||
/**
|
||||
* The number of image layers that must be in the allocated buffer.
|
||||
*/
|
||||
int layerCount;
|
||||
|
||||
/**
|
||||
* Buffer pixel format. See PixelFormat.aidl in graphics/common for
|
||||
* valid values
|
||||
*/
|
||||
PixelFormat format = PixelFormat.UNSPECIFIED;
|
||||
|
||||
/**
|
||||
* Buffer usage mask; valid flags can be found in the definition of
|
||||
* BufferUsage.aidl in graphics/common
|
||||
*/
|
||||
BufferUsage usage = BufferUsage.CPU_READ_NEVER;
|
||||
|
||||
/**
|
||||
* The size in bytes of the reserved region associated with the buffer.
|
||||
* See getReservedRegion for more information.
|
||||
*/
|
||||
long reservedSize;
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
package android.hardware.graphics.allocator;
|
||||
|
||||
import android.hardware.graphics.allocator.AllocationResult;
|
||||
import android.hardware.graphics.allocator.BufferDescriptorInfo;
|
||||
|
||||
@VintfStability
|
||||
interface IAllocator {
|
||||
|
@ -31,6 +32,43 @@ interface IAllocator {
|
|||
* @param count The number of buffers to allocate.
|
||||
* @return An AllocationResult containing the result of the allocation
|
||||
* @throws AllocationError on failure
|
||||
* @deprecated As of android.hardware.graphics.allocator-V2, this is deprecated & replaced with
|
||||
* allocate2
|
||||
*/
|
||||
AllocationResult allocate(in byte[] descriptor, in int count);
|
||||
|
||||
/**
|
||||
* Allocates buffers with the properties specified by the descriptor.
|
||||
*
|
||||
* Allocations should be optimized for usage bits provided in the
|
||||
* descriptor.
|
||||
*
|
||||
* @param descriptor Properties of the buffers to allocate. This must be
|
||||
* obtained from IMapper::createDescriptor().
|
||||
* @param count The number of buffers to allocate.
|
||||
* @return An AllocationResult containing the result of the allocation
|
||||
* @throws AllocationError on failure
|
||||
*/
|
||||
AllocationResult allocate2(in BufferDescriptorInfo descriptor, in int count);
|
||||
|
||||
/**
|
||||
* Test whether the given BufferDescriptorInfo is allocatable.
|
||||
*
|
||||
* If this function returns true, it means that a buffer with the given
|
||||
* description can be allocated on this implementation, unless resource
|
||||
* exhaustion occurs. If this function returns false, it means that the
|
||||
* allocation of the given description will never succeed.
|
||||
*
|
||||
* @param description the description of the buffer
|
||||
* @return supported whether the description is supported
|
||||
*/
|
||||
boolean isSupported(in BufferDescriptorInfo descriptor);
|
||||
|
||||
/**
|
||||
* Retrieve the library suffix to load for the IMapper SP-HAL. This library must implement the
|
||||
* IMapper stable-C interface (android/hardware/graphics/mapper/IMapper.h).
|
||||
*
|
||||
* The library that will attempt to be loaded is "/vendor/lib[64]/hw/mapper.<imapper_suffix>.so"
|
||||
*/
|
||||
String getIMapperLibrarySuffix();
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ cc_test {
|
|||
],
|
||||
header_libs: [
|
||||
"libhwui_internal_headers",
|
||||
"libimapper_stablec",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
|
|
|
@ -25,7 +25,10 @@
|
|||
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
|
||||
#include <aidlcommonsupport/NativeHandle.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/dlext.h>
|
||||
#include <android/hardware/graphics/mapper/4.0/IMapper.h>
|
||||
#include <android/hardware/graphics/mapper/IMapper.h>
|
||||
#include <dlfcn.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hidl/GtestPrinter.h>
|
||||
#include <hidl/ServiceManagement.h>
|
||||
|
@ -33,6 +36,7 @@
|
|||
#include <renderthread/EglManager.h>
|
||||
#include <utils/GLUtils.h>
|
||||
#include <vndk/hardware_buffer.h>
|
||||
#include <vndksupport/linker.h>
|
||||
#include <initializer_list>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
@ -42,60 +46,70 @@ using namespace aidl::android::hardware::graphics::allocator;
|
|||
using namespace aidl::android::hardware::graphics::common;
|
||||
using namespace android;
|
||||
using namespace android::hardware;
|
||||
using namespace android::hardware::graphics::mapper::V4_0;
|
||||
using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
|
||||
using Error = android::hardware::graphics::mapper::V4_0::Error;
|
||||
using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
|
||||
using android::uirenderer::AutoEglImage;
|
||||
using android::uirenderer::AutoGLFramebuffer;
|
||||
using android::uirenderer::AutoSkiaGlTexture;
|
||||
using android::uirenderer::renderthread::EglManager;
|
||||
|
||||
static constexpr uint64_t pack(const std::initializer_list<BufferUsage>& usages) {
|
||||
uint64_t ret = 0;
|
||||
for (const auto u : usages) {
|
||||
ret |= static_cast<uint64_t>(u);
|
||||
}
|
||||
return ret;
|
||||
typedef AIMapper_Error (*AIMapper_loadIMapperFn)(AIMapper* _Nullable* _Nonnull outImplementation);
|
||||
|
||||
inline BufferUsage operator|(BufferUsage lhs, BufferUsage rhs) {
|
||||
using T = std::underlying_type_t<BufferUsage>;
|
||||
return static_cast<BufferUsage>(static_cast<T>(lhs) | static_cast<T>(rhs));
|
||||
}
|
||||
|
||||
static constexpr hardware::graphics::common::V1_2::PixelFormat cast(PixelFormat format) {
|
||||
return static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
|
||||
inline BufferUsage& operator|=(BufferUsage& lhs, BufferUsage rhs) {
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
static IMapper4::BufferDescriptorInfo convert(const BufferDescriptorInfo& info) {
|
||||
return IMapper4::BufferDescriptorInfo{
|
||||
.name{reinterpret_cast<const char*>(info.name.data())},
|
||||
.width = static_cast<uint32_t>(info.width),
|
||||
.height = static_cast<uint32_t>(info.height),
|
||||
.layerCount = static_cast<uint32_t>(info.layerCount),
|
||||
.format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(info.format),
|
||||
.usage = static_cast<uint64_t>(info.usage),
|
||||
.reservedSize = 0,
|
||||
};
|
||||
}
|
||||
|
||||
class GraphicsTestsBase;
|
||||
|
||||
class BufferHandle {
|
||||
sp<IMapper> mMapper;
|
||||
GraphicsTestsBase& mTestBase;
|
||||
native_handle_t* mRawHandle;
|
||||
bool mImported = false;
|
||||
uint32_t mStride;
|
||||
const IMapper::BufferDescriptorInfo mInfo;
|
||||
const BufferDescriptorInfo mInfo;
|
||||
|
||||
BufferHandle(const BufferHandle&) = delete;
|
||||
void operator=(const BufferHandle&) = delete;
|
||||
|
||||
public:
|
||||
BufferHandle(const sp<IMapper> mapper, native_handle_t* handle, bool imported, uint32_t stride,
|
||||
const IMapper::BufferDescriptorInfo& info)
|
||||
: mMapper(mapper), mRawHandle(handle), mImported(imported), mStride(stride), mInfo(info) {}
|
||||
BufferHandle(GraphicsTestsBase& testBase, native_handle_t* handle, bool imported,
|
||||
uint32_t stride, const BufferDescriptorInfo& info)
|
||||
: mTestBase(testBase),
|
||||
mRawHandle(handle),
|
||||
mImported(imported),
|
||||
mStride(stride),
|
||||
mInfo(info) {}
|
||||
|
||||
~BufferHandle() {
|
||||
if (mRawHandle == nullptr) return;
|
||||
|
||||
if (mImported) {
|
||||
Error error = mMapper->freeBuffer(mRawHandle);
|
||||
EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
|
||||
} else {
|
||||
native_handle_close(mRawHandle);
|
||||
native_handle_delete(mRawHandle);
|
||||
}
|
||||
}
|
||||
~BufferHandle();
|
||||
|
||||
uint32_t stride() const { return mStride; }
|
||||
|
||||
AHardwareBuffer_Desc describe() const {
|
||||
return {
|
||||
.width = mInfo.width,
|
||||
.height = mInfo.height,
|
||||
.layers = mInfo.layerCount,
|
||||
.width = static_cast<uint32_t>(mInfo.width),
|
||||
.height = static_cast<uint32_t>(mInfo.height),
|
||||
.layers = static_cast<uint32_t>(mInfo.layerCount),
|
||||
.format = static_cast<uint32_t>(mInfo.format),
|
||||
.usage = mInfo.usage,
|
||||
.usage = static_cast<uint64_t>(mInfo.usage),
|
||||
.stride = stride(),
|
||||
.rfu0 = 0,
|
||||
.rfu1 = 0,
|
||||
|
@ -114,25 +128,43 @@ class BufferHandle {
|
|||
|
||||
class GraphicsTestsBase {
|
||||
private:
|
||||
friend class BufferHandle;
|
||||
int32_t mIAllocatorVersion = 1;
|
||||
std::shared_ptr<IAllocator> mAllocator;
|
||||
sp<IMapper> mMapper;
|
||||
sp<IMapper4> mMapper4;
|
||||
AIMapper* mAIMapper = nullptr;
|
||||
|
||||
protected:
|
||||
void Initialize(std::string allocatorService, std::string mapperService) {
|
||||
void Initialize(std::string allocatorService) {
|
||||
mAllocator = IAllocator::fromBinder(
|
||||
ndk::SpAIBinder(AServiceManager_checkService(allocatorService.c_str())));
|
||||
mMapper = IMapper::getService(mapperService);
|
||||
ASSERT_TRUE(mAllocator->getInterfaceVersion(&mIAllocatorVersion).isOk());
|
||||
if (mIAllocatorVersion >= 2) {
|
||||
std::string mapperSuffix;
|
||||
auto status = mAllocator->getIMapperLibrarySuffix(&mapperSuffix);
|
||||
ASSERT_TRUE(status.isOk());
|
||||
std::string lib_name = "mapper." + mapperSuffix + ".so";
|
||||
void* so = android_load_sphal_library(lib_name.c_str(), RTLD_LOCAL | RTLD_NOW);
|
||||
ASSERT_NE(nullptr, so) << "Failed to load " << lib_name;
|
||||
auto loadIMapper = (AIMapper_loadIMapperFn)dlsym(so, "AIMapper_loadIMapper");
|
||||
ASSERT_NE(nullptr, loadIMapper) << "AIMapper_locaIMapper missing from " << lib_name;
|
||||
ASSERT_EQ(AIMAPPER_ERROR_NONE, loadIMapper(&mAIMapper));
|
||||
ASSERT_NE(mAIMapper, nullptr);
|
||||
} else {
|
||||
// Don't have IMapper 5, fall back to IMapper 4
|
||||
mMapper4 = IMapper4::getService();
|
||||
ASSERT_NE(nullptr, mMapper4.get()) << "failed to get mapper service";
|
||||
ASSERT_FALSE(mMapper4->isRemote()) << "mapper is not in passthrough mode";
|
||||
}
|
||||
|
||||
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
|
||||
ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
|
||||
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
|
||||
}
|
||||
|
||||
public:
|
||||
BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
|
||||
private:
|
||||
BufferDescriptor createDescriptor(const BufferDescriptorInfo& descriptorInfo) {
|
||||
BufferDescriptor descriptor;
|
||||
mMapper->createDescriptor(
|
||||
descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
|
||||
mMapper4->createDescriptor(
|
||||
convert(descriptorInfo), [&](const auto& tmpError, const auto& tmpDescriptor) {
|
||||
ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
|
||||
descriptor = tmpDescriptor;
|
||||
});
|
||||
|
@ -140,14 +172,22 @@ class GraphicsTestsBase {
|
|||
return descriptor;
|
||||
}
|
||||
|
||||
std::unique_ptr<BufferHandle> allocate(const IMapper::BufferDescriptorInfo& descriptorInfo) {
|
||||
auto descriptor = createDescriptor(descriptorInfo);
|
||||
if (::testing::Test::HasFatalFailure()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
std::unique_ptr<BufferHandle> allocate(const BufferDescriptorInfo& descriptorInfo) {
|
||||
AllocationResult result;
|
||||
auto status = mAllocator->allocate(descriptor, 1, &result);
|
||||
::ndk::ScopedAStatus status;
|
||||
if (mIAllocatorVersion >= 2) {
|
||||
status = mAllocator->allocate2(descriptorInfo, 1, &result);
|
||||
} else {
|
||||
auto descriptor = createDescriptor(descriptorInfo);
|
||||
if (::testing::Test::HasFatalFailure()) {
|
||||
return nullptr;
|
||||
}
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
status = mAllocator->allocate(descriptor, 1, &result);
|
||||
#pragma clang diagnostic pop // deprecation
|
||||
}
|
||||
if (!status.isOk()) {
|
||||
status_t error = status.getExceptionCode();
|
||||
if (error == EX_SERVICE_SPECIFIC) {
|
||||
|
@ -158,28 +198,48 @@ class GraphicsTestsBase {
|
|||
}
|
||||
return nullptr;
|
||||
} else {
|
||||
return std::make_unique<BufferHandle>(mMapper, dupFromAidl(result.buffers[0]), false,
|
||||
return std::make_unique<BufferHandle>(*this, dupFromAidl(result.buffers[0]), false,
|
||||
result.stride, descriptorInfo);
|
||||
}
|
||||
}
|
||||
|
||||
bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
|
||||
bool isSupported(const BufferDescriptorInfo& descriptorInfo) {
|
||||
bool ret = false;
|
||||
EXPECT_TRUE(mMapper->isSupported(descriptorInfo,
|
||||
[&](auto error, bool supported) {
|
||||
ASSERT_EQ(Error::NONE, error);
|
||||
ret = supported;
|
||||
})
|
||||
.isOk());
|
||||
if (mIAllocatorVersion >= 2) {
|
||||
EXPECT_TRUE(mAllocator->isSupported(descriptorInfo, &ret).isOk());
|
||||
} else {
|
||||
EXPECT_TRUE(mMapper4->isSupported(convert(descriptorInfo),
|
||||
[&](auto error, bool supported) {
|
||||
ASSERT_EQ(Error::NONE, error);
|
||||
ret = supported;
|
||||
})
|
||||
.isOk());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class GraphicsAllocatorAidlTests
|
||||
: public GraphicsTestsBase,
|
||||
public ::testing::TestWithParam<std::tuple<std::string, std::string>> {
|
||||
BufferHandle::~BufferHandle() {
|
||||
if (mRawHandle == nullptr) return;
|
||||
|
||||
if (mImported) {
|
||||
if (mTestBase.mAIMapper) {
|
||||
AIMapper_Error error = mTestBase.mAIMapper->v5.freeBuffer(mRawHandle);
|
||||
EXPECT_EQ(AIMAPPER_ERROR_NONE, error);
|
||||
} else {
|
||||
Error error = mTestBase.mMapper4->freeBuffer(mRawHandle);
|
||||
EXPECT_EQ(Error::NONE, error) << "failed to free buffer " << mRawHandle;
|
||||
}
|
||||
} else {
|
||||
native_handle_close(mRawHandle);
|
||||
native_handle_delete(mRawHandle);
|
||||
}
|
||||
}
|
||||
|
||||
class GraphicsAllocatorAidlTests : public GraphicsTestsBase,
|
||||
public ::testing::TestWithParam<std::string> {
|
||||
public:
|
||||
void SetUp() override { Initialize(std::get<0>(GetParam()), std::get<1>(GetParam())); }
|
||||
void SetUp() override { Initialize(GetParam()); }
|
||||
|
||||
void TearDown() override {}
|
||||
};
|
||||
|
@ -191,22 +251,22 @@ struct FlushMethod {
|
|||
|
||||
class GraphicsFrontBufferTests
|
||||
: public GraphicsTestsBase,
|
||||
public ::testing::TestWithParam<std::tuple<std::string, std::string, FlushMethod>> {
|
||||
public ::testing::TestWithParam<std::tuple<std::string, FlushMethod>> {
|
||||
private:
|
||||
EglManager eglManager;
|
||||
std::function<void(EglManager&)> flush;
|
||||
|
||||
public:
|
||||
void SetUp() override {
|
||||
Initialize(std::get<0>(GetParam()), std::get<1>(GetParam()));
|
||||
flush = std::get<2>(GetParam()).func;
|
||||
Initialize(std::get<0>(GetParam()));
|
||||
flush = std::get<1>(GetParam()).func;
|
||||
eglManager.initialize();
|
||||
}
|
||||
|
||||
void TearDown() override { eglManager.destroy(); }
|
||||
|
||||
void fillWithGpu(AHardwareBuffer* buffer, float red, float green, float blue, float alpha) {
|
||||
const EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
|
||||
EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(buffer);
|
||||
AutoEglImage eglImage(eglManager.eglDisplay(), clientBuffer);
|
||||
AutoSkiaGlTexture glTexture;
|
||||
AutoGLFramebuffer glFbo;
|
||||
|
@ -235,26 +295,14 @@ class GraphicsFrontBufferTests
|
|||
}
|
||||
};
|
||||
|
||||
TEST_P(GraphicsAllocatorAidlTests, CreateDescriptorBasic) {
|
||||
ASSERT_NO_FATAL_FAILURE(createDescriptor({
|
||||
.name = "CPU_8888",
|
||||
.width = 64,
|
||||
.height = 64,
|
||||
.layerCount = 1,
|
||||
.format = cast(PixelFormat::RGBA_8888),
|
||||
.usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
|
||||
.reservedSize = 0,
|
||||
}));
|
||||
}
|
||||
|
||||
TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
|
||||
auto buffer = allocate({
|
||||
.name = "CPU_8888",
|
||||
.name = {"CPU_8888"},
|
||||
.width = 64,
|
||||
.height = 64,
|
||||
.layerCount = 1,
|
||||
.format = cast(PixelFormat::RGBA_8888),
|
||||
.usage = pack({BufferUsage::CPU_WRITE_OFTEN, BufferUsage::CPU_READ_OFTEN}),
|
||||
.format = PixelFormat::RGBA_8888,
|
||||
.usage = BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN,
|
||||
.reservedSize = 0,
|
||||
});
|
||||
ASSERT_NE(nullptr, buffer.get());
|
||||
|
@ -262,14 +310,14 @@ TEST_P(GraphicsAllocatorAidlTests, CanAllocate) {
|
|||
}
|
||||
|
||||
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
|
||||
IMapper::BufferDescriptorInfo info{
|
||||
.name = "CPU_8888",
|
||||
BufferDescriptorInfo info{
|
||||
.name = {"CPU_8888"},
|
||||
.width = 64,
|
||||
.height = 64,
|
||||
.layerCount = 1,
|
||||
.format = cast(PixelFormat::RGBA_8888),
|
||||
.usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::CPU_READ_OFTEN,
|
||||
BufferUsage::FRONT_BUFFER}),
|
||||
.format = PixelFormat::RGBA_8888,
|
||||
.usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::CPU_READ_OFTEN |
|
||||
BufferUsage::FRONT_BUFFER,
|
||||
.reservedSize = 0,
|
||||
};
|
||||
const bool supported = isSupported(info);
|
||||
|
@ -304,14 +352,14 @@ TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
|
|||
}
|
||||
|
||||
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
|
||||
IMapper::BufferDescriptorInfo info{
|
||||
.name = "CPU_8888",
|
||||
BufferDescriptorInfo info{
|
||||
.name = {"CPU_8888"},
|
||||
.width = 64,
|
||||
.height = 64,
|
||||
.layerCount = 1,
|
||||
.format = cast(PixelFormat::RGBA_8888),
|
||||
.usage = pack({BufferUsage::GPU_RENDER_TARGET, BufferUsage::GPU_TEXTURE,
|
||||
BufferUsage::FRONT_BUFFER}),
|
||||
.format = PixelFormat::RGBA_8888,
|
||||
.usage = BufferUsage::GPU_RENDER_TARGET | BufferUsage::GPU_TEXTURE |
|
||||
BufferUsage::FRONT_BUFFER,
|
||||
.reservedSize = 0,
|
||||
};
|
||||
const bool supported = isSupported(info);
|
||||
|
@ -344,11 +392,9 @@ TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToGpu) {
|
|||
}
|
||||
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsAllocatorAidlTests);
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
PerInstance, GraphicsAllocatorAidlTests,
|
||||
testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
|
||||
testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor))),
|
||||
PrintInstanceTupleNameToString<>);
|
||||
INSTANTIATE_TEST_CASE_P(PerInstance, GraphicsAllocatorAidlTests,
|
||||
testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
|
||||
PrintInstanceNameToString);
|
||||
|
||||
const auto FlushMethodsValues = testing::Values(
|
||||
FlushMethod{"glFinish", [](EglManager&) { glFinish(); }},
|
||||
|
@ -362,7 +408,7 @@ const auto FlushMethodsValues = testing::Values(
|
|||
}},
|
||||
FlushMethod{"eglClientWaitSync", [](EglManager& eglManager) {
|
||||
EGLDisplay display = eglManager.eglDisplay();
|
||||
EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
|
||||
EGLSyncKHR fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, nullptr);
|
||||
eglClientWaitSyncKHR(display, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
|
||||
EGL_FOREVER_KHR);
|
||||
eglDestroySyncKHR(display, fence);
|
||||
|
@ -371,9 +417,8 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsFrontBufferTests);
|
|||
INSTANTIATE_TEST_CASE_P(
|
||||
PerInstance, GraphicsFrontBufferTests,
|
||||
testing::Combine(testing::ValuesIn(getAidlHalInstanceNames(IAllocator::descriptor)),
|
||||
testing::ValuesIn(getAllHalInstanceNames(IMapper::descriptor)),
|
||||
FlushMethodsValues),
|
||||
[](auto info) -> std::string {
|
||||
std::string name = std::to_string(info.index) + "/" + std::get<2>(info.param).name;
|
||||
std::string name = std::to_string(info.index) + "/" + std::get<1>(info.param).name;
|
||||
return Sanitize(name);
|
||||
});
|
||||
});
|
104
graphics/mapper/stable-c/Android.bp
Normal file
104
graphics/mapper/stable-c/Android.bp
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "hardware_interfaces_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["hardware_interfaces_license"],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libimapper_stablec",
|
||||
export_include_dirs: ["include"],
|
||||
vendor_available: true,
|
||||
header_libs: [
|
||||
"libarect_headers",
|
||||
],
|
||||
export_header_lib_headers: [
|
||||
"libarect_headers",
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_headers {
|
||||
name: "libimapper_providerutils",
|
||||
vendor_available: true,
|
||||
export_include_dirs: ["implutils/include"],
|
||||
header_libs: [
|
||||
"libbase_headers",
|
||||
"libimapper_stablec",
|
||||
],
|
||||
export_header_lib_headers: [
|
||||
"libbase_headers",
|
||||
"libimapper_stablec",
|
||||
],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "libimapper_providerutils_tests",
|
||||
defaults: [
|
||||
"android.hardware.graphics.allocator-ndk_shared",
|
||||
"android.hardware.graphics.common-ndk_shared",
|
||||
],
|
||||
header_libs: [
|
||||
"libimapper_providerutils",
|
||||
],
|
||||
srcs: [
|
||||
"implutils/impltests.cpp",
|
||||
],
|
||||
visibility: [":__subpackages__"],
|
||||
cpp_std: "experimental",
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "VtsHalGraphicsMapperStableC_TargetTest",
|
||||
cpp_std: "experimental",
|
||||
defaults: [
|
||||
"VtsHalTargetTestDefaults",
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
"android.hardware.graphics.allocator-ndk_shared",
|
||||
"android.hardware.graphics.common-ndk_shared",
|
||||
],
|
||||
srcs: [
|
||||
"vts/VtsHalGraphicsMapperStableC_TargetTest.cpp",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"libbase",
|
||||
"libsync",
|
||||
"libvndksupport",
|
||||
],
|
||||
static_libs: [
|
||||
"libaidlcommonsupport",
|
||||
"libgralloctypes",
|
||||
"libgtest",
|
||||
],
|
||||
header_libs: [
|
||||
"libimapper_stablec",
|
||||
"libimapper_providerutils",
|
||||
],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Werror",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts",
|
||||
],
|
||||
}
|
314
graphics/mapper/stable-c/implutils/impltests.cpp
Normal file
314
graphics/mapper/stable-c/implutils/impltests.cpp
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
|
||||
#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
|
||||
#include <vector>
|
||||
|
||||
using namespace ::android::hardware::graphics::mapper;
|
||||
using namespace ::aidl::android::hardware::graphics::common;
|
||||
|
||||
// These tests are primarily interested in hitting all the different *types* that can be
|
||||
// serialized/deserialized than in exhaustively testing all the StandardMetadataTypes.
|
||||
// Exhaustive testing of the actual metadata types is relegated for IMapper's VTS suite
|
||||
// where meaning & correctness of values are more narrowly defined (eg, read-only values)
|
||||
|
||||
TEST(Metadata, setGetBufferId) {
|
||||
using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(12, 0);
|
||||
*reinterpret_cast<int64_t*>(buffer.data()) = 42;
|
||||
|
||||
EXPECT_EQ(8, BufferId::encode(18, buffer.data(), 0));
|
||||
EXPECT_EQ(42, *reinterpret_cast<int64_t*>(buffer.data()));
|
||||
EXPECT_EQ(8, BufferId::encode(18, buffer.data(), buffer.size()));
|
||||
EXPECT_EQ(18, *reinterpret_cast<int64_t*>(buffer.data()));
|
||||
EXPECT_FALSE(BufferId::decode(buffer.data(), 0));
|
||||
auto read = BufferId::decode(buffer.data(), buffer.size());
|
||||
EXPECT_TRUE(read.has_value());
|
||||
EXPECT_EQ(18, read.value_or(0));
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetDataspace) {
|
||||
using DataspaceValue = StandardMetadata<StandardMetadataType::DATASPACE>::value;
|
||||
using intType = std::underlying_type_t<Dataspace>;
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(12, 0);
|
||||
|
||||
EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), 0));
|
||||
EXPECT_EQ(0, *reinterpret_cast<intType*>(buffer.data()));
|
||||
EXPECT_EQ(4, DataspaceValue::encode(Dataspace::BT2020, buffer.data(), buffer.size()));
|
||||
EXPECT_EQ(static_cast<intType>(Dataspace::BT2020), *reinterpret_cast<intType*>(buffer.data()));
|
||||
EXPECT_FALSE(DataspaceValue::decode(buffer.data(), 0));
|
||||
auto read = DataspaceValue::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
EXPECT_EQ(Dataspace::BT2020, *read);
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetValidName) {
|
||||
using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(100, 'a');
|
||||
buffer[buffer.size() - 1] = '\0';
|
||||
|
||||
// len("Hello") + sizeof(int64)
|
||||
constexpr int expectedSize = 5 + sizeof(int64_t);
|
||||
EXPECT_EQ(expectedSize, NameValue::encode("Hello", buffer.data(), buffer.size()));
|
||||
EXPECT_EQ(5, *reinterpret_cast<int64_t*>(buffer.data()));
|
||||
// Verify didn't write past the end of the desired size
|
||||
EXPECT_EQ('a', buffer[expectedSize]);
|
||||
|
||||
auto readValue = NameValue::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(readValue.has_value());
|
||||
EXPECT_EQ(5, readValue->length());
|
||||
EXPECT_EQ("Hello", *readValue);
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetInvalidName) {
|
||||
using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
|
||||
|
||||
std::vector<char> buffer;
|
||||
buffer.resize(12, 'a');
|
||||
buffer[buffer.size() - 1] = '\0';
|
||||
|
||||
// len("This is a long string") + sizeof(int64)
|
||||
constexpr int expectedSize = 21 + sizeof(int64_t);
|
||||
EXPECT_EQ(expectedSize,
|
||||
NameValue::encode("This is a long string", buffer.data(), buffer.size()));
|
||||
EXPECT_EQ(21, *reinterpret_cast<int64_t*>(buffer.data()));
|
||||
// Verify didn't write the too-long string
|
||||
EXPECT_EQ('a', buffer[9]);
|
||||
EXPECT_EQ('\0', buffer[buffer.size() - 1]);
|
||||
|
||||
auto readValue = NameValue::decode(buffer.data(), buffer.size());
|
||||
EXPECT_FALSE(readValue.has_value());
|
||||
readValue = NameValue::decode(buffer.data(), 0);
|
||||
ASSERT_FALSE(readValue.has_value());
|
||||
}
|
||||
|
||||
TEST(Metadata, wouldOverflowName) {
|
||||
using NameValue = StandardMetadata<StandardMetadataType::NAME>::value;
|
||||
std::vector<char> buffer(100, 0);
|
||||
|
||||
// int_max + sizeof(int64) overflows int32
|
||||
std::string_view bad_string{"badbeef", std::numeric_limits<int32_t>::max()};
|
||||
EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
|
||||
NameValue::encode(bad_string, buffer.data(), buffer.size()));
|
||||
|
||||
// check barely overflows
|
||||
bad_string = std::string_view{"badbeef", std::numeric_limits<int32_t>::max() - 7};
|
||||
EXPECT_EQ(-AIMAPPER_ERROR_BAD_VALUE,
|
||||
NameValue::encode(bad_string, buffer.data(), buffer.size()));
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetCompression) {
|
||||
using CompressionValue = StandardMetadata<StandardMetadataType::COMPRESSION>::value;
|
||||
ExtendableType myCompression{"bestest_compression_ever", 42};
|
||||
std::vector<char> buffer(100, '\0');
|
||||
const int expectedSize = myCompression.name.length() + sizeof(int64_t) + sizeof(int64_t);
|
||||
EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), 0));
|
||||
EXPECT_EQ(0, buffer[0]);
|
||||
EXPECT_EQ(expectedSize, CompressionValue::encode(myCompression, buffer.data(), buffer.size()));
|
||||
EXPECT_EQ(myCompression.name.length(), *reinterpret_cast<int64_t*>(buffer.data()));
|
||||
EXPECT_FALSE(CompressionValue::decode(buffer.data(), 0).has_value());
|
||||
auto read = CompressionValue::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
EXPECT_EQ(myCompression, read.value());
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetPlaneLayout) {
|
||||
using PlaneLayoutValue = StandardMetadata<StandardMetadataType::PLANE_LAYOUTS>::value;
|
||||
PlaneLayout myPlaneLayout;
|
||||
myPlaneLayout.offsetInBytes = 10;
|
||||
myPlaneLayout.sampleIncrementInBits = 11;
|
||||
myPlaneLayout.strideInBytes = 12;
|
||||
myPlaneLayout.widthInSamples = 13;
|
||||
myPlaneLayout.heightInSamples = 14;
|
||||
myPlaneLayout.totalSizeInBytes = 15;
|
||||
myPlaneLayout.horizontalSubsampling = 16;
|
||||
myPlaneLayout.verticalSubsampling = 17;
|
||||
|
||||
myPlaneLayout.components.resize(3);
|
||||
for (int i = 0; i < myPlaneLayout.components.size(); i++) {
|
||||
auto& it = myPlaneLayout.components[i];
|
||||
it.type = ExtendableType{"Plane ID", 40 + i};
|
||||
it.offsetInBits = 20 + i;
|
||||
it.sizeInBits = 30 + i;
|
||||
}
|
||||
|
||||
std::vector<PlaneLayout> layouts{myPlaneLayout, PlaneLayout{}};
|
||||
|
||||
std::vector<char> buffer(5000, '\0');
|
||||
constexpr int componentSize = 8 + (4 * sizeof(int64_t));
|
||||
constexpr int firstLayoutSize = (8 + 1) * sizeof(int64_t) + (3 * componentSize);
|
||||
constexpr int secondLayoutSize = (8 + 1) * sizeof(int64_t);
|
||||
constexpr int expectedSize = firstLayoutSize + secondLayoutSize + sizeof(int64_t);
|
||||
EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), 0));
|
||||
EXPECT_EQ(0, buffer[0]);
|
||||
EXPECT_EQ(expectedSize, PlaneLayoutValue::encode(layouts, buffer.data(), buffer.size()));
|
||||
EXPECT_EQ(3, reinterpret_cast<int64_t*>(buffer.data())[1]);
|
||||
EXPECT_EQ(8, reinterpret_cast<int64_t*>(buffer.data())[2]);
|
||||
EXPECT_EQ(40, reinterpret_cast<int64_t*>(buffer.data())[4]);
|
||||
EXPECT_EQ(31, reinterpret_cast<int64_t*>(buffer.data())[11]);
|
||||
EXPECT_EQ(22, reinterpret_cast<int64_t*>(buffer.data())[15]);
|
||||
EXPECT_EQ(10, reinterpret_cast<int64_t*>(buffer.data())[17]);
|
||||
EXPECT_EQ(11, reinterpret_cast<int64_t*>(buffer.data())[18]);
|
||||
EXPECT_FALSE(PlaneLayoutValue::decode(buffer.data(), 0).has_value());
|
||||
auto read = PlaneLayoutValue::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
EXPECT_EQ(layouts, *read);
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetRects) {
|
||||
using RectsValue = StandardMetadata<StandardMetadataType::CROP>::value;
|
||||
std::vector<uint8_t> buffer(500, 0);
|
||||
std::vector<Rect> cropRects{2};
|
||||
cropRects[0] = Rect{10, 11, 12, 13};
|
||||
cropRects[1] = Rect{20, 21, 22, 23};
|
||||
|
||||
constexpr int expectedSize = sizeof(int64_t) + (8 * sizeof(int32_t));
|
||||
EXPECT_EQ(expectedSize, RectsValue::encode(cropRects, buffer.data(), buffer.size()));
|
||||
EXPECT_EQ(2, reinterpret_cast<int64_t*>(buffer.data())[0]);
|
||||
EXPECT_EQ(10, reinterpret_cast<int32_t*>(buffer.data())[2]);
|
||||
auto read = RectsValue::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
EXPECT_EQ(cropRects.size(), read->size());
|
||||
EXPECT_EQ(cropRects, *read);
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetSmpte2086) {
|
||||
using Smpte2086Value = StandardMetadata<StandardMetadataType::SMPTE2086>::value;
|
||||
Smpte2086 source;
|
||||
source.minLuminance = 12.335f;
|
||||
source.maxLuminance = 452.889f;
|
||||
source.whitePoint = XyColor{-6.f, -9.f};
|
||||
source.primaryRed = XyColor{.1f, .2f};
|
||||
source.primaryGreen = XyColor{.3f, .4f};
|
||||
source.primaryBlue = XyColor{.5f, .6f};
|
||||
|
||||
constexpr int expectedSize = 10 * sizeof(float);
|
||||
std::vector<uint8_t> buffer(500, 0);
|
||||
EXPECT_EQ(expectedSize, Smpte2086Value::encode(source, buffer.data(), buffer.size()));
|
||||
auto read = Smpte2086Value::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
ASSERT_TRUE(read->has_value());
|
||||
EXPECT_EQ(source, read->value());
|
||||
|
||||
// A valid encoding of a nullopt
|
||||
read = Smpte2086Value::decode(nullptr, 0);
|
||||
ASSERT_TRUE(read.has_value());
|
||||
EXPECT_FALSE(read->has_value());
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetCta861_3) {
|
||||
using Cta861_3Value = StandardMetadata<StandardMetadataType::CTA861_3>::value;
|
||||
Cta861_3 source;
|
||||
source.maxFrameAverageLightLevel = 244.55f;
|
||||
source.maxContentLightLevel = 202.202f;
|
||||
|
||||
constexpr int expectedSize = 2 * sizeof(float);
|
||||
std::vector<uint8_t> buffer(500, 0);
|
||||
EXPECT_EQ(expectedSize, Cta861_3Value::encode(source, buffer.data(), buffer.size()));
|
||||
auto read = Cta861_3Value::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
ASSERT_TRUE(read->has_value());
|
||||
EXPECT_EQ(source, read->value());
|
||||
|
||||
// A valid encoding of a nullopt
|
||||
read = Cta861_3Value::decode(nullptr, 0);
|
||||
ASSERT_TRUE(read.has_value());
|
||||
EXPECT_FALSE(read->has_value());
|
||||
}
|
||||
|
||||
TEST(Metadata, setGetSmpte2094_10) {
|
||||
using SMPTE2094_10Value = StandardMetadata<StandardMetadataType::SMPTE2094_10>::value;
|
||||
|
||||
std::vector<uint8_t> buffer(500, 0);
|
||||
EXPECT_EQ(0, SMPTE2094_10Value::encode(std::nullopt, buffer.data(), buffer.size()));
|
||||
auto read = SMPTE2094_10Value::decode(buffer.data(), 0);
|
||||
ASSERT_TRUE(read.has_value());
|
||||
EXPECT_FALSE(read->has_value());
|
||||
|
||||
const std::vector<uint8_t> emptyBuffer;
|
||||
EXPECT_EQ(sizeof(int64_t),
|
||||
SMPTE2094_10Value::encode(emptyBuffer, buffer.data(), buffer.size()));
|
||||
read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
ASSERT_TRUE(read->has_value());
|
||||
EXPECT_EQ(0, read->value().size());
|
||||
|
||||
const std::vector<uint8_t> simpleBuffer{0, 1, 2, 3, 4, 5};
|
||||
EXPECT_EQ(sizeof(int64_t) + 6,
|
||||
SMPTE2094_10Value::encode(simpleBuffer, buffer.data(), buffer.size()));
|
||||
read = SMPTE2094_10Value::decode(buffer.data(), buffer.size());
|
||||
ASSERT_TRUE(read.has_value());
|
||||
ASSERT_TRUE(read->has_value());
|
||||
EXPECT_EQ(6, read->value().size());
|
||||
EXPECT_EQ(simpleBuffer, read->value());
|
||||
}
|
||||
|
||||
TEST(MetadataProvider, bufferId) {
|
||||
using BufferId = StandardMetadata<StandardMetadataType::BUFFER_ID>::value;
|
||||
std::vector<uint8_t> buffer(500, 0);
|
||||
int result = provideStandardMetadata(StandardMetadataType::BUFFER_ID, buffer.data(),
|
||||
buffer.size(), []<StandardMetadataType T>(auto&& provide) {
|
||||
if constexpr (T == StandardMetadataType::BUFFER_ID) {
|
||||
return provide(42);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
EXPECT_EQ(8, result);
|
||||
auto read = BufferId::decode(buffer.data(), buffer.size());
|
||||
EXPECT_EQ(42, read.value_or(0));
|
||||
}
|
||||
|
||||
TEST(MetadataProvider, allJumpsWork) {
|
||||
const auto& values = ndk::internal::enum_values<StandardMetadataType>;
|
||||
auto get = [](StandardMetadataType type) -> int {
|
||||
return provideStandardMetadata(type, nullptr, 0, []<StandardMetadataType T>(auto&&) {
|
||||
return static_cast<int>(T) + 100;
|
||||
});
|
||||
};
|
||||
|
||||
for (auto& type : values) {
|
||||
const int expected = type == StandardMetadataType::INVALID ? -AIMAPPER_ERROR_UNSUPPORTED
|
||||
: static_cast<int>(type) + 100;
|
||||
EXPECT_EQ(expected, get(type));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MetadataProvider, invalid) {
|
||||
int result = provideStandardMetadata(StandardMetadataType::INVALID, nullptr, 0,
|
||||
[]<StandardMetadataType T>(auto&&) { return 10; });
|
||||
|
||||
EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result);
|
||||
}
|
||||
|
||||
TEST(MetadataProvider, outOfBounds) {
|
||||
int result = provideStandardMetadata(static_cast<StandardMetadataType>(-1), nullptr, 0,
|
||||
[]<StandardMetadataType T>(auto&&) { return 10; });
|
||||
EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result) << "-1 should have resulted in UNSUPPORTED";
|
||||
|
||||
result = provideStandardMetadata(static_cast<StandardMetadataType>(100), nullptr, 0,
|
||||
[]<StandardMetadataType T>(auto&&) { return 10; });
|
||||
EXPECT_EQ(-AIMAPPER_ERROR_UNSUPPORTED, result)
|
||||
<< "100 (out of range) should have resulted in UNSUPPORTED";
|
||||
}
|
|
@ -0,0 +1,576 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/android/hardware/graphics/common/BlendMode.h>
|
||||
#include <aidl/android/hardware/graphics/common/BufferUsage.h>
|
||||
#include <aidl/android/hardware/graphics/common/Cta861_3.h>
|
||||
#include <aidl/android/hardware/graphics/common/Dataspace.h>
|
||||
#include <aidl/android/hardware/graphics/common/ExtendableType.h>
|
||||
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
|
||||
#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
|
||||
#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
|
||||
#include <aidl/android/hardware/graphics/common/Rect.h>
|
||||
#include <aidl/android/hardware/graphics/common/Smpte2086.h>
|
||||
#include <aidl/android/hardware/graphics/common/StandardMetadataType.h>
|
||||
#include <aidl/android/hardware/graphics/common/XyColor.h>
|
||||
#include <android/hardware/graphics/mapper/IMapper.h>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace android::hardware::graphics::mapper {
|
||||
|
||||
using ::aidl::android::hardware::graphics::common::BlendMode;
|
||||
using ::aidl::android::hardware::graphics::common::BufferUsage;
|
||||
using ::aidl::android::hardware::graphics::common::Cta861_3;
|
||||
using ::aidl::android::hardware::graphics::common::Dataspace;
|
||||
using ::aidl::android::hardware::graphics::common::ExtendableType;
|
||||
using ::aidl::android::hardware::graphics::common::PixelFormat;
|
||||
using ::aidl::android::hardware::graphics::common::PlaneLayout;
|
||||
using ::aidl::android::hardware::graphics::common::PlaneLayoutComponent;
|
||||
using ::aidl::android::hardware::graphics::common::Rect;
|
||||
using ::aidl::android::hardware::graphics::common::Smpte2086;
|
||||
using ::aidl::android::hardware::graphics::common::StandardMetadataType;
|
||||
using ::aidl::android::hardware::graphics::common::XyColor;
|
||||
|
||||
class MetadataWriter {
|
||||
private:
|
||||
uint8_t* _Nonnull mDest;
|
||||
size_t mSizeRemaining = 0;
|
||||
int32_t mDesiredSize = 0;
|
||||
|
||||
void* _Nullable reserve(size_t sizeToWrite) {
|
||||
if (mDesiredSize < 0) {
|
||||
// Error state
|
||||
return nullptr;
|
||||
}
|
||||
if (__builtin_add_overflow(mDesiredSize, sizeToWrite, &mDesiredSize)) {
|
||||
// Overflowed, abort writing any further data
|
||||
mDesiredSize = -AIMAPPER_ERROR_BAD_VALUE;
|
||||
mSizeRemaining = 0;
|
||||
return nullptr;
|
||||
}
|
||||
if (sizeToWrite > mSizeRemaining) {
|
||||
mSizeRemaining = 0;
|
||||
return nullptr;
|
||||
} else {
|
||||
mSizeRemaining -= sizeToWrite;
|
||||
uint8_t* whereToWrite = mDest;
|
||||
mDest += sizeToWrite;
|
||||
return whereToWrite;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit MetadataWriter(void* _Nullable destBuffer, size_t destBufferSize)
|
||||
: mDest(reinterpret_cast<uint8_t*>(destBuffer)), mSizeRemaining(destBufferSize) {}
|
||||
|
||||
int32_t desiredSize() const { return mDesiredSize; }
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
MetadataWriter& write(T value) {
|
||||
auto sizeToWrite = sizeof(T);
|
||||
if (void* dest = reserve(sizeToWrite)) {
|
||||
memcpy(dest, &value, sizeToWrite);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataWriter& write(float value) {
|
||||
auto sizeToWrite = sizeof(float);
|
||||
if (void* dest = reserve(sizeToWrite)) {
|
||||
memcpy(dest, &value, sizeToWrite);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataWriter& write(const std::string_view& value) {
|
||||
auto sizeToWrite = value.length();
|
||||
write<int64_t>(sizeToWrite);
|
||||
if (void* dest = reserve(sizeToWrite)) {
|
||||
memcpy(dest, value.data(), sizeToWrite);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataWriter& write(const std::vector<uint8_t>& value) {
|
||||
auto sizeToWrite = value.size();
|
||||
write<int64_t>(sizeToWrite);
|
||||
if (void* dest = reserve(sizeToWrite)) {
|
||||
memcpy(dest, value.data(), sizeToWrite);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataWriter& write(const ExtendableType& value) {
|
||||
return write(value.name).write(value.value);
|
||||
}
|
||||
|
||||
MetadataWriter& write(const XyColor& value) { return write(value.x).write(value.y); }
|
||||
};
|
||||
|
||||
class MetadataReader {
|
||||
private:
|
||||
const uint8_t* _Nonnull mSrc;
|
||||
size_t mSizeRemaining = 0;
|
||||
bool mOk = true;
|
||||
|
||||
const void* _Nullable advance(size_t size) {
|
||||
if (mOk && mSizeRemaining >= size) {
|
||||
const void* buf = mSrc;
|
||||
mSrc += size;
|
||||
mSizeRemaining -= size;
|
||||
return buf;
|
||||
}
|
||||
mOk = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit MetadataReader(const void* _Nonnull metadata, size_t metadataSize)
|
||||
: mSrc(reinterpret_cast<const uint8_t*>(metadata)), mSizeRemaining(metadataSize) {}
|
||||
|
||||
[[nodiscard]] size_t remaining() const { return mSizeRemaining; }
|
||||
[[nodiscard]] bool ok() const { return mOk; }
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
MetadataReader& read(T& dest) {
|
||||
if (const void* src = advance(sizeof(T))) {
|
||||
memcpy(&dest, src, sizeof(T));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataReader& read(float& dest) {
|
||||
if (const void* src = advance(sizeof(float))) {
|
||||
memcpy(&dest, src, sizeof(float));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataReader& read(std::string& dest) {
|
||||
dest = readString();
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataReader& read(ExtendableType& dest) {
|
||||
dest.name = readString();
|
||||
read(dest.value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MetadataReader& read(XyColor& dest) {
|
||||
read(dest.x);
|
||||
read(dest.y);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
|
||||
[[nodiscard]] std::optional<T> readInt() {
|
||||
auto sizeToRead = sizeof(T);
|
||||
if (const void* src = advance(sizeof(T))) {
|
||||
T ret;
|
||||
memcpy(&ret, src, sizeToRead);
|
||||
return ret;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view readString() {
|
||||
auto lengthOpt = readInt<int64_t>();
|
||||
if (!lengthOpt) {
|
||||
return std::string_view{};
|
||||
}
|
||||
size_t length = lengthOpt.value();
|
||||
if (const void* src = advance(length)) {
|
||||
return std::string_view{reinterpret_cast<const char*>(src), length};
|
||||
}
|
||||
return std::string_view{};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<ExtendableType> readExtendable() {
|
||||
ExtendableType ret;
|
||||
ret.name = readString();
|
||||
auto value = readInt<int64_t>();
|
||||
if (value) {
|
||||
ret.value = value.value();
|
||||
return ret;
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<uint8_t> readBuffer() {
|
||||
std::vector<uint8_t> ret;
|
||||
size_t length = readInt<int64_t>().value_or(0);
|
||||
if (const void* src = advance(length)) {
|
||||
ret.resize(length);
|
||||
memcpy(ret.data(), src, length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, class Enable = void>
|
||||
struct MetadataValue {};
|
||||
|
||||
template <typename T>
|
||||
struct MetadataValue<T, std::enable_if_t<std::is_integral_v<T>>> {
|
||||
[[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) {
|
||||
return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
|
||||
size_t metadataSize) {
|
||||
return MetadataReader{metadata, metadataSize}.readInt<T>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct MetadataValue<T, std::enable_if_t<std::is_enum_v<T>>> {
|
||||
[[nodiscard]] static int32_t encode(T value, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) {
|
||||
return MetadataWriter{destBuffer, destBufferSize}
|
||||
.write(static_cast<std::underlying_type_t<T>>(value))
|
||||
.desiredSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::optional<T> decode(const void* _Nonnull metadata,
|
||||
size_t metadataSize) {
|
||||
std::underlying_type_t<T> temp;
|
||||
return MetadataReader{metadata, metadataSize}.read(temp).ok()
|
||||
? std::optional<T>(static_cast<T>(temp))
|
||||
: std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MetadataValue<std::string> {
|
||||
[[nodiscard]] static int32_t encode(const std::string_view& value, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) {
|
||||
return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::optional<std::string> decode(const void* _Nonnull metadata,
|
||||
size_t metadataSize) {
|
||||
auto reader = MetadataReader{metadata, metadataSize};
|
||||
auto result = reader.readString();
|
||||
return reader.ok() ? std::optional<std::string>{result} : std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MetadataValue<ExtendableType> {
|
||||
static_assert(sizeof(int64_t) == sizeof(ExtendableType::value));
|
||||
|
||||
[[nodiscard]] static int32_t encode(const ExtendableType& value, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) {
|
||||
return MetadataWriter{destBuffer, destBufferSize}.write(value).desiredSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] static std::optional<ExtendableType> decode(const void* _Nonnull metadata,
|
||||
size_t metadataSize) {
|
||||
return MetadataReader{metadata, metadataSize}.readExtendable();
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MetadataValue<std::vector<PlaneLayout>> {
|
||||
[[nodiscard]] static int32_t encode(const std::vector<PlaneLayout>& values,
|
||||
void* _Nullable destBuffer, size_t destBufferSize) {
|
||||
MetadataWriter writer{destBuffer, destBufferSize};
|
||||
writer.write<int64_t>(values.size());
|
||||
for (const auto& value : values) {
|
||||
writer.write<int64_t>(value.components.size());
|
||||
for (const auto& component : value.components) {
|
||||
writer.write(component.type)
|
||||
.write<int64_t>(component.offsetInBits)
|
||||
.write<int64_t>(component.sizeInBits);
|
||||
}
|
||||
writer.write<int64_t>(value.offsetInBytes)
|
||||
.write<int64_t>(value.sampleIncrementInBits)
|
||||
.write<int64_t>(value.strideInBytes)
|
||||
.write<int64_t>(value.widthInSamples)
|
||||
.write<int64_t>(value.heightInSamples)
|
||||
.write<int64_t>(value.totalSizeInBytes)
|
||||
.write<int64_t>(value.horizontalSubsampling)
|
||||
.write<int64_t>(value.verticalSubsampling);
|
||||
}
|
||||
return writer.desiredSize();
|
||||
}
|
||||
|
||||
using DecodeResult = std::optional<std::vector<PlaneLayout>>;
|
||||
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
|
||||
std::vector<PlaneLayout> values;
|
||||
MetadataReader reader{metadata, metadataSize};
|
||||
auto numPlanes = reader.readInt<int64_t>().value_or(0);
|
||||
values.reserve(numPlanes);
|
||||
for (int i = 0; i < numPlanes && reader.ok(); i++) {
|
||||
PlaneLayout& value = values.emplace_back();
|
||||
auto numPlaneComponents = reader.readInt<int64_t>().value_or(0);
|
||||
value.components.reserve(numPlaneComponents);
|
||||
for (int i = 0; i < numPlaneComponents && reader.ok(); i++) {
|
||||
PlaneLayoutComponent& component = value.components.emplace_back();
|
||||
reader.read(component.type)
|
||||
.read<int64_t>(component.offsetInBits)
|
||||
.read<int64_t>(component.sizeInBits);
|
||||
}
|
||||
reader.read<int64_t>(value.offsetInBytes)
|
||||
.read<int64_t>(value.sampleIncrementInBits)
|
||||
.read<int64_t>(value.strideInBytes)
|
||||
.read<int64_t>(value.widthInSamples)
|
||||
.read<int64_t>(value.heightInSamples)
|
||||
.read<int64_t>(value.totalSizeInBytes)
|
||||
.read<int64_t>(value.horizontalSubsampling)
|
||||
.read<int64_t>(value.verticalSubsampling);
|
||||
}
|
||||
return reader.ok() ? DecodeResult{std::move(values)} : std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MetadataValue<std::vector<Rect>> {
|
||||
[[nodiscard]] static int32_t encode(const std::vector<Rect>& value, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) {
|
||||
MetadataWriter writer{destBuffer, destBufferSize};
|
||||
writer.write<int64_t>(value.size());
|
||||
for (auto& rect : value) {
|
||||
writer.write<int32_t>(rect.left)
|
||||
.write<int32_t>(rect.top)
|
||||
.write<int32_t>(rect.right)
|
||||
.write<int32_t>(rect.bottom);
|
||||
}
|
||||
return writer.desiredSize();
|
||||
}
|
||||
|
||||
using DecodeResult = std::optional<std::vector<Rect>>;
|
||||
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
|
||||
MetadataReader reader{metadata, metadataSize};
|
||||
std::vector<Rect> value;
|
||||
auto numRects = reader.readInt<int64_t>().value_or(0);
|
||||
value.reserve(numRects);
|
||||
for (int i = 0; i < numRects && reader.ok(); i++) {
|
||||
Rect& rect = value.emplace_back();
|
||||
reader.read<int32_t>(rect.left)
|
||||
.read<int32_t>(rect.top)
|
||||
.read<int32_t>(rect.right)
|
||||
.read<int32_t>(rect.bottom);
|
||||
}
|
||||
return reader.ok() ? DecodeResult{std::move(value)} : std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MetadataValue<std::optional<Smpte2086>> {
|
||||
[[nodiscard]] static int32_t encode(const std::optional<Smpte2086>& optValue,
|
||||
void* _Nullable destBuffer, size_t destBufferSize) {
|
||||
if (optValue.has_value()) {
|
||||
const auto& value = *optValue;
|
||||
return MetadataWriter{destBuffer, destBufferSize}
|
||||
.write(value.primaryRed)
|
||||
.write(value.primaryGreen)
|
||||
.write(value.primaryBlue)
|
||||
.write(value.whitePoint)
|
||||
.write(value.maxLuminance)
|
||||
.write(value.minLuminance)
|
||||
.desiredSize();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Double optional because the value type itself is an optional<>
|
||||
using DecodeResult = std::optional<std::optional<Smpte2086>>;
|
||||
[[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
|
||||
std::optional<Smpte2086> optValue{std::nullopt};
|
||||
if (metadataSize > 0) {
|
||||
Smpte2086 value;
|
||||
MetadataReader reader{metadata, metadataSize};
|
||||
reader.read(value.primaryRed)
|
||||
.read(value.primaryGreen)
|
||||
.read(value.primaryBlue)
|
||||
.read(value.whitePoint)
|
||||
.read(value.maxLuminance)
|
||||
.read(value.minLuminance);
|
||||
if (reader.ok()) {
|
||||
optValue = std::move(value);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return DecodeResult{std::move(optValue)};
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MetadataValue<std::optional<Cta861_3>> {
|
||||
[[nodiscard]] static int32_t encode(const std::optional<Cta861_3>& optValue,
|
||||
void* _Nullable destBuffer, size_t destBufferSize) {
|
||||
if (optValue.has_value()) {
|
||||
const auto& value = *optValue;
|
||||
return MetadataWriter{destBuffer, destBufferSize}
|
||||
.write(value.maxContentLightLevel)
|
||||
.write(value.maxFrameAverageLightLevel)
|
||||
.desiredSize();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Double optional because the value type itself is an optional<>
|
||||
using DecodeResult = std::optional<std::optional<Cta861_3>>;
|
||||
[[nodiscard]] static DecodeResult decode(const void* _Nullable metadata, size_t metadataSize) {
|
||||
std::optional<Cta861_3> optValue{std::nullopt};
|
||||
if (metadataSize > 0) {
|
||||
MetadataReader reader{metadata, metadataSize};
|
||||
Cta861_3 value;
|
||||
reader.read(value.maxContentLightLevel).read(value.maxFrameAverageLightLevel);
|
||||
if (reader.ok()) {
|
||||
optValue = std::move(value);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return DecodeResult{std::move(optValue)};
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MetadataValue<std::optional<std::vector<uint8_t>>> {
|
||||
[[nodiscard]] static int32_t encode(const std::optional<std::vector<uint8_t>>& value,
|
||||
void* _Nullable destBuffer, size_t destBufferSize) {
|
||||
if (!value.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
return MetadataWriter{destBuffer, destBufferSize}.write(*value).desiredSize();
|
||||
}
|
||||
|
||||
using DecodeResult = std::optional<std::optional<std::vector<uint8_t>>>;
|
||||
[[nodiscard]] static DecodeResult decode(const void* _Nonnull metadata, size_t metadataSize) {
|
||||
std::optional<std::vector<uint8_t>> optValue;
|
||||
if (metadataSize > 0) {
|
||||
MetadataReader reader{metadata, metadataSize};
|
||||
auto value = reader.readBuffer();
|
||||
if (reader.ok()) {
|
||||
optValue = std::move(value);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
return DecodeResult{std::move(optValue)};
|
||||
}
|
||||
};
|
||||
|
||||
template <StandardMetadataType>
|
||||
struct StandardMetadata {};
|
||||
|
||||
#define DEFINE_TYPE(name, typeArg) \
|
||||
template <> \
|
||||
struct StandardMetadata<StandardMetadataType::name> { \
|
||||
using value_type = typeArg; \
|
||||
using value = MetadataValue<value_type>; \
|
||||
static_assert( \
|
||||
StandardMetadataType::name == \
|
||||
ndk::internal::enum_values<StandardMetadataType>[static_cast<size_t>( \
|
||||
StandardMetadataType::name)], \
|
||||
"StandardMetadataType must have equivalent value to index"); \
|
||||
}
|
||||
|
||||
DEFINE_TYPE(BUFFER_ID, uint64_t);
|
||||
DEFINE_TYPE(NAME, std::string);
|
||||
DEFINE_TYPE(WIDTH, uint64_t);
|
||||
DEFINE_TYPE(HEIGHT, uint64_t);
|
||||
DEFINE_TYPE(LAYER_COUNT, uint64_t);
|
||||
DEFINE_TYPE(PIXEL_FORMAT_REQUESTED, PixelFormat);
|
||||
DEFINE_TYPE(PIXEL_FORMAT_FOURCC, uint32_t);
|
||||
DEFINE_TYPE(PIXEL_FORMAT_MODIFIER, uint64_t);
|
||||
DEFINE_TYPE(USAGE, BufferUsage);
|
||||
DEFINE_TYPE(ALLOCATION_SIZE, uint64_t);
|
||||
DEFINE_TYPE(PROTECTED_CONTENT, uint64_t);
|
||||
DEFINE_TYPE(COMPRESSION, ExtendableType);
|
||||
DEFINE_TYPE(INTERLACED, ExtendableType);
|
||||
DEFINE_TYPE(CHROMA_SITING, ExtendableType);
|
||||
DEFINE_TYPE(PLANE_LAYOUTS, std::vector<PlaneLayout>);
|
||||
DEFINE_TYPE(CROP, std::vector<Rect>);
|
||||
DEFINE_TYPE(DATASPACE, Dataspace);
|
||||
DEFINE_TYPE(BLEND_MODE, BlendMode);
|
||||
DEFINE_TYPE(SMPTE2086, std::optional<Smpte2086>);
|
||||
DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
|
||||
DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
|
||||
DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
|
||||
|
||||
#undef DEFINE_TYPE
|
||||
|
||||
template <typename F, std::size_t... I>
|
||||
void invokeWithStandardMetadata(F&& f, StandardMetadataType type, std::index_sequence<I...>) {
|
||||
// Setup the jump table, mapping from each type to a springboard that invokes the template
|
||||
// function with the appropriate concrete type
|
||||
using F_PTR = decltype(&f);
|
||||
using THUNK = void (*)(F_PTR);
|
||||
static constexpr auto jump = std::array<THUNK, sizeof...(I)>{[](F_PTR fp) {
|
||||
constexpr StandardMetadataType type = ndk::internal::enum_values<StandardMetadataType>[I];
|
||||
if constexpr (type != StandardMetadataType::INVALID) {
|
||||
(*fp)(StandardMetadata<type>{});
|
||||
}
|
||||
}...};
|
||||
|
||||
auto index = static_cast<size_t>(type);
|
||||
if (index >= 0 && index < jump.size()) {
|
||||
jump[index](&f);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
|
||||
ndk::internal::enum_values<StandardMetadataType>.size()>>
|
||||
int32_t provideStandardMetadata(StandardMetadataType type, void* _Nullable destBuffer,
|
||||
size_t destBufferSize, F&& f) {
|
||||
int32_t retVal = -AIMAPPER_ERROR_UNSUPPORTED;
|
||||
invokeWithStandardMetadata(
|
||||
[&]<StandardMetadataType T>(StandardMetadata<T>) {
|
||||
retVal = f.template operator()<T>(
|
||||
[&](const typename StandardMetadata<T>::value_type& value) -> int32_t {
|
||||
return StandardMetadata<T>::value::encode(value, destBuffer,
|
||||
destBufferSize);
|
||||
});
|
||||
},
|
||||
type, StandardMetadataSequence{});
|
||||
return retVal;
|
||||
}
|
||||
|
||||
template <typename F, typename StandardMetadataSequence = std::make_index_sequence<
|
||||
ndk::internal::enum_values<StandardMetadataType>.size()>>
|
||||
AIMapper_Error applyStandardMetadata(StandardMetadataType type, const void* _Nonnull metadata,
|
||||
size_t metadataSize, F&& f) {
|
||||
AIMapper_Error retVal = AIMAPPER_ERROR_UNSUPPORTED;
|
||||
invokeWithStandardMetadata(
|
||||
[&]<StandardMetadataType T>(StandardMetadata<T>) {
|
||||
auto value = StandardMetadata<T>::value::decode(metadata, metadataSize);
|
||||
if (value.has_value()) {
|
||||
retVal = f.template operator()<T>(std::move(*value));
|
||||
} else {
|
||||
retVal = AIMAPPER_ERROR_BAD_VALUE;
|
||||
}
|
||||
},
|
||||
type, StandardMetadataSequence{});
|
||||
return retVal;
|
||||
}
|
||||
|
||||
} // namespace android::hardware::graphics::mapper
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <android/hardware/graphics/mapper/IMapper.h>
|
||||
#include <log/log.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
/**
|
||||
* Helper utilities for providing an IMapper-StableC implementation.
|
||||
*/
|
||||
|
||||
namespace vendor::mapper {
|
||||
|
||||
/**
|
||||
* Extend from this interface to provide Version 5 of the IMapper interface
|
||||
*/
|
||||
struct IMapperV5Impl {
|
||||
static const auto version = AIMAPPER_VERSION_5;
|
||||
virtual ~IMapperV5Impl() = default;
|
||||
|
||||
virtual AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
|
||||
buffer_handle_t _Nullable* _Nonnull outBufferHandle) = 0;
|
||||
|
||||
virtual AIMapper_Error freeBuffer(buffer_handle_t _Nonnull buffer) = 0;
|
||||
|
||||
virtual AIMapper_Error getTransportSize(buffer_handle_t _Nonnull buffer,
|
||||
uint32_t* _Nonnull outNumFds,
|
||||
uint32_t* _Nonnull outNumInts) = 0;
|
||||
|
||||
virtual AIMapper_Error lock(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
|
||||
ARect accessRegion, int acquireFence,
|
||||
void* _Nullable* _Nonnull outData) = 0;
|
||||
|
||||
virtual AIMapper_Error unlock(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence) = 0;
|
||||
|
||||
virtual AIMapper_Error flushLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
|
||||
|
||||
virtual AIMapper_Error rereadLockedBuffer(buffer_handle_t _Nonnull buffer) = 0;
|
||||
|
||||
virtual int32_t getMetadata(buffer_handle_t _Nonnull buffer, AIMapper_MetadataType metadataType,
|
||||
void* _Nullable destBuffer, size_t destBufferSize) = 0;
|
||||
|
||||
virtual int32_t getStandardMetadata(buffer_handle_t _Nonnull buffer,
|
||||
int64_t standardMetadataType, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) = 0;
|
||||
|
||||
virtual AIMapper_Error setMetadata(buffer_handle_t _Nonnull buffer,
|
||||
AIMapper_MetadataType metadataType,
|
||||
const void* _Nonnull metadata, size_t metadataSize) = 0;
|
||||
|
||||
virtual AIMapper_Error setStandardMetadata(buffer_handle_t _Nonnull buffer,
|
||||
int64_t standardMetadataType,
|
||||
const void* _Nonnull metadata,
|
||||
size_t metadataSize) = 0;
|
||||
|
||||
virtual AIMapper_Error listSupportedMetadataTypes(
|
||||
const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
|
||||
size_t* _Nonnull outNumberOfDescriptions) = 0;
|
||||
|
||||
virtual AIMapper_Error dumpBuffer(buffer_handle_t _Nonnull bufferHandle,
|
||||
AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
|
||||
void* _Null_unspecified context) = 0;
|
||||
|
||||
virtual AIMapper_Error dumpAllBuffers(
|
||||
AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
|
||||
AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
|
||||
void* _Null_unspecified context) = 0;
|
||||
|
||||
virtual AIMapper_Error getReservedRegion(buffer_handle_t _Nonnull buffer,
|
||||
void* _Nullable* _Nonnull outReservedRegion,
|
||||
uint64_t* _Nonnull outReservedSize) = 0;
|
||||
};
|
||||
|
||||
namespace provider {
|
||||
#ifndef __cpp_inline_variables
|
||||
#error "Only C++17 & newer is supported; inline variables is missing"
|
||||
#endif
|
||||
|
||||
inline void* _Nullable sIMapperInstance = nullptr;
|
||||
} // namespace provider
|
||||
|
||||
template <typename IMPL>
|
||||
class IMapperProvider {
|
||||
private:
|
||||
static_assert(IMPL::version >= AIMAPPER_VERSION_5, "Must be at least AIMAPPER_VERSION_5");
|
||||
static_assert(std::is_final_v<IMPL>, "Implementation must be final");
|
||||
static_assert(std::is_constructible_v<IMPL>, "Implementation must have a no-args constructor");
|
||||
|
||||
std::once_flag mLoadOnceFlag;
|
||||
std::optional<IMPL> mImpl;
|
||||
AIMapper mMapper = {};
|
||||
|
||||
static IMPL& impl() {
|
||||
return *reinterpret_cast<IMapperProvider<IMPL>*>(provider::sIMapperInstance)->mImpl;
|
||||
}
|
||||
|
||||
void bindV5() {
|
||||
mMapper.v5 = {
|
||||
.importBuffer = [](const native_handle_t* _Nonnull handle,
|
||||
buffer_handle_t _Nullable* _Nonnull outBufferHandle)
|
||||
-> AIMapper_Error { return impl().importBuffer(handle, outBufferHandle); },
|
||||
|
||||
.freeBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
|
||||
return impl().freeBuffer(buffer);
|
||||
},
|
||||
|
||||
.getTransportSize = [](buffer_handle_t _Nonnull buffer,
|
||||
uint32_t* _Nonnull outNumFds,
|
||||
uint32_t* _Nonnull outNumInts) -> AIMapper_Error {
|
||||
return impl().getTransportSize(buffer, outNumFds, outNumInts);
|
||||
},
|
||||
|
||||
.lock = [](buffer_handle_t _Nonnull buffer, uint64_t cpuUsage, ARect accessRegion,
|
||||
int acquireFence, void* _Nullable* _Nonnull outData) -> AIMapper_Error {
|
||||
return impl().lock(buffer, cpuUsage, accessRegion, acquireFence, outData);
|
||||
},
|
||||
|
||||
.unlock = [](buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence)
|
||||
-> AIMapper_Error { return impl().unlock(buffer, releaseFence); },
|
||||
|
||||
.flushLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
|
||||
return impl().flushLockedBuffer(buffer);
|
||||
},
|
||||
|
||||
.rereadLockedBuffer = [](buffer_handle_t _Nonnull buffer) -> AIMapper_Error {
|
||||
return impl().rereadLockedBuffer(buffer);
|
||||
},
|
||||
|
||||
.getMetadata = [](buffer_handle_t _Nonnull buffer,
|
||||
AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) -> int32_t {
|
||||
return impl().getMetadata(buffer, metadataType, destBuffer, destBufferSize);
|
||||
},
|
||||
|
||||
.getStandardMetadata = [](buffer_handle_t _Nonnull buffer,
|
||||
int64_t standardMetadataType, void* _Nullable destBuffer,
|
||||
size_t destBufferSize) -> int32_t {
|
||||
return impl().getStandardMetadata(buffer, standardMetadataType, destBuffer,
|
||||
destBufferSize);
|
||||
},
|
||||
|
||||
.setMetadata = [](buffer_handle_t _Nonnull buffer,
|
||||
AIMapper_MetadataType metadataType, const void* _Nonnull metadata,
|
||||
size_t metadataSize) -> AIMapper_Error {
|
||||
return impl().setMetadata(buffer, metadataType, metadata, metadataSize);
|
||||
},
|
||||
|
||||
.setStandardMetadata =
|
||||
[](buffer_handle_t _Nonnull buffer, int64_t standardMetadataType,
|
||||
const void* _Nonnull metadata, size_t metadataSize) -> AIMapper_Error {
|
||||
return impl().setStandardMetadata(buffer, standardMetadataType, metadata,
|
||||
metadataSize);
|
||||
},
|
||||
|
||||
.listSupportedMetadataTypes =
|
||||
[](const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
|
||||
size_t* _Nonnull outNumberOfDescriptions) -> AIMapper_Error {
|
||||
return impl().listSupportedMetadataTypes(outDescriptionList,
|
||||
outNumberOfDescriptions);
|
||||
},
|
||||
|
||||
.dumpBuffer = [](buffer_handle_t _Nonnull bufferHandle,
|
||||
AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
|
||||
void* _Null_unspecified context) -> AIMapper_Error {
|
||||
return impl().dumpBuffer(bufferHandle, dumpBufferCallback, context);
|
||||
},
|
||||
|
||||
.dumpAllBuffers =
|
||||
[](AIMapper_BeginDumpBufferCallback _Nonnull beginDumpBufferCallback,
|
||||
AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
|
||||
void* _Null_unspecified context) {
|
||||
return impl().dumpAllBuffers(beginDumpBufferCallback,
|
||||
dumpBufferCallback, context);
|
||||
},
|
||||
|
||||
.getReservedRegion = [](buffer_handle_t _Nonnull buffer,
|
||||
void* _Nullable* _Nonnull outReservedRegion,
|
||||
uint64_t* _Nonnull outReservedSize) -> AIMapper_Error {
|
||||
return impl().getReservedRegion(buffer, outReservedRegion, outReservedSize);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public:
|
||||
explicit IMapperProvider() = default;
|
||||
|
||||
AIMapper_Error load(AIMapper* _Nullable* _Nonnull outImplementation) {
|
||||
std::call_once(mLoadOnceFlag, [this] {
|
||||
LOG_ALWAYS_FATAL_IF(provider::sIMapperInstance != nullptr,
|
||||
"AIMapper implementation already loaded!");
|
||||
provider::sIMapperInstance = this;
|
||||
mImpl.emplace();
|
||||
mMapper.version = IMPL::version;
|
||||
if (IMPL::version >= AIMAPPER_VERSION_5) {
|
||||
bindV5();
|
||||
}
|
||||
});
|
||||
*outImplementation = &mMapper;
|
||||
return AIMAPPER_ERROR_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace vendor::mapper
|
|
@ -0,0 +1,689 @@
|
|||
/*
|
||||
* Copyright (C) 2022 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* IMapper Stable-C HAL interface
|
||||
*
|
||||
* This file represents the sphal interface between libui & the IMapper HAL implementation.
|
||||
* A vendor implementation of this interface is retrieved by looking up the vendor imapper
|
||||
* implementation library via the IAllocator AIDL interface.
|
||||
*
|
||||
* This interface is not intended for general use.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include <android/rect.h>
|
||||
#include <cutils/native_handle.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* AIMapper versioning
|
||||
*
|
||||
* IMapper versions 0-1 are pre-treble
|
||||
* IMapper versions 2-4 are HIDL
|
||||
* C-style AIMapper API starts at 5
|
||||
*/
|
||||
enum AIMapper_Version : uint32_t {
|
||||
AIMAPPER_VERSION_5 = 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible AIMapper errors
|
||||
* Values are the same as IMapper 4.0's Error type for simplicity
|
||||
*/
|
||||
enum AIMapper_Error : int32_t {
|
||||
/**
|
||||
* No error.
|
||||
*/
|
||||
AIMAPPER_ERROR_NONE = 0,
|
||||
/**
|
||||
* Invalid BufferDescriptor.
|
||||
*/
|
||||
AIMAPPER_ERROR_BAD_DESCRIPTOR = 1,
|
||||
/**
|
||||
* Invalid buffer handle.
|
||||
*/
|
||||
AIMAPPER_ERROR_BAD_BUFFER = 2,
|
||||
/**
|
||||
* Invalid HardwareBufferDescription.
|
||||
*/
|
||||
AIMAPPER_ERROR_BAD_VALUE = 3,
|
||||
/**
|
||||
* Resource unavailable.
|
||||
*/
|
||||
AIMAPPER_ERROR_NO_RESOURCES = 5,
|
||||
/**
|
||||
* Permanent failure.
|
||||
*/
|
||||
AIMAPPER_ERROR_UNSUPPORTED = 7,
|
||||
};
|
||||
|
||||
/**
|
||||
* MetadataType represents the different types of buffer metadata that could be
|
||||
* associated with a buffer. It is used by IMapper to help get and set buffer metadata
|
||||
* on the buffer's native handle.
|
||||
*
|
||||
* Standard buffer metadata will have the name field set to
|
||||
* "android.hardware.graphics.common.StandardMetadataType" and will contain values
|
||||
* from StandardMetadataType.aidl.
|
||||
*
|
||||
* Vendor-provided metadata should be prefixed with a "vendor.mycompanyname.*" namespace. It is
|
||||
* recommended that the metadata follows the pattern of StandardMetadaType.aidl. That is, an
|
||||
* aidl-defined enum with @VendorStability on it and the naming then matching that type such
|
||||
* as "vendor.mycompanyname.graphics.common.MetadataType" with the value field then set to the
|
||||
* aidl's enum value.
|
||||
*
|
||||
* Each company should create their own enum & namespace. The name
|
||||
* field prevents values from different companies from colliding.
|
||||
*/
|
||||
typedef struct AIMapper_MetadataType {
|
||||
const char* _Nonnull name;
|
||||
int64_t value;
|
||||
} AIMapper_MetadataType;
|
||||
|
||||
typedef struct AIMapper_MetadataTypeDescription {
|
||||
/**
|
||||
* The `name` of the metadataType must be valid for the lifetime of the process
|
||||
*/
|
||||
AIMapper_MetadataType metadataType;
|
||||
/**
|
||||
* description should contain a string representation of the MetadataType.
|
||||
*
|
||||
* For example: "MyExampleMetadataType is a 64-bit timestamp in nanoseconds
|
||||
* that indicates when a buffer is decoded. It is set by the media HAL after
|
||||
* a buffer is decoded. It is used by the display HAL for hardware
|
||||
* synchronization".
|
||||
*
|
||||
* This field is required for any non-StandardMetadataTypes. For StandardMetadataTypes this
|
||||
* field may be null. The lifetime of this pointer must be valid for the duration of the
|
||||
* process (that is, a static const char*).
|
||||
*/
|
||||
const char* _Nullable description;
|
||||
/**
|
||||
* isGettable represents if the MetadataType can be get.
|
||||
*/
|
||||
bool isGettable;
|
||||
/**
|
||||
* isSettable represents if the MetadataType can be set.
|
||||
*/
|
||||
bool isSettable;
|
||||
|
||||
/** Reserved for future use; must be zero-initialized currently */
|
||||
uint8_t reserved[32];
|
||||
} AIMapper_MetadataTypeDescription;
|
||||
|
||||
/**
|
||||
* Callback that is passed to dumpBuffer.
|
||||
*
|
||||
* @param context The caller-provided void* that was passed to dumpBuffer.
|
||||
* @param metadataType The type of the metadata passed to the callback
|
||||
* @param value A pointer to the value of the metadata. The lifetime of this pointer is only
|
||||
* valid for the duration of the call
|
||||
* @param valueSize The size of the value buffer.
|
||||
*/
|
||||
typedef void (*AIMapper_DumpBufferCallback)(void* _Null_unspecified context,
|
||||
AIMapper_MetadataType metadataType,
|
||||
const void* _Nonnull value, size_t valueSize);
|
||||
|
||||
/**
|
||||
* Callback that is passed to dumpAllBuffers.
|
||||
*
|
||||
* Indicates that a buffer is about to be dumped. Will be followed by N calls to
|
||||
* AIMapper_DumpBufferCallback for all the metadata for this buffer.
|
||||
*
|
||||
* @param context The caller-provided void* that was passed to dumpAllBuffers.
|
||||
*/
|
||||
typedef void (*AIMapper_BeginDumpBufferCallback)(void* _Null_unspecified context);
|
||||
|
||||
/**
|
||||
* Implementation of AIMAPPER_VERSION_5
|
||||
* All functions must not be null & must provide a valid implementation.
|
||||
*/
|
||||
typedef struct AIMapperV5 {
|
||||
/**
|
||||
* Imports a raw buffer handle to create an imported buffer handle for use
|
||||
* with the rest of the mapper or with other in-process libraries.
|
||||
*
|
||||
* A buffer handle is considered raw when it is cloned (e.g., with
|
||||
* `native_handle_clone()`) from another buffer handle locally, or when it
|
||||
* is received from another HAL server/client or another process. A raw
|
||||
* buffer handle must not be used to access the underlying graphic
|
||||
* buffer. It must be imported to create an imported handle first.
|
||||
*
|
||||
* This function must at least validate the raw handle before creating the
|
||||
* imported handle. It must also support importing the same raw handle
|
||||
* multiple times to create multiple imported handles. The imported handle
|
||||
* must be considered valid everywhere in the process, including in
|
||||
* another instance of the mapper.
|
||||
*
|
||||
* Because of passthrough HALs, a raw buffer handle received from a HAL
|
||||
* may actually have been imported in the process. importBuffer() must treat
|
||||
* such a handle as if it is raw and must not return `BAD_BUFFER`. The
|
||||
* returned handle is independent from the input handle as usual, and
|
||||
* freeBuffer() must be called on it when it is no longer needed.
|
||||
*
|
||||
* @param handle Raw buffer handle to import.
|
||||
* @param outBufferHandle The resulting imported buffer handle.
|
||||
* @return Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the raw handle is invalid.
|
||||
* - `NO_RESOURCES` if the raw handle cannot be imported due to
|
||||
* unavailability of resources.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull importBuffer)(const native_handle_t* _Nonnull handle,
|
||||
buffer_handle_t _Nullable* _Nonnull outBufferHandle);
|
||||
|
||||
/**
|
||||
* Frees a buffer handle. Buffer handles returned by importBuffer() must be
|
||||
* freed with this function when no longer needed.
|
||||
*
|
||||
* This function must free up all resources allocated by importBuffer() for
|
||||
* the imported handle. For example, if the imported handle was created
|
||||
* with `native_handle_create()`, this function must call
|
||||
* `native_handle_close()` and `native_handle_delete()`.
|
||||
*
|
||||
* @param buffer Imported buffer handle.
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the buffer is invalid.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull freeBuffer)(buffer_handle_t _Nonnull buffer);
|
||||
|
||||
/**
|
||||
* Calculates the transport size of a buffer. An imported buffer handle is a
|
||||
* raw buffer handle with the process-local runtime data appended. This
|
||||
* function, for example, allows a caller to omit the process-local runtime
|
||||
* data at the tail when serializing the imported buffer handle.
|
||||
*
|
||||
* Note that a client might or might not omit the process-local runtime data
|
||||
* when sending an imported buffer handle. The mapper must support both
|
||||
* cases on the receiving end.
|
||||
*
|
||||
* @param buffer Buffer to get the transport size from.
|
||||
* @param outNumFds The number of file descriptors needed for transport.
|
||||
* @param outNumInts The number of integers needed for transport.
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the buffer is invalid.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull getTransportSize)(buffer_handle_t _Nonnull buffer,
|
||||
uint32_t* _Nonnull outNumFds,
|
||||
uint32_t* _Nonnull outNumInts);
|
||||
|
||||
/**
|
||||
* Locks the given buffer for the specified CPU usage.
|
||||
*
|
||||
* Locking the same buffer simultaneously from multiple threads is
|
||||
* permitted, but if any of the threads attempt to lock the buffer for
|
||||
* writing, the behavior is undefined, except that it must not cause
|
||||
* process termination or block the client indefinitely. Leaving the
|
||||
* buffer content in an indeterminate state or returning an error are both
|
||||
* acceptable.
|
||||
*
|
||||
* 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
|
||||
* "lock in place". The buffers must be directly accessible via mapping.
|
||||
*
|
||||
* The client must not modify the content of the buffer outside of
|
||||
* @p accessRegion, and the device need not guarantee that content outside
|
||||
* of @p accessRegion is valid for reading. The result of reading or writing
|
||||
* outside of @p accessRegion is undefined, except that it must not cause
|
||||
* process termination.
|
||||
*
|
||||
* An accessRegion of all-zeros means the entire buffer. That is, it is
|
||||
* equivalent to '(0,0)-(buffer width, buffer height)'.
|
||||
*
|
||||
* This function can lock both single-planar and multi-planar formats. The caller
|
||||
* should use get() to get information about the buffer they are locking.
|
||||
* get() can be used to get information about the planes, offsets, stride,
|
||||
* etc.
|
||||
*
|
||||
* This function must also work on buffers with
|
||||
* `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
|
||||
* as with any other formats requested by multimedia codecs when they are
|
||||
* configured with a flexible-YUV-compatible color format.
|
||||
*
|
||||
* On success, @p data must be filled with a pointer to the locked buffer
|
||||
* memory. This address will represent the top-left corner of the entire
|
||||
* buffer, even if @p accessRegion does not begin at the top-left corner.
|
||||
*
|
||||
* The locked buffer must adhere to the format requested at allocation time
|
||||
* in the BufferDescriptorInfo.
|
||||
*
|
||||
* @param buffer Buffer to lock.
|
||||
* @param cpuUsage CPU usage flags to request. See BufferUsage.aidl for possible values.
|
||||
* @param accessRegion Portion of the buffer that the client intends to
|
||||
* access.
|
||||
* @param acquireFence Handle containing a file descriptor referring to a
|
||||
* sync fence object, which will be signaled when it is safe for the
|
||||
* mapper to lock the buffer. @p acquireFence may be an empty fence (-1) if
|
||||
* it is already safe to lock. Ownership is passed to the callee and it is the
|
||||
* implementations responsibility to ensure it is closed even when an error
|
||||
* occurs.
|
||||
* @param outData CPU-accessible pointer to the buffer data.
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
|
||||
* function.
|
||||
* - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
|
||||
* is incompatible with the buffer. Also if the @p accessRegion is
|
||||
* outside the bounds of the buffer or the accessRegion is invalid.
|
||||
* - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
|
||||
* that locking may succeed at a later time.
|
||||
* @return data CPU-accessible pointer to the buffer data.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull lock)(buffer_handle_t _Nonnull buffer, uint64_t cpuUsage,
|
||||
ARect accessRegion, int acquireFence,
|
||||
void* _Nullable* _Nonnull outData);
|
||||
|
||||
/**
|
||||
* Unlocks a buffer to indicate all CPU accesses to the buffer have
|
||||
* completed.
|
||||
*
|
||||
* @param buffer Buffer to unlock.
|
||||
* @param releaseFence Handle containing a file descriptor referring to a
|
||||
* sync fence object. The sync fence object will be signaled when the
|
||||
* mapper has completed any pending work. @p releaseFence may be an
|
||||
* empty fence (-1).
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the buffer is invalid or not locked.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull unlock)(buffer_handle_t _Nonnull buffer, int* _Nonnull releaseFence);
|
||||
|
||||
/**
|
||||
* Flushes the contents of a locked buffer.
|
||||
*
|
||||
* This function flushes the CPUs caches for the range of all the buffer's
|
||||
* planes and metadata. This should behave similarly to unlock() except the
|
||||
* buffer should remain mapped to the CPU.
|
||||
*
|
||||
* The client is still responsible for calling unlock() when it is done
|
||||
* with all CPU accesses to the buffer.
|
||||
*
|
||||
* If non-CPU blocks are simultaneously writing the buffer, the locked
|
||||
* copy should still be flushed but what happens is undefined except that
|
||||
* it should not cause any crashes.
|
||||
*
|
||||
* @param buffer Buffer to flush.
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the buffer is invalid or not locked.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull flushLockedBuffer)(buffer_handle_t _Nonnull buffer);
|
||||
|
||||
/**
|
||||
* Rereads the contents of a locked buffer.
|
||||
*
|
||||
* This should fetch the most recent copy of the locked buffer.
|
||||
*
|
||||
* It may reread locked copies of the buffer in other processes.
|
||||
*
|
||||
* The client is still responsible for calling unlock() when it is done
|
||||
* with all CPU accesses to the buffer.
|
||||
*
|
||||
* @param buffer Buffer to reread.
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the buffer is invalid or not locked.
|
||||
* - `NO_RESOURCES` if the buffer cannot be reread at this time. Note
|
||||
* that rereading may succeed at a later time.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull rereadLockedBuffer)(buffer_handle_t _Nonnull buffer);
|
||||
|
||||
/**
|
||||
* Description for get(...), set(...) and getFromBufferDescriptorInfo(...)
|
||||
*
|
||||
* ------------ Overview -----------------------------------
|
||||
* Gralloc 4 adds support for getting and setting buffer metadata on a buffer.
|
||||
*
|
||||
* To get buffer metadata, the client passes in a buffer handle and a token that
|
||||
* represents the type of buffer metadata they would like to get. IMapper returns
|
||||
* a byte stream that contains the buffer metadata. To set the buffer metadata, the
|
||||
* client passes in a buffer handle and a token that represents the type of buffer
|
||||
* metadata they would like to set and a byte stream that contains the buffer metadata
|
||||
* they are setting.
|
||||
*
|
||||
* Buffer metadata is global for a buffer. When the metadata is set on the buffer
|
||||
* in a process, the updated metadata should be available to all other processes.
|
||||
* Please see "Storing and Propagating Metadata" below for more details.
|
||||
*
|
||||
* The getter and setter functions have been optimized for easy vendor extension.
|
||||
* They do not require a formal extension to add support for getting and setting
|
||||
* vendor defined buffer metadata. See "Buffer Metadata Token" and
|
||||
* "Buffer Metadata Stream" below for more details.
|
||||
*
|
||||
* ------------ Storing and Propagating Metadata -----------
|
||||
* Buffer metadata must be global. Any changes to the metadata must be propagated
|
||||
* to all other processes immediately. Vendors may chose how they would like support
|
||||
* this functionality.
|
||||
*
|
||||
* We recommend supporting this functionality by allocating an extra page of shared
|
||||
* memory and storing it in the buffer's native_handle_t. The buffer metadata can
|
||||
* be stored in the extra page of shared memory. Set operations are automatically
|
||||
* propagated to all other processes.
|
||||
*
|
||||
* ------------ Buffer Metadata Synchronization ------------
|
||||
* There are no explicit buffer metadata synchronization primitives. Many devices
|
||||
* before gralloc 4 already support getting and setting of global buffer metadata
|
||||
* with no explicit synchronization primitives. Adding synchronization primitives
|
||||
* would just add unnecessary complexity.
|
||||
*
|
||||
* The general rule is if a process has permission to write to a buffer, they
|
||||
* have permission to write to the buffer's writable metadata. If a process has permission
|
||||
* to read from a buffer, they have permission to read the buffer's metadata.
|
||||
*
|
||||
* There is one exception to this rule. Fences CANNOT be used to protect a buffer's
|
||||
* metadata. A process should finish writing to a buffer's metadata before
|
||||
* sending the buffer to another process that will read or write to the buffer.
|
||||
* This exception is needed because sometimes userspace needs to read the
|
||||
* buffer's metadata before the buffer's contents are ready.
|
||||
*
|
||||
* As a simple example: an app renders to a buffer and then displays the buffer.
|
||||
* In this example when the app renders to the buffer, both the buffer and its
|
||||
* metadata need to be updated. The app's process queues up its work on the GPU
|
||||
* and gets back an acquire fence. The app's process must update the buffer's
|
||||
* metadata before enqueuing the buffer to SurfaceFlinger. The app process CANNOT
|
||||
* update the buffer's metadata after enqueuing the buffer. When HardwareComposer
|
||||
* receives the buffer, it is immediately safe to read the buffer's metadata
|
||||
* and use it to program the display driver. To read the buffer's contents,
|
||||
* display driver must still wait on the acquire fence.
|
||||
*
|
||||
* ------------ Buffer Metadata Token ----------------------
|
||||
* In order to allow arbitrary vendor defined metadata, the token used to access
|
||||
* metadata is defined defined as a struct that has a string representing
|
||||
* the enum type and an int that represents the enum value. The string protects
|
||||
* different enum values from colliding.
|
||||
*
|
||||
* The token struct (MetadataType) is defined as a C struct since it
|
||||
* is passed into a C function. The standard buffer metadata types are NOT
|
||||
* defined as a C enum but instead as an AIDL enum to allow for broader usage across
|
||||
* other HALs and libraries. By putting the enum in the
|
||||
* stable AIDL (hardware/interfaces/graphics/common/aidl/android/hardware/
|
||||
* graphics/common/StandardMetadataType.aidl), vendors will be able to optionally
|
||||
* choose to support future standard buffer metadata types without upgrading
|
||||
* IMapper versions. For more information see the description of "struct MetadataType".
|
||||
*
|
||||
* ------------ Buffer Metadata Stream ---------------------
|
||||
* The buffer metadata is get and set as a void* buffer. By getting
|
||||
* and setting buffer metadata as a generic buffer, vendors can use the standard
|
||||
* getters and setter functions defined here. Vendors do NOT need to add their own
|
||||
* getters and setter functions for each new type of buffer metadata.
|
||||
*
|
||||
* Converting buffer metadata into a byte stream can be non-trivial. For the standard
|
||||
* buffer metadata types defined in StandardMetadataType.aidl, there are also
|
||||
* support functions that will encode the buffer metadata into a byte stream
|
||||
* and decode the buffer metadata from a byte stream. We STRONGLY recommend using
|
||||
* these support functions. The framework will use them when getting and setting
|
||||
* metadata. The support functions are defined in
|
||||
* frameworks/native/libs/gralloc/types/include/gralloctypes/Gralloc4.h.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the buffer metadata for a given MetadataType.
|
||||
*
|
||||
* Buffer metadata can be changed after allocation so clients should avoid "caching"
|
||||
* the buffer metadata. For example, if the video resolution changes and the buffers
|
||||
* are not reallocated, several buffer metadata values may change without warning.
|
||||
* Clients should not expect the values to be constant. They should requery them every
|
||||
* frame. The only exception is buffer metadata that is determined at allocation
|
||||
* time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
|
||||
* HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
|
||||
* they are determined at allocation time.
|
||||
*
|
||||
* @param buffer Buffer containing desired metadata
|
||||
* @param metadataType MetadataType for the metadata value being queried
|
||||
* @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
|
||||
* null, the computed output size or error must still be returned.
|
||||
* @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
|
||||
* 0.
|
||||
* @return The number of bytes written to `destBuffer` or which would have been written
|
||||
* if `destBufferSize` was large enough.
|
||||
* A negative value indicates an error, which may be
|
||||
* - `BAD_BUFFER` if the raw handle is invalid.
|
||||
* - `UNSUPPORTED` when metadataType is unknown/unsupported.
|
||||
* IMapper must support getting all StandardMetadataType.aidl values defined
|
||||
* at the time the device first launches.
|
||||
*/
|
||||
int32_t (*_Nonnull getMetadata)(buffer_handle_t _Nonnull buffer,
|
||||
AIMapper_MetadataType metadataType, void* _Nullable destBuffer,
|
||||
size_t destBufferSize);
|
||||
|
||||
/**
|
||||
* Gets the buffer metadata for a StandardMetadataType.
|
||||
*
|
||||
* This is equivalent to `getMetadata` when passed an AIMapper_MetadataType with name
|
||||
* set to "android.hardware.graphics.common.StandardMetadataType"
|
||||
*
|
||||
* Buffer metadata can be changed after allocation so clients should avoid "caching"
|
||||
* the buffer metadata. For example, if the video resolution changes and the buffers
|
||||
* are not reallocated, several buffer metadata values may change without warning.
|
||||
* Clients should not expect the values to be constant. They should requery them every
|
||||
* frame. The only exception is buffer metadata that is determined at allocation
|
||||
* time. For StandardMetadataType values, only BUFFER_ID, NAME, WIDTH,
|
||||
* HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and USAGE are safe to cache because
|
||||
* they are determined at allocation time.
|
||||
*
|
||||
* @param buffer Buffer containing desired metadata
|
||||
* @param standardMetadataType StandardMetadataType for the metadata value being queried
|
||||
* @param destBuffer Pointer to a buffer in which to store the result of the get() call; if
|
||||
* null, the computed output size or error must still be returned.
|
||||
* @param destBufferSize How large the destBuffer buffer is. If destBuffer is null this must be
|
||||
* 0.
|
||||
* @return The number of bytes written to `destBuffer` or which would have been written
|
||||
* if `destBufferSize` was large enough.
|
||||
* A negative value indicates an error, which may be
|
||||
* - `BAD_BUFFER` if the raw handle is invalid.
|
||||
* - `UNSUPPORTED` when metadataType is unknown/unsupported.
|
||||
* IMapper must support getting all StandardMetadataType.aidl values defined
|
||||
* at the time the device first launches.
|
||||
*/
|
||||
int32_t (*_Nonnull getStandardMetadata)(buffer_handle_t _Nonnull buffer,
|
||||
int64_t standardMetadataType,
|
||||
void* _Nullable destBuffer, size_t destBufferSize);
|
||||
|
||||
/**
|
||||
* Sets the global value for a given MetadataType.
|
||||
*
|
||||
* Metadata fields are not required to be settable. This function can
|
||||
* return Error::UNSUPPORTED whenever it doesn't support setting a
|
||||
* particular Metadata field.
|
||||
*
|
||||
* The framework will attempt to set the following StandardMetadataType
|
||||
* values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
|
||||
* We require everyone to support setting those fields. If a device's Composer
|
||||
* implementation supports a field, it should be supported here. Over time these
|
||||
* metadata fields will be moved out of Composer/BufferQueue/etc. and into the
|
||||
* buffer's Metadata fields.
|
||||
*
|
||||
* @param buffer Buffer receiving desired metadata
|
||||
* @param metadataType MetadataType for the metadata value being set
|
||||
* @param metadata Pointer to a buffer of bytes representing the value associated with
|
||||
* @param metadataSize The size of the metadata buffer
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the raw handle is invalid.
|
||||
* - `BAD_VALUE` when the field is constant and can never be set (such as
|
||||
* BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
|
||||
* USAGE)
|
||||
* - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
|
||||
* resources.
|
||||
* - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
|
||||
* it is unsupported. Unsupported should also be returned if the metadata
|
||||
* is malformed.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull setMetadata)(buffer_handle_t _Nonnull buffer,
|
||||
AIMapper_MetadataType metadataType,
|
||||
const void* _Nonnull metadata, size_t metadataSize);
|
||||
|
||||
/**
|
||||
* Sets the global value for a given MetadataType.
|
||||
*
|
||||
* This is equivalent to `setMetadata` when passed an AIMapper_MetadataType with name
|
||||
* set to "android.hardware.graphics.common.StandardMetadataType"
|
||||
*
|
||||
* Metadata fields are not required to be settable. This function can
|
||||
* return Error::UNSUPPORTED whenever it doesn't support setting a
|
||||
* particular Metadata field.
|
||||
*
|
||||
* The framework will attempt to set the following StandardMetadataType
|
||||
* values: DATASPACE, SMPTE2086, CTA861_3, SMPTE2094_40 and BLEND_MODE.
|
||||
* We require everyone to support setting those fields. If a device's Composer
|
||||
* implementation supports a field, it should be supported here. Over time these
|
||||
* metadata fields will be moved out of Composer/BufferQueue/etc. and into the
|
||||
* buffer's Metadata fields.
|
||||
*
|
||||
* @param buffer Buffer receiving desired metadata
|
||||
* @param standardMetadataType StandardMetadataType for the metadata value being set
|
||||
* @param metadata Pointer to a buffer of bytes representing the value associated with
|
||||
* @param metadataSize The size of the metadata buffer
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the raw handle is invalid.
|
||||
* - `BAD_VALUE` when the field is constant and can never be set (such as
|
||||
* BUFFER_ID, NAME, WIDTH, HEIGHT, LAYER_COUNT, PIXEL_FORMAT_REQUESTED and
|
||||
* USAGE)
|
||||
* - `NO_RESOURCES` if the set cannot be fulfilled due to unavailability of
|
||||
* resources.
|
||||
* - `UNSUPPORTED` when metadataType is unknown/unsupported or setting
|
||||
* it is unsupported. Unsupported should also be returned if the metadata
|
||||
* is malformed.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull setStandardMetadata)(buffer_handle_t _Nonnull buffer,
|
||||
int64_t standardMetadataType,
|
||||
const void* _Nonnull metadata,
|
||||
size_t metadataSize);
|
||||
|
||||
/**
|
||||
* Lists all the MetadataTypes supported by IMapper as well as a description
|
||||
* of each supported MetadataType. For StandardMetadataTypes, the description
|
||||
* string can be left empty.
|
||||
*
|
||||
* This list is expected to be static & thus the returned array must be valid for the
|
||||
* lifetime of the process.
|
||||
*
|
||||
* @param outDescriptionList The list of descriptions
|
||||
* @param outNumberOfDescriptions How many descriptions are in `outDescriptionList`
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `UNSUPPORTED` if there's any error
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull listSupportedMetadataTypes)(
|
||||
const AIMapper_MetadataTypeDescription* _Nullable* _Nonnull outDescriptionList,
|
||||
size_t* _Nonnull outNumberOfDescriptions);
|
||||
|
||||
/**
|
||||
* Dumps a buffer's metadata.
|
||||
*
|
||||
* @param buffer The buffer to dump the metadata for
|
||||
* @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
|
||||
* @param context A caller-provided context to be passed to the dumpBufferCallback
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the raw handle is invalid.
|
||||
* - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
|
||||
* resources.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull dumpBuffer)(buffer_handle_t _Nonnull buffer,
|
||||
AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
|
||||
void* _Null_unspecified context);
|
||||
|
||||
/**
|
||||
* Dump the metadata for all imported buffers in the current process
|
||||
*
|
||||
* The HAL implementation should invoke beginDumpCallback before dumping a buffer's metadata,
|
||||
* followed by N calls to dumpBufferCallback for that buffer's metadata fields. The call
|
||||
* sequence should follow this pseudocode:
|
||||
*
|
||||
* for (auto buffer : gListOfImportedBuffers) {
|
||||
* beginDumpCallback(context);
|
||||
* for (auto metadata : buffer->allMetadata()) {
|
||||
* dumpBufferCallback(context, metadata...);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @param beginDumpCallback Signals that a buffer is about to be dumped
|
||||
* @param dumpBufferCallback Callback that will be invoked for each of the metadata fields
|
||||
* @param context A caller-provided context to be passed to beginDumpCallback and
|
||||
* dumpBufferCallback
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the raw handle is invalid.
|
||||
* - `NO_RESOURCES` if the get cannot be fulfilled due to unavailability of
|
||||
* resources.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull dumpAllBuffers)(
|
||||
AIMapper_BeginDumpBufferCallback _Nonnull beginDumpCallback,
|
||||
AIMapper_DumpBufferCallback _Nonnull dumpBufferCallback,
|
||||
void* _Null_unspecified context);
|
||||
|
||||
/**
|
||||
* Returns the region of shared memory associated with the buffer that is
|
||||
* reserved for client use.
|
||||
*
|
||||
* The shared memory may be allocated from any shared memory allocator.
|
||||
* The shared memory must be CPU-accessible and virtually contiguous. The
|
||||
* starting address must be word-aligned.
|
||||
*
|
||||
* This function may only be called after importBuffer() has been called by the
|
||||
* client. The reserved region must remain accessible until freeBuffer() has
|
||||
* been called. After freeBuffer() has been called, the client must not access
|
||||
* the reserved region.
|
||||
*
|
||||
* This reserved memory may be used in future versions of Android to
|
||||
* help clients implement backwards compatible features without requiring
|
||||
* IAllocator/IMapper updates.
|
||||
*
|
||||
* @param buffer Imported buffer handle.
|
||||
* @param outReservedRegion CPU-accessible pointer to the reserved region
|
||||
* @param outReservedSize the size of the reservedRegion that was requested
|
||||
* in the BufferDescriptorInfo.
|
||||
* @return error Error status of the call, which may be
|
||||
* - `NONE` upon success.
|
||||
* - `BAD_BUFFER` if the buffer is invalid.
|
||||
*/
|
||||
AIMapper_Error (*_Nonnull getReservedRegion)(buffer_handle_t _Nonnull buffer,
|
||||
void* _Nullable* _Nonnull outReservedRegion,
|
||||
uint64_t* _Nonnull outReservedSize);
|
||||
|
||||
} AIMapperV5;
|
||||
|
||||
/**
|
||||
* Return value for AIMapper_loadIMapper
|
||||
*
|
||||
* Note: This struct's size is not fixed and callers must never store it by-value as a result.
|
||||
* Only fields up to those covered by `version` are allowed to be accessed.
|
||||
*/
|
||||
typedef struct AIMapper {
|
||||
alignas(alignof(max_align_t)) AIMapper_Version version;
|
||||
AIMapperV5 v5;
|
||||
} AIMapper;
|
||||
|
||||
/**
|
||||
* Loads the vendor-provided implementation of AIMapper
|
||||
* @return Error status of the call.
|
||||
* - `NONE` upon success
|
||||
* - `UNSUPPORTED` if no implementation is available
|
||||
*/
|
||||
AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation);
|
||||
|
||||
__END_DECLS
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue