diff options
author | Sumit Semwal <sumit.semwal@linaro.org> | 2018-06-25 16:38:18 +0530 |
---|---|---|
committer | Sumit Semwal <sumit.semwal@linaro.org> | 2018-06-25 16:38:18 +0530 |
commit | 44eb7ff624a6cf9f707a73d7f3d3b2dd5201093c (patch) | |
tree | c8d517248ae2761b34b8e912ec363b02954f657b | |
parent | 60a60eee1e1abdf8e8621bb1a64a53a6ba976233 (diff) | |
parent | 78c9f6c26210423926ea027edfab0b9504c2d7ff (diff) |
Merge branch 'master' of git://anongit.freedesktop.org/drm_hwcomposer into forAOSPforAOSP
40 files changed, 599 insertions, 4157 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..43bce5f --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,19 @@ +image: ubuntu:16.04 + +before_script: + - apt-get --quiet update --yes >/dev/null + - apt-get --quiet install --yes clang-format-3.5 git >/dev/null + +stages: + - style + +clang-format: + 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-3.5 -p 1 -style=file > format-fixup.patch + - if [ -s format-fixup.patch ]; then cat format-fixup.patch && exit 1; fi + artifacts: + when: on_failure + paths: + - format-fixup.patch @@ -16,6 +16,15 @@ ifeq ($(strip $(BOARD_USES_DRM_HWCOMPOSER)),true) LOCAL_PATH := $(call my-dir) +common_drm_hwcomposer_cflags := \ + -Wall \ + -Werror \ + -Wno-unused-function \ + -Wno-unused-label \ + -Wno-unused-parameter \ + -Wno-unused-private-field \ + -Wno-unused-variable \ + # ===================== # libdrmhwc_utils.a # ===================== @@ -24,7 +33,10 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ worker.cpp +LOCAL_CFLAGS := $(common_drm_hwcomposer_cflags) + LOCAL_MODULE := libdrmhwc_utils +LOCAL_VENDOR_MODULE := true include $(BUILD_STATIC_LIBRARY) @@ -36,8 +48,6 @@ include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := \ libcutils \ libdrm \ - libEGL \ - libGLESv2 \ libhardware \ liblog \ libsync \ @@ -47,7 +57,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_STATIC_LIBRARIES := libdrmhwc_utils LOCAL_C_INCLUDES := \ - external/drm_gralloc \ system/core/libsync LOCAL_SRC_FILES := \ @@ -63,14 +72,13 @@ LOCAL_SRC_FILES := \ drmmode.cpp \ drmplane.cpp \ drmproperty.cpp \ - glworker.cpp \ hwcutils.cpp \ platform.cpp \ platformdrmgeneric.cpp \ - separate_rects.cpp \ - virtualcompositorworker.cpp \ vsyncworker.cpp +LOCAL_CFLAGS := $(common_drm_hwcomposer_cflags) + LOCAL_CPPFLAGS += \ -DHWC2_USE_CPP11 \ -DHWC2_INCLUDE_STRINGIFICATION @@ -80,15 +88,16 @@ ifeq ($(TARGET_PRODUCT),hikey960) LOCAL_CPPFLAGS += -DUSE_HISI_IMPORTER LOCAL_SRC_FILES += platformhisi.cpp LOCAL_C_INCLUDES += device/linaro/hikey/gralloc960/ -else -ifeq ($(TARGET_PRODUCT),hikey) +else ifeq ($(TARGET_PRODUCT),hikey) LOCAL_CPPFLAGS += -DUSE_HISI_IMPORTER LOCAL_SRC_FILES += platformhisi.cpp LOCAL_C_INCLUDES += device/linaro/hikey/gralloc/ +else ifeq ($(strip $(BOARD_DRM_HWCOMPOSER_BUFFER_IMPORTER)),minigbm) +LOCAL_SRC_FILES += platformminigbm.cpp +LOCAL_C_INCLUDES += external/minigbm/cros_gralloc/ else LOCAL_CPPFLAGS += -DUSE_DRM_GENERIC_IMPORTER endif -endif LOCAL_MODULE := hwcomposer.drm LOCAL_MODULE_TAGS := optional diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_APACHE2 @@ -0,0 +1,203 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..260ac9b --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +drm_hwcomposer +====== + +Patches to drm_hwcomposer are very much welcome, we really want this to be the +universal HW composer implementation for Android and similar platforms +So please bring on porting patches, bugfixes, improvements for documentation +and new features. + +A short list of contribution guidelines: +* Submit changes via gitlab merge requests on gitlab.freedesktop.org +* 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` +* 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) + +Happy hacking! diff --git a/autogl.h b/autogl.h deleted file mode 100644 index fc77fb0..0000000 --- a/autogl.h +++ /dev/null @@ -1,110 +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_AUTO_GL_H_ -#define ANDROID_AUTO_GL_H_ - -#include <memory> -#define EGL_EGLEXT_PROTOTYPES -#define GL_GLEXT_PROTOTYPES - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -// TODO(zachr): use hwc_drm_bo to turn buffer handles into textures -#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX -#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A -#endif - -namespace android { - -#define AUTO_GL_TYPE(name, type, zero, deleter) \ - struct name##Deleter { \ - typedef type pointer; \ - \ - void operator()(pointer p) const { \ - if (p != zero) { \ - deleter; \ - } \ - } \ - }; \ - typedef std::unique_ptr<type, name##Deleter> name; - -AUTO_GL_TYPE(AutoGLFramebuffer, GLuint, 0, glDeleteFramebuffers(1, &p)) -AUTO_GL_TYPE(AutoGLBuffer, GLuint, 0, glDeleteBuffers(1, &p)) -AUTO_GL_TYPE(AutoGLTexture, GLuint, 0, glDeleteTextures(1, &p)) -AUTO_GL_TYPE(AutoGLShader, GLint, 0, glDeleteShader(p)) -AUTO_GL_TYPE(AutoGLProgram, GLint, 0, glDeleteProgram(p)) - -struct AutoEGLDisplayImage { - AutoEGLDisplayImage() = default; - - AutoEGLDisplayImage(EGLDisplay display, EGLImageKHR image) - : display_(display), image_(image) { - } - - AutoEGLDisplayImage(const AutoEGLDisplayImage& rhs) = delete; - AutoEGLDisplayImage(AutoEGLDisplayImage&& rhs) { - display_ = rhs.display_; - image_ = rhs.image_; - rhs.display_ = EGL_NO_DISPLAY; - rhs.image_ = EGL_NO_IMAGE_KHR; - } - - ~AutoEGLDisplayImage() { - clear(); - } - - AutoEGLDisplayImage& operator=(const AutoEGLDisplayImage& rhs) = delete; - AutoEGLDisplayImage& operator=(AutoEGLDisplayImage&& rhs) { - clear(); - std::swap(display_, rhs.display_); - std::swap(image_, rhs.image_); - return *this; - } - - void reset(EGLDisplay display, EGLImageKHR image) { - clear(); - display_ = display; - image_ = image; - } - - void clear() { - if (image_ != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(display_, image_); - display_ = EGL_NO_DISPLAY; - image_ = EGL_NO_IMAGE_KHR; - } - } - - EGLImageKHR image() const { - return image_; - } - - private: - EGLDisplay display_ = EGL_NO_DISPLAY; - EGLImageKHR image_ = EGL_NO_IMAGE_KHR; -}; - -struct AutoEGLImageAndGLTexture { - AutoEGLDisplayImage image; - AutoGLTexture texture; -}; -} - -#endif diff --git a/autolock.cpp b/autolock.cpp index 1a2ded7..795a8c2 100644 --- a/autolock.cpp +++ b/autolock.cpp @@ -22,7 +22,7 @@ #include <errno.h> #include <pthread.h> -#include <cutils/log.h> +#include <log/log.h> namespace android { diff --git a/drmcompositorworker.cpp b/drmcompositorworker.cpp deleted file mode 100644 index a4e7fc9..0000000 --- a/drmcompositorworker.cpp +++ /dev/null @@ -1,78 +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()) { - Lock(); - - // 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); - Unlock(); - - 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/drmconnector.cpp b/drmconnector.cpp index 145518f..10b96b5 100644 --- a/drmconnector.cpp +++ b/drmconnector.cpp @@ -22,7 +22,7 @@ #include <errno.h> #include <stdint.h> -#include <cutils/log.h> +#include <log/log.h> #include <xf86drmMode.h> namespace android { diff --git a/drmcrtc.cpp b/drmcrtc.cpp index 1b354fe..4033269 100644 --- a/drmcrtc.cpp +++ b/drmcrtc.cpp @@ -22,7 +22,7 @@ #include <stdint.h> #include <xf86drmMode.h> -#include <cutils/log.h> +#include <log/log.h> namespace android { diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp index 66e67a4..129bec2 100644 --- a/drmdisplaycomposition.cpp +++ b/drmdisplaycomposition.cpp @@ -28,18 +28,13 @@ #include <algorithm> #include <unordered_set> -#include <cutils/log.h> -#include <sw_sync.h> +#include <log/log.h> #include <sync/sync.h> #include <xf86drmMode.h> namespace android { DrmDisplayComposition::~DrmDisplayComposition() { - if (timeline_fd_ >= 0) { - SignalCompositionDone(); - close(timeline_fd_); - } } int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc, @@ -51,12 +46,6 @@ int DrmDisplayComposition::Init(DrmResources *drm, DrmCrtc *crtc, planner_ = planner; frame_no_ = frame_no; - int ret = sw_sync_timeline_create(); - if (ret < 0) { - ALOGE("Failed to create sw sync timeline %d", ret); - return ret; - } - timeline_fd_ = ret; return 0; } @@ -64,26 +53,6 @@ bool DrmDisplayComposition::validate_composition_type(DrmCompositionType des) { return type_ == DRM_COMPOSITION_TYPE_EMPTY || type_ == des; } -int DrmDisplayComposition::CreateNextTimelineFence() { - ++timeline_; - return sw_sync_fence_create(timeline_fd_, "hwc drm display composition fence", - timeline_); -} - -int DrmDisplayComposition::IncreaseTimelineToPoint(int point) { - int timeline_increase = point - timeline_current_; - if (timeline_increase <= 0) - return 0; - - int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase); - if (ret) - ALOGE("Failed to increment sync timeline %d", ret); - else - timeline_current_ = point; - - return ret; -} - int DrmDisplayComposition::SetLayers(DrmHwcLayer *layers, size_t num_layers, bool geometry_changed) { if (!validate_composition_type(DRM_COMPOSITION_TYPE_FRAME)) @@ -122,253 +91,25 @@ int DrmDisplayComposition::AddPlaneDisable(DrmPlane *plane) { return 0; } -static std::vector<size_t> SetBitsToVector( - uint64_t in, const std::vector<size_t> &index_map) { - std::vector<size_t> out; - size_t msb = sizeof(in) * 8 - 1; - uint64_t mask = (uint64_t)1 << msb; - for (size_t i = msb; mask != (uint64_t)0; i--, mask >>= 1) - if (in & mask) - out.push_back(index_map[i]); - return out; -} - int DrmDisplayComposition::AddPlaneComposition(DrmCompositionPlane plane) { composition_planes_.emplace_back(std::move(plane)); return 0; } -void DrmDisplayComposition::SeparateLayers(DrmHwcRect<int> *exclude_rects, - size_t num_exclude_rects) { - DrmCompositionPlane *comp = NULL; - std::vector<size_t> dedicated_layers; - - // Go through the composition and find the precomp layer as well as any - // layers that have a dedicated plane located below the precomp layer. - for (auto &i : composition_planes_) { - if (i.type() == DrmCompositionPlane::Type::kLayer) { - dedicated_layers.insert(dedicated_layers.end(), i.source_layers().begin(), - i.source_layers().end()); - } else if (i.type() == DrmCompositionPlane::Type::kPrecomp) { - comp = &i; - break; - } - } - if (!comp) - return; - - const std::vector<size_t> &comp_layers = comp->source_layers(); - if (comp_layers.size() > 64) { - ALOGE("Failed to separate layers because there are more than 64"); - return; - } - - // Index at which the actual layers begin - size_t layer_offset = num_exclude_rects + dedicated_layers.size(); - if (comp_layers.size() + layer_offset > 64) { - ALOGW( - "Exclusion rectangles are being truncated to make the rectangle count " - "fit into 64"); - num_exclude_rects = 64 - comp_layers.size() - dedicated_layers.size(); - } - - // We inject all the exclude rects into the rects list. Any resulting rect - // that includes ANY of the first num_exclude_rects is rejected. After the - // exclude rects, we add the lower layers. The rects that intersect with - // these layers will be inspected and only those which are to be composited - // above the layer will be included in the composition regions. - std::vector<DrmHwcRect<int>> layer_rects(comp_layers.size() + layer_offset); - std::copy(exclude_rects, exclude_rects + num_exclude_rects, - layer_rects.begin()); - std::transform( - dedicated_layers.begin(), dedicated_layers.end(), - layer_rects.begin() + num_exclude_rects, - [=](size_t layer_index) { return layers_[layer_index].display_frame; }); - std::transform(comp_layers.begin(), comp_layers.end(), - layer_rects.begin() + layer_offset, [=](size_t layer_index) { - return layers_[layer_index].display_frame; - }); - - std::vector<separate_rects::RectSet<uint64_t, int>> separate_regions; - separate_rects::separate_rects_64(layer_rects, &separate_regions); - uint64_t exclude_mask = ((uint64_t)1 << num_exclude_rects) - 1; - uint64_t dedicated_mask = (((uint64_t)1 << dedicated_layers.size()) - 1) - << num_exclude_rects; - - for (separate_rects::RectSet<uint64_t, int> ®ion : separate_regions) { - if (region.id_set.getBits() & exclude_mask) - continue; - - // If a rect intersects one of the dedicated layers, we need to remove the - // layers from the composition region which appear *below* the dedicated - // layer. This effectively punches a hole through the composition layer such - // that the dedicated layer can be placed below the composition and not - // be occluded. - uint64_t dedicated_intersect = region.id_set.getBits() & dedicated_mask; - for (size_t i = 0; dedicated_intersect && i < dedicated_layers.size(); - ++i) { - // Only exclude layers if they intersect this particular dedicated layer - if (!(dedicated_intersect & (1 << (i + num_exclude_rects)))) - continue; - - for (size_t j = 0; j < comp_layers.size(); ++j) { - if (comp_layers[j] < dedicated_layers[i]) - region.id_set.subtract(j + layer_offset); - } - } - if (!(region.id_set.getBits() >> layer_offset)) - continue; - - pre_comp_regions_.emplace_back(DrmCompositionRegion{ - region.rect, - SetBitsToVector(region.id_set.getBits() >> layer_offset, comp_layers)}); - } -} - -int DrmDisplayComposition::CreateAndAssignReleaseFences() { - std::unordered_set<DrmHwcLayer *> squash_layers; - std::unordered_set<DrmHwcLayer *> pre_comp_layers; - std::unordered_set<DrmHwcLayer *> comp_layers; - - for (const DrmCompositionRegion ®ion : squash_regions_) { - for (size_t source_layer_index : region.source_layers) { - DrmHwcLayer *source_layer = &layers_[source_layer_index]; - squash_layers.emplace(source_layer); - } - } - - for (const DrmCompositionRegion ®ion : pre_comp_regions_) { - for (size_t source_layer_index : region.source_layers) { - DrmHwcLayer *source_layer = &layers_[source_layer_index]; - pre_comp_layers.emplace(source_layer); - squash_layers.erase(source_layer); - } - } - - for (const DrmCompositionPlane &plane : composition_planes_) { - if (plane.type() == DrmCompositionPlane::Type::kLayer) { - for (auto i : plane.source_layers()) { - DrmHwcLayer *source_layer = &layers_[i]; - comp_layers.emplace(source_layer); - pre_comp_layers.erase(source_layer); - } - } - } - - for (DrmHwcLayer *layer : squash_layers) { - if (!layer->release_fence) - continue; - int ret = layer->release_fence.Set(CreateNextTimelineFence()); - if (ret < 0) { - ALOGE("Failed to set the release fence (squash) %d", ret); - return ret; - } - } - timeline_squash_done_ = timeline_; - - for (DrmHwcLayer *layer : pre_comp_layers) { - if (!layer->release_fence) - continue; - int ret = layer->release_fence.Set(CreateNextTimelineFence()); - if (ret < 0) - return ret; - } - timeline_pre_comp_done_ = timeline_; - - for (DrmHwcLayer *layer : comp_layers) { - if (!layer->release_fence) - continue; - int ret = layer->release_fence.Set(CreateNextTimelineFence()); - if (ret < 0) { - ALOGE("Failed to set the release fence (comp) %d", ret); - return ret; - } - } - - return 0; -} - -int DrmDisplayComposition::Plan(SquashState *squash, - std::vector<DrmPlane *> *primary_planes, +int DrmDisplayComposition::Plan(std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes) { if (type_ != DRM_COMPOSITION_TYPE_FRAME) return 0; - // Used to track which layers should be sent to the planner. We exclude layers - // that are entirely squashed so the planner can provision a precomposition - // layer as appropriate (ex: if 5 layers are squashed and 1 is not, we don't - // want to plan a precomposition layer that will be comprised of the already - // squashed layers). std::map<size_t, DrmHwcLayer *> to_composite; - bool use_squash_framebuffer = false; - // Used to determine which layers were entirely squashed - std::vector<int> layer_squash_area(layers_.size(), 0); - // Used to avoid rerendering regions that were squashed - std::vector<DrmHwcRect<int>> exclude_rects; - if (squash != NULL) { - if (geometry_changed_) { - squash->Init(layers_.data(), layers_.size()); - } else { - std::vector<bool> changed_regions; - squash->GenerateHistory(layers_.data(), layers_.size(), changed_regions); - - std::vector<bool> stable_regions; - squash->StableRegionsWithMarginalHistory(changed_regions, stable_regions); - - // Only if SOME region is stable - use_squash_framebuffer = - std::find(stable_regions.begin(), stable_regions.end(), true) != - stable_regions.end(); - - squash->RecordHistory(layers_.data(), layers_.size(), changed_regions); - - // Changes in which regions are squashed triggers a rerender via - // squash_regions. - bool render_squash = squash->RecordAndCompareSquashed(stable_regions); - - for (size_t region_index = 0; region_index < stable_regions.size(); - region_index++) { - const SquashState::Region ®ion = squash->regions()[region_index]; - if (!stable_regions[region_index]) - continue; - - exclude_rects.emplace_back(region.rect); - - if (render_squash) { - squash_regions_.emplace_back(); - squash_regions_.back().frame = region.rect; - } - - int frame_area = region.rect.area(); - // Source layers are sorted front to back i.e. top layer has lowest - // index. - for (size_t layer_index = layers_.size(); - layer_index-- > 0; // Yes, I double checked this - /* See condition */) { - if (!region.layer_refs[layer_index]) - continue; - layer_squash_area[layer_index] += frame_area; - if (render_squash) - squash_regions_.back().source_layers.push_back(layer_index); - } - } - } - - for (size_t i = 0; i < layers_.size(); ++i) { - if (layer_squash_area[i] < layers_[i].display_frame.area()) - to_composite.emplace(std::make_pair(i, &layers_[i])); - } - } else { - for (size_t i = 0; i < layers_.size(); ++i) - to_composite.emplace(std::make_pair(i, &layers_[i])); - } + for (size_t i = 0; i < layers_.size(); ++i) + to_composite.emplace(std::make_pair(i, &layers_[i])); int ret; std::vector<DrmCompositionPlane> plan; - std::tie(ret, composition_planes_) = - planner_->ProvisionPlanes(to_composite, use_squash_framebuffer, crtc_, - primary_planes, overlay_planes); + std::tie(ret, composition_planes_) = planner_->ProvisionPlanes( + to_composite, crtc_, primary_planes, overlay_planes); if (ret) { ALOGE("Planner failed provisioning planes ret=%d", ret); return ret; @@ -396,17 +137,7 @@ int DrmDisplayComposition::Plan(SquashState *squash, } } - return FinalizeComposition(exclude_rects.data(), exclude_rects.size()); -} - -int DrmDisplayComposition::FinalizeComposition() { - return FinalizeComposition(NULL, 0); -} - -int DrmDisplayComposition::FinalizeComposition(DrmHwcRect<int> *exclude_rects, - size_t num_exclude_rects) { - SeparateLayers(exclude_rects, num_exclude_rects); - return CreateAndAssignReleaseFences(); + return 0; } static const char *DrmCompositionTypeToString(DrmCompositionType type) { @@ -506,23 +237,6 @@ static const char *BlendingToString(DrmHwcBlending blending) { } } -static void DumpRegion(const DrmCompositionRegion ®ion, - std::ostringstream *out) { - *out << "frame"; - region.frame.Dump(out); - *out << " source_layers=("; - - const std::vector<size_t> &source_layers = region.source_layers; - for (size_t i = 0; i < source_layers.size(); i++) { - *out << source_layers[i]; - if (i < source_layers.size() - 1) { - *out << " "; - } - } - - *out << ")"; -} - void DrmDisplayComposition::Dump(std::ostringstream *out) const { *out << "----DrmDisplayComposition" << " crtc=" << (crtc_ ? crtc_->id() : -1) @@ -540,10 +254,6 @@ void DrmDisplayComposition::Dump(std::ostringstream *out) const { break; } - *out << " timeline[current/squash/pre-comp/done]=" << timeline_current_ << "/" - << timeline_squash_done_ << "/" << timeline_pre_comp_done_ << "/" - << timeline_ << "\n"; - *out << " Layers: count=" << layers_.size() << "\n"; for (size_t i = 0; i < layers_.size(); i++) { const DrmHwcLayer &layer = layers_[i]; @@ -557,12 +267,7 @@ void DrmDisplayComposition::Dump(std::ostringstream *out) const { *out << " transform="; DumpTransform(layer.transform, out); *out << " blending[a=" << (int)layer.alpha - << "]=" << BlendingToString(layer.blending) << " source_crop"; - layer.source_crop.Dump(out); - *out << " display_frame"; - layer.display_frame.Dump(out); - - *out << "\n"; + << "]=" << BlendingToString(layer.blending) << "\n"; } *out << " Planes: count=" << composition_planes_.size() << "\n"; @@ -578,12 +283,6 @@ void DrmDisplayComposition::Dump(std::ostringstream *out) const { case DrmCompositionPlane::Type::kLayer: *out << "LAYER"; break; - case DrmCompositionPlane::Type::kPrecomp: - *out << "PRECOMP"; - break; - case DrmCompositionPlane::Type::kSquash: - *out << "SQUASH"; - break; default: *out << "<invalid>"; break; @@ -595,19 +294,5 @@ void DrmDisplayComposition::Dump(std::ostringstream *out) const { } *out << "\n"; } - - *out << " Squash Regions: count=" << squash_regions_.size() << "\n"; - for (size_t i = 0; i < squash_regions_.size(); i++) { - *out << " [" << i << "] "; - DumpRegion(squash_regions_[i], out); - *out << "\n"; - } - - *out << " Pre-Comp Regions: count=" << pre_comp_regions_.size() << "\n"; - for (size_t i = 0; i < pre_comp_regions_.size(); i++) { - *out << " [" << i << "] "; - DumpRegion(pre_comp_regions_[i], out); - *out << "\n"; - } } } diff --git a/drmdisplaycomposition.h b/drmdisplaycomposition.h index 9183925..b4c5892 100644 --- a/drmdisplaycomposition.h +++ b/drmdisplaycomposition.h @@ -20,12 +20,10 @@ #include "drmcrtc.h" #include "drmhwcomposer.h" #include "drmplane.h" -#include "glworker.h" #include <sstream> #include <vector> -#include <hardware/gralloc.h> #include <hardware/hardware.h> #include <hardware/hwcomposer.h> @@ -53,7 +51,6 @@ struct DrmCompositionDisplayLayersMap { }; struct DrmCompositionRegion { - DrmHwcRect<int> frame; std::vector<size_t> source_layers; }; @@ -62,8 +59,6 @@ class DrmCompositionPlane { enum class Type : int32_t { kDisable, kLayer, - kPrecomp, - kSquash, }; DrmCompositionPlane() = default; @@ -125,34 +120,13 @@ class DrmDisplayComposition { int SetDpmsMode(uint32_t dpms_mode); int SetDisplayMode(const DrmMode &display_mode); - int Plan(SquashState *squash, std::vector<DrmPlane *> *primary_planes, + int Plan(std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes); - int FinalizeComposition(); - - int CreateNextTimelineFence(); - int SignalSquashDone() { - return IncreaseTimelineToPoint(timeline_squash_done_); - } - int SignalPreCompDone() { - return IncreaseTimelineToPoint(timeline_pre_comp_done_); - } - int SignalCompositionDone() { - return IncreaseTimelineToPoint(timeline_); - } - std::vector<DrmHwcLayer> &layers() { return layers_; } - std::vector<DrmCompositionRegion> &squash_regions() { - return squash_regions_; - } - - std::vector<DrmCompositionRegion> &pre_comp_regions() { - return pre_comp_regions_; - } - std::vector<DrmCompositionPlane> &composition_planes() { return composition_planes_; } @@ -202,13 +176,6 @@ class DrmDisplayComposition { private: bool validate_composition_type(DrmCompositionType desired); - int IncreaseTimelineToPoint(int point); - - int FinalizeComposition(DrmHwcRect<int> *exclude_rects, - size_t num_exclude_rects); - void SeparateLayers(DrmHwcRect<int> *exclude_rects, size_t num_exclude_rects); - int CreateAndAssignReleaseFences(); - DrmResources *drm_ = NULL; DrmCrtc *crtc_ = NULL; Importer *importer_ = NULL; @@ -218,17 +185,10 @@ class DrmDisplayComposition { uint32_t dpms_mode_ = DRM_MODE_DPMS_ON; DrmMode display_mode_; - int timeline_fd_ = -1; - int timeline_ = 0; - int timeline_current_ = 0; - int timeline_squash_done_ = 0; - int timeline_pre_comp_done_ = 0; UniqueFd out_fence_ = -1; bool geometry_changed_; std::vector<DrmHwcLayer> layers_; - std::vector<DrmCompositionRegion> squash_regions_; - std::vector<DrmCompositionRegion> pre_comp_regions_; std::vector<DrmCompositionPlane> composition_planes_; uint64_t frame_no_ = 0; diff --git a/drmdisplaycompositor.cpp b/drmdisplaycompositor.cpp index e556e86..e7e0694 100644 --- a/drmdisplaycompositor.cpp +++ b/drmdisplaycompositor.cpp @@ -26,7 +26,7 @@ #include <sstream> #include <vector> -#include <cutils/log.h> +#include <log/log.h> #include <drm/drm_mode.h> #include <sync/sync.h> #include <utils/Trace.h> @@ -35,153 +35,15 @@ #include "drmcrtc.h" #include "drmplane.h" #include "drmresources.h" -#include "glworker.h" namespace android { -void SquashState::Init(DrmHwcLayer *layers, size_t num_layers) { - generation_number_++; - valid_history_ = 0; - regions_.clear(); - last_handles_.clear(); - - std::vector<DrmHwcRect<int>> in_rects; - for (size_t i = 0; i < num_layers; i++) { - DrmHwcLayer *layer = &layers[i]; - in_rects.emplace_back(layer->display_frame); - last_handles_.push_back(layer->sf_handle); - } - - std::vector<separate_rects::RectSet<uint64_t, int>> out_regions; - separate_rects::separate_rects_64(in_rects, &out_regions); - - for (const separate_rects::RectSet<uint64_t, int> &out_region : out_regions) { - regions_.emplace_back(); - Region ®ion = regions_.back(); - region.rect = out_region.rect; - region.layer_refs = out_region.id_set.getBits(); - } -} - -void SquashState::GenerateHistory(DrmHwcLayer *layers, size_t num_layers, - std::vector<bool> &changed_regions) const { - changed_regions.resize(regions_.size()); - if (num_layers != last_handles_.size()) { - ALOGE("SquashState::GenerateHistory expected %zu layers but got %zu layers", - last_handles_.size(), num_layers); - return; - } - std::bitset<kMaxLayers> changed_layers; - for (size_t i = 0; i < last_handles_.size(); i++) { - DrmHwcLayer *layer = &layers[i]; - // Protected layers can't be squashed so we treat them as constantly - // changing. - if (layer->protected_usage() || last_handles_[i] != layer->sf_handle) - changed_layers.set(i); - } - - for (size_t i = 0; i < regions_.size(); i++) { - changed_regions[i] = (regions_[i].layer_refs & changed_layers).any(); - } -} - -void SquashState::StableRegionsWithMarginalHistory( - const std::vector<bool> &changed_regions, - std::vector<bool> &stable_regions) const { - stable_regions.resize(regions_.size()); - for (size_t i = 0; i < regions_.size(); i++) { - stable_regions[i] = !changed_regions[i] && is_stable(i); - } -} - -void SquashState::RecordHistory(DrmHwcLayer *layers, size_t num_layers, - const std::vector<bool> &changed_regions) { - if (num_layers != last_handles_.size()) { - ALOGE("SquashState::RecordHistory expected %zu layers but got %zu layers", - last_handles_.size(), num_layers); - return; - } - if (changed_regions.size() != regions_.size()) { - ALOGE("SquashState::RecordHistory expected %zu regions but got %zu regions", - regions_.size(), changed_regions.size()); - return; - } - - for (size_t i = 0; i < last_handles_.size(); i++) { - DrmHwcLayer *layer = &layers[i]; - last_handles_[i] = layer->sf_handle; - } - - for (size_t i = 0; i < regions_.size(); i++) { - regions_[i].change_history <<= 1; - regions_[i].change_history.set(/* LSB */ 0, changed_regions[i]); - } - - valid_history_++; -} - -bool SquashState::RecordAndCompareSquashed( - const std::vector<bool> &squashed_regions) { - if (squashed_regions.size() != regions_.size()) { - ALOGE( - "SquashState::RecordAndCompareSquashed expected %zu regions but got " - "%zu regions", - regions_.size(), squashed_regions.size()); - return false; - } - bool changed = false; - for (size_t i = 0; i < regions_.size(); i++) { - if (regions_[i].squashed != squashed_regions[i]) { - regions_[i].squashed = squashed_regions[i]; - changed = true; - } - } - return changed; -} - -void SquashState::Dump(std::ostringstream *out) const { - *out << "----SquashState generation=" << generation_number_ - << " history=" << valid_history_ << "\n" - << " Regions: count=" << regions_.size() << "\n"; - for (size_t i = 0; i < regions_.size(); i++) { - const Region ®ion = regions_[i]; - *out << " [" << i << "]" - << " history=" << region.change_history << " rect"; - region.rect.Dump(out); - *out << " layers=("; - bool first = true; - for (size_t layer_index = 0; layer_index < kMaxLayers; layer_index++) { - if ((region.layer_refs & - std::bitset<kMaxLayers>((size_t)1 << layer_index)) - .any()) { - if (!first) - *out << " "; - first = false; - *out << layer_index; - } - } - *out << ")"; - if (region.squashed) - *out << " squashed"; - *out << "\n"; - } -} - -static bool UsesSquash(const std::vector<DrmCompositionPlane> &comp_planes) { - return std::any_of(comp_planes.begin(), comp_planes.end(), - [](const DrmCompositionPlane &plane) { - return plane.type() == DrmCompositionPlane::Type::kSquash; - }); -} - DrmDisplayCompositor::DrmDisplayCompositor() : drm_(NULL), display_(-1), initialized_(false), active_(false), use_hw_overlays_(true), - framebuffer_index_(0), - squash_framebuffer_index_(0), dump_frames_composited_(0), dump_last_timestamp_ns_(0) { struct timespec ts; @@ -244,112 +106,6 @@ DrmDisplayCompositor::GetActiveModeResolution() { return std::make_tuple(mode.h_display(), mode.v_display(), 0); } -int DrmDisplayCompositor::PrepareFramebuffer( - DrmFramebuffer &fb, DrmDisplayComposition *display_comp) { - int ret = fb.WaitReleased(-1); - if (ret) { - ALOGE("Failed to wait for framebuffer release %d", ret); - return ret; - } - uint32_t width, height; - std::tie(width, height, ret) = GetActiveModeResolution(); - if (ret) { - ALOGE( - "Failed to allocate framebuffer because the display resolution could " - "not be determined %d", - ret); - return ret; - } - - fb.set_release_fence_fd(-1); - if (!fb.Allocate(width, height)) { - ALOGE("Failed to allocate framebuffer with size %dx%d", width, height); - return -ENOMEM; - } - - display_comp->layers().emplace_back(); - DrmHwcLayer &pre_comp_layer = display_comp->layers().back(); - pre_comp_layer.sf_handle = fb.buffer()->handle; - pre_comp_layer.blending = DrmHwcBlending::kPreMult; - pre_comp_layer.source_crop = DrmHwcRect<float>(0, 0, width, height); - pre_comp_layer.display_frame = DrmHwcRect<int>(0, 0, width, height); - ret = pre_comp_layer.buffer.ImportBuffer(fb.buffer()->handle, - display_comp->importer()); - if (ret) { - ALOGE("Failed to import framebuffer for display %d", ret); - return ret; - } - - return ret; -} - -int DrmDisplayCompositor::ApplySquash(DrmDisplayComposition *display_comp) { - int ret = 0; - - DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_]; - ret = PrepareFramebuffer(fb, display_comp); - if (ret) { - ALOGE("Failed to prepare framebuffer for squash %d", ret); - return ret; - } - - std::vector<DrmCompositionRegion> ®ions = display_comp->squash_regions(); - ret = pre_compositor_->Composite(display_comp->layers().data(), - regions.data(), regions.size(), fb.buffer(), - display_comp->importer()); - pre_compositor_->Finish(); - - if (ret) { - ALOGE("Failed to squash layers"); - return ret; - } - - ret = display_comp->CreateNextTimelineFence(); - if (ret <= 0) { - ALOGE("Failed to create squash framebuffer release fence %d", ret); - return ret; - } - - fb.set_release_fence_fd(ret); - display_comp->SignalSquashDone(); - - return 0; -} - -int DrmDisplayCompositor::ApplyPreComposite( - DrmDisplayComposition *display_comp) { - int ret = 0; - - DrmFramebuffer &fb = framebuffers_[framebuffer_index_]; - ret = PrepareFramebuffer(fb, display_comp); - if (ret) { - ALOGE("Failed to prepare framebuffer for pre-composite %d", ret); - return ret; - } - - std::vector<DrmCompositionRegion> ®ions = display_comp->pre_comp_regions(); - ret = pre_compositor_->Composite(display_comp->layers().data(), - regions.data(), regions.size(), fb.buffer(), - display_comp->importer()); - pre_compositor_->Finish(); - - if (ret) { - ALOGE("Failed to pre-composite layers"); - return ret; - } - - ret = display_comp->CreateNextTimelineFence(); - if (ret <= 0) { - ALOGE("Failed to create pre-composite framebuffer release fence %d", ret); - return ret; - } - - fb.set_release_fence_fd(ret); - display_comp->SignalPreCompDone(); - - return 0; -} - int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) { drmModeAtomicReqPtr pset = drmModeAtomicAlloc(); if (!pset) { @@ -384,103 +140,6 @@ int DrmDisplayCompositor::DisablePlanes(DrmDisplayComposition *display_comp) { return 0; } -int DrmDisplayCompositor::PrepareFrame(DrmDisplayComposition *display_comp) { - int ret = 0; - - std::vector<DrmHwcLayer> &layers = display_comp->layers(); - std::vector<DrmCompositionPlane> &comp_planes = - display_comp->composition_planes(); - std::vector<DrmCompositionRegion> &squash_regions = - display_comp->squash_regions(); - 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; - ret = ApplySquash(display_comp); - if (ret) - return ret; - - squash_layer_index = layers.size() - 1; - } else { - if (UsesSquash(comp_planes)) { - DrmFramebuffer &fb = squash_framebuffers_[squash_framebuffer_index_]; - layers.emplace_back(); - squash_layer_index = layers.size() - 1; - DrmHwcLayer &squash_layer = layers.back(); - ret = squash_layer.buffer.ImportBuffer(fb.buffer()->handle, - display_comp->importer()); - if (ret) { - ALOGE("Failed to import old squashed framebuffer %d", ret); - return ret; - } - squash_layer.sf_handle = fb.buffer()->handle; - squash_layer.blending = DrmHwcBlending::kPreMult; - squash_layer.source_crop = DrmHwcRect<float>( - 0, 0, squash_layer.buffer->width, squash_layer.buffer->height); - squash_layer.display_frame = DrmHwcRect<int>( - 0, 0, squash_layer.buffer->width, squash_layer.buffer->height); - ret = display_comp->CreateNextTimelineFence(); - - if (ret <= 0) { - ALOGE("Failed to create squash framebuffer release fence %d", ret); - return ret; - } - - fb.set_release_fence_fd(ret); - ret = 0; - } - } - - bool do_pre_comp = pre_comp_regions.size() > 0; - int pre_comp_layer_index = -1; - if (do_pre_comp) { - ret = ApplyPreComposite(display_comp); - if (ret) - return ret; - - pre_comp_layer_index = layers.size() - 1; - framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; - } - - for (DrmCompositionPlane &comp_plane : comp_planes) { - std::vector<size_t> &source_layers = comp_plane.source_layers(); - switch (comp_plane.type()) { - case DrmCompositionPlane::Type::kSquash: - if (source_layers.size()) - ALOGE("Squash source_layers is expected to be empty (%zu/%d)", - source_layers[0], squash_layer_index); - source_layers.push_back(squash_layer_index); - break; - case DrmCompositionPlane::Type::kPrecomp: - if (!do_pre_comp) { - ALOGE( - "Can not use pre composite framebuffer with no pre composite " - "regions"); - return -EINVAL; - } - // Replace source_layers with the output of the precomposite - source_layers.clear(); - source_layers.push_back(pre_comp_layer_index); - break; - default: - break; - } - } - - return ret; -} - int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, bool test_only) { ATRACE_CALL(); @@ -546,10 +205,10 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, int fb_id = -1; int fence_fd = -1; - DrmHwcRect<int> display_frame; - DrmHwcRect<float> source_crop; + hwc_rect_t display_frame; + hwc_frect_t source_crop; uint64_t rotation = 0; - uint64_t alpha = 0xFF; + uint64_t alpha = 0xFFFF; if (comp_plane.type() != DrmCompositionPlane::Type::kDisable) { if (source_layers.size() > 1) { @@ -618,14 +277,14 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, // TODO: Once we have atomic test, this should fall back to GL if (rotation != DRM_MODE_ROTATE_0 && plane->rotation_property().id() == 0) { - ALOGE("Rotation is not supported on plane %d", plane->id()); + 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 != 0xFF && plane->alpha_property().id() == 0) { - ALOGE("Alpha is not supported on plane %d", plane->id()); + if (alpha != 0xFFFF && plane->alpha_property().id() == 0) { + ALOGV("Alpha is not supported on plane %d", plane->id()); ret = -EINVAL; break; } @@ -693,9 +352,7 @@ int DrmDisplayCompositor::CommitFrame(DrmDisplayComposition *display_comp, ret = drmModeAtomicCommit(drm_->fd(), pset, flags, drm_); if (ret) { - if (test_only) - ALOGI("Commit test pset failed ret=%d\n", ret); - else + if (!test_only) ALOGE("Failed to commit pset ret=%d\n", ret); drmModeAtomicFree(pset); return ret; @@ -778,8 +435,6 @@ void DrmDisplayCompositor::ClearDisplay() { if (DisablePlanes(active_composition_.get())) return; - active_composition_->SignalCompositionDone(); - active_composition_.reset(NULL); } @@ -799,9 +454,6 @@ void DrmDisplayCompositor::ApplyFrame( } ++dump_frames_composited_; - if (active_composition_) - active_composition_->SignalCompositionDone(); - ret = pthread_mutex_lock(&lock_); if (ret) ALOGE("Failed to acquire lock for active_composition swap"); @@ -819,38 +471,16 @@ int DrmDisplayCompositor::ApplyComposition( int ret = 0; switch (composition->type()) { case DRM_COMPOSITION_TYPE_FRAME: - ret = PrepareFrame(composition.get()); - if (ret) { - ALOGE("Failed to prepare frame for display %d", display_); - return ret; - } if (composition->geometry_changed()) { // Send the composition to the kernel to ensure we can commit it. This - // is just a test, it won't actually commit the frame. If rejected, - // squash the frame into one layer and use the squashed composition + // is just a test, it won't actually commit the frame. ret = CommitFrame(composition.get(), true); - if (ret) - ALOGI("Commit test failed, squashing frame for display %d", display_); - use_hw_overlays_ = !ret; - } - - // If use_hw_overlays_ is false, we can't use hardware to composite the - // frame. So squash all layers into a single composition and apply that - // instead. - if (!use_hw_overlays_) { - std::unique_ptr<DrmDisplayComposition> squashed = CreateComposition(); - ret = SquashFrame(composition.get(), squashed.get()); - if (!ret) { - composition = std::move(squashed); - } else { - ALOGE("Failed to squash frame for display %d", display_); - // Disable the hw used by the last active composition. This allows us - // to signal the release fences from that composition to avoid - // hanging. - ClearDisplay(); + if (ret) { + ALOGE("Commit test failed for display %d, FIXME", display_); return ret; } } + ApplyFrame(std::move(composition), ret); break; case DRM_COMPOSITION_TYPE_DPMS: @@ -878,152 +508,8 @@ int DrmDisplayCompositor::ApplyComposition( return ret; } -int DrmDisplayCompositor::SquashAll() { - AutoLock lock(&lock_, "compositor"); - int ret = lock.Lock(); - if (ret) - return ret; - - if (!active_composition_) - return 0; - - std::unique_ptr<DrmDisplayComposition> comp = CreateComposition(); - ret = SquashFrame(active_composition_.get(), comp.get()); - - // ApplyFrame needs the lock - lock.Unlock(); - - if (!ret) - ApplyFrame(std::move(comp), 0); - - return ret; -} - -// Returns: -// - 0 if src is successfully squashed into dst -// - -EALREADY if the src is already squashed -// - Appropriate error if the squash fails -int DrmDisplayCompositor::SquashFrame(DrmDisplayComposition *src, - DrmDisplayComposition *dst) { - if (src->type() != DRM_COMPOSITION_TYPE_FRAME) - return -ENOTSUP; - - std::vector<DrmCompositionPlane> &src_planes = src->composition_planes(); - std::vector<DrmHwcLayer> &src_layers = src->layers(); - - // Make sure there is more than one layer to squash. - size_t src_planes_with_layer = std::count_if( - src_planes.begin(), src_planes.end(), [](DrmCompositionPlane &p) { - return p.type() != DrmCompositionPlane::Type::kDisable; - }); - if (src_planes_with_layer <= 1) - return -EALREADY; - - int pre_comp_layer_index; - - int ret = dst->Init(drm_, src->crtc(), src->importer(), src->planner(), - src->frame_no()); - if (ret) { - ALOGE("Failed to init squash all composition %d", ret); - return ret; - } - - DrmCompositionPlane squashed_comp(DrmCompositionPlane::Type::kPrecomp, NULL, - src->crtc()); - std::vector<DrmHwcLayer> dst_layers; - for (DrmCompositionPlane &comp_plane : src_planes) { - // Composition planes without DRM planes should never happen - if (comp_plane.plane() == NULL) { - ALOGE("Skipping squash all because of NULL plane"); - ret = -EINVAL; - goto move_layers_back; - } - - if (comp_plane.plane()->type() == DRM_PLANE_TYPE_PRIMARY) - squashed_comp.set_plane(comp_plane.plane()); - else - dst->AddPlaneDisable(comp_plane.plane()); - - if (comp_plane.type() == DrmCompositionPlane::Type::kDisable) - continue; - - for (auto i : comp_plane.source_layers()) { - DrmHwcLayer &layer = src_layers[i]; - - // Squashing protected layers is impossible. - if (layer.protected_usage()) { - ret = -ENOTSUP; - goto move_layers_back; - } - - // The OutputFds point to freed memory after hwc_set returns. They are - // returned to the default to prevent DrmDisplayComposition::Plan from - // filling the OutputFds. - layer.release_fence = OutputFd(); - dst_layers.emplace_back(std::move(layer)); - squashed_comp.source_layers().push_back( - squashed_comp.source_layers().size()); - } - } - - if (squashed_comp.plane() == NULL) { - ALOGE("Primary plane not found for squash"); - ret = -ENOTSUP; - goto move_layers_back; - } - - ret = dst->SetLayers(dst_layers.data(), dst_layers.size(), false); - if (ret) { - ALOGE("Failed to set layers for squash all composition %d", ret); - goto move_layers_back; - } - - ret = dst->AddPlaneComposition(std::move(squashed_comp)); - if (ret) { - ALOGE("Failed to add squashed plane composition %d", ret); - goto move_layers_back; - } - - ret = dst->FinalizeComposition(); - if (ret) { - ALOGE("Failed to plan for squash all composition %d", ret); - goto move_layers_back; - } - - ret = ApplyPreComposite(dst); - if (ret) { - ALOGE("Failed to pre-composite for squash all composition %d", ret); - goto move_layers_back; - } - - pre_comp_layer_index = dst->layers().size() - 1; - framebuffer_index_ = (framebuffer_index_ + 1) % DRM_DISPLAY_BUFFERS; - - for (DrmCompositionPlane &plane : dst->composition_planes()) { - if (plane.type() == DrmCompositionPlane::Type::kPrecomp) { - // Replace source_layers with the output of the precomposite - plane.source_layers().clear(); - plane.source_layers().push_back(pre_comp_layer_index); - break; - } - } - - return 0; - -// TODO(zachr): think of a better way to transfer ownership back to the active -// composition. -move_layers_back: - for (size_t plane_index = 0; - plane_index < src_planes.size() && plane_index < dst_layers.size();) { - if (src_planes[plane_index].source_layers().empty()) { - plane_index++; - continue; - } - for (auto i : src_planes[plane_index].source_layers()) - src_layers[i] = std::move(dst_layers[plane_index++]); - } - - return ret; +int DrmDisplayCompositor::TestComposition(DrmDisplayComposition *composition) { + return CommitFrame(composition, true); } void DrmDisplayCompositor::Dump(std::ostringstream *out) const { @@ -1051,11 +537,6 @@ void DrmDisplayCompositor::Dump(std::ostringstream *out) const { dump_last_timestamp_ns_ = cur_ts; - if (active_composition_) - active_composition_->Dump(out); - - squash_state_.Dump(out); - pthread_mutex_unlock(&lock_); } } diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h index f1965fb..0d85949 100644 --- a/drmdisplaycompositor.h +++ b/drmdisplaycompositor.h @@ -20,7 +20,6 @@ #include "drmhwcomposer.h" #include "drmdisplaycomposition.h" #include "drmframebuffer.h" -#include "separate_rects.h" #include <pthread.h> #include <memory> @@ -36,49 +35,6 @@ namespace android { -class GLWorkerCompositor; - -class SquashState { - public: - static const unsigned kHistoryLength = 6; // TODO: make this number not magic - static const unsigned kMaxLayers = 64; - - struct Region { - DrmHwcRect<int> rect; - std::bitset<kMaxLayers> layer_refs; - std::bitset<kHistoryLength> change_history; - bool squashed = false; - }; - - bool is_stable(int region_index) const { - return valid_history_ >= kHistoryLength && - regions_[region_index].change_history.none(); - } - - const std::vector<Region> ®ions() const { - return regions_; - } - - void Init(DrmHwcLayer *layers, size_t num_layers); - void GenerateHistory(DrmHwcLayer *layers, size_t num_layers, - std::vector<bool> &changed_regions) const; - void StableRegionsWithMarginalHistory( - const std::vector<bool> &changed_regions, - std::vector<bool> &stable_regions) const; - void RecordHistory(DrmHwcLayer *layers, size_t num_layers, - const std::vector<bool> &changed_regions); - bool RecordAndCompareSquashed(const std::vector<bool> &squashed_regions); - - void Dump(std::ostringstream *out) const; - - private: - size_t generation_number_ = 0; - unsigned valid_history_ = 0; - std::vector<buffer_handle_t> last_handles_; - - std::vector<Region> regions_; -}; - class DrmDisplayCompositor { public: DrmDisplayCompositor(); @@ -88,16 +44,12 @@ class DrmDisplayCompositor { std::unique_ptr<DrmDisplayComposition> CreateComposition() const; int ApplyComposition(std::unique_ptr<DrmDisplayComposition> composition); + int TestComposition(DrmDisplayComposition *composition); int Composite(); - int SquashAll(); void Dump(std::ostringstream *out) const; std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution(); - SquashState *squash_state() { - return &squash_state_; - } - private: struct ModeState { bool needs_modeset = false; @@ -115,11 +67,8 @@ class DrmDisplayCompositor { int PrepareFramebuffer(DrmFramebuffer &fb, DrmDisplayComposition *display_comp); - int ApplySquash(DrmDisplayComposition *display_comp); - int ApplyPreComposite(DrmDisplayComposition *display_comp); int PrepareFrame(DrmDisplayComposition *display_comp); int CommitFrame(DrmDisplayComposition *display_comp, bool test_only); - int SquashFrame(DrmDisplayComposition *src, DrmDisplayComposition *dst); int ApplyDpms(DrmDisplayComposition *display_comp); int DisablePlanes(DrmDisplayComposition *display_comp); @@ -142,11 +91,6 @@ class DrmDisplayCompositor { int framebuffer_index_; DrmFramebuffer framebuffers_[DRM_DISPLAY_BUFFERS]; - std::unique_ptr<GLWorkerCompositor> pre_compositor_; - - SquashState squash_state_; - int squash_framebuffer_index_; - DrmFramebuffer squash_framebuffers_[2]; // mutable since we need to acquire in Dump() mutable pthread_mutex_t lock_; diff --git a/drmeventlistener.cpp b/drmeventlistener.cpp index 984d1dd..9cdff81 100644 --- a/drmeventlistener.cpp +++ b/drmeventlistener.cpp @@ -24,7 +24,7 @@ #include <linux/netlink.h> #include <sys/socket.h> -#include <cutils/log.h> +#include <log/log.h> #include <hardware/hardware.h> #include <hardware/hwcomposer.h> #include <xf86drm.h> @@ -46,7 +46,7 @@ int DrmEventListener::Init() { struct sockaddr_nl addr; memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; - addr.nl_pid = getpid(); + addr.nl_pid = 0; addr.nl_groups = 0xFFFFFFFF; int ret = bind(uevent_fd_.get(), (struct sockaddr *)&addr, sizeof(addr)); diff --git a/drmhwcomposer.h b/drmhwcomposer.h index f8440fb..f3b000b 100644 --- a/drmhwcomposer.h +++ b/drmhwcomposer.h @@ -20,10 +20,11 @@ #include <stdbool.h> #include <stdint.h> +#include <vector> + #include <hardware/hardware.h> #include <hardware/hwcomposer.h> #include "autofd.h" -#include "separate_rects.h" #include "drmhwcgralloc.h" struct hwc_import_context; @@ -81,13 +82,10 @@ class DrmHwcNativeHandle { public: DrmHwcNativeHandle() = default; - DrmHwcNativeHandle(const gralloc_module_t *gralloc, native_handle_t *handle) - : gralloc_(gralloc), handle_(handle) { + DrmHwcNativeHandle(native_handle_t *handle) : handle_(handle) { } DrmHwcNativeHandle(DrmHwcNativeHandle &&rhs) { - gralloc_ = rhs.gralloc_; - rhs.gralloc_ = NULL; handle_ = rhs.handle_; rhs.handle_ = NULL; } @@ -96,14 +94,12 @@ class DrmHwcNativeHandle { DrmHwcNativeHandle &operator=(DrmHwcNativeHandle &&rhs) { Clear(); - gralloc_ = rhs.gralloc_; - rhs.gralloc_ = NULL; handle_ = rhs.handle_; rhs.handle_ = NULL; return *this; } - int CopyBufferHandle(buffer_handle_t handle, const gralloc_module_t *gralloc); + int CopyBufferHandle(buffer_handle_t handle); void Clear(); @@ -112,13 +108,9 @@ class DrmHwcNativeHandle { } private: - const gralloc_module_t *gralloc_ = NULL; native_handle_t *handle_ = NULL; }; -template <typename T> -using DrmHwcRect = separate_rects::Rect<T>; - enum DrmHwcTransform { kIdentity = 0, kFlipH = 1 << 0, @@ -141,16 +133,14 @@ struct DrmHwcLayer { DrmHwcNativeHandle handle; uint32_t transform; DrmHwcBlending blending = DrmHwcBlending::kNone; - uint8_t alpha = 0xff; - DrmHwcRect<float> source_crop; - DrmHwcRect<int> display_frame; + uint16_t alpha = 0xffff; + hwc_frect_t source_crop; + hwc_rect_t display_frame; UniqueFd acquire_fence; OutputFd release_fence; - int InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer, - const gralloc_module_t *gralloc); - int ImportBuffer(Importer *importer, const gralloc_module_t *gralloc); + int ImportBuffer(Importer *importer); void SetTransform(int32_t sf_transform); void SetSourceCrop(hwc_frect_t const &crop); diff --git a/drmhwctwo.cpp b/drmhwctwo.cpp index 5ab4595..6bab17b 100644 --- a/drmhwctwo.cpp +++ b/drmhwctwo.cpp @@ -26,7 +26,7 @@ #include <inttypes.h> #include <string> -#include <cutils/log.h> +#include <log/log.h> #include <cutils/properties.h> #include <hardware/hardware.h> #include <hardware/hwcomposer2.h> @@ -70,17 +70,9 @@ HWC2::Error DrmHwcTwo::Init() { return HWC2::Error::NoResources; } - ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, - (const hw_module_t **)&gralloc_); - if (ret) { - ALOGE("Failed to open gralloc module %d", ret); - return HWC2::Error::NoResources; - } - displays_.emplace(std::piecewise_construct, std::forward_as_tuple(HWC_DISPLAY_PRIMARY), - std::forward_as_tuple(&drm_, importer_, gralloc_, - HWC_DISPLAY_PRIMARY, + std::forward_as_tuple(&drm_, importer_, HWC_DISPLAY_PRIMARY, HWC2::DisplayType::Physical)); DrmCrtc *crtc = drm_.GetCrtcForDisplay(static_cast<int>(HWC_DISPLAY_PRIMARY)); @@ -160,13 +152,8 @@ HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor, DrmHwcTwo::HwcDisplay::HwcDisplay(DrmResources *drm, std::shared_ptr<Importer> importer, - const gralloc_module_t *gralloc, hwc2_display_t handle, HWC2::DisplayType type) - : drm_(drm), - importer_(importer), - gralloc_(gralloc), - handle_(handle), - type_(type) { + : drm_(drm), importer_(importer), handle_(handle), type_(type) { supported(__func__); } @@ -480,8 +467,7 @@ void DrmHwcTwo::HwcDisplay::AddFenceToRetireFence(int fd) { } } -HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) { - supported(__func__); +HWC2::Error DrmHwcTwo::HwcDisplay::CreateComposition(bool test) { std::vector<DrmCompositionDisplayLayersMap> layers_map; layers_map.emplace_back(); DrmCompositionDisplayLayersMap &map = layers_map.back(); @@ -491,17 +477,23 @@ HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) { // order the layers by z-order bool use_client_layer = false; - uint32_t client_z_order = 0; + uint32_t client_z_order = UINT32_MAX; std::map<uint32_t, DrmHwcTwo::HwcLayer *> z_map; for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { - switch (l.second.validated_type()) { + HWC2::Composition comp_type; + if (test) + comp_type = l.second.sf_type(); + else + comp_type = l.second.validated_type(); + + switch (comp_type) { case HWC2::Composition::Device: z_map.emplace(std::make_pair(l.second.z_order(), &l.second)); break; case HWC2::Composition::Client: - // Place it at the z_order of the highest client layer + // Place it at the z_order of the lowest client layer use_client_layer = true; - client_z_order = std::max(client_z_order, l.second.z_order()); + client_z_order = std::min(client_z_order, l.second.z_order()); break; default: continue; @@ -510,21 +502,20 @@ HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) { if (use_client_layer) z_map.emplace(std::make_pair(client_z_order, &client_layer_)); + if (z_map.empty()) + return HWC2::Error::BadLayer; + // now that they're ordered by z, add them to the composition for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) { DrmHwcLayer layer; l.second->PopulateDrmLayer(&layer); - int ret = layer.ImportBuffer(importer_.get(), gralloc_); + int ret = layer.ImportBuffer(importer_.get()); if (ret) { ALOGE("Failed to import layer, ret=%d", ret); return HWC2::Error::NoResources; } map.layers.emplace_back(std::move(layer)); } - if (map.layers.empty()) { - *retire_fence = -1; - return HWC2::Error::None; - } std::unique_ptr<DrmDisplayComposition> composition = compositor_.CreateComposition(); @@ -539,8 +530,7 @@ HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) { std::vector<DrmPlane *> primary_planes(primary_planes_); std::vector<DrmPlane *> overlay_planes(overlay_planes_); - ret = composition->Plan(compositor_.squash_state(), &primary_planes, - &overlay_planes); + ret = composition->Plan(&primary_planes, &overlay_planes); if (ret) { ALOGE("Failed to plan the composition ret=%d", ret); return HWC2::Error::BadConfig; @@ -556,13 +546,32 @@ HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) { i = overlay_planes.erase(i); } - AddFenceToRetireFence(composition->take_out_fence()); - - ret = compositor_.ApplyComposition(std::move(composition)); + if (test) { + ret = compositor_.TestComposition(composition.get()); + } else { + AddFenceToRetireFence(composition->take_out_fence()); + ret = compositor_.ApplyComposition(std::move(composition)); + } if (ret) { - ALOGE("Failed to apply the frame composition ret=%d", ret); + if (!test) + ALOGE("Failed to apply the frame composition ret=%d", ret); return HWC2::Error::BadParameter; } + return HWC2::Error::None; +} + +HWC2::Error DrmHwcTwo::HwcDisplay::PresentDisplay(int32_t *retire_fence) { + supported(__func__); + HWC2::Error ret; + + ret = CreateComposition(false); + if (ret == HWC2::Error::BadLayer) { + // Can we really have no client or device layers? + *retire_fence = -1; + return HWC2::Error::None; + } + if (ret != HWC2::Error::None) + return ret; // The retire fence returned here is for the last frame, so return it and // promote the next retire fence @@ -684,11 +693,47 @@ HWC2::Error DrmHwcTwo::HwcDisplay::SetVsyncEnabled(int32_t enabled) { HWC2::Error DrmHwcTwo::HwcDisplay::ValidateDisplay(uint32_t *num_types, uint32_t *num_requests) { supported(__func__); + size_t plane_count = 0; *num_types = 0; *num_requests = 0; + size_t avail_planes = primary_planes_.size() + overlay_planes_.size(); + + HWC2::Error ret; + + for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) + l.second.set_validated_type(HWC2::Composition::Invalid); + + ret = CreateComposition(true); + if (ret != HWC2::Error::None) + // Assume the test failed due to overlay planes + avail_planes = 1; + + std::map<uint32_t, DrmHwcTwo::HwcLayer *, std::greater<int>> z_map; + for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { + if (l.second.sf_type() == HWC2::Composition::Device) + z_map.emplace(std::make_pair(l.second.z_order(), &l.second)); + } + + /* + * If more layers then planes, save one plane + * for client composited layers + */ + if (avail_planes < layers_.size()) + avail_planes--; + + for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) { + if (!avail_planes--) + break; + l.second->set_validated_type(HWC2::Composition::Device); + } + for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_) { DrmHwcTwo::HwcLayer &layer = l.second; switch (layer.sf_type()) { + case HWC2::Composition::Device: + if (layer.validated_type() == HWC2::Composition::Device) + break; + // fall thru case HWC2::Composition::SolidColor: case HWC2::Composition::Cursor: case HWC2::Composition::Sideband: @@ -821,7 +866,7 @@ void DrmHwcTwo::HwcLayer::PopulateDrmLayer(DrmHwcLayer *layer) { layer->acquire_fence = acquire_fence_.Release(); layer->release_fence = std::move(release_fence); layer->SetDisplayFrame(display_frame_); - layer->alpha = static_cast<uint8_t>(255.0f * alpha_ + 0.5f); + layer->alpha = static_cast<uint16_t>(65535.0f * alpha_ + 0.5f); layer->SetSourceCrop(source_crop_); layer->SetTransform(static_cast<int32_t>(transform_)); } diff --git a/drmhwctwo.h b/drmhwctwo.h index 0490e2a..82a9768 100644 --- a/drmhwctwo.h +++ b/drmhwctwo.h @@ -136,8 +136,7 @@ class DrmHwcTwo : public hwc2_device_t { class HwcDisplay { public: HwcDisplay(DrmResources *drm, std::shared_ptr<Importer> importer, - const gralloc_module_t *gralloc, hwc2_display_t handle, - HWC2::DisplayType type); + hwc2_display_t handle, HWC2::DisplayType type); HwcDisplay(const HwcDisplay &) = delete; HWC2::Error Init(std::vector<DrmPlane *> *planes); @@ -186,13 +185,13 @@ class DrmHwcTwo : public hwc2_device_t { } private: + HWC2::Error CreateComposition(bool test); void AddFenceToRetireFence(int fd); DrmResources *drm_; DrmDisplayCompositor compositor_; std::shared_ptr<Importer> importer_; std::unique_ptr<Planner> planner_; - const gralloc_module_t *gralloc_; std::vector<DrmPlane *> primary_planes_; std::vector<DrmPlane *> overlay_planes_; @@ -264,7 +263,6 @@ class DrmHwcTwo : public hwc2_device_t { DrmResources drm_; std::shared_ptr<Importer> importer_; // Shared with HwcDisplay - const gralloc_module_t *gralloc_; std::map<hwc2_display_t, HwcDisplay> displays_; std::map<HWC2::Callback, HwcCallback> callbacks_; }; diff --git a/drmplane.cpp b/drmplane.cpp index 1f739ae..4449256 100644 --- a/drmplane.cpp +++ b/drmplane.cpp @@ -23,7 +23,7 @@ #include <errno.h> #include <stdint.h> -#include <cutils/log.h> +#include <log/log.h> #include <xf86drmMode.h> namespace android { diff --git a/drmresources.cpp b/drmresources.cpp index 32dd376..ec6664c 100644 --- a/drmresources.cpp +++ b/drmresources.cpp @@ -30,7 +30,7 @@ #include <xf86drm.h> #include <xf86drmMode.h> -#include <cutils/log.h> +#include <log/log.h> #include <cutils/properties.h> namespace android { diff --git a/glworker.cpp b/glworker.cpp deleted file mode 100644 index ca726bf..0000000 --- a/glworker.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 "hwc-gl-worker" - -#include <algorithm> -#include <string> -#include <sstream> -#include <unordered_set> - -#include <sys/resource.h> - -#include <cutils/properties.h> - -#include <hardware/hardware.h> -#include <hardware/hwcomposer.h> - -#include <ui/GraphicBuffer.h> -#include <ui/PixelFormat.h> - -#include <utils/Trace.h> - -#include "drmdisplaycomposition.h" -#include "platform.h" - -#include "glworker.h" - -#define MAX_OVERLAPPING_LAYERS 64 - -namespace android { - -// clang-format off -// Column-major order: -// float mat[4] = { 1, 2, 3, 4 } === -// [ 1 3 ] -// [ 2 4 ] -float kTextureTransformMatrices[] = { - 1.0f, 0.0f, 0.0f, 1.0f, // identity matrix - 0.0f, 1.0f, 1.0f, 0.0f, // swap x and y -}; -// clang-format on - -static const char *GetGLError(void) { - switch (glGetError()) { - case GL_NO_ERROR: - return "GL_NO_ERROR"; - case GL_INVALID_ENUM: - return "GL_INVALID_ENUM"; - case GL_INVALID_VALUE: - return "GL_INVALID_VALUE"; - case GL_INVALID_OPERATION: - return "GL_INVALID_OPERATION"; - case GL_INVALID_FRAMEBUFFER_OPERATION: - return "GL_INVALID_FRAMEBUFFER_OPERATION"; - case GL_OUT_OF_MEMORY: - return "GL_OUT_OF_MEMORY"; - default: - return "Unknown error"; - } -} - -static const char *GetGLFramebufferError(void) { - switch (glCheckFramebufferStatus(GL_FRAMEBUFFER)) { - case GL_FRAMEBUFFER_COMPLETE: - return "GL_FRAMEBUFFER_COMPLETE"; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; - case GL_FRAMEBUFFER_UNSUPPORTED: - return "GL_FRAMEBUFFER_UNSUPPORTED"; - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; - default: - return "Unknown error"; - } -} - -static const char *GetEGLError(void) { - switch (eglGetError()) { - case EGL_SUCCESS: - return "EGL_SUCCESS"; - case EGL_NOT_INITIALIZED: - return "EGL_NOT_INITIALIZED"; - case EGL_BAD_ACCESS: - return "EGL_BAD_ACCESS"; - case EGL_BAD_ALLOC: - return "EGL_BAD_ALLOC"; - case EGL_BAD_ATTRIBUTE: - return "EGL_BAD_ATTRIBUTE"; - case EGL_BAD_CONTEXT: - return "EGL_BAD_CONTEXT"; - case EGL_BAD_CONFIG: - return "EGL_BAD_CONFIG"; - case EGL_BAD_CURRENT_SURFACE: - return "EGL_BAD_CURRENT_SURFACE"; - case EGL_BAD_DISPLAY: - return "EGL_BAD_DISPLAY"; - case EGL_BAD_SURFACE: - return "EGL_BAD_SURFACE"; - case EGL_BAD_MATCH: - return "EGL_BAD_MATCH"; - case EGL_BAD_PARAMETER: - return "EGL_BAD_PARAMETER"; - case EGL_BAD_NATIVE_PIXMAP: - return "EGL_BAD_NATIVE_PIXMAP"; - case EGL_BAD_NATIVE_WINDOW: - return "EGL_BAD_NATIVE_WINDOW"; - case EGL_CONTEXT_LOST: - return "EGL_CONTEXT_LOST"; - default: - return "Unknown error"; - } -} - -static bool HasExtension(const char *extension, const char *extensions) { - const char *start, *where, *terminator; - start = extensions; - for (;;) { - where = (char *)strstr((const char *)start, extension); - if (!where) - break; - terminator = where + strlen(extension); - if (where == start || *(where - 1) == ' ') - if (*terminator == ' ' || *terminator == '\0') - return true; - start = terminator; - } - 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) { - GLint status; - AutoGLShader shader(glCreateShader(type)); - if (shader.get() == 0) { - if (shader_log) - *shader_log << "Failed glCreateShader call"; - return 0; - } - - glShaderSource(shader.get(), source_count, sources, NULL); - glCompileShader(shader.get()); - glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status); - if (!status) { - if (shader_log) { - GLint log_length; - glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &log_length); - std::string info_log(log_length, ' '); - glGetShaderInfoLog(shader.get(), log_length, NULL, &info_log.front()); - *shader_log << "Failed to compile shader:\n" << info_log.c_str() - << "\nShader Source:\n"; - for (unsigned i = 0; i < source_count; i++) { - *shader_log << sources[i]; - } - *shader_log << "\n"; - } - return 0; - } - - return shader; -} - -static std::string GenerateVertexShader(int layer_count) { - std::ostringstream vertex_shader_stream; - vertex_shader_stream - << "#version 300 es\n" - << "#define LAYER_COUNT " << layer_count << "\n" - << "precision mediump int;\n" - << "uniform vec4 uViewport;\n" - << "uniform vec4 uLayerCrop[LAYER_COUNT];\n" - << "uniform mat2 uTexMatrix[LAYER_COUNT];\n" - << "in vec2 vPosition;\n" - << "in vec2 vTexCoords;\n" - << "out vec2 fTexCoords[LAYER_COUNT];\n" - << "void main() {\n" - << " for (int i = 0; i < LAYER_COUNT; i++) {\n" - << " vec2 tempCoords = vTexCoords * uTexMatrix[i];\n" - << " fTexCoords[i] =\n" - << " uLayerCrop[i].xy + tempCoords * uLayerCrop[i].zw;\n" - << " }\n" - << " vec2 scaledPosition = uViewport.xy + vPosition * uViewport.zw;\n" - << " gl_Position =\n" - << " vec4(scaledPosition * vec2(2.0) - vec2(1.0), 0.0, 1.0);\n" - << "}\n"; - return vertex_shader_stream.str(); -} - -static std::string GenerateFragmentShader(int layer_count) { - std::ostringstream fragment_shader_stream; - fragment_shader_stream << "#version 300 es\n" - << "#define LAYER_COUNT " << layer_count << "\n" - << "#extension GL_OES_EGL_image_external : require\n" - << "precision mediump float;\n"; - for (int i = 0; i < layer_count; ++i) { - fragment_shader_stream << "uniform samplerExternalOES uLayerTexture" << i - << ";\n"; - } - fragment_shader_stream << "uniform float uLayerAlpha[LAYER_COUNT];\n" - << "uniform float uLayerPremult[LAYER_COUNT];\n" - << "in vec2 fTexCoords[LAYER_COUNT];\n" - << "out vec4 oFragColor;\n" - << "void main() {\n" - << " vec3 color = vec3(0.0, 0.0, 0.0);\n" - << " float alphaCover = 1.0;\n" - << " vec4 texSample;\n" - << " vec3 multRgb;\n"; - for (int i = 0; i < layer_count; ++i) { - if (i > 0) - fragment_shader_stream << " if (alphaCover > 0.5/255.0) {\n"; - // clang-format off - fragment_shader_stream - << " texSample = texture2D(uLayerTexture" << i << ",\n" - << " fTexCoords[" << i << "]);\n" - << " multRgb = texSample.rgb *\n" - << " max(texSample.a, uLayerPremult[" << i << "]);\n" - << " color += multRgb * uLayerAlpha[" << i << "] * alphaCover;\n" - << " alphaCover *= 1.0 - texSample.a * uLayerAlpha[" << i << "];\n"; - // clang-format on - } - for (int i = 0; i < layer_count - 1; ++i) - fragment_shader_stream << " }\n"; - fragment_shader_stream << " oFragColor = vec4(color, 1.0 - alphaCover);\n" - << "}\n"; - return fragment_shader_stream.str(); -} - -static AutoGLProgram GenerateProgram(unsigned num_textures, - std::ostringstream *shader_log) { - std::string vertex_shader_string = GenerateVertexShader(num_textures); - const GLchar *vertex_shader_source = vertex_shader_string.c_str(); - AutoGLShader vertex_shader = CompileAndCheckShader( - GL_VERTEX_SHADER, 1, &vertex_shader_source, shader_log); - if (!vertex_shader.get()) - return 0; - - std::string fragment_shader_string = GenerateFragmentShader(num_textures); - const GLchar *fragment_shader_source = fragment_shader_string.c_str(); - AutoGLShader fragment_shader = CompileAndCheckShader( - GL_FRAGMENT_SHADER, 1, &fragment_shader_source, shader_log); - if (!fragment_shader.get()) - return 0; - - AutoGLProgram program(glCreateProgram()); - if (!program.get()) { - if (shader_log) - *shader_log << "Failed to create program: " << GetGLError() << "\n"; - return 0; - } - - glAttachShader(program.get(), vertex_shader.get()); - glAttachShader(program.get(), fragment_shader.get()); - glBindAttribLocation(program.get(), 0, "vPosition"); - glBindAttribLocation(program.get(), 1, "vTexCoords"); - glLinkProgram(program.get()); - glDetachShader(program.get(), vertex_shader.get()); - glDetachShader(program.get(), fragment_shader.get()); - - GLint status; - glGetProgramiv(program.get(), GL_LINK_STATUS, &status); - if (!status) { - if (shader_log) { - GLint log_length; - glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &log_length); - std::string program_log(log_length, ' '); - glGetProgramInfoLog(program.get(), log_length, NULL, - &program_log.front()); - *shader_log << "Failed to link program:\n" << program_log.c_str() << "\n"; - } - return 0; - } - - return program; -} - -struct RenderingCommand { - struct TextureSource { - unsigned texture_index; - float crop_bounds[4]; - float alpha; - float premult; - float texture_matrix[4]; - }; - - float bounds[4]; - unsigned texture_count = 0; - TextureSource textures[MAX_OVERLAPPING_LAYERS]; -}; - -static void ConstructCommand(const DrmHwcLayer *layers, - const DrmCompositionRegion ®ion, - RenderingCommand &cmd) { - std::copy_n(region.frame.bounds, 4, cmd.bounds); - - for (size_t texture_index : region.source_layers) { - const DrmHwcLayer &layer = layers[texture_index]; - - DrmHwcRect<float> display_rect(layer.display_frame); - float display_size[2] = {display_rect.bounds[2] - display_rect.bounds[0], - display_rect.bounds[3] - display_rect.bounds[1]}; - - float tex_width = layer.buffer->width; - float tex_height = layer.buffer->height; - DrmHwcRect<float> crop_rect(layer.source_crop.left / tex_width, - layer.source_crop.top / tex_height, - layer.source_crop.right / tex_width, - layer.source_crop.bottom / tex_height); - - float crop_size[2] = {crop_rect.bounds[2] - crop_rect.bounds[0], - crop_rect.bounds[3] - crop_rect.bounds[1]}; - - RenderingCommand::TextureSource &src = cmd.textures[cmd.texture_count]; - cmd.texture_count++; - src.texture_index = texture_index; - - bool swap_xy = false; - bool flip_xy[2] = { false, false }; - - if (layer.transform == DrmHwcTransform::kRotate180) { - swap_xy = false; - flip_xy[0] = true; - flip_xy[1] = true; - } else if (layer.transform == DrmHwcTransform::kRotate270) { - swap_xy = true; - flip_xy[0] = true; - flip_xy[1] = false; - } else if (layer.transform & DrmHwcTransform::kRotate90) { - swap_xy = true; - if (layer.transform & DrmHwcTransform::kFlipH) { - flip_xy[0] = true; - flip_xy[1] = true; - } else if (layer.transform & DrmHwcTransform::kFlipV) { - flip_xy[0] = false; - flip_xy[1] = false; - } else { - flip_xy[0] = false; - flip_xy[1] = true; - } - } else { - if (layer.transform & DrmHwcTransform::kFlipH) - flip_xy[0] = true; - if (layer.transform & DrmHwcTransform::kFlipV) - flip_xy[1] = true; - } - - if (swap_xy) - std::copy_n(&kTextureTransformMatrices[4], 4, src.texture_matrix); - else - std::copy_n(&kTextureTransformMatrices[0], 4, src.texture_matrix); - - for (int j = 0; j < 4; j++) { - int b = j ^ (swap_xy ? 1 : 0); - float bound_percent = - (cmd.bounds[b] - display_rect.bounds[b % 2]) / display_size[b % 2]; - if (flip_xy[j % 2]) { - src.crop_bounds[j] = - crop_rect.bounds[j % 2 + 2] - bound_percent * crop_size[j % 2]; - } else { - src.crop_bounds[j] = - crop_rect.bounds[j % 2] + bound_percent * crop_size[j % 2]; - } - } - - if (layer.blending == DrmHwcBlending::kNone) { - src.alpha = src.premult = 1.0f; - // This layer is opaque. There is no point in using layers below this one. - break; - } - - src.alpha = layer.alpha / 255.0f; - src.premult = (layer.blending == DrmHwcBlending::kPreMult) ? 1.0f : 0.0f; - } -} - -static int EGLFenceWait(EGLDisplay egl_display, int acquireFenceFd) { - int ret = 0; - - EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, acquireFenceFd, - EGL_NONE}; - EGLSyncKHR egl_sync = - eglCreateSyncKHR(egl_display, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); - if (egl_sync == EGL_NO_SYNC_KHR) { - ALOGE("Failed to make EGLSyncKHR from acquireFenceFd: %s", GetEGLError()); - close(acquireFenceFd); - return 1; - } - - EGLint success = eglWaitSyncKHR(egl_display, egl_sync, 0); - if (success == EGL_FALSE) { - ALOGE("Failed to wait for acquire: %s", GetEGLError()); - ret = 1; - } - eglDestroySyncKHR(egl_display, egl_sync); - - return ret; -} - -static int CreateTextureFromHandle(EGLDisplay egl_display, - buffer_handle_t handle, - Importer *importer, - AutoEGLImageAndGLTexture *out) { - EGLImageKHR image = importer->ImportImage(egl_display, handle); - - if (image == EGL_NO_IMAGE_KHR) { - ALOGE("Failed to make image %s %p", GetEGLError(), handle); - return -EINVAL; - } - - GLuint texture; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_REPEAT); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); - - out->image.reset(egl_display, image); - out->texture.reset(texture); - - return 0; -} - -GLWorkerCompositor::GLWorkerCompositor() - : egl_display_(EGL_NO_DISPLAY), egl_ctx_(EGL_NO_CONTEXT) { -} - -int GLWorkerCompositor::Init() { - int ret = 0; - const char *egl_extensions; - const char *gl_extensions; - EGLint num_configs; - EGLConfig egl_config; - - // clang-format off - const GLfloat verts[] = { - 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 2.0f, 0.0f, 2.0f, - 2.0f, 0.0f, 2.0f, 0.0f - }; - // clang-format on - - const EGLint config_attribs[] = {EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, - 8, - EGL_GREEN_SIZE, - 8, - EGL_BLUE_SIZE, - 8, - EGL_NONE}; - - const EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; - - egl_display_ = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (egl_display_ == EGL_NO_DISPLAY) { - ALOGE("Failed to get egl display"); - return 1; - } - - if (!eglInitialize(egl_display_, NULL, NULL)) { - ALOGE("Failed to initialize egl: %s", GetEGLError()); - return 1; - } - - egl_extensions = eglQueryString(egl_display_, EGL_EXTENSIONS); - - // These extensions are all technically required but not always reported due - // to meta EGL filtering them out. - if (!HasExtension("EGL_KHR_image_base", egl_extensions)) - ALOGW("EGL_KHR_image_base extension not supported"); - - if (!HasExtension("EGL_ANDROID_image_native_buffer", egl_extensions)) - ALOGW("EGL_ANDROID_image_native_buffer extension not supported"); - - if (!HasExtension("EGL_ANDROID_native_fence_sync", egl_extensions)) - ALOGW("EGL_ANDROID_native_fence_sync extension not supported"); - - if (!eglChooseConfig(egl_display_, config_attribs, &egl_config, 1, - &num_configs)) { - ALOGE("eglChooseConfig() failed with error: %s", GetEGLError()); - return 1; - } - - egl_ctx_ = - eglCreateContext(egl_display_, egl_config, - EGL_NO_CONTEXT /* No shared context */, context_attribs); - - if (egl_ctx_ == EGL_NO_CONTEXT) { - ALOGE("Failed to create OpenGL ES Context: %s", GetEGLError()); - return 1; - } - - ret = BeginContext(); - if (ret) - return ret; - - gl_extensions = (const char *)glGetString(GL_EXTENSIONS); - - if (!HasExtension("GL_OES_EGL_image", gl_extensions)) - ALOGW("GL_OES_EGL_image extension not supported"); - - if (!HasExtension("GL_OES_EGL_image_external", gl_extensions)) - ALOGW("GL_OES_EGL_image_external extension not supported"); - - GLuint vertex_buffer; - glGenBuffers(1, &vertex_buffer); - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - vertex_buffer_.reset(vertex_buffer); - - 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; - } - - return 0; -} - -GLWorkerCompositor::~GLWorkerCompositor() { - if (egl_display_ != EGL_NO_DISPLAY && egl_ctx_ != EGL_NO_CONTEXT) - if (eglDestroyContext(egl_display_, egl_ctx_) == EGL_FALSE) - ALOGE("Failed to destroy OpenGL ES Context: %s", GetEGLError()); -} - -int GLWorkerCompositor::Composite(DrmHwcLayer *layers, - DrmCompositionRegion *regions, - size_t num_regions, - const sp<GraphicBuffer> &framebuffer, - Importer *importer) { - ATRACE_CALL(); - int ret = 0; - std::vector<AutoEGLImageAndGLTexture> layer_textures; - std::vector<RenderingCommand> commands; - - if (num_regions == 0) { - 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; - } - - std::unordered_set<size_t> layers_used_indices; - for (size_t region_index = 0; region_index < num_regions; region_index++) { - DrmCompositionRegion ®ion = regions[region_index]; - layers_used_indices.insert(region.source_layers.begin(), - region.source_layers.end()); - commands.emplace_back(); - ConstructCommand(layers, region, commands.back()); - } - - for (size_t layer_index = 0; layer_index < MAX_OVERLAPPING_LAYERS; - layer_index++) { - DrmHwcLayer *layer = &layers[layer_index]; - - layer_textures.emplace_back(); - - if (layers_used_indices.count(layer_index) == 0) - continue; - - ret = CreateTextureFromHandle(egl_display_, layer->get_usable_handle(), - importer, &layer_textures.back()); - - if (!ret) { - ret = EGLFenceWait(egl_display_, layer->acquire_fence.Release()); - } - if (ret) { - layer_textures.pop_back(); - ret = -EINVAL; - } - } - - if (ret) { - EndContext(); - return ret; - } - - glViewport(0, 0, frame_width, frame_height); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); - - glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_.get()); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, NULL); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, - (void *)(sizeof(float) * 2)); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnable(GL_SCISSOR_TEST); - - for (const RenderingCommand &cmd : commands) { - if (cmd.texture_count == 0) - continue; - - // TODO(zachr): handle the case of too many overlapping textures for one - // area by falling back to rendering as many layers as possible using - // multiple blending passes. - GLint program = PrepareAndCacheProgram(cmd.texture_count); - if (program == 0) { - ALOGE("Too many layers to render in one area"); - continue; - } - - glUseProgram(program); - GLint gl_viewport_loc = glGetUniformLocation(program, "uViewport"); - GLint gl_crop_loc = glGetUniformLocation(program, "uLayerCrop"); - GLint gl_alpha_loc = glGetUniformLocation(program, "uLayerAlpha"); - GLint gl_premult_loc = glGetUniformLocation(program, "uLayerPremult"); - GLint gl_tex_matrix_loc = glGetUniformLocation(program, "uTexMatrix"); - glUniform4f(gl_viewport_loc, cmd.bounds[0] / (float)frame_width, - cmd.bounds[1] / (float)frame_height, - (cmd.bounds[2] - cmd.bounds[0]) / (float)frame_width, - (cmd.bounds[3] - cmd.bounds[1]) / (float)frame_height); - - for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) { - std::ostringstream texture_name_formatter; - texture_name_formatter << "uLayerTexture" << src_index; - GLint gl_tex_loc = - glGetUniformLocation(program, texture_name_formatter.str().c_str()); - - const RenderingCommand::TextureSource &src = cmd.textures[src_index]; - glUniform1f(gl_alpha_loc + src_index, src.alpha); - glUniform1f(gl_premult_loc + src_index, src.premult); - glUniform4f(gl_crop_loc + src_index, src.crop_bounds[0], - src.crop_bounds[1], src.crop_bounds[2] - src.crop_bounds[0], - src.crop_bounds[3] - src.crop_bounds[1]); - glUniform1i(gl_tex_loc, src_index); - glUniformMatrix2fv(gl_tex_matrix_loc + src_index, 1, GL_FALSE, - src.texture_matrix); - glActiveTexture(GL_TEXTURE0 + src_index); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, - layer_textures[src.texture_index].texture.get()); - } - - glScissor(cmd.bounds[0], cmd.bounds[1], cmd.bounds[2] - cmd.bounds[0], - cmd.bounds[3] - cmd.bounds[1]); - glDrawArrays(GL_TRIANGLES, 0, 3); - - for (unsigned src_index = 0; src_index < cmd.texture_count; src_index++) { - glActiveTexture(GL_TEXTURE0 + src_index); - glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); - } - } - - glDisable(GL_SCISSOR_TEST); - glActiveTexture(GL_TEXTURE0); - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glUseProgram(0); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - EndContext(); - return ret; -} - -void GLWorkerCompositor::Finish() { - ATRACE_CALL(); - glFinish(); - - char use_framebuffer_cache_opt[PROPERTY_VALUE_MAX]; - property_get("hwc.drm.use_framebuffer_cache", use_framebuffer_cache_opt, "1"); - bool use_framebuffer_cache = atoi(use_framebuffer_cache_opt); - - if (use_framebuffer_cache) { - for (auto &fb : cached_framebuffers_) - fb.strong_framebuffer.clear(); - } else { - cached_framebuffers_.clear(); - } -} - -GLWorkerCompositor::CachedFramebuffer::CachedFramebuffer( - const sp<GraphicBuffer> &gb, AutoEGLDisplayImage &&image, - AutoGLTexture &&tex, AutoGLFramebuffer &&fb) - : strong_framebuffer(gb), - weak_framebuffer(gb), - egl_fb_image(std::move(image)), - gl_fb_tex(std::move(tex)), - gl_fb(std::move(fb)) { -} - -bool GLWorkerCompositor::CachedFramebuffer::Promote() { - if (strong_framebuffer.get() != NULL) - return true; - strong_framebuffer = weak_framebuffer.promote(); - return strong_framebuffer.get() != NULL; -} - -GLWorkerCompositor::CachedFramebuffer * -GLWorkerCompositor::FindCachedFramebuffer( - const sp<GraphicBuffer> &framebuffer) { - for (auto &fb : cached_framebuffers_) - if (fb.weak_framebuffer == framebuffer) - return &fb; - return NULL; -} - -GLWorkerCompositor::CachedFramebuffer * -GLWorkerCompositor::PrepareAndCacheFramebuffer( - const sp<GraphicBuffer> &framebuffer) { - CachedFramebuffer *cached_framebuffer = FindCachedFramebuffer(framebuffer); - if (cached_framebuffer != NULL) { - if (cached_framebuffer->Promote()) { - glBindFramebuffer(GL_FRAMEBUFFER, cached_framebuffer->gl_fb.get()); - return cached_framebuffer; - } - - for (auto it = cached_framebuffers_.begin(); - it != cached_framebuffers_.end(); ++it) { - if (it->weak_framebuffer == framebuffer) { - cached_framebuffers_.erase(it); - break; - } - } - } - - AutoEGLDisplayImage egl_fb_image( - egl_display_, - eglCreateImageKHR(egl_display_, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - (EGLClientBuffer)framebuffer->getNativeBuffer(), - NULL /* no attribs */)); - - if (egl_fb_image.image() == EGL_NO_IMAGE_KHR) { - ALOGE("Failed to make image from target buffer: %s", GetEGLError()); - return NULL; - } - - GLuint gl_fb_tex; - glGenTextures(1, &gl_fb_tex); - AutoGLTexture gl_fb_tex_auto(gl_fb_tex); - glBindTexture(GL_TEXTURE_2D, gl_fb_tex); - glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, - (GLeglImageOES)egl_fb_image.image()); - glBindTexture(GL_TEXTURE_2D, 0); - - GLuint gl_fb; - glGenFramebuffers(1, &gl_fb); - AutoGLFramebuffer gl_fb_auto(gl_fb); - glBindFramebuffer(GL_FRAMEBUFFER, gl_fb); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - gl_fb_tex, 0); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - ALOGE("Failed framebuffer check for created target buffer: %s", - GetGLFramebufferError()); - return NULL; - } - - cached_framebuffers_.emplace_back(framebuffer, std::move(egl_fb_image), - std::move(gl_fb_tex_auto), - std::move(gl_fb_auto)); - return &cached_framebuffers_.back(); -} - -GLint GLWorkerCompositor::PrepareAndCacheProgram(unsigned texture_count) { - if (blend_programs_.size() >= texture_count) { - GLint program = blend_programs_[texture_count - 1].get(); - if (program != 0) - return program; - } - - AutoGLProgram program = GenerateProgram(texture_count, NULL); - if (program.get() != 0) { - if (blend_programs_.size() < texture_count) - blend_programs_.resize(texture_count); - blend_programs_[texture_count - 1] = std::move(program); - return blend_programs_[texture_count - 1].get(); - } - - return 0; -} - -} // namespace android diff --git a/glworker.h b/glworker.h deleted file mode 100644 index 26de55d..0000000 --- a/glworker.h +++ /dev/null @@ -1,94 +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_GL_WORKER_H_ -#define ANDROID_GL_WORKER_H_ - -#include <vector> - -#define EGL_EGLEXT_PROTOTYPES -#define GL_GLEXT_PROTOTYPES - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> - -#include <ui/GraphicBuffer.h> - -#include "autogl.h" - -namespace android { - -struct DrmHwcLayer; -struct DrmCompositionRegion; - -class GLWorkerCompositor { - public: - GLWorkerCompositor(); - ~GLWorkerCompositor(); - - int Init(); - int Composite(DrmHwcLayer *layers, DrmCompositionRegion *regions, - size_t num_regions, const sp<GraphicBuffer> &framebuffer, - Importer *importer); - void Finish(); - - private: - struct CachedFramebuffer { - // If the strong_framebuffer is non-NULL, we are holding a strong reference - // until we are sure rendering is done. The weak reference will be equal in - // that case. - sp<GraphicBuffer> strong_framebuffer; - wp<GraphicBuffer> weak_framebuffer; - AutoEGLDisplayImage egl_fb_image; - AutoGLTexture gl_fb_tex; - AutoGLFramebuffer gl_fb; - - CachedFramebuffer(const sp<GraphicBuffer> &gb, AutoEGLDisplayImage &&image, - AutoGLTexture &&tex, AutoGLFramebuffer &&fb); - - 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( - const sp<GraphicBuffer> &framebuffer); - - GLint PrepareAndCacheProgram(unsigned texture_count); - - EGLDisplay egl_display_; - EGLContext egl_ctx_; - - std::vector<AutoGLProgram> blend_programs_; - AutoGLBuffer vertex_buffer_; - - std::vector<CachedFramebuffer> cached_framebuffers_; -}; -} - -#endif diff --git a/hwcomposer.cpp b/hwcomposer.cpp deleted file mode 100644 index c0aafef..0000000 --- a/hwcomposer.cpp +++ /dev/null @@ -1,841 +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]; - hd->vsync_worker.VSyncControl(enabled); - return 0; -} - -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}, - } -}; diff --git a/hwcutils.cpp b/hwcutils.cpp index 53a7d82..e452bc8 100644 --- a/hwcutils.cpp +++ b/hwcutils.cpp @@ -20,7 +20,8 @@ #include "drmhwcomposer.h" #include "platform.h" -#include <cutils/log.h> +#include <log/log.h> +#include <ui/GraphicBufferMapper.h> namespace android { @@ -58,51 +59,18 @@ int DrmHwcBuffer::ImportBuffer(buffer_handle_t handle, Importer *importer) { return 0; } -static native_handle_t *dup_buffer_handle(buffer_handle_t handle) { - native_handle_t *new_handle = - native_handle_create(handle->numFds, handle->numInts); - if (new_handle == NULL) - return NULL; - - const int *old_data = handle->data; - int *new_data = new_handle->data; - for (int i = 0; i < handle->numFds; i++) { - *new_data = dup(*old_data); - old_data++; - new_data++; - } - memcpy(new_data, old_data, sizeof(int) * handle->numInts); - - return new_handle; -} - -static void free_buffer_handle(native_handle_t *handle) { - int ret = native_handle_close(handle); - if (ret) - ALOGE("Failed to close native handle %d", ret); - ret = native_handle_delete(handle); - if (ret) - ALOGE("Failed to delete native handle %d", ret); -} - -int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle, - const gralloc_module_t *gralloc) { - native_handle_t *handle_copy = dup_buffer_handle(handle); - if (handle_copy == NULL) { - ALOGE("Failed to duplicate handle"); - return -ENOMEM; - } - - int ret = gralloc->registerBuffer(gralloc, handle_copy); +int DrmHwcNativeHandle::CopyBufferHandle(buffer_handle_t handle) { + native_handle_t *handle_copy; + GraphicBufferMapper &gm(GraphicBufferMapper::get()); + int ret = + gm.importBuffer(handle, const_cast<buffer_handle_t *>(&handle_copy)); if (ret) { - ALOGE("Failed to register buffer handle %d", ret); - free_buffer_handle(handle_copy); + ALOGE("Failed to import buffer handle %d", ret); return ret; } Clear(); - gralloc_ = gralloc; handle_ = handle_copy; return 0; @@ -113,49 +81,22 @@ DrmHwcNativeHandle::~DrmHwcNativeHandle() { } void DrmHwcNativeHandle::Clear() { - if (gralloc_ != NULL && handle_ != NULL) { - gralloc_->unregisterBuffer(gralloc_, handle_); - free_buffer_handle(handle_); - gralloc_ = NULL; + if (handle_ != NULL) { + GraphicBufferMapper &gm(GraphicBufferMapper::get()); + int ret = gm.freeBuffer(handle_); + if (ret) { + ALOGE("Failed to free buffer handle %d", ret); + } handle_ = NULL; } } -int DrmHwcLayer::InitFromHwcLayer(hwc_layer_1_t *sf_layer, Importer *importer, - const gralloc_module_t *gralloc) { - alpha = sf_layer->planeAlpha; - - SetSourceCrop(sf_layer->sourceCropf); - SetDisplayFrame(sf_layer->displayFrame); - SetTransform(sf_layer->transform); - - switch (sf_layer->blending) { - case HWC_BLENDING_NONE: - blending = DrmHwcBlending::kNone; - break; - case HWC_BLENDING_PREMULT: - blending = DrmHwcBlending::kPreMult; - break; - case HWC_BLENDING_COVERAGE: - blending = DrmHwcBlending::kCoverage; - break; - default: - ALOGE("Invalid blending in hwc_layer_1_t %d", sf_layer->blending); - return -EINVAL; - } - - sf_handle = sf_layer->handle; - - return ImportBuffer(importer, gralloc); -} - -int DrmHwcLayer::ImportBuffer(Importer *importer, - const gralloc_module_t *gralloc) { +int DrmHwcLayer::ImportBuffer(Importer *importer) { int ret = buffer.ImportBuffer(sf_handle, importer); if (ret) return ret; - ret = handle.CopyBufferHandle(sf_handle, gralloc); + ret = handle.CopyBufferHandle(sf_handle); if (ret) return ret; @@ -165,12 +106,11 @@ int DrmHwcLayer::ImportBuffer(Importer *importer, } void DrmHwcLayer::SetSourceCrop(hwc_frect_t const &crop) { - source_crop = DrmHwcRect<float>(crop.left, crop.top, crop.right, crop.bottom); + source_crop = crop; } void DrmHwcLayer::SetDisplayFrame(hwc_rect_t const &frame) { - display_frame = - DrmHwcRect<int>(frame.left, frame.top, frame.right, frame.bottom); + display_frame = frame; } void DrmHwcLayer::SetTransform(int32_t sf_transform) { diff --git a/platform.cpp b/platform.cpp index 56ab37e..b6c39d0 100644 --- a/platform.cpp +++ b/platform.cpp @@ -19,7 +19,7 @@ #include "drmresources.h" #include "platform.h" -#include <cutils/log.h> +#include <log/log.h> namespace android { @@ -37,7 +37,7 @@ std::vector<DrmPlane *> Planner::GetUsablePlanes( } std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes( - std::map<size_t, DrmHwcLayer *> &layers, bool use_squash_fb, DrmCrtc *crtc, + std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes) { std::vector<DrmCompositionPlane> composition; @@ -48,30 +48,6 @@ std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes( 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); @@ -81,10 +57,6 @@ std::tuple<int, std::vector<DrmCompositionPlane>> Planner::ProvisionPlanes( } } - if (squash_plane) - composition.emplace_back(DrmCompositionPlane::Type::kSquash, squash_plane, - crtc); - return std::make_tuple(0, std::move(composition)); } @@ -109,62 +81,6 @@ int PlanStageProtected::ProvisionPlanes( 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 PlanStagePrecomp::ProvisionPlanes( - std::vector<DrmCompositionPlane> *composition, - std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc * /*crtc*/, - std::vector<DrmPlane *> * /*planes*/) { - DrmCompositionPlane *precomp = GetPrecomp(composition); - if (!precomp || precomp->source_layers().empty()) - return 0; - - // Find lowest zorder out of precomp layers - size_t precomp_zorder = *std::min_element( - precomp->source_layers().begin(), precomp->source_layers().end(), - [](size_t a, size_t b) { return a < b; }); - - // if there are any remaining layers on top of any of the precomp layers, - // add them to precomp to avoid blending issues since precomp is always at - // highest zorder - for (auto i = layers.begin(); i != layers.end();) { - if (i->first < precomp_zorder) { - i++; - continue; - } - precomp->source_layers().emplace_back(i->first); - i = layers.erase(i); - } - return 0; } @@ -183,13 +99,6 @@ int PlanStageGreedy::ProvisionPlanes( 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; } } @@ -38,10 +38,6 @@ class Importer { // Creates a platform-specific importer instance static Importer *CreateInstance(DrmResources *drm); - // Imports EGLImage for glcompositor, since NV handles this in non-standard - // way, and fishing out the details is specific to the gralloc used. - virtual EGLImageKHR ImportImage(EGLDisplay egl_display, buffer_handle_t handle) = 0; - // Imports the buffer referred to by handle into bo. // // Note: This can be called from a different thread than ReleaseBuffer. The @@ -77,17 +73,7 @@ class Planner { 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 + // 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, @@ -96,41 +82,26 @@ class Planner { if (!plane) return -ENOENT; - auto precomp = GetPrecompIter(composition); - composition->emplace(precomp, type, plane, crtc, source_layer); + composition->emplace_back(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. + // entire stack can't fit in hardware, FIXME // // @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::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, + std::vector<DrmPlane *> *primary_planes, std::vector<DrmPlane *> *overlay_planes); template <typename T, typename... A> @@ -156,18 +127,6 @@ class PlanStageProtected : public Planner::PlanStage { std::vector<DrmPlane *> *planes); }; -// This plan stage provisions the precomp plane with any remaining layers that -// are on top of the current precomp layers. This stage should be included in -// all platforms before loosely allocating layers (i.e. PlanStageGreedy) if -// any previous plan could have modified the precomp plane layers -// (ex. PlanStageProtected). -class PlanStagePrecomp : 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). diff --git a/platformdrmgeneric.cpp b/platformdrmgeneric.cpp index 2a6773c..7c4758d 100644 --- a/platformdrmgeneric.cpp +++ b/platformdrmgeneric.cpp @@ -24,10 +24,9 @@ #include <xf86drm.h> #include <xf86drmMode.h> -#include <cutils/log.h> +#include <log/log.h> #include <gralloc_handle.h> #include <hardware/gralloc.h> -#include <EGL/eglext.h> namespace android { @@ -84,22 +83,6 @@ uint32_t DrmGenericImporter::ConvertHalFormatToDrm(uint32_t hal_format) { } } -EGLImageKHR DrmGenericImporter::ImportImage(EGLDisplay egl_display, buffer_handle_t handle) { - gralloc_handle_t *gr_handle = gralloc_handle(handle); - if (!gr_handle) - return NULL; - EGLint attr[] = { - EGL_WIDTH, (EGLint)gr_handle->width, - EGL_HEIGHT, (EGLint)gr_handle->height, - EGL_LINUX_DRM_FOURCC_EXT, (EGLint)ConvertHalFormatToDrm(gr_handle->format), - EGL_DMA_BUF_PLANE0_FD_EXT, gr_handle->prime_fd, - EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, - EGL_DMA_BUF_PLANE0_PITCH_EXT, (EGLint)gr_handle->stride, - EGL_NONE, - }; - return eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr); -} - int DrmGenericImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { gralloc_handle_t *gr_handle = gralloc_handle(handle); if (!gr_handle) @@ -145,10 +128,14 @@ int DrmGenericImporter::ReleaseBuffer(hwc_drm_bo_t *bo) { gem_close.handle = bo->gem_handles[i]; int ret = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close); - if (ret) + if (ret) { ALOGE("Failed to close gem handle %d %d", i, ret); - else + } else { + for (int j = i + 1; j < num_gem_handles; j++) + if (bo->gem_handles[j] == bo->gem_handles[i]) + bo->gem_handles[j] = 0; bo->gem_handles[i] = 0; + } } return 0; } diff --git a/platformdrmgeneric.h b/platformdrmgeneric.h index fbe059b..0339e1e 100644 --- a/platformdrmgeneric.h +++ b/platformdrmgeneric.h @@ -31,7 +31,6 @@ class DrmGenericImporter : public Importer { int Init(); - EGLImageKHR ImportImage(EGLDisplay egl_display, buffer_handle_t handle) override; int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; int ReleaseBuffer(hwc_drm_bo_t *bo) override; diff --git a/platformhisi.cpp b/platformhisi.cpp index 16c5e6f..d4428d0 100644 --- a/platformhisi.cpp +++ b/platformhisi.cpp @@ -27,10 +27,11 @@ #include <xf86drm.h> #include <xf86drmMode.h> -#include <cutils/log.h> +#include <log/log.h> #include <hardware/gralloc.h> #include "gralloc_priv.h" +#define MALI_ALIGN(value, base) (((value) + ((base)-1)) & ~((base)-1)) namespace android { @@ -69,29 +70,9 @@ int HisiImporter::Init() { return 0; } -EGLImageKHR HisiImporter::ImportImage(EGLDisplay egl_display, buffer_handle_t handle) { - private_handle_t const *hnd = reinterpret_cast < private_handle_t const *>(handle); - if (!hnd) - return NULL; - - EGLint fmt = ConvertHalFormatToDrm(hnd->req_format); - if (fmt < 0) - return NULL; - - EGLint attr[] = { - EGL_WIDTH, hnd->width, - EGL_HEIGHT, hnd->height, - EGL_LINUX_DRM_FOURCC_EXT, fmt, - EGL_DMA_BUF_PLANE0_FD_EXT, hnd->share_fd, - EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0, - EGL_DMA_BUF_PLANE0_PITCH_EXT, hnd->byte_stride, - EGL_NONE, - }; - return eglCreateImageKHR(egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attr); -} - int HisiImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { - private_handle_t const *hnd = reinterpret_cast < private_handle_t const *>(handle); + private_handle_t const *hnd = + reinterpret_cast<private_handle_t const *>(handle); if (!hnd) return -EINVAL; @@ -102,19 +83,45 @@ int HisiImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { return ret; } - EGLint fmt = ConvertHalFormatToDrm(hnd->req_format); + int32_t fmt = ConvertHalFormatToDrm(hnd->req_format); if (fmt < 0) - return fmt; + return fmt; memset(bo, 0, sizeof(hwc_drm_bo_t)); bo->width = hnd->width; bo->height = hnd->height; bo->format = fmt; bo->usage = hnd->usage; + bo->pitches[0] = hnd->byte_stride; bo->gem_handles[0] = gem_handle; bo->offsets[0] = 0; + switch (fmt) { + case DRM_FORMAT_YVU420: { + int align = 128; + if (hnd->usage & + (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) + align = 16; + int adjusted_height = MALI_ALIGN(hnd->height, 2); + int y_size = adjusted_height * hnd->byte_stride; + int vu_stride = MALI_ALIGN(hnd->byte_stride / 2, align); + int v_size = vu_stride * (adjusted_height / 2); + + /* V plane*/ + bo->gem_handles[1] = gem_handle; + bo->pitches[1] = vu_stride; + bo->offsets[1] = y_size; + /* U plane */ + bo->gem_handles[2] = gem_handle; + bo->pitches[2] = vu_stride; + bo->offsets[2] = y_size + v_size; + break; + } + default: + break; + } + ret = drmModeAddFB2(drm_->fd(), bo->width, bo->height, bo->format, bo->gem_handles, bo->pitches, bo->offsets, &bo->fb_id, 0); if (ret) { @@ -131,5 +138,3 @@ std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) { return planner; } } - - diff --git a/platformhisi.h b/platformhisi.h index 46f4595..a098692 100644 --- a/platformhisi.h +++ b/platformhisi.h @@ -34,7 +34,6 @@ class HisiImporter : public DrmGenericImporter { int Init(); - EGLImageKHR ImportImage(EGLDisplay egl_display, buffer_handle_t handle) override; int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; private: diff --git a/platformminigbm.cpp b/platformminigbm.cpp new file mode 100644 index 0000000..8e3cc65 --- /dev/null +++ b/platformminigbm.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 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-drm-minigbm" + +#include "drmresources.h" +#include "platform.h" +#include "platformminigbm.h" + +#include <drm/drm_fourcc.h> +#include <xf86drm.h> +#include <xf86drmMode.h> + +#include <log/log.h> +#include <hardware/gralloc.h> + +#include "cros_gralloc_handle.h" + +namespace android { + +Importer *Importer::CreateInstance(DrmResources *drm) { + DrmMinigbmImporter *importer = new DrmMinigbmImporter(drm); + if (!importer) + return NULL; + + int ret = importer->Init(); + if (ret) { + ALOGE("Failed to initialize the minigbm importer %d", ret); + delete importer; + return NULL; + } + return importer; +} + +DrmMinigbmImporter::DrmMinigbmImporter(DrmResources *drm) : DrmGenericImporter(drm), drm_(drm) { +} + +DrmMinigbmImporter::~DrmMinigbmImporter() { +} + +int DrmMinigbmImporter::Init() { + int ret = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, + (const hw_module_t **)&gralloc_); + if (ret) { + ALOGE("Failed to open gralloc module %d", ret); + return ret; + } + + if (strcasecmp(gralloc_->common.author, "Chrome OS")) + ALOGW("Using non-minigbm gralloc module: %s/%s\n", gralloc_->common.name, + gralloc_->common.author); + + return 0; +} + +int DrmMinigbmImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) { + cros_gralloc_handle *gr_handle = (cros_gralloc_handle *)handle; + if (!gr_handle) + return -EINVAL; + + uint32_t gem_handle; + int ret = drmPrimeFDToHandle(drm_->fd(), gr_handle->fds[0], &gem_handle); + if (ret) { + ALOGE("failed to import prime fd %d ret=%d", gr_handle->fds[0], ret); + return ret; + } + + memset(bo, 0, sizeof(hwc_drm_bo_t)); + bo->width = gr_handle->width; + bo->height = gr_handle->height; + bo->format = gr_handle->format; + bo->usage = gr_handle->usage; + bo->pitches[0] = gr_handle->strides[0]; + bo->offsets[0] = gr_handle->offsets[0]; + bo->gem_handles[0] = gem_handle; + + ret = drmModeAddFB2(drm_->fd(), bo->width, bo->height, bo->format, + bo->gem_handles, bo->pitches, bo->offsets, &bo->fb_id, 0); + if (ret) { + ALOGE("could not create drm fb %d", ret); + return ret; + } + + return ret; +} + +std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) { + std::unique_ptr<Planner> planner(new Planner); + planner->AddStage<PlanStageGreedy>(); + return planner; +} + +} diff --git a/platformminigbm.h b/platformminigbm.h new file mode 100644 index 0000000..f25bf7b --- /dev/null +++ b/platformminigbm.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 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_PLATFORM_DRM_MINIGBM_H_ +#define ANDROID_PLATFORM_DRM_MINIGBM_H_ + +#include "drmresources.h" +#include "platform.h" +#include "platformdrmgeneric.h" + +#include <hardware/gralloc.h> + +namespace android { + +class DrmMinigbmImporter : public DrmGenericImporter { + public: + DrmMinigbmImporter(DrmResources *drm); + ~DrmMinigbmImporter() override; + + int Init(); + + int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; + + private: + DrmResources *drm_; + + const gralloc_module_t *gralloc_; +}; + +} + +#endif diff --git a/platformnv.h b/platformnv.h deleted file mode 100644 index 7e2784f..0000000 --- a/platformnv.h +++ /dev/null @@ -1,90 +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_PLATFORM_NV_H_ -#define ANDROID_PLATFORM_NV_H_ - -#include "drmresources.h" -#include "platform.h" -#include "platformdrmgeneric.h" - -#include <stdatomic.h> - -#include <hardware/gralloc.h> - -namespace android { - -class NvImporter : public Importer { - public: - NvImporter(DrmResources *drm); - ~NvImporter() override; - - int Init(); - - EGLImageKHR ImportImage(EGLDisplay egl_display, buffer_handle_t handle) override; - int ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) override; - int ReleaseBuffer(hwc_drm_bo_t *bo) override; - - private: - typedef struct NvBuffer { - NvImporter *importer; - hwc_drm_bo_t bo; - atomic_int ref; - } NvBuffer_t; - - static void NvGrallocRelease(void *nv_buffer); - void ReleaseBufferImpl(hwc_drm_bo_t *bo); - - NvBuffer_t *GrallocGetNvBuffer(buffer_handle_t handle); - int GrallocSetNvBuffer(buffer_handle_t handle, NvBuffer_t *buf); - - DrmResources *drm_; - - 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); -}; - -// This stage looks for layers that would not be supported by Tegra driver due -// to limitations such as downscaling. If the layer is unprotected it will be -// punted for precomp to handle, other wise if protected it will be dropped as -// it cannot be supported by any means. -class PlanStageNvLimits : public Planner::PlanStage { - public: - int ProvisionPlanes(std::vector<DrmCompositionPlane> *composition, - std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc, - std::vector<DrmPlane *> *planes); - protected: - bool CheckLayer(size_t zorder, DrmHwcLayer *layer); -}; -} - -#endif diff --git a/separate_rects.cpp b/separate_rects.cpp deleted file mode 100644 index 0e74cfc..0000000 --- a/separate_rects.cpp +++ /dev/null @@ -1,317 +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. - */ - -#include "separate_rects.h" -#include <algorithm> -#include <assert.h> -#include <iostream> -#include <map> -#include <set> -#include <utility> -#include <vector> - -namespace separate_rects { - -enum EventType { START, END }; - -template <typename TId, typename TNum> -struct StartedRect { - IdSet<TId> id_set; - TNum left, top, bottom; - - // Note that this->left is not part of the key. That field is only to mark the - // left edge of the rectangle. - bool operator<(const StartedRect<TId, TNum> &rhs) const { - return (top < rhs.top || (top == rhs.top && bottom < rhs.bottom)) || - (top == rhs.top && bottom == rhs.bottom && id_set < rhs.id_set); - } -}; - -template <typename TId, typename TNum> -struct SweepEvent { - EventType type; - union { - TNum x; - TNum y; - }; - - TId rect_id; - - bool operator<(const SweepEvent<TId, TNum> &rhs) const { - return (y < rhs.y || (y == rhs.y && rect_id < rhs.rect_id)); - } -}; - -template <typename TNum> -std::ostream &operator<<(std::ostream &os, const Rect<TNum> &rect) { - return os << rect.bounds[0] << ", " << rect.bounds[1] << ", " - << rect.bounds[2] << ", " << rect.bounds[3]; -} - -template <typename TUInt> -std::ostream &operator<<(std::ostream &os, const IdSet<TUInt> &obj) { - int bits = IdSet<TUInt>::max_elements; - TUInt mask = ((TUInt)0x1) << (bits - 1); - for (int i = 0; i < bits; i++) - os << ((obj.getBits() & (mask >> i)) ? "1" : "0"); - return os; -} - -template <typename TNum, typename TId> -void separate_rects(const std::vector<Rect<TNum>> &in, - std::vector<RectSet<TId, TNum>> *out) { - // Overview: - // This algorithm is a line sweep algorithm that travels from left to right. - // The sweep stops at each vertical edge of each input rectangle in sorted - // order of x-coordinate. At each stop, the sweep line is examined in order of - // y-coordinate from top to bottom. Along the way, a running set of rectangle - // IDs is either added to or subtracted from as the top and bottom edges are - // encountered, respectively. At each change of that running set, a copy of - // that set is recorded in along with the the y-coordinate it happened at in a - // list. This list is then interpreted as a sort of vertical cross section of - // our output set of non-overlapping rectangles. Based of the algorithm found - // at: http://stackoverflow.com/a/2755498 - - if (in.size() > IdSet<TId>::max_elements) { - return; - } - - // Events are when the sweep line encounters the starting or ending edge of - // any input rectangle. - std::set<SweepEvent<TId, TNum>> sweep_h_events; // Left or right bounds - std::set<SweepEvent<TId, TNum>> sweep_v_events; // Top or bottom bounds - - // A started rect is a rectangle whose left, top, bottom edge, and set of - // rectangle IDs is known. The key of this map includes all that information - // (except the left edge is never used to determine key equivalence or - // ordering), - std::map<StartedRect<TId, TNum>, bool> started_rects; - - // This is cleared after every event. Its declaration is here to avoid - // reallocating a vector and its buffers every event. - std::vector<std::pair<TNum, IdSet<TId>>> active_regions; - - // This pass will add rectangle start and end events to be triggered as the - // algorithm sweeps from left to right. - for (TId i = 0; i < in.size(); i++) { - const Rect<TNum> &rect = in[i]; - - // Filter out empty or invalid rects. - if (rect.left >= rect.right || rect.top >= rect.bottom) - continue; - - SweepEvent<TId, TNum> evt; - evt.rect_id = i; - - evt.type = START; - evt.x = rect.left; - sweep_h_events.insert(evt); - - evt.type = END; - evt.x = rect.right; - sweep_h_events.insert(evt); - } - - for (typename std::set<SweepEvent<TId, TNum>>::iterator it = - sweep_h_events.begin(); - it != sweep_h_events.end(); ++it) { - const SweepEvent<TId, TNum> &h_evt = *it; - const Rect<TNum> &rect = in[h_evt.rect_id]; - - // During this event, we have encountered a vertical starting or ending edge - // of a rectangle so want to append or remove (respectively) that rectangles - // top and bottom from the vertical sweep line. - SweepEvent<TId, TNum> v_evt; - v_evt.rect_id = h_evt.rect_id; - if (h_evt.type == START) { - v_evt.type = START; - v_evt.y = rect.top; - sweep_v_events.insert(v_evt); - - v_evt.type = END; - v_evt.y = rect.bottom; - sweep_v_events.insert(v_evt); - } else { - v_evt.type = START; - v_evt.y = rect.top; - typename std::set<SweepEvent<TId, TNum>>::iterator start_it = - sweep_v_events.find(v_evt); - assert(start_it != sweep_v_events.end()); - sweep_v_events.erase(start_it); - - v_evt.type = END; - v_evt.y = rect.bottom; - typename std::set<SweepEvent<TId, TNum>>::iterator end_it = - sweep_v_events.find(v_evt); - assert(end_it != sweep_v_events.end()); - sweep_v_events.erase(end_it); - } - - // Peeks ahead to see if there are other rectangles sharing a vertical edge - // with the current sweep line. If so, we want to continue marking up the - // sweep line before actually processing the rectangles the sweep line is - // intersecting. - typename std::set<SweepEvent<TId, TNum>>::iterator next_it = it; - ++next_it; - if (next_it != sweep_h_events.end()) { - if (next_it->x == h_evt.x) { - continue; - } - } - -#ifdef RECTS_DEBUG - std::cout << h_evt.x << std::endl; -#endif - - // After the following for loop, active_regions will be a list of - // y-coordinates paired with the set of rectangle IDs that are intersect at - // that y-coordinate (and the current sweep line's x-coordinate). For - // example if the current sweep line were the left edge of a scene with only - // one rectangle of ID 0 and bounds (left, top, right, bottom) == (2, 3, 4, - // 5), active_regions will be [({ 0 }, 3), {}, 5]. - active_regions.clear(); - IdSet<TId> active_set; - for (typename std::set<SweepEvent<TId, TNum>>::iterator it = - sweep_v_events.begin(); - it != sweep_v_events.end(); ++it) { - const SweepEvent<TId, TNum> &v_evt = *it; - - if (v_evt.type == START) { - active_set.add(v_evt.rect_id); - } else { - active_set.subtract(v_evt.rect_id); - } - - if (active_regions.size() > 0 && active_regions.back().first == v_evt.y) { - active_regions.back().second = active_set; - } else { - active_regions.push_back(std::make_pair(v_evt.y, active_set)); - } - } - -#ifdef RECTS_DEBUG - std::cout << "x:" << h_evt.x; - for (std::vector<std::pair<TNum, IdSet>>::iterator it = - active_regions.begin(); - it != active_regions.end(); ++it) { - std::cout << " " << it->first << "(" << it->second << ")" - << ","; - } - std::cout << std::endl; -#endif - - // To determine which started rectangles are ending this event, we make them - // all as false, or unseen during this sweep line. - for (typename std::map<StartedRect<TId, TNum>, bool>::iterator it = - started_rects.begin(); - it != started_rects.end(); ++it) { - it->second = false; - } - - // This for loop will iterate all potential new rectangles and either - // discover it was already started (and then mark it true), or that it is a - // new rectangle and add it to the started rectangles. A started rectangle - // is unique if it has a distinct top, bottom, and set of rectangle IDs. - // This is tricky because a potential rectangle could be encountered here - // that has a non-unique top and bottom, so it shares geometry with an - // already started rectangle, but the set of rectangle IDs differs. In that - // case, we have a new rectangle, and the already existing started rectangle - // will not be marked as seen ("true" in the std::pair) and will get ended - // by the for loop after this one. This is as intended. - for (typename std::vector<std::pair<TNum, IdSet<TId>>>::iterator it = - active_regions.begin(); - it != active_regions.end(); ++it) { - IdSet<TId> region_set = it->second; - - if (region_set.isEmpty()) - continue; - - // An important property of active_regions is that each region where a set - // of rectangles applies is bounded at the bottom by the next (in the - // vector) region's starting y-coordinate. - typename std::vector<std::pair<TNum, IdSet<TId>>>::iterator next_it = it; - ++next_it; - assert(next_it != active_regions.end()); - - TNum region_top = it->first; - TNum region_bottom = next_it->first; - - StartedRect<TId, TNum> rect_key; - rect_key.id_set = region_set; - rect_key.left = h_evt.x; - rect_key.top = region_top; - rect_key.bottom = region_bottom; - - // Remember that rect_key.left is ignored for the purposes of searching - // the started rects. This follows from the fact that a previously started - // rectangle would by definition have a left bound less than the current - // event's x-coordinate. We are interested in continuing the started - // rectangles by marking them seen (true) but we don't know, care, or wish - // to change the left bound at this point. If there are no matching - // rectangles for this region, start a new one and mark it as seen (true). - typename std::map<StartedRect<TId, TNum>, bool>::iterator - started_rect_it = started_rects.find(rect_key); - if (started_rect_it == started_rects.end()) { - started_rects[rect_key] = true; - } else { - started_rect_it->second = true; - } - } - - // This for loop ends all rectangles that were unseen during this event. - // Because this is the first event where we didn't see this rectangle, it's - // right edge is exactly the current event's x-coordinate. With this, we - // have the final piece of information to output this rectangle's geometry - // and set of input rectangle IDs. To end a started rectangle, we erase it - // from the started_rects map and append the completed rectangle to the - // output vector. - for (typename std::map<StartedRect<TId, TNum>, bool>::iterator it = - started_rects.begin(); - it != started_rects.end(); - /* inc in body */) { - if (!it->second) { - const StartedRect<TId, TNum> &proto_rect = it->first; - Rect<TNum> out_rect; - out_rect.left = proto_rect.left; - out_rect.top = proto_rect.top; - out_rect.right = h_evt.x; - out_rect.bottom = proto_rect.bottom; - out->push_back(RectSet<TId, TNum>(proto_rect.id_set, out_rect)); - started_rects.erase(it++); // Also increments out iterator. - -#ifdef RECTS_DEBUG - std::cout << " <" << proto_rect.id_set << "(" << rect << ")" - << std::endl; -#endif - } else { - // Remember this for loop has no built in increment step. We do it here. - ++it; - } - } - } -} - -void separate_frects_64(const std::vector<Rect<float>> &in, - std::vector<RectSet<uint64_t, float>> *out) { - separate_rects(in, out); -} - -void separate_rects_64(const std::vector<Rect<int>> &in, - std::vector<RectSet<uint64_t, int>> *out) { - separate_rects(in, out); -} - -} // namespace separate_rects diff --git a/separate_rects.h b/separate_rects.h deleted file mode 100644 index de8b660..0000000 --- a/separate_rects.h +++ /dev/null @@ -1,169 +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 DRM_HWCOMPOSER_SEPARATE_RECTS_H_ -#define DRM_HWCOMPOSER_SEPARATE_RECTS_H_ - -#include <stdint.h> - -#include <sstream> -#include <vector> - -namespace separate_rects { - -template <typename TFloat> -struct Rect { - union { - struct { - TFloat left, top, right, bottom; - }; - struct { - TFloat x1, y1, x2, y2; - }; - TFloat bounds[4]; - }; - - typedef TFloat TNum; - - Rect() { - } - - Rect(TFloat xx1, TFloat yy1, TFloat xx2, TFloat yy2) - : x1(xx1), y1(yy1), x2(xx2), y2(yy2) { - } - - template <typename T> - Rect(const Rect<T> &rhs) { - for (int i = 0; i < 4; i++) - bounds[i] = rhs.bounds[i]; - } - - template <typename T> - Rect<TFloat> &operator=(const Rect<T> &rhs) { - for (int i = 0; i < 4; i++) - bounds[i] = rhs.bounds[i]; - return *this; - } - - bool operator==(const Rect &rhs) const { - for (int i = 0; i < 4; i++) { - if (bounds[i] != rhs.bounds[i]) - return false; - } - - return true; - } - - TFloat width() const { - return bounds[2] - bounds[0]; - } - - TFloat height() const { - return bounds[3] - bounds[1]; - } - - TFloat area() const { - return width() * height(); - } - - void Dump(std::ostringstream *out) const { - *out << "[x/y/w/h]=" << left << "/" << top << "/" << width() << "/" - << height(); - } -}; - -template <typename TUInt> -struct IdSet { - public: - typedef TUInt TId; - - IdSet() : bitset(0) { - } - - IdSet(TId id) : bitset(0) { - add(id); - } - - void add(TId id) { - bitset |= ((TUInt)1) << id; - } - - void subtract(TId id) { - bitset &= ~(((TUInt)1) << id); - } - - bool isEmpty() const { - return bitset == 0; - } - - TUInt getBits() const { - return bitset; - } - - bool operator==(const IdSet<TId> &rhs) const { - return bitset == rhs.bitset; - } - - bool operator<(const IdSet<TId> &rhs) const { - return bitset < rhs.bitset; - } - - IdSet<TId> operator|(const IdSet<TId> &rhs) const { - IdSet ret; - ret.bitset = bitset | rhs.bitset; - return ret; - } - - IdSet<TId> operator|(TId id) const { - IdSet<TId> ret; - ret.bitset = bitset; - ret.add(id); - return ret; - } - - static const int max_elements = sizeof(TId) * 8; - - private: - TUInt bitset; -}; - -template <typename TId, typename TNum> -struct RectSet { - IdSet<TId> id_set; - Rect<TNum> rect; - - RectSet(const IdSet<TId> &i, const Rect<TNum> &r) : id_set(i), rect(r) { - } - - bool operator==(const RectSet<TId, TNum> &rhs) const { - return id_set == rhs.id_set && rect == rhs.rect; - } -}; - -// Separates up to a maximum of 64 input rectangles into mutually non- -// overlapping rectangles that cover the exact same area and outputs those non- -// overlapping rectangles. Each output rectangle also includes the set of input -// rectangle indices that overlap the output rectangle encoded in a bitset. For -// example, an output rectangle that overlaps input rectangles in[0], in[1], and -// in[4], the bitset would be (ommitting leading zeroes) 10011. -void separate_frects_64(const std::vector<Rect<float>> &in, - std::vector<RectSet<uint64_t, float>> *out); -void separate_rects_64(const std::vector<Rect<int>> &in, - std::vector<RectSet<uint64_t, int>> *out); - -} // namespace separate_rects - -#endif diff --git a/tests/Android.mk b/tests/Android.mk index 3b9e0a2..b498d62 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -3,10 +3,11 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := \ - separate_rects_test.cpp \ worker_test.cpp LOCAL_MODULE := hwc-drm-tests +LOCAL_VENDOR_MODULE := true +LOCAL_HEADER_LIBRARIES := libhardware_headers LOCAL_STATIC_LIBRARIES := libdrmhwc_utils LOCAL_SHARED_LIBRARIES := hwcomposer.drm LOCAL_C_INCLUDES := external/drm_hwcomposer diff --git a/tests/separate_rects_test.cpp b/tests/separate_rects_test.cpp deleted file mode 100644 index d9595dd..0000000 --- a/tests/separate_rects_test.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include <gtest/gtest.h> -#include <hardware/hardware.h> - -#include "separate_rects.h" - -using namespace separate_rects; - -#define RectSet RectSet<TId, TNum> -#define Rect Rect<TNum> -#define IdSet IdSet<TId> -typedef uint64_t TId; -typedef float TNum; - -struct SeparateRectTest : public testing::Test { - bool IsEquality(std::vector<RectSet> &out, - std::vector<RectSet> &expected_out) { - // Test for rects missing from out - for (size_t i = 0; i < expected_out.size(); i++) { - RectSet &ex_out = expected_out[i]; - if (std::find(out.begin(), out.end(), ex_out) == out.end()) { - return false; - } - } - - // Test for presence of unexpected rects in out - for (size_t i = 0; i < out.size(); i++) { - RectSet &actual_out = out[i]; - if (std::find(expected_out.begin(), expected_out.end(), actual_out) == - expected_out.end()) { - return false; - } - } - - return true; - } -}; - -TEST_F(SeparateRectTest, test_separate_rect) { - std::vector<Rect> in; - std::vector<RectSet> out; - std::vector<RectSet> expected_out; - - in.push_back({0, 0, 4, 5}); - in.push_back({2, 0, 6, 6}); - in.push_back({4, 0, 8, 5}); - in.push_back({0, 7, 8, 9}); - - in.push_back({10, 0, 18, 5}); - in.push_back({12, 0, 16, 5}); - - in.push_back({20, 11, 24, 17}); - in.push_back({22, 13, 26, 21}); - in.push_back({32, 33, 36, 37}); - in.push_back({30, 31, 38, 39}); - - in.push_back({40, 43, 48, 45}); - in.push_back({44, 41, 46, 47}); - - in.push_back({50, 51, 52, 53}); - in.push_back({50, 51, 52, 53}); - in.push_back({50, 51, 52, 53}); - - in.push_back({0, 0, 0, 10}); - in.push_back({0, 0, 10, 0}); - in.push_back({10, 0, 0, 10}); - in.push_back({0, 10, 10, 0}); - - for (int i = 0; i < 100000; i++) { - out.clear(); - separate_frects_64(in, &out); - } - - expected_out.push_back(RectSet(IdSet(0), Rect(0, 0, 2, 5))); - expected_out.push_back(RectSet(IdSet(1), Rect(2, 5, 6, 6))); - expected_out.push_back(RectSet(IdSet(1) | 0, Rect(2, 0, 4, 5))); - expected_out.push_back(RectSet(IdSet(1) | 2, Rect(4, 0, 6, 5))); - expected_out.push_back(RectSet(IdSet(2), Rect(6, 0, 8, 5))); - expected_out.push_back(RectSet(IdSet(3), Rect(0, 7, 8, 9))); - expected_out.push_back(RectSet(IdSet(4), Rect(10, 0, 12, 5))); - expected_out.push_back(RectSet(IdSet(5) | 4, Rect(12, 0, 16, 5))); - expected_out.push_back(RectSet(IdSet(4), Rect(16, 0, 18, 5))); - expected_out.push_back(RectSet(IdSet(6), Rect(20, 11, 22, 17))); - expected_out.push_back(RectSet(IdSet(6) | 7, Rect(22, 13, 24, 17))); - expected_out.push_back(RectSet(IdSet(6), Rect(22, 11, 24, 13))); - expected_out.push_back(RectSet(IdSet(7), Rect(22, 17, 24, 21))); - expected_out.push_back(RectSet(IdSet(7), Rect(24, 13, 26, 21))); - expected_out.push_back(RectSet(IdSet(9), Rect(30, 31, 32, 39))); - expected_out.push_back(RectSet(IdSet(8) | 9, Rect(32, 33, 36, 37))); - expected_out.push_back(RectSet(IdSet(9), Rect(32, 37, 36, 39))); - expected_out.push_back(RectSet(IdSet(9), Rect(32, 31, 36, 33))); - expected_out.push_back(RectSet(IdSet(9), Rect(36, 31, 38, 39))); - expected_out.push_back(RectSet(IdSet(10), Rect(40, 43, 44, 45))); - expected_out.push_back(RectSet(IdSet(10) | 11, Rect(44, 43, 46, 45))); - expected_out.push_back(RectSet(IdSet(11), Rect(44, 41, 46, 43))); - expected_out.push_back(RectSet(IdSet(11), Rect(44, 45, 46, 47))); - expected_out.push_back(RectSet(IdSet(10), Rect(46, 43, 48, 45))); - expected_out.push_back(RectSet(IdSet(12) | 13 | 14, Rect(50, 51, 52, 53))); - - ASSERT_TRUE(IsEquality(out, expected_out)); -} diff --git a/virtualcompositorworker.cpp b/virtualcompositorworker.cpp deleted file mode 100644 index 639dc86..0000000 --- a/virtualcompositorworker.cpp +++ /dev/null @@ -1,168 +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-virtual-compositor-worker" - -#include "virtualcompositorworker.h" -#include "worker.h" - -#include <errno.h> -#include <stdlib.h> - -#include <cutils/log.h> -#include <hardware/hardware.h> -#include <hardware/hwcomposer.h> -#include <sched.h> -#include <sw_sync.h> -#include <sync/sync.h> - -namespace android { - -static const int kMaxQueueDepth = 3; -static const int kAcquireWaitTimeoutMs = 3000; - -VirtualCompositorWorker::VirtualCompositorWorker() - : Worker("virtual-compositor", HAL_PRIORITY_URGENT_DISPLAY), - timeline_fd_(-1), - timeline_(0), - timeline_current_(0) { -} - -VirtualCompositorWorker::~VirtualCompositorWorker() { - if (timeline_fd_ >= 0) { - FinishComposition(timeline_); - close(timeline_fd_); - timeline_fd_ = -1; - } -} - -int VirtualCompositorWorker::Init() { - int ret = sw_sync_timeline_create(); - if (ret < 0) { - ALOGE("Failed to create sw sync timeline %d", ret); - return ret; - } - timeline_fd_ = ret; - return InitWorker(); -} - -void VirtualCompositorWorker::QueueComposite(hwc_display_contents_1_t *dc) { - std::unique_ptr<VirtualComposition> composition(new VirtualComposition); - - composition->outbuf_acquire_fence.Set(dc->outbufAcquireFenceFd); - dc->outbufAcquireFenceFd = -1; - if (dc->retireFenceFd >= 0) - close(dc->retireFenceFd); - dc->retireFenceFd = CreateNextTimelineFence(); - - for (size_t i = 0; i < dc->numHwLayers; ++i) { - hwc_layer_1_t *layer = &dc->hwLayers[i]; - if (layer->flags & HWC_SKIP_LAYER) - continue; - composition->layer_acquire_fences.emplace_back(layer->acquireFenceFd); - layer->acquireFenceFd = -1; - if (layer->releaseFenceFd >= 0) - close(layer->releaseFenceFd); - layer->releaseFenceFd = CreateNextTimelineFence(); - } - - composition->release_timeline = timeline_; - - Lock(); - while (composite_queue_.size() >= kMaxQueueDepth) { - Unlock(); - sched_yield(); - Lock(); - } - - composite_queue_.push(std::move(composition)); - Unlock(); - Signal(); -} - -void VirtualCompositorWorker::Routine() { - int wait_ret = 0; - - Lock(); - if (composite_queue_.empty()) { - wait_ret = WaitForSignalOrExitLocked(); - } - - std::unique_ptr<VirtualComposition> composition; - if (!composite_queue_.empty()) { - composition = std::move(composite_queue_.front()); - composite_queue_.pop(); - } - Unlock(); - - if (wait_ret == -EINTR) { - return; - } else if (wait_ret) { - ALOGE("Failed to wait for signal, %d", wait_ret); - return; - } - - Compose(std::move(composition)); -} - -int VirtualCompositorWorker::CreateNextTimelineFence() { - ++timeline_; - return sw_sync_fence_create(timeline_fd_, "drm_fence", timeline_); -} - -int VirtualCompositorWorker::FinishComposition(int point) { - int timeline_increase = point - timeline_current_; - if (timeline_increase <= 0) - return 0; - int ret = sw_sync_timeline_inc(timeline_fd_, timeline_increase); - if (ret) - ALOGE("Failed to increment sync timeline %d", ret); - else - timeline_current_ = point; - return ret; -} - -void VirtualCompositorWorker::Compose( - std::unique_ptr<VirtualComposition> composition) { - if (!composition.get()) - return; - - int ret; - int outbuf_acquire_fence = composition->outbuf_acquire_fence.get(); - if (outbuf_acquire_fence >= 0) { - ret = sync_wait(outbuf_acquire_fence, kAcquireWaitTimeoutMs); - if (ret) { - ALOGE("Failed to wait for outbuf acquire %d/%d", outbuf_acquire_fence, - ret); - return; - } - composition->outbuf_acquire_fence.Close(); - } - for (size_t i = 0; i < composition->layer_acquire_fences.size(); ++i) { - int layer_acquire_fence = composition->layer_acquire_fences[i].get(); - if (layer_acquire_fence >= 0) { - ret = sync_wait(layer_acquire_fence, kAcquireWaitTimeoutMs); - if (ret) { - ALOGE("Failed to wait for layer acquire %d/%d", layer_acquire_fence, - ret); - return; - } - composition->layer_acquire_fences[i].Close(); - } - } - FinishComposition(composition->release_timeline); -} -} diff --git a/virtualcompositorworker.h b/virtualcompositorworker.h deleted file mode 100644 index 1fc5e43..0000000 --- a/virtualcompositorworker.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_VIRTUAL_COMPOSITOR_WORKER_H_ -#define ANDROID_VIRTUAL_COMPOSITOR_WORKER_H_ - -#include "drmhwcomposer.h" -#include "worker.h" - -#include <queue> - -namespace android { - -class VirtualCompositorWorker : public Worker { - public: - VirtualCompositorWorker(); - ~VirtualCompositorWorker() override; - - int Init(); - void QueueComposite(hwc_display_contents_1_t *dc); - - protected: - void Routine() override; - - private: - struct VirtualComposition { - UniqueFd outbuf_acquire_fence; - std::vector<UniqueFd> layer_acquire_fences; - int release_timeline; - }; - - int CreateNextTimelineFence(); - int FinishComposition(int timeline); - void Compose(std::unique_ptr<VirtualComposition> composition); - - std::queue<std::unique_ptr<VirtualComposition>> composite_queue_; - int timeline_fd_; - int timeline_; - int timeline_current_; -}; -} - -#endif diff --git a/vsyncworker.cpp b/vsyncworker.cpp index 3ad16fe..6ac016d 100644 --- a/vsyncworker.cpp +++ b/vsyncworker.cpp @@ -26,7 +26,7 @@ #include <xf86drm.h> #include <xf86drmMode.h> -#include <cutils/log.h> +#include <log/log.h> #include <hardware/hardware.h> namespace android { @@ -35,6 +35,7 @@ VSyncWorker::VSyncWorker() : Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY), drm_(NULL), display_(-1), + enabled_(false), last_timestamp_(-1) { } @@ -119,6 +120,7 @@ void VSyncWorker::Routine() { if (!enabled_) { ret = WaitForSignalOrExitLocked(); if (ret == -EINTR) { + Unlock(); return; } } |