Upgrade drm_hwcomposer to f638348b22e96e208badb71de52a860d201ee2fb
This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/drm_hwcomposer
For more info, check https://cs.android.com/android/platform/superproject/main/+/main:tools/external_updater/README.md
Bug: 383346402
Test: TreeHugger
Change-Id: If01d83a02be030c21e820b05782d6c19059668c2
diff --git a/METADATA b/METADATA
index 2d137a9..24845b6 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
last_upgrade_date {
year: 2025
month: 3
- day: 13
+ day: 14
}
identifier {
type: "Git"
value: "https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer"
- version: "7009cc1909804ef707376441b5b3f986b492d66a"
+ version: "f638348b22e96e208badb71de52a860d201ee2fb"
}
}
diff --git a/backend/Backend.cpp b/backend/Backend.cpp
index 650e29e..12a5fea 100644
--- a/backend/Backend.cpp
+++ b/backend/Backend.cpp
@@ -20,9 +20,20 @@
#include "BackendManager.h"
#include "bufferinfo/BufferInfoGetter.h"
+#include "hardware/hwcomposer2.h"
namespace android {
+namespace {
+
+bool HasCursorLayer(const std::vector<HwcLayer *> &layers) {
+ return std::find_if(layers.begin(), layers.end(), [&](auto *layer) -> bool {
+ return layer->GetSfType() == HWC2::Composition::Cursor;
+ }) != layers.end();
+}
+
+} // namespace
+
HWC2::Error Backend::ValidateDisplay(HwcDisplay *display, uint32_t *num_types,
uint32_t *num_requests) {
*num_types = 0;
@@ -62,7 +73,27 @@
++display->total_stats().failed_kms_validate_;
client_start = 0;
client_size = layers.size();
- MarkValidated(layers, 0, client_size);
+
+ // Expand the client range to include all layers except the cursor layer (if
+ // there is one) and retry.
+ auto [_, cursor_plane] = display->GetPipe().GetUsablePlanes();
+ if (cursor_plane && HasCursorLayer(layers)) {
+ --client_size;
+ MarkValidated(layers, 0, client_size);
+
+ testing_needed = display->CreateComposition(a_args) != HWC2::Error::None;
+
+ // If testing is still needed, expand the client range to include the
+ // cursor layer for the next retry.
+ if (testing_needed) {
+ ++client_size;
+ ++display->total_stats().failed_kms_validate_;
+ }
+ }
+
+ if (testing_needed) {
+ MarkValidated(layers, 0, client_size);
+ }
}
*num_types = client_size;
@@ -120,10 +151,13 @@
void Backend::MarkValidated(std::vector<HwcLayer *> &layers,
size_t client_first_z, size_t client_size) {
for (size_t z_order = 0; z_order < layers.size(); ++z_order) {
- if (z_order >= client_first_z && z_order < client_first_z + client_size)
+ if (z_order >= client_first_z && z_order < client_first_z + client_size) {
layers[z_order]->SetValidatedType(HWC2::Composition::Client);
- else
+ } else if (layers[z_order]->GetSfType() == HWC2::Composition::Cursor) {
+ layers[z_order]->SetValidatedType(HWC2::Composition::Cursor);
+ } else {
layers[z_order]->SetValidatedType(HWC2::Composition::Device);
+ }
}
}
@@ -132,31 +166,39 @@
int client_start, size_t client_size) {
auto [planes, cursor_plane] = display->GetPipe().GetUsablePlanes();
size_t avail_planes = planes.size();
+ size_t layers_size = layers.size();
+
+ // |cursor_plane| is not counted among |avail_planes|, so the cursor layer
+ // shouldn't be counted in |layers_size|.
+ if (cursor_plane && HasCursorLayer(layers)) {
+ --layers_size;
+ }
/*
- * If more layers then planes, save one plane
+ * If more layers than planes, save one plane
* for client composited layers
*/
- if (avail_planes < display->layers().size())
+ if (avail_planes < layers_size) {
avail_planes--;
+ }
- const int extra_client = int(layers.size() - client_size) - int(avail_planes);
+ const int extra_client = int(layers_size - client_size) - int(avail_planes);
if (extra_client > 0) {
int start = 0;
size_t steps = 0;
if (client_size != 0) {
const int prepend = std::min(client_start, extra_client);
- const int append = std::min(int(layers.size()) -
+ const int append = std::min(int(layers_size) -
int(client_start + client_size),
extra_client);
start = client_start - (int)prepend;
client_size += extra_client;
steps = 1 + std::min(std::min(append, prepend),
- int(layers.size()) - int(start + client_size));
+ int(layers_size) - int(start + client_size));
} else {
client_size = extra_client;
- steps = 1 + layers.size() - extra_client;
+ steps = 1 + layers_size - extra_client;
}
uint32_t gpu_pixops = UINT32_MAX;
diff --git a/bufferinfo/BufferInfoMapperMetadata.cpp b/bufferinfo/BufferInfoMapperMetadata.cpp
index dc1b906..125c5c8 100644
--- a/bufferinfo/BufferInfoMapperMetadata.cpp
+++ b/bufferinfo/BufferInfoMapperMetadata.cpp
@@ -31,6 +31,23 @@
namespace android {
+namespace {
+
+std::optional<std::pair<uint32_t, uint32_t>> GetAlignedDimensions(
+ const ui::PlaneLayout &layout) {
+ if (layout.sampleIncrementInBits == 0 || layout.strideInBytes == 0) {
+ ALOGW("Invalid plane layout");
+ return std::nullopt;
+ }
+
+ constexpr uint32_t kBitsPerByte = 8;
+ return std::pair{layout.strideInBytes * kBitsPerByte /
+ layout.sampleIncrementInBits,
+ layout.totalSizeInBytes / layout.strideInBytes};
+}
+
+} // namespace
+
BufferInfoGetter *BufferInfoMapperMetadata::CreateInstance() {
if (GraphicBufferMapper::getInstance().getMapperVersion() <
GraphicBufferMapper::GRALLOC_4)
@@ -136,6 +153,25 @@
bi.sizes[i] = layouts[i].totalSizeInBytes;
}
+ uint64_t usage = 0;
+ err = mapper.getUsage(handle, &usage);
+ if (err != 0) {
+ ALOGE("Failed to get Usage err=%d", err);
+ return {};
+ }
+
+ if ((usage & GRALLOC_USAGE_CURSOR) != 0) {
+ if (layouts.size() > 1) {
+ ALOGW("Multiplanar format buffer alignment not supported");
+ } else {
+ auto aligned = GetAlignedDimensions(layouts[0]);
+ if (aligned.has_value()) {
+ bi.width = aligned->first;
+ bi.height = aligned->second;
+ }
+ }
+ }
+
err = GetFds(handle, &bi);
if (err != 0) {
ALOGE("Failed to get fds (err=%d)", err);
diff --git a/compositor/DrmKmsPlan.cpp b/compositor/DrmKmsPlan.cpp
index 443b515..1155697 100644
--- a/compositor/DrmKmsPlan.cpp
+++ b/compositor/DrmKmsPlan.cpp
@@ -23,17 +23,30 @@
#include "utils/log.h"
namespace android {
-auto DrmKmsPlan::CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
- std::vector<LayerData> composition)
- -> std::unique_ptr<DrmKmsPlan> {
+auto DrmKmsPlan::CreateDrmKmsPlan(
+ DrmDisplayPipeline &pipe, std::vector<LayerData> composition,
+ std::optional<LayerData> cursor_layer) -> std::unique_ptr<DrmKmsPlan> {
auto plan = std::make_unique<DrmKmsPlan>();
auto [avail_planes, cursor_plane] = pipe.GetUsablePlanes();
int z_pos = 0;
+ if (cursor_layer.has_value()) {
+ if (cursor_plane &&
+ cursor_plane->Get()->IsValidForLayer(&cursor_layer.value())) {
+ plan->plan.emplace_back(
+ LayerToPlaneJoining{.layer = std::move(cursor_layer.value()),
+ .plane = cursor_plane,
+ .z_pos = z_pos++});
+ } else {
+ // Cursor layer can't use cursor plane, so let it match normally with
+ // others.
+ composition.push_back(std::move(cursor_layer.value()));
+ }
+ }
+
for (auto &dhl : composition) {
std::shared_ptr<BindingOwner<DrmPlane>> plane;
-
/* Skip unsupported planes */
do {
if (avail_planes.empty()) {
diff --git a/compositor/DrmKmsPlan.h b/compositor/DrmKmsPlan.h
index 054cd93..d0b271a 100644
--- a/compositor/DrmKmsPlan.h
+++ b/compositor/DrmKmsPlan.h
@@ -35,8 +35,9 @@
std::vector<LayerToPlaneJoining> plan;
static auto CreateDrmKmsPlan(DrmDisplayPipeline &pipe,
- std::vector<LayerData> composition)
- -> std::unique_ptr<DrmKmsPlan>;
+ std::vector<LayerData> composition,
+ std::optional<LayerData> cursor_layer =
+ std::nullopt) -> std::unique_ptr<DrmKmsPlan>;
};
} // namespace android
diff --git a/drm/DrmPlane.cpp b/drm/DrmPlane.cpp
index 0fe060d..2251a78 100644
--- a/drm/DrmPlane.cpp
+++ b/drm/DrmPlane.cpp
@@ -284,6 +284,13 @@
auto disp = opt_disp.value();
auto src = opt_src.value();
+ if (type_ == DRM_PLANE_TYPE_CURSOR) {
+ disp.right = disp.left + static_cast<int>(layer.bi->width);
+ disp.bottom = disp.top + static_cast<int>(layer.bi->height);
+ src = {0, 0, static_cast<float>(layer.bi->width),
+ static_cast<float>(layer.bi->height)};
+ }
+
if (!crtc_property_.AtomicSet(pset, crtc_id) ||
!fb_property_.AtomicSet(pset, layer.fb->GetFbId()) ||
!crtc_x_property_.AtomicSet(pset, disp.left) ||
diff --git a/drm/VSyncWorker.cpp b/drm/VSyncWorker.cpp
index 7ec1c28..4b08515 100644
--- a/drm/VSyncWorker.cpp
+++ b/drm/VSyncWorker.cpp
@@ -84,6 +84,11 @@
return last_timestamp_is_fresh_ ? last_timestamp_.value_or(0) : 0;
}
+int64_t VSyncWorker::GetNextVsyncTimestamp(int64_t time) {
+ const std::lock_guard<std::mutex> lock(mutex_);
+ return GetPhasedVSync(vsync_period_ns_, time);
+}
+
void VSyncWorker::SetTimestampCallback(
std::optional<VsyncTimestampCallback> &&callback) {
{
diff --git a/drm/VSyncWorker.h b/drm/VSyncWorker.h
index 8e410f4..e8ed24b 100644
--- a/drm/VSyncWorker.h
+++ b/drm/VSyncWorker.h
@@ -50,6 +50,10 @@
void SetVsyncTimestampTracking(bool enabled);
uint32_t GetLastVsyncTimestamp();
+ // Get the next predicted vsync timestamp after |time|, based on the last
+ // recorded vsync timestamp and the current vsync period.
+ int64_t GetNextVsyncTimestamp(int64_t time);
+
void StopThread();
private:
diff --git a/hwc2_device/HwcDisplay.cpp b/hwc2_device/HwcDisplay.cpp
index 15a4c6e..c97c640 100644
--- a/hwc2_device/HwcDisplay.cpp
+++ b/hwc2_device/HwcDisplay.cpp
@@ -375,8 +375,8 @@
}
auto HwcDisplay::PresentStagedComposition(
- SharedFd &out_present_fence, std::vector<ReleaseFence> &out_release_fences)
- -> bool {
+ std::optional<int64_t> desired_present_time, SharedFd &out_present_fence,
+ std::vector<ReleaseFence> &out_release_fences) -> bool {
if (IsInHeadlessMode()) {
return true;
}
@@ -384,6 +384,17 @@
++total_stats_.total_frames_;
+ uint32_t vperiod_ns = 0;
+ GetDisplayVsyncPeriod(&vperiod_ns);
+
+ if (desired_present_time && vperiod_ns != 0) {
+ // DRM atomic uAPI does not support specifying that a commit should be
+ // applied to some future vsync. Until such uAPI is available, sleep in
+ // userspace until the next expected vsync time is consistent with the
+ // desired present time.
+ WaitForPresentTime(desired_present_time.value(), vperiod_ns);
+ }
+
AtomicCommitArgs a_args{};
ret = CreateComposition(a_args);
@@ -745,6 +756,39 @@
return args;
}
+void HwcDisplay::WaitForPresentTime(int64_t present_time,
+ uint32_t vsync_period_ns) {
+ const int64_t current_time = ResourceManager::GetTimeMonotonicNs();
+ int64_t next_vsync_time = vsync_worker_->GetNextVsyncTimestamp(current_time);
+
+ int64_t vsync_after_present_time = vsync_worker_->GetNextVsyncTimestamp(
+ present_time);
+ int64_t vsync_before_present_time = vsync_after_present_time -
+ vsync_period_ns;
+
+ // Check if |present_time| is closer to the expected vsync before or after.
+ int64_t desired_vsync = (vsync_after_present_time - present_time) <
+ (present_time - vsync_before_present_time)
+ ? vsync_after_present_time
+ : vsync_before_present_time;
+
+ // Don't sleep if desired_vsync is before or nearly equal to vsync_period of
+ // the next expected vsync.
+ const int64_t quarter_vsync_period = vsync_period_ns / 4;
+ if ((desired_vsync - next_vsync_time) < quarter_vsync_period) {
+ return;
+ }
+
+ // Sleep until 75% vsync_period before the desired_vsync.
+ int64_t sleep_until = desired_vsync - (quarter_vsync_period * 3);
+ struct timespec sleep_until_ts{};
+ constexpr int64_t kOneSecondNs = 1LL * 1000 * 1000 * 1000;
+ sleep_until_ts.tv_sec = int(sleep_until / kOneSecondNs);
+ sleep_until_ts.tv_nsec = int(sleep_until -
+ (sleep_until_ts.tv_sec * kOneSecondNs));
+ clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &sleep_until_ts, nullptr);
+}
+
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
HWC2::Error HwcDisplay::CreateComposition(AtomicCommitArgs &a_args) {
if (IsInHeadlessMode()) {
@@ -781,11 +825,21 @@
bool use_client_layer = false;
uint32_t client_z_order = UINT32_MAX;
std::map<uint32_t, HwcLayer *> z_map;
+ std::optional<LayerData> cursor_layer = std::nullopt;
for (auto &[_, layer] : layers_) {
switch (layer.GetValidatedType()) {
case HWC2::Composition::Device:
z_map.emplace(layer.GetZOrder(), &layer);
break;
+ case HWC2::Composition::Cursor:
+ if (!cursor_layer.has_value()) {
+ layer.PopulateLayerData();
+ cursor_layer = layer.GetLayerData();
+ } else {
+ ALOGW("Detected multiple cursor layers");
+ z_map.emplace(layer.GetZOrder(), &layer);
+ }
+ break;
case HWC2::Composition::Client:
// Place it at the z_order of the lowest client layer
use_client_layer = true;
@@ -835,7 +889,8 @@
* in between of ValidateDisplay() and PresentDisplay() calls
*/
current_plan_ = DrmKmsPlan::CreateDrmKmsPlan(GetPipe(),
- std::move(composition_layers));
+ std::move(composition_layers),
+ cursor_layer);
if (type_ == HWC2::DisplayType::Virtual) {
writeback_layer_->PopulateLayerData();
@@ -1064,6 +1119,12 @@
std::sort(std::begin(ordered_layers), std::end(ordered_layers),
[](const HwcLayer *lhs, const HwcLayer *rhs) {
+ // Cursor layers should always have highest zpos.
+ if ((lhs->GetSfType() == HWC2::Composition::Cursor) !=
+ (rhs->GetSfType() == HWC2::Composition::Cursor)) {
+ return rhs->GetSfType() == HWC2::Composition::Cursor;
+ }
+
return lhs->GetZOrder() < rhs->GetZOrder();
});
diff --git a/hwc2_device/HwcDisplay.h b/hwc2_device/HwcDisplay.h
index b8c52fe..c645400 100644
--- a/hwc2_device/HwcDisplay.h
+++ b/hwc2_device/HwcDisplay.h
@@ -98,7 +98,7 @@
auto GetConfig(hwc2_config_t config_id) const -> const HwcDisplayConfig *;
auto GetDisplayBoundsMm() -> std::pair<int32_t, int32_t>;
-
+
// To be called after SetDisplayProperties. Returns an empty vector if the
// requested layers have been validated, otherwise the vector describes
// the requested composition type changes.
@@ -108,11 +108,14 @@
// Mark previously validated properties as ready to present.
auto AcceptValidatedComposition() -> void;
+ using ReleaseFence = std::pair<ILayerId, SharedFd>;
// Present previously staged properties, and return fences to indicate when
// the new content has been presented, and when the previous buffers have
- // been released.
- using ReleaseFence = std::pair<ILayerId, SharedFd>;
- auto PresentStagedComposition(SharedFd &out_present_fence,
+ // been released. If |desired_present_time| is set, ensure that the
+ // composition is presented at the closest vsync to that requested time.
+ // Otherwise, present immediately.
+ auto PresentStagedComposition(std::optional<int64_t> desired_present_time,
+ SharedFd &out_present_fence,
std::vector<ReleaseFence> &out_release_fences)
-> bool;
@@ -255,6 +258,10 @@
const HwcDisplayConfig *config,
const std::optional<LayerData> &modeset_layer);
+ // Sleep the current thread until |present_time| is closest to the next
+ // expected vsync time.
+ void WaitForPresentTime(int64_t present_time, uint32_t vsync_period_ns);
+
HwcDisplayConfigs configs_;
DrmHwc *const hwc_;
diff --git a/hwc2_device/hwc2_device.cpp b/hwc2_device/hwc2_device.cpp
index c1c5157..7c9d806 100644
--- a/hwc2_device/hwc2_device.cpp
+++ b/hwc2_device/hwc2_device.cpp
@@ -501,7 +501,7 @@
hwc2display->release_fences.clear();
- if (!idisplay->PresentStagedComposition(out_fence,
+ if (!idisplay->PresentStagedComposition(std::nullopt, out_fence,
hwc2display->release_fences)) {
ALOGE("Failed to present display");
return static_cast<int32_t>(HWC2::Error::BadDisplay);
diff --git a/hwc3/ComposerClient.cpp b/hwc3/ComposerClient.cpp
index c7ec522..ecb2dca 100644
--- a/hwc3/ComposerClient.cpp
+++ b/hwc3/ComposerClient.cpp
@@ -154,6 +154,14 @@
return AidlToSampleRange(dataspace->dataspace);
}
+std::optional<int64_t> AidlToPresentTimeNs(
+ const std::optional<ClockMonotonicTimestamp>& expected_present_time) {
+ if (!expected_present_time || expected_present_time->timestampNanos == 0) {
+ return std::nullopt;
+ }
+ return expected_present_time->timestampNanos;
+}
+
bool IsSupportedCompositionType(
const std::optional<ParcelableComposition> composition) {
if (!composition) {
@@ -731,6 +739,8 @@
cmd_result_writer_->AddChanges(changes);
auto hwc3_display = DrmHwcThree::GetHwc3Display(*display);
hwc3_display->must_validate = false;
+ hwc3_display->desired_present_time = AidlToPresentTimeNs(
+ command.expectedPresentTime);
// TODO: DisplayRequests are not implemented.
}
@@ -755,9 +765,12 @@
cmd_result_writer_->AddError(hwc3::Error::kNotValidated);
return;
}
+
::android::SharedFd present_fence;
std::vector<HwcDisplay::ReleaseFence> release_fences;
- bool ret = display->PresentStagedComposition(present_fence, release_fences);
+ bool ret = display->PresentStagedComposition(hwc3_display
+ ->desired_present_time,
+ present_fence, release_fences);
if (!ret) {
cmd_result_writer_->AddError(hwc3::Error::kBadDisplay);
diff --git a/hwc3/DrmHwcThree.h b/hwc3/DrmHwcThree.h
index 10470ea..89bcf46 100644
--- a/hwc3/DrmHwcThree.h
+++ b/hwc3/DrmHwcThree.h
@@ -26,6 +26,9 @@
class Hwc3Display : public ::android::FrontendDisplayBase {
public:
bool must_validate = false;
+ // Desired present time for a composition that has been validated but not
+ // yet presented. nullopt means it should be presented at the next vsync.
+ std::optional<int64_t> desired_present_time = std::nullopt;
int64_t next_layer_id = 1;
};