[PATCH hwc v2 17/18] drm_hwcomposer: Flatten scene synchronously
Alexandru Gheorghe
alexandru-cosmin.gheorghe at arm.com
Wed Apr 11 15:22:28 UTC 2018
Flatten scene on the same CRTC as the one driving the display.
The active composition is played back to the display with a buffer
attached to the writeback connector.
Then we build a composition that has only one plane enabled and that
uses the result of the writeback as the input.
Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe at arm.com>
---
drmdisplaycompositor.cpp | 203 +++++++++++++++++++++++++++++++++++++++++++++--
drmdisplaycompositor.h | 7 +-
2 files changed, 204 insertions(+), 6 deletions(-)
diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp
index e535e8a..cb670e6 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -36,6 +36,7 @@
#include "drmplane.h"
#include "drmresources.h"
#include "glworker.h"
+static const uint32_t kWaitWritebackFence = 100; // ms
namespace android {
@@ -523,7 +524,9 @@ int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) {
}
int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
- bool test_only) {
+ bool test_only,
+ DrmDisplayComposition *writeback_comp,
+ DrmConnector *writeback_conn) {
ATRACE_CALL();
int ret = 0;
@@ -532,6 +535,7 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
std::vector<DrmCompositionPlane> &comp_planes =
display_comp->composition_planes();
uint64_t out_fences[drm_->crtcs().size()];
+ int writeback_fence = -1;
DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
if (!connector) {
@@ -550,9 +554,37 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
return -ENOMEM;
}
+ if (writeback_comp != NULL) {
+ if (writeback_conn == NULL)
+ return -EINVAL;
+ 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_comp->layers().size() != 1) {
+ ALOGE("Invalid number of layers for writeback composition");
+ return -EINVAL;
+ }
+ ret = drmModeAtomicAddProperty(
+ pset, writeback_conn->id(), writeback_conn->writeback_fb_id().id(),
+ writeback_comp->layers().back().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;
+ }
+ }
if (crtc->out_fence_ptr_property().id() != 0) {
- ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->out_fence_ptr_property().id(),
- (uint64_t) &out_fences[crtc->pipe()]);
+ ret = drmModeAtomicAddProperty(pset, crtc->id(),
+ crtc->out_fence_ptr_property().id(),
+ (uint64_t)&out_fences[crtc->pipe()]);
if (ret < 0) {
ALOGE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
drmModeAtomicFree(pset);
@@ -580,6 +612,15 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
}
}
+ if (writeback_conn != NULL) {
+ ret = drmModeAtomicAddProperty(pset, writeback_conn->id(),
+ writeback_conn->crtc_id_property().id(),
+ crtc->id());
+ if (ret < 0) {
+ ALOGE("Failed to attach writeback");
+ }
+ }
+
for (DrmCompositionPlane &comp_plane : comp_planes) {
DrmPlane *plane = comp_plane.plane();
DrmCrtc *crtc = comp_plane.crtc();
@@ -729,8 +770,18 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
if (!ret) {
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
- if (test_only)
+ if (test_only) {
flags |= DRM_MODE_ATOMIC_TEST_ONLY;
+ } else {
+ if (writeback_comp != NULL) {
+ if (!CountdownExpired() && active_composition_) {
+ ALOGE("Writeback composition not needed, abort commit");
+ drmModeAtomicFree(pset);
+ return -EINVAL;
+ };
+ flags |= DRM_MODE_ATOMIC_NONBLOCK;
+ }
+ }
ret = drmModeAtomicCommit(drm_->fd(), pset, flags, drm_);
if (ret) {
@@ -769,6 +820,13 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp,
if (crtc->out_fence_ptr_property().id()) {
display_comp->set_out_fence((int) out_fences[crtc->pipe()]);
}
+ if (writeback_fence >= 0) {
+ if (writeback_comp->layers().size() != 1) {
+ ALOGE("Invalid numbers of layer for writeback_comp");
+ return -EINVAL;
+ }
+ writeback_comp->layers()[0].acquire_fence.Set(writeback_fence);
+ }
return ret;
}
@@ -837,6 +895,8 @@ void DrmDisplayCompositor::ApplyFrame(
if (active_composition_)
active_composition_->SignalCompositionDone();
active_composition_.swap(composition);
+ flatten_countdown_ = FLATTEN_COUNTDOWN_INIT;
+ vsync_worker_.VSyncControl(!writeback);
}
}
@@ -913,8 +973,141 @@ int DrmDisplayCompositor::ApplyComposition(
return ret;
}
+int DrmDisplayCompositor::WritebackComposite(DrmDisplayComposition *src,
+ DrmDisplayComposition *dst,
+ DrmConnector *writeback_conn) {
+ int ret = 0;
+ if (src == NULL || dst == NULL)
+ return -EINVAL;
+ std::vector<DrmCompositionPlane> &src_planes = src->composition_planes();
+ DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kPrecomp, NULL,
+ src->crtc());
+ for (DrmCompositionPlane &comp_plane : src_planes) {
+ if (comp_plane.plane() == NULL) {
+ ALOGE("Skipping squash all because of NULL plane");
+ ret = -EINVAL;
+ }
+ if (!squashed_comp.plane() &&
+ comp_plane.plane()->type() == DRM_PLANE_TYPE_PRIMARY)
+ squashed_comp.set_plane(comp_plane.plane());
+ else
+ dst->AddPlaneDisable(comp_plane.plane());
+ }
+
+ DrmFramebuffer *writeback_fb = NULL;
+ AutoLock lock(&lock_, __FUNCTION__);
+ if ((ret = lock.Lock()))
+ return ret;
+ writeback_fb = &framebuffers_[framebuffer_index_];
+ framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS;
+ ret = PrepareFramebuffer(*writeback_fb, dst, mode_.mode.h_display(),
+ mode_.mode.v_display());
+ if (ret) {
+ ALOGE("Failed to prepare destination buffer");
+ return ret;
+ }
+ lock.Unlock();
+ ret = CommitFrame(src, true, dst, writeback_conn);
+ if (ret) {
+ ALOGE("Atomic check failed");
+ return ret;
+ }
+ if ((ret = lock.Lock()))
+ return ret;
+ if (!CountdownExpired() && active_composition_) {
+ ALOGE("Writeback composition not needed abort");
+ return -EINVAL;
+ }
+ ret = CommitFrame(src, false, dst, writeback_conn);
+ lock.Unlock();
+ if (ret || dst->layers().size() != 1) {
+ ALOGE("Failed to flatten scene using writeback");
+ return -EINVAL;
+ }
+ squashed_comp.source_layers().push_back(0);
+ ret =
+ sync_wait(dst->layers()[0].acquire_fence.Release(), kWaitWritebackFence);
+ if (ret) {
+ ALOGE("Failed to wait on writeback fence");
+ return ret;
+ }
+ ret = dst->AddPlaneComposition(std::move(squashed_comp));
+ if (ret) {
+ ALOGE("Failed to add flatten scene");
+ return ret;
+ }
+ ret = dst->FinalizeComposition();
+ if (ret) {
+ ALOGE("Failed to finalize composition");
+ return ret;
+ }
+ return 0;
+}
+
+int DrmDisplayCompositor::FlattenSynchronously(DrmConnector *writeback_conn) {
+ if (writeback_conn->display() != display_) {
+ ALOGE("Cannot flatten synchronously on different display");
+ return -EINVAL;
+ }
+ ALOGI("FlattenSynchronously using the same display");
+ int ret = 0;
+ /* Flattened composition with only one layer that is built
+ * using the writeback connector
+ */
+ std::unique_ptr<DrmDisplayComposition> writeback_comp =
+ CreateInitializedComposition();
+ /* Copy of the active_composition_, we need a copy because
+ * if we use the active composition we have to hold the lock
+ * for the entire sequence of flattening.
+ */
+ std::unique_ptr<DrmDisplayComposition> copy_comp =
+ CreateInitializedComposition();
+
+ if (!copy_comp || !writeback_comp)
+ return -EINVAL;
+ AutoLock lock(&lock_, __FUNCTION__);
+ if ((ret = lock.Lock()))
+ return ret;
+ if (CountdownExpired()) {
+ ret = copy_comp->CopyLayers(active_composition_.get());
+ if (ret)
+ return ret;
+ copy_comp->CopyCompPlanes(active_composition_.get());
+ } else {
+ return -EINVAL;
+ }
+ lock.Unlock();
+ ret =
+ WritebackComposite(copy_comp.get(), writeback_comp.get(), writeback_conn);
+ if (ret) {
+ ALOGE("Failed to prepare writebackScene");
+ return ret;
+ }
+
+ ApplyFrame(std::move(writeback_comp), 0, true);
+ return 0;
+}
+
int DrmDisplayCompositor::FlattenScene() {
- return -EINVAL;
+ DrmConnector *writeback_conn =
+ drm_->resource_manager()->AvailableWritebackConnector(display_);
+ if (!active_composition_ || !writeback_conn)
+ return -EINVAL;
+ std::vector<DrmCompositionPlane> &src_planes =
+ active_composition_->composition_planes();
+ size_t src_planes_with_layer = std::count_if(
+ src_planes.begin(), src_planes.end(), [](DrmCompositionPlane &p) {
+ return p.type() != DrmCompositionPlane::Type::kDisable;
+ });
+
+ if (src_planes_with_layer <= 1)
+ return -EALREADY;
+
+ if (writeback_conn->display() == display_) {
+ return FlattenSynchronously(writeback_conn);
+ }
+
+ return 0;
}
int DrmDisplayCompositor::SquashAll() {
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 26201b9..4cc4a5e 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -125,7 +125,9 @@ class DrmDisplayCompositor {
int ApplySquash(DrmDisplayComposition *display_comp);
int ApplyPreComposite(DrmDisplayComposition *display_comp);
int PrepareFrame(DrmDisplayComposition *display_comp);
- int CommitFrame(DrmDisplayComposition *display_comp, bool test_only);
+ int CommitFrame(DrmDisplayComposition *display_comp, bool test_only,
+ DrmDisplayComposition *writeback_comp = NULL,
+ DrmConnector *writeback_conn = NULL);
int SquashFrame(DrmDisplayComposition *src, DrmDisplayComposition *dst);
int ApplyDpms(DrmDisplayComposition *display_comp);
int DisablePlanes(DrmDisplayComposition *display_comp);
@@ -134,7 +136,10 @@ class DrmDisplayCompositor {
void ApplyFrame(std::unique_ptr<DrmDisplayComposition> composition,
int status, bool writeback = false);
int FlattenScene();
+ int FlattenSynchronously(DrmConnector *writeback_conn);
+ int WritebackComposite(DrmDisplayComposition *src, DrmDisplayComposition *dst,
+ DrmConnector *writeback_conn);
bool CountdownExpired() const;
std::tuple<int, uint32_t> CreateModeBlob(const DrmMode &mode);
--
2.7.4
More information about the dri-devel
mailing list