diff options
author | Sean Paul <seanpaul@chromium.org> | 2016-05-16 23:24:49 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-05-16 23:24:49 +0000 |
commit | c7eaa803884524c406ae123d890644252d37c5b8 (patch) | |
tree | 2487241b689f8d3051d93b7ef0bbeaca86fe4250 | |
parent | 179590238252ddd288fff0d79c1a7e41687ca74f (diff) | |
parent | d9c3e2d9c8b15082b1ef2372406ba46e4bb7d199 (diff) | |
download | drm_hwcomposer-c7eaa803884524c406ae123d890644252d37c5b8.tar.gz |
DO NOT MERGE: drm_hwcomposer: Introduce Planner interface
am: d9c3e2d9c8
* commit 'd9c3e2d9c8b15082b1ef2372406ba46e4bb7d199':
DO NOT MERGE: drm_hwcomposer: Introduce Planner interface
Change-Id: Ib540305069398638db10a6fc3a4db41d8a36096f
-rw-r--r-- | Android.mk | 7 | ||||
-rw-r--r-- | drmdisplaycomposition.h | 2 | ||||
-rw-r--r-- | platform.cpp | 167 | ||||
-rw-r--r-- | platform.h | 115 | ||||
-rw-r--r-- | platformdrmgeneric.cpp | 8 | ||||
-rw-r--r-- | platformnv.cpp | 88 | ||||
-rw-r--r-- | platformnv.h | 18 |
7 files changed, 401 insertions, 4 deletions
@@ -30,6 +30,7 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES := \ + external/drm_gralloc \ external/libdrm \ external/libdrm/include/drm \ system/core/include/utils \ @@ -53,17 +54,17 @@ LOCAL_SRC_FILES := \ drmproperty.cpp \ glworker.cpp \ hwcomposer.cpp \ + platform.cpp \ + platformdrmgeneric.cpp \ + platformnv.cpp \ separate_rects.cpp \ virtualcompositorworker.cpp \ vsyncworker.cpp \ worker.cpp ifeq ($(strip $(BOARD_DRM_HWCOMPOSER_BUFFER_IMPORTER)),nvidia-gralloc) -LOCAL_SRC_FILES += platformnv.cpp LOCAL_CPPFLAGS += -DUSE_NVIDIA_IMPORTER else -LOCAL_C_INCLUDES += external/drm_gralloc -LOCAL_SRC_FILES += platformdrmgeneric.cpp LOCAL_CPPFLAGS += -DUSE_DRM_GENERIC_IMPORTER endif diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h index 6c52664..4f48b52 100644 --- a/drmdisplaycomposition.h +++ b/drmdisplaycomposition.h @@ -21,7 +21,6 @@ #include "drmhwcomposer.h" #include "drmplane.h" #include "glworker.h" -#include "platform.h" #include <sstream> #include <vector> @@ -32,6 +31,7 @@ namespace android { +class Importer; class SquashState; enum DrmCompositionType { diff --git a/platform.cpp b/platform.cpp new file mode 100644 index 0000000..105d8f7 --- /dev/null +++ b/platform.cpp @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2016 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-platform" + +#include "drmresources.h" +#include "platform.h" + +#include <cutils/log.h> + +namespace android { + +std::vector<DrmPlane *> Planner::GetUsablePlanes( + DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, + std::vector<DrmPlane *> *overlay_planes) { + std::vector<DrmPlane *> usable_planes; + std::copy_if(primary_planes->begin(), primary_planes->end(), + std::back_inserter(usable_planes), + [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); }); + std::copy_if(overlay_planes->begin(), overlay_planes->end(), + std::back_inserter(usable_planes), + [=](DrmPlane *plane) { return plane->GetCrtcSupported(*crtc); }); + return usable_planes; +} + +std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes( + std::map<size_t, DrmHwcLayer *> &layers, bool use_squash_fb, DrmCrtc *crtc, + std::vector<DrmPlane *> *primary_planes, + std::vector<DrmPlane *> *overlay_planes) { + std::vector<DrmCompositionPlane> composition; + std::vector<DrmPlane *> planes = + GetUsablePlanes(crtc, primary_planes, overlay_planes); + if (planes.empty()) { + ALOGE("Display %d has no usable planes", crtc->display()); + return std::make_tuple(-ENODEV, std::vector<DrmCompositionPlane>()); + } + + // If needed, reserve the squash plane at the highest z-order + DrmPlane *squash_plane = NULL; + if (use_squash_fb) { + if (!planes.empty()) { + squash_plane = planes.back(); + planes.pop_back(); + } else { + ALOGI("Not enough planes to reserve for squash fb"); + } + } + + // If needed, reserve the precomp plane at the next highest z-order + DrmPlane *precomp_plane = NULL; + if (layers.size() > planes.size()) { + if (!planes.empty()) { + precomp_plane = planes.back(); + planes.pop_back(); + composition.emplace_back(DrmCompositionPlane::Type::kPrecomp, + precomp_plane, crtc); + } else { + ALOGE("Not enough planes to reserve for precomp fb"); + } + } + + // Go through the provisioning stages and provision planes + for (auto &i : stages_) { + int ret = i->ProvisionPlanes(&composition, layers, crtc, &planes); + if (ret) { + ALOGE("Failed provision stage with ret %d", ret); + return std::make_tuple(ret, std::vector<DrmCompositionPlane>()); + } + } + + if (squash_plane) + composition.emplace_back(DrmCompositionPlane::Type::kSquash, squash_plane, + crtc); + + return std::make_tuple(0, std::move(composition)); +} + +int PlanStageProtected::ProvisionPlanes( + std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, + std::vector<DrmPlane *> *planes) { + int ret; + int protected_zorder = -1; + for (auto i = layers.begin(); i != layers.end();) { + if (!i->second->protected_usage()) { + ++i; + continue; + } + + ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, crtc, + i->first); + if (ret) + ALOGE("Failed to dedicate protected layer! Dropping it."); + + protected_zorder = i->first; + i = layers.erase(i); + } + + if (protected_zorder == -1) + return 0; + + // Add any layers below the protected content to the precomposition since we + // need to punch a hole through them. + for (auto i = layers.begin(); i != layers.end();) { + // Skip layers above the z-order of the protected content + if (i->first > static_cast<size_t>(protected_zorder)) { + ++i; + continue; + } + + // If there's no precomp layer already queued, queue one now. + DrmCompositionPlane *precomp = GetPrecomp(composition); + if (precomp) { + precomp->source_layers().emplace_back(i->first); + } else { + if (!planes->empty()) { + DrmPlane *precomp_plane = planes->back(); + planes->pop_back(); + composition->emplace_back(DrmCompositionPlane::Type::kPrecomp, + precomp_plane, crtc, i->first); + } else { + ALOGE("Not enough planes to reserve for precomp fb"); + } + } + i = layers.erase(i); + } + return 0; +} + +int PlanStageGreedy::ProvisionPlanes( + std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, + std::vector<DrmPlane *> *planes) { + // Fill up the remaining planes + for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) { + int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, + crtc, i->first); + // We don't have any planes left + if (ret == -ENOENT) + break; + else if (ret) + ALOGE("Failed to emplace layer %zu, dropping it", i->first); + } + + // Put the rest of the layers in the precomp plane + DrmCompositionPlane *precomp = GetPrecomp(composition); + if (precomp) { + for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) + precomp->source_layers().emplace_back(i->first); + } + + return 0; +} +} @@ -17,11 +17,15 @@ #ifndef ANDROID_DRM_PLATFORM_H_ #define ANDROID_DRM_PLATFORM_H_ +#include "drmdisplaycomposition.h" #include "drmhwcomposer.h" #include <hardware/hardware.h> #include <hardware/hwcomposer.h> +#include <map> +#include <vector> + namespace android { class DrmResources; @@ -46,5 +50,116 @@ class Importer { // implementation is responsible for ensuring thread safety. virtual int ReleaseBuffer(hwc_drm_bo_t *bo) = 0; }; + +class Planner { + public: + class PlanStage { + public: + virtual ~PlanStage() { + } + + virtual int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, + DrmCrtc *crtc, + std::vector<DrmPlane *> *planes) = 0; + + protected: + // Removes and returns the next available plane from planes + static DrmPlane *PopPlane(std::vector<DrmPlane *> *planes) { + if (planes->empty()) + return NULL; + DrmPlane *plane = planes->front(); + planes->erase(planes->begin()); + return plane; + } + + // Finds and returns the squash layer from the composition + static DrmCompositionPlane *GetPrecomp( + std::vector<DrmCompositionPlane> *composition) { + auto l = GetPrecompIter(composition); + if (l == composition->end()) + return NULL; + return &(*l); + } + + // Inserts the given layer:plane in the composition right before the precomp + // layer + static int Emplace(std::vector<DrmCompositionPlane> *composition, + std::vector<DrmPlane *> *planes, + DrmCompositionPlane::Type type, DrmCrtc *crtc, + size_t source_layer) { + DrmPlane *plane = PopPlane(planes); + if (!plane) + return -ENOENT; + + auto precomp = GetPrecompIter(composition); + composition->emplace(precomp, type, plane, crtc, source_layer); + return 0; + } + + private: + static std::vector<DrmCompositionPlane>::iterator GetPrecompIter( + std::vector<DrmCompositionPlane> *composition) { + return std::find_if(composition->begin(), composition->end(), + [](const DrmCompositionPlane &p) { + return p.type() == DrmCompositionPlane::Type::kPrecomp; + }); + } + }; + + // Creates a planner instance with platform-specific planning stages + static std::unique_ptr<Planner> CreateInstance(DrmResources *drm); + + // Takes a stack of layers and provisions hardware planes for them. If the + // entire stack can't fit in hardware, the Planner may place the remaining + // layers in a PRECOMP plane. Layers in the PRECOMP plane will be composited + // using GL. PRECOMP planes should be placed above any 1:1 layer:plane + // compositions. If use_squash_fb is true, the Planner should try to reserve a + // plane at the highest z-order with type SQUASH. + // + // @layers: a map of index:layer of layers to composite + // @use_squash_fb: reserve a squash framebuffer + // @primary_planes: a vector of primary planes available for this frame + // @overlay_planes: a vector of overlay planes available for this frame + // + // Returns: A tuple with the status of the operation (0 for success) and + // a vector of the resulting plan (ie: layer->plane mapping). + std::tuple<int, std::vector<DrmCompositionPlane>> ProvisionPlanes( + std::map<size_t, DrmHwcLayer *> &layers, bool use_squash_fb, + DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, + std::vector<DrmPlane *> *overlay_planes); + + template <typename T, typename... A> + void AddStage(A &&... args) { + stages_.emplace_back( + std::unique_ptr<PlanStage>(new T(std::forward(args)...))); + } + + private: + std::vector<DrmPlane *> GetUsablePlanes( + DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, + std::vector<DrmPlane *> *overlay_planes); + + std::vector<std::unique_ptr<PlanStage>> stages_; +}; + +// This plan stage extracts all protected layers and places them on dedicated +// planes. +class PlanStageProtected : public Planner::PlanStage { + public: + int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, + std::vector<DrmPlane *> *planes); +}; + +// This plan stage places as many layers on dedicated planes as possible (first +// come first serve), and then sticks the rest in a precomposition plane (if +// needed). +class PlanStageGreedy : public Planner::PlanStage { + public: + int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, + std::vector<DrmPlane *> *planes); +}; } #endif diff --git a/platformdrmgeneric.cpp b/platformdrmgeneric.cpp index 95ea11e..e94bf26 100644 --- a/platformdrmgeneric.cpp +++ b/platformdrmgeneric.cpp @@ -142,4 +142,12 @@ int DrmGenericImporter::ReleaseBuffer(hwc_drm_bo_t *bo) { } return 0; } + +#ifdef USE_DRM_GENERIC_IMPORTER +std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) { + std::unique_ptr<Planner> planner(new Planner); + planner->AddStage<PlanStageGreedy>(); + return planner; +} +#endif } diff --git a/platformnv.cpp b/platformnv.cpp index 5b79826..db7ee36 100644 --- a/platformnv.cpp +++ b/platformnv.cpp @@ -183,4 +183,92 @@ int NvImporter::GrallocSetNvBuffer(buffer_handle_t handle, NvBuffer_t *buf) { GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE, handle, NvGrallocRelease, buf); } + +#ifdef USE_NVIDIA_IMPORTER +// static +std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) { + std::unique_ptr<Planner> planner(new Planner); + planner->AddStage<PlanStageProtectedRotated>(); + planner->AddStage<PlanStageProtected>(); + planner->AddStage<PlanStageGreedy>(); + return planner; +} +#endif + +static DrmPlane *GetCrtcPrimaryPlane(DrmCrtc *crtc, + std::vector<DrmPlane *> *planes) { + for (auto i = planes->begin(); i != planes->end(); ++i) { + if ((*i)->GetCrtcSupported(*crtc)) { + DrmPlane *plane = *i; + planes->erase(i); + return plane; + } + } + return NULL; +} + +int PlanStageProtectedRotated::ProvisionPlanes( + std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, + std::vector<DrmPlane *> *planes) { + int ret; + int protected_zorder = -1; + for (auto i = layers.begin(); i != layers.end();) { + if (!i->second->protected_usage() || !i->second->transform) { + ++i; + continue; + } + + auto primary_iter = planes->begin(); + for (; primary_iter != planes->end(); ++primary_iter) { + if ((*primary_iter)->type() == DRM_PLANE_TYPE_PRIMARY) + break; + } + + // We cheat a little here. Since there can only be one primary plane per + // crtc, we know we'll only hit this case once. So we blindly insert the + // protected content at the beginning of the composition, knowing this path + // won't be taken a second time during the loop. + if (primary_iter != planes->end()) { + composition->emplace(composition->begin(), + DrmCompositionPlane::Type::kLayer, *primary_iter, + crtc, i->first); + planes->erase(primary_iter); + protected_zorder = i->first; + } else { + ALOGE("Could not provision primary plane for protected/rotated layer"); + } + i = layers.erase(i); + } + + if (protected_zorder == -1) + return 0; + + // Add any layers below the protected content to the precomposition since we + // need to punch a hole through them. + for (auto i = layers.begin(); i != layers.end();) { + // Skip layers above the z-order of the protected content + if (i->first > static_cast<size_t>(protected_zorder)) { + ++i; + continue; + } + + // If there's no precomp layer already queued, queue one now. + DrmCompositionPlane *precomp = GetPrecomp(composition); + if (precomp) { + precomp->source_layers().emplace_back(i->first); + } else { + if (planes->size()) { + DrmPlane *precomp_plane = planes->back(); + planes->pop_back(); + composition->emplace_back(DrmCompositionPlane::Type::kPrecomp, + precomp_plane, crtc, i->first); + } else { + ALOGE("Not enough planes to reserve for precomp fb"); + } + } + i = layers.erase(i); + } + return 0; +} } diff --git a/platformnv.h b/platformnv.h index 652409b..a9e5d39 100644 --- a/platformnv.h +++ b/platformnv.h @@ -19,6 +19,7 @@ #include "drmresources.h" #include "platform.h" +#include "platformdrmgeneric.h" #include <stdatomic.h> @@ -53,6 +54,23 @@ class NvImporter : public Importer { const gralloc_module_t *gralloc_; }; + +// This stage looks for any layers that contain transformed protected content +// and puts it in the primary plane since Tegra doesn't support planar rotation +// on the overlay planes. +// +// There are two caveats to this approach: 1- Protected content isn't +// necessarily planar, but it's usually a safe bet, and 2- This doesn't catch +// non-protected planar content. If we wanted to fix this, we'd need to import +// the buffer in this stage and peek at it's format. The overhead of doing this +// doesn't seem worth it since we'll end up displaying the right thing in both +// cases anyways. +class PlanStageProtectedRotated : public Planner::PlanStage { + public: + int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, + std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, + std::vector<DrmPlane *> *planes); +}; } #endif |