blob: 8423a124cf0c34472cd7f5990a47cc1795383d21 [file] [log] [blame]
/*
* Copyright 2021 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 <compositionengine/impl/planner/LayerState.h>
namespace {
extern "C" const char* __attribute__((unused)) __asan_default_options() {
return "detect_container_overflow=0";
}
} // namespace
namespace android::compositionengine::impl::planner {
LayerState::LayerState(compositionengine::OutputLayer* layer)
: mOutputLayer(layer),
mColorTransform({[](auto layer) {
const auto state = layer->getLayerFE().getCompositionState();
return state->colorTransformIsIdentity ? mat4{}
: state->colorTransform;
},
[](const mat4& mat) {
using namespace std::string_literals;
std::vector<std::string> split =
base::Split(std::string(mat.asString().string()), "\n"s);
split.pop_back(); // Strip the last (empty) line
return split;
}}) {
update(layer);
}
Flags<LayerStateField> LayerState::update(compositionengine::OutputLayer* layer) {
ALOGE_IF(layer != mOutputLayer, "[%s] Expected mOutputLayer to never change", __func__);
Flags<LayerStateField> differences;
// Update the unique fields as well, since we have to set them at least
// once from the OutputLayer
differences |= mId.update(layer);
differences |= mName.update(layer);
for (StateInterface* field : getNonUniqueFields()) {
differences |= field->update(layer);
}
return differences;
}
size_t LayerState::getHash() const {
size_t hash = 0;
for (const StateInterface* field : getNonUniqueFields()) {
if (field->getField() == LayerStateField::Buffer) {
continue;
}
android::hashCombineSingleHashed(hash, field->getHash());
}
return hash;
}
Flags<LayerStateField> LayerState::getDifferingFields(const LayerState& other) const {
Flags<LayerStateField> differences;
auto myFields = getNonUniqueFields();
auto otherFields = other.getNonUniqueFields();
for (size_t i = 0; i < myFields.size(); ++i) {
if (myFields[i]->getField() == LayerStateField::Buffer) {
continue;
}
differences |= myFields[i]->getFieldIfDifferent(otherFields[i]);
}
return differences;
}
void LayerState::dump(std::string& result) const {
for (const StateInterface* field : getNonUniqueFields()) {
if (auto viewOpt = flag_name(field->getField()); viewOpt) {
base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str());
} else {
result.append("<UNKNOWN FIELD>:\n");
}
bool first = true;
for (const std::string& line : field->toStrings()) {
base::StringAppendF(&result, "%s%s\n", first ? "" : " ",
line.c_str());
first = false;
}
}
result.append("\n");
}
std::optional<std::string> LayerState::compare(const LayerState& other) const {
std::string result;
const auto& thisFields = getNonUniqueFields();
const auto& otherFields = other.getNonUniqueFields();
for (size_t f = 0; f < thisFields.size(); ++f) {
const auto& thisField = thisFields[f];
const auto& otherField = otherFields[f];
// Skip comparing buffers
if (thisField->getField() == LayerStateField::Buffer) {
continue;
}
if (thisField->equals(otherField)) {
continue;
}
if (auto viewOpt = flag_name(thisField->getField()); viewOpt) {
base::StringAppendF(&result, " %16s: ", std::string(*viewOpt).c_str());
} else {
result.append("<UNKNOWN FIELD>:\n");
}
const auto& thisStrings = thisField->toStrings();
const auto& otherStrings = otherField->toStrings();
bool first = true;
for (size_t line = 0; line < std::max(thisStrings.size(), otherStrings.size()); ++line) {
if (!first) {
result.append(" ");
}
first = false;
if (line < thisStrings.size()) {
base::StringAppendF(&result, "%-48.48s", thisStrings[line].c_str());
} else {
result.append(" ");
}
if (line < otherStrings.size()) {
base::StringAppendF(&result, "%-48.48s", otherStrings[line].c_str());
} else {
result.append(" ");
}
result.append("\n");
}
}
return result.empty() ? std::nullopt : std::make_optional(result);
}
bool operator==(const LayerState& lhs, const LayerState& rhs) {
return lhs.mId == rhs.mId && lhs.mName == rhs.mName && lhs.mDisplayFrame == rhs.mDisplayFrame &&
lhs.mSourceCrop == rhs.mSourceCrop && lhs.mBufferTransform == rhs.mBufferTransform &&
lhs.mBlendMode == rhs.mBlendMode && lhs.mAlpha == rhs.mAlpha &&
lhs.mLayerMetadata == rhs.mLayerMetadata && lhs.mVisibleRegion == rhs.mVisibleRegion &&
lhs.mOutputDataspace == rhs.mOutputDataspace && lhs.mPixelFormat == rhs.mPixelFormat &&
lhs.mColorTransform == rhs.mColorTransform &&
lhs.mCompositionType == rhs.mCompositionType &&
lhs.mSidebandStream == rhs.mSidebandStream && lhs.mBuffer == rhs.mBuffer &&
(lhs.mCompositionType.get() != hal::Composition::SOLID_COLOR ||
lhs.mSolidColor == rhs.mSolidColor);
}
NonBufferHash getNonBufferHash(const std::vector<const LayerState*>& layers) {
size_t hash = 0;
for (const auto layer : layers) {
android::hashCombineSingleHashed(hash, layer->getHash());
}
return hash;
}
} // namespace android::compositionengine::impl::planner