Add generic layer metadata to Composer 2.4
Bug: 139747351 Test: VtsHalGraphicsComposerV2_4TargetTest Test: Manual verification with a modified Composer implementation Change-Id: I800841ab1348a93c73c25c5f8bcf2254d9dc22e8
This commit is contained in:
parent
fdb6b518e9
commit
a4bea0eac9
9 changed files with 242 additions and 0 deletions
|
@ -71,6 +71,51 @@ interface IComposerClient extends @2.3::IComposerClient {
|
|||
* setClientTargetProperty(ClientTargetProperty clientTargetProperty);
|
||||
*/
|
||||
SET_CLIENT_TARGET_PROPERTY = 0x105 << @2.1::IComposerClient.Command:OPCODE_SHIFT,
|
||||
|
||||
/**
|
||||
* SET_LAYER_GENERIC_METADATA has this pseudo prototype
|
||||
*
|
||||
* setLayerGenericMetadata(string key, bool mandatory, vec<uint8_t> value);
|
||||
*
|
||||
* Sets a piece of generic metadata for the given layer. If this
|
||||
* function is called twice with the same key but different values, the
|
||||
* newer value must override the older one. Calling this function with a
|
||||
* 0-length value must reset that key's metadata as if it had not been
|
||||
* set.
|
||||
*
|
||||
* A given piece of metadata may either be mandatory or a hint
|
||||
* (non-mandatory) as indicated by the second parameter. Mandatory
|
||||
* metadata may affect the composition result, which is to say that it
|
||||
* may cause a visible change in the final image. By contrast, hints may
|
||||
* only affect the composition strategy, such as which layers are
|
||||
* composited by the client, but must not cause a visible change in the
|
||||
* final image. The value of the mandatory flag shall match the value
|
||||
* returned from getLayerGenericMetadataKeys for the given key.
|
||||
*
|
||||
* Only keys which have been returned from getLayerGenericMetadataKeys()
|
||||
* shall be accepted. Any other keys must result in an UNSUPPORTED error.
|
||||
*
|
||||
* The value passed into this function shall be the binary
|
||||
* representation of a HIDL type corresponding to the given key. For
|
||||
* example, a key of 'com.example.V1_3.Foo' shall be paired with a
|
||||
* value of type com.example@1.3::Foo, which would be defined in a
|
||||
* vendor HAL extension.
|
||||
*
|
||||
* This function will be encoded in the command buffer in this order:
|
||||
* 1) The key length, stored as a uint32_t
|
||||
* 2) The key itself, padded to a uint32_t boundary if necessary
|
||||
* 3) The mandatory flag, stored as a uint32_t
|
||||
* 4) The value length in bytes, stored as a uint32_t
|
||||
* 5) The value itself, padded to a uint32_t boundary if necessary
|
||||
*
|
||||
* @param key indicates which metadata value should be set on this layer
|
||||
* @param mandatory indicates whether this particular key represents
|
||||
* mandatory metadata or a hint (non-mandatory metadata), as
|
||||
* described above
|
||||
* @param value is a binary representation of a HIDL struct
|
||||
* corresponding to the key as described above
|
||||
*/
|
||||
SET_LAYER_GENERIC_METADATA = 0x40e << @2.1::IComposerClient.Command:OPCODE_SHIFT,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -271,4 +316,33 @@ interface IComposerClient extends @2.3::IComposerClient {
|
|||
*/
|
||||
setContentType(Display display, ContentType type)
|
||||
generates (Error error);
|
||||
|
||||
struct LayerGenericMetadataKey {
|
||||
/**
|
||||
* Key names must comply with the requirements specified for
|
||||
* getLayerGenericMetadataKeys below
|
||||
*/
|
||||
string name;
|
||||
|
||||
/**
|
||||
* The mandatory flag is defined in the description of
|
||||
* setLayerGenericMetadata above
|
||||
*/
|
||||
bool mandatory;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves the set of keys that may be passed into setLayerGenericMetadata
|
||||
*
|
||||
* Key names must meet the following requirements:
|
||||
* - Must be specified in reverse domain name notation
|
||||
* - Must not start with 'com.android' or 'android'
|
||||
* - Must be unique within the returned vector
|
||||
* - Must correspond to a matching HIDL struct type, which defines the
|
||||
* structure of its values. For example, the key 'com.example.V1-3.Foo'
|
||||
* should correspond to a value of type com.example@1.3::Foo, which is
|
||||
* defined in a vendor HAL extension
|
||||
*/
|
||||
getLayerGenericMetadataKeys()
|
||||
generates(Error error, vec<LayerGenericMetadataKey> keys);
|
||||
};
|
||||
|
|
|
@ -53,6 +53,27 @@ class CommandWriterBase : public V2_3::CommandWriterBase {
|
|||
writeSigned(static_cast<int32_t>(clientTargetProperty.dataspace));
|
||||
endCommand();
|
||||
}
|
||||
|
||||
void setLayerGenericMetadata(const hidl_string& key, const bool mandatory,
|
||||
const hidl_vec<uint8_t>& value) {
|
||||
const size_t commandSize = 3 + sizeToElements(key.size()) + sizeToElements(value.size());
|
||||
if (commandSize > std::numeric_limits<uint16_t>::max()) {
|
||||
LOG_FATAL("Too much generic metadata (%zu elements)", commandSize);
|
||||
return;
|
||||
}
|
||||
|
||||
beginCommand(IComposerClient::Command::SET_LAYER_GENERIC_METADATA,
|
||||
static_cast<uint16_t>(commandSize));
|
||||
write(key.size());
|
||||
writeBlob(key.size(), reinterpret_cast<const unsigned char*>(key.c_str()));
|
||||
write(mandatory);
|
||||
write(value.size());
|
||||
writeBlob(value.size(), value.data());
|
||||
endCommand();
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t sizeToElements(uint32_t size) { return (size + 3) / 4; }
|
||||
};
|
||||
|
||||
// This class helps parse a command queue. Note that all sizes/lengths are in
|
||||
|
|
|
@ -164,6 +164,14 @@ class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl<Interfac
|
|||
return mHal->setContentType(display, contentType);
|
||||
}
|
||||
|
||||
Return<void> getLayerGenericMetadataKeys(
|
||||
IComposerClient::getLayerGenericMetadataKeys_cb hidl_cb) override {
|
||||
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
|
||||
Error error = mHal->getLayerGenericMetadataKeys(&keys);
|
||||
hidl_cb(error, keys);
|
||||
return Void();
|
||||
}
|
||||
|
||||
static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
|
||||
auto client = std::make_unique<ComposerClientImpl>(hal);
|
||||
return client->init() ? std::move(client) : nullptr;
|
||||
|
|
|
@ -74,6 +74,43 @@ class ComposerCommandEngine : public V2_3::hal::ComposerCommandEngine {
|
|||
|
||||
CommandWriterBase* getWriter() { return static_cast<CommandWriterBase*>(mWriter.get()); }
|
||||
|
||||
bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
|
||||
switch (static_cast<IComposerClient::Command>(command)) {
|
||||
case IComposerClient::Command::SET_LAYER_GENERIC_METADATA:
|
||||
return executeSetLayerGenericMetadata(length);
|
||||
default:
|
||||
return BaseType2_3::executeCommand(command, length);
|
||||
}
|
||||
}
|
||||
|
||||
bool executeSetLayerGenericMetadata(uint16_t length) {
|
||||
// We expect at least two buffer lengths and a mandatory flag
|
||||
if (length < 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t keySize = read();
|
||||
std::string key;
|
||||
key.resize(keySize);
|
||||
readBlob(keySize, key.data());
|
||||
|
||||
const bool mandatory = read();
|
||||
|
||||
const uint32_t valueSize = read();
|
||||
std::vector<uint8_t> value(valueSize);
|
||||
readBlob(valueSize, value.data());
|
||||
|
||||
auto error = mHal->setLayerGenericMetadata(mCurrentDisplay, mCurrentLayer, key, mandatory,
|
||||
value);
|
||||
if (error != Error::NONE) {
|
||||
// The error cast is safe because setLayerGenericMetadata doesn't
|
||||
// return any of the new values added in V2_4::Error
|
||||
mWriter->setError(getCommandLoc(), static_cast<V2_1::Error>(error));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ComposerHal* mHal;
|
||||
};
|
||||
|
||||
|
|
|
@ -79,6 +79,10 @@ class ComposerHal : public V2_3::hal::ComposerHal {
|
|||
uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
|
||||
std::vector<uint32_t>* outRequestMasks,
|
||||
IComposerClient::ClientTargetProperty* outClientTargetProperty) = 0;
|
||||
virtual Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
|
||||
bool mandatory, const std::vector<uint8_t>& value) = 0;
|
||||
virtual Error getLayerGenericMetadataKeys(
|
||||
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) = 0;
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
|
|
|
@ -245,6 +245,61 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
|
|||
return err;
|
||||
}
|
||||
|
||||
Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
|
||||
bool mandatory, const std::vector<uint8_t>& value) override {
|
||||
if (!mDispatch.setLayerGenericMetadata) {
|
||||
return Error::UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (key.size() > std::numeric_limits<uint32_t>::max()) {
|
||||
return Error::BAD_PARAMETER;
|
||||
}
|
||||
|
||||
if (value.size() > std::numeric_limits<uint32_t>::max()) {
|
||||
return Error::BAD_PARAMETER;
|
||||
}
|
||||
|
||||
int32_t error = mDispatch.setLayerGenericMetadata(
|
||||
mDevice, display, layer, static_cast<uint32_t>(key.size()), key.c_str(), mandatory,
|
||||
static_cast<uint32_t>(value.size()), value.data());
|
||||
return static_cast<Error>(error);
|
||||
}
|
||||
|
||||
Error getLayerGenericMetadataKeys(
|
||||
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override {
|
||||
if (!mDispatch.getLayerGenericMetadataKey) {
|
||||
return Error::UNSUPPORTED;
|
||||
}
|
||||
|
||||
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
|
||||
|
||||
uint32_t index = 0;
|
||||
uint32_t keyLength = 0;
|
||||
while (true) {
|
||||
mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, nullptr, nullptr);
|
||||
if (keyLength == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
IComposerClient::LayerGenericMetadataKey key;
|
||||
std::string keyName;
|
||||
keyName.resize(keyLength);
|
||||
mDispatch.getLayerGenericMetadataKey(mDevice, index, &keyLength, keyName.data(),
|
||||
&key.mandatory);
|
||||
key.name = keyName;
|
||||
keys.emplace_back(std::move(key));
|
||||
|
||||
// Only attempt to load the first 100 keys to avoid an infinite loop
|
||||
// if something goes wrong
|
||||
if (++index > 100) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*outKeys = std::move(keys);
|
||||
return Error::NONE;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool initDispatch() override {
|
||||
if (!BaseType2_3::initDispatch()) {
|
||||
|
@ -267,6 +322,11 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
|
|||
this->initOptionalDispatch(HWC2_FUNCTION_SET_CONTENT_TYPE, &mDispatch.setContentType);
|
||||
this->initOptionalDispatch(HWC2_FUNCTION_GET_CLIENT_TARGET_PROPERTY,
|
||||
&mDispatch.getClientTargetProperty);
|
||||
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_GENERIC_METADATA,
|
||||
&mDispatch.setLayerGenericMetadata);
|
||||
this->initOptionalDispatch(HWC2_FUNCTION_GET_LAYER_GENERIC_METADATA_KEY,
|
||||
&mDispatch.getLayerGenericMetadataKey);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -319,6 +379,8 @@ class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
|
|||
HWC2_PFN_GET_SUPPORTED_CONTENT_TYPES getSupportedContentTypes;
|
||||
HWC2_PFN_SET_CONTENT_TYPE setContentType;
|
||||
HWC2_PFN_GET_CLIENT_TARGET_PROPERTY getClientTargetProperty;
|
||||
HWC2_PFN_SET_LAYER_GENERIC_METADATA setLayerGenericMetadata;
|
||||
HWC2_PFN_GET_LAYER_GENERIC_METADATA_KEY getLayerGenericMetadataKey;
|
||||
} mDispatch = {};
|
||||
|
||||
hal::ComposerHal::EventCallback_2_4* mEventCallback_2_4 = nullptr;
|
||||
|
|
|
@ -129,6 +129,16 @@ Error ComposerClient::setContentType(Display display, IComposerClient::ContentTy
|
|||
return mClient->setContentType(display, contentType);
|
||||
}
|
||||
|
||||
Error ComposerClient::getLayerGenericMetadataKeys(
|
||||
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) {
|
||||
Error error = Error::NONE;
|
||||
mClient->getLayerGenericMetadataKeys([&](const auto tmpError, const auto& tmpKeys) {
|
||||
error = tmpError;
|
||||
*outKeys = tmpKeys;
|
||||
});
|
||||
return error;
|
||||
}
|
||||
|
||||
} // namespace vts
|
||||
} // namespace V2_4
|
||||
} // namespace composer
|
||||
|
|
|
@ -93,6 +93,9 @@ class ComposerClient : public V2_3::vts::ComposerClient {
|
|||
|
||||
Error setContentType(Display display, IComposerClient::ContentType contentType);
|
||||
|
||||
Error getLayerGenericMetadataKeys(
|
||||
std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys);
|
||||
|
||||
private:
|
||||
const sp<IComposerClient> mClient;
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#define LOG_TAG "graphics_composer_hidl_hal_test@2.4"
|
||||
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
#include <thread>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
@ -625,6 +626,28 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
|
||||
android::hardware::PrintInstanceNameToString);
|
||||
|
||||
TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
|
||||
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
|
||||
mComposerClient->getLayerGenericMetadataKeys(&keys);
|
||||
|
||||
std::regex reverseDomainName("^[a-zA-Z-]{2,}(\\.[a-zA-Z0-9-]+)+$");
|
||||
std::unordered_set<std::string> uniqueNames;
|
||||
for (const auto& key : keys) {
|
||||
std::string name(key.name.c_str());
|
||||
|
||||
// Keys must not start with 'android' or 'com.android'
|
||||
ASSERT_FALSE(name.find("android") == 0);
|
||||
ASSERT_FALSE(name.find("com.android") == 0);
|
||||
|
||||
// Keys must be in reverse domain name format
|
||||
ASSERT_TRUE(std::regex_match(name, reverseDomainName));
|
||||
|
||||
// Keys must be unique within this list
|
||||
const auto& [iter, inserted] = uniqueNames.insert(name);
|
||||
ASSERT_TRUE(inserted);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace vts
|
||||
} // namespace V2_4
|
||||
|
|
Loading…
Reference in a new issue