drm_hwcomposer: Use cached validated composition
This change adds caching to save the most recently validated composition. The cached value is used where appropriate to avoid recalculating the DrmKmsPlan or the CompositionTypeMap from ValidateDisplay again in PresentDisplay. The cached ValidatedComposition replaces the previously cached DrmKmsPlan, preserving the lifecycle management requirements. Change-Id: I59704e26ae1a6950e750d246314b2db6af2f11a0
This commit is contained in:
parent
99f677a2ea
commit
a51a43422d
4 changed files with 61 additions and 41 deletions
|
|
@ -84,7 +84,7 @@ auto Backend::ValidateDisplay(HwcDisplay* display) -> ValidatedComposition {
|
|||
}
|
||||
|
||||
// Reset the plan in case it was set during a previous test.
|
||||
validated_composition.composition_plan = std::make_shared<DrmKmsPlan>();
|
||||
validated_composition.composition_plan.reset();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
@ -130,7 +130,7 @@ Backend::ValidatedComposition Backend::GetFlattenedComposition(
|
|||
const std::vector<const HwcLayer*>& layers) {
|
||||
return ValidatedComposition{
|
||||
.composition_types = GetCompositionTypes(layers, 0, layers.size(), false),
|
||||
.composition_plan = std::make_shared<DrmKmsPlan>()};
|
||||
.composition_plan = nullptr};
|
||||
}
|
||||
|
||||
std::tuple<size_t, size_t> Backend::GetClientLayers(
|
||||
|
|
|
|||
|
|
@ -34,12 +34,12 @@ class Backend {
|
|||
using CompositionTypeMap = std::map<const HwcLayer*, CompositionType>;
|
||||
struct ValidatedComposition {
|
||||
// The resulting composition type for each layer.
|
||||
CompositionTypeMap composition_types;
|
||||
CompositionTypeMap composition_types{};
|
||||
// The DrmKms resources required for the composition. The lifetime of
|
||||
// the DrmKmsPlan ensures that corresponding drm resources are reserved
|
||||
// for use by this display. As such, the caller must ensure that the
|
||||
// DrmKmsPlan is not destructed before the composition is committed.
|
||||
std::shared_ptr<DrmKmsPlan> composition_plan;
|
||||
std::shared_ptr<DrmKmsPlan> composition_plan = nullptr;
|
||||
};
|
||||
|
||||
virtual ~Backend() = default;
|
||||
|
|
|
|||
|
|
@ -303,6 +303,11 @@ auto HwcDisplay::QueueConfig(ConfigId config, int64_t desired_time,
|
|||
}
|
||||
|
||||
auto HwcDisplay::ValidateStagedComposition() -> std::vector<ChangedLayer> {
|
||||
if (validated_composition_.has_value()) {
|
||||
ALOGE("%s: Previously validated composition was not presented", __func__);
|
||||
validated_composition_.reset();
|
||||
}
|
||||
|
||||
if (IsInHeadlessMode()) {
|
||||
return {};
|
||||
}
|
||||
|
|
@ -334,19 +339,16 @@ auto HwcDisplay::ValidateStagedComposition() -> std::vector<ChangedLayer> {
|
|||
flatcon_->NewFrame();
|
||||
}
|
||||
|
||||
// The CompositionTypeMap in the ValidatedComposition indicates the
|
||||
// composition type that the Backend has determined for each layer.
|
||||
auto result = backend_->ValidateDisplay(this);
|
||||
current_plan_ = result.composition_plan;
|
||||
validated_composition_.emplace(backend_->ValidateDisplay(this));
|
||||
|
||||
// Iterate through the layers to find which layers actually changed.
|
||||
std::vector<ChangedLayer> changed_layers;
|
||||
for (auto &[id, layer] : layers_) {
|
||||
// Set the validated type
|
||||
auto it = result.composition_types.find(&layer);
|
||||
ALOGE_IF(it == result.composition_types.end(),
|
||||
auto it = validated_composition_->composition_types.find(&layer);
|
||||
ALOGE_IF(it == validated_composition_->composition_types.end(),
|
||||
"Backend did not composite layer %" PRId64 "", id);
|
||||
if (it != result.composition_types.end()) {
|
||||
if (it != validated_composition_->composition_types.end()) {
|
||||
layer.SetValidatedType(it->second);
|
||||
}
|
||||
if (layer.IsTypeChanged()) {
|
||||
|
|
@ -394,7 +396,7 @@ auto HwcDisplay::PresentStagedComposition(
|
|||
|
||||
++total_stats_.total_frames;
|
||||
|
||||
// With multiple displays configured at differet refresh rates,
|
||||
// With multiple displays configured at different refresh rates,
|
||||
// desired_present_time can be up to almost 2 vsync periods away for the
|
||||
// slower display. WaitLastFrame() should be called before
|
||||
// WaitForPresenttime(), otherwise can lead to a situation where hwc sleeps
|
||||
|
|
@ -410,12 +412,17 @@ auto HwcDisplay::PresentStagedComposition(
|
|||
WaitForPresentTime(desired_present_time.value(), vperiod_ns);
|
||||
}
|
||||
|
||||
Backend::CompositionTypeMap composition;
|
||||
for (auto &l : layers_) {
|
||||
composition.emplace(&l.second, l.second.GetValidatedType());
|
||||
// Check if validation was skipped, and populate the composition types as
|
||||
// needed. Otherwise, use the already-validated composition types.
|
||||
if (!validated_composition_.has_value()) {
|
||||
validated_composition_ = Backend::ValidatedComposition{};
|
||||
for (auto &l : layers_) {
|
||||
validated_composition_->composition_types
|
||||
.emplace(&l.second, l.second.GetValidatedType());
|
||||
}
|
||||
}
|
||||
|
||||
if (!CommitComposition(composition, out_present_fence)) {
|
||||
if (!CommitStagedComposition(out_present_fence)) {
|
||||
++total_stats_.failed_kms_present;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -572,7 +579,7 @@ void HwcDisplay::Deinit() {
|
|||
a_args.teardown = true;
|
||||
GetPipe().atomic_state_manager->ExecuteAtomicCommit(a_args);
|
||||
|
||||
current_plan_.reset();
|
||||
validated_composition_.reset();
|
||||
backend_.reset();
|
||||
flatcon_.reset();
|
||||
}
|
||||
|
|
@ -815,12 +822,14 @@ bool HwcDisplay::TestComposition(
|
|||
if (IsInHeadlessMode()) {
|
||||
return true;
|
||||
}
|
||||
auto a_args = CreateFrameUpdateCommit(composition.composition_types);
|
||||
auto a_args = CreateFrameUpdateCommit(composition);
|
||||
if (!a_args) {
|
||||
return false;
|
||||
}
|
||||
a_args->test_only = true;
|
||||
if (GetPipe().atomic_state_manager->ExecuteAtomicCommit(*a_args)) {
|
||||
// Put the composition plan into the newly-validated composition. Its owner
|
||||
// is responsible for keeping it alive until commit.
|
||||
composition.composition_plan = a_args->composition;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -829,7 +838,7 @@ bool HwcDisplay::TestComposition(
|
|||
|
||||
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
|
||||
std::optional<AtomicCommitArgs> HwcDisplay::CreateFrameUpdateCommit(
|
||||
const Backend::CompositionTypeMap &composition) const {
|
||||
const Backend::ValidatedComposition &composition) const {
|
||||
if (IsInHeadlessMode()) {
|
||||
ALOGE("%s: Display is in headless mode, should never reach here", __func__);
|
||||
return AtomicCommitArgs{};
|
||||
|
|
@ -860,9 +869,10 @@ std::optional<AtomicCommitArgs> HwcDisplay::CreateFrameUpdateCommit(
|
|||
std::map<uint32_t, const HwcLayer *> z_map;
|
||||
std::optional<LayerData> cursor_layer = std::nullopt;
|
||||
for (const auto &[_, layer] : layers_) {
|
||||
auto it = composition.find(&layer);
|
||||
CompositionType type = it != composition.end() ? it->second
|
||||
: CompositionType::kInvalid;
|
||||
auto it = composition.composition_types.find(&layer);
|
||||
CompositionType type = it != composition.composition_types.end()
|
||||
? it->second
|
||||
: CompositionType::kInvalid;
|
||||
switch (type) {
|
||||
case CompositionType::kDevice:
|
||||
z_map.emplace(layer.GetZOrder(), &layer);
|
||||
|
|
@ -922,10 +932,15 @@ std::optional<AtomicCommitArgs> HwcDisplay::CreateFrameUpdateCommit(
|
|||
composition_layers.emplace_back(layer->GetLayerData());
|
||||
}
|
||||
|
||||
a_args.composition = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
|
||||
std::move(
|
||||
composition_layers),
|
||||
cursor_layer);
|
||||
// Use the provided validated composition plan if it exists, otherwise create
|
||||
// it now.
|
||||
a_args
|
||||
.composition = composition.composition_plan != nullptr
|
||||
? composition.composition_plan
|
||||
: DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
|
||||
std::move(
|
||||
composition_layers),
|
||||
cursor_layer);
|
||||
if (!a_args.composition) {
|
||||
ALOGE_IF(!a_args.test_only, "Failed to create DrmKmsPlan");
|
||||
return std::nullopt;
|
||||
|
|
@ -944,29 +959,34 @@ std::optional<AtomicCommitArgs> HwcDisplay::CreateFrameUpdateCommit(
|
|||
return a_args;
|
||||
}
|
||||
|
||||
bool HwcDisplay::CommitComposition(
|
||||
const Backend::CompositionTypeMap &composition,
|
||||
SharedFd &out_present_fence) {
|
||||
bool HwcDisplay::CommitStagedComposition(SharedFd &out_present_fence) {
|
||||
ATRACE_CALL();
|
||||
|
||||
if (IsInHeadlessMode()) {
|
||||
ALOGE("%s: Display is in headless mode, should never reach here", __func__);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!validated_composition_.has_value()) {
|
||||
ALOGE("%s: No composition is staged. Cannot commit.", __func__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Client layer needs to be populated after validation since the client may
|
||||
// not provide a new buffer until after validation.
|
||||
if (std::any_of(composition.begin(), composition.end(),
|
||||
if (std::any_of(validated_composition_->composition_types.begin(),
|
||||
validated_composition_->composition_types.end(),
|
||||
[](const auto &pair) -> bool {
|
||||
return pair.second == CompositionType::kClient;
|
||||
})) {
|
||||
client_layer_.PopulateLayerData();
|
||||
}
|
||||
|
||||
auto a_args = CreateFrameUpdateCommit(composition);
|
||||
// |current_plan_| can safely be reset now. |a_args| holds its own pointer
|
||||
// which will remain in scope until the commit is finished (successfully or
|
||||
// not).
|
||||
current_plan_.reset();
|
||||
auto a_args = CreateFrameUpdateCommit(validated_composition_.value());
|
||||
// |validated_composition_| can safely be reset now. |a_args| holds its own
|
||||
// pointer to the plan which will remain in scope until the commit is finished
|
||||
// (successfully or not).
|
||||
validated_composition_.reset();
|
||||
|
||||
if (!a_args) {
|
||||
ALOGE("Failed to create AtomicCommitArgs for frame composition.");
|
||||
|
|
|
|||
|
|
@ -241,10 +241,9 @@ class HwcDisplay {
|
|||
// The caller must do a test commit on the returned args to ensure that the
|
||||
// hardware can perform the commit.
|
||||
std::optional<AtomicCommitArgs> CreateFrameUpdateCommit(
|
||||
const Backend::CompositionTypeMap &composition) const;
|
||||
const Backend::ValidatedComposition &composition) const;
|
||||
|
||||
bool CommitComposition(const Backend::CompositionTypeMap &composition,
|
||||
SharedFd &out_present_fence);
|
||||
bool CommitStagedComposition(SharedFd &out_present_fence);
|
||||
|
||||
// Update HwcDisplay state tracking to reflect what was committed in |a_args|.
|
||||
// This should be called after a successful commit.
|
||||
|
|
@ -300,9 +299,10 @@ class HwcDisplay {
|
|||
Colorspace colorspace_{};
|
||||
int32_t min_bpc_{};
|
||||
std::shared_ptr<hdr_output_metadata> hdr_metadata_;
|
||||
// Stored plan to ensure shared planes won't be stolen by other displays
|
||||
// between ValidateDisplay() and PresentDisplay() calls.
|
||||
std::shared_ptr<DrmKmsPlan> current_plan_;
|
||||
// Most recent result of ValidateStagedComposition. Must be kept alive until
|
||||
// the composition is committed.
|
||||
std::optional<Backend::ValidatedComposition>
|
||||
validated_composition_ = std::nullopt;
|
||||
|
||||
SharedFd writeback_complete_fence_;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue