diff options
author | Sean Paul <seanpaul@chromium.org> | 2017-02-28 13:17:34 -0500 |
---|---|---|
committer | Robert Foss <robert.foss@collabora.com> | 2017-03-22 14:38:43 -0400 |
commit | 172b45221148299b57ea59b861d754adc1e270f4 (patch) | |
tree | 4181a90ce567b7416a70ac118169f443e42c90b0 | |
parent | d4c0ad6a29646f6882ceadb84b24ae7c41b5234a (diff) | |
download | drm_hwcomposer-172b45221148299b57ea59b861d754adc1e270f4.tar.gz drm_hwcomposer-172b45221148299b57ea59b861d754adc1e270f4.tar.xz |
drm_hwcomposer: Remove threading
Since HWC2 doesn't require the use of threads to implement correct
synchronization, remove some of these threads.
BUG=None
TEST=Tested on Qemu+drm_hwcomposer
Change-Id: Ia1cfb44648e0d85547cdff2e1a2f5e034bf5f110
Signed-off-by: Robert Foss <robert.foss@collabora.com>
-rw-r--r-- | Android.mk | 3 | ||||
-rw-r--r-- | drmcomposition.cpp | 166 | ||||
-rw-r--r-- | drmcomposition.h | 79 | ||||
-rw-r--r-- | drmcompositor.cpp | 106 | ||||
-rw-r--r-- | drmcompositor.h | 56 | ||||
-rw-r--r-- | drmcompositorworker.cpp | 87 | ||||
-rw-r--r-- | drmcompositorworker.h | 41 | ||||
-rw-r--r-- | drmdisplaycomposition.cpp | 1 | ||||
-rw-r--r-- | drmdisplaycomposition.h | 10 | ||||
-rw-r--r-- | drmdisplaycompositor.cpp | 198 | ||||
-rw-r--r-- | drmdisplaycompositor.h | 36 | ||||
-rw-r--r-- | drmeventlistener.cpp | 3 | ||||
-rw-r--r-- | drmresources.cpp | 54 | ||||
-rw-r--r-- | drmresources.h | 5 | ||||
-rw-r--r-- | glworker.cpp | 52 | ||||
-rw-r--r-- | glworker.h | 10 | ||||
-rw-r--r-- | hwcomposer.cpp | 840 |
17 files changed, 90 insertions, 1657 deletions
@@ -40,9 +40,6 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := \ autolock.cpp \ drmresources.cpp \ - drmcomposition.cpp \ - drmcompositor.cpp \ - drmcompositorworker.cpp \ drmconnector.cpp \ drmcrtc.cpp \ drmdisplaycomposition.cpp \ diff --git a/drmcomposition.cpp b/drmcomposition.cpp deleted file mode 100644 index 1aaf920..0000000 --- a/drmcomposition.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#define LOG_TAG "hwc-drm-composition" - -#include "drmcomposition.h" -#include "drmcrtc.h" -#include "drmplane.h" -#include "drmresources.h" -#include "platform.h" - -#include <stdlib.h> - -#include <cutils/log.h> -#include <cutils/properties.h> -#include <sw_sync.h> -#include <sync/sync.h> - -namespace android { - -DrmComposition::DrmComposition(DrmResources *drm, Importer *importer, - Planner *planner) - : drm_(drm), importer_(importer), planner_(planner) { - char use_overlay_planes_prop[PROPERTY_VALUE_MAX]; - property_get("hwc.drm.use_overlay_planes", use_overlay_planes_prop, "1"); - bool use_overlay_planes = atoi(use_overlay_planes_prop); - - for (auto &plane : drm->planes()) { - if (plane->type() == DRM_PLANE_TYPE_PRIMARY) - primary_planes_.push_back(plane.get()); - else if (use_overlay_planes && plane->type() == DRM_PLANE_TYPE_OVERLAY) - overlay_planes_.push_back(plane.get()); - } -} - -int DrmComposition::Init(uint64_t frame_no) { - for (auto &conn : drm_->connectors()) { - int display = conn->display(); - composition_map_[display].reset(new DrmDisplayComposition()); - if (!composition_map_[display]) { - ALOGE("Failed to allocate new display composition\n"); - return -ENOMEM; - } - - // If the display hasn't been modeset yet, this will be NULL - DrmCrtc *crtc = drm_->GetCrtcForDisplay(display); - - int ret = composition_map_[display]->Init(drm_, crtc, importer_, planner_, - frame_no); - if (ret) { - ALOGE("Failed to init display composition for %d", display); - return ret; - } - } - return 0; -} - -int DrmComposition::SetLayers(size_t num_displays, - DrmCompositionDisplayLayersMap *maps) { - int ret = 0; - for (size_t display_index = 0; display_index < num_displays; - display_index++) { - DrmCompositionDisplayLayersMap &map = maps[display_index]; - int display = map.display; - - if (!drm_->GetConnectorForDisplay(display)) { - ALOGE("Invalid display given to SetLayers %d", display); - continue; - } - - ret = composition_map_[display]->SetLayers( - map.layers.data(), map.layers.size(), map.geometry_changed); - if (ret) - return ret; - } - - return 0; -} - -int DrmComposition::SetDpmsMode(int display, uint32_t dpms_mode) { - return composition_map_[display]->SetDpmsMode(dpms_mode); -} - -int DrmComposition::SetDisplayMode(int display, const DrmMode &display_mode) { - return composition_map_[display]->SetDisplayMode(display_mode); -} - -std::unique_ptr<DrmDisplayComposition> DrmComposition::TakeDisplayComposition( - int display) { - return std::move(composition_map_[display]); -} - -int DrmComposition::Plan(std::map<int, DrmDisplayCompositor> &compositor_map) { - int ret = 0; - for (auto &conn : drm_->connectors()) { - int display = conn->display(); - DrmDisplayComposition *comp = GetDisplayComposition(display); - ret = comp->Plan(compositor_map[display].squash_state(), &primary_planes_, - &overlay_planes_); - if (ret) { - ALOGE("Failed to plan composition for dislay %d", display); - return ret; - } - } - - return 0; -} - -int DrmComposition::DisableUnusedPlanes() { - for (auto &conn : drm_->connectors()) { - int display = conn->display(); - DrmDisplayComposition *comp = GetDisplayComposition(display); - - /* - * Leave empty compositions alone - * TODO: re-visit this and potentially disable leftover planes after the - * active compositions have gobbled up all they can - */ - if (comp->type() == DRM_COMPOSITION_TYPE_EMPTY || - comp->type() == DRM_COMPOSITION_TYPE_MODESET) - continue; - - DrmCrtc *crtc = drm_->GetCrtcForDisplay(display); - if (!crtc) { - ALOGE("Failed to find crtc for display %d", display); - continue; - } - - for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin(); - iter != primary_planes_.end(); ++iter) { - if ((*iter)->GetCrtcSupported(*crtc)) { - comp->AddPlaneDisable(*iter); - primary_planes_.erase(iter); - break; - } - } - for (std::vector<DrmPlane *>::iterator iter = overlay_planes_.begin(); - iter != overlay_planes_.end();) { - if ((*iter)->GetCrtcSupported(*crtc)) { - comp->AddPlaneDisable(*iter); - iter = overlay_planes_.erase(iter); - } else { - iter++; - } - } - } - return 0; -} - -DrmDisplayComposition *DrmComposition::GetDisplayComposition(int display) { - return composition_map_[display].get(); -} -} diff --git a/drmcomposition.h b/drmcomposition.h deleted file mode 100644 index eae8cde..0000000 --- a/drmcomposition.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef ANDROID_DRM_COMPOSITION_H_ -#define ANDROID_DRM_COMPOSITION_H_ - -#include "drmhwcomposer.h" -#include "drmdisplaycomposition.h" -#include "drmplane.h" -#include "platform.h" - -#include <map> -#include <vector> - -#include <hardware/hardware.h> -#include <hardware/hwcomposer.h> - -namespace android { - -class DrmDisplayCompositor; - -struct DrmCompositionDisplayLayersMap { - int display; - bool geometry_changed = true; - std::vector<DrmHwcLayer> layers; - - DrmCompositionDisplayLayersMap() = default; - DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) = - default; -}; - -class DrmComposition { - public: - DrmComposition(DrmResources *drm, Importer *importer, Planner *planner); - - int Init(uint64_t frame_no); - - int SetLayers(size_t num_displays, DrmCompositionDisplayLayersMap *maps); - int SetDpmsMode(int display, uint32_t dpms_mode); - int SetDisplayMode(int display, const DrmMode &display_mode); - - std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display); - DrmDisplayComposition *GetDisplayComposition(int display); - - int Plan(std::map<int, DrmDisplayCompositor> &compositor_map); - int DisableUnusedPlanes(); - - private: - DrmComposition(const DrmComposition &) = delete; - - DrmResources *drm_; - Importer *importer_; - Planner *planner_; - - std::vector<DrmPlane *> primary_planes_; - std::vector<DrmPlane *> overlay_planes_; - - /* - * This _must_ be read-only after it's passed to QueueComposition. Otherwise - * locking is required to maintain consistency across the compositor threads. - */ - std::map<int, std::unique_ptr<DrmDisplayComposition>> composition_map_; -}; -} - -#endif // ANDROID_DRM_COMPOSITION_H_ diff --git a/drmcompositor.cpp b/drmcompositor.cpp deleted file mode 100644 index c1f3ed8..0000000 --- a/drmcompositor.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#define LOG_TAG "hwc-drm-compositor" - -#include "drmcompositor.h" -#include "drmdisplaycompositor.h" -#include "drmresources.h" -#include "platform.h" - -#include <sstream> -#include <stdlib.h> - -#include <cutils/log.h> - -namespace android { - -DrmCompositor::DrmCompositor(DrmResources *drm) : drm_(drm), frame_no_(0) { -} - -DrmCompositor::~DrmCompositor() { -} - -int DrmCompositor::Init() { - for (auto &conn : drm_->connectors()) { - int display = conn->display(); - int ret = compositor_map_[display].Init(drm_, display); - if (ret) { - ALOGE("Failed to initialize display compositor for %d", display); - return ret; - } - } - planner_ = Planner::CreateInstance(drm_); - if (!planner_) { - ALOGE("Failed to create planner instance for composition"); - return -ENOMEM; - } - - return 0; -} - -std::unique_ptr<DrmComposition> DrmCompositor::CreateComposition( - Importer *importer) { - std::unique_ptr<DrmComposition> composition( - new DrmComposition(drm_, importer, planner_.get())); - int ret = composition->Init(++frame_no_); - if (ret) { - ALOGE("Failed to initialize drm composition %d", ret); - return nullptr; - } - return composition; -} - -int DrmCompositor::QueueComposition( - std::unique_ptr<DrmComposition> composition) { - int ret; - - ret = composition->Plan(compositor_map_); - if (ret) - return ret; - - ret = composition->DisableUnusedPlanes(); - if (ret) - return ret; - - for (auto &conn : drm_->connectors()) { - int display = conn->display(); - int ret = compositor_map_[display].QueueComposition( - composition->TakeDisplayComposition(display)); - if (ret) { - ALOGE("Failed to queue composition for display %d (%d)", display, ret); - return ret; - } - } - - return 0; -} - -int DrmCompositor::Composite() { - /* - * This shouldn't be called, we should be calling Composite() on the display - * compositors directly. - */ - ALOGE("Calling base drm compositor Composite() function"); - return -EINVAL; -} - -void DrmCompositor::Dump(std::ostringstream *out) const { - *out << "DrmCompositor stats:\n"; - for (auto &conn : drm_->connectors()) - compositor_map_[conn->display()].Dump(out); -} -} diff --git a/drmcompositor.h b/drmcompositor.h deleted file mode 100644 index 19271b5..0000000 --- a/drmcompositor.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef ANDROID_DRM_COMPOSITOR_H_ -#define ANDROID_DRM_COMPOSITOR_H_ - -#include "drmcomposition.h" -#include "drmdisplaycompositor.h" -#include "platform.h" - -#include <map> -#include <memory> -#include <sstream> - -namespace android { - -class DrmCompositor { - public: - DrmCompositor(DrmResources *drm); - ~DrmCompositor(); - - int Init(); - - std::unique_ptr<DrmComposition> CreateComposition(Importer *importer); - - int QueueComposition(std::unique_ptr<DrmComposition> composition); - int Composite(); - void Dump(std::ostringstream *out) const; - - private: - DrmCompositor(const DrmCompositor &) = delete; - - DrmResources *drm_; - std::unique_ptr<Planner> planner_; - - uint64_t frame_no_; - - // mutable for Dump() propagation - mutable std::map<int, DrmDisplayCompositor> compositor_map_; -}; -} - -#endif // ANDROID_DRM_COMPOSITOR_H_ diff --git a/drmcompositorworker.cpp b/drmcompositorworker.cpp deleted file mode 100644 index 9804322..0000000 --- a/drmcompositorworker.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#define LOG_TAG "hwc-drm-compositor-worker" - -#include "drmdisplaycompositor.h" -#include "drmcompositorworker.h" -#include "worker.h" - -#include <stdlib.h> - -#include <cutils/log.h> -#include <hardware/hardware.h> - -namespace android { - -static const int64_t kSquashWait = 500000000LL; - -DrmCompositorWorker::DrmCompositorWorker(DrmDisplayCompositor *compositor) - : Worker("drm-compositor", HAL_PRIORITY_URGENT_DISPLAY), - compositor_(compositor) { -} - -DrmCompositorWorker::~DrmCompositorWorker() { -} - -int DrmCompositorWorker::Init() { - return InitWorker(); -} - -void DrmCompositorWorker::Routine() { - int ret; - if (!compositor_->HaveQueuedComposites()) { - ret = Lock(); - if (ret) { - ALOGE("Failed to lock worker, %d", ret); - return; - } - - // Only use a timeout if we didn't do a SquashAll last time. This will - // prevent wait_ret == -ETIMEDOUT which would trigger a SquashAll and be a - // pointless drain on resources. - int wait_ret = did_squash_all_ ? WaitForSignalOrExitLocked() - : WaitForSignalOrExitLocked(kSquashWait); - - ret = Unlock(); - if (ret) { - ALOGE("Failed to unlock worker, %d", ret); - return; - } - - switch (wait_ret) { - case 0: - break; - case -EINTR: - return; - case -ETIMEDOUT: - ret = compositor_->SquashAll(); - if (ret) - ALOGE("Failed to squash all %d", ret); - did_squash_all_ = true; - return; - default: - ALOGE("Failed to wait for signal, %d", wait_ret); - return; - } - } - - ret = compositor_->Composite(); - if (ret) - ALOGE("Failed to composite! %d", ret); - did_squash_all_ = false; -} -} diff --git a/drmcompositorworker.h b/drmcompositorworker.h deleted file mode 100644 index 731bc65..0000000 --- a/drmcompositorworker.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#ifndef ANDROID_DRM_COMPOSITOR_WORKER_H_ -#define ANDROID_DRM_COMPOSITOR_WORKER_H_ - -#include "worker.h" - -namespace android { - -class DrmDisplayCompositor; - -class DrmCompositorWorker : public Worker { - public: - DrmCompositorWorker(DrmDisplayCompositor *compositor); - ~DrmCompositorWorker() override; - - int Init(); - - protected: - void Routine() override; - - DrmDisplayCompositor *compositor_; - bool did_squash_all_ = false; -}; -} - -#endif diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp index 293160b..bc1d668 100644 --- a/drmdisplaycomposition.cpp +++ b/drmdisplaycomposition.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "hwc-drm-display-composition" #include "drmdisplaycomposition.h" +#include "drmdisplaycompositor.h" #include "drmcrtc.h" #include "drmplane.h" #include "drmresources.h" diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h index 13da19d..b165adc 100644 --- a/drmdisplaycomposition.h +++ b/drmdisplaycomposition.h @@ -42,6 +42,16 @@ enum DrmCompositionType { DRM_COMPOSITION_TYPE_MODESET, }; +struct DrmCompositionDisplayLayersMap { + int display; + bool geometry_changed = true; + std::vector<DrmHwcLayer> layers; + + DrmCompositionDisplayLayersMap() = default; + DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) = + default; +}; + struct DrmCompositionRegion { DrmHwcRect<int> frame; std::vector<size_t> source_layers; diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp index bc0adbc..bd670cf 100644 --- a/drmdisplaycompositor.cpp +++ b/drmdisplaycompositor.cpp @@ -37,8 +37,6 @@ #include "drmresources.h" #include "glworker.h" -#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 2 - namespace android { void SquashState::Init(DrmHwcLayer *layers, size_t num_layers) { @@ -176,67 +174,9 @@ static bool UsesSquash(const std::vector<DrmCompositionPlane> &comp_planes) { }); } -DrmDisplayCompositor::FrameWorker::FrameWorker(DrmDisplayCompositor *compositor) - : Worker("frame-worker", HAL_PRIORITY_URGENT_DISPLAY), - compositor_(compositor) { -} - -DrmDisplayCompositor::FrameWorker::~FrameWorker() { -} - -int DrmDisplayCompositor::FrameWorker::Init() { - return InitWorker(); -} - -void DrmDisplayCompositor::FrameWorker::QueueFrame( - std::unique_ptr<DrmDisplayComposition> composition, int status) { - Lock(); - FrameState frame; - frame.composition = std::move(composition); - frame.status = status; - frame_queue_.push(std::move(frame)); - SignalLocked(); - Unlock(); -} - -void DrmDisplayCompositor::FrameWorker::Routine() { - int ret = Lock(); - if (ret) { - ALOGE("Failed to lock worker, %d", ret); - return; - } - - int wait_ret = 0; - if (frame_queue_.empty()) { - wait_ret = WaitForSignalOrExitLocked(); - } - - FrameState frame; - if (!frame_queue_.empty()) { - frame = std::move(frame_queue_.front()); - frame_queue_.pop(); - } - - ret = Unlock(); - if (ret) { - ALOGE("Failed to unlock worker, %d", ret); - return; - } - - if (wait_ret == -EINTR) { - return; - } else if (wait_ret) { - ALOGE("Failed to wait for signal, %d", wait_ret); - return; - } - compositor_->ApplyFrame(std::move(frame.composition), frame.status); -} - DrmDisplayCompositor::DrmDisplayCompositor() : drm_(NULL), display_(-1), - worker_(this), - frame_worker_(this), initialized_(false), active_(false), use_hw_overlays_(true), @@ -254,9 +194,6 @@ DrmDisplayCompositor::~DrmDisplayCompositor() { if (!initialized_) return; - worker_.Exit(); - frame_worker_.Exit(); - int ret = pthread_mutex_lock(&lock_); if (ret) ALOGE("Failed to acquire compositor lock %d", ret); @@ -266,10 +203,6 @@ DrmDisplayCompositor::~DrmDisplayCompositor() { if (mode_.old_blob_id) drm_->DestroyPropertyBlob(mode_.old_blob_id); - while (!composite_queue_.empty()) { - composite_queue_.front().reset(); - composite_queue_.pop(); - } active_composition_.reset(); ret = pthread_mutex_unlock(&lock_); @@ -288,18 +221,6 @@ int DrmDisplayCompositor::Init(DrmResources *drm, int display) { ALOGE("Failed to initialize drm compositor lock %d\n", ret); return ret; } - ret = worker_.Init(); - if (ret) { - pthread_mutex_destroy(&lock_); - ALOGE("Failed to initialize compositor worker %d\n", ret); - return ret; - } - ret = frame_worker_.Init(); - if (ret) { - pthread_mutex_destroy(&lock_); - ALOGE("Failed to initialize frame worker %d\n", ret); - return ret; - } initialized_ = true; return 0; @@ -310,55 +231,6 @@ std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition() return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition()); } -int DrmDisplayCompositor::QueueComposition( - std::unique_ptr<DrmDisplayComposition> composition) { - switch (composition->type()) { - case DRM_COMPOSITION_TYPE_FRAME: - if (!active_) - return -ENODEV; - break; - case DRM_COMPOSITION_TYPE_DPMS: - /* - * Update the state as soon as we get it so we can start/stop queuing - * frames asap. - */ - active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON); - break; - case DRM_COMPOSITION_TYPE_MODESET: - break; - case DRM_COMPOSITION_TYPE_EMPTY: - return 0; - default: - ALOGE("Unknown composition type %d/%d", composition->type(), display_); - return -ENOENT; - } - - int ret = pthread_mutex_lock(&lock_); - if (ret) { - ALOGE("Failed to acquire compositor lock %d", ret); - return ret; - } - - // Block the queue if it gets too large. Otherwise, SurfaceFlinger will start - // to eat our buffer handles when we get about 1 second behind. - while (composite_queue_.size() >= DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH) { - pthread_mutex_unlock(&lock_); - sched_yield(); - pthread_mutex_lock(&lock_); - } - - composite_queue_.push(std::move(composition)); - - ret = pthread_mutex_unlock(&lock_); - if (ret) { - ALOGE("Failed to release compositor lock %d", ret); - return ret; - } - - worker_.Signal(); - return 0; -} - std::tuple<uint32_t, uint32_t, int> DrmDisplayCompositor::GetActiveModeResolution() { DrmConnector *connector = drm_->GetConnectorForDisplay(display_); @@ -523,6 +395,15 @@ int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) { std::vector<DrmCompositionRegion> &pre_comp_regions = display_comp->pre_comp_regions(); + if (!pre_compositor_) { + pre_compositor_.reset(new GLWorkerCompositor()); + int ret = pre_compositor_->Init(); + if (ret) { + ALOGE("Failed to initialize OpenGL compositor %d", ret); + return ret; + } + } + int squash_layer_index = -1; if (squash_regions.size() > 0) { squash_framebuffer_index_ = (squash_framebuffer_index_ + 1) % 2; @@ -915,41 +796,9 @@ void DrmDisplayCompositor::ApplyFrame( ALOGE("Failed to release lock for active_composition swap"); } -int DrmDisplayCompositor::Composite() { - ATRACE_CALL(); - - if (!pre_compositor_) { - pre_compositor_.reset(new GLWorkerCompositor()); - int ret = pre_compositor_->Init(); - if (ret) { - ALOGE("Failed to initialize OpenGL compositor %d", ret); - return ret; - } - } - - int ret = pthread_mutex_lock(&lock_); - if (ret) { - ALOGE("Failed to acquire compositor lock %d", ret); - return ret; - } - if (composite_queue_.empty()) { - ret = pthread_mutex_unlock(&lock_); - if (ret) - ALOGE("Failed to release compositor lock %d", ret); - return ret; - } - - std::unique_ptr<DrmDisplayComposition> composition( - std::move(composite_queue_.front())); - - composite_queue_.pop(); - - ret = pthread_mutex_unlock(&lock_); - if (ret) { - ALOGE("Failed to release compositor lock %d", ret); - return ret; - } - +int DrmDisplayCompositor::ApplyComposition( + std::unique_ptr<DrmDisplayComposition> composition) { + int ret = 0; switch (composition->type()) { case DRM_COMPOSITION_TYPE_FRAME: ret = PrepareFrame(composition.get()); @@ -968,7 +817,7 @@ int DrmDisplayCompositor::Composite() { } // If use_hw_overlays_ is false, we can't use hardware to composite the - // frame. So squash all layers into a single composition and queue that + // frame. So squash all layers into a single composition and apply that // instead. if (!use_hw_overlays_) { std::unique_ptr<DrmDisplayComposition> squashed = CreateComposition(); @@ -984,9 +833,10 @@ int DrmDisplayCompositor::Composite() { return ret; } } - frame_worker_.QueueFrame(std::move(composition), ret); + ApplyFrame(std::move(composition), ret); break; case DRM_COMPOSITION_TYPE_DPMS: + active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON); ret = ApplyDpms(composition.get()); if (ret) ALOGE("Failed to apply dpms for display %d", display_); @@ -1010,24 +860,6 @@ int DrmDisplayCompositor::Composite() { return ret; } -bool DrmDisplayCompositor::HaveQueuedComposites() const { - int ret = pthread_mutex_lock(&lock_); - if (ret) { - ALOGE("Failed to acquire compositor lock %d", ret); - return false; - } - - bool empty_ret = !composite_queue_.empty(); - - ret = pthread_mutex_unlock(&lock_); - if (ret) { - ALOGE("Failed to release compositor lock %d", ret); - return false; - } - - return empty_ret; -} - int DrmDisplayCompositor::SquashAll() { AutoLock lock(&lock_, "compositor"); int ret = lock.Lock(); diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h index 9487cac..f1965fb 100644 --- a/drmdisplaycompositor.h +++ b/drmdisplaycompositor.h @@ -18,14 +18,12 @@ #define ANDROID_DRM_DISPLAY_COMPOSITOR_H_ #include "drmhwcomposer.h" -#include "drmcomposition.h" -#include "drmcompositorworker.h" +#include "drmdisplaycomposition.h" #include "drmframebuffer.h" #include "separate_rects.h" #include <pthread.h> #include <memory> -#include <queue> #include <sstream> #include <tuple> @@ -89,42 +87,18 @@ class DrmDisplayCompositor { int Init(DrmResources *drm, int display); std::unique_ptr<DrmDisplayComposition> CreateComposition() const; - int QueueComposition(std::unique_ptr<DrmDisplayComposition> composition); + int ApplyComposition(std::unique_ptr<DrmDisplayComposition> composition); int Composite(); int SquashAll(); void Dump(std::ostringstream *out) const; std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution(); - bool HaveQueuedComposites() const; - SquashState *squash_state() { return &squash_state_; } private: - struct FrameState { - std::unique_ptr<DrmDisplayComposition> composition; - int status = 0; - }; - - class FrameWorker : public Worker { - public: - FrameWorker(DrmDisplayCompositor *compositor); - ~FrameWorker() override; - - int Init(); - void QueueFrame(std::unique_ptr<DrmDisplayComposition> composition, - int status); - - protected: - void Routine() override; - - private: - DrmDisplayCompositor *compositor_; - std::queue<FrameState> frame_queue_; - }; - struct ModeState { bool needs_modeset = false; DrmMode mode; @@ -158,10 +132,6 @@ class DrmDisplayCompositor { DrmResources *drm_; int display_; - DrmCompositorWorker worker_; - FrameWorker frame_worker_; - - std::queue<std::unique_ptr<DrmDisplayComposition>> composite_queue_; std::unique_ptr<DrmDisplayComposition> active_composition_; bool initialized_; @@ -178,7 +148,7 @@ class DrmDisplayCompositor { int squash_framebuffer_index_; DrmFramebuffer squash_framebuffers_[2]; - // mutable since we need to acquire in HaveQueuedComposites + // mutable since we need to acquire in Dump() mutable pthread_mutex_t lock_; // State tracking progress since our last Dump(). These are mutable since diff --git a/drmeventlistener.cpp b/drmeventlistener.cpp index 1880549..049ace2 100644 --- a/drmeventlistener.cpp +++ b/drmeventlistener.cpp @@ -20,10 +20,13 @@ #include "drmresources.h" #include <assert.h> +#include <errno.h> #include <linux/netlink.h> #include <sys/socket.h> #include <cutils/log.h> +#include <hardware/hardware.h> +#include <hardware/hwcomposer.h> #include <xf86drm.h> namespace android { diff --git a/drmresources.cpp b/drmresources.cpp index 6b8ed03..762f5ef 100644 --- a/drmresources.cpp +++ b/drmresources.cpp @@ -35,7 +35,7 @@ namespace android { -DrmResources::DrmResources() : compositor_(this), event_listener_(this) { +DrmResources::DrmResources() : event_listener_(this) { } DrmResources::~DrmResources() { @@ -201,10 +201,6 @@ int DrmResources::Init() { if (ret) return ret; - ret = compositor_.Init(); - if (ret) - return ret; - ret = event_listener_.Init(); if (ret) { ALOGE("Can't initialize event listener %d", ret); @@ -333,54 +329,6 @@ int DrmResources::DestroyPropertyBlob(uint32_t blob_id) { return 0; } -int DrmResources::SetDisplayActiveMode(int display, const DrmMode &mode) { - std::unique_ptr<DrmComposition> comp(compositor_.CreateComposition(NULL)); - if (!comp) { - ALOGE("Failed to create composition for dpms on %d", display); - return -ENOMEM; - } - int ret = comp->SetDisplayMode(display, mode); - if (ret) { - ALOGE("Failed to add mode to composition on %d %d", display, ret); - return ret; - } - ret = compositor_.QueueComposition(std::move(comp)); - if (ret) { - ALOGE("Failed to queue dpms composition on %d %d", display, ret); - return ret; - } - return 0; -} - -int DrmResources::SetDpmsMode(int display, uint64_t mode) { - if (mode != DRM_MODE_DPMS_ON && mode != DRM_MODE_DPMS_OFF) { - ALOGE("Invalid dpms mode %" PRIu64, mode); - return -EINVAL; - } - - std::unique_ptr<DrmComposition> comp(compositor_.CreateComposition(NULL)); - if (!comp) { - ALOGE("Failed to create composition for dpms on %d", display); - return -ENOMEM; - } - int ret = comp->SetDpmsMode(display, mode); - if (ret) { - ALOGE("Failed to add dpms %" PRIu64 " to composition on %d %d", mode, - display, ret); - return ret; - } - ret = compositor_.QueueComposition(std::move(comp)); - if (ret) { - ALOGE("Failed to queue dpms composition on %d %d", display, ret); - return ret; - } - return 0; -} - -DrmCompositor *DrmResources::compositor() { - return &compositor_; -} - DrmEventListener *DrmResources::event_listener() { return &event_listener_; } diff --git a/drmresources.h b/drmresources.h index 011f87e..a2d8d16 100644 --- a/drmresources.h +++ b/drmresources.h @@ -17,7 +17,6 @@ #ifndef ANDROID_DRM_H_ #define ANDROID_DRM_H_ -#include "drmcompositor.h" #include "drmconnector.h" #include "drmcrtc.h" #include "drmencoder.h" @@ -58,7 +57,6 @@ class DrmResources { DrmConnector *GetConnectorForDisplay(int display) const; DrmCrtc *GetCrtcForDisplay(int display) const; DrmPlane *GetPlane(uint32_t id) const; - DrmCompositor *compositor(); DrmEventListener *event_listener(); int GetPlaneProperty(const DrmPlane &plane, const char *prop_name, @@ -69,8 +67,6 @@ class DrmResources { DrmProperty *property); uint32_t next_mode_id(); - int SetDisplayActiveMode(int display, const DrmMode &mode); - int SetDpmsMode(int display, uint64_t mode); int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id); int DestroyPropertyBlob(uint32_t blob_id); @@ -89,7 +85,6 @@ class DrmResources { std::vector<std::unique_ptr<DrmEncoder>> encoders_; std::vector<std::unique_ptr<DrmCrtc>> crtcs_; std::vector<std::unique_ptr<DrmPlane>> planes_; - DrmCompositor compositor_; DrmEventListener event_listener_; std::pair<uint32_t, uint32_t> min_resolution_; diff --git a/glworker.cpp b/glworker.cpp index e12995e..e90576a 100644 --- a/glworker.cpp +++ b/glworker.cpp @@ -143,6 +143,38 @@ static bool HasExtension(const char *extension, const char *extensions) { return false; } +int GLWorkerCompositor::BeginContext() { + private_.saved_egl_display = eglGetCurrentDisplay(); + private_.saved_egl_ctx = eglGetCurrentContext(); + + if (private_.saved_egl_display != egl_display_ || + private_.saved_egl_ctx != egl_ctx_) { + private_.saved_egl_read = eglGetCurrentSurface(EGL_READ); + private_.saved_egl_draw = eglGetCurrentSurface(EGL_DRAW); + } else { + return 0; + } + + if (!eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_ctx_)) { + ALOGE("BeginContext failed: %s", GetEGLError()); + return 1; + } + return 0; +} + +int GLWorkerCompositor::EndContext() { + if (private_.saved_egl_display != eglGetCurrentDisplay() || + private_.saved_egl_ctx != eglGetCurrentContext()) { + if (!eglMakeCurrent(private_.saved_egl_display, private_.saved_egl_read, + private_.saved_egl_draw, private_.saved_egl_ctx)) { + ALOGE("EndContext failed: %s", GetEGLError()); + return 1; + } + } + + return 0; +} + static AutoGLShader CompileAndCheckShader(GLenum type, unsigned source_count, const GLchar **sources, std::ostringstream *shader_log) { @@ -508,10 +540,9 @@ int GLWorkerCompositor::Init() { return 1; } - if (!eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_ctx_)) { - ALOGE("Failed to make the OpenGL ES Context current: %s", GetEGLError()); - return 1; - } + ret = BeginContext(); + if (ret) + return ret; gl_extensions = (const char *)glGetString(GL_EXTENSIONS); @@ -530,6 +561,9 @@ int GLWorkerCompositor::Init() { std::ostringstream shader_log; blend_programs_.emplace_back(GenerateProgram(1, &shader_log)); + + EndContext(); + if (blend_programs_.back().get() == 0) { ALOGE("%s", shader_log.str().c_str()); return 1; @@ -558,12 +592,17 @@ int GLWorkerCompositor::Composite(DrmHwcLayer *layers, return -EALREADY; } + ret = BeginContext(); + if (ret) + return -1; + GLint frame_width = framebuffer->getWidth(); GLint frame_height = framebuffer->getHeight(); CachedFramebuffer *cached_framebuffer = PrepareAndCacheFramebuffer(framebuffer); if (cached_framebuffer == NULL) { ALOGE("Composite failed because of failed framebuffer"); + EndContext(); return -EINVAL; } @@ -597,8 +636,10 @@ int GLWorkerCompositor::Composite(DrmHwcLayer *layers, } } - if (ret) + if (ret) { + EndContext(); return ret; + } glViewport(0, 0, frame_width, frame_height); @@ -676,6 +717,7 @@ int GLWorkerCompositor::Composite(DrmHwcLayer *layers, glBindFramebuffer(GL_FRAMEBUFFER, 0); + EndContext(); return ret; } @@ -64,6 +64,16 @@ class GLWorkerCompositor { bool Promote(); }; + struct { + EGLDisplay saved_egl_display = EGL_NO_DISPLAY; + EGLContext saved_egl_ctx = EGL_NO_CONTEXT; + EGLSurface saved_egl_read = EGL_NO_SURFACE; + EGLSurface saved_egl_draw = EGL_NO_SURFACE; + } private_; + + int BeginContext(); + int EndContext(); + CachedFramebuffer *FindCachedFramebuffer( const sp<GraphicBuffer> &framebuffer); CachedFramebuffer *PrepareAndCacheFramebuffer( diff --git a/hwcomposer.cpp b/hwcomposer.cpp deleted file mode 100644 index e0483e9..0000000 --- a/hwcomposer.cpp +++ /dev/null @@ -1,840 +0,0 @@ -/* - * Copyright (C) 2015 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. - */ - -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#define LOG_TAG "hwcomposer-drm" - -#include "drmhwcomposer.h" -#include "drmeventlistener.h" -#include "drmresources.h" -#include "platform.h" -#include "virtualcompositorworker.h" -#include "vsyncworker.h" - -#include <stdlib.h> - -#include <cinttypes> -#include <map> -#include <vector> -#include <sstream> - -#include <errno.h> -#include <fcntl.h> -#include <pthread.h> -#include <sys/param.h> -#include <sys/resource.h> -#include <xf86drm.h> -#include <xf86drmMode.h> - -#include <cutils/log.h> -#include <cutils/properties.h> -#include <hardware/hardware.h> -#include <hardware/hwcomposer.h> -#include <sw_sync.h> -#include <sync/sync.h> -#include <utils/Trace.h> - -#define UM_PER_INCH 25400 - -namespace android { - -class DummySwSyncTimeline { - public: - int Init() { - int ret = timeline_fd_.Set(sw_sync_timeline_create()); - if (ret < 0) - return ret; - return 0; - } - - UniqueFd CreateDummyFence() { - int ret = sw_sync_fence_create(timeline_fd_.get(), "dummy fence", - timeline_pt_ + 1); - if (ret < 0) { - ALOGE("Failed to create dummy fence %d", ret); - return ret; - } - - UniqueFd ret_fd(ret); - - ret = sw_sync_timeline_inc(timeline_fd_.get(), 1); - if (ret) { - ALOGE("Failed to increment dummy sync timeline %d", ret); - return ret; - } - - ++timeline_pt_; - return ret_fd; - } - - private: - UniqueFd timeline_fd_; - int timeline_pt_ = 0; -}; - -struct CheckedOutputFd { - CheckedOutputFd(int *fd, const char *description, - DummySwSyncTimeline &timeline) - : fd_(fd), description_(description), timeline_(timeline) { - } - CheckedOutputFd(CheckedOutputFd &&rhs) - : description_(rhs.description_), timeline_(rhs.timeline_) { - std::swap(fd_, rhs.fd_); - } - - CheckedOutputFd &operator=(const CheckedOutputFd &rhs) = delete; - - ~CheckedOutputFd() { - if (fd_ == NULL) - return; - - if (*fd_ >= 0) - return; - - *fd_ = timeline_.CreateDummyFence().Release(); - - if (*fd_ < 0) - ALOGE("Failed to fill %s (%p == %d) before destruction", - description_.c_str(), fd_, *fd_); - } - - private: - int *fd_ = NULL; - std::string description_; - DummySwSyncTimeline &timeline_; -}; - -typedef struct hwc_drm_display { - struct hwc_context_t *ctx; - int display; - - std::vector<uint32_t> config_ids; - - VSyncWorker vsync_worker; -} hwc_drm_display_t; - -class DrmHotplugHandler : public DrmEventHandler { - public: - void Init(DrmResources *drm, const struct hwc_procs *procs) { - drm_ = drm; - procs_ = procs; - } - - void HandleEvent(uint64_t timestamp_us) { - for (auto &conn : drm_->connectors()) { - drmModeConnection old_state = conn->state(); - - conn->UpdateModes(); - - drmModeConnection cur_state = conn->state(); - - if (cur_state == old_state) - continue; - - ALOGI("%s event @%" PRIu64 " for connector %u\n", - cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug", timestamp_us, - conn->id()); - - if (cur_state == DRM_MODE_CONNECTED) { - // Take the first one, then look for the preferred - DrmMode mode = *(conn->modes().begin()); - for (auto &m : conn->modes()) { - if (m.type() & DRM_MODE_TYPE_PREFERRED) { - mode = m; - break; - } - } - ALOGI("Setting mode %dx%d for connector %d\n", mode.h_display(), - mode.v_display(), conn->id()); - int ret = drm_->SetDisplayActiveMode(conn->display(), mode); - if (ret) { - ALOGE("Failed to set active config %d", ret); - return; - } - } else { - int ret = drm_->SetDpmsMode(conn->display(), DRM_MODE_DPMS_OFF); - if (ret) { - ALOGE("Failed to set dpms mode off %d", ret); - return; - } - } - - procs_->hotplug(procs_, conn->display(), - cur_state == DRM_MODE_CONNECTED ? 1 : 0); - } - } - - private: - DrmResources *drm_ = NULL; - const struct hwc_procs *procs_ = NULL; -}; - -struct hwc_context_t { - // map of display:hwc_drm_display_t - typedef std::map<int, hwc_drm_display_t> DisplayMap; - - ~hwc_context_t() { - virtual_compositor_worker.Exit(); - } - - hwc_composer_device_1_t device; - hwc_procs_t const *procs = NULL; - - DisplayMap displays; - DrmResources drm; - std::unique_ptr<Importer> importer; - const gralloc_module_t *gralloc; - DummySwSyncTimeline dummy_timeline; - VirtualCompositorWorker virtual_compositor_worker; - DrmHotplugHandler hotplug_handler; -}; - -class DrmVsyncCallback : public VsyncCallback { - public: - DrmVsyncCallback(hwc_procs_t const *procs) : procs_(procs) { - } - - void Callback(int display, int64_t timestamp) { - procs_->vsync(procs_, display, timestamp); - } - private: - hwc_procs_t const *procs_; -}; - -static void hwc_dump(struct hwc_composer_device_1 *dev, char *buff, - int buff_len) { - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - std::ostringstream out; - - ctx->drm.compositor()->Dump(&out); - std::string out_str = out.str(); - strncpy(buff, out_str.c_str(), - std::min((size_t)buff_len, out_str.length() + 1)); - buff[buff_len - 1] = '\0'; -} - -static bool hwc_skip_layer(const std::pair<int, int> &indices, int i) { - return indices.first >= 0 && i >= indices.first && i <= indices.second; -} - -static int hwc_prepare(hwc_composer_device_1_t *dev, size_t num_displays, - hwc_display_contents_1_t **display_contents) { - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - - for (int i = 0; i < (int)num_displays; ++i) { - if (!display_contents[i]) - continue; - - bool use_framebuffer_target = false; - DrmMode mode; - if (i == HWC_DISPLAY_VIRTUAL) { - use_framebuffer_target = true; - } else { - DrmConnector *c = ctx->drm.GetConnectorForDisplay(i); - if (!c) { - ALOGE("Failed to get DrmConnector for display %d", i); - return -ENODEV; - } - mode = c->active_mode(); - } - - // Since we can't composite HWC_SKIP_LAYERs by ourselves, we'll let SF - // handle all layers in between the first and last skip layers. So find the - // outer indices and mark everything in between as HWC_FRAMEBUFFER - std::pair<int, int> skip_layer_indices(-1, -1); - int num_layers = display_contents[i]->numHwLayers; - for (int j = 0; !use_framebuffer_target && j < num_layers; ++j) { - hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j]; - - if (!(layer->flags & HWC_SKIP_LAYER)) - continue; - - if (skip_layer_indices.first == -1) - skip_layer_indices.first = j; - skip_layer_indices.second = j; - } - - for (int j = 0; j < num_layers; ++j) { - hwc_layer_1_t *layer = &display_contents[i]->hwLayers[j]; - - if (!use_framebuffer_target && !hwc_skip_layer(skip_layer_indices, j)) { - // If the layer is off the screen, don't earmark it for an overlay. - // We'll leave it as-is, which effectively just drops it from the frame - const hwc_rect_t *frame = &layer->displayFrame; - if ((frame->right - frame->left) <= 0 || - (frame->bottom - frame->top) <= 0 || - frame->right <= 0 || frame->bottom <= 0 || - frame->left >= (int)mode.h_display() || - frame->top >= (int)mode.v_display()) - continue; - - if (layer->compositionType == HWC_FRAMEBUFFER) - layer->compositionType = HWC_OVERLAY; - } else { - switch (layer->compositionType) { - case HWC_OVERLAY: - case HWC_BACKGROUND: - case HWC_SIDEBAND: - case HWC_CURSOR_OVERLAY: - layer->compositionType = HWC_FRAMEBUFFER; - break; - } - } - } - } - - return 0; -} - -static void hwc_add_layer_to_retire_fence( - hwc_layer_1_t *layer, hwc_display_contents_1_t *display_contents) { - if (layer->releaseFenceFd < 0) - return; - - if (display_contents->retireFenceFd >= 0) { - int old_retire_fence = display_contents->retireFenceFd; - display_contents->retireFenceFd = - sync_merge("dc_retire", old_retire_fence, layer->releaseFenceFd); - close(old_retire_fence); - } else { - display_contents->retireFenceFd = dup(layer->releaseFenceFd); - } -} - -static int hwc_set(hwc_composer_device_1_t *dev, size_t num_displays, - hwc_display_contents_1_t **sf_display_contents) { - ATRACE_CALL(); - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - int ret = 0; - - std::vector<CheckedOutputFd> checked_output_fences; - std::vector<DrmHwcDisplayContents> displays_contents; - std::vector<DrmCompositionDisplayLayersMap> layers_map; - std::vector<std::vector<size_t>> layers_indices; - displays_contents.reserve(num_displays); - // layers_map.reserve(num_displays); - layers_indices.reserve(num_displays); - - // Phase one does nothing that would cause errors. Only take ownership of FDs. - for (size_t i = 0; i < num_displays; ++i) { - hwc_display_contents_1_t *dc = sf_display_contents[i]; - displays_contents.emplace_back(); - DrmHwcDisplayContents &display_contents = displays_contents.back(); - layers_indices.emplace_back(); - std::vector<size_t> &indices_to_composite = layers_indices.back(); - - if (!sf_display_contents[i]) - continue; - - if (i == HWC_DISPLAY_VIRTUAL) { - ctx->virtual_compositor_worker.QueueComposite(dc); - continue; - } - - std::ostringstream display_index_formatter; - display_index_formatter << "retire fence for display " << i; - std::string display_fence_description(display_index_formatter.str()); - checked_output_fences.emplace_back(&dc->retireFenceFd, - display_fence_description.c_str(), - ctx->dummy_timeline); - display_contents.retire_fence = OutputFd(&dc->retireFenceFd); - - size_t num_dc_layers = dc->numHwLayers; - int framebuffer_target_index = -1; - for (size_t j = 0; j < num_dc_layers; ++j) { - hwc_layer_1_t *sf_layer = &dc->hwLayers[j]; - if (sf_layer->compositionType == HWC_FRAMEBUFFER_TARGET) { - framebuffer_target_index = j; - break; - } - } - - for (size_t j = 0; j < num_dc_layers; ++j) { - hwc_layer_1_t *sf_layer = &dc->hwLayers[j]; - - display_contents.layers.emplace_back(); - DrmHwcLayer &layer = display_contents.layers.back(); - - // In prepare() we marked all layers FRAMEBUFFER between SKIP_LAYER's. - // This means we should insert the FB_TARGET layer in the composition - // stack at the location of the first skip layer, and ignore the rest. - if (sf_layer->flags & HWC_SKIP_LAYER) { - if (framebuffer_target_index < 0) - continue; - int idx = framebuffer_target_index; - framebuffer_target_index = -1; - hwc_layer_1_t *fbt_layer = &dc->hwLayers[idx]; - if (!fbt_layer->handle || (fbt_layer->flags & HWC_SKIP_LAYER)) { - ALOGE("Invalid HWC_FRAMEBUFFER_TARGET with HWC_SKIP_LAYER present"); - continue; - } - indices_to_composite.push_back(idx); - continue; - } - - if (sf_layer->compositionType == HWC_OVERLAY) - indices_to_composite.push_back(j); - - layer.acquire_fence.Set(sf_layer->acquireFenceFd); - sf_layer->acquireFenceFd = -1; - - std::ostringstream layer_fence_formatter; - layer_fence_formatter << "release fence for layer " << j << " of display " - << i; - std::string layer_fence_description(layer_fence_formatter.str()); - checked_output_fences.emplace_back(&sf_layer->releaseFenceFd, - layer_fence_description.c_str(), - ctx->dummy_timeline); - layer.release_fence = OutputFd(&sf_layer->releaseFenceFd); - } - - // This is a catch-all in case we get a frame without any overlay layers, or - // skip layers, but with a value fb_target layer. This _shouldn't_ happen, - // but it's not ruled out by the hwc specification - if (indices_to_composite.empty() && framebuffer_target_index >= 0) { - hwc_layer_1_t *sf_layer = &dc->hwLayers[framebuffer_target_index]; - if (!sf_layer->handle || (sf_layer->flags & HWC_SKIP_LAYER)) { - ALOGE( - "Expected valid layer with HWC_FRAMEBUFFER_TARGET when all " - "HWC_OVERLAY layers are skipped."); - ret = -EINVAL; - } - indices_to_composite.push_back(framebuffer_target_index); - } - } - - if (ret) - return ret; - - for (size_t i = 0; i < num_displays; ++i) { - hwc_display_contents_1_t *dc = sf_display_contents[i]; - DrmHwcDisplayContents &display_contents = displays_contents[i]; - if (!sf_display_contents[i] || i == HWC_DISPLAY_VIRTUAL) - continue; - - layers_map.emplace_back(); - DrmCompositionDisplayLayersMap &map = layers_map.back(); - map.display = i; - map.geometry_changed = - (dc->flags & HWC_GEOMETRY_CHANGED) == HWC_GEOMETRY_CHANGED; - std::vector<size_t> &indices_to_composite = layers_indices[i]; - for (size_t j : indices_to_composite) { - hwc_layer_1_t *sf_layer = &dc->hwLayers[j]; - - DrmHwcLayer &layer = display_contents.layers[j]; - - ret = layer.InitFromHwcLayer(sf_layer, ctx->importer.get(), ctx->gralloc); - if (ret) { - ALOGE("Failed to init composition from layer %d", ret); - return ret; - } - map.layers.emplace_back(std::move(layer)); - } - } - - std::unique_ptr<DrmComposition> composition( - ctx->drm.compositor()->CreateComposition(ctx->importer.get())); - if (!composition) { - ALOGE("Drm composition init failed"); - return -EINVAL; - } - - ret = composition->SetLayers(layers_map.size(), layers_map.data()); - if (ret) { - return -EINVAL; - } - - ret = ctx->drm.compositor()->QueueComposition(std::move(composition)); - if (ret) { - return -EINVAL; - } - - for (size_t i = 0; i < num_displays; ++i) { - hwc_display_contents_1_t *dc = sf_display_contents[i]; - if (!dc) - continue; - - size_t num_dc_layers = dc->numHwLayers; - for (size_t j = 0; j < num_dc_layers; ++j) { - hwc_layer_1_t *layer = &dc->hwLayers[j]; - if (layer->flags & HWC_SKIP_LAYER) - continue; - hwc_add_layer_to_retire_fence(layer, dc); - } - } - - composition.reset(NULL); - - return ret; -} - -static int hwc_event_control(struct hwc_composer_device_1 *dev, int display, - int event, int enabled) { - if (event != HWC_EVENT_VSYNC || (enabled != 0 && enabled != 1)) - return -EINVAL; - - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - hwc_drm_display_t *hd = &ctx->displays[display]; - return hd->vsync_worker.VSyncControl(enabled); -} - -static int hwc_set_power_mode(struct hwc_composer_device_1 *dev, int display, - int mode) { - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - - uint64_t dpmsValue = 0; - switch (mode) { - case HWC_POWER_MODE_OFF: - dpmsValue = DRM_MODE_DPMS_OFF; - break; - - /* We can't support dozing right now, so go full on */ - case HWC_POWER_MODE_DOZE: - case HWC_POWER_MODE_DOZE_SUSPEND: - case HWC_POWER_MODE_NORMAL: - dpmsValue = DRM_MODE_DPMS_ON; - break; - }; - return ctx->drm.SetDpmsMode(display, dpmsValue); -} - -static int hwc_query(struct hwc_composer_device_1 * /* dev */, int what, - int *value) { - switch (what) { - case HWC_BACKGROUND_LAYER_SUPPORTED: - *value = 0; /* TODO: We should do this */ - break; - case HWC_VSYNC_PERIOD: - ALOGW("Query for deprecated vsync value, returning 60Hz"); - *value = 1000 * 1000 * 1000 / 60; - break; - case HWC_DISPLAY_TYPES_SUPPORTED: - *value = HWC_DISPLAY_PRIMARY_BIT | HWC_DISPLAY_EXTERNAL_BIT | - HWC_DISPLAY_VIRTUAL_BIT; - break; - } - return 0; -} - -static void hwc_register_procs(struct hwc_composer_device_1 *dev, - hwc_procs_t const *procs) { - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - - ctx->procs = procs; - - for (std::pair<const int, hwc_drm_display> &display_entry : ctx->displays) { - auto callback = std::make_shared<DrmVsyncCallback>(procs); - display_entry.second.vsync_worker.RegisterCallback(std::move(callback)); - } - - ctx->hotplug_handler.Init(&ctx->drm, procs); - ctx->drm.event_listener()->RegisterHotplugHandler(&ctx->hotplug_handler); -} - -static int hwc_get_display_configs(struct hwc_composer_device_1 *dev, - int display, uint32_t *configs, - size_t *num_configs) { - if (!*num_configs) - return 0; - - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - hwc_drm_display_t *hd = &ctx->displays[display]; - hd->config_ids.clear(); - - DrmConnector *connector = ctx->drm.GetConnectorForDisplay(display); - if (!connector) { - ALOGE("Failed to get connector for display %d", display); - return -ENODEV; - } - - int ret = connector->UpdateModes(); - if (ret) { - ALOGE("Failed to update display modes %d", ret); - return ret; - } - - for (const DrmMode &mode : connector->modes()) { - size_t idx = hd->config_ids.size(); - if (idx == *num_configs) - break; - hd->config_ids.push_back(mode.id()); - configs[idx] = mode.id(); - } - *num_configs = hd->config_ids.size(); - return *num_configs == 0 ? -1 : 0; -} - -static int hwc_get_display_attributes(struct hwc_composer_device_1 *dev, - int display, uint32_t config, - const uint32_t *attributes, - int32_t *values) { - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - DrmConnector *c = ctx->drm.GetConnectorForDisplay(display); - if (!c) { - ALOGE("Failed to get DrmConnector for display %d", display); - return -ENODEV; - } - DrmMode mode; - for (const DrmMode &conn_mode : c->modes()) { - if (conn_mode.id() == config) { - mode = conn_mode; - break; - } - } - if (mode.id() == 0) { - ALOGE("Failed to find active mode for display %d", display); - return -ENOENT; - } - - uint32_t mm_width = c->mm_width(); - uint32_t mm_height = c->mm_height(); - for (int i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; ++i) { - switch (attributes[i]) { - case HWC_DISPLAY_VSYNC_PERIOD: - values[i] = 1000 * 1000 * 1000 / mode.v_refresh(); - break; - case HWC_DISPLAY_WIDTH: - values[i] = mode.h_display(); - break; - case HWC_DISPLAY_HEIGHT: - values[i] = mode.v_display(); - break; - case HWC_DISPLAY_DPI_X: - /* Dots per 1000 inches */ - values[i] = mm_width ? (mode.h_display() * UM_PER_INCH) / mm_width : 0; - break; - case HWC_DISPLAY_DPI_Y: - /* Dots per 1000 inches */ - values[i] = - mm_height ? (mode.v_display() * UM_PER_INCH) / mm_height : 0; - break; - } - } - return 0; -} - -static int hwc_get_active_config(struct hwc_composer_device_1 *dev, - int display) { - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - DrmConnector *c = ctx->drm.GetConnectorForDisplay(display); - if (!c) { - ALOGE("Failed to get DrmConnector for display %d", display); - return -ENODEV; - } - - DrmMode mode = c->active_mode(); - hwc_drm_display_t *hd = &ctx->displays[display]; - for (size_t i = 0; i < hd->config_ids.size(); ++i) { - if (hd->config_ids[i] == mode.id()) - return i; - } - return -1; -} - -static int hwc_set_active_config(struct hwc_composer_device_1 *dev, int display, - int index) { - struct hwc_context_t *ctx = (struct hwc_context_t *)&dev->common; - hwc_drm_display_t *hd = &ctx->displays[display]; - if (index >= (int)hd->config_ids.size()) { - ALOGE("Invalid config index %d passed in", index); - return -EINVAL; - } - - DrmConnector *c = ctx->drm.GetConnectorForDisplay(display); - if (!c) { - ALOGE("Failed to get connector for display %d", display); - return -ENODEV; - } - - if (c->state() != DRM_MODE_CONNECTED) - return -ENODEV; - - DrmMode mode; - for (const DrmMode &conn_mode : c->modes()) { - if (conn_mode.id() == hd->config_ids[index]) { - mode = conn_mode; - break; - } - } - if (mode.id() != hd->config_ids[index]) { - ALOGE("Could not find active mode for %d/%d", index, hd->config_ids[index]); - return -ENOENT; - } - int ret = ctx->drm.SetDisplayActiveMode(display, mode); - if (ret) { - ALOGE("Failed to set active config %d", ret); - return ret; - } - ret = ctx->drm.SetDpmsMode(display, DRM_MODE_DPMS_ON); - if (ret) { - ALOGE("Failed to set dpms mode on %d", ret); - return ret; - } - return ret; -} - -static int hwc_device_close(struct hw_device_t *dev) { - struct hwc_context_t *ctx = (struct hwc_context_t *)dev; - delete ctx; - return 0; -} - -/* - * TODO: This function sets the active config to the first one in the list. This - * should be fixed such that it selects the preferred mode for the display, or - * some other, saner, method of choosing the config. - */ -static int hwc_set_initial_config(hwc_drm_display_t *hd) { - uint32_t config; - size_t num_configs = 1; - int ret = hwc_get_display_configs(&hd->ctx->device, hd->display, &config, - &num_configs); - if (ret || !num_configs) - return 0; - - ret = hwc_set_active_config(&hd->ctx->device, hd->display, 0); - if (ret) { - ALOGE("Failed to set active config d=%d ret=%d", hd->display, ret); - return ret; - } - - return ret; -} - -static int hwc_initialize_display(struct hwc_context_t *ctx, int display) { - hwc_drm_display_t *hd = &ctx->displays[display]; - hd->ctx = ctx; - hd->display = display; - - int ret = hwc_set_initial_config(hd); - if (ret) { - ALOGE("Failed to set initial config for d=%d ret=%d", display, ret); - return ret; - } - - ret = hd->vsync_worker.Init(&ctx->drm, display); - if (ret) { - ALOGE("Failed to create event worker for display %d %d\n", display, ret); - return ret; - } - - return 0; -} - -static int hwc_enumerate_displays(struct hwc_context_t *ctx) { - int ret; - for (auto &conn : ctx->drm.connectors()) { - ret = hwc_initialize_display(ctx, conn->display()); - if (ret) { - ALOGE("Failed to initialize display %d", conn->display()); - return ret; - } - } - - ret = ctx->virtual_compositor_worker.Init(); - if (ret) { - ALOGE("Failed to initialize virtual compositor worker"); - return ret; - } - return 0; -} - -static int hwc_device_open(const struct hw_module_t *module, const char *name, - struct hw_device_t **dev) { - if (strcmp(name, HWC_HARDWARE_COMPOSER)) { - ALOGE("Invalid module name- %s", name); - return -EINVAL; - } - - std::unique_ptr<hwc_context_t> ctx(new hwc_context_t()); - if (!ctx) { - ALOGE("Failed to allocate hwc context"); - return -ENOMEM; - } - - int ret = ctx->drm.Init(); - if (ret) { - ALOGE("Can't initialize Drm object %d", ret); - return ret; - } - - ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, - (const hw_module_t **)&ctx->gralloc); - if (ret) { - ALOGE("Failed to open gralloc module %d", ret); - return ret; - } - - ret = ctx->dummy_timeline.Init(); - if (ret) { - ALOGE("Failed to create dummy sw sync timeline %d", ret); - return ret; - } - - ctx->importer.reset(Importer::CreateInstance(&ctx->drm)); - if (!ctx->importer) { - ALOGE("Failed to create importer instance"); - return ret; - } - - ret = hwc_enumerate_displays(ctx.get()); - if (ret) { - ALOGE("Failed to enumerate displays: %s", strerror(ret)); - return ret; - } - - ctx->device.common.tag = HARDWARE_DEVICE_TAG; - ctx->device.common.version = HWC_DEVICE_API_VERSION_1_4; - ctx->device.common.module = const_cast<hw_module_t *>(module); - ctx->device.common.close = hwc_device_close; - - ctx->device.dump = hwc_dump; - ctx->device.prepare = hwc_prepare; - ctx->device.set = hwc_set; - ctx->device.eventControl = hwc_event_control; - ctx->device.setPowerMode = hwc_set_power_mode; - ctx->device.query = hwc_query; - ctx->device.registerProcs = hwc_register_procs; - ctx->device.getDisplayConfigs = hwc_get_display_configs; - ctx->device.getDisplayAttributes = hwc_get_display_attributes; - ctx->device.getActiveConfig = hwc_get_active_config; - ctx->device.setActiveConfig = hwc_set_active_config; - ctx->device.setCursorPositionAsync = NULL; /* TODO: Add cursor */ - - *dev = &ctx->device.common; - ctx.release(); - - return 0; -} -} - -static struct hw_module_methods_t hwc_module_methods = { - .open = android::hwc_device_open -}; - -hwc_module_t HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .version_major = 1, - .version_minor = 0, - .id = HWC_HARDWARE_MODULE_ID, - .name = "DRM hwcomposer module", - .author = "The Android Open Source Project", - .methods = &hwc_module_methods, - .dso = NULL, - .reserved = {0}, - } -}; |