summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew F. Davis <afd@ti.com>2018-10-19 13:35:29 -0700
committerandroid-build-merger <android-build-merger@google.com>2018-10-19 13:35:29 -0700
commiteb5b7bae36257a0ac9085388ea8a8bed2a4b2393 (patch)
tree624db8896f88f8680bb2e8a1e100497230716b65
parent86a022aa92b8f174df250113f4717737b9edfd25 (diff)
parent8eaa2bfcd5a0abbd52051f14de0c0e200e98175b (diff)
downloadam57x-eb5b7bae36257a0ac9085388ea8a8bed2a4b2393.tar.gz
libhwcomposer: Add initial support
am: 8eaa2bfcd5 Change-Id: I0187bfe064c899c14051aa332fd03ce2fb757919
-rw-r--r--libhwcomposer/Android.bp44
-rw-r--r--libhwcomposer/NOTICE203
-rw-r--r--libhwcomposer/display.cpp273
-rw-r--r--libhwcomposer/display.h126
-rw-r--r--libhwcomposer/drmfb.cpp100
-rw-r--r--libhwcomposer/drmfb.h35
-rw-r--r--libhwcomposer/format.cpp152
-rw-r--r--libhwcomposer/format.h63
-rw-r--r--libhwcomposer/hal_public.h245
-rw-r--r--libhwcomposer/hwc.cpp724
-rw-r--r--libhwcomposer/hwc_dev.h57
11 files changed, 2022 insertions, 0 deletions
diff --git a/libhwcomposer/Android.bp b/libhwcomposer/Android.bp
new file mode 100644
index 0000000..384e7e2
--- /dev/null
+++ b/libhwcomposer/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+//
+// 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.
+
+cc_library_shared {
+ name: "hwcomposer.am57x",
+
+ vendor: true,
+ relative_install_path: "hw",
+
+ srcs: [
+ "display.cpp",
+ "drmfb.cpp",
+ "format.cpp",
+ "hwc.cpp",
+ ],
+
+ cflags: [
+ "-DLOG_TAG=\"ti_hwc\"",
+ "-Wno-unused-parameter",
+ "-Wno-missing-field-initializers",
+ "-fexceptions",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libhardware",
+ "libhardware_legacy",
+ "libdrm",
+ "libkmsxx",
+ ],
+}
diff --git a/libhwcomposer/NOTICE b/libhwcomposer/NOTICE
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/libhwcomposer/NOTICE
@@ -0,0 +1,203 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/libhwcomposer/display.cpp b/libhwcomposer/display.cpp
new file mode 100644
index 0000000..f881a84
--- /dev/null
+++ b/libhwcomposer/display.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <algorithm>
+
+#include <cstdint>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#include "display.h"
+#include "format.h"
+#include "hwc_dev.h"
+
+HWCDisplay::HWCDisplay(enum disp_role role) :
+ active_config(0),
+ role(role),
+ cb_procs(NULL),
+ is_dummy(false),
+ vsync_on(false),
+ blanked(true),
+ is_flip_pending(false)
+{
+}
+
+void HWCDisplay::setup_composition_pipes()
+{
+ std::unique_lock<std::mutex> lock(this->mutex);
+
+ KMSDisplay* kdisp = &this->disp_link;
+
+ int count = 0;
+ for (auto plane : kdisp->card->get_planes()) {
+ auto possible_crtcs = plane->get_possible_crtcs();
+ if (std::find(possible_crtcs.begin(), possible_crtcs.end(), kdisp->crtc) != possible_crtcs.end()) {
+ planeProps[count].plane = plane;
+ ALOGI("Overlay %d: plane_id: %d", count, planeProps[count].plane->id());
+ count++;
+ }
+ }
+}
+
+/* Page flip handler callback */
+void HWCDisplay::page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data)
+{
+ HWCDisplay* display = static_cast<HWCDisplay*>(data);
+
+ std::unique_lock<std::mutex> lock(display->mutex);
+
+ if (display->is_flip_pending == false) {
+ ALOGW("Spurious page flip?");
+ return;
+ }
+
+ /* release the old buffers */
+ for (auto current_fb_info : display->current_fb_infos)
+ delete current_fb_info;
+ display->current_fb_infos.clear();
+
+ /* pending are now current */
+ for (auto pending_fb_info : display->pending_fb_infos)
+ display->current_fb_infos.push_back(pending_fb_info);
+ display->pending_fb_infos.clear();
+
+ display->is_flip_pending = false;
+ lock.unlock();
+ display->cond_flip.notify_one();
+}
+
+static int vblank_kick(HWCDisplay* display)
+{
+ drmVBlank vblank;
+ memset(&vblank, 0, sizeof(vblank));
+ vblank.request.type = (drmVBlankSeqType)(DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT |
+ display->role == DISP_ROLE_SECONDARY ? DRM_VBLANK_SECONDARY : 0);
+ vblank.request.sequence = 1;
+ vblank.request.signal = (unsigned long)display;
+ int err = drmWaitVBlank(display->disp_link.card->fd(), &vblank);
+ if (err < 0) {
+ /* FIXME: error in drmWaitVBlank() use SW vsync instead? */
+ ALOGE("drmWaitVBlank error %d (%s)", err, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Callback function that gets triggered on vsync */
+void HWCDisplay::vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data)
+{
+ HWCDisplay* display = static_cast<HWCDisplay*>(data);
+
+ std::unique_lock<std::mutex> lock(display->mutex);
+
+ if (display->vsync_on) {
+ int64_t ts = sec * (int64_t)1000000000 + usec * (int64_t)1000;
+
+// ALOGD("Sending VBLANK at %lld for display %d", ts, display->role);
+ display->cb_procs->vsync(display->cb_procs, display->role, ts);
+
+ vblank_kick(display);
+ }
+}
+
+int HWCDisplay::set_vsync_state(bool state)
+{
+ std::unique_lock<std::mutex> lock(this->mutex);
+
+ if (this->is_dummy)
+ return 0;
+
+ this->vsync_on = state;
+
+ if (this->vsync_on)
+ return vblank_kick(this);
+
+ return 0;
+}
+
+static void set_plane_properties(kms::AtomicReq& req, drm_plane_props_t* plane_props)
+{
+ kms::Plane* plane = plane_props->plane;
+
+ req.add(plane, "FB_ID", plane_props->fb_info->fb_id);
+
+ req.add(plane, "IN_FENCE_FD", plane_props->layer->acquireFenceFd);
+
+ req.add(plane, {
+ { "CRTC_ID", plane_props->crtc_id },
+ { "SRC_X", (plane_props->src_x) << 16 },
+ { "SRC_Y", (plane_props->src_y) << 16 },
+ { "SRC_W", (plane_props->src_w) << 16 },
+ { "SRC_H", (plane_props->src_h) << 16 },
+ { "CRTC_X", plane_props->crtc_x },
+ { "CRTC_Y", plane_props->crtc_y },
+ { "CRTC_W", plane_props->crtc_w },
+ { "CRTC_H", plane_props->crtc_h },
+ });
+
+ /* optional props */
+ req.add(plane, {
+ { "zorder", plane_props->zorder },
+ { "pre_mult_alpha", plane_props->pre_mult_alpha },
+ });
+}
+
+int HWCDisplay::update_display(drm_plane_props_t* planeProp)
+{
+ std::unique_lock<std::mutex> lock(this->mutex);
+
+ this->cond_flip.wait(lock, [this]{return !this->is_flip_pending;});
+
+ buffer_handle_t handle = planeProp->layer->handle;
+ if (!handle) {
+ ALOGW("Got empty handle, nothing to display");
+ return 0;
+ }
+
+ KMSDisplay* kdisp = &this->disp_link;
+
+ planeProp->fb_info = new DRMFramebuffer(kdisp->card->fd(), handle, false);
+ this->pending_fb_infos.push_back(planeProp->fb_info);
+
+ planeProp->crtc_id = kdisp->crtc->id();
+
+ // Atomic display update
+ kms::AtomicReq req(*kdisp->card);
+ set_plane_properties(req, planeProp);
+ int ret = req.commit(this, true);
+ if (ret) {
+ ALOGE("cannot do atomic commit/page flip: %d (%s)", ret, strerror(errno));
+ for (auto pending_fb_info : this->pending_fb_infos)
+ delete pending_fb_info;
+ this->pending_fb_infos.clear();
+ return ret;
+ }
+
+// ALOGD("Scheduled page flip on display %d", this->role);
+ this->is_flip_pending = true;
+
+ return 0;
+}
+
+void HWCDisplay::blank(int blank)
+{
+ std::unique_lock<std::mutex> lock(this->mutex);
+
+ if (this->is_dummy)
+ return;
+
+ KMSDisplay* kdisp = &this->disp_link;
+
+ ALOGI("Linking connector %d to crtc %d", kdisp->con->id(), kdisp->crtc->id());
+
+ int ret = kdisp->crtc->set_mode(kdisp->con, kdisp->mode);
+ if (ret) {
+ ALOGE("Failed to set crtc mode (%s)", strerror(-ret));
+ return;
+ }
+
+ // FIXME: This should actually blank the screen
+ this->blanked = blank;
+}
+
+int HWCDisplay::get_display_configs(uint32_t* configs, size_t* numConfigs)
+{
+ if (!configs || !numConfigs)
+ return -EINVAL;
+
+ if (*numConfigs == 0)
+ return 0;
+
+ std::unique_lock<std::mutex> lock(this->mutex);
+
+ size_t num = this->configs.size();
+ if (num > *numConfigs)
+ num = *numConfigs;
+
+ for (size_t i = 0; i < num; i++)
+ configs[i] = i;
+
+ *numConfigs = num;
+
+ return 0;
+}
+
+int HWCDisplay::get_display_attributes(uint32_t cfg, const uint32_t* attributes, int32_t* values)
+{
+ if (!attributes || !values)
+ return 0;
+
+ std::unique_lock<std::mutex> lock(this->mutex);
+
+ if (cfg >= this->configs.size())
+ return -EINVAL;
+
+ display_config_t* config = &this->configs[cfg];
+
+ for (size_t i = 0; attributes[i] != HWC_DISPLAY_NO_ATTRIBUTE; i++) {
+ switch (attributes[i]) {
+ case HWC_DISPLAY_VSYNC_PERIOD:
+ values[i] = 1000000000 / config->fps;
+ break;
+ case HWC_DISPLAY_WIDTH:
+ values[i] = config->xres;
+ break;
+ case HWC_DISPLAY_HEIGHT:
+ values[i] = config->yres;
+ break;
+ case HWC_DISPLAY_DPI_X:
+ values[i] = 1000 * config->xdpi;
+ break;
+ case HWC_DISPLAY_DPI_Y:
+ values[i] = 1000 * config->ydpi;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/libhwcomposer/display.h b/libhwcomposer/display.h
new file mode 100644
index 0000000..5df923f
--- /dev/null
+++ b/libhwcomposer/display.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <condition_variable>
+#include <mutex>
+
+#include <cstdbool>
+#include <cstdint>
+
+#include <hardware/hwcomposer.h>
+#include <kms++/kms++.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "drmfb.h"
+
+#define MAX_DISPLAYS 4
+#define DSS_AVAILABLE_PIPES 4
+
+typedef struct display_config {
+ unsigned int xres;
+ unsigned int yres;
+ unsigned int fps;
+ unsigned int xdpi;
+ unsigned int ydpi;
+} display_config_t;
+
+enum disp_role {
+ DISP_ROLE_PRIMARY = 0,
+ DISP_ROLE_SECONDARY,
+};
+
+typedef struct drm_plane_props {
+ hwc_layer_1_t* layer;
+
+ kms::Plane* plane;
+ uint64_t crtc_id;
+
+ uint64_t crtc_x;
+ uint64_t crtc_y;
+ uint64_t crtc_w;
+ uint64_t crtc_h;
+ uint64_t src_x;
+ uint64_t src_y;
+ uint64_t src_w;
+ uint64_t src_h;
+
+ uint64_t rotation;
+ uint64_t zorder;
+ uint64_t pre_mult_alpha;
+
+ DRMFramebuffer* fb_info;
+} drm_plane_props_t;
+
+class KMSDisplay {
+public:
+ KMSDisplay() :
+ card(NULL),
+ con(NULL),
+ crtc(NULL),
+ mode() {}
+
+ kms::Card* card;
+ kms::Connector* con;
+ kms::Crtc* crtc;
+ kms::Videomode mode;
+};
+
+class HWCDisplay
+{
+public:
+ HWCDisplay(enum disp_role role);
+ ~HWCDisplay(){};
+
+ void setup_composition_pipes();
+
+ int update_display(drm_plane_props_t* planeProp);
+
+ std::vector<display_config_t> configs;
+ uint32_t active_config;
+
+ enum disp_role role;
+
+ drm_plane_props_t planeProps[DSS_AVAILABLE_PIPES];
+
+ KMSDisplay disp_link;
+
+ const hwc_procs_t* cb_procs;
+
+ bool is_dummy;
+
+ int set_vsync_state(bool state);
+ void blank(int blank);
+ int get_display_configs(uint32_t* configs, size_t* numConfigs);
+ int get_display_attributes(uint32_t cfg, const uint32_t* attributes, int32_t* values);
+
+ static void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data);
+ static void vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void* data);
+
+private:
+ std::vector<DRMFramebuffer*> pending_fb_infos;
+ std::vector<DRMFramebuffer*> current_fb_infos;
+
+ bool vsync_on;
+ bool blanked;
+
+ std::mutex mutex;
+ std::condition_variable cond_flip;
+ volatile bool is_flip_pending;
+};
diff --git a/libhwcomposer/drmfb.cpp b/libhwcomposer/drmfb.cpp
new file mode 100644
index 0000000..04c41dd
--- /dev/null
+++ b/libhwcomposer/drmfb.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <cutils/log.h>
+#include <drm/drm_fourcc.h>
+#include <hardware/hwcomposer.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "drmfb.h"
+#include "format.h"
+#include "hal_public.h"
+
+DRMFramebuffer::DRMFramebuffer(int drm_fd, buffer_handle_t handle, bool is_overlay) :
+ bo(), pitches(), offsets()
+{
+ if (!handle)
+ return;
+
+ uint32_t gem_handle;
+ IMG_native_handle_t* img_hnd = (IMG_native_handle_t*)handle;
+ int ret = drmPrimeFDToHandle(drm_fd, img_hnd->fd[0], &gem_handle);
+ if (ret) {
+ ALOGE("Failed to get DRM buffer object from handle");
+ return;
+ }
+
+ this->width = img_hnd->iWidth;
+ this->height = img_hnd->iHeight;
+ this->format = convert_hal_to_drm_format(img_hnd->iFormat, true);
+ this->bo[0] = gem_handle;
+ this->pitches[0] = ALIGN(img_hnd->iWidth, HW_ALIGN) * get_format_bpp(img_hnd->iFormat) >> 3;
+ this->offsets[0] = 0;
+ this->drm_fd = drm_fd;
+
+ if (is_overlay) {
+ switch (this->format) {
+ case DRM_FORMAT_NV12:
+ this->bo[1] = gem_handle;
+
+ this->pitches[0] = ALIGN(img_hnd->iWidth, HW_ALIGN);
+ this->pitches[1] = this->pitches[0];
+
+ this->offsets[1] = this->pitches[0] * img_hnd->iHeight;
+ break;
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XRGB8888:
+ case DRM_FORMAT_RGB565:
+ break;
+ default:
+ ALOGE("Bad format for overlay");
+ return;
+ }
+ }
+
+ ret = drmModeAddFB2(drm_fd, this->width, this->height,
+ this->format, this->bo,
+ this->pitches, this->offsets,
+ &this->fb_id, 0);
+ if (ret) {
+ ALOGE("Could not create DRM frame buffer %d", ret);
+ return;
+ }
+}
+
+DRMFramebuffer::~DRMFramebuffer()
+{
+ if (this->fb_id) {
+ if (drmModeRmFB(this->drm_fd, this->fb_id))
+ ALOGE("Failed to remove DRM frame buffer");
+ }
+
+ for (size_t i = 0; i < 4; i++) {
+ if (this->bo[i]) {
+ struct drm_gem_close close_args = {
+ close_args.handle = this->bo[i],
+ close_args.pad = 0,
+ };
+ int ret = drmIoctl(this->drm_fd, DRM_IOCTL_GEM_CLOSE, &close_args);
+ if (ret) {
+ ALOGE("Failed to close GEM handle");
+ return;
+ }
+ }
+ }
+}
diff --git a/libhwcomposer/drmfb.h b/libhwcomposer/drmfb.h
new file mode 100644
index 0000000..1efff0d
--- /dev/null
+++ b/libhwcomposer/drmfb.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+class DRMFramebuffer
+{
+ public:
+ DRMFramebuffer(int drm_fd, buffer_handle_t handle, bool is_overlay);
+ ~DRMFramebuffer();
+
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t bo[4];
+ uint32_t pitches[4];
+ uint32_t offsets[4];
+ uint32_t fb_id;
+ int drm_fd;
+};
diff --git a/libhwcomposer/format.cpp b/libhwcomposer/format.cpp
new file mode 100644
index 0000000..7f39203
--- /dev/null
+++ b/libhwcomposer/format.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <cstdint>
+
+#include <cutils/log.h>
+
+#include <linux/types.h>
+
+#include "format.h"
+#include "hal_public.h"
+
+bool is_valid_format(uint32_t format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return true;
+
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return true;
+
+ case HAL_PIXEL_FORMAT_NV12:
+ return true;
+
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ return true;
+
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ case HAL_PIXEL_FORMAT_TI_NV12_1D:
+ /* legacy formats not supported anymore */
+ return false;
+
+ default:
+ return false;
+ }
+}
+
+bool is_rgb_format(uint32_t format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool is_bgr_format(uint32_t format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool is_nv12_format(uint32_t format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ case HAL_PIXEL_FORMAT_TI_NV12_1D:
+ case HAL_PIXEL_FORMAT_NV12:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool is_opaque_format(uint32_t format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_RGB_565:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ return true;
+ default:
+ return false;
+ }
+}
+
+uint32_t get_format_bpp(uint32_t format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return 32;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return 16;
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ case HAL_PIXEL_FORMAT_TI_NV12_1D:
+ case HAL_PIXEL_FORMAT_NV12:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+uint32_t convert_hal_to_drm_format(uint32_t hal_format, bool blended)
+{
+ uint32_t dss_format = HAL_PIXEL_FORMAT_RGBA_8888;
+
+ /* convert color format */
+ switch (hal_format) {
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ dss_format = DRM_FORMAT_ARGB8888;
+ if (blended)
+ break;
+
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ case HAL_PIXEL_FORMAT_BGRX_8888:
+ dss_format = DRM_FORMAT_XRGB8888;
+ break;
+
+ case HAL_PIXEL_FORMAT_RGB_565:
+ dss_format = DRM_FORMAT_RGB565;
+ break;
+
+ case HAL_PIXEL_FORMAT_TI_NV12:
+ case HAL_PIXEL_FORMAT_TI_NV12_1D:
+ case HAL_PIXEL_FORMAT_NV12:
+ dss_format = DRM_FORMAT_NV12;
+ break;
+
+ default:
+ /* Should have been filtered out */
+ ALOGV("Unsupported pixel format");
+ }
+
+ return dss_format;
+}
diff --git a/libhwcomposer/format.h b/libhwcomposer/format.h
new file mode 100644
index 0000000..731c53a
--- /dev/null
+++ b/libhwcomposer/format.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <cstdint>
+
+#include <drm/drm_fourcc.h>
+#include <linux/types.h>
+
+#include "hal_public.h"
+
+static inline std::string HAL_FMT(uint32_t format)
+{
+ switch (format) {
+ case HAL_PIXEL_FORMAT_TI_NV12: return "NV12";
+ case HAL_PIXEL_FORMAT_TI_NV12_1D: return "NV12";
+ case HAL_PIXEL_FORMAT_YV12: return "YV12";
+ case HAL_PIXEL_FORMAT_BGRX_8888: return "xRGB32";
+ case HAL_PIXEL_FORMAT_RGBX_8888: return "xBGR32";
+ case HAL_PIXEL_FORMAT_BGRA_8888: return "ARGB32";
+ case HAL_PIXEL_FORMAT_RGBA_8888: return "ABGR32";
+ case HAL_PIXEL_FORMAT_RGB_565: return "RGB565";
+ default: return "??";
+ }
+}
+
+static inline std::string DRM_FMT(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_NV12: return "NV12";
+ case DRM_FORMAT_XRGB8888: return "xRGB32";
+ case DRM_FORMAT_ARGB8888: return "ARGB32";
+ case DRM_FORMAT_RGB565: return "RGB565";
+ default: return "??";
+ }
+}
+
+bool is_valid_format(uint32_t format);
+bool is_rgb_format(uint32_t format);
+bool is_bgr_format(uint32_t format);
+bool is_nv12_format(uint32_t format);
+bool is_opaque_format(uint32_t format);
+uint32_t get_format_bpp(uint32_t format);
+uint32_t convert_hal_to_dss_format(uint32_t format, bool blended);
+uint32_t convert_hal_to_drm_format(uint32_t hal_format, bool blended);
+uint32_t convert_hal_to_ocd_format(uint32_t hal_format);
+uint32_t get_stride_from_format(uint32_t format, uint32_t width);
diff --git a/libhwcomposer/hal_public.h b/libhwcomposer/hal_public.h
new file mode 100644
index 0000000..5ca9bd2
--- /dev/null
+++ b/libhwcomposer/hal_public.h
@@ -0,0 +1,245 @@
+/* Copyright (c) Imagination Technologies Ltd.
+ *
+ * The contents of this file are subject to the MIT license as set out below.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef HAL_PUBLIC_H
+#define HAL_PUBLIC_H
+
+/* Authors of third party hardware composer (HWC) modules will need to include
+ * this header to access functionality in the gralloc and framebuffer HALs.
+ */
+
+#include <hardware/gralloc.h>
+#include <hardware/memtrack.h>
+
+#define ALIGN(x,a) (((x) + (a) - 1L) & ~((a) - 1L))
+#define HW_ALIGN 16
+
+/* This can be tuned down as appropriate for the SOC.
+ *
+ * IMG formats are usually a single sub-alloc.
+ * Some OEM video formats are two sub-allocs (Y, UV planes).
+ * Future OEM video formats might be three sub-allocs (Y, U, V planes).
+ */
+#define MAX_SUB_ALLOCS 3
+
+/* Format is not YCbCr (e.g. a RGB format) - bIsYUVFormat should be false */
+#define YUV_CHROMA_ORDER_NONE 0
+/* Cb follows Y */
+#define YUV_CHROMA_ORDER_CBCR_UV 1
+/* Cr follows Y */
+#define YUV_CHROMA_ORDER_CRCB_VU 2
+
+typedef struct
+{
+ native_handle_t base;
+
+ /* These fields can be sent cross process. They are also valid
+ * to duplicate within the same process.
+ *
+ * A table is stored within psPrivateData on gralloc_module_t (this
+ * is obviously per-process) which maps stamps to a mapped
+ * PVRSRV_CLIENT_MEM_INFO in that process. Each map entry has a lock
+ * count associated with it, satisfying the requirements of the
+ * Android API. This also prevents us from leaking maps/allocations.
+ *
+ * This table has entries inserted either by alloc()
+ * (alloc_device_t) or map() (gralloc_module_t). Entries are removed
+ * by free() (alloc_device_t) and unmap() (gralloc_module_t).
+ *
+ * As a special case for framebuffer_device_t, framebuffer_open()
+ * will add and framebuffer_close() will remove from this table.
+ */
+
+#define IMG_NATIVE_HANDLE_NUMFDS MAX_SUB_ALLOCS
+ /* The `fd' field is used to "export" a meminfo to another process.
+ * Therefore, it is allocated by alloc_device_t, and consumed by
+ * gralloc_module_t. The framebuffer_device_t does not need a handle,
+ * and the special value IMG_FRAMEBUFFER_FD is used instead.
+ */
+ int fd[MAX_SUB_ALLOCS];
+
+#define IMG_NATIVE_HANDLE_NUMINTS \
+ ((sizeof(unsigned long long) / sizeof(int)) + 5 + MAX_SUB_ALLOCS + 1 + MAX_SUB_ALLOCS + MAX_SUB_ALLOCS)
+ /* A KERNEL unique identifier for any exported kernel meminfo. Each
+ * exported kernel meminfo will have a unique stamp, but note that in
+ * userspace, several meminfos across multiple processes could have
+ * the same stamp. As the native_handle can be dup(2)'d, there could be
+ * multiple handles with the same stamp but different file descriptors.
+ */
+ unsigned long long ui64Stamp;
+
+ /* This is used for buffer usage validation when locking a buffer,
+ * and also in WSEGL (for the composition bypass feature).
+ */
+ int usage;
+
+ /* In order to do efficient cache flushes we need the buffer dimensions
+ * and format. These are available on the ANativeWindowBuffer,
+ * but the platform doesn't pass them down to the graphics HAL.
+ */
+ int iWidth;
+ int iHeight;
+ int iFormat;
+ unsigned int uiBpp;
+
+ /* The ion allocation path doesn't allow for the allocation size and
+ * mapping flags to be communicated cross-process automatically.
+ * Cache these here so we can map buffers in client processes.
+ */
+ unsigned int uiAllocSize[MAX_SUB_ALLOCS];
+ unsigned int uiFlags;
+ /* For multi-planar allocations, there will be multiple hstrides */
+ int aiStride[MAX_SUB_ALLOCS];
+
+ /* For multi-planar allocations, there will be multiple vstrides */
+ int aiVStride[MAX_SUB_ALLOCS];
+
+}
+__attribute__((aligned(sizeof(int)),packed)) IMG_native_handle_t;
+
+typedef struct
+{
+ int l, t, w, h;
+}
+IMG_write_lock_rect_t;
+
+typedef int (*IMG_buffer_format_compute_params_pfn)(
+ unsigned int uiPlane, int *piWidth, int *piHeight,
+ int *piStride, int *piVStride, unsigned long *pulPlaneOffset);
+
+typedef struct IMG_buffer_format_public_t
+{
+ /* Buffer formats are returned as a linked list */
+ struct IMG_buffer_format_public_t *psNext;
+
+ /* HAL_PIXEL_FORMAT_... enumerant */
+ int iHalPixelFormat;
+
+ /* WSEGL_PIXELFORMAT_... enumerant */
+ int iWSEGLPixelFormat;
+
+ /* Friendly name for format */
+ const char *const szName;
+
+ /* Bits (not bytes) per pixel */
+ unsigned int uiBpp;
+
+ /* Supported HW usage bits. If this is GRALLOC_USAGE_HW_MASK, all usages
+ * are supported. Used for HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED.
+ */
+ int iSupportedUsage;
+
+ /* YUV output format */
+ int bIsYUVFormat;
+
+ /* YCBCR_ORDERING_* defined the order of the Cb/Cr values */
+ int eYUVChromaOrder;
+
+ /* Utility function for adjusting YUV per-plane parameters */
+ IMG_buffer_format_compute_params_pfn pfnComputeParams;
+}
+IMG_buffer_format_public_t;
+
+typedef struct
+{
+ /* Base memtrack record, copied to caller */
+ struct memtrack_record base;
+
+ /* Record type, for filtering cached records */
+ enum memtrack_type eType;
+
+ /* Process ID, for filtering cached records */
+ pid_t pid;
+}
+IMG_memtrack_record_public_t;
+
+typedef struct IMG_gralloc_module_public_t
+{
+ gralloc_module_t base;
+
+ /* This function is deprecated and might be NULL. Do not use it. */
+ int (*GetPhyAddrs)(gralloc_module_t const* module,
+ buffer_handle_t handle, void **ppvPhyAddr);
+
+ /* Obtain HAL's registered format list */
+ const IMG_buffer_format_public_t *(*GetBufferFormats)(void);
+
+ int (*GetImplementationFormat) (struct IMG_gralloc_module_public_t const *psGrallocModule, int usage);
+
+ int (*GetMemTrackRecords)(struct IMG_gralloc_module_public_t const *module,
+ IMG_memtrack_record_public_t **ppsRecords,
+ size_t *puNumRecords);
+
+ /* Custom-blit components in lieu of overlay hardware */
+ int (*Blit)(struct IMG_gralloc_module_public_t const *module,
+ buffer_handle_t src,
+ void *dest[MAX_SUB_ALLOCS], int format);
+
+ int (*Blit2)(struct IMG_gralloc_module_public_t const *module,
+ buffer_handle_t src, buffer_handle_t dest,
+ int w, int h, int x, int y);
+
+ int (*Blit3)(struct IMG_gralloc_module_public_t const *module,
+ unsigned long long ui64SrcStamp, int iSrcWidth,
+ int iSrcHeight, int iSrcFormat, int eSrcRotation,
+ buffer_handle_t dest, int eDestRotation);
+}
+IMG_gralloc_module_public_t;
+
+/**
+ * pixel format definitions
+ */
+
+enum {
+ /*
+ * 0x100 = 0x1FF
+ *
+ * This range is reserved for pixel formats that are specific to the HAL
+ * implementation. Implementations can use any value in this range to
+ * communicate video pixel formats between their HAL modules. These
+ * formats must not have an alpha channel. Additionally, an EGLimage
+ * created from a gralloc buffer of one of these formats must be
+ * supported for use with the GL_OES_EGL_image_external OpenGL ES
+ * extension.
+ */
+
+ /*
+ * These are vendor specific pixel format, by (informal) convention
+ * IMGTec formats start from the top of the range, TI formats start from
+ * the bottom
+ */
+ HAL_PIXEL_FORMAT_TI_NV12 = 0x100,
+ HAL_PIXEL_FORMAT_TI_UNUSED = 0x101,
+ HAL_PIXEL_FORMAT_TI_NV12_1D = 0x102,
+ HAL_PIXEL_FORMAT_TI_Y8 = 0x103,
+ HAL_PIXEL_FORMAT_TI_Y16 = 0x104,
+ HAL_PIXEL_FORMAT_TI_UYVY = 0x105,
+ HAL_PIXEL_FORMAT_BGRX_8888 = 0x1FF,
+
+ /* generic format missing from Android list, not specific to vendor
+ * implementation
+ */
+ HAL_PIXEL_FORMAT_NV12 = 0x3231564E, // FourCC for NV12
+};
+
+#endif /* HAL_PUBLIC_H */
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
new file mode 100644
index 0000000..b04c548
--- /dev/null
+++ b/libhwcomposer/hwc.cpp
@@ -0,0 +1,724 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 <sstream>
+
+#include <cutils/trace.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#define HWC_REMOVE_DEPRECATED_VERSIONS 1
+#include <hardware/hardware.h>
+#include <hardware/hwcomposer.h>
+#include <hardware_legacy/uevent.h>
+
+#include <kms++/kms++.h>
+
+#include "display.h"
+#include "format.h"
+#include "hwc_dev.h"
+
+#define LCD_DISPLAY_DEFAULT_HRES 1920
+#define LCD_DISPLAY_DEFAULT_VRES 1080
+#define LCD_DISPLAY_DEFAULT_FPS 60
+
+#define LCD_DISPLAY_DEFAULT_DPI 120
+#define HDMI_DISPLAY_DEFAULT_DPI 75
+
+#define HWC_PRIORITY_LOW_DISPLAY (19)
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+#endif
+
+#define WIDTH(rect) ((rect).right - (rect).left)
+#define HEIGHT(rect) ((rect).bottom - (rect).top)
+
+static bool is_valid_display(omap_hwc_device_t* hwc_dev, int disp)
+{
+ if (disp < 0 || disp >= MAX_DISPLAYS || !hwc_dev->displays[disp])
+ return false;
+
+ return true;
+}
+
+struct drm_connector_type {
+ int type;
+ char name[64];
+};
+
+#define CONNECTOR_TYPE_STR(type) { DRM_MODE_CONNECTOR_ ## type, #type }
+
+static const struct drm_connector_type connector_type_list[] = {
+ CONNECTOR_TYPE_STR(Unknown),
+ CONNECTOR_TYPE_STR(VGA),
+ CONNECTOR_TYPE_STR(DVII),
+ CONNECTOR_TYPE_STR(DVID),
+ CONNECTOR_TYPE_STR(DVIA),
+ CONNECTOR_TYPE_STR(Composite),
+ CONNECTOR_TYPE_STR(SVIDEO),
+ CONNECTOR_TYPE_STR(LVDS),
+ CONNECTOR_TYPE_STR(Component),
+ CONNECTOR_TYPE_STR(9PinDIN),
+ CONNECTOR_TYPE_STR(DisplayPort),
+ CONNECTOR_TYPE_STR(HDMIA),
+ CONNECTOR_TYPE_STR(HDMIB),
+ CONNECTOR_TYPE_STR(TV),
+ CONNECTOR_TYPE_STR(eDP),
+ CONNECTOR_TYPE_STR(VIRTUAL),
+ CONNECTOR_TYPE_STR(DSI),
+ CONNECTOR_TYPE_STR(DPI),
+};
+
+/* The connectors for primary and external displays can be controlled
+ * by the below system properties
+ * - ro.hwc.primary.conn
+ * - ro.hwc.external.conn
+ * If these are not set (default), `DRM_CONNECTOR_TYPE_Unknown` will be
+ * considered as primary display connector, and `DRM_CONNECTOR_TYPE_HDMIA`
+ * will be considered as secondary display.
+ *
+ * The values are <string> constants, with acceptable values being as defined
+ * by the DRM interface `DRM_CONNECTOR_TYPE_<string>`.
+ *
+ * If nothing is set, external is `HDMIA` connector.
+ */
+static int display_get_connector_type(int disp)
+{
+ char prop_val[PROPERTY_VALUE_MAX];
+
+ if (disp == HWC_DISPLAY_PRIMARY)
+ property_get("ro.hwc.primary.conn", prop_val, "");
+ else
+ property_get("ro.hwc.external.conn", prop_val, "HDMIA");
+
+ for (size_t i = 0; i < ARRAY_SIZE(connector_type_list); i++) {
+ if (!strncasecmp(prop_val, connector_type_list[i].name, 64))
+ return connector_type_list[i].type;
+ }
+
+ return -1;
+}
+
+static void get_connectors(omap_hwc_device_t* hwc_dev)
+{
+ int primary_connector_type = display_get_connector_type(HWC_DISPLAY_PRIMARY);
+ int external_connector_type = display_get_connector_type(HWC_DISPLAY_EXTERNAL);
+
+ // Find primary connector
+ for (auto connector : hwc_dev->card->get_connectors()) {
+ if (primary_connector_type != -1) {
+ if (connector->connector_type() == (uint32_t)primary_connector_type) {
+ hwc_dev->primaryConector = connector;
+ break;
+ }
+ } else {
+ /* If connector type is not specified use the first
+ * connector that is not our HWC_DISPLAY_EXTERNAL connector
+ */
+ if (connector->connector_type() != (uint32_t)external_connector_type) {
+ hwc_dev->primaryConector = connector;
+ break;
+ }
+ }
+ }
+
+ // Find external connector
+ for (auto connector : hwc_dev->card->get_connectors()) {
+ if (connector->connector_type() == (uint32_t)external_connector_type) {
+ hwc_dev->externalConector = connector;
+ break;
+ }
+ }
+}
+
+static int init_primary_display(omap_hwc_device_t* hwc_dev)
+{
+ if (hwc_dev->displays[HWC_DISPLAY_PRIMARY]) {
+ ALOGE("Display %d is already connected", HWC_DISPLAY_PRIMARY);
+ return -EBUSY;
+ }
+
+ kms::Connector* connector = hwc_dev->primaryConector;
+
+ HWCDisplay* display = new HWCDisplay(DISP_ROLE_PRIMARY);
+ hwc_dev->displays[HWC_DISPLAY_PRIMARY] = display;
+
+ if (!connector) {
+ ALOGW("No connector found for primary display");
+ ALOGW("Using dummy primary display");
+
+ display->is_dummy = true;
+
+ display_config_t config;
+ config.xres = LCD_DISPLAY_DEFAULT_HRES;
+ config.yres = LCD_DISPLAY_DEFAULT_VRES;
+ config.fps = LCD_DISPLAY_DEFAULT_FPS;
+ config.xdpi = LCD_DISPLAY_DEFAULT_DPI;
+ config.ydpi = LCD_DISPLAY_DEFAULT_DPI;
+ display->configs.push_back(config);
+
+ return 0;
+ }
+
+ /* Always use default mode for now */
+ kms::Videomode mode = connector->get_default_mode();
+
+ display_config_t config;
+ config.xres = mode.hdisplay;
+ config.yres = mode.vdisplay;
+ config.fps = mode.vrefresh;
+ config.xdpi = LCD_DISPLAY_DEFAULT_DPI;
+ config.ydpi = LCD_DISPLAY_DEFAULT_DPI;
+ display->configs.push_back(config);
+
+ display->disp_link.card = hwc_dev->card;
+ display->disp_link.con = connector;
+ display->disp_link.crtc = connector->get_current_crtc();
+ // FIXME: user resource manager
+ if (!display->disp_link.crtc)
+ display->disp_link.crtc = connector->get_possible_crtcs()[0];
+ display->disp_link.mode = mode;
+
+ display->setup_composition_pipes();
+
+ return 0;
+}
+
+static int add_external_hdmi_display(omap_hwc_device_t* hwc_dev)
+{
+ if (hwc_dev->displays[HWC_DISPLAY_EXTERNAL]) {
+ ALOGE("Display %d is already connected", HWC_DISPLAY_EXTERNAL);
+ return 0;
+ }
+
+ kms::Connector* connector = hwc_dev->externalConector;
+
+ if (!connector) {
+ ALOGE("No connector for external display");
+ return -1;
+ }
+
+ /* wait until EDID read finishes */
+ do {
+ connector->refresh();
+ } while (connector->get_modes().size() == 0);
+
+ // FIXME: Allow selecting other modes until HWC 1.4 support is added
+ kms::Videomode mode = connector->get_default_mode();
+
+ HWCDisplay* display = new HWCDisplay(DISP_ROLE_SECONDARY);
+ hwc_dev->displays[HWC_DISPLAY_EXTERNAL] = display;
+
+ display_config_t config;
+ config.xres = mode.hdisplay;
+ config.yres = mode.vdisplay;
+ config.fps = mode.vrefresh;
+ config.xdpi = HDMI_DISPLAY_DEFAULT_DPI;
+ config.ydpi = HDMI_DISPLAY_DEFAULT_DPI;
+ display->configs.push_back(config);
+
+ display->disp_link.card = hwc_dev->card;
+ display->disp_link.con = connector;
+ display->disp_link.crtc = connector->get_current_crtc();
+ // FIXME: user resource manager
+ if (!display->disp_link.crtc)
+ display->disp_link.crtc = connector->get_possible_crtcs()[0];
+ display->disp_link.mode = mode;
+
+ display->setup_composition_pipes();
+
+ return 0;
+}
+
+static void remove_external_hdmi_display(omap_hwc_device_t* hwc_dev)
+{
+ HWCDisplay* display = hwc_dev->displays[HWC_DISPLAY_EXTERNAL];
+ if (!display) {
+ ALOGW("Failed to remove non-existent display %d", HWC_DISPLAY_EXTERNAL);
+ return;
+ }
+
+ delete hwc_dev->displays[HWC_DISPLAY_EXTERNAL];
+ hwc_dev->displays[HWC_DISPLAY_EXTERNAL] = NULL;
+}
+
+static void handle_hotplug(omap_hwc_device_t* hwc_dev, bool state)
+{
+ if (state) {
+ int err = add_external_hdmi_display(hwc_dev);
+ if (err) {
+ remove_external_hdmi_display(hwc_dev);
+ return;
+ }
+ ALOGI("Added external display");
+ } else {
+ remove_external_hdmi_display(hwc_dev);
+ ALOGI("Removed external display");
+ }
+}
+
+static int find_hdmi_connector_status(omap_hwc_device_t* hwc_dev)
+{
+ auto connector = hwc_dev->externalConector;
+ if (!connector)
+ return false;
+
+ bool old_state = connector->connected();
+ connector->refresh();
+ bool cur_state = connector->connected();
+
+ if (cur_state != old_state)
+ ALOGI("%s event for connector %u\n",
+ cur_state == DRM_MODE_CONNECTED ? "Plug" : "Unplug",
+ connector->id());
+
+ return cur_state == DRM_MODE_CONNECTED;
+}
+
+static bool check_hotplug_status(omap_hwc_device_t* hwc_dev, bool old_state)
+{
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ bool state = find_hdmi_connector_status(hwc_dev);
+ if (state != old_state)
+ handle_hotplug(hwc_dev, state);
+
+ lock.unlock();
+
+ if (hwc_dev->cb_procs) {
+ if (hwc_dev->cb_procs->hotplug)
+ hwc_dev->cb_procs->hotplug(hwc_dev->cb_procs, HWC_DISPLAY_EXTERNAL, state);
+ if (hwc_dev->cb_procs->invalidate)
+ hwc_dev->cb_procs->invalidate(hwc_dev->cb_procs);
+ }
+
+ return state;
+}
+
+static void hwc_hdmi_thread(void* data)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)data;
+
+ setpriority(PRIO_PROCESS, 0, HWC_PRIORITY_LOW_DISPLAY);
+
+ uevent_init();
+
+ struct pollfd pfds[1] = {
+ {
+ pfds[0].fd = uevent_get_fd(),
+ pfds[0].events = POLLIN,
+ pfds[0].revents = 0,
+ }
+ };
+
+ const char* hdmi_uevent_path = "change@/devices/platform/omapdrm.0/drm/card0";
+ static char uevent_desc[4096];
+ memset(uevent_desc, 0, sizeof(uevent_desc));
+
+ /* Check outside of uevent loop in-case already plugged in */
+ bool state = check_hotplug_status(hwc_dev, false);
+
+ while (true) {
+ int err = poll(pfds, ARRAY_SIZE(pfds), -1);
+ if (err < 0) {
+ ALOGE("received hdmi_thread poll() error event %d", err);
+ break;
+ }
+
+ if (pfds[0].revents & POLLIN) {
+ /* keep last 2 zeroes to ensure double 0 termination */
+ uevent_next_event(uevent_desc, sizeof(uevent_desc) - 2);
+ if (strlen(hdmi_uevent_path) <= 0 || strcmp(uevent_desc, hdmi_uevent_path))
+ continue; /* event not for us */
+
+ state = check_hotplug_status(hwc_dev, state);
+ }
+ }
+
+ ALOGE("HDMI polling thread exiting\n");
+}
+
+/*
+ * DRM event polling thread
+ * We poll for DRM events in this thread. DRM events can be vblank and/or
+ * page-flip events both occurring on Vsync.
+ */
+static void hwc_drm_event_thread(void* data)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)data;
+
+ setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY);
+
+ struct pollfd pfds = {
+ pfds.fd = hwc_dev->card->fd(),
+ pfds.events = POLLIN,
+ pfds.revents = 0,
+ };
+
+ drmEventContext evctx = {
+ evctx.version = 2,
+ evctx.vblank_handler = HWCDisplay::vblank_handler,
+ evctx.page_flip_handler = HWCDisplay::page_flip_handler,
+ };
+
+ while (true) {
+ int ret = poll(&pfds, 1, 60000);
+ if (ret < 0) {
+ ALOGE("Event poll error %d", errno);
+ break;
+ } else if (ret == 0) {
+ ALOGI("Event poll timeout");
+ continue;
+ }
+ if (pfds.revents & POLLIN)
+ drmHandleEvent(pfds.fd, &evctx);
+ }
+
+ ALOGE("DRM event polling thread exiting\n");
+}
+
+static void adjust_drm_plane_to_layer(hwc_layer_1_t* layer, int zorder, drm_plane_props_t* plane)
+{
+ if (!layer || !plane) {
+ ALOGE("Bad layer or plane");
+ return;
+ }
+
+ /* display position */
+ plane->crtc_x = layer->displayFrame.left;
+ plane->crtc_y = layer->displayFrame.top;
+ plane->crtc_w = WIDTH(layer->displayFrame);
+ plane->crtc_h = HEIGHT(layer->displayFrame);
+
+ /* crop */
+ plane->src_x = layer->sourceCrop.left;
+ plane->src_y = layer->sourceCrop.top;
+ plane->src_w = WIDTH(layer->sourceCrop);
+ plane->src_h = HEIGHT(layer->sourceCrop);
+
+ plane->zorder = zorder;
+ plane->layer = layer;
+
+ if (layer->blending == HWC_BLENDING_PREMULT)
+ plane->pre_mult_alpha = 1;
+ else
+ plane->pre_mult_alpha = 0;
+}
+
+static int hwc_prepare_for_display(omap_hwc_device_t* hwc_dev, int disp, hwc_display_contents_1_t* content)
+{
+ if (!is_valid_display(hwc_dev, disp))
+ return -ENODEV;
+
+ HWCDisplay* display = hwc_dev->displays[disp];
+
+ if (display->is_dummy) {
+ for (size_t i = 0; i < content->numHwLayers - 1; i++) {
+ hwc_layer_1_t* layer = &content->hwLayers[i];
+ layer->compositionType = HWC_OVERLAY;
+ }
+ return 0;
+ }
+
+ /* Set the FB_TARGET layer */
+ adjust_drm_plane_to_layer(&content->hwLayers[content->numHwLayers - 1], 0, &display->planeProps[disp]);
+
+ return 0;
+}
+
+static int hwc_prepare(struct hwc_composer_device_1* dev, size_t numDisplays, hwc_display_contents_1_t** displays)
+{
+ atrace_begin(ATRACE_TAG_HAL, "am57xx_hwc_prepare");
+ if (!numDisplays || !displays)
+ return 0;
+
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ int err = 0;
+
+ for (size_t i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t* contents = displays[i];
+
+ if (!contents)
+ continue;
+
+ if (contents->numHwLayers == 0) {
+ ALOGW("Prepare given no content for display %d", i);
+ continue;
+ }
+
+ int disp_err = hwc_prepare_for_display(hwc_dev, i, contents);
+ if (!err && disp_err)
+ err = disp_err;
+ }
+
+ atrace_end(ATRACE_TAG_HAL);
+ return err;
+}
+
+static int hwc_set_for_display(omap_hwc_device_t* hwc_dev, int disp, hwc_display_contents_1_t* content)
+{
+ if (!is_valid_display(hwc_dev, disp))
+ return -ENODEV;
+
+ HWCDisplay* display = hwc_dev->displays[disp];
+ drm_plane_props_t* planeProp = &display->planeProps[disp];
+
+ int err = 0;
+
+ /*
+ * clear release and retire fence fd's here in case we do
+ * not set them in update_display()
+ */
+ for (size_t i = 0; i < content->numHwLayers; i++) {
+ hwc_layer_1_t* layer = &content->hwLayers[i];
+ layer->releaseFenceFd = -1;
+ }
+ content->retireFenceFd = -1;
+
+ if (!display->is_dummy) {
+ err = display->update_display(planeProp);
+ if (err)
+ ALOGE("Failed to update display %d\n", disp);
+ }
+
+ /* clear any remaining acquire fences */
+ for (size_t i = 0; i < content->numHwLayers; i++) {
+ hwc_layer_1_t* layer = &content->hwLayers[i];
+ if (layer->acquireFenceFd >= 0) {
+ close(layer->acquireFenceFd);
+ layer->acquireFenceFd = -1;
+ }
+ }
+
+ return err;
+}
+
+static int hwc_set(struct hwc_composer_device_1* dev, size_t numDisplays, hwc_display_contents_1_t** displays)
+{
+ atrace_begin(ATRACE_TAG_HAL, "am57xx_hwc_set");
+ if (!numDisplays || !displays)
+ return 0;
+
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ int err = 0;
+
+ for (size_t i = 0; i < numDisplays; i++) {
+ hwc_display_contents_1_t* contents = displays[i];
+
+ if (!contents)
+ continue;
+
+ if (contents->numHwLayers == 0) {
+ ALOGE("Set given no content for display %d", i);
+ continue;
+ }
+
+ int disp_err = hwc_set_for_display(hwc_dev, i, contents);
+ if (!err && disp_err)
+ err = disp_err;
+ }
+
+ atrace_end(ATRACE_TAG_HAL);
+ return err;
+}
+
+static int hwc_eventControl(struct hwc_composer_device_1* dev, int disp, int event, int enabled)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ if (!is_valid_display(hwc_dev, disp))
+ return -EINVAL;
+
+ switch (event) {
+ case HWC_EVENT_VSYNC:
+ // FIXME: This is a hack
+ hwc_dev->displays[disp]->cb_procs = hwc_dev->cb_procs;
+
+ ALOGD("%s vsync for display %d", enabled ? "Enabling" : "Disabling", disp);
+ return hwc_dev->displays[disp]->set_vsync_state(enabled);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hwc_blank(struct hwc_composer_device_1* dev, int disp, int blank)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ ALOGD("%s display %d", blank ? "Blanking" : "Unblanking", disp);
+
+ if (!is_valid_display(hwc_dev, disp))
+ return -EINVAL;
+
+ hwc_dev->displays[disp]->blank(blank);
+
+ return 0;
+}
+
+static int hwc_query(struct hwc_composer_device_1* dev, int what, int* value)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ switch (what) {
+ case HWC_BACKGROUND_LAYER_SUPPORTED:
+ // we don't support the background layer yet
+ value[0] = 0;
+ 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;
+ break;
+ default:
+ // unsupported query
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void hwc_registerProcs(struct hwc_composer_device_1* dev, hwc_procs_t const* procs)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ hwc_dev->cb_procs = (typeof(hwc_dev->cb_procs))procs;
+
+ /* now that cb_procs->hotplug is valid */
+ try {
+ hwc_dev->hdmi_thread = new std::thread(hwc_hdmi_thread, hwc_dev);
+ } catch (...) {
+ ALOGE("Failed to create HDMI listening thread (%s)", strerror(errno));
+ }
+}
+
+static int hwc_getDisplayConfigs(struct hwc_composer_device_1* dev, int disp, uint32_t* configs, size_t* numConfigs)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ if (!is_valid_display(hwc_dev, disp))
+ return -EINVAL;
+
+ HWCDisplay* display = hwc_dev->displays[disp];
+
+ return display->get_display_configs(configs, numConfigs);
+}
+
+static int hwc_getDisplayAttributes(struct hwc_composer_device_1* dev, int disp, uint32_t config, const uint32_t* attributes, int32_t* values)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)dev;
+ std::unique_lock<std::mutex> lock(hwc_dev->mutex);
+
+ if (!is_valid_display(hwc_dev, disp))
+ return -EINVAL;
+
+ HWCDisplay* display = hwc_dev->displays[disp];
+
+ return display->get_display_attributes(config, attributes, values);
+}
+
+static int hwc_device_close(hw_device_t* device)
+{
+ omap_hwc_device_t* hwc_dev = (omap_hwc_device_t*)device;
+
+ if (hwc_dev) {
+ if (hwc_dev->event_thread)
+ delete hwc_dev->event_thread;
+
+ for (size_t i = 0; i < MAX_DISPLAYS; i++)
+ delete hwc_dev->displays[i];
+
+ delete hwc_dev;
+ }
+
+ return 0;
+}
+
+static int hwc_device_open(const hw_module_t* module, const char* name, hw_device_t** device)
+{
+ if (strcmp(name, HWC_HARDWARE_COMPOSER))
+ return -EINVAL;
+
+ omap_hwc_device_t* hwc_dev = new omap_hwc_device_t;
+ memset(hwc_dev, 0, sizeof(*hwc_dev));
+
+ /* Open DRM device */
+ hwc_dev->card = new kms::Card();
+
+ /* Find primary and external connectors */
+ get_connectors(hwc_dev);
+
+ int ret = init_primary_display(hwc_dev);
+ if (ret) {
+ ALOGE("Could not initialize primary display");
+ return -1;
+ }
+
+ hwc_dev->event_thread = new std::thread(hwc_drm_event_thread, hwc_dev);
+
+ hwc_dev->device.common.tag = HARDWARE_DEVICE_TAG;
+ hwc_dev->device.common.version = HWC_DEVICE_API_VERSION_1_1;
+ hwc_dev->device.common.module = (hw_module_t*)module;
+ hwc_dev->device.common.close = hwc_device_close;
+ hwc_dev->device.prepare = hwc_prepare;
+ hwc_dev->device.set = hwc_set;
+ hwc_dev->device.eventControl = hwc_eventControl;
+ hwc_dev->device.blank = hwc_blank;
+ hwc_dev->device.query = hwc_query;
+ hwc_dev->device.registerProcs = hwc_registerProcs;
+ hwc_dev->device.getDisplayConfigs = hwc_getDisplayConfigs;
+ hwc_dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
+
+ *device = &hwc_dev->device.common;
+
+ return 0;
+}
+
+static struct hw_module_methods_t module_methods = {
+ .open = hwc_device_open,
+};
+
+omap_hwc_module_t HAL_MODULE_INFO_SYM = {
+ .base = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = HWC_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = HWC_HARDWARE_MODULE_ID,
+ .name = "AM57xx Hardware Composer HAL",
+ .author = "Texas Instruments",
+ .methods = &module_methods,
+ },
+ },
+};
diff --git a/libhwcomposer/hwc_dev.h b/libhwcomposer/hwc_dev.h
new file mode 100644
index 0000000..03d413b
--- /dev/null
+++ b/libhwcomposer/hwc_dev.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * 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 HWC_DEV_H
+#define HWC_DEV_H
+
+#include <mutex>
+#include <thread>
+
+#include <cstdbool>
+#include <cstdint>
+
+#include <hardware/hwcomposer.h>
+#include <kms++/kms++.h>
+
+#include "display.h"
+
+typedef struct omap_hwc_module {
+ hwc_module_t base;
+
+} omap_hwc_module_t;
+
+typedef struct omap_hwc_device {
+ /* static data */
+ hwc_composer_device_1_t device;
+
+ std::mutex mutex;
+
+ std::thread* hdmi_thread;
+ std::thread* event_thread;
+
+ kms::Card* card;
+
+ HWCDisplay* displays[MAX_DISPLAYS];
+
+ kms::Connector* primaryConector;
+ kms::Connector* externalConector;
+
+ drmEventContext evctx;
+
+ const hwc_procs_t* cb_procs;
+} omap_hwc_device_t;
+
+#endif /* HWC_DEV_H */