diff options
-rwxr-xr-x | .gitlab-ci-checkcommit.sh | 37 | ||||
-rw-r--r-- | .gitlab-ci.yml | 10 | ||||
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | drmdisplaycompositor.cpp | 57 | ||||
-rw-r--r-- | drmhwctwo.cpp | 11 | ||||
-rw-r--r-- | drmplane.cpp | 16 | ||||
-rw-r--r-- | drmplane.h | 4 | ||||
-rw-r--r-- | drmproperty.cpp | 15 | ||||
-rw-r--r-- | drmproperty.h | 2 | ||||
-rw-r--r-- | platform.cpp | 56 | ||||
-rw-r--r-- | platform.h | 30 | ||||
-rw-r--r-- | platformdrmgeneric.cpp | 6 | ||||
-rw-r--r-- | platformdrmgeneric.h | 1 | ||||
-rw-r--r-- | platformhisi.cpp | 35 | ||||
-rw-r--r-- | platformhisi.h | 2 |
15 files changed, 231 insertions, 53 deletions
diff --git a/.gitlab-ci-checkcommit.sh b/.gitlab-ci-checkcommit.sh new file mode 100755 index 0000000..fc8963a --- /dev/null +++ b/.gitlab-ci-checkcommit.sh @@ -0,0 +1,37 @@ +#! /usr/bin/env bash + +echoerr() { + printf "ERROR: %s\n" "$*" >&2 +} + +git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git + +git log --pretty='%h' FETCH_HEAD..HEAD | while read h; do + subject=$(git show -s --pretty='%s' "$h") + if [[ $subject != drm_hwcomposer:* ]]; then + echoerr "Invalid subject prefix: $subject" + exit 1 + fi + + commit_body=$(git show -s --pretty=%b "$h") + + author=$(git show -s --format='%an <%ae>') + sob=$(echo "$commit_body" | grep "Signed-off-by: $author") + if [ -z "$sob" ] ; then + echoerr "Author SoB tag is missing from commit $h" + exit 1 + fi + + committer=$(git show -s --format='%cn <%ce>') + sob=$(echo "$commit_body" | grep "Signed-off-by: $committer") + if [ -z "$sob" ] ; then + echoerr "Committer SoB tag is missing from commit $h" + exit 1 + fi + + git show "$h" -- | clang-format-diff-5.0 -p 1 -style=file > format-fixup.patch + if [ -s format-fixup.patch ]; then + cat format-fixup.patch >&2 + exit 1 + fi +done diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24c4a0a..c97f4ff 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,13 +7,9 @@ before_script: stages: - style -clang-format: +checkstyle: stage: style - script: - - git fetch https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer.git - - git diff -U0 --no-color FETCH_HEAD...HEAD -- | clang-format-diff-5.0 -p 1 -style=file > format-fixup.patch - - if [ -s format-fixup.patch ]; then cat format-fixup.patch && exit 1; fi + script: "./.gitlab-ci-checkcommit.sh" artifacts: when: on_failure - paths: - - format-fixup.patch + untracked: true @@ -11,7 +11,7 @@ A short list of contribution guidelines: * drm_hwcomposer is Apache 2.0 Licensed and we require contributions to follow the developer's certificate of origin: http://developercertificate.org/ * When submitting new code please follow the naming conventions documented in the generated documentation. Also please make full use of all the helpers and convenience macros provided by drm_hwcomposer. The below command can help you with formatting of your patches: - `git diff | clang-format-diff-3.5 -p 1 -style=file` + `git diff | clang-format-diff-5.0 -p 1 -style=file` * Hardware specific changes should be tested on relevant platforms before committing. If you need inspiration, please checkout our [TODO issues](https://gitlab.freedesktop.org/drm-hwcomposer/drm-hwcomposer/issues?label_name%5B%5D=TODO) diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp index f479f10..a1ccdc7 100644 --- a/drmdisplaycompositor.cpp +++ b/drmdisplaycompositor.cpp @@ -316,6 +316,7 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, hwc_frect_t source_crop; uint64_t rotation = 0; uint64_t alpha = 0xFFFF; + uint64_t blend; if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) { if (source_layers.size() > 1) { @@ -338,8 +339,36 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, fence_fd = layer.acquire_fence.get(); display_frame = layer.display_frame; source_crop = layer.source_crop; - if (layer.blending == DrmHwcBlending::kPreMult) - alpha = layer.alpha; + alpha = layer.alpha; + + if (plane->blend_property().id()) { + switch (layer.blending) { + case DrmHwcBlending::kPreMult: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "Pre-multiplied"); + break; + case DrmHwcBlending::kCoverage: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "Coverage"); + break; + case DrmHwcBlending::kNone: + default: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "None"); + break; + } + } + + if (plane->zpos_property().id() && !plane->zpos_property().immutable()) { + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->zpos_property().id(), + source_layers.front()) < 0; + if (ret) { + ALOGE("Failed to add zpos property %d to plane %d", + plane->zpos_property().id(), plane->id()); + break; + } + } rotation = 0; if (layer.transform & DrmHwcTransform::kFlipH) @@ -382,20 +411,6 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, continue; } - // TODO: Once we have atomic test, this should fall back to GL - if (rotation != DRM_MODE_ROTATE_0 && plane->rotation_property().id() == 0) { - ALOGV("Rotation is not supported on plane %d", plane->id()); - ret = -EINVAL; - break; - } - - // TODO: Once we have atomic test, this should fall back to GL - if (alpha != 0xFFFF && plane->alpha_property().id() == 0) { - ALOGV("Alpha is not supported on plane %d", plane->id()); - ret = -EINVAL; - break; - } - ret = drmModeAtomicAddProperty(pset, plane->id(), plane->crtc_property().id(), crtc->id()) < 0; ret |= drmModeAtomicAddProperty(pset, plane->id(), @@ -453,6 +468,16 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, break; } } + + if (plane->blend_property().id()) { + ret = drmModeAtomicAddProperty(pset, plane->id(), + plane->blend_property().id(), blend) < 0; + if (ret) { + ALOGE("Failed to add pixel blend mode property %d to plane %d", + plane->blend_property().id(), plane->id()); + break; + } + } } if (!ret) { diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp index c801f2e..cd79e7b 100644 --- a/drmhwctwo.cpp +++ b/drmhwctwo.cpp @@ -491,9 +491,13 @@ HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(bool test) { std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map; for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { HWC2::Composition comp_type; - if (test) + if (test) { comp_type = l.second.sf_type(); - else + if (comp_type == HWC2::Composition::Device) { + if (!importer_->CanImportBuffer(l.second.buffer())) + comp_type = HWC2::Composition::Client; + } + } else comp_type = l.second.validated_type(); switch (comp_type) { @@ -735,7 +739,8 @@ HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) { if (comp_failed || !avail_planes--) break; - l.second->set_validated_type(HWC2::Composition::Device); + if (importer_->CanImportBuffer(l.second->buffer())) + l.second->set_validated_type(HWC2::Composition::Device); } for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { diff --git a/drmplane.cpp b/drmplane.cpp index 2603e16..35f91b4 100644 --- a/drmplane.cpp +++ b/drmplane.cpp @@ -118,6 +118,10 @@ int DrmPlane::Init() { return ret; } + ret = drm_->GetPlaneProperty(*this, "zpos", &zpos_property_); + if (ret) + ALOGE("Could not get zpos property for plane %u", id()); + ret = drm_->GetPlaneProperty(*this, "rotation", &rotation_property_); if (ret) ALOGE("Could not get rotation property"); @@ -126,6 +130,10 @@ int DrmPlane::Init() { if (ret) ALOGI("Could not get alpha property"); + ret = drm_->GetPlaneProperty(*this, "pixel blend mode", &blend_property_); + if (ret) + ALOGI("Could not get pixel blend mode property"); + ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_); if (ret) ALOGI("Could not get IN_FENCE_FD property"); @@ -185,6 +193,10 @@ const DrmProperty &DrmPlane::src_h_property() const { return src_h_property_; } +const DrmProperty &DrmPlane::zpos_property() const { + return zpos_property_; +} + const DrmProperty &DrmPlane::rotation_property() const { return rotation_property_; } @@ -193,6 +205,10 @@ const DrmProperty &DrmPlane::alpha_property() const { return alpha_property_; } +const DrmProperty &DrmPlane::blend_property() const { + return blend_property_; +} + const DrmProperty &DrmPlane::in_fence_fd_property() const { return in_fence_fd_property_; } @@ -52,8 +52,10 @@ class DrmPlane { const DrmProperty &src_y_property() const; const DrmProperty &src_w_property() const; const DrmProperty &src_h_property() const; + const DrmProperty &zpos_property() const; const DrmProperty &rotation_property() const; const DrmProperty &alpha_property() const; + const DrmProperty &blend_property() const; const DrmProperty &in_fence_fd_property() const; private: @@ -74,8 +76,10 @@ class DrmPlane { DrmProperty src_y_property_; DrmProperty src_w_property_; DrmProperty src_h_property_; + DrmProperty zpos_property_; DrmProperty rotation_property_; DrmProperty alpha_property_; + DrmProperty blend_property_; DrmProperty in_fence_fd_property_; }; } // namespace android diff --git a/drmproperty.cpp b/drmproperty.cpp index e71c159..9faa37e 100644 --- a/drmproperty.cpp +++ b/drmproperty.cpp @@ -99,4 +99,19 @@ int DrmProperty::value(uint64_t *value) const { return -EINVAL; } } + +bool DrmProperty::immutable() const { + return id_ && (flags_ & DRM_MODE_PROP_IMMUTABLE); +} + +std::tuple<uint64_t, int> DrmProperty::GetEnumValueWithName( + std::string name) const { + for (auto it : enums_) { + if (it.name_.compare(name) == 0) { + return std::make_tuple(it.value_, 0); + } + } + + return std::make_tuple(UINT64_MAX, -EINVAL); +} } // namespace android diff --git a/drmproperty.h b/drmproperty.h index dc01c88..f1328fe 100644 --- a/drmproperty.h +++ b/drmproperty.h @@ -40,11 +40,13 @@ class DrmProperty { DrmProperty &operator=(const DrmProperty &) = delete; void Init(drmModePropertyPtr p, uint64_t value); + std::tuple<uint64_t, int> GetEnumValueWithName(std::string name) const; uint32_t id() const; std::string name() const; int value(uint64_t *value) const; + bool immutable() const; private: class DrmPropertyEnum { diff --git a/platform.cpp b/platform.cpp index af18124..b7a47c7 100644 --- a/platform.cpp +++ b/platform.cpp @@ -36,6 +36,50 @@ std::vector<DrmPlane *> Planner::GetUsablePlanes( return usable_planes; } +int Planner::PlanStage::ValidatePlane(DrmPlane *plane, DrmHwcLayer *layer) { + int ret = 0; + uint64_t blend; + + if ((plane->rotation_property().id() == 0) && + layer->transform != DrmHwcTransform::kIdentity) { + ALOGE("Rotation is not supported on plane %d", plane->id()); + return -EINVAL; + } + + if (plane->alpha_property().id() == 0 && layer->alpha != 0xffff) { + ALOGE("Alpha is not supported on plane %d", plane->id()); + return -EINVAL; + } + + if (plane->blend_property().id() == 0) { + if ((layer->blending != DrmHwcBlending::kNone) && + (layer->blending != DrmHwcBlending::kPreMult)) { + ALOGE("Blending is not supported on plane %d", plane->id()); + return -EINVAL; + } + } else { + switch (layer->blending) { + case DrmHwcBlending::kPreMult: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "Pre-multiplied"); + break; + case DrmHwcBlending::kCoverage: + std::tie(blend, ret) = plane->blend_property().GetEnumValueWithName( + "Coverage"); + break; + case DrmHwcBlending::kNone: + default: + std::tie(blend, + ret) = plane->blend_property().GetEnumValueWithName("None"); + break; + } + if (ret) + ALOGE("Expected a valid blend mode on plane %d", plane->id()); + } + + return ret; +} + std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes( std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, @@ -73,9 +117,11 @@ int PlanStageProtected::ProvisionPlanes( } ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, crtc, - i->first); - if (ret) + std::make_pair(i->first, i->second)); + if (ret) { ALOGE("Failed to dedicate protected layer! Dropping it."); + return ret; + } protected_zorder = i->first; i = layers.erase(i); @@ -91,12 +137,14 @@ int PlanStageGreedy::ProvisionPlanes( // 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); + crtc, std::make_pair(i->first, i->second)); // We don't have any planes left if (ret == -ENOENT) break; - else if (ret) + else if (ret) { ALOGE("Failed to emplace layer %zu, dropping it", i->first); + return ret; + } } return 0; @@ -49,6 +49,9 @@ class Importer { // Note: This can be called from a different thread than ImportBuffer. The // implementation is responsible for ensuring thread safety. virtual int ReleaseBuffer(hwc_drm_bo_t *bo) = 0; + + // Checks if importer can import the buffer. + virtual bool CanImportBuffer(buffer_handle_t handle) = 0; }; class Planner { @@ -73,17 +76,32 @@ class Planner { return plane; } + static int ValidatePlane(DrmPlane *plane, DrmHwcLayer *layer); + // Inserts the given layer:plane in the composition at the back static int Emplace(std::vector<DrmCompositionPlane> *composition, std::vector<DrmPlane *> *planes, DrmCompositionPlane::Type type, DrmCrtc *crtc, - size_t source_layer) { + std::pair<size_t, DrmHwcLayer *> layer) { DrmPlane *plane = PopPlane(planes); - if (!plane) - return -ENOENT; - - composition->emplace_back(type, plane, crtc, source_layer); - return 0; + std::vector<DrmPlane *> unused_planes; + int ret = -ENOENT; + while (plane) { + ret = ValidatePlane(plane, layer.second); + if (!ret) + break; + if (!plane->zpos_property().immutable()) + unused_planes.push_back(plane); + plane = PopPlane(planes); + } + + if (!ret) { + composition->emplace_back(type, plane, crtc, layer.first); + planes->insert(planes->begin(), unused_planes.begin(), + unused_planes.end()); + } + + return ret; } }; diff --git a/platformdrmgeneric.cpp b/platformdrmgeneric.cpp index 24d0650..503c04a 100644 --- a/platformdrmgeneric.cpp +++ b/platformdrmgeneric.cpp @@ -161,6 +161,12 @@ int DrmGenericImporter::ReleaseBuffer(hwc_drm_bo_t *bo) { return 0; } +bool DrmGenericImporter::CanImportBuffer(buffer_handle_t handle) { + if (handle == NULL) + return false; + return true; +} + #ifdef USE_DRM_GENERIC_IMPORTER std::unique_ptr<Planner> Planner::CreateInstance(DrmDevice *) { std::unique_ptr<Planner> planner(new Planner); diff --git a/platformdrmgeneric.h b/platformdrmgeneric.h index d46e8b0..233ba55 100644 --- a/platformdrmgeneric.h +++ b/platformdrmgeneric.h @@ -33,6 +33,7 @@ class DrmGenericImporter : public Importer { int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; int ReleaseBuffer(hwc_drm_bo_t *bo) override; + bool CanImportBuffer(buffer_handle_t handle) override; uint32_t ConvertHalFormatToDrm(uint32_t hal_format); uint32_t DrmFormatToBitsPerPixel(uint32_t drm_format); diff --git a/platformhisi.cpp b/platformhisi.cpp index 68bb5a7..76fe1e7 100644 --- a/platformhisi.cpp +++ b/platformhisi.cpp @@ -78,10 +78,10 @@ int HisiImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { if (!hnd) return -EINVAL; - // We can't import these types of buffers, so pretend we did and rely on the - // planner to skip them when choosing layers for planes + // We can't import these types of buffers. + // These buffers should have been filtered out with CanImportBuffer() if (!(hnd->usage & GRALLOC_USAGE_HW_FB)) - return 0; + return -EINVAL; uint32_t gem_handle; int ret = drmPrimeFDToHandle(drm_->fd(), hnd->share_fd, &gem_handle); @@ -139,36 +139,39 @@ int HisiImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { return ret; } +bool HisiImporter::CanImportBuffer(buffer_handle_t handle) { + private_handle_t const *hnd = reinterpret_cast<private_handle_t const *>( + handle); + return hnd && (hnd->usage & GRALLOC_USAGE_HW_FB); +} + class PlanStageHiSi : public Planner::PlanStage { public: int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, std::vector<DrmPlane *> *planes) { int layers_added = 0; - int initial_layers = layers.size(); - // Fill up as many planes as we can with buffers that do not have HW_FB - // usage + // Fill up as many DRM planes as we can with buffers that have HW_FB usage. + // Buffers without HW_FB should have been filtered out with + // CanImportBuffer(), if we meet one here, just skip it. for (auto i = layers.begin(); i != layers.end(); i = layers.erase(i)) { if (!(i->second->gralloc_buffer_usage & GRALLOC_USAGE_HW_FB)) continue; int ret = Emplace(composition, planes, DrmCompositionPlane::Type::kLayer, - crtc, i->first); + crtc, std::make_pair(i->first, i->second)); layers_added++; // We don't have any planes left if (ret == -ENOENT) break; - else if (ret) + else if (ret) { ALOGE("Failed to emplace layer %zu, dropping it", i->first); + return ret; + } } - /* - * If we only have one layer, but we didn't emplace anything, we - * can run into trouble, as we might try to device composite a - * buffer we fake-imported, which can cause things to jamb up. - * So return an error in this case to ensure we force client - * compositing. - */ - if (!layers_added && (initial_layers <= 1)) + // If we didn't emplace anything, return an error to ensure we force client + // compositing. + if (!layers_added) return -EINVAL; return 0; diff --git a/platformhisi.h b/platformhisi.h index 2b2d439..927da17 100644 --- a/platformhisi.h +++ b/platformhisi.h @@ -36,6 +36,8 @@ class HisiImporter : public DrmGenericImporter { int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; + bool CanImportBuffer(buffer_handle_t handle) override; + private: DrmDevice *drm_; |