resolve merge conflicts of 98804031fb4692cd1987c31a6056eb3052538ac4 to stage-aosp-master
Test: I solemnly swear I tested this conflict resolution.
Bug: None
Change-Id: I545b97420802447969b2a960c3d6a50a9f228c7f
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
diff --git a/Android.mk b/Android.mk
index 44ab1bb..3d48ba5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -36,6 +36,7 @@
LOCAL_CFLAGS := $(common_drm_hwcomposer_cflags)
LOCAL_MODULE := libdrmhwc_utils
+LOCAL_VENDOR_MODULE := true
include $(BUILD_STATIC_LIBRARY)
@@ -47,8 +48,6 @@
LOCAL_SHARED_LIBRARIES := \
libcutils \
libdrm \
- libEGL \
- libGLESv2 \
libhardware \
liblog \
libsync \
@@ -58,17 +57,11 @@
LOCAL_STATIC_LIBRARIES := libdrmhwc_utils
LOCAL_C_INCLUDES := \
- external/drm_gralloc \
- external/libdrm \
- external/libdrm/include/drm \
- system/core/include/utils \
- system/core/libsync \
- system/core/libsync/include \
+ system/core/libsync
LOCAL_SRC_FILES := \
+ autolock.cpp \
drmresources.cpp \
- drmcomposition.cpp \
- drmcompositor.cpp \
drmconnector.cpp \
drmcrtc.cpp \
drmdisplaycomposition.cpp \
@@ -79,11 +72,9 @@
drmmode.cpp \
drmplane.cpp \
drmproperty.cpp \
- glworker.cpp \
hwcutils.cpp \
platform.cpp \
- separate_rects.cpp \
- virtualcompositorworker.cpp \
+ platformdrmgeneric.cpp \
vsyncworker.cpp
LOCAL_CFLAGS := $(common_drm_hwcomposer_cflags)
@@ -92,12 +83,20 @@
-DHWC2_USE_CPP11 \
-DHWC2_INCLUDE_STRINGIFICATION
-ifeq ($(strip $(BOARD_DRM_HWCOMPOSER_BUFFER_IMPORTER)),nvidia-gralloc)
-LOCAL_CPPFLAGS += -DUSE_NVIDIA_IMPORTER
-LOCAL_SRC_FILES += platformnv.cpp
+
+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)
+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
-LOCAL_SRC_FILES += platformdrmgeneric.cpp
endif
LOCAL_MODULE := hwcomposer.drm
@@ -105,6 +104,8 @@
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_SUFFIX := $(TARGET_SHLIB_SUFFIX)
+LOCAL_VENDOR_MODULE := true
+
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
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
new file mode 100644
index 0000000..795a8c2
--- /dev/null
+++ b/autolock.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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-drm-auto-lock"
+
+#include "autolock.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+#include <log/log.h>
+
+namespace android {
+
+int AutoLock::Lock() {
+ if (locked_) {
+ ALOGE("Invalid attempt to double lock AutoLock %s", name_);
+ return -EINVAL;
+ }
+ int ret = pthread_mutex_lock(mutex_);
+ if (ret) {
+ ALOGE("Failed to acquire %s lock %d", name_, ret);
+ return ret;
+ }
+ locked_ = true;
+ return 0;
+}
+
+int AutoLock::Unlock() {
+ if (!locked_) {
+ ALOGE("Invalid attempt to unlock unlocked AutoLock %s", name_);
+ return -EINVAL;
+ }
+ int ret = pthread_mutex_unlock(mutex_);
+ if (ret) {
+ ALOGE("Failed to release %s lock %d", name_, ret);
+ return ret;
+ }
+ locked_ = false;
+ return 0;
+}
+}
diff --git a/autolock.h b/autolock.h
new file mode 100644
index 0000000..3b824e2
--- /dev/null
+++ b/autolock.h
@@ -0,0 +1,42 @@
+/*
+ * 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 <pthread.h>
+
+namespace android {
+
+class AutoLock {
+ public:
+ AutoLock(pthread_mutex_t *mutex, const char *const name)
+ : mutex_(mutex), name_(name) {
+ }
+ ~AutoLock() {
+ if (locked_)
+ Unlock();
+ }
+
+ AutoLock(const AutoLock &rhs) = delete;
+ AutoLock &operator=(const AutoLock &rhs) = delete;
+
+ int Lock();
+ int Unlock();
+
+ private:
+ pthread_mutex_t *const mutex_;
+ bool locked_ = false;
+ const char *const name_;
+};
+}
diff --git a/drmcomposition.cpp b/drmcomposition.cpp
deleted file mode 100644
index 1aaf920..0000000
--- a/drmcomposition.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "hwc-drm-composition"
-
-#include "drmcomposition.h"
-#include "drmcrtc.h"
-#include "drmplane.h"
-#include "drmresources.h"
-#include "platform.h"
-
-#include <stdlib.h>
-
-#include <cutils/log.h>
-#include <cutils/properties.h>
-#include <sw_sync.h>
-#include <sync/sync.h>
-
-namespace android {
-
-DrmComposition::DrmComposition(DrmResources *drm, Importer *importer,
- Planner *planner)
- : drm_(drm), importer_(importer), planner_(planner) {
- char use_overlay_planes_prop[PROPERTY_VALUE_MAX];
- property_get("hwc.drm.use_overlay_planes", use_overlay_planes_prop, "1");
- bool use_overlay_planes = atoi(use_overlay_planes_prop);
-
- for (auto &plane : drm->planes()) {
- if (plane->type() == DRM_PLANE_TYPE_PRIMARY)
- primary_planes_.push_back(plane.get());
- else if (use_overlay_planes && plane->type() == DRM_PLANE_TYPE_OVERLAY)
- overlay_planes_.push_back(plane.get());
- }
-}
-
-int DrmComposition::Init(uint64_t frame_no) {
- for (auto &conn : drm_->connectors()) {
- int display = conn->display();
- composition_map_[display].reset(new DrmDisplayComposition());
- if (!composition_map_[display]) {
- ALOGE("Failed to allocate new display composition\n");
- return -ENOMEM;
- }
-
- // If the display hasn't been modeset yet, this will be NULL
- DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
-
- int ret = composition_map_[display]->Init(drm_, crtc, importer_, planner_,
- frame_no);
- if (ret) {
- ALOGE("Failed to init display composition for %d", display);
- return ret;
- }
- }
- return 0;
-}
-
-int DrmComposition::SetLayers(size_t num_displays,
- DrmCompositionDisplayLayersMap *maps) {
- int ret = 0;
- for (size_t display_index = 0; display_index < num_displays;
- display_index++) {
- DrmCompositionDisplayLayersMap &map = maps[display_index];
- int display = map.display;
-
- if (!drm_->GetConnectorForDisplay(display)) {
- ALOGE("Invalid display given to SetLayers %d", display);
- continue;
- }
-
- ret = composition_map_[display]->SetLayers(
- map.layers.data(), map.layers.size(), map.geometry_changed);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-int DrmComposition::SetDpmsMode(int display, uint32_t dpms_mode) {
- return composition_map_[display]->SetDpmsMode(dpms_mode);
-}
-
-int DrmComposition::SetDisplayMode(int display, const DrmMode &display_mode) {
- return composition_map_[display]->SetDisplayMode(display_mode);
-}
-
-std::unique_ptr<DrmDisplayComposition> DrmComposition::TakeDisplayComposition(
- int display) {
- return std::move(composition_map_[display]);
-}
-
-int DrmComposition::Plan(std::map<int, DrmDisplayCompositor> &compositor_map) {
- int ret = 0;
- for (auto &conn : drm_->connectors()) {
- int display = conn->display();
- DrmDisplayComposition *comp = GetDisplayComposition(display);
- ret = comp->Plan(compositor_map[display].squash_state(), &primary_planes_,
- &overlay_planes_);
- if (ret) {
- ALOGE("Failed to plan composition for dislay %d", display);
- return ret;
- }
- }
-
- return 0;
-}
-
-int DrmComposition::DisableUnusedPlanes() {
- for (auto &conn : drm_->connectors()) {
- int display = conn->display();
- DrmDisplayComposition *comp = GetDisplayComposition(display);
-
- /*
- * Leave empty compositions alone
- * TODO: re-visit this and potentially disable leftover planes after the
- * active compositions have gobbled up all they can
- */
- if (comp->type() == DRM_COMPOSITION_TYPE_EMPTY ||
- comp->type() == DRM_COMPOSITION_TYPE_MODESET)
- continue;
-
- DrmCrtc *crtc = drm_->GetCrtcForDisplay(display);
- if (!crtc) {
- ALOGE("Failed to find crtc for display %d", display);
- continue;
- }
-
- for (std::vector<DrmPlane *>::iterator iter = primary_planes_.begin();
- iter != primary_planes_.end(); ++iter) {
- if ((*iter)->GetCrtcSupported(*crtc)) {
- comp->AddPlaneDisable(*iter);
- primary_planes_.erase(iter);
- break;
- }
- }
- for (std::vector<DrmPlane *>::iterator iter = overlay_planes_.begin();
- iter != overlay_planes_.end();) {
- if ((*iter)->GetCrtcSupported(*crtc)) {
- comp->AddPlaneDisable(*iter);
- iter = overlay_planes_.erase(iter);
- } else {
- iter++;
- }
- }
- }
- return 0;
-}
-
-DrmDisplayComposition *DrmComposition::GetDisplayComposition(int display) {
- return composition_map_[display].get();
-}
-}
diff --git a/drmcomposition.h b/drmcomposition.h
deleted file mode 100644
index eae8cde..0000000
--- a/drmcomposition.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_COMPOSITION_H_
-#define ANDROID_DRM_COMPOSITION_H_
-
-#include "drmhwcomposer.h"
-#include "drmdisplaycomposition.h"
-#include "drmplane.h"
-#include "platform.h"
-
-#include <map>
-#include <vector>
-
-#include <hardware/hardware.h>
-#include <hardware/hwcomposer.h>
-
-namespace android {
-
-class DrmDisplayCompositor;
-
-struct DrmCompositionDisplayLayersMap {
- int display;
- bool geometry_changed = true;
- std::vector<DrmHwcLayer> layers;
-
- DrmCompositionDisplayLayersMap() = default;
- DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) =
- default;
-};
-
-class DrmComposition {
- public:
- DrmComposition(DrmResources *drm, Importer *importer, Planner *planner);
-
- int Init(uint64_t frame_no);
-
- int SetLayers(size_t num_displays, DrmCompositionDisplayLayersMap *maps);
- int SetDpmsMode(int display, uint32_t dpms_mode);
- int SetDisplayMode(int display, const DrmMode &display_mode);
-
- std::unique_ptr<DrmDisplayComposition> TakeDisplayComposition(int display);
- DrmDisplayComposition *GetDisplayComposition(int display);
-
- int Plan(std::map<int, DrmDisplayCompositor> &compositor_map);
- int DisableUnusedPlanes();
-
- private:
- DrmComposition(const DrmComposition &) = delete;
-
- DrmResources *drm_;
- Importer *importer_;
- Planner *planner_;
-
- std::vector<DrmPlane *> primary_planes_;
- std::vector<DrmPlane *> overlay_planes_;
-
- /*
- * This _must_ be read-only after it's passed to QueueComposition. Otherwise
- * locking is required to maintain consistency across the compositor threads.
- */
- std::map<int, std::unique_ptr<DrmDisplayComposition>> composition_map_;
-};
-}
-
-#endif // ANDROID_DRM_COMPOSITION_H_
diff --git a/drmcompositor.cpp b/drmcompositor.cpp
deleted file mode 100644
index c1f3ed8..0000000
--- a/drmcompositor.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "hwc-drm-compositor"
-
-#include "drmcompositor.h"
-#include "drmdisplaycompositor.h"
-#include "drmresources.h"
-#include "platform.h"
-
-#include <sstream>
-#include <stdlib.h>
-
-#include <cutils/log.h>
-
-namespace android {
-
-DrmCompositor::DrmCompositor(DrmResources *drm) : drm_(drm), frame_no_(0) {
-}
-
-DrmCompositor::~DrmCompositor() {
-}
-
-int DrmCompositor::Init() {
- for (auto &conn : drm_->connectors()) {
- int display = conn->display();
- int ret = compositor_map_[display].Init(drm_, display);
- if (ret) {
- ALOGE("Failed to initialize display compositor for %d", display);
- return ret;
- }
- }
- planner_ = Planner::CreateInstance(drm_);
- if (!planner_) {
- ALOGE("Failed to create planner instance for composition");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-std::unique_ptr<DrmComposition> DrmCompositor::CreateComposition(
- Importer *importer) {
- std::unique_ptr<DrmComposition> composition(
- new DrmComposition(drm_, importer, planner_.get()));
- int ret = composition->Init(++frame_no_);
- if (ret) {
- ALOGE("Failed to initialize drm composition %d", ret);
- return nullptr;
- }
- return composition;
-}
-
-int DrmCompositor::QueueComposition(
- std::unique_ptr<DrmComposition> composition) {
- int ret;
-
- ret = composition->Plan(compositor_map_);
- if (ret)
- return ret;
-
- ret = composition->DisableUnusedPlanes();
- if (ret)
- return ret;
-
- for (auto &conn : drm_->connectors()) {
- int display = conn->display();
- int ret = compositor_map_[display].QueueComposition(
- composition->TakeDisplayComposition(display));
- if (ret) {
- ALOGE("Failed to queue composition for display %d (%d)", display, ret);
- return ret;
- }
- }
-
- return 0;
-}
-
-int DrmCompositor::Composite() {
- /*
- * This shouldn't be called, we should be calling Composite() on the display
- * compositors directly.
- */
- ALOGE("Calling base drm compositor Composite() function");
- return -EINVAL;
-}
-
-void DrmCompositor::Dump(std::ostringstream *out) const {
- *out << "DrmCompositor stats:\n";
- for (auto &conn : drm_->connectors())
- compositor_map_[conn->display()].Dump(out);
-}
-}
diff --git a/drmcompositor.h b/drmcompositor.h
deleted file mode 100644
index 19271b5..0000000
--- a/drmcompositor.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_DRM_COMPOSITOR_H_
-#define ANDROID_DRM_COMPOSITOR_H_
-
-#include "drmcomposition.h"
-#include "drmdisplaycompositor.h"
-#include "platform.h"
-
-#include <map>
-#include <memory>
-#include <sstream>
-
-namespace android {
-
-class DrmCompositor {
- public:
- DrmCompositor(DrmResources *drm);
- ~DrmCompositor();
-
- int Init();
-
- std::unique_ptr<DrmComposition> CreateComposition(Importer *importer);
-
- int QueueComposition(std::unique_ptr<DrmComposition> composition);
- int Composite();
- void Dump(std::ostringstream *out) const;
-
- private:
- DrmCompositor(const DrmCompositor &) = delete;
-
- DrmResources *drm_;
- std::unique_ptr<Planner> planner_;
-
- uint64_t frame_no_;
-
- // mutable for Dump() propagation
- mutable std::map<int, DrmDisplayCompositor> compositor_map_;
-};
-}
-
-#endif // ANDROID_DRM_COMPOSITOR_H_
diff --git a/drmconnector.cpp b/drmconnector.cpp
index ccb38e2..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 {
@@ -67,11 +67,21 @@
display_ = display;
}
-bool DrmConnector::built_in() const {
+bool DrmConnector::internal() const {
return type_ == DRM_MODE_CONNECTOR_LVDS || type_ == DRM_MODE_CONNECTOR_eDP ||
type_ == DRM_MODE_CONNECTOR_DSI || type_ == DRM_MODE_CONNECTOR_VIRTUAL;
}
+bool DrmConnector::external() const {
+ return type_ == DRM_MODE_CONNECTOR_HDMIA || type_ == DRM_MODE_CONNECTOR_DisplayPort ||
+ type_ == DRM_MODE_CONNECTOR_DVID || type_ == DRM_MODE_CONNECTOR_DVII ||
+ type_ == DRM_MODE_CONNECTOR_VGA;
+}
+
+bool DrmConnector::valid_type() const {
+ return internal() || external();
+}
+
int DrmConnector::UpdateModes() {
int fd = drm_->fd();
diff --git a/drmconnector.h b/drmconnector.h
index e1488bb..5601e06 100644
--- a/drmconnector.h
+++ b/drmconnector.h
@@ -44,7 +44,9 @@
int display() const;
void set_display(int display);
- bool built_in() const;
+ bool internal() const;
+ bool external() const;
+ bool valid_type() const;
int UpdateModes();
diff --git a/drmcrtc.cpp b/drmcrtc.cpp
index 1fbdc12..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 {
@@ -31,12 +31,7 @@
id_(c->crtc_id),
pipe_(pipe),
display_(-1),
- x_(c->x),
- y_(c->y),
- width_(c->width),
- height_(c->height),
- mode_(&c->mode),
- mode_valid_(c->mode_valid) {
+ mode_(&c->mode) {
}
int DrmCrtc::Init() {
@@ -51,6 +46,12 @@
ALOGE("Failed to get MODE_ID property");
return ret;
}
+
+ ret = drm_->GetCrtcProperty(*this, "OUT_FENCE_PTR", &out_fence_ptr_property_);
+ if (ret) {
+ ALOGE("Failed to get OUT_FENCE_PTR property");
+ return ret;
+ }
return 0;
}
@@ -81,4 +82,8 @@
const DrmProperty &DrmCrtc::mode_property() const {
return mode_property_;
}
+
+const DrmProperty &DrmCrtc::out_fence_ptr_property() const {
+ return out_fence_ptr_property_;
+}
}
diff --git a/drmcrtc.h b/drmcrtc.h
index ad95352..c5a5599 100644
--- a/drmcrtc.h
+++ b/drmcrtc.h
@@ -45,6 +45,7 @@
const DrmProperty &active_property() const;
const DrmProperty &mode_property() const;
+ const DrmProperty &out_fence_ptr_property() const;
private:
DrmResources *drm_;
@@ -53,16 +54,11 @@
unsigned pipe_;
int display_;
- uint32_t x_;
- uint32_t y_;
- uint32_t width_;
- uint32_t height_;
-
DrmMode mode_;
- bool mode_valid_;
DrmProperty active_property_;
DrmProperty mode_property_;
+ DrmProperty out_fence_ptr_property_;
};
}
diff --git a/drmdisplaycomposition.cpp b/drmdisplaycomposition.cpp
index 0f8084b..129bec2 100644
--- a/drmdisplaycomposition.cpp
+++ b/drmdisplaycomposition.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "hwc-drm-display-composition"
#include "drmdisplaycomposition.h"
+#include "drmdisplaycompositor.h"
#include "drmcrtc.h"
#include "drmplane.h"
#include "drmresources.h"
@@ -27,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,
@@ -50,12 +46,6 @@
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;
}
@@ -63,26 +53,6 @@
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))
@@ -121,253 +91,25 @@
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;
@@ -395,17 +137,7 @@
}
}
- 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) {
@@ -505,23 +237,6 @@
}
}
-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)
@@ -539,10 +254,6 @@
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];
@@ -556,12 +267,7 @@
*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";
@@ -577,12 +283,6 @@
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;
@@ -594,19 +294,5 @@
}
*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 13da19d..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>
@@ -42,8 +40,17 @@
DRM_COMPOSITION_TYPE_MODESET,
};
+struct DrmCompositionDisplayLayersMap {
+ int display;
+ bool geometry_changed = true;
+ std::vector<DrmHwcLayer> layers;
+
+ DrmCompositionDisplayLayersMap() = default;
+ DrmCompositionDisplayLayersMap(DrmCompositionDisplayLayersMap &&rhs) =
+ default;
+};
+
struct DrmCompositionRegion {
- DrmHwcRect<int> frame;
std::vector<size_t> source_layers;
};
@@ -52,8 +59,6 @@
enum class Type : int32_t {
kDisable,
kLayer,
- kPrecomp,
- kSquash,
};
DrmCompositionPlane() = default;
@@ -115,34 +120,13 @@
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_;
}
@@ -179,18 +163,19 @@
return planner_;
}
+ int take_out_fence() {
+ return out_fence_.Release();
+ }
+
+ void set_out_fence(int out_fence) {
+ out_fence_.Set(out_fence);
+ }
+
void Dump(std::ostringstream *out) const;
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;
@@ -200,16 +185,10 @@
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 b3cfb6d..e7e0694 100644
--- a/drmdisplaycompositor.cpp
+++ b/drmdisplaycompositor.cpp
@@ -19,215 +19,33 @@
#include "drmdisplaycompositor.h"
+#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <time.h>
-#include <algorithm>
-#include <bitset>
-#include <cinttypes>
-#include <mutex>
#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>
+#include "autolock.h"
#include "drmcrtc.h"
#include "drmplane.h"
#include "drmresources.h"
-#include "glworker.h"
-
-#define DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH 2
namespace android {
-static const int64_t kSquashWait = 500LL;
-
-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::FrameWorker::FrameWorker(DrmDisplayCompositor *compositor)
- : QueueWorker("frame-worker", HAL_PRIORITY_URGENT_DISPLAY),
- compositor_(compositor) {
-}
-
-int DrmDisplayCompositor::FrameWorker::Init() {
- set_max_queue_size(DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH);
- return InitWorker();
-}
-
-void DrmDisplayCompositor::FrameWorker::QueueFrame(
- std::unique_ptr<DrmDisplayComposition> composition, int status) {
- std::unique_ptr<FrameState> frame(
- new FrameState(std::move(composition), status));
-
- auto start = std::chrono::high_resolution_clock::now();
- int ret = QueueWork(std::move(frame));
- if (ret) {
- ALOGE("Unable to queue frame work (%d)", ret);
- // TODO: error handling (timeout or exit)
- return;
- }
- auto end = std::chrono::high_resolution_clock::now();
-
- uint64_t duration_us =
- std::chrono::duration_cast<std::chrono::microseconds>(end - start)
- .count();
- if (duration_us > max_duration_us)
- max_duration_us = duration_us;
-}
-
-void DrmDisplayCompositor::FrameWorker::ProcessWork(
- std::unique_ptr<FrameState> frame) {
- compositor_->ApplyFrame(std::move(frame->composition), frame->status);
-}
-
DrmDisplayCompositor::DrmDisplayCompositor()
- : QueueWorker("drm-compositor", HAL_PRIORITY_URGENT_DISPLAY),
- drm_(NULL),
+ : drm_(NULL),
display_(-1),
- frame_worker_(this),
+ initialized_(false),
active_(false),
use_hw_overlays_(true),
- framebuffer_index_(0),
- squash_framebuffer_index_(0),
dump_frames_composited_(0),
- dump_last_timestamp_ns_(0),
- max_duration_us(0) {
+ dump_last_timestamp_ns_(0) {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts))
return;
@@ -235,13 +53,12 @@
}
DrmDisplayCompositor::~DrmDisplayCompositor() {
- if (!initialized())
+ if (!initialized_)
return;
- frame_worker_.Exit();
- Exit();
-
- std::lock_guard<std::mutex> lk(mutex_);
+ int ret = pthread_mutex_lock(&lock_);
+ if (ret)
+ ALOGE("Failed to acquire compositor lock %d", ret);
if (mode_.blob_id)
drm_->DestroyPropertyBlob(mode_.blob_id);
@@ -249,18 +66,26 @@
drm_->DestroyPropertyBlob(mode_.old_blob_id);
active_composition_.reset();
+
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret)
+ ALOGE("Failed to acquire compositor lock %d", ret);
+
+ pthread_mutex_destroy(&lock_);
}
int DrmDisplayCompositor::Init(DrmResources *drm, int display) {
drm_ = drm;
display_ = display;
- frame_worker_.Init();
+ int ret = pthread_mutex_init(&lock_, NULL);
+ if (ret) {
+ ALOGE("Failed to initialize drm compositor lock %d\n", ret);
+ return ret;
+ }
- set_max_queue_size(DRM_DISPLAY_COMPOSITOR_MAX_QUEUE_DEPTH);
- set_idle_timeout(kSquashWait);
-
- return InitWorker();
+ initialized_ = true;
+ return 0;
}
std::unique_ptr<DrmDisplayComposition> DrmDisplayCompositor::CreateComposition()
@@ -268,49 +93,6 @@
return std::unique_ptr<DrmDisplayComposition>(new DrmDisplayComposition());
}
-int DrmDisplayCompositor::QueueComposition(
- std::unique_ptr<DrmDisplayComposition> composition) {
- switch (composition->type()) {
- case DRM_COMPOSITION_TYPE_FRAME:
- if (!active_)
- return -ENODEV;
- break;
- case DRM_COMPOSITION_TYPE_DPMS:
- /*
- * Update the state as soon as we get it so we can start/stop queuing
- * frames asap.
- */
- active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
- break;
- case DRM_COMPOSITION_TYPE_MODESET:
- break;
- case DRM_COMPOSITION_TYPE_EMPTY:
- return 0;
- default:
- ALOGE("Unknown composition type %d/%d", composition->type(), display_);
- return -ENOENT;
- }
-
- auto start = std::chrono::high_resolution_clock::now();
-
- int ret = QueueWork(std::move(composition));
- if (ret) {
- ALOGE("Unable to queue work (%d)", ret);
- // TODO: error handling (timeout or exit)
- return ret;
- }
-
- auto end = std::chrono::high_resolution_clock::now();
-
- uint64_t duration_us =
- std::chrono::duration_cast<std::chrono::microseconds>(end - start)
- .count();
- if (duration_us > max_duration_us)
- max_duration_us = duration_us;
-
- return 0;
-}
-
std::tuple<uint32_t, uint32_t, int>
DrmDisplayCompositor::GetActiveModeResolution() {
DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
@@ -324,112 +106,6 @@
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) {
@@ -464,94 +140,6 @@
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();
-
- 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();
@@ -561,8 +149,7 @@
std::vector<DrmHwcLayer> &layers = display_comp->layers();
std::vector<DrmCompositionPlane> &comp_planes =
display_comp->composition_planes();
- std::vector<DrmCompositionRegion> &pre_comp_regions =
- display_comp->pre_comp_regions();
+ uint64_t out_fences[drm_->crtcs().size()];
DrmConnector *connector = drm_->GetConnectorForDisplay(display_);
if (!connector) {
@@ -581,7 +168,24 @@
return -ENOMEM;
}
+ if (crtc->out_fence_ptr_property().id() != 0) {
+ ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->out_fence_ptr_property().id(),
+ (uint64_t) &out_fences[crtc->pipe()]);
+ if (ret < 0) {
+ ALOGE("Failed to add OUT_FENCE_PTR property to pset: %d", ret);
+ drmModeAtomicFree(pset);
+ return ret;
+ }
+ }
+
if (mode_.needs_modeset) {
+ ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->active_property().id(), 1);
+ if (ret < 0) {
+ ALOGE("Failed to add crtc active to pset\n");
+ drmModeAtomicFree(pset);
+ return ret;
+ }
+
ret = drmModeAtomicAddProperty(pset, crtc->id(), crtc->mode_property().id(),
mode_.blob_id) < 0 ||
drmModeAtomicAddProperty(pset, connector->id(),
@@ -600,10 +204,11 @@
std::vector<size_t> &source_layers = comp_plane.source_layers();
int fb_id = -1;
- DrmHwcRect<int> display_frame;
- DrmHwcRect<float> source_crop;
+ int fence_fd = -1;
+ 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,30 +223,12 @@
break;
}
DrmHwcLayer &layer = layers[source_layers.front()];
- if (!test_only && layer.acquire_fence.get() >= 0) {
- int acquire_fence = layer.acquire_fence.get();
- int total_fence_timeout = 0;
- for (int i = 0; i < kAcquireWaitTries; ++i) {
- int fence_timeout = kAcquireWaitTimeoutMs * (1 << i);
- total_fence_timeout += fence_timeout;
- ret = sync_wait(acquire_fence, fence_timeout);
- if (ret)
- ALOGW("Acquire fence %d wait %d failed (%d). Total time %d",
- acquire_fence, i, ret, total_fence_timeout);
- else
- break;
- }
- if (ret) {
- ALOGE("Failed to wait for acquire %d/%d", acquire_fence, ret);
- break;
- }
- layer.acquire_fence.Close();
- }
if (!layer.buffer) {
ALOGE("Expected a valid framebuffer for pset");
break;
}
fb_id = layer.buffer->fb_id;
+ fence_fd = layer.acquire_fence.get();
display_frame = layer.display_frame;
source_crop = layer.source_crop;
if (layer.blending == DrmHwcBlending::kPreMult)
@@ -649,16 +236,32 @@
rotation = 0;
if (layer.transform & DrmHwcTransform::kFlipH)
- rotation |= 1 << DRM_REFLECT_X;
+ rotation |= DRM_MODE_REFLECT_X;
if (layer.transform & DrmHwcTransform::kFlipV)
- rotation |= 1 << DRM_REFLECT_Y;
+ rotation |= DRM_MODE_REFLECT_Y;
if (layer.transform & DrmHwcTransform::kRotate90)
- rotation |= 1 << DRM_ROTATE_90;
+ rotation |= DRM_MODE_ROTATE_90;
else if (layer.transform & DrmHwcTransform::kRotate180)
- rotation |= 1 << DRM_ROTATE_180;
+ rotation |= DRM_MODE_ROTATE_180;
else if (layer.transform & DrmHwcTransform::kRotate270)
- rotation |= 1 << DRM_ROTATE_270;
+ rotation |= DRM_MODE_ROTATE_270;
+ else
+ rotation |= DRM_MODE_ROTATE_0;
+
+ if (fence_fd >= 0) {
+ int prop_id = plane->in_fence_fd_property().id();
+ if (prop_id == 0) {
+ ALOGE("Failed to get IN_FENCE_FD property id");
+ break;
+ }
+ ret = drmModeAtomicAddProperty(pset, plane->id(), prop_id, fence_fd);
+ if (ret < 0) {
+ ALOGE("Failed to add IN_FENCE_FD property to pset: %d", ret);
+ break;
+ }
+ }
}
+
// Disable the plane if there's no framebuffer
if (fb_id < 0) {
ret = drmModeAtomicAddProperty(pset, plane->id(),
@@ -673,15 +276,15 @@
}
// TODO: Once we have atomic test, this should fall back to GL
- if (rotation && plane->rotation_property().id() == 0) {
- ALOGE("Rotation is not supported on plane %d", plane->id());
+ if (rotation != DRM_MODE_ROTATE_0 && plane->rotation_property().id() == 0) {
+ ALOGV("Rotation is not supported on plane %d", plane->id());
ret = -EINVAL;
break;
}
// TODO: Once we have atomic test, this should fall back to GL
- if (alpha != 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;
}
@@ -742,7 +345,6 @@
}
}
-out:
if (!ret) {
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
if (test_only)
@@ -750,9 +352,7 @@
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;
@@ -782,6 +382,10 @@
mode_.needs_modeset = false;
}
+ if (crtc->out_fence_ptr_property().id()) {
+ display_comp->set_out_fence((int) out_fences[crtc->pipe()]);
+ }
+
return ret;
}
@@ -820,15 +424,17 @@
}
void DrmDisplayCompositor::ClearDisplay() {
- std::lock_guard<std::mutex> lk(mutex_);
+ AutoLock lock(&lock_, "compositor");
+ int ret = lock.Lock();
+ if (ret)
+ return;
+
if (!active_composition_)
return;
if (DisablePlanes(active_composition_.get()))
return;
- active_composition_->SignalCompositionDone();
-
active_composition_.reset(NULL);
}
@@ -848,68 +454,41 @@
}
++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");
- std::lock_guard<std::mutex> lk(mutex_);
active_composition_.swap(composition);
+
+ if (!ret)
+ ret = pthread_mutex_unlock(&lock_);
+ if (ret)
+ ALOGE("Failed to release lock for active_composition swap");
}
-void DrmDisplayCompositor::ProcessWork(
+int DrmDisplayCompositor::ApplyComposition(
std::unique_ptr<DrmDisplayComposition> composition) {
- ATRACE_CALL();
-
- if (!pre_compositor_) {
- pre_compositor_.reset(new GLWorkerCompositor());
- int ret = pre_compositor_->Init();
- if (ret) {
- ALOGE("Failed to initialize OpenGL compositor %d", ret);
- return;
- }
- }
-
- int ret;
+ 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;
- }
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 queue 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();
- return;
+ if (ret) {
+ ALOGE("Commit test failed for display %d, FIXME", display_);
+ return ret;
}
}
- frame_worker_.QueueFrame(std::move(composition), ret);
+
+ ApplyFrame(std::move(composition), ret);
break;
case DRM_COMPOSITION_TYPE_DPMS:
+ active_ = (composition->dpms_mode() == DRM_MODE_DPMS_ON);
ret = ApplyDpms(composition.get());
if (ret)
ALOGE("Failed to apply dpms for display %d", display_);
- break;
+ return ret;
case DRM_COMPOSITION_TYPE_MODESET:
mode_.mode = composition->display_mode();
if (mode_.blob_id)
@@ -917,170 +496,34 @@
std::tie(ret, mode_.blob_id) = CreateModeBlob(mode_.mode);
if (ret) {
ALOGE("Failed to create mode blob for display %d", display_);
- return;
+ return ret;
}
mode_.needs_modeset = true;
- break;
+ return 0;
default:
ALOGE("Unknown composition type %d", composition->type());
- break;
+ return -EINVAL;
}
-}
-
-int DrmDisplayCompositor::SquashAll() {
- std::unique_lock<std::mutex> lk(mutex_);
- int ret;
-
- if (!active_composition_)
- return 0;
-
- std::unique_ptr<DrmDisplayComposition> comp = CreateComposition();
- ret = SquashFrame(active_composition_.get(), comp.get());
-
- // ApplyFrame needs the lock
- lk.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 {
- std::lock_guard<std::mutex> lk(mutex_);
+ int ret = pthread_mutex_lock(&lock_);
+ if (ret)
+ return;
+
uint64_t num_frames = dump_frames_composited_;
dump_frames_composited_ = 0;
struct timespec ts;
- int ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
if (ret) {
+ pthread_mutex_unlock(&lock_);
return;
}
@@ -1094,21 +537,6 @@
dump_last_timestamp_ns_ = cur_ts;
- *out << "----Jank Stats: "
- << " compositor_max_q_wait_us=" << max_duration_us
- << " frameworker_max_q_wait_us=" << frame_worker_.max_duration_us
- << "\n";
-
- max_duration_us = 0;
- frame_worker_.max_duration_us = 0;
-
- if (active_composition_)
- active_composition_->Dump(out);
-
- squash_state_.Dump(out);
-}
-
-void DrmDisplayCompositor::ProcessIdle() {
- SquashAll();
+ pthread_mutex_unlock(&lock_);
}
}
diff --git a/drmdisplaycompositor.h b/drmdisplaycompositor.h
index 961fe72..0d85949 100644
--- a/drmdisplaycompositor.h
+++ b/drmdisplaycompositor.h
@@ -17,15 +17,12 @@
#ifndef ANDROID_DRM_DISPLAY_COMPOSITOR_H_
#define ANDROID_DRM_DISPLAY_COMPOSITOR_H_
-#include "drmcomposition.h"
-#include "drmframebuffer.h"
#include "drmhwcomposer.h"
-#include "queue_worker.h"
-#include "separate_rects.h"
+#include "drmdisplaycomposition.h"
+#include "drmframebuffer.h"
-#include <chrono>
+#include <pthread.h>
#include <memory>
-#include <queue>
#include <sstream>
#include <tuple>
@@ -38,50 +35,7 @@
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 QueueWorker<DrmDisplayComposition> {
+class DrmDisplayCompositor {
public:
DrmDisplayCompositor();
~DrmDisplayCompositor();
@@ -89,45 +43,14 @@
int Init(DrmResources *drm, int display);
std::unique_ptr<DrmDisplayComposition> CreateComposition() const;
- int QueueComposition(std::unique_ptr<DrmDisplayComposition> composition);
- void ProcessWork(std::unique_ptr<DrmDisplayComposition> composition);
- void ProcessIdle();
- int SquashAll();
+ int ApplyComposition(std::unique_ptr<DrmDisplayComposition> composition);
+ int TestComposition(DrmDisplayComposition *composition);
+ int Composite();
void Dump(std::ostringstream *out) const;
std::tuple<uint32_t, uint32_t, int> GetActiveModeResolution();
- SquashState *squash_state() {
- return &squash_state_;
- }
-
private:
- struct FrameState {
- FrameState(std::unique_ptr<DrmDisplayComposition> composition, int status)
- : composition(std::move(composition)), status(status) {
- }
-
- std::unique_ptr<DrmDisplayComposition> composition;
- int status = 0;
- };
-
- class FrameWorker : public QueueWorker<FrameState> {
- public:
- FrameWorker(DrmDisplayCompositor *compositor);
-
- int Init();
- void QueueFrame(std::unique_ptr<DrmDisplayComposition> composition,
- int status);
-
- mutable uint64_t max_duration_us;
-
- protected:
- void ProcessWork(std::unique_ptr<FrameState> frame);
-
- private:
- DrmDisplayCompositor *compositor_;
- };
-
struct ModeState {
bool needs_modeset = false;
DrmMode mode;
@@ -144,11 +67,8 @@
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);
@@ -161,10 +81,9 @@
DrmResources *drm_;
int display_;
- FrameWorker frame_worker_;
-
std::unique_ptr<DrmDisplayComposition> active_composition_;
+ bool initialized_;
bool active_;
bool use_hw_overlays_;
@@ -172,20 +91,14 @@
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 HaveQueuedComposites
- mutable std::mutex mutex_;
+ // mutable since we need to acquire in Dump()
+ mutable pthread_mutex_t lock_;
// State tracking progress since our last Dump(). These are mutable since
// we need to reset them on every Dump() call.
mutable uint64_t dump_frames_composited_;
mutable uint64_t dump_last_timestamp_ns_;
- mutable uint64_t max_duration_us;
};
}
diff --git a/drmencoder.cpp b/drmencoder.cpp
index 1d4ebdc..3d762f3 100644
--- a/drmencoder.cpp
+++ b/drmencoder.cpp
@@ -27,7 +27,6 @@
const std::vector<DrmCrtc *> &possible_crtcs)
: id_(e->encoder_id),
crtc_(current_crtc),
- type_(e->encoder_type),
possible_crtcs_(possible_crtcs) {
}
diff --git a/drmencoder.h b/drmencoder.h
index ed3c21e..58ccbfb 100644
--- a/drmencoder.h
+++ b/drmencoder.h
@@ -45,8 +45,6 @@
uint32_t id_;
DrmCrtc *crtc_;
- uint32_t type_;
-
std::vector<DrmCrtc *> possible_crtcs_;
};
}
diff --git a/drmeventlistener.cpp b/drmeventlistener.cpp
index 7a21980..9cdff81 100644
--- a/drmeventlistener.cpp
+++ b/drmeventlistener.cpp
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-#include <assert.h>
-
#define LOG_TAG "hwc-drm-event-listener"
#include "drmeventlistener.h"
#include "drmresources.h"
+#include <assert.h>
+#include <errno.h>
#include <linux/netlink.h>
#include <sys/socket.h>
-#include <assert.h>
-#include <cutils/log.h>
+#include <log/log.h>
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
#include <xf86drm.h>
namespace android {
@@ -45,7 +46,7 @@
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/drmhwcgralloc.h b/drmhwcgralloc.h
index 765c897..759746a 100644
--- a/drmhwcgralloc.h
+++ b/drmhwcgralloc.h
@@ -19,43 +19,11 @@
#include <stdint.h>
-enum {
- /* perform(const struct gralloc_module_t *mod,
- * int op,
- * int drm_fd,
- * buffer_handle_t buffer,
- * struct hwc_drm_bo *bo);
- */
- GRALLOC_MODULE_PERFORM_DRM_IMPORT = 0xffeeff00,
-
- /* perform(const struct gralloc_module_t *mod,
- * int op,
- * buffer_handle_t buffer,
- * void (*free_callback)(void *),
- * void *priv);
- */
- GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE = 0xffeeff01,
-
- /* perform(const struct gralloc_module_t *mod,
- * int op,
- * buffer_handle_t buffer,
- * void (*free_callback)(void *),
- * void **priv);
- */
- GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE = 0xffeeff02,
-
- /* perform(const struct gralloc_module_t *mod,
- * int op,
- * buffer_handle_t buffer,
- * int *usage);
- */
- GRALLOC_MODULE_PERFORM_GET_USAGE = 0xffeeff03,
-};
-
typedef struct hwc_drm_bo {
uint32_t width;
uint32_t height;
uint32_t format; /* DRM_FORMAT_* from drm_fourcc.h */
+ uint32_t usage;
uint32_t pitches[4];
uint32_t offsets[4];
uint32_t gem_handles[4];
diff --git a/drmhwcomposer.h b/drmhwcomposer.h
index f8440fb..ab8f087 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 @@
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,13 @@
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, int width, int height,
+ int layerCount, int format, int usage, int stride);
void Clear();
@@ -112,13 +109,9 @@
}
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 +134,14 @@
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 8c853f4..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 @@
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 @@
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__);
}
@@ -242,7 +229,6 @@
HWC2::Error DrmHwcTwo::HwcDisplay::AcceptDisplayChanges() {
supported(__func__);
- uint32_t num_changes = 0;
for (std::pair<const hwc2_layer_t, DrmHwcTwo::HwcLayer> &l : layers_)
l.second.accept_type_change();
return HWC2::Error::None;
@@ -481,8 +467,7 @@
}
}
-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();
@@ -492,17 +477,23 @@
// 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;
@@ -511,21 +502,20 @@
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();
@@ -540,8 +530,7 @@
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;
@@ -557,18 +546,32 @@
i = overlay_planes.erase(i);
}
- ret = compositor_.QueueComposition(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;
+}
- // Now that the release fences have been generated by the compositor, make
- // sure they're managed properly
- for (std::pair<const uint32_t, DrmHwcTwo::HwcLayer *> &l : z_map) {
- l.second->manage_release_fence();
- AddFenceToRetireFence(l.second->release_fence());
+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
@@ -593,7 +596,7 @@
compositor_.CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_);
int ret = composition->SetDisplayMode(*mode);
- ret = compositor_.QueueComposition(std::move(composition));
+ ret = compositor_.ApplyComposition(std::move(composition));
if (ret) {
ALOGE("Failed to queue dpms composition on %d", ret);
return HWC2::Error::BadConfig;
@@ -619,7 +622,7 @@
HWC2::Error DrmHwcTwo::HwcDisplay::SetClientTarget(buffer_handle_t target,
int32_t acquire_fence,
int32_t dataspace,
- hwc_region_t damage) {
+ hwc_region_t /*damage*/) {
supported(__func__);
UniqueFd uf(acquire_fence);
@@ -673,7 +676,7 @@
compositor_.CreateComposition();
composition->Init(drm_, crtc_, importer_.get(), planner_.get(), frame_no_);
composition->SetDpmsMode(dpms_value);
- int ret = compositor_.QueueComposition(std::move(composition));
+ int ret = compositor_.ApplyComposition(std::move(composition));
if (ret) {
ALOGE("Failed to apply the dpms composition ret=%d", ret);
return HWC2::Error::BadParameter;
@@ -690,23 +693,57 @@
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:
+ default:
layer.set_validated_type(HWC2::Composition::Client);
++*num_types;
break;
- default:
- layer.set_validated_type(layer.sf_type());
- break;
}
}
- return HWC2::Error::None;
+ return *num_types ? HWC2::Error::HasChanges : HWC2::Error::None;
}
HWC2::Error DrmHwcTwo::HwcLayer::SetCursorPosition(int32_t x, int32_t y) {
@@ -829,7 +866,7 @@
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 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 @@
}
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 @@
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 c4ea722..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 {
@@ -126,6 +126,10 @@
if (ret)
ALOGI("Could not get alpha property");
+ ret = drm_->GetPlaneProperty(*this, "IN_FENCE_FD", &in_fence_fd_property_);
+ if (ret)
+ ALOGI("Could not get IN_FENCE_FD property");
+
return 0;
}
@@ -188,4 +192,8 @@
const DrmProperty &DrmPlane::alpha_property() const {
return alpha_property_;
}
+
+const DrmProperty &DrmPlane::in_fence_fd_property() const {
+ return in_fence_fd_property_;
+}
}
diff --git a/drmplane.h b/drmplane.h
index 2e06986..5b73b08 100644
--- a/drmplane.h
+++ b/drmplane.h
@@ -54,6 +54,7 @@
const DrmProperty &src_h_property() const;
const DrmProperty &rotation_property() const;
const DrmProperty &alpha_property() const;
+ const DrmProperty &in_fence_fd_property() const;
private:
DrmResources *drm_;
@@ -75,6 +76,7 @@
DrmProperty src_h_property_;
DrmProperty rotation_property_;
DrmProperty alpha_property_;
+ DrmProperty in_fence_fd_property_;
};
}
diff --git a/drmresources.cpp b/drmresources.cpp
index 6b8ed03..ec6664c 100644
--- a/drmresources.cpp
+++ b/drmresources.cpp
@@ -30,12 +30,12 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <cutils/properties.h>
namespace android {
-DrmResources::DrmResources() : compositor_(this), event_listener_(this) {
+DrmResources::DrmResources() : event_listener_(this) {
}
DrmResources::~DrmResources() {
@@ -154,16 +154,28 @@
break;
}
- if (conn->built_in() && !found_primary) {
+ connectors_.emplace_back(std::move(conn));
+ }
+
+ // First look for primary amongst internal connectors
+ for (auto &conn : connectors_) {
+ if (conn->internal() && !found_primary) {
conn->set_display(0);
found_primary = true;
} else {
conn->set_display(display_num);
++display_num;
}
-
- connectors_.emplace_back(std::move(conn));
}
+
+ // Then look for primary amongst external connectors
+ for (auto &conn : connectors_) {
+ if (conn->external() && !found_primary) {
+ conn->set_display(0);
+ found_primary = true;
+ }
+ }
+
if (res)
drmModeFreeResources(res);
@@ -201,10 +213,6 @@
if (ret)
return ret;
- ret = compositor_.Init();
- if (ret)
- return ret;
-
ret = event_listener_.Init();
if (ret) {
ALOGE("Can't initialize event listener %d", ret);
@@ -245,6 +253,10 @@
return NULL;
}
+const std::vector<std::unique_ptr<DrmCrtc>> & DrmResources::crtcs() const {
+ return crtcs_;
+}
+
uint32_t DrmResources::next_mode_id() {
return ++mode_id_;
}
@@ -333,54 +345,6 @@
return 0;
}
-int DrmResources::SetDisplayActiveMode(int display, const DrmMode &mode) {
- std::unique_ptr<DrmComposition> comp(compositor_.CreateComposition(NULL));
- if (!comp) {
- ALOGE("Failed to create composition for dpms on %d", display);
- return -ENOMEM;
- }
- int ret = comp->SetDisplayMode(display, mode);
- if (ret) {
- ALOGE("Failed to add mode to composition on %d %d", display, ret);
- return ret;
- }
- ret = compositor_.QueueComposition(std::move(comp));
- if (ret) {
- ALOGE("Failed to queue dpms composition on %d %d", display, ret);
- return ret;
- }
- return 0;
-}
-
-int DrmResources::SetDpmsMode(int display, uint64_t mode) {
- if (mode != DRM_MODE_DPMS_ON && mode != DRM_MODE_DPMS_OFF) {
- ALOGE("Invalid dpms mode %" PRIu64, mode);
- return -EINVAL;
- }
-
- std::unique_ptr<DrmComposition> comp(compositor_.CreateComposition(NULL));
- if (!comp) {
- ALOGE("Failed to create composition for dpms on %d", display);
- return -ENOMEM;
- }
- int ret = comp->SetDpmsMode(display, mode);
- if (ret) {
- ALOGE("Failed to add dpms %" PRIu64 " to composition on %d %d", mode,
- display, ret);
- return ret;
- }
- ret = compositor_.QueueComposition(std::move(comp));
- if (ret) {
- ALOGE("Failed to queue dpms composition on %d %d", display, ret);
- return ret;
- }
- return 0;
-}
-
-DrmCompositor *DrmResources::compositor() {
- return &compositor_;
-}
-
DrmEventListener *DrmResources::event_listener() {
return &event_listener_;
}
diff --git a/drmresources.h b/drmresources.h
index 011f87e..4cca48c 100644
--- a/drmresources.h
+++ b/drmresources.h
@@ -17,7 +17,6 @@
#ifndef ANDROID_DRM_H_
#define ANDROID_DRM_H_
-#include "drmcompositor.h"
#include "drmconnector.h"
#include "drmcrtc.h"
#include "drmencoder.h"
@@ -58,7 +57,6 @@
DrmConnector *GetConnectorForDisplay(int display) const;
DrmCrtc *GetCrtcForDisplay(int display) const;
DrmPlane *GetPlane(uint32_t id) const;
- DrmCompositor *compositor();
DrmEventListener *event_listener();
int GetPlaneProperty(const DrmPlane &plane, const char *prop_name,
@@ -68,9 +66,8 @@
int GetConnectorProperty(const DrmConnector &connector, const char *prop_name,
DrmProperty *property);
+ const std::vector<std::unique_ptr<DrmCrtc>> &crtcs() const;
uint32_t next_mode_id();
- int SetDisplayActiveMode(int display, const DrmMode &mode);
- int SetDpmsMode(int display, uint64_t mode);
int CreatePropertyBlob(void *data, size_t length, uint32_t *blob_id);
int DestroyPropertyBlob(uint32_t blob_id);
@@ -89,7 +86,6 @@
std::vector<std::unique_ptr<DrmEncoder>> encoders_;
std::vector<std::unique_ptr<DrmCrtc>> crtcs_;
std::vector<std::unique_ptr<DrmPlane>> planes_;
- DrmCompositor compositor_;
DrmEventListener event_listener_;
std::pair<uint32_t, uint32_t> min_resolution_;
diff --git a/glworker.cpp b/glworker.cpp
deleted file mode 100644
index e12995e..0000000
--- a/glworker.cpp
+++ /dev/null
@@ -1,799 +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;
-}
-
-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;
- EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
- 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;
- }
-
- if (!eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, egl_ctx_)) {
- ALOGE("Failed to make the OpenGL ES Context current: %s", GetEGLError());
- return 1;
- }
-
- 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));
- 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;
- }
-
- 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");
- 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)
- 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);
-
- 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 158490c..0000000
--- a/glworker.h
+++ /dev/null
@@ -1,84 +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();
- };
-
- 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 875056d..0000000
--- a/hwcomposer.cpp
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#define LOG_TAG "hwcomposer-drm"
-
-#include "drmhwcomposer.h"
-#include "drmeventlistener.h"
-#include "drmresources.h"
-#include "platform.h"
-#include "virtualcompositorworker.h"
-#include "vsyncworker.h"
-
-#include <stdlib.h>
-
-#include <cinttypes>
-#include <map>
-#include <vector>
-#include <sstream>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <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 0091575..be70a39 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,21 @@
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, int width,
+ int height, int layerCount,
+ int format, int usage, int stride) {
+ native_handle_t *handle_copy;
+ GraphicBufferMapper &gm(GraphicBufferMapper::get());
+ int ret =
+ gm.importBuffer(handle, width, height, layerCount, format, usage,
+ stride, 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,68 +84,40 @@
}
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);
+ const hwc_drm_bo *bo = buffer.operator->();
+
+ // FIXME: Add layerCount and a pixel stride to the hwc_drm_bo
+ ret = handle.CopyBufferHandle(sf_handle, bo->width, bo->height,
+ 1, bo->format, bo->usage, bo->width);
if (ret)
return ret;
- ret = gralloc->perform(gralloc, GRALLOC_MODULE_PERFORM_GET_USAGE,
- handle.get(), &gralloc_buffer_usage);
- if (ret) {
- ALOGE("Failed to get usage for buffer %p (%d)", handle.get(), ret);
- return ret;
- }
+ gralloc_buffer_usage = bo->usage;
+
return 0;
}
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 e920872..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::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 @@
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 @@
}
}
- if (squash_plane)
- composition.emplace_back(DrmCompositionPlane::Type::kSquash, squash_plane,
- crtc);
-
return std::make_tuple(0, std::move(composition));
}
@@ -109,62 +81,6 @@
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 @@
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;
}
}
diff --git a/platform.h b/platform.h
index e417bf7..068499e 100644
--- a/platform.h
+++ b/platform.h
@@ -38,10 +38,6 @@
// 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 @@
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 @@
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 @@
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 aa3d0fa..7c4758d 100644
--- a/platformdrmgeneric.cpp
+++ b/platformdrmgeneric.cpp
@@ -24,10 +24,9 @@
#include <xf86drm.h>
#include <xf86drmMode.h>
-#include <cutils/log.h>
-#include <gralloc_drm_handle.h>
+#include <log/log.h>
+#include <gralloc_handle.h>
#include <hardware/gralloc.h>
-#include <EGL/eglext.h>
namespace android {
@@ -84,24 +83,8 @@
}
}
-EGLImageKHR DrmGenericImporter::ImportImage(EGLDisplay egl_display, buffer_handle_t handle) {
- gralloc_drm_handle_t *gr_handle = gralloc_drm_handle(handle);
- if (!gr_handle)
- return NULL;
- EGLint attr[] = {
- EGL_WIDTH, gr_handle->width,
- EGL_HEIGHT, 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, 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_drm_handle_t *gr_handle = gralloc_drm_handle(handle);
+ gralloc_handle_t *gr_handle = gralloc_handle(handle);
if (!gr_handle)
return -EINVAL;
@@ -116,6 +99,7 @@
bo->width = gr_handle->width;
bo->height = gr_handle->height;
bo->format = ConvertHalFormatToDrm(gr_handle->format);
+ bo->usage = gr_handle->usage;
bo->pitches[0] = gr_handle->stride;
bo->gem_handles[0] = gem_handle;
bo->offsets[0] = 0;
@@ -144,10 +128,14 @@
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 8376580..0339e1e 100644
--- a/platformdrmgeneric.h
+++ b/platformdrmgeneric.h
@@ -31,12 +31,11 @@
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:
uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
+ private:
DrmResources *drm_;
diff --git a/platformhisi.cpp b/platformhisi.cpp
new file mode 100644
index 0000000..d4428d0
--- /dev/null
+++ b/platformhisi.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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-platform-hisi"
+
+#include "drmresources.h"
+#include "platform.h"
+#include "platformhisi.h"
+
+
+#include <drm/drm_fourcc.h>
+#include <cinttypes>
+#include <stdatomic.h>
+#include <xf86drm.h>
+#include <xf86drmMode.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 {
+
+Importer *Importer::CreateInstance(DrmResources *drm) {
+ HisiImporter *importer = new HisiImporter(drm);
+ if (!importer)
+ return NULL;
+
+ int ret = importer->Init();
+ if (ret) {
+ ALOGE("Failed to initialize the hisi importer %d", ret);
+ delete importer;
+ return NULL;
+ }
+ return importer;
+}
+
+HisiImporter::HisiImporter(DrmResources *drm) : DrmGenericImporter(drm), drm_(drm) {
+}
+
+HisiImporter::~HisiImporter() {
+}
+
+int HisiImporter::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, "ARM Ltd."))
+ ALOGW("Using non-ARM gralloc module: %s/%s\n", gralloc_->common.name,
+ gralloc_->common.author);
+
+ return 0;
+}
+
+int HisiImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
+ private_handle_t const *hnd =
+ reinterpret_cast<private_handle_t const *>(handle);
+ if (!hnd)
+ return -EINVAL;
+
+ uint32_t gem_handle;
+ int ret = drmPrimeFDToHandle(drm_->fd(), hnd->share_fd, &gem_handle);
+ if (ret) {
+ ALOGE("failed to import prime fd %d ret=%d", hnd->share_fd, ret);
+ return ret;
+ }
+
+ int32_t fmt = ConvertHalFormatToDrm(hnd->req_format);
+ if (fmt < 0)
+ 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) {
+ 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/platformhisi.h b/platformhisi.h
new file mode 100644
index 0000000..a098692
--- /dev/null
+++ b/platformhisi.h
@@ -0,0 +1,47 @@
+/*
+ * 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_HISI_H_
+#define ANDROID_PLATFORM_HISI_H_
+
+#include "drmresources.h"
+#include "platform.h"
+#include "platformdrmgeneric.h"
+
+#include <stdatomic.h>
+
+#include <hardware/gralloc.h>
+
+namespace android {
+
+class HisiImporter : public DrmGenericImporter {
+ public:
+ HisiImporter(DrmResources *drm);
+ ~HisiImporter() 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/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.cpp b/platformnv.cpp
deleted file mode 100644
index e7b6be3..0000000
--- a/platformnv.cpp
+++ /dev/null
@@ -1,374 +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-platform-nv"
-
-#include "drmresources.h"
-#include "platform.h"
-#include "platformnv.h"
-
-#include <cinttypes>
-#include <stdatomic.h>
-#include <drm/drm_fourcc.h>
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#include <cutils/log.h>
-#include <hardware/gralloc.h>
-
-#ifndef EGL_NATIVE_HANDLE_ANDROID_NVX
-#define EGL_NATIVE_HANDLE_ANDROID_NVX 0x322A
-#endif
-
-namespace android {
-
-#ifdef USE_NVIDIA_IMPORTER
-// static
-Importer *Importer::CreateInstance(DrmResources *drm) {
- NvImporter *importer = new NvImporter(drm);
- if (!importer)
- return NULL;
-
- int ret = importer->Init();
- if (ret) {
- ALOGE("Failed to initialize the nv importer %d", ret);
- delete importer;
- return NULL;
- }
- return importer;
-}
-#endif
-
-NvImporter::NvImporter(DrmResources *drm) : drm_(drm) {
-}
-
-NvImporter::~NvImporter() {
-}
-
-int NvImporter::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, "NVIDIA"))
- ALOGW("Using non-NVIDIA gralloc module: %s/%s\n", gralloc_->common.name,
- gralloc_->common.author);
-
- return 0;
-}
-
-
-EGLImageKHR NvImporter::ImportImage(EGLDisplay egl_display, buffer_handle_t handle) {
- return eglCreateImageKHR(
- egl_display, EGL_NO_CONTEXT, EGL_NATIVE_HANDLE_ANDROID_NVX,
- (EGLClientBuffer)handle, NULL /* no attribs */);
-}
-
-int NvImporter::ImportBuffer(buffer_handle_t handle, hwc_drm_bo_t *bo) {
- memset(bo, 0, sizeof(hwc_drm_bo_t));
- NvBuffer_t *buf = GrallocGetNvBuffer(handle);
- if (buf) {
- atomic_fetch_add(&buf->ref, 1);
- *bo = buf->bo;
- return 0;
- }
-
- buf = new NvBuffer_t();
- if (!buf) {
- ALOGE("Failed to allocate new NvBuffer_t");
- return -ENOMEM;
- }
- buf->bo.priv = buf;
- buf->importer = this;
-
- // We initialize the reference count to 2 since NvGralloc is still using this
- // buffer (will be cleared in the NvGrallocRelease), and the other
- // reference is for HWC (this ImportBuffer call).
- atomic_init(&buf->ref, 2);
-
- int ret = gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_DRM_IMPORT,
- drm_->fd(), handle, &buf->bo);
- if (ret) {
- ALOGE("GRALLOC_MODULE_PERFORM_DRM_IMPORT failed %d", ret);
- delete buf;
- return ret;
- }
-
- ret = drmModeAddFB2(drm_->fd(), buf->bo.width, buf->bo.height, buf->bo.format,
- buf->bo.gem_handles, buf->bo.pitches, buf->bo.offsets,
- &buf->bo.fb_id, 0);
- if (ret) {
- ALOGE("Failed to add fb %d", ret);
- ReleaseBufferImpl(&buf->bo);
- delete buf;
- return ret;
- }
-
- ret = GrallocSetNvBuffer(handle, buf);
- if (ret) {
- /* This will happen is persist.tegra.gpu_mapping_cache is 0/off,
- * or if NV gralloc runs out of "priv slots" (currently 3 per buffer,
- * only one of which should be used by drm_hwcomposer). */
- ALOGE("Failed to register free callback for imported buffer %d", ret);
- ReleaseBufferImpl(&buf->bo);
- delete buf;
- return ret;
- }
- *bo = buf->bo;
- return 0;
-}
-
-int NvImporter::ReleaseBuffer(hwc_drm_bo_t *bo) {
- NvBuffer_t *buf = (NvBuffer_t *)bo->priv;
- if (!buf) {
- ALOGE("Freeing bo %" PRIu32 ", buf is NULL!", bo->fb_id);
- return 0;
- }
- if (atomic_fetch_sub(&buf->ref, 1) > 1)
- return 0;
-
- ReleaseBufferImpl(bo);
- delete buf;
- return 0;
-}
-
-// static
-void NvImporter::NvGrallocRelease(void *nv_buffer) {
- NvBuffer_t *buf = (NvBuffer *)nv_buffer;
- buf->importer->ReleaseBuffer(&buf->bo);
-}
-
-void NvImporter::ReleaseBufferImpl(hwc_drm_bo_t *bo) {
- if (bo->fb_id) {
- int ret = drmModeRmFB(drm_->fd(), bo->fb_id);
- if (ret)
- ALOGE("Failed to rm fb %d", ret);
- }
-
- struct drm_gem_close gem_close;
- memset(&gem_close, 0, sizeof(gem_close));
- int num_gem_handles = sizeof(bo->gem_handles) / sizeof(bo->gem_handles[0]);
- for (int i = 0; i < num_gem_handles; i++) {
- if (!bo->gem_handles[i])
- continue;
-
- gem_close.handle = bo->gem_handles[i];
- int ret = drmIoctl(drm_->fd(), DRM_IOCTL_GEM_CLOSE, &gem_close);
- if (ret) {
- ALOGE("Failed to close gem handle %d %d", i, ret);
- } else {
- /* Clear any duplicate gem handle as well but don't close again */
- 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;
- }
- }
-}
-
-NvImporter::NvBuffer_t *NvImporter::GrallocGetNvBuffer(buffer_handle_t handle) {
- void *priv = NULL;
- int ret =
- gralloc_->perform(gralloc_, GRALLOC_MODULE_PERFORM_GET_IMPORTER_PRIVATE,
- handle, NvGrallocRelease, &priv);
- return ret ? NULL : (NvBuffer_t *)priv;
-}
-
-int NvImporter::GrallocSetNvBuffer(buffer_handle_t handle, NvBuffer_t *buf) {
- return gralloc_->perform(gralloc_,
- GRALLOC_MODULE_PERFORM_SET_IMPORTER_PRIVATE, handle,
- NvGrallocRelease, buf);
-}
-
-#ifdef USE_NVIDIA_IMPORTER
-// static
-std::unique_ptr<Planner> Planner::CreateInstance(DrmResources *) {
- std::unique_ptr<Planner> planner(new Planner);
- planner->AddStage<PlanStageNvLimits>();
- planner->AddStage<PlanStageProtectedRotated>();
- planner->AddStage<PlanStageProtected>();
- planner->AddStage<PlanStagePrecomp>();
- planner->AddStage<PlanStageGreedy>();
- return planner;
-}
-#endif
-
-static DrmPlane *GetCrtcPrimaryPlane(DrmCrtc *crtc,
- std::vector<DrmPlane *> *planes) {
- for (auto i = planes->begin(); i != planes->end(); ++i) {
- if ((*i)->GetCrtcSupported(*crtc)) {
- DrmPlane *plane = *i;
- planes->erase(i);
- return plane;
- }
- }
- return NULL;
-}
-
-int PlanStageProtectedRotated::ProvisionPlanes(
- std::vector<DrmCompositionPlane> *composition,
- std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
- std::vector<DrmPlane *> *planes) {
- int ret;
- int protected_zorder = -1;
- for (auto i = layers.begin(); i != layers.end();) {
- if (!i->second->protected_usage() || !i->second->transform) {
- ++i;
- continue;
- }
-
- auto primary_iter = planes->begin();
- for (; primary_iter != planes->end(); ++primary_iter) {
- if ((*primary_iter)->type() == DRM_PLANE_TYPE_PRIMARY)
- break;
- }
-
- // We cheat a little here. Since there can only be one primary plane per
- // crtc, we know we'll only hit this case once. So we blindly insert the
- // protected content at the beginning of the composition, knowing this path
- // won't be taken a second time during the loop.
- if (primary_iter != planes->end()) {
- composition->emplace(composition->begin(),
- DrmCompositionPlane::Type::kLayer, *primary_iter,
- crtc, i->first);
- planes->erase(primary_iter);
- protected_zorder = i->first;
- } else {
- ALOGE("Could not provision primary plane for protected/rotated layer");
- }
- i = layers.erase(i);
- }
-
- if (protected_zorder == -1)
- return 0;
-
- // Add any layers below the protected content to the precomposition since we
- // need to punch a hole through them.
- for (auto i = layers.begin(); i != layers.end();) {
- // Skip layers above the z-order of the protected content
- if (i->first > static_cast<size_t>(protected_zorder)) {
- ++i;
- continue;
- }
-
- // If there's no precomp layer already queued, queue one now.
- DrmCompositionPlane *precomp = GetPrecomp(composition);
- if (precomp) {
- precomp->source_layers().emplace_back(i->first);
- } else {
- if (planes->size()) {
- DrmPlane *precomp_plane = planes->back();
- planes->pop_back();
- composition->emplace_back(DrmCompositionPlane::Type::kPrecomp,
- precomp_plane, crtc, i->first);
- } else {
- ALOGE("Not enough planes to reserve for precomp fb");
- }
- }
- i = layers.erase(i);
- }
- return 0;
-}
-
-bool PlanStageNvLimits::CheckLayer(size_t zorder, DrmHwcLayer *layer) {
- auto src_w = layer->source_crop.width();
- auto src_h = layer->source_crop.height();
- auto dst_w = layer->display_frame.width();
- auto dst_h = layer->display_frame.height();
- int h_limit = 4;
- int v_limit;
-
- switch (layer->buffer->format) {
- case DRM_FORMAT_ARGB8888:
- case DRM_FORMAT_ABGR8888:
- case DRM_FORMAT_XBGR8888:
- case DRM_FORMAT_XRGB8888:
- // tegra driver assumes any layer with alpha channel has premult
- // blending, avoid handling it this is not the case. This is not an
- // issue for bottom-most layer since there's nothing to blend with
- if (zorder > 0 && layer->blending != DrmHwcBlending::kPreMult)
- return false;
-
- v_limit = 2;
- break;
- case DRM_FORMAT_YVU420:
- case DRM_FORMAT_YUV420:
- case DRM_FORMAT_YUV422:
- case DRM_FORMAT_UYVY:
- case DRM_FORMAT_YUYV:
- case DRM_FORMAT_NV12:
- case DRM_FORMAT_NV21:
- case DRM_FORMAT_RGB565:
- case DRM_FORMAT_BGR565:
- v_limit = 4;
- break;
- default:
- v_limit = 2;
- break;
- }
-
- if (layer->transform &
- (DrmHwcTransform::kRotate90 | DrmHwcTransform::kRotate270))
- std::swap(dst_w, dst_h);
-
- // check for max supported down scaling
- if (((src_w / dst_w) > h_limit) || ((src_h / dst_h) > v_limit))
- return false;
-
- return true;
-}
-
-int PlanStageNvLimits::ProvisionPlanes(
- std::vector<DrmCompositionPlane> *composition,
- std::map<size_t, DrmHwcLayer *> &layers, DrmCrtc *crtc,
- std::vector<DrmPlane *> *planes) {
- int ret;
-
- for (auto i = layers.begin(); i != layers.end();) {
- // Skip layer if supported
- if (CheckLayer(i->first, i->second)) {
- i++;
- continue;
- }
-
- if (i->second->protected_usage()) {
- // Drop the layer if unsupported and protected, this will just display
- // black in the area of this layer but it's better than failing miserably
- i = layers.erase(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;
-}
-}
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/queue_worker.h b/queue_worker.h
deleted file mode 100644
index 7e96eec..0000000
--- a/queue_worker.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_QUEUE_WORKER_H_
-#define ANDROID_QUEUE_WORKER_H_
-
-#include "worker.h"
-
-#include <queue>
-
-namespace android {
-
-template <typename T>
-class QueueWorker : public Worker {
- public:
- static const size_t kDefaultMaxQueueSize = 2;
- static const int64_t kTimeoutDisabled = -1;
-
- QueueWorker(const char *name, int priority)
- : Worker(name, priority),
- max_queue_size_(kDefaultMaxQueueSize),
- queue_timeout_ms_(kTimeoutDisabled),
- idle_timeout_ms_(kTimeoutDisabled),
- idled_out_(false) {
- }
-
- int QueueWork(std::unique_ptr<T> workitem);
-
- bool IsWorkPending() const {
- return !queue_.empty();
- }
- bool idle() const {
- return idled_out_;
- }
-
- int64_t idle_timeout() {
- return idle_timeout_ms_;
- }
- void set_idle_timeout(int64_t timeout_ms) {
- idle_timeout_ms_ = timeout_ms;
- }
-
- int64_t queue_timeout() {
- return queue_timeout_ms_;
- }
- void set_queue_timeout(int64_t timeout_ms) {
- queue_timeout_ms_ = timeout_ms;
- }
-
- size_t max_queue_size() const {
- return max_queue_size_;
- }
- void set_max_queue_size(size_t size) {
- max_queue_size_ = size;
- }
-
- protected:
- virtual void ProcessWork(std::unique_ptr<T> workitem) = 0;
- virtual void ProcessIdle(){}
- virtual void Routine();
-
- template <typename Predicate>
- int WaitCond(std::unique_lock<std::mutex> &lock, Predicate pred,
- int64_t max_msecs);
-
- private:
- std::queue<std::unique_ptr<T>> queue_;
- size_t max_queue_size_;
- int64_t queue_timeout_ms_;
- int64_t idle_timeout_ms_;
- bool idled_out_;
-};
-
-template <typename T>
-template <typename Predicate>
-int QueueWorker<T>::WaitCond(std::unique_lock<std::mutex> &lock, Predicate pred,
- int64_t max_msecs) {
- bool ret = true;
- auto wait_func = [&] { return pred() || should_exit(); };
-
- if (max_msecs < 0) {
- cond_.wait(lock, wait_func);
- } else {
- auto timeout = std::chrono::milliseconds(max_msecs);
- ret = cond_.wait_for(lock, timeout, wait_func);
- }
-
- if (!ret)
- return -ETIMEDOUT;
- else if (should_exit())
- return -EINTR;
-
- return 0;
-}
-
-template <typename T>
-void QueueWorker<T>::Routine() {
- std::unique_lock<std::mutex> lk(mutex_);
- std::unique_ptr<T> workitem;
-
- auto wait_func = [&] { return !queue_.empty(); };
- int ret =
- WaitCond(lk, wait_func, idled_out_ ? kTimeoutDisabled : idle_timeout_ms_);
- switch (ret) {
- case 0:
- break;
- case -ETIMEDOUT:
- ProcessIdle();
- idled_out_ = true;
- return;
- case -EINTR:
- default:
- return;
- }
-
- if (!queue_.empty()) {
- workitem = std::move(queue_.front());
- queue_.pop();
- }
- lk.unlock();
- cond_.notify_all();
-
- idled_out_ = false;
- ProcessWork(std::move(workitem));
-}
-
-template <typename T>
-int QueueWorker<T>::QueueWork(std::unique_ptr<T> workitem) {
- std::unique_lock<std::mutex> lk(mutex_);
-
- auto wait_func = [&] { return queue_.size() < max_queue_size_; };
- int ret = WaitCond(lk, wait_func, queue_timeout_ms_);
- if (ret)
- return ret;
-
- queue_.push(std::move(workitem));
- lk.unlock();
-
- cond_.notify_one();
-
- return 0;
-}
-};
-#endif
diff --git a/separate_rects.cpp b/separate_rects.cpp
deleted file mode 100644
index 9fd1ae4..0000000
--- a/separate_rects.cpp
+++ /dev/null
@@ -1,416 +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
-
-#ifdef RECTS_TEST
-
-using namespace separate_rects;
-
-int main(int argc, char **argv) {
-#define RectSet RectSet<TId, TNum>
-#define Rect Rect<TNum>
-#define IdSet IdSet<TId>
- typedef uint64_t TId;
- typedef float TNum;
-
- 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_rects(in, &out);
- }
-
- for (int i = 0; i < out.size(); i++) {
- std::cout << out[i].id_set << "(" << out[i].rect << ")" << std::endl;
- }
-
- std::cout << "# of rects: " << out.size() << std::endl;
-
- 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)));
-
- for (int i = 0; i < expected_out.size(); i++) {
- RectSet &ex_out = expected_out[i];
- if (std::find(out.begin(), out.end(), ex_out) == out.end()) {
- std::cout << "Missing Rect: " << ex_out.id_set << "(" << ex_out.rect
- << ")" << std::endl;
- }
- }
-
- for (int 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()) {
- std::cout << "Extra Rect: " << actual_out.id_set << "(" << actual_out.rect
- << ")" << std::endl;
- }
- }
-
- return 0;
-}
-
-#endif
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 b86cca6..b498d62 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -3,11 +3,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- queue_worker_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
include $(BUILD_NATIVE_TEST)
diff --git a/tests/queue_worker_test.cpp b/tests/queue_worker_test.cpp
deleted file mode 100644
index d1c0470..0000000
--- a/tests/queue_worker_test.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-#include <gtest/gtest.h>
-#include <hardware/hardware.h>
-
-#include <chrono>
-#include <mutex>
-
-#include "queue_worker.h"
-
-using android::QueueWorker;
-
-#define UNUSED_ARG(x) (void)(x)
-
-struct TestData {
- TestData(int val) : value(val) {
- }
- virtual ~TestData() {
- }
-
- virtual void CheckValue(int prev_value) {
- ASSERT_EQ(prev_value + 1, value);
- }
-
- int value;
-};
-
-struct TestQueueWorker : public QueueWorker<TestData> {
- TestQueueWorker()
- : QueueWorker("test-queueworker", HAL_PRIORITY_URGENT_DISPLAY), value(0) {
- }
-
- int Init() {
- return InitWorker();
- }
-
- void ProcessWork(std::unique_ptr<TestData> data) {
- std::lock_guard<std::mutex> blk(block);
- data->CheckValue(value);
- {
- std::lock_guard<std::mutex> lk(lock);
- value = data->value;
- }
- cond.notify_one();
- }
-
- void ProcessIdle() {
- ASSERT_FALSE(idle());
- }
-
- std::mutex lock;
- std::mutex block;
- std::condition_variable cond;
- int value;
-};
-
-struct QueueWorkerTest : public testing::Test {
- static const int kTimeoutMs = 1000;
- TestQueueWorker qw;
-
- virtual void SetUp() {
- qw.Init();
- }
- bool QueueValue(int val) {
- std::unique_ptr<TestData> data(new TestData(val));
- return !qw.QueueWork(std::move(data));
- }
-
- bool WaitFor(int val, int timeout_ms = kTimeoutMs) {
- std::unique_lock<std::mutex> lk(qw.lock);
-
- auto timeout = std::chrono::milliseconds(timeout_ms);
- return qw.cond.wait_for(lk, timeout, [&] { return qw.value == val; });
- }
-};
-
-struct IdleQueueWorkerTest : public QueueWorkerTest {
- const int64_t kIdleTimeoutMs = 100;
-
- virtual void SetUp() {
- qw.set_idle_timeout(kIdleTimeoutMs);
- qw.Init();
- }
-};
-
-TEST_F(QueueWorkerTest, single_queue) {
- // already isInitialized so should fail
- ASSERT_NE(qw.Init(), 0);
-
- ASSERT_EQ(qw.value, 0);
- ASSERT_TRUE(QueueValue(1));
- ASSERT_TRUE(WaitFor(1));
- ASSERT_EQ(qw.value, 1);
- ASSERT_FALSE(qw.IsWorkPending());
-}
-
-TEST_F(QueueWorkerTest, multiple_waits) {
- for (int i = 1; i <= 100; i++) {
- ASSERT_TRUE(QueueValue(i));
- ASSERT_TRUE(WaitFor(i));
- ASSERT_EQ(qw.value, i);
- ASSERT_FALSE(qw.IsWorkPending());
- }
-}
-
-TEST_F(QueueWorkerTest, multiple_queue) {
- for (int i = 1; i <= 100; i++) {
- ASSERT_TRUE(QueueValue(i));
- }
- ASSERT_TRUE(WaitFor(100));
- ASSERT_EQ(qw.value, 100);
- ASSERT_FALSE(qw.IsWorkPending());
-}
-
-TEST_F(QueueWorkerTest, blocking) {
- // First wait for inital value to be setup
- ASSERT_TRUE(QueueValue(1));
- ASSERT_TRUE(WaitFor(1));
-
- // Block processing and fill up the queue
- std::unique_lock<std::mutex> lk(qw.block);
- size_t expected_value = qw.max_queue_size() + 2;
- for (size_t i = 2; i <= expected_value; i++) {
- ASSERT_TRUE(QueueValue(i));
- }
-
- qw.set_queue_timeout(100);
- // any additional queueing should fail
- ASSERT_FALSE(QueueValue(expected_value + 1));
-
- // make sure value is not changed while blocked
- {
- std::unique_lock<std::mutex> lock(qw.lock);
- auto timeout = std::chrono::milliseconds(100);
- ASSERT_FALSE(
- qw.cond.wait_for(lock, timeout, [&] { return qw.value != 1; }));
- }
- ASSERT_EQ(qw.value, 1);
- ASSERT_TRUE(qw.IsWorkPending());
-
- // unblock and wait for value to be reached
- lk.unlock();
- ASSERT_TRUE(WaitFor(expected_value));
- ASSERT_FALSE(qw.IsWorkPending());
-}
-
-TEST_F(QueueWorkerTest, exit_slow) {
- struct SlowData : public TestData {
- SlowData(int val) : TestData(val) {
- }
- void CheckValue(int prev_value) {
- UNUSED_ARG(prev_value);
-
- std::this_thread::sleep_for(std::chrono::milliseconds(100));
- }
- };
- std::unique_ptr<SlowData> data(new SlowData(1));
- ASSERT_EQ(qw.QueueWork(std::move(data)), 0);
- data = std::unique_ptr<SlowData>(new SlowData(2));
- ASSERT_EQ(qw.QueueWork(std::move(data)), 0);
- qw.Exit();
- ASSERT_FALSE(qw.initialized());
-}
-
-TEST_F(QueueWorkerTest, exit_empty) {
- qw.Exit();
- ASSERT_FALSE(qw.initialized());
-}
-
-TEST_F(QueueWorkerTest, queue_worker_noidling) {
- ASSERT_TRUE(QueueValue(1));
- ASSERT_TRUE(WaitFor(1));
-
- ASSERT_FALSE(qw.idle());
- auto timeout = std::chrono::milliseconds(200);
- std::this_thread::sleep_for(timeout);
- ASSERT_FALSE(qw.idle());
-}
-
-TEST_F(IdleQueueWorkerTest, queue_worker_idling) {
- ASSERT_TRUE(QueueValue(1));
- ASSERT_TRUE(WaitFor(1));
- ASSERT_FALSE(qw.idle());
-
- auto timeout = std::chrono::milliseconds(kIdleTimeoutMs + 10);
- std::this_thread::sleep_for(timeout);
- ASSERT_TRUE(qw.idle());
- ASSERT_TRUE(QueueValue(2));
- ASSERT_TRUE(WaitFor(2));
- ASSERT_FALSE(qw.idle());
-
- std::this_thread::sleep_for(3 * timeout);
- ASSERT_TRUE(qw.idle());
-
- ASSERT_TRUE(QueueValue(3));
- ASSERT_TRUE(WaitFor(3));
- for (int i = 4; i <= 100; i++) {
- QueueValue(i);
- }
- ASSERT_FALSE(qw.idle());
- qw.Exit();
- ASSERT_FALSE(qw.initialized());
-}
\ No newline at end of file
diff --git a/tests/worker_test.cpp b/tests/worker_test.cpp
index 38f91db..82523f0 100644
--- a/tests/worker_test.cpp
+++ b/tests/worker_test.cpp
@@ -66,7 +66,7 @@
};
TEST_F(WorkerTest, test_worker) {
- // already isInitialized so should fail
+ // already isInitialized so should succeed
ASSERT_TRUE(worker.initialized());
int val = worker.value;
diff --git a/virtualcompositorworker.cpp b/virtualcompositorworker.cpp
deleted file mode 100644
index c1a6d2f..0000000
--- a/virtualcompositorworker.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2015-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "hwc-virtual-compositor-worker"
-
-#include "virtualcompositorworker.h"
-
-#include <cutils/log.h>
-#include <sw_sync.h>
-#include <sync/sync.h>
-
-namespace android {
-
-static const int kMaxQueueDepth = 3;
-static const int kAcquireWaitTimeoutMs = 3000;
-
-VirtualCompositorWorker::VirtualCompositorWorker()
- : QueueWorker("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;
-
- set_max_queue_size(kMaxQueueDepth);
- 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_;
-
- QueueWork(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::ProcessWork(
- 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 885cf31..0000000
--- a/virtualcompositorworker.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2015-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_VIRTUAL_COMPOSITOR_WORKER_H_
-#define ANDROID_VIRTUAL_COMPOSITOR_WORKER_H_
-
-#include "drmhwcomposer.h"
-#include "queue_worker.h"
-
-namespace android {
-
-struct VirtualComposition {
- UniqueFd outbuf_acquire_fence;
- std::vector<UniqueFd> layer_acquire_fences;
- int release_timeline;
-};
-
-class VirtualCompositorWorker : public QueueWorker<VirtualComposition> {
- public:
- VirtualCompositorWorker();
- ~VirtualCompositorWorker() override;
-
- int Init();
- void QueueComposite(hwc_display_contents_1_t *dc);
-
- protected:
- void ProcessWork(std::unique_ptr<VirtualComposition> composition);
-
- private:
- int CreateNextTimelineFence();
- int FinishComposition(int timeline);
-
- int timeline_fd_;
- int timeline_;
- int timeline_current_;
-};
-}
-
-#endif
diff --git a/vsyncworker.cpp b/vsyncworker.cpp
index 2177521..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 @@
: Worker("vsync", HAL_PRIORITY_URGENT_DISPLAY),
drm_(NULL),
display_(-1),
+ enabled_(false),
last_timestamp_(-1) {
}
@@ -119,6 +120,7 @@
if (!enabled_) {
ret = WaitForSignalOrExitLocked();
if (ret == -EINTR) {
+ Unlock();
return;
}
}
@@ -126,7 +128,6 @@
bool enabled = enabled_;
int display = display_;
std::shared_ptr<VsyncCallback> callback(callback_);
-
Unlock();
if (!enabled)