drm_hwcomposer: Remove writeback-based flattening logic
Writeback Pros:
a. Very tiny reduction in power consumption required for
rendering the composition compared to CLIENT-based flattening.
Writeback Cons:
a. A lot of extra code. High maintenance cost(effort).
Nobody tests it as for now.
b. Writeback isn't implemented by the set of KMS drivers
c. Require separate memory buffer to be allocated
Part of: https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/-/issues/47
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
diff --git a/compositor/DrmDisplayCompositor.cpp b/compositor/DrmDisplayCompositor.cpp
index 8d96d0e..2cc0da5 100644
--- a/compositor/DrmDisplayCompositor.cpp
+++ b/compositor/DrmDisplayCompositor.cpp
@@ -37,8 +37,6 @@
#include "drm/DrmPlane.h"
#include "utils/autolock.h"
-static const uint32_t kWaitWritebackFence = 100; // ms
-
namespace android {
std::ostream &operator<<(std::ostream &str, FlatteningState state) {
@@ -73,7 +71,6 @@
dump_frames_composited_(0),
dump_last_timestamp_ns_(0),
flatten_countdown_(FLATTEN_COUNTDOWN_INIT),
- writeback_fence_(-1),
flattening_state_(FlatteningState::kNone),
frames_flattened_(0) {
struct timespec ts {};
@@ -216,49 +213,8 @@
return 0;
}
-int DrmDisplayCompositor::SetupWritebackCommit(drmModeAtomicReqPtr pset,
- uint32_t crtc_id,
- DrmConnector *writeback_conn,
- DrmHwcBuffer *writeback_buffer) {
- int ret = 0;
- if (writeback_conn->writeback_fb_id().id() == 0 ||
- writeback_conn->writeback_out_fence().id() == 0) {
- ALOGE("Writeback properties don't exit");
- return -EINVAL;
- }
- if ((*writeback_buffer)->fb_id == 0) {
- ALOGE("Invalid writeback buffer");
- return -EINVAL;
- }
- ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
- writeback_conn->writeback_fb_id().id(),
- (*writeback_buffer)->fb_id);
- if (ret < 0) {
- ALOGE("Failed to add writeback_fb_id");
- return ret;
- }
- ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
- writeback_conn->writeback_out_fence().id(),
- (uint64_t)&writeback_fence_);
- if (ret < 0) {
- ALOGE("Failed to add writeback_out_fence");
- return ret;
- }
-
- ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
- writeback_conn->crtc_id_property().id(),
- crtc_id);
- if (ret < 0) {
- ALOGE("Failed to attach writeback");
- return ret;
- }
- return 0;
-}
-
int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
- bool test_only,
- DrmConnector *writeback_conn,
- DrmHwcBuffer *writeback_buffer) {
+ bool test_only) {
ATRACE_CALL();
int ret = 0;
@@ -286,18 +242,6 @@
return -ENOMEM;
}
- if (writeback_buffer != nullptr) {
- if (writeback_conn == nullptr) {
- ALOGE("Invalid arguments requested writeback without writeback conn");
- return -EINVAL;
- }
- ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn,
- writeback_buffer);
- if (ret < 0) {
- ALOGE("Failed to Setup Writeback Commit ret = %d", ret);
- return ret;
- }
- }
if (crtc->out_fence_ptr_property().id() != 0) {
ret = drmModeAtomicAddProperty(pset, crtc->id(),
crtc->out_fence_ptr_property().id(),
@@ -661,22 +605,16 @@
return;
active_composition_.reset(nullptr);
- vsync_worker_.VSyncControl(false);
}
void DrmDisplayCompositor::ApplyFrame(
- std::unique_ptr<DrmDisplayComposition> composition, int status,
- bool writeback) {
+ std::unique_ptr<DrmDisplayComposition> composition, int status) {
AutoLock lock(&lock_, __func__);
if (lock.Lock())
return;
int ret = status;
if (!ret) {
- if (writeback && !CountdownExpired()) {
- ALOGE("Abort playing back scene");
- return;
- }
ret = CommitFrame(composition.get(), false);
}
@@ -697,7 +635,7 @@
} else {
SetFlattening(FlatteningState::kClientDone);
}
- vsync_worker_.VSyncControl(!writeback);
+ vsync_worker_.VSyncControl(true);
}
int DrmDisplayCompositor::ApplyComposition(
@@ -747,118 +685,10 @@
return CommitFrame(composition, true);
}
-// Flatten a scene on the display by using a writeback connector
-// and returns the composition result as a DrmHwcLayer.
-int DrmDisplayCompositor::FlattenOnDisplay(
- std::unique_ptr<DrmDisplayComposition> &src, DrmConnector *writeback_conn,
- DrmMode &src_mode, DrmHwcLayer *writeback_layer) {
- int ret = 0;
- DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
- ret = writeback_conn->UpdateModes();
- if (ret) {
- ALOGE("Failed to update modes %d", ret);
- return ret;
- }
- for (const DrmMode &mode : writeback_conn->modes()) {
- if (mode.h_display() == src_mode.h_display() &&
- mode.v_display() == src_mode.v_display()) {
- mode_.mode = mode;
- if (mode_.blob_id)
- drm->DestroyPropertyBlob(mode_.blob_id);
- std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
- if (ret) {
- ALOGE("Failed to create mode blob for display %d", display_);
- return ret;
- }
- mode_.needs_modeset = true;
- break;
- }
- }
- if (mode_.blob_id <= 0) {
- ALOGE("Failed to find similar mode");
- return -EINVAL;
- }
-
- DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
- if (!crtc) {
- ALOGE("Failed to find crtc for display %d", display_);
- return -EINVAL;
- }
- // TODO(nobody) what happens if planes could go to both CRTCs, I don't think
- // it's handled anywhere
- std::vector<DrmPlane *> primary_planes;
- std::vector<DrmPlane *> overlay_planes;
- for (auto &plane : drm->planes()) {
- if (!plane->GetCrtcSupported(*crtc))
- continue;
- if (plane->type() == DRM_PLANE_TYPE_PRIMARY)
- primary_planes.push_back(plane.get());
- else if (plane->type() == DRM_PLANE_TYPE_OVERLAY)
- overlay_planes.push_back(plane.get());
- }
-
- ret = src->Plan(&primary_planes, &overlay_planes);
- if (ret) {
- ALOGE("Failed to plan the composition ret = %d", ret);
- return ret;
- }
-
- // Disable the planes we're not using
- for (auto i = primary_planes.begin(); i != primary_planes.end();) {
- src->AddPlaneDisable(*i);
- i = primary_planes.erase(i);
- }
- for (auto i = overlay_planes.begin(); i != overlay_planes.end();) {
- src->AddPlaneDisable(*i);
- i = overlay_planes.erase(i);
- }
-
- AutoLock lock(&lock_, __func__);
- ret = lock.Lock();
- if (ret)
- return ret;
- DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_];
- framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
- if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) {
- ALOGE("Failed to allocate writeback buffer");
- return -ENOMEM;
- }
- DrmHwcBuffer *writeback_buffer = &writeback_layer->buffer;
- writeback_layer->sf_handle = writeback_fb->buffer()->handle;
- ret = writeback_layer->ImportBuffer(
- resource_manager_->GetImporter(display_).get());
- if (ret) {
- ALOGE("Failed to import writeback buffer");
- return ret;
- }
-
- ret = CommitFrame(src.get(), true, writeback_conn, writeback_buffer);
- if (ret) {
- ALOGE("Atomic check failed");
- return ret;
- }
- ret = CommitFrame(src.get(), false, writeback_conn, writeback_buffer);
- if (ret) {
- ALOGE("Atomic commit failed");
- return ret;
- }
-
- ret = sync_wait(writeback_fence_, kWaitWritebackFence);
- writeback_layer->acquire_fence.Set(writeback_fence_);
- writeback_fence_ = -1;
- if (ret) {
- ALOGE("Failed to wait on writeback fence");
- return ret;
- }
- return 0;
-}
-
void DrmDisplayCompositor::SetFlattening(FlatteningState new_state) {
if (flattening_state_ != new_state) {
switch (flattening_state_) {
case FlatteningState::kClientDone:
- case FlatteningState::kConcurrent:
- case FlatteningState::kSerial:
++frames_flattened_;
break;
case FlatteningState::kClientRequested:
@@ -901,214 +731,8 @@
return -EINVAL;
}
-// Flatten a scene by enabling the writeback connector attached
-// to the same CRTC as the one driving the display.
-int DrmDisplayCompositor::FlattenSerial(DrmConnector *writeback_conn) {
- ALOGV("FlattenSerial by enabling writeback connector to the same crtc");
- // Flattened composition with only one layer that is obtained
- // using the writeback connector
- std::unique_ptr<DrmDisplayComposition>
- writeback_comp = CreateInitializedComposition();
- if (!writeback_comp)
- return -EINVAL;
-
- AutoLock lock(&lock_, __func__);
- int ret = lock.Lock();
- if (ret)
- return ret;
- if (!IsFlatteningNeeded()) {
- ALOGV("Flattening is not needed");
- SetFlattening(FlatteningState::kNotNeeded);
- return -EALREADY;
- }
-
- DrmFramebuffer *writeback_fb = &framebuffers_[framebuffer_index_];
- framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
- lock.Unlock();
-
- if (!writeback_fb->Allocate(mode_.mode.h_display(), mode_.mode.v_display())) {
- ALOGE("Failed to allocate writeback buffer");
- return -ENOMEM;
- }
- writeback_comp->layers().emplace_back();
-
- DrmHwcLayer &writeback_layer = writeback_comp->layers().back();
- writeback_layer.sf_handle = writeback_fb->buffer()->handle;
- writeback_layer.source_crop = {0, 0, (float)mode_.mode.h_display(),
- (float)mode_.mode.v_display()};
- writeback_layer.display_frame = {0, 0, (int)mode_.mode.h_display(),
- (int)mode_.mode.v_display()};
- ret = writeback_layer.ImportBuffer(
- resource_manager_->GetImporter(display_).get());
- if (ret || writeback_comp->layers().size() != 1) {
- ALOGE("Failed to import writeback buffer");
- return ret;
- }
-
- drmModeAtomicReqPtr pset = drmModeAtomicAlloc();
- if (!pset) {
- ALOGE("Failed to allocate property set");
- return -ENOMEM;
- }
- DrmDevice *drm = resource_manager_->GetDrmDevice(display_);
- DrmCrtc *crtc = drm->GetCrtcForDisplay(display_);
- if (!crtc) {
- ALOGE("Failed to find crtc for display %d", display_);
- return -EINVAL;
- }
- ret = SetupWritebackCommit(pset, crtc->id(), writeback_conn,
- &writeback_layer.buffer);
- if (ret < 0) {
- ALOGE("Failed to Setup Writeback Commit");
- return ret;
- }
- ret = drmModeAtomicCommit(drm->fd(), pset, 0, drm);
- if (ret) {
- ALOGE("Failed to enable writeback %d", ret);
- return ret;
- }
- ret = sync_wait(writeback_fence_, kWaitWritebackFence);
- writeback_layer.acquire_fence.Set(writeback_fence_);
- writeback_fence_ = -1;
- if (ret) {
- ALOGE("Failed to wait on writeback fence");
- return ret;
- }
-
- DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, nullptr,
- crtc);
- for (auto &drmplane : drm->planes()) {
- if (!drmplane->GetCrtcSupported(*crtc))
- continue;
- if (!squashed_comp.plane() && drmplane->type() == DRM_PLANE_TYPE_PRIMARY)
- squashed_comp.set_plane(drmplane.get());
- else
- writeback_comp->AddPlaneDisable(drmplane.get());
- }
- squashed_comp.source_layers().push_back(0);
- ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp));
- if (ret) {
- ALOGE("Failed to add flatten scene");
- return ret;
- }
-
- ApplyFrame(std::move(writeback_comp), 0, true);
- return 0;
-}
-
-// Flatten a scene by using a crtc which works concurrent with
-// the one driving the display.
-int DrmDisplayCompositor::FlattenConcurrent(DrmConnector *writeback_conn) {
- ALOGV("FlattenConcurrent by using an unused crtc/display");
- int ret = 0;
- DrmDisplayCompositor drmdisplaycompositor;
- ret = drmdisplaycompositor.Init(resource_manager_, writeback_conn->display());
- if (ret) {
- ALOGE("Failed to init drmdisplaycompositor = %d", ret);
- return ret;
- }
- // Copy of the active_composition, needed because of two things:
- // 1) Not to hold the lock for the whole time we are accessing
- // active_composition
- // 2) It will be committed on a crtc that might not be on the same
- // dri node, so buffers need to be imported on the right node.
- std::unique_ptr<DrmDisplayComposition>
- copy_comp = drmdisplaycompositor.CreateInitializedComposition();
-
- // Writeback composition that will be committed to the display.
- std::unique_ptr<DrmDisplayComposition>
- writeback_comp = CreateInitializedComposition();
-
- if (!copy_comp || !writeback_comp)
- return -EINVAL;
- AutoLock lock(&lock_, __func__);
- ret = lock.Lock();
- if (ret)
- return ret;
- if (!IsFlatteningNeeded()) {
- ALOGV("Flattening is not needed");
- SetFlattening(FlatteningState::kNotNeeded);
- return -EALREADY;
- }
- DrmCrtc *crtc = active_composition_->crtc();
-
- std::vector<DrmHwcLayer> copy_layers;
- for (DrmHwcLayer &src_layer : active_composition_->layers()) {
- DrmHwcLayer copy;
- ret = copy.InitFromDrmHwcLayer(&src_layer,
- resource_manager_
- ->GetImporter(writeback_conn->display())
- .get());
- if (ret) {
- ALOGE("Failed to import buffer ret = %d", ret);
- return -EINVAL;
- }
- copy_layers.emplace_back(std::move(copy));
- }
- ret = copy_comp->SetLayers(copy_layers.data(), copy_layers.size(), true);
- if (ret) {
- ALOGE("Failed to set copy_comp layers");
- return ret;
- }
-
- lock.Unlock();
- DrmHwcLayer writeback_layer;
- ret = drmdisplaycompositor.FlattenOnDisplay(copy_comp, writeback_conn,
- mode_.mode, &writeback_layer);
- if (ret) {
- ALOGE("Failed to flatten on display ret = %d", ret);
- return ret;
- }
-
- DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kLayer, nullptr,
- crtc);
- for (auto &drmplane : resource_manager_->GetDrmDevice(display_)->planes()) {
- if (!drmplane->GetCrtcSupported(*crtc))
- continue;
- if (drmplane->type() == DRM_PLANE_TYPE_PRIMARY)
- squashed_comp.set_plane(drmplane.get());
- else
- writeback_comp->AddPlaneDisable(drmplane.get());
- }
- writeback_comp->layers().emplace_back();
- DrmHwcLayer &next_layer = writeback_comp->layers().back();
- next_layer.sf_handle = writeback_layer.get_usable_handle();
- next_layer.blending = DrmHwcBlending::kPreMult;
- next_layer.source_crop = {0, 0, (float)mode_.mode.h_display(),
- (float)mode_.mode.v_display()};
- next_layer.display_frame = {0, 0, (int)mode_.mode.h_display(),
- (int)mode_.mode.v_display()};
- ret = next_layer.ImportBuffer(resource_manager_->GetImporter(display_).get());
- if (ret) {
- ALOGE("Failed to import framebuffer for display %d", ret);
- return ret;
- }
- squashed_comp.source_layers().push_back(0);
- ret = writeback_comp->AddPlaneComposition(std::move(squashed_comp));
- if (ret) {
- ALOGE("Failed to add plane composition %d", ret);
- return ret;
- }
- ApplyFrame(std::move(writeback_comp), 0, true);
- return ret;
-}
-
int DrmDisplayCompositor::FlattenActiveComposition() {
- DrmConnector *writeback_conn = resource_manager_->AvailableWritebackConnector(
- display_);
- if (!active_composition_ || !writeback_conn) {
- // Try to fallback to GPU composition on client, since it is more
- // power-efficient than composition on device side
- return FlattenOnClient();
- }
-
- if (writeback_conn->display() != display_) {
- SetFlattening(FlatteningState::kConcurrent);
- return FlattenConcurrent(writeback_conn);
- }
-
- SetFlattening(FlatteningState::kSerial);
- return FlattenSerial(writeback_conn);
+ return FlattenOnClient();
}
bool DrmDisplayCompositor::CountdownExpired() const {